简介
CPH:Custom Parameter Handler extension for Burp Suite.
Burp Suite 的自定义参数处理扩展:一款用于精准修改HTTP消息的工具。
CPH 提供了一种简单的方法来修改 HTTP 消息的任何部分,即使使用宏也可以进行精确的操作。通常,宏仅支持 HTTP 参数(name=value),但使用此扩展可以定位任何内容。
功能:
-
-
根据范围和模式匹配,自动修改请求和响应。 -
查找和替换,完全支持 RegEx。 -
范围限定到特定的 Burp Suite 工具。 -
指定特定匹配项(仅第一个、所有匹配项或手动选择)。 -
支持修改动作的连接和排序,以及根据先前的响应进行下一项修改的能力。 -
快速保存/快速加载(在 Burp/Extender 会话之间持续存在)。 -
从 JSON 文件导入/导出。 -
运行宏后,从其最终响应中提取替换值。 -
修改宏中的每个请求/响应。
-
CPH VS 宏:
CPH的优势:
-
CPH 可以处理 HTTP 消息的任何部分;而宏只能动态派生格式为 name=value 的参数,即不能对 JSON、RESTful(如 /user/123)或任何其他序列化等格式进行操作。 -
CPH 可以修改请求和/或响应,宏只能修改请求CPH 将所有必要的配置集中到了一起;宏需要额外配置会话处理规则(session handling rules) -
CPH 可以检查 HTTP 消息的任何部分,以确定其是否应在范围内;宏依赖于触发它们的会话处理规则中设置的范围,并且此范围仅限于协议、主机、端口和路径
CPH的难点:
-
正则表达式的编写 -
日志不够详细
问题场景
-
-
解决CSRF Token -
解决随机字符串 -
解决流程化操作
-
CSRF Token:CSRF Token 比较好理解,每次访问网页,服务器会随机返回一个CSRF Token在前端界面中,下一步请求包中需要使用该Token,该工具可以自动化提取该Token并进行替换,让每次发送的CSRF Token都是有效的。
随机字符串:这种情况下的可能的场景有:
-
-
请求某个接口,服务端返回一个随机 key,下一个请求包需要使用该key才能访问下一个接口获取数据。 -
登录过程有验证码回显,获取验证码的值,再进行登录
-
其实上述的常见本质上都是一样的。
流程化操作:类似Burp自带的宏,宏中可以进行key1=value2&key2=value2
形式的数据替换,但不支持JSON等其他格式,该工具可以完成相应的动作。
该工具可以作为宏的替代或补充。
UI 介绍
本文的介绍基于BurpSuite 商店 BApp Store 中的 CPH V3.0a 版本。
1、Options页面
首先,首次加载时默认只有一个Options页面,如下所示:
左上角依次是:
-
-
verbosity level,日志输出的详细程度,默认是 3 INFO 级别,输出的内容可在 Burp Extensions中查看,也可以自定义输出到文件 -
Quicksave/Quickload:快速保存/快速加载(在 Burp/Extender 会话之间持续存在) -
Export Config / Import Config:从 JSON 文件导入/导出CPH选项卡配置文件 -
Visit Wiki: 访问Github Wiki -
Show EMV:打开修改查看器 (EMV)页面 -
Running built-in httpd on 127.0.0.1:9001 :启动内置的测试用例
-
右上角是Tool scop settings
:用于控制工具生效的范围。
下方是 版面最大Quickstart guide
,这块就不提了。
2、选项卡
用法
具体用法可以参考burp-cph-wiki:https://github.com/elespike/burp-cph/wiki
给了相应的教程,花点时间就能学会理解并使用。
明确范围
CPH 只会针对 Burp Suite 范围内的消息。
⚠️如果请求/响应不在 Burp 的范围内,CPH 将忽略它⚠️
需要先把目标网站添加到 Burp 的 Target列表中。
有效修改查看器 (EMV)
EMV 显示每个选项卡对 HTTP 消息的最终修改的差异,并可以有效帮助您微调 CPH 配置。
ℹ️请注意,EMV 选项卡将仅显示由 CPH 中相应选项卡修改的消息。
也就是说如果通过Session handling rules
调用的具体修改是看不到的。
而且EMV在我测试版本有Bug,只能查看最开始的一个包
1.字符串查找替换
CPH 允许在请求或响应中找到目标字符串,然后用新的所需值替换目标字符串。想要的值可能来源于:
-
-
正则表达式 -
CPH 实时发出的请求的响应 -
Burp 宏的最终响应 -
上一个 CPH 选项卡的缓存响应
-
文本匹配
最简单的查找替换就是文本匹配模式,例如:
hello xiaoming --> hello xiaohong
即 交互式案例1:
I do not speak like Yoda!
I do not speak like Mr. Mackey, m'kay?
正则匹配
利用正则进行匹配,支持正则分组语法。
利用正则分组,调整语句,如:
# 交互式案例2,注意正则的写法
Ido not speak like Yoda
Speak like Yoda, Ido not!
定位匹配
这是一个很有意思的设计,与Python切片类似。
如果某个特定匹配在给定的 HTTP 消息中出现多次,则可以定位特定匹配,但并非所有匹配都应该修改。
负值有效。无效值(例如字母)将被忽略。支持0:3,-1
这种写法,表示对前3个和最后1个匹配项进行替换。
选择:Target a subset of the matches
# 交互式案例4,注意定位匹配的写法
# 匹配 [ ] 符号,选择其中的0,4,8 进行替换
## 原响应:
[0][ ]1st [1][ ]2nd [2][ ]3rd
[3][ ]4th [4][ ]5th [5][ ]6th
[6][ ]7th [7][ ]8th [8][ ]9th
## 预期响应:
[0][X]1st [1][ ]2nd [2][ ]3rd
[3][ ]4th [4][X]5th [5][ ]6th
[6][ ]7th [7][ ]8th [8][X]9th
2.替换动态值
发出单独的请求以使用其响应中的动态值
如果需要发出单独的请求以提取要使用的新值(例如,CSRF令牌),且必要的请求已经存在于Burp Suite的其他地方(例如,Target,Proxy,Repeater等),只需右键单击所述请求并选择发送到CPH。
否则,创建一个 CPH 选项卡,然后:
-
-
勾选:我需要的值是动态(The value I need is dynamic) -
在下拉菜单中选择:发出单个请求返回的值(values returned by issuing a single request) -
然后,将请求复制/粘贴(或手动输入)到左侧窗格中。 -
最后,配置一个适当的表达式以便从相关响应中提取值。
-
# 交互式案例4,注意正则的写法
# 从响应包中匹配返回值:(?P<number>d{1,5})$,并在请求包中进行替换 /1/g<number>
## 原响应:
Try again!
New number: <randomnumber>
## 预期响应:
<number> was correct!
New number: <randomnumber>
3. 宏 VS CPH
利用CPH 实现 Burp 宏的功能。
案例场景:校验随机Cookie,访问请求:
-
-
访问 /number,获取校验码 value; -
访问 /cookie,设置cookie -
配置 Cookie: number=<value>,使用POST请求,访问 /number,修改number值。
-
-
POST/numberHTTP/1.1
Host:127.0.0.1:9001
Content-Length:10
Cookie:number=<value>
number=123
在这个场景下,Burp宏 与 CPH 都可以实现。
Burp的配置文件:
-
Burp 宏文件:https://raw.githubusercontent.com/elespike/burp-cph-demos/master/dynamic/macros_vs_cph/macros.json -
Burp Session rules文件:https://raw.githubusercontent.com/elespike/burp-cph-demos/master/dynamic/macros_vs_cph/rules.json
CPH 配置文件:https://raw.githubusercontent.com/elespike/burp-cph-demos/master/dynamic/macros_vs_cph/cph_config.json
4. Burp 宏结合 CPH
案例场景:
按照以下流程进行校验:
-
- 访问 /number,获取第一个校验码 value1;
- 访问 /1?number=<value1>,获取第二个校验码 value2;
- 访问 /2?number=<value2>,获取第三个校验码 value3;
- 访问 /3?number=<value3>,获取第四个校验码 value4;
- 访问 /check/<value4>通过最终的校验。
其中1-4步都可以通过Burp 宏解决,最后一步宏无法完成,需要使用CPH进行替换。
Burp的配置文件:
- Burp 宏文件:https://raw.githubusercontent.com/elespike/burp-cph-demos/master/dynamic/final_macro/macros.json
- Burp 规则文件:https://raw.githubusercontent.com/elespike/burp-cph-demos/master/dynamic/final_macro/rules.json
CPH 配置文件:https://raw.githubusercontent.com/elespike/burp-cph-demos/master/dynamic/final_macro/cph_config.json
5. 利用缓存响应
案例场景:按照以下流程进行校验:
-
-
访问 /number,获取第一个校验码 value1; -
访问 /1/<value1>,获取第二个校验码 value2; -
访问 /2/<value2>,获取第三个校验码 value3; -
访问 /3/<value3>,获取第四个校验码 value4; -
访问 /check/<value4>通过最终的校验。
-
上述场景下,Burp宏无法实现校验码的替换,可以利用CPH的缓存响应功能进行实现。
勾选: 我需要的值是动态(The value I need is dynamic
)在下拉列表中选择:上一个 CPH 选项卡的缓存响应中的值 (values in the cached response of a previous CPH tab
)
Burp的配置文件:
- Burp 宏文件:https://raw.githubusercontent.com/elespike/burp-cph-demos/master/dynamic/cached/macros.json
- Burp 规则文件:https://raw.githubusercontent.com/elespike/burp-cph-demos/master/dynamic/cached/rules.json
CPH 配置文件:https://raw.githubusercontent.com/elespike/burp-cph-demos/master/dynamic/cached/cph_config.json
6. CPH 代替 宏
案例场景:按照以下流程进行校验:
-
-
访问 /number,获取第一个校验码 value1; -
访问 /1/<value1>,获取第二个校验码 value2; -
访问 /2/<value2>,获取第三个校验码 value3; -
访问 /3/<value3>,获取第四个校验码 value4; -
访问 /check/<value4>通过最终的校验。
-
这里的案例场景与5一样,但是这次不使用宏和缓存响应功能,纯粹依靠CPH进行实现。
CPH 配置文件:https://raw.githubusercontent.com/elespike/burp-cph-demos/master/dynamic/cph_macro_alternative.json
CPH 进行范围匹配,会自动篡改标签中定义范围内的数据,因此它的调用逻辑是逆序的,如下所示:
-
- 监测到用户访问 /check/<value>,其中 <value> 值是动态的来自 /3/<value>,于是去请求 /3/<value3>
- 监测到访问 /3/<value>,其中 <value>值是动态的来自 /2/<value>,于是去请求 /2/<value3>
- 监测到访问 /2/<value>,其中 <value> 值是动态的来自 /1/<value>,于是去请求 /1/<value3>
- 监测到访问 /1/<value>,其中 <value> 值是动态的来自 /number,于是去请求 /number
- 请求 /number 获取动态值,并替换给 /1/<value>,后面也是如此依次进行。
JSON测试用例
个人编写的一个简单测试
案例场景:从上一个响应包中提取所需的JSON数据,赋值给目标请求的相应JSON参数。
测试代码:
from flask import Flask, request, jsonify
import requests
import random
from flask_caching import Cache
app = Flask(__name__)
cache = Cache(app, config={'CACHE_TYPE': 'simple'})
.route('/api1', methods=['GET'])
def api1():
result = random.randint(1, 100)
cache.set('result', result)
return jsonify({"验证码": result,"yzm": result, "message": "success"})
.route('/api/check', methods=['POST'])
def api4():
data = request.get_json()
ifdatais None or 'index' not indata:
return jsonify({"error": "Invalid JSON data or missing 'index' field"})
index = int(data['index'])
result_from_api1 = int(cache.get('result'))
if index == result_from_api1:
return jsonify({"message": "check successfully!"})
else:
return jsonify({"message": "invaild value!"})
if __name__ == '__main__':
app.run(debug=True)
配置:
Parameter handling:
# 1) Find matches to this expression:
{"index": 123}
# 3) Replaceeach target with this expression:
{"index": g<number>}
# 4) In the expression above, refer to the named RegEx groups you'll define below in order to insert:
"\u9a8c\u8bc1\u7801": (?P<number>d{1,5})n}n
参考
-
-
Run multiple JSON Requests as Macro:
https://forum.portswigger.net/thread/run-multiple-json-requests-as-macro-16f28e2b
-
项目地址: https://github.com/elespike/burp-cph/ -
wiki地址: https://github.com/elespike/burp-cph/wiki -
Burp Suiteの拡張機能 Custom-Request-Handlerを作成しました https://blog.cybozu.io/entry/2018/07/05/170000
-
原文始发于微信公众号(X的碎碎念):Burp插件CPH代替原生宏功能
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论