行业知识
ssrf刷题——buu [第二章 web进阶]SSRF Training [网鼎杯 2020 玄武组]SSRFMe
[第二章 web进阶]SSRF Training
点击即可获得源码
源码审计
get方式传参
是否存在url
url不为空就调用safe_request_url()函数
来看一下这个safe_request_url和check_inner_ip两个需要绕过的过滤函数
function check_inner_ip($url) { $match_result=preg_match('/^(http|https)?:\/\/.*(\/)?.*$/',$url); if (!$match_result) { die('url fomat error'); } //检查请求的url是否为正确的格式 try { $url_parse=parse_url($url); } //parse_url 是 PHP 的一个内置函数。 它用于解析 URL,并返回一个关联数组,包含了 URL 的各个部分, 比如协议、主机名、路径等。 parse_url 函数可以帮助开发者在处理 URL 时更方便地提取其中的信息,例如在这段代码中,它被用来解析用户输入的 URL。 catch(Exception $e) { die('url fomat error'); return false; } $hostname=$url_parse['host']; $ip=gethostbyname($hostname); $int_ip=ip2long($ip); //ip2long 是 PHP 中的一个内置函数,用于将 IPv4 地址转换为对应的长整型数字。IPv4 地址由四个十进制数(每个数范围在 0 到 255 之间)组成,用点分十进制表示(例如:"192.168.1.1")。ip2long 函数将这种点分十进制表示的 IPv4 地址转换为一个长整型数字,方便进行比较和处理。这个长整型数字可以更有效地存储和比较,通常用于 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; } //这行代码是在检查给定的 IP 地址是否属于内部 IP 地址范围: ip2long('127.0.0.0'): 将 IPv4 地址 "127.0.0.0" 转换为长整型数字。 >> 24: 对长整型数字进行右移 24 位,这相当于将 IP 地址的前 3 个字节移出,只留下第一个字节。 == $int_ip >> 24: 比较经过右移操作的 "127.0.0.0" 的结果是否与输入的 IP 地址的前 3 个字节相同。如果相同,则说明该 IP 地址属于 "127.0.0.0/8" 的范围。同样的逻辑被应用于其他内部 IP 地址范围: "10.0.0.0/8" 被右移 24 位后与输入 IP 地址的前 3 个字节进行比较。 "172.16.0.0/12" 被右移 20 位后与输入 IP 地址的前 3 个字节进行比较。 "192.168.0.0/16" 被右移 16 位后与输入 IP 地址的前 3 个字节进行比较。如果给定的 IP 地址匹配了这些范围中的任何一个,则返回 true,否则返回 false。 //综上所述,这里就是一个IP白名单,不允许我们输入类似127.*.*.*、10.*.*.*、172.16.*.*、192.168.*.* function safe_request_url($url) { if (check_inner_ip($url)) { echo $url.' is inner ip'; } else { $ch = curl_init(); //初始化新的会话,返回 cURL 句柄,供curl_setopt()、 curl_exec() 和 curl_close() 函数使用 curl_setopt($ch, CURLOPT_URL, $url); //访问的域名 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_HEADER, 0); //curl_setopt函数参数解释:https://www.cnblogs.com/lilyhomexl/p/6278921.html $output = curl_exec($ch); //执行一个cURL会话并且获取相关回复 $result_info = curl_getinfo($ch); //php curl请求在curl_exec()函数执行之后,可以使用curl_getinfo()函数获取CURL请求输出的相关信息 if ($result_info['redirect_url']) { safe_request_url($result_info['redirect_url']); } curl_close($ch); //if的作用就是如果没有获取到信息,就重复获取,重复执行safe_request_url函数//最后把exec后的数据dump出来//var_dump($output);之后就出函数了//接下来将parse_url后的url赋值给$url_parse//如果parse_url执行失败,则返回false var_dump($output); } } 绕过
我们最终的目的是要curl 127.0.0.1/flag然后得到dump出来的数据
那么该怎么绕过这两重检测呢
parse_url函数的绕过
PHP: parse_url - Manual
此函数返回一个关联数组,包含现有 URL 的各种组成部分。如果缺少了其中的某一个,则不会为这个组成部分创建数组项。组成部分为:
- scheme – 如 http
- host 域名
- port 端口
- pass
- path 路径
- query – 在问号 ? 之后
- fragment – 在散列符号 # 之后
此函数并 不 意味着给定的 URL 是合法的,它只是将上方列表中的各部分分开。parse_url() 可接受不完整的 URL,并尽量将其解析正确。
注: 此函数对相对路径的 URL 不起作用。demo
这是输出
但是如果我们输入http://www.baidu.com@2333.com/suning?v=1&k=2#id
那么结果就会变成
host就会变成@后面的字符
这样我们的host就可控了
回到题目
如果我们输入'http://127.0.0.1:80@baidu.com/flag.php'
这样也无法正确绕过
因为curl_getinfo()函数也无法解析成127.0.0.1
在前面再加一个@
这样curl_getinfo()函数解析的是127.0.0.1:80
而parse_url函数解析的host是www.baidu.com
这样就成功绕过
payload:
http://c47efe80-3429-4c17-afa8-b11ed8e4fa8f.node5.buuoj.cn:81/challenge.php?url=http://@127.0.0.1:80@www.baidu.com/flag.php
[网鼎杯 2020 玄武组]SSRFMe
代码审计
和上一题的代码菀菀类卿
也是get方式传参
不对
是一模一样的过滤
试了一下
还是有点不一样
正则匹配不同 这里不仅支持http伪协议还支持https|gopher|dict
但是后面的匹配是正常的啊
看不懂
可能@被ban了?
不知道
还可以用0.0.0.0绕过
也可以用环回地址绕过
我自己试下来可以用的有
?url=http://0x7F000001/hint.php
?url=http://[0:0:0:0:0:ffff:127.0.0.1]/hint.php
?url=http://0.0.0.0/hint.php
——————————————更新——————————————
上面那个问题 大佬给出答案
然后我们终于来到第二步
if($_SERVER['REMOTE_ADDR']==="127.0.0.1"){ highlight_file(__FILE__);}if(isset($_POST['file'])){ file_put_contents($_POST['file'],"
上一篇:建站服务器镜像怎么用啊?