背景与挑战概述 一次面向安全社区的 CTF 提供了单一 IP 的目标服务,初始页面为默认 Apache 欢迎页。题目描述暗示"管理员面板"托管在该 IP,且文件读取会触发检测。面对默认站点与题目提示,合理猜测可能的托管方式包括目录路径或基于虚拟主机的站点。首次尝试常见管理目录未果后,将注意力集中到 Host 头与子域名上,这是 Web 应用渗透中识别隐藏虚拟主机的常见手段。 虚拟主机与 Host 头的侦测技巧 HTTP/1.1 要求客户端发送 Host 头。许多开发者和管理员在同一 IP 上托管多个站点,区别不同站点的关键就是 Host 头。
通过 curl 手动替换 Host 值可以发现服务器是否根据 Host 返回不同内容。针对题目,发送 Host: acme.org 未产生新结果,随后尝试 Host: admin.acme.org 得到特殊响应头并返回了名为 admin 的 Cookie,其值为 no。这个细节提示了潜在的访问控制逻辑:服务器可能基于 Cookie 值决定行为。 Cookie 绕过与方法限制识别 将 admin Cookie 值改为 yes 后,访问根路径直接返回 405 Method Not Allowed,暗示 GET 请求在被授权上下文中被禁用了,需要尝试其他 HTTP 方法。后续尝试显示 POST 返回 406 Not Acceptable,这提示请求的 Content-Type 与服务器期望不匹配。此处的思路转向猜测服务器可能期望 JSON 格式而非传统的 application/x-www-form-urlencoded。
改变 Content-Type 为 application/json 并发送空体得到 unable to decode 的响应,说明服务器正在尝试解析 JSON。进一步尝试携带 domain 字段并解析服务器返回的验证提示,能快速反推服务器的域名校验逻辑。 域名校验策略与试探 通过不断试探 JSON 字段中 domain 的值,可以发现服务器对域名有多重限制。典型约束包括要求域名以 .com 结尾,下层子域必须包含特定字符串"212",并且域名整体必须包含至少两个点。基于这些限制,攻击者可以准备一个可控的子域用于验证远端请求行为。将子域指向自己的服务器后,能观察到由目标服务器发起的 HTTP 请求,从而确认服务器正在向传入的域名发起请求并将响应以 base64 编码返回给调用者,典型的 SSRF 行为由此被确认。
CNAME 与 nip.io 的实战应用 在无法上传 A 记录或无法直接控制域名解析为任意 IP 的情况下,利用 CNAME 指向一个由动态 DNS 服务提供的带 IP 的域名成为解决思路。nip.io 提供的通用解析功能,允许通过像 127.0.0.1.nip.io 这样的名字直接解析到指定 IP。这一技巧对绕过子域注册或免费托管只允许 CNAME 的限制尤为有效。通过将子域的 CNAME 指向 127.0.0.1.nip.io,攻击者能够让目标服务器请求解析并连接到其本地回环地址,进而验证内网访问能力并读取内网服务响应。 重定向与响应跟随的限制 在早期试验中,通过让自己的子域返回 302 重定向指向其他目标并未奏效,表面上看似目标服务不跟随重定向或仅允许特定行为。同时,结合响应为 base64 编码的事实,意味着只要能使目标服务器直接请求任意可达地址并返回其响应,便可读取目标资源。
关键在于如何突破服务器对域名格式与路径的校验限制,以便让目标发起对任意主机或端口的请求。 换行注入技巧:从单目标到多目标 SSRF 在对域名字符限制的进一步试验中,发现域名字段对某些字符如问号和井号进行禁止,但可以传入空格与换行。在被请求方的日志中,换行字符分割了域名字符串并将其作为多条请求处理。通过构造包含换行的 domain 值,能够让服务器在单次提交中顺序尝试多个目标。观察到服务器只返回最后一个目标的返回 ID,但会为每个目标生成并存储请求记录,从而能够通过读取前一条或相邻 ID 得到想要的响应。 双换行构造与端口控制 基于换行分割的发现,进一步构造双换行 payload,即第一段满足"212"规则的伪造子域,第二段是任意要访问的目标(可以包含 IP、端口和路径),第三段再次满足 .com 校验以绕过末尾检查。
服务器在处理时会为每个分段生成独立记录并依序发起请求,但返回给调用者的是最后一个记录的 ID。通过计算相对 ID 偏移并读取之前的记录,即可获取第二段的请求响应。更重要的是,通过在第二段指定端口号,攻击者成功让目标服务在任意 TCP 端口上向其监听的服务发起 HTTP 请求,从而突破了只能访问 80 端口的限制。 利用 SSRF 做内网端口扫描 掌握了端口控制后,可以使用自动化脚本遍历可能的端口并读取对应 ID-1 的响应内容,进而实现对内网端口的探测。通过逐端口发送构造后的 domain 请求并解析 read.php 返回的 base64 字符串,可以识别开放端口与运行在其上的协议特征。实践中在目标服务器的本地回环上发现了 SSH 标识响应,还有一个在 1337 端口返回自定义字符串的服务。
这种方法有效地把 SSRF 转化为内网服务枚举工具,通过返回数据可以判断服务类型并进一步针对性请求特定路径。 发现内部服务并获取 Flag 在端口扫描过程中,1337 端口呈现出 Web 服务的行为,返回了 nginx 默认的 404 页面提示。继续尝试对该端口上的特定路径发起请求,最终访问 /flag 路径并获得了 Flag 的内容。整个利用过程由初始的 Host 探测、Cookie 符合性测试、POST/JSON 内容嗅探、域名验证绕过、CNAME/nip.io 技巧、换行注入到端口扫描和内网资源读取,循序渐进地完成了从外网到内网敏感文件读取的链路。 防御与修补建议 从防御角度看,首先要避免将敏感功能直接暴露给通过 Host 或外部输入控制的域名解析。应用应尽量避免根据外部输入构建网络请求,若必须允许用户提交 URL 或域名,应对协议、主机、端口和路径进行严格白名单控制。
对内部资源访问应进行防护措施,例如对目标主机的请求仅允许特定白名单内的域名或 IP,并拒绝局域网和回环地址。对 HTTP 请求的解析应当避免对输入字符串直接使用换行或其他控制字符,否则可能被拆分为多条请求,产生注入式 SSRF。对 Content-Type 的严格验证应结合对 JSON 解析器的深度校验,避免在解码时泄露服务器内部错误信息或返回错误状态码暴露解析逻辑。 代码层面的缓解包括禁止通过用户提供的域名直接发起系统级别的 DNS 解析与连接,或通过代理与网关来统一处理外部请求,内网 IP 及环回地址应在代理层被显式屏蔽。对于需要访问外部资源的服务,建议在网络层和应用层都建立强约束,审计和监控不寻常的外部请求行为,及时报警并限制潜在的滥用。 渗透测试与研究者的启示 通过此案例可以看到中级到高级 SSRF 利用往往依赖对目标应用复杂的输入校验逻辑的逆向推断。
单一的错误页面或错误状态码常常蕴含有价值的线索,例如 406 提示 Content-Type 问题。测试者要善于通过细致的探测推导出服务器的服务流程,包括输入字段如何被拆分、如何生成请求 ID、请求是如何排队与回显等。利用公共 DNS 解析服务如 nip.io 或类似的动态域名解析,能够在受限域名控制环境下建立回连。换行注入与头部注入是常见但易被忽视的向量,需在测试时重点验证。 结语 从默认的 Apache 页面到最终读取 Flag 的过程体现了渗透测试中逐层剥离与构造利用链的常规模式。对防守者而言,理解这些利用技巧并在设计和实现时加入多层次约束将大大降低 SSRF 导致的内网信息泄露风险。
对攻防双方而言,通过案例学习和复盘可以提升识别复杂输入校验逻辑以及针对性防护与利用的能力。希望这次复盘对安全研究、渗透测试工程师以及希望提高 Web 应用安全的开发者都能提供实用的思路与可执行的防护建议。 。