-
Notifications
You must be signed in to change notification settings - Fork 80
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}}
如果需要将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
如果需要将请求体中的参数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,比如大多数的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"}
你也可以选择共同改变其中的某些选项,例如,将上面的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特性,而非单纯的相对固定位置的变异。
这个示例将展示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问题。