好久没写过SSRF了,感觉都忘了,就找来一个写写
<?php
highlight_file(__FILE__);
function check_inner_ip($url)
{
$match_result=preg_match('/^(http|https)?:\/\/.*(\/)?.*$/',$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);
}
}
$url = $_GET['url'];
if(!empty($url)){
safe_request_url($url);
}
?>
点中间连接可以找到源码,get方法传入一个url首先进入safe_request_url函数,去瞅瞅
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);
}
}
发现有一个函数check_inner_ip的判断
function check_inner_ip($url)
{
$match_result=preg_match('/^(http|https)?:\/\/.*(\/)?.*$/',$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;
}
首先有个正则,是一个传入url的格式要求,相当于我们常见的url连接格式
这里用到一个parse_url函数(这里因为不是认证机制因此没有添加username和password)
一个对url进行解析分割成数组的函数,下面只用了url的host,再用gethostbyname函数将host转换为对应的ip地址;后面的ip2long函数用一种计算方法将ip地址转换为一个整数,测试如下:
接下来是一个返回值(结合后面的函数必须要返回0,否则进入不了后面那个函数)
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;
一开始这种移位并没懂,但是自己写代码试试即可
是一个对于私有地址的判断,说明我们给予的域名不能是私有地址,也就是不让我们用127.0.0.1这个回环地址
进入下一个函数
$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);
这里只需要看到最后面var_dump将会话结果输出出来了即可,但还是要学习一下,借鉴别人的
curl_init — 初始化一个cURL会话
curl_setopt — 设置一个cURL传输选项
curl_exec — 执行一个cURL会话
curl_getinfo — 获取一个cURL连接资源句柄的信息
curl_close — 关闭一个cURL会话
一个cURL执行的基本流程
因此我们思路清晰,由最前面的页面可知道flag在flag.php下,因为是SSRF,我们肯定要用127.0.0.1去访问,现在就是我们要绕过这个函数不能解析为127.0.0.1,但是url可以解析为127.0.0.1即可。
又国外大佬一张ppt可以知晓,当我们利用两个@的时候可以让解析的实际地址与函数获得的地址不一样,以达到绕过的结果
http://@127.0.0.1:80@www.baidu.com/flag.php
利用百度的公有ip来绕过私有地址检测
进行上传