payloads格式较为简单,一般来说能够通过lint检查就是一个正常的payloads,这里不做过多说明。但是对于该如何去使用payloads一直是一个头疼的问题,这里举一个简单的例子进行说明
对于某一个漏洞,我们有以下内容
虚拟情景
某cve,能通过多个组件完成利用(这里举例为8个),同时不同组件能够使用一个统一的入口进行调用。
在调用组件之后,有一个统一的位置会存储着我们访问的结果,我们需要对产生的结果额外发出请求来匹配其中的内容,从而判断这个系统中是否存在相关的漏洞。
试考虑写出这个漏洞对应的yaml poc
优化之前,普通写法
那么结合这个场景,我们可以有以下的思路
那么结合这样的思路,我们可以得出以下的内容
name: poc-yaml-test-payloads
manual: true
transport: http
rules:
r0:
request:
method: POST
path: /admin%20/upload-srv-1/test
headers:
Content-Type: application/x-www-form-urlencoded
body: xxxxxxxxxxxx
expression: |
response.status == 200 && response.body_string.contains("aaaavvvcccc")
v0:
request:
method: GET
path: /aaaavvvcccc
expression: |
"aaaaaaaa".bmatches(response.body)
r1:
request:
method: POST
path: /admin%20/upload-srv-2/test
headers:
Content-Type: application/x-www-form-urlencoded
body: xxxxxxxxxxxx
expression: |
response.status == 200 && response.body_string.contains("aaaavvvcccc")
v1:
request:
method: GET
path: /aaaavvvcccc
expression: |
"bbbbbbbb".bmatches(response.body)
r2:
request:
method: POST
path: /admin%20/upload-srv-3/test
headers:
Content-Type: application/x-www-form-urlencoded
body: xxxxxxxxxxxx
expression: |
response.status == 200 && response.body_string.contains("aaaavvvcccc")
v2:
request:
method: GET
path: /aaaavvvcccc
expression: |
"cccccccc".bmatches(response.body)
r3:
request:
method: POST
path: /admin%20/test
headers:
Content-Type: application/x-www-form-urlencoded
body: xxxxxxxxxxxx
expression: |
response.status == 200 && response.body_string.contains("aaaavvvcccc")
v4:
request:
method: GET
path: /aaaavvvcccc
expression: |
"dddddddd".bmatches(response.body)
expression: r0() && v0() || r1() && v1() || r2() && v2() || r3() && v3()
detail:
author: Chaitin
links:
- http://example.com
优化之后,使用payloads进行编写
那么考虑一下上边写出的内容,我们发现貌似不同rule之间是有一定规律的,而且poc总体看上去过为冗长,不利于阅读。这里给出考虑到的问题
那么结合下这样的思路,再考虑到已经给出的payloads字段,我们可以获得这样的内容
name: poc-yaml-test-payloads
manual: true
transport: http
payloads:
payloads:
upload1:
path: |
"upload-srv-1/"
body: |
"xxxxxxxxxxxx"
re: |
"aaaaaaaa"
upload2:
path: |
"upload-srv-2/"
body: |
"xxxxxxxxxxxx"
re: |
"bbbbbbbb"
upload3:
path: |
"upload-srv-3/"
body: |
"xxxxxxxxxxxx"
re: |
"cccccccc"
upload4:
path: |
""
body: |
"xxxxxxxxxxxx"
re: |
"dddddddd"
rules:
r0:
request:
method: POST
path: /admin%20/{{path}}test
headers:
Content-Type: application/x-www-form-urlencoded
body: |
"{{body}}"
expression: |
response.status == 200 && response.body_string.contains("aaaavvvcccc")
verify:
request:
method: GET
path: /aaaavvvcccc
expression: |
re.bmatches(response.body)
expression: r0() && verify()
detail:
author: Chaitin
links:
- http://example.com
按照payload的展开规则展开后两者的expression其实是相同的,但是将两者进行对比,我们可以发现,优化之后的poc相比优化之前的poc,内容上大概有以下方面的强化
- 天然抽象出了漏洞的利用路径,忽略了一些暂时无需多加关注的信息,能让我们更加关注于如何通过这样一条路径去分辨漏洞的存在与否
- payload的
名称
和内部具体需要填充的内容都可以以key的形式进行呈现,非常有利于我们对不同的利用方式进行区分与修改,同时不必去费尽心思去想如何对不同的rule进行命名
- 大幅缩短了所编写poc的长度,在方便日常阅读的同时更有利于后续整体的大小优化
- 在需要添加一些利用手段时,只需要在payload中继续添加利用方式即可,而不用再回到rule中,重新了解rule该去如何编写
在对路径进行替换的时候,因为需要替换的内容是在中间,所以需要注意/
的问题,我们需要将/
写在payloads中,而不是原文中,这样,在值为空的时候才不会出现两个/
导致解析出现问题的情况。可以重点关注upload4的path与其他的path在替换后的不同
综上,当我们执行的rule数量较多且互相重复(拥有相同的访问路径,参数以及判断表达式)时,非常推荐
将rule抽象为payloads进行处理