mitmproxy的使用

[TOC]

mitmproxy is a free and open source interactive HTTPS proxy.
官网:https://mitmproxy.org/
安装:pip3 install mitmproxybrew install mitmproxy
安装后有3个命令行工具:mitmproxy, mitmdump, mitmweb

这里不介绍mitmweb的使用,mitmproxymitmdump的功能重点:
mitmproxy:交互式;查看流量数据(请求与响应);执行自定义脚本
mitmdump:执行自定义脚本,脚本在Mitmproxy中叫做Addon

使用mitmproxy:因为是命令行界面,所以需要记住一些快捷键
使用mitmdump:偏向编写python脚本

通过一个典型的调用,来认识下Mitmproxy下的核心概念:

➜  ~ mitmproxy --set scripts=ad_short_mitm.py '~u baidu\.com'
在Mitmproxy的叫法
set Command
scripts Options
ad_short_mitm.py Addon
'~u baidu\.com' Filter expressions

mitmproxy

➜  ~ mitmproxy

输入上面命令,启动mitmproxy并显示Flows界面

Flows界面
mitmproxy的使用_第1张图片
Flows界面

快捷键

  • 第1个也是最重要的快捷键:?: 进入Help界面
进入Help界面
mitmproxy的使用_第2张图片
Help界面
  • 第2个重要的快捷键::: Command prompt,进入命令输入模式
进入命令输入模式
mitmproxy的使用_第3张图片
命令输入模式
可以输入的命令:可以在Command Reference界面查看
可以按tab来命令补全:比如输入flow.m;再按tab; 补全为flow.mark
可以按tab来路径补全
enter执行命令
常用的命令可以用快捷键,不用进入命令输入模式,省去输入的时间
  • 界面间跳转快捷键
快捷键 界面 截图
? Help界面
mitmproxy的使用_第4张图片
Help界面
K Key Bindings界面
mitmproxy的使用_第5张图片
Key Bindings界面
P Flow Details界面
mitmproxy的使用_第6张图片
Flow Details界面
E Events界面
mitmproxy的使用_第7张图片
Events界面
C Command Reference界面
mitmproxy的使用_第8张图片
Command Reference界面
O Options界面
mitmproxy的使用_第9张图片
Options界面

注意:上面的快捷键,都是大写字母,mitmproxy的快捷键是区分大小写的
Flows界面居然没有快捷键?

  • 导航快捷键
快捷键 command 说明
q console.view.pop 返回:界面间的返回
g console.nav.start 跳到第一行
G console.nav.end 跳到最后一行
h console.nav.left
j console.nav.down 跳到下一行
k console.nav.up 跳到上一行
l console.nav.right
space console.nav.pagedown
ctrl b console.nav.pageup
ctrl f console.nav.pagedown
tab console.nav.next

g\G\j\k等这样的导航键是通用的:在Flows、Events、Command、Options等界面都能用

刚开始学命令行界面时,有这么命令、快捷键要记,没记住怎么办?
这里介绍下mitmproxy的--no-server, -n应用

➜  ~ mitmproxy --help
usage: mitmproxy [options]
...
Proxy Options:
  --no-server, -n
  --server              Start a proxy server. Enabled by default.
  • 第1个Terminal窗口里正常启动mitmproxy:➜ ~ mitmproxy
  • 开启第2个Terminal窗口带--no-server选项启动mitmproxy:➜ ~ mitmproxy --no-server;按K/C/O/?查看快捷键、Command、Options、帮助
第2个mitmproxy专门用于查看快捷键、Command、Options、帮助
mitmproxy的使用_第10张图片
image

案例实战

东方头条App - 幸运大转盘这个游戏为实战

东方头条App - 幸运大转盘
mitmproxy的使用_第11张图片
image
1.点击'领取金币':会发出https://.../zhuanpan/get_zhuanpan_new网络请求
2.点击'立即领取':会发出https://.../zhuanpan/get_gold网络请求

应用目的:通过mitmproxy的replay功能来自动化领取金币
知识点:Filter expressions, Options, Command

  • 1.启动mitmproxy
➜  ~ mitmproxy
  • 2.点开东方头条App幸运大转盘界面
  • 3.点击'领取金币';点击'立即领取';
  • 问题:这时候mitmrpoxy的Flow界面已包含上面的网络请求,网络请求非常多,怎么找到需要的请求
  • 解答:应用mitmrpoxy的Filter expressions
  • 4.按f快捷键:设置view_filter这个Option
f快捷键, 设置view_filter
mitmproxy的使用_第12张图片
image
  • 5.输入~u zhuanpan, 按回车执行命令
输入~u zhuanpan
mitmproxy的使用_第13张图片
image
mitmproxy的使用_第14张图片
image
  • 知识点:~u zhuanpanFilter expressions~u regex,用来过滤URL符合regex正则表达式的网络请求;可以按跳转到Help界面查看全部的Filter expressions

  • 6.用j导航快捷键定位到zhuanpan/get_zhuanpan_new网络请求;按下m快捷键将这条网络请求标记

按下m标记网络请求
mitmproxy的使用_第15张图片
image
  • 7.用同样的操作,标记zhuanpan/get_gold网络请求
按下m标记网络请求
mitmproxy的使用_第16张图片
image
  • 8.按:快捷键, 进入命令输入模式;输入rep, 按tab补全命令; 输入@marked; 按回车执行命令
tab补全命令
mitmproxy的使用_第17张图片
image
mitmproxy的使用_第18张图片
image

出于演示使用mitmrpoxy的目的,才增加了许多不必要的步骤;简洁方法:

  • 去除步骤4、5、6、7
  • 步骤8改为: replay.client "(~u zhuanpan/get_zhuanpan_new) | (~u zhuanpan/get_gold)"

案例到此结束,小结下用到的快捷键、命令:

快捷键 command 说明
f : set view_fliter= 只显示符合条件的网络请求
m flow.mark.toggle @focus Toggle mark on this flow
: replay.client @marked 重放多条标记的网络请求

相关快捷键:

快捷键 界面 command 说明
M flowlist view.marked.toggle Toggle viewing marked flows
U flowlist flow.mark @all false Un-set all marks
r flowlist replay.client @focus Replay this flow

一些用到Filter expressionsOptions:
view_filter、save_stream_filter、intercept

相关文档:
https://docs.mitmproxy.org/stable/concepts-options/
https://docs.mitmproxy.org/stable/concepts-filters/

问题

上面的实战有以下几个问题:

  • 第1次收集操作时,不是每次都抽到金币,也有可能抽到广告;怎样每次都跳过广告?
  • 游戏有20次机会,要手动输入多次replay.client @marked才能把20次机会用完;怎样才能减少手动操作?

这些问题我们通过编写脚本来解决。这里使用mitmproxy的其它功能为编写脚本提供方便
把实战的已被标记的2个网络请求保存为文件,方便查看:

快捷键 界面 command 说明
w flowlist console.command save.file @shown Save listed flows to file
  • 1.按w快捷键, 把@shown修改为@marked; 指定保存路径;按回车执行命令
w保存为文件
mitmproxy的使用_第19张图片
image
mitmproxy的使用_第20张图片
image
输入路径时,可以按tab来补全路径
最好不要使用~:像我自己Mac上输入~/zhuanpan.mitm,没有保存成功;当然你也可以测试下使用~的路径能否保存成功
输入的文件的后缀名是可以随意指定的;保存的文件为二进制格式
  • 2.开启第2个Terminal窗口带--no-server选项启动mitmproxy
➜  ~ mitmproxy --no-server
快捷键 界面 command 说明
L flowlist console.command view.load Load flows from file
  • 3.按L快捷键, 把步骤1保存的文件加载进来
L加载文件
mitmproxy的使用_第21张图片
image
mitmproxy的使用_第22张图片
image

好了,编写脚本的准备工作结束!
小结下用到的快捷键、命令:

快捷键 界面 command 说明
w flowlist console.command save.file @shown Save listed flows to file
L flowlist console.command view.load Load flows from file

相关快捷键:

快捷键 界面 command 说明
e flowlist console.command export.file {choice} @focus Export this flow to file

快捷键we的区别

w e
文件为二进制文件 文件为文本文件
保存的信息完整 只保存请求信息,不保存响应信息
能一次保存多条网络请求信息 一次只能保存一条网络请求信息

mitmdump

Mitmproxy是用python实现的,编写相应的Addon脚本也是用python

先用在mitmproxye快捷键来辅助编写shell脚本,来解决下上面的实战问题

    1. e快捷键分别保存zhuanpan/get_zhuanpan_newzhuanpan/get_gold网络请求为文件get_zhuanpan_new.shget_gold.sh

get_zhuanpan_new.sh文件内容:[get_gold.sh内容类似,不再列出]

curl -H 'Host:zhuanpan.dftoutiao.com' -H 'Content-Type:application/x-www-form-urlencoded' -H 'Connection:keep-alive' -H 'Accept:*/*' -H 'User-Agent:DFTT/2.4.8 (iPhone; iOS 12.3.1; Scale/3.00)' -H 'Accept-Language:zh-Hans-CN;q=1, en-CN;q=0.9, zh-Hant-CN;q=0.8' -H 'Content-Length:484' -H 'Accept-Encoding:br, gzip, deflate' -X POST 'https://zhuanpan.dftoutiao.com/zhuanpan/get_zhuanpan_new' --data-binary 'accid=834536089&appqid=AppStore190602&apptypeid=DFTT&appver=2.4.8&device=iPhone%206s%20Plus%20%28A1634/A1687%29&deviceid=AE9418A1-561A-4F5C-AF05-1EC222A50CF3&fr=rwzx&ime=F2B14555-E2EB-4556-B757-2C55799C92C2<=d2RlWExGb015UjRqSkxMZk0rRkYwcTAzd0I3RmErMWRLbzZsYTc4dkFtakxLMmgvdW9xWFhYUEFNdU9XTHZMV3F6cWNhVXRPalBSMkJNUHlvTktRbnc9PQ%3D%3D&network=wifi&num=57&os=iOS%2012.3.1&position=%E6%B5%99%E6%B1%9F&sign=5aac4e159e8d205c084c9f9e6cf4e41f&softname=DFTTIOS&softtype=TouTiao&ts=1564368354'
    1. get_zhuanpan_new.shget_gold.sh的内容合并到最终的文件中zhuanpan.sh
#!/usr/bin/env bash

function zhuanpan
{
    # mitmproxy用快捷键e导出的get_zhuanpan_new.sh文件内容原样写到这
    curl -H 'Host:zhuanpan.dftoutiao.com' -H 'Content-Type:application/x-www-form-urlencoded' -H 'Connection:keep-alive' -H 'Accept:*/*' -H 'User-Agent:DFTT/2.4.8 (iPhone; iOS 12.3.1; Scale/3.00)' -H 'Accept-Language:zh-Hans-CN;q=1, en-CN;q=0.9, zh-Hant-CN;q=0.8' -H 'Content-Length:484' -H 'Accept-Encoding:br, gzip, deflate' -X POST 'https://zhuanpan.dftoutiao.com/zhuanpan/get_zhuanpan_new' --data-binary 'accid=834536089&appqid=AppStore190602&apptypeid=DFTT&appver=2.4.8&device=iPhone%206s%20Plus%20%28A1634/A1687%29&deviceid=AE9418A1-561A-4F5C-AF05-1EC222A50CF3&fr=rwzx&ime=F2B14555-E2EB-4556-B757-2C55799C92C2<=d2RlWExGb015UjRqSkxMZk0rRkYwcTAzd0I3RmErMWRLbzZsYTc4dkFtakxLMmgvdW9xWFhYUEFNdU9XTHZMV3F6cWNhVXRPalBSMkJNUHlvTktRbnc9PQ%3D%3D&network=wifi&num=57&os=iOS%2012.3.1&position=%E6%B5%99%E6%B1%9F&sign=5aac4e159e8d205c084c9f9e6cf4e41f&softname=DFTTIOS&softtype=TouTiao&ts=1564368354'

    # mitmproxy用快捷键e导出的get_gold.sh文件内容原样写到这
    curl -H 'Host:zhuanpan.dftoutiao.com' -H 'Content-Type:application/x-www-form-urlencoded' -H 'Connection:keep-alive' -H 'Accept:*/*' -H 'User-Agent:DFTT/2.4.8 (iPhone; iOS 12.3.1; Scale/3.00)' -H 'Accept-Language:zh-Hans-CN;q=1, en-CN;q=0.9, zh-Hant-CN;q=0.8' -H 'Content-Length:487' -H 'Accept-Encoding:br, gzip, deflate' -X POST 'https://zhuanpan.dftoutiao.com/zhuanpan/get_gold' --data-binary 'accid=834536089&appqid=AppStore190602&apptypeid=DFTT&appver=2.4.8&device=iPhone%206s%20Plus%20%28A1634/A1687%29&deviceid=AE9418A1-561A-4F5C-AF05-1EC222A50CF3&fr=rwzx&ime=F2B14555-E2EB-4556-B757-2C55799C92C2&isfirst=0<=d2RlWExGb015UjRqSkxMZk0rRkYwcTAzd0I3RmErMWRLbzZsYTc4dkFtakxLMmgvdW9xWFhYUEFNdU9XTHZMV3F6cWNhVXRPalBSMkJNUHlvTktRbnc9PQ%3D%3D&network=wifi&os=iOS%2012.3.1&position=%E6%B5%99%E6%B1%9F&sign=c6f61f80d1c001ac5382ef73632e0e9e&softname=DFTTIOS&softtype=TouTiao&ts=1564368376'
}

for ((i=0; i<20; i++));
do
    zhuanpan
done

ok,shell脚本以编写完成

mitmdump --set userid=zhj -s "mitm_user_xxx.py"  -s math_mitm.py '~u mapi.hddgood.com'

mitmdump --set replacements='/~s/"video_url":"(.+)"}/"video_url":"https://vd3.bdstatic.com/mda-jfpeu3azyxp3yxjr/mda-jfpeu3azyxp3yxjr.mp4"}'

# 代码里可以调用
ctx.master.commands.call("replay.client", [flow])

ctx.master.commands.execute("view.focus.go 0")

代码阅读

源码地址:https://github.com/mitmproxy/mitmproxy

mitmproxy/tools/_main.py

入口方法:
def mitmproxy(args=None) -> typing.Optional[int]:
    run(console.master.ConsoleMaster)

def mitmdump(args=None) -> typing.Optional[int]:
    run(dump.DumpMaster)
    
主要代码
def run(master_cls):

    opts   = options.Options()
    master = master_cls(opts)
    
    pconf  = proxy.config.ProxyConfig(opts)
    server = proxy.server.ProxyServer(pconf)
    
    master.server = server
    master.run()
    return master
    
    

master.Master
    console.master.ConsoleMaster
    dump.DumpMaster
    web.master.WebMaster

Server
    proxy.server.ProxyServer
    proxy.server.DummyServer


Master与Server关系:
    master.server = server


Master和Server对象生成:
    Master(opts: options.Options)
    Server(config: config.ProxyConfig)

ProxyConfig与Options关系:
    ProxyConfig(options: options.Options)
开始运行:
    master.run()
        master.start()

    def start(self):
        if self.server:
            ServerThread(self.server).start()

class ServerThread(basethread.BaseThread):
    def __init__(self, server):
        self.server = server
        address = getattr(self.server, "address", None)
        super().__init__(
            "ServerThread ({})".format(repr(address))
        )

    def run(self):
        self.server.serve_forever()
线程:
    ServerThread
    connection_thread

    def connection_thread(self, connection, client_address):
        with self.handler_counter:
            try:
                self.handle_client_connection(connection, client_address)
            finally:
                close_socket(connection)


    def handle_client_connection(self, conn, client_address):
        h = ConnectionHandler(
            conn,
            client_address,
            self.config,
            self.channel
        )
        h.handle()

    def handle(self):
        self.log("clientconnect", "info")

        root_layer = None
        root_layer = self._create_root_layer()
        root_layer = self.channel.ask("clientconnect", root_layer)
        root_layer()

        self.log("clientdisconnect", "info")

    def _create_root_layer(self):
        root_ctx = ...
        mode = self.config.options.mode
        if mode.startswith("upstream:"):
            return modes.HttpUpstreamProxy
        elif mode == "transparent":
            return modes.TransparentProxy(root_ctx)
        elif mode == "regular":
            return modes.HttpProxy(root_ctx)
        
addons的运行过程[生命周期]
[1]. "load"
[2]. "running"
[3]. "configure"

[1]. "load"
DumpMaster.__init__(self,options):
    super().__init__(options)
    self.addons.add(*addons.default_addons())

AddonManager.add(self, *addons):
    for i in addons:
        self.chain.append(self.register(i))
        
AddonManager.register(self, addon):
    l = Loader(self.master)
    self.invoke_addon(addon, "load", l)
    
[2]. "running"
master.run():
    loop = asyncio.get_event_loop()
    self.run_loop(loop.run_forever)
        
    master.run_loop(self, loop):
        asyncio.ensure_future(self.running())
        
    master.running(self):
        self.addons.trigger("running")
        
[3]. "configure"
class AddonManager:
    def __init__(self, master):
        self.lookup = {}
        self.chain = []
        self.master = master
        master.options.changed.connect(self._configure_all)

    def _configure_all(self, options, updated):
        self.trigger("configure", updated)

参考

https://stackoverflow.com/questions/51893788/using-mitmproxy-inside-python-script

https://dev.to/kevcui/3-mitmproxy-tips-you-might-not-know-about-5dbg

https://github.com/KevCui/mitm-scripts

你可能感兴趣的:(mitmproxy的使用)