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
      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
      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
      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/upload-srv-4
      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: |
				"upload-srv-4"
			body: |
				"xxxxxxxxxxxx"
			re: |
				"dddddddd"
rules:
	r0:
		request:
			method: POST
			path: /admin%20/{{path}}
			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该去如何编写

综上,当我们执行的rule数量较多且互相重复(拥有相同的访问路径,参数以及判断表达式)时,非常推荐将rule抽象为payloads进行处理