Skip to content

POC编写指南

zy010101 edited this page Nov 7, 2022 · 5 revisions

POC编写指南

POC是以yaml文件的形式来进行编写。下面是POC可以包含的所有内容。您可以根据需要,选择其中某些部分来使用。下面是对POC文件中字段的一些解释。下面的内容保存在github的poc-rule.yaml文件中。

info:                                 # 基本信息部分POC的编写者可以任意进行修改。
  author: test                        # 编写者
  name: test                          # 规则名称
  description: test                   # 规则描述
  time: 2022/10/20                    # 编写(修改)时间
  note: test                          # 备注信息
  reference:                          # 相关信息
    - test

mutate_rule:                          # 数组值,可以有多组,它们之间是And关系。
- 
  mutate_position:                    # 变异位置,表示你选择哪些位置进行变异
    header_all: false                 # 布尔值,表示是否对http的所有header进行变异。
    header_filter:                    # 数组值,可以通过参数名称或者参数值筛选你想要变异的http header,
    - 
      args:                           # 整数,只能取1或2,分别表示参数名称,参数值。
      operator:                       # 整数,只能取1或2,分别表示正则匹配,字符串相等
      value:                          # 字符串,你想筛选的值
    body_all_leaf_argname: false      # 布尔值,表示是否对body中所有叶子结点的参数名进行变异
    body_all_leaf_argvalue: false     # 布尔值,表示是否对body中所有叶子结点的参数值进行变异
    body_leaf_add_node:               # 数组值,表示body新增叶子节点
    - 
      argname:                        # 字符串,表示参数名
      argvalue:                       # 字符串,表示参数值
    body_root_add_node:               # 数组值,表示在body的根节点下面直接新增子节点
    - 
      argname:                        # 字符串,表示参数名
      argvalue:                       # 字符串,表示参数值
    body_filter:                      # 数组值,可以通过参数名称或者参数值筛选你想要变异的body节点
    - 
      args:                           # 整数,只能取1或2,分别表示参数名称,参数值。
      operator:                       # 整数,只能取1或2,分别表示正则匹配,字符串相等
      value:                          # 字符串,你想筛选的值
    body_str: false                   # 布尔值,表示是否对body字符串整体进行操作
    method: false                     # 布尔值,表示是否对method进行操作
    netloc: false                     # 布尔值,表示是否对url中网络位置部分进行操作
    path: false                       # 布尔值,表示是否对进行操作
    query_str:                        # 布尔值,表示是否对query整体进行操作
    url:                              # 布尔值,表示是否对整个url进行操作,指的是HTTP报文中不含有协议和域名的URL
    query_leaf_argname:               # 布尔值,表示是否对所有的query参数名进行操作
    query_leaf_argvalue:              # 布尔值,表示是否对所有的query参数值进行操作
    query_add_node:                   # 数组值,表示query新增的子节点
    - 
      argname:                        # 字符串,表示参数名
      argvalue:                       # 字符串,表示参数值
    query_filter:                     # 数组值,可以通过参数名称或者参数值筛选你想要变异的query节点
    - 
      args:                           # 整数,只能取1或2,分别表示参数名称,参数值。
      operator:                       # 整数,只能取1或2,分别表示正则匹配,字符串相等
      value:                          # 字符串,你想筛选的值
  
  mutate_way:                         # 数组值,变异方式。表示对你选择的变异位置进行变异的方式,可以有多组,它们之间是OR关系
  - 
    pos:                              # 整数,只能取1,2,3其中一个,分别表示插入末尾,插入随机位置以及替换
    value:                            # 字符串,表示你想要的值

response_check:                       # 数组值,输出检查,用来检查poc是否命中,多个组之间是OR关系
-                                     # 每组内的参数之间是AND关系
  status_code:                        # 表示响应状态码
    value:                            # 需要检查的状态码的值
    operator:                         # 比较规则,可以取值1,2,3,4,5;分别代表操作是字符串包含,正则匹配,大于,小于以及等于
  resp_headers:                       # 表示响应中的headers
    value:                            # 需要检查的响应头中的值
    operator:                         # 比较规则,可以取值1,2;;分别代表操作是字符串包含,正则匹配
  resp_body:                          # 表示响应中的body
    value:                            # 需要检查的响应体中的值
    operator:                         # 比较规则,可以取值1,2;分别代表操作是字符串包含,正则匹配

需要注意的是,response_check部分是用来编写响应检查的,这部分编写的好坏与否会影响到扫描结果的准确率。下面通过一些例子来直观的展示如何编写POC。一个HTTP报文如下所示:

POST /post HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Length: 45
Content-Type: application/json
User-Agent: python-httpx/0.22.0

{"userinfo": {"name": "jack", "age": 22}}

poc示例1

如果需要将path从/post更改为/index.html,那么编写的POC如下所示,这里省略了poc文件中的info部分。

mutate_rule:
- 
  mutate_position:                    # 变异位置,表示你选择哪些位置进行变异
    url: true                         # 对URL进行变异
  
  mutate_way:                         # 变异方式。表示对你选择的变异位置进行变异的方式
  - 
    pos: 3                            # 整数,只能取1,2,3其中一个,分别表示插入末尾,插入随机位置以及替换
    value: /index.html

response_check:                       # 数组值,输出检查,用来检查poc是否命中,多个组之间是OR关系
-
  status_code:                        # 表示响应状态码
    value: 200                        # 需要检查的状态码的值
    operator: 1                       # 比较规则,可以取值1,2,3,4,5;分别代表操作是字符串包含,正则匹配,大于,小于以及等于

这个poc表示的含义就是更改路径/post为/index.html;响应的检查规则是响应状态码的值等于200

poc示例2

如果需要将请求体中的参数name的值改为"wang",那么编写的POC如下所示,同样,这里省略了poc文件中的info部分。

mutate_rule:                          # 数组值,可以有多组,它们之间是And关系。
- 
  mutate_position:                    # 变异位置,表示你选择哪些位置进行变异
    body_all_leaf_argvalue: true      # 布尔值,表示是否对body中所有叶子结点的参数值进行变异
  
  mutate_way:                         # 变异方式。表示对你选择的变异位置进行变异的方式
  - 
    pos: 3                            # 整数,只能取1,2,3其中一个,分别表示插入末尾,插入随机位置以及替换
    value: wang

response_check:                       # 数组值,输出检查,用来检查poc是否命中,多个组之间是OR关系
-                                     # 每组内的参数之间是AND关系
  status_code:                        # 表示响应状态码
    value: 200                        # 需要检查的状态码的值
    operator: 5                       # 比较规则,可以取值1,2,3,4,5;分别代表操作是字符串包含,正则匹配,大于,小于以及等于。其中大于,小于,等于只适用于数值

这样,就会产生如下所示的两个报文。

POST /post HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Type: application/json
User-Agent: python-httpx/0.22.0

{"userinfo": {"name": "zhangsan", "age": "wang"}}


POST /post HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Type: application/json
User-Agent: python-httpx/0.22.0

{"userinfo": {"name": "wang", "age": 10}}

其中第二个报文就是我们想要的,它会将name的值替换为wang。至于为什么要产生第一个报文,这是因为我们这里提供的方式是变异全部的叶子节点。这样能够达到一定程度上fuzz的意义。会使的poc在一定程度上智能化,而不是固定某种模式下的poc。这也是为什么提供了随机插入以及尾部插入的原因。另外一个可能性,例如想替换用户名相关的参数,但是关键的字段可能叫username, user_name, UserName, UName, user, name等。当你无法确定字段名称的时候,这种你就需要这样的Fuzz可能性。

poc示例3

可能绝大多数的场景都是相对固定的POC,比如大多数的CVE漏洞的POC都是相对固定位置的变化。因此,该示例将展示对整个body进行替换的操作。

mutate_rule:                          # 数组值,可以有多组,它们之间是And关系。
- 
  mutate_position:                    # 变异位置,表示你选择哪些位置进行变异
    body_str: true                    # 布尔值,表示是否对body字符串整体进行操作
  
  mutate_way:                         # 变异方式。表示对你选择的变异位置进行变异的方式
  - 
    pos: 3                            # 整数,只能取1,2,3其中一个,分别表示插入末尾,插入随机位置以及替换
    value: '{"user":admin, "pass":"123456"}'

response_check:                       # 数组值,输出检查,用来检查poc是否命中,多个组之间是OR关系
-                                     # 每组内的参数之间是AND关系
  status_code:                        # 表示响应状态码
    value: 200                        # 需要检查的状态码的值
    operator: 5                       # 比较规则,可以取值1,2,3,4,5;分别代表操作是字符串包含,正则匹配,大于,小于以及等于。其中大于,小于,等于只适用于数值

这样的POC,对于上面的请求而言,将会产生如下的变异结果。

POST /post HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Type: application/json
User-Agent: python-httpx/0.22.0

{"user":admin, "pass":"123456"}

poc示例4

你也可以选择共同改变其中的某些选项,例如,将上面的Content-Type替换为application/x-www-form-urlencoded,将body替换为user=admin&pass=admin

mutate_rule:                          # 数组值,可以有多组,它们之间是And关系。
- 
  mutate_position:                    # 变异位置,表示你选择哪些位置进行变异
    body_str: true                    # 布尔值,表示是否对body字符串整体进行操作
  
  mutate_way:                         # 变异方式。表示对你选择的变异位置进行变异的方式
  - 
    pos: 3                            # 整数,只能取1,2,3其中一个,分别表示插入末尾,插入随机位置以及替换
    value: user=admin&pass=admin
-
  mutate_position:                    # 变异位置,表示你选择哪些位置进行变异
    header_all: true                    # 布尔值,表示是否对所有的header进行操作
  
  mutate_way:                         # 变异方式。表示对你选择的变异位置进行变异的方式
  - 
    pos: 3                            # 整数,只能取1,2,3其中一个,分别表示插入末尾,插入随机位置以及替换
    value: application/x-www-form-urlencoded

response_check:                       # 数组值,输出检查,用来检查poc是否命中,多个组之间是OR关系
-                                     # 每组内的参数之间是AND关系
  status_code:                        # 表示响应状态码
    value: 200                        # 需要检查的状态码的值
    operator: 5                       # 比较规则,可以取值1,2,3,4,5;分别代表操作是字符串包含,正则匹配,大于,小于以及等于。其中大于,小于,等于只适用于数值

这样的POC将会产生很多的报文,而下面这个报文就是我们需要的。

POST /post HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
User-Agent: python-httpx/0.22.0

user=admin&pass=admin

暂时没有提供指定某个参数进行变异的操作,这是因为想保留scalpel的Fuzz特性,而非单纯的相对固定位置的变异。

poc示例5

这个示例将展示scalpel的Fuzz能力,例如:

mutate_rule:                          # 数组值,可以有多组,它们之间是And关系。
- 
  mutate_position:                    # 变异位置,表示你选择哪些位置进行变异
    body_all_leaf_argvalue: true      # 布尔值,表示是否对body中所有叶子节点的参数值进行变异
  
  mutate_way:                         # 变异方式。表示对你选择的变异位置进行变异的方式
  - 
    pos: 3                            # 整数,只能取1,2,3其中一个,分别表示插入末尾,插入随机位置以及替换
    value: "aaaaa"
  - 
    pos: 3                            # 整数,只能取1,2,3其中一个,分别表示插入末尾,插入随机位置以及替换
    value: "aaaaaaaaaaaa"
  - 
    pos: 3                            # 整数,只能取1,2,3其中一个,分别表示插入末尾,插入随机位置以及替换
    value: "aaaaaaaaaaaaaaaaaaa"
  - 
    pos: 3                            # 整数,只能取1,2,3其中一个,分别表示插入末尾,插入随机位置以及替换
    value: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
  - 

response_check:                       # 数组值,输出检查,用来检查poc是否命中,多个组之间是OR关系
-                                     # 每组内的参数之间是AND关系
  status_code:                        # 表示响应状态码
    value: 500                        # 需要检查的状态码的值
    operator: 5                       # 比较规则,可以取值1,2,3,4,5;分别代表操作是字符串包含,正则匹配,大于,小于以及等于。其中大于,小于,等于只适用于数值

这个poc展示的情形通常在测试边界值的时候是非常有用的,例如name字段,可能只允许长度是32以内的字符串,它能够帮助你测试出,超长的字符串可能引发的500问题。

Clone this wiki locally