mitmproxy

  1. mitmproxy介绍
  2. 安装
  3. 配置
  4. mitmproxy Addons 插件机制
    1. 钩子函数

mitmproxy介绍

官网: https://mitmproxy.org/

mitmproxy is a free and open source interactive HTTPS proxy.

mitmproxy 主要包含3个核心工具:

  • mitmproxy:一个交互式的、具有HTTP/1、HTTP/2和WebSocket的控制台接口的、支持SSL/TLS的拦截代理。
  • mitmweb:mitmproxy的web的界面
  • mitmdump:mitmproxy的命令行版本

安装

注意:python 3.8 以上

pip install mitmproxy==7.0.4

配置

  1. 启动代理

    # mitmweb
    Web server listening at http://127.0.0.1:8081/
    Proxy server listening at http://*:8080
  2. 客户端设置网络代理

    客户端设置网络代理,代理端口设置为8080端口(如上)

  3. 客户端安装mitmproxy证书

    客户端设置好代理后,访问http://mitm.it 即可显示证书,根据系统选择对应证书进行安装即可。

mitmproxy Addons 插件机制

anatomy.py:

"""
Basic skeleton of a mitmproxy addon.

Run as follows: mitmproxy -s anatomy.py
"""
from mitmproxy import ctx


class Counter:
    def __init__(self):
        self.num = 0

    def request(self, flow):
        self.num = self.num + 1
        ctx.log.info("We've seen %d flows" % self.num)


addons = [
    Counter()
]

mitmdump -s 指定py脚本

mitmdump -s ./anatomy.py

上面是一个简单的插件,它跟踪我们看到的流(或者更具体地说HTTP请求)的数量

(venv) E:\workspace\>mitmdump -s anatomy.py
Loading script anatomy.py
Proxy server listening at http://*:8080
192.168.198.169:38882: client connect
We've seen 1 flows
192.168.198.169:38882: server connect aps.amap.com:80 (106.11.23.53:80)
192.168.198.169:38882: POST http://aps.amap.com/APS/r?ver=5.1&q=0&csid=e1e8d28c-c81c-45d3-bcce-b6eeadf283ee
                    << 200  363b
192.168.198.169:38882: server disconnect aps.amap.com:80 (106.11.23.53:80)
192.168.198.169:38882: client disconnect
We've seen 2 flows
...

钩子函数

插件通过事件挂钩连接到mitmproxy的内部机制。

许多事件接收流对象作为参数-通过修改这些对象,插件可以动态更改流量。

下面举例常见的钩子如request,response,修改请求信息,修改响应信息

"""
Basic skeleton of a mitmproxy addon.

Run as follows: mitmproxy -s anatomy.py
"""
from mitmproxy import ctx
from mitmproxy import http
import json


class Counter:
    def __init__(self):
        self.num = 0

    def request(self, flow):
        self.num = self.num + 1
        ctx.log.info("We've seen %d flows" % self.num)


class MyTest:
    def request(self,flow:http.HTTPFlow) -> None:
        """ request 钩子:处理request拦截,参数修改,制造mocke响应,重定向等"""
        if "postman-echo" in flow.request.host:
            # 修改get querystring参数
            if flow.request.method.lower()=="get" and "get" in flow.request.pretty_url:
                flow.request.query["name"] = "Milton_Proxy"
            # 修改post 表单参数
            if flow.request.method.lower()=="post":
                if flow.request.urlencoded_form:
                    # If there's already a form, one can just add items to the dict:
                    ctx.log.info(flow.request.urlencoded_form)
                    flow.request.urlencoded_form["name"] = "Milton_Proxy"
            # 制造mock响应
            if flow.request.method.lower()=="patch":
                content = {"msg":"map_local"}
                flow.response = http.Response.make(
                    status_code=200,
                    content=json.dumps(content),
                    headers={"Content-Type":"application/json"}
                )

    def response(self,flow:http.HTTPFlow) -> None:
        """ response 钩子:修改响应信息"""
        if "postman-echo" in flow.request.host and "delete" in flow.request.pretty_url:
            data = json.loads(flow.response.content)
            data["data"]={"msg":"reponse_modify"}
            flow.response.text = json.dumps(data)


addons = [
    Counter(),MyTest()
]

# 测试命令:
# curl --proxy http://127.0.0.1:8080  http://postman-echo.com/get?name=tom
# curl --proxy http://127.0.0.1:8080 -X POST http://postman-echo.com/post -d "name=Jack" -H "Content-Type: application/x-www-form-urlencoded"
# curl --proxy http://127.0.0.1:8080 -X PATCH http://postman-echo.com/patch
# curl --proxy http://127.0.0.1:8080 -X DELETE http://postman-echo.com/delete

测试情况

  1. 篡改get请求中的querystring
    # curl --proxy http://127.0.0.1:8080  http://postman-echo.com/get?name=tom
    {"args":{"name":"Milton_Proxy"},"headers":{"x-forwarded-proto":"http","x-forwarded-port":"80","host":"postman-echo.com","x-amzn-trace-id":"Root=1-61cd80b7-64f6c8f668e2a29b59201848","user-agent":"curl/7.80.0","accept":"*/*","proxy-connection":"Keep-Alive"},"url":"http://postman-echo.com/get?name=Milton_Proxy"}
  2. 篡改post请求中的form表单参数
    #  curl --proxy http://127.0.0.1:8080 -X POST http://postman-echo.com/post -d "name=Jack" -H "Content-Type: application/x-www-form-urlencoded"
    {"args":{},"data":"","files":{},"form":{"name":"Milton_Proxy"},"headers":{"x-forwarded-proto":"http","x-forwarded-port":"80","host":"postman-echo.com","x-amzn-trace-id":"Root=1-61cd8129-60130e9b255eb7b77856bd84","content-length":"17","user-agent":"curl/7.80.0","accept":"*/*","proxy-connection":"Keep-Alive","content-type":"application/x-www-form-urlencoded"},"json":{"name":"Milton_Proxy"},"url":"http://postman-echo.com/post"}
  3. request钩子中,直接mock响应
    # curl --proxy http://127.0.0.1:8080 -X PATCH http://postman-echo.com/patch
    {"msg": "map_local"}
  4. reponse钩子中,篡改服务端响应数据
    # curl --proxy http://127.0.0.1:8080 -X DELETE http://postman-echo.com/delete
    {"args": {}, "data": {"msg": "reponse_modify"}, "files": {}, "form": {}, "headers": {"x-forwarded-proto": "http", "x-forwarded-port": "80", "host": "postman-echo.com", "x-amzn-trace-id": "Root=1-61cd8201-67d81c874137d0f173ccb8b3", "user-agent": "curl/7.80.0", "accept": "*/*", "proxy-connection": "Keep-Alive", "content-type": "application/json"}, "json": null, "url": "http://postman-echo.com/delete"}

tips:
更多钩子函数与示例,可参考以下:


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。
My Show My Code