Mitmproxy 常规功能介绍

背景

MITMProxy是一种用于中间人攻击(Man-in-the-middle attack)的代理工具。它的作用是在正常的代理功能基础上,截获、记录或篡改数据,并自定义特定的行为。与其他抓包工具(如Fiddler或Wireshark)不同的是,MITMProxy不仅可以查看和分析截获的请求,还可以通过自定义脚本进行二次开发。例如,可以截获浏览器对特定URL的请求,将返回内容置空并存储真实的返回内容到数据库,并在出现异常时发送邮件通知。与Fiddler类似的需求无法实现高度定制化,而MITMProxy可通过载入自定义Python脚本轻松实现。

需要注意的是,MITMProxy并不会真的对无辜的人发起中间人攻击。由于MITMProxy工作在HTTP层,当前HTTPS的普及使得客户端具备检测和规避中间人攻击的能力。因此,要使MITMProxy正常工作,客户端(如APP或浏览器)必须信任MITMProxy的SSL证书或忽略证书异常。这意味着APP或浏览器是由开发者自己控制的,这一点很显而易见,说明MITMProxy的使用并非用于黑产,而是用于开发或测试目的。

那么,这样的工具有什么实际意义呢?据我所知,目前广泛应用的一种情况是进行仿真爬虫。通过使用手机模拟器或无头浏览器来模拟用户行为,MITMProxy作为代理可以拦截、存储爬虫获取到的数据,或修改数据以调整爬虫的行为。

除了正向代理模式,MITMProxy还可以通过调整配置工作在透明代理、反向代理、上游代理、SOCKS代理等不同的模式下。然而,这些工作模式对于MITMProxy来说似乎并不常用,因此本文仅讨论正向代理模式。

安装

根据你的操作系统选择相应的安装方式。

在Linux中,打开终端并运行以下命令:

sudo pip3 install mitmproxy

在Windows中,以管理员身份打开命令提示符(cmd)或 PowerShell,并运行以下命令:

pip3 install mitmproxy

安装完成后,系统将拥有三个命令可用:mitmproxy、mitmdump和mitmweb。需要注意的是,mitmproxy命令在Windows系统中无法运行,但不用担心,我们可以使用mitmdump来测试安装是否成功。

在终端或命令提示符中执行以下命令验证安装是否成功:

mitmdump --version

运行

要启动 mitmproxy 用 mitmproxy、mitmdump、mitmweb 这三个命令中的任意一个即可,这三个命令功能一致,且都可以加载自定义脚本,唯一的区别是交互界面的不同。

  • mitmproxy:提供命令行界面,使用命令行进行操作和监控。
  • mitmweb:提供浏览器界面,通过Web界面进行操作和监控。
  • mitmdump:提供简单的终端输出,适用于自动化和脚本化的使用场景。

由于 mitmproxy 命令的交互操作稍显繁杂且不支持 windows 系统,而我们主要的使用方式又是载入自定义脚本,并不需要交互,所以原则上说只需要 mitmdump 即可,但考虑到有交互界面可以更方便排查错误,所以这里以 mitmweb 命令为例。实际使用中可以根据情况选择任何一个命令。

使用mitmproxy可以通过mitmdump模块编写扩展脚本,从而提高工作效率。下面是一些可以使用mitmdump解决的问题示例:

  1. 模拟接口返回数据以验证客户端是否出现UI异常或兼容性问题。
  2. 模拟接口返回数据延迟,验证客户端对接口加载状态的处理。
  3. 录制接口数据信息,用于回归测试接口功能是否正常。

启动MITMProxy

  1. 输入以下命令启动mitmweb:

    mitmweb
    
  2. 可见如下输出:

    Web server listening at http://127.0.0.1:8081/
    Proxy server listening at http://*:8080
    

    MITMProxy绑定了*:8080作为代理端口,并在127.0.0.1:8081提供了一个Web交互界面。

现在可以测试一下代理,让Chrome以MITMProxy为代理并忽略证书错误。为了不影响平时的正常使用,我们会通过命令行加参数的方式启动一个新的Chrome实例。如果你使用的不是Chrome而是其他浏览器,你可以搜索相应浏览器的启动参数,应该不会有太大差异。以下示例仅以Windows系统为例,因为那些使用Linux或Mac环境的开发者应该更熟悉命令行操作,应该可以自行推导出在自己环境中的操作方法。

由于Chrome会通过代理访问网页,为了方便继续在Web界面上与MITMProxy进行交互,我们委屈求全使用Edge或其他浏览器打开127.0.0.1:8081。以下是解决方案,因为Edge有一个默认禁止访问回环地址的设置。
以下是解决Windows系统中Edge浏览器访问本地回环地址的限制的步骤:

以管理员权限打开命令提示符(cmd),在命令提示符中输入以下命令,解除Edge浏览器访问本地回环地址的限制:

CheckNetIsolation LoopbackExempt -a -n=Microsoft.MicrosoftEdge_8wekyb3d8bbwe

请注意,上述命令中的Microsoft.MicrosoftEdge_8wekyb3d8bbwe是Edge浏览器的应用标识符,用于允许其访问本地回环地址。

接下来关闭所有 Chrome 窗口,否则命令行启动时的附加参数将失效。打开 cmd,执行:

"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --proxy-server=127.0.0.1:8080 --ignore-certificate-errors

前面那一长串是 Chrome 的的安装路径,应当根据系统实际情况修改,后面两参数设置了代理地址并强制忽略掉证书错误。

mitmdump

mitmdump是mitmproxy的命令行版本,具有丰富的命令行参数,可以根据需求进行配置。可以使用以下命令查看参数选项:

mitmdump --help

录制与回放

mitmdump提供了录制和回放功能,可以通过规则将请求数据录制到二进制文件中,并使用回放功能对接口进行数据回放。

录制

使用以下命令进行录制,并将请求数据保存到文件中:

mitmdump -w filename

过滤

可以使用过滤规则对录制的数据进行过滤,只录制符合规则的数据:

mitmdump -nr filename -w filename2 "~s keyword"

上述命令将从filename中读取数据,过滤出包含关键字"keyword"的响应数据,并将过滤结果保存到filename2中。

回放

使用以下命令对录制的数据文件进行回放:

mitmdump -nC filename

参数说明

  • -s "script.py --bar":使用双引号命令执行脚本并传递参数。
  • -n:不启动代理,仅回放数据。
  • -r:读取文件内容。
  • -w:写入文件。
  • ~s:过滤响应数据。
  • ~q:过滤请求数据。

示例

下面是一些示例用法:

  1. 使用录制功能,本地开启8999端口代理并过滤响应数据"igetget",将结果保存到本地文件igetget.txt中:
mitmdump -p 8999 -w igetget.txt "~s igetget"
  1. 连接手机到代理端口8999,并操作手机应用程序。

  2. 录制结束后,注意igetget.txt是一个二进制文件,无法直接查看详细的接口信息。

  3. 使用回放功能,回放igetcool.txt文件中的接口数据:

mitmdump -nC igetcool.txt

在回放过程中,您将看到发送请求的信息与第一次录制的数据相同。

  1. 过滤录制的请求,仅保存包含"igetcool"关键字的数据:
mitmdump -nr igetcool.txt -w igetcool-test.txt "~s igetcool"

mitmdump 功能扩展

介绍

常用的 mitmdump 扩展功能,包括修改接口响应状态码、修改接口响应结果、加载本地数据和模拟接口响应延迟。

前提条件

首先,在本地创建 script.py 文件。

修改接口响应状态码

以下示例代码演示了如何使用 mitmdump 修改接口的响应状态码。

def response(flow: http.HTTPFlow):
    if "igetcool-gateway.igetcool.com" in str(flow.request.pretty_url):
        flow.response.status_code = 404

在上述示例中,我们在 response 函数中判断请求的 URL 是否满足特定条件,如果满足,则将响应状态码设置为 404。您可以根据需要修改过滤条件和状态码值。

修改接口响应结果

以下示例代码演示了如何使用 mitmdump 修改接口的响应结果。

import json

def response(flow: http.HTTPFlow):
    if "https://igetcool-gateway.igetcool.com/app-api-user-server/white/app/head/config.json" in str(flow.request.pretty_url):
        data = json.loads(flow.response.content)
        data['data']['isShow'] = 2
        flow.response.set_text(json.dumps(data))

在上述示例代码中,我们通过添加过滤条件来确定要修改响应结果的特定接口。然后,我们加载原始响应数据并进行修改。在示例中,我们修改了数据字段 data['data']['isShow'] 的值为 2。最后,我们将修改后的数据重新设置为响应结果,以确保返回给客户端的数据已被修改。

加载本地数据(Map Local)

以下示例代码演示了如何使用 mitmdump 将指定的网络请求重定向到本地文件,以实现加载本地数据的目的。

import json

def response(flow: http.HTTPFlow):
    if "igetcool" in str(flow.request.pretty_url):
        with open("/Users/xinxi/Documents/zhihu/mitmproxyRecode/igetget.json", 'r') as f:
            resp_info = json.loads(f.read())
        flow.response.set_text(json.dumps(resp_info))

在上述示例代码中,我们使用一个过滤条件来匹配需要加载本地数据的网络请求。例如,在过滤条件中,我们检查请求 URL 中是否包含 "igetcool" 字符串。然后,我们打开本地文件并将文件中的内容加载为 JSON 格式的数据。最后,我们将本地数据作为响应结果返回。

请根据您自己的实际情况,修改文件路径以及过滤条件。

模拟接口响应延迟的方法

在 mitmdump 中没有直接设置接口延迟的方法,但我们可以使用 time.sleep() 函数来实现该效果。以下示例代码可以模拟接口响应延迟。

import time
import random
from mitmproxy import http

def response(flow: http.HTTPFlow):
    if "igetcool" in str(flow.request.pretty_url):
        random_time = random.randint(100, 1000)
        time.sleep(random_time / 1000)

在上述示例代码中,我们添加了一个过滤条件,仅对特定请求进行延迟模拟。如果请求的 URL 中包含 "igetcool" 字符串,我们会生成一个介于 100 到 1000 之间的随机整数,表示延迟的毫秒数。然后,利用 time.sleep() 函数将程序暂停指定的毫秒数,模拟延迟。


posted @ 2023-07-05 17:21  术科术  阅读(539)  评论(0编辑  收藏  举报