vulhub漏洞复现
第一次用vulhub复现Struts2那个S2-045漏洞时,漏洞我盯着docker-compose up之后跳出的复现那行"struts2/s2-045:latest",心里其实没底。漏洞浏览器打开8080端口,复现页面正常得让人怀疑——这玩意儿真能远程命令执行?漏洞直到把构造好的Content-Type头塞进Burp Suite,服务器回显了"uid=0(root)",复现我才意识到这套环境的漏洞价值:它把真实漏洞的触发条件完整保留了下来,省去了自己搭Tomcat、复现配JDK版本、漏洞找有漏洞的复现jar包这些破事。
vulhub本质上就是漏洞一堆预置好的Docker镜像,每个文件夹对应一个漏洞编号或CVE。复现拿s2-045来说,漏洞目录里就三个文件:docker-compose.yml、复现README.md和那个关键的漏洞struts2版本war包。docker-compose.yml里写死了端口映射和镜像来源,README里直接给POC。这种设计把复现门槛压到了最低——会敲docker命令就行,不需要理解Struts2的拦截器链怎么工作,也不需要手动编译一个存在漏洞的版本。
但这里有个坑。很多人复现完截图丢进报告就结束了,连漏洞触发时服务器日志里出现了什么异常都不看。我习惯在docker-compose up之后加一个docker logs -f,盯着容器输出。S2-045触发时,日志里会打印出OGNL表达式解析失败的堆栈,那个堆栈能告诉你payload为什么被拦截或者为什么成功。这个细节比单纯弹个计算器有价值得多。
再说一个实际遇到的案例。复现CVE-2021-44228,也就是Log4j2那个核弹漏洞时,vulhub给的镜像里跑的是一个Spring Boot应用。docker-compose.yml里配置了LOG4J_FORMAT_MSG_NO_LOOKUPS=false这个环境变量。你不加这个变量,漏洞根本触发不了——因为Log4j2在2.15.0-rc1之后默认关闭了lookup功能。vulhub把版本和环境变量都锁死在脆弱状态,这比看十篇分析文章都直观。
不过vulhub也不是万能。有些漏洞依赖特定的网络拓扑或者外部服务,比如需要LDAP服务器回连的漏洞,vulhub只给了靶机端,LDAP服务得自己搭。我见过有人卡在JNDI注入这一步,以为是payload写错了,其实是LDAP服务器没起。这种时候得去看README里有没有"额外步骤"的说明,vulhub的文档写得不算详细,但关键信息通常都在。
用久了会发现,vulhub最大的价值不是让你"复现成功",而是让你"复现失败"。失败的时候你会去查为什么,查着查着就摸到了漏洞的边界条件。比如某些payload在JDK 8u191之后就不行了,因为JNDI远程加载类被限制。vulhub的镜像用的JDK版本决定了你能不能用某种利用链。这种踩坑过程比看别人的成功截图有用十倍。
最后说个使用习惯。我一般会把vulhub的目录clone到本地,然后cd vulhub/struts2/s2-045,直接docker-compose up -d。复现完docker-compose down,环境干干净净。别在同一个目录里反复up和down,有时候端口没释放会报错,直接docker-compose down --remove-orphans更省事。还有,记得把docker-compose.yml里的端口映射改一下,默认的8080和你的开发环境冲突是常事。
这套工具适合谁?适合已经知道漏洞原理、需要快速验证POC的人,也适合刚学安全、想亲眼看看漏洞长什么样的人。但它不负责教你Java反序列化或者OGNL语法。你得先有基础,vulhub只是把靶场搬到了你面前。