mitm命令和脚本
1、介绍
在命令窗口中,输入命令可以获得帮助。
常用的一些命令整理:
-h, --help 查看帮助信息
--version 查看版本新
-q, --quiet 退出
-v, --verbose 增加日志详情
--scripts script, -s script 这里的script是.py文件
mitmweb:
--no-web-open-browser
--web-open-browser Start a browser.
--web-port PORT Web UI port.
--web-host HOST Web UI host.
Proxy Options:
--listen-host HOST
--listen-port PORT, -p PORT
2、脚本
(1)命令
mitmweb -s a.py
- 命令脚本的方式如上,基于-s指令,参数为py文件
- 不一定是mitmweb,另外两个mitmproxy和mitmdump大致也可以
- 并不建议在脚本中写子线程,虽然可以实现,但是无法通过ctrl+c关闭命令窗口,相对有些麻烦
使用时,有两类场景:直接系统命令窗口执行命令,python程序以调用系统命令的形式执行该命令。
由于python的路径机制,如果代码使用到相对路径,都是以启动的py文件作为参照。
所以,习惯将作为脚本的py文件和作为python程序启动的py文件,设置在同一目录下
这样,可以两种方式使用脚本。
(2)脚本编写
from mitmproxy import http
class Counter:
def __init__(self):
print('代理开始')
def response(self, flow):
# 请求处理
flow.request: http.Request
url = flow.request.url
print(url)
addons = [
Counter()
]
- 注意尽量参照这里的范例进行引入和声明,以帮助pycharm中代码提示
- 经测试,脚本中是支持引入开发者自定义的模块的
- 以上范例讲解:
- addons的名称是固定的,会被mitm使用。而Counter类名称并不固定,可以随意命名。
- 一般,脚本执行过程中,Counter类会初始化一次,然后该对象被反复使用。(pycharm中测试时,发现如果中间过程脚本被编辑,那么可能会重新被动的重新初始化Counter类)。相应的,可以在初始化中声明count变量,记录次数。
- 浏览器每次发生相应的动作,会调用Counter类中对应的方法,比如接收响应,对应response方法,这些方法名称是固定的。
- 类中方法,开发者可以自定义内部代码,操作方法接收的数据。
- addons的列表中,可以声明多个类的对象,不同类实现不同功能,比如请求过滤,相应过滤,计数等。按照方向进行传递。
3、示例
这是一个脚本代码,用于记录请求和响应数据,写入文件。(一些自定义的类和函数并未展出)
import json
import os
import time
from mitmproxy import http
from api import requestclass, responseclass, propertiesclass, httplog
from api.httplog import read_own
class Counter:
def __init__(self):
print('代理开始')
# 请求id,最小为1
self.id = 1
# 在mitm目录下创建log目录存放产生的http日志和异常日志
if not os.path.exists(os.path.abspath('').replace('\\', '/') + '/mitm/log'):
os.mkdir(os.path.abspath('').replace('\\', '/') + '/mitm/log')
# 读取配置文件log_set.json
if not os.path.exists('mitm/log_set.json'):
self.log_set = {'message_log': '', 'err_log': '', 'append_flag': False}
# 创建文件并写入初始数据
with open('mitm/log_set.json', mode='w', encoding='utf-8') as f:
f.write(json.dumps(self.log_set))
else:
with open('mitm/log_set.json', mode='r', encoding='utf-8') as f:
self.log_set = json.loads(f.read())
# 如果配置文件append_flag为True,则mitm代理的日志写入之前的日志文件,否则新建日志文件
if self.log_set.get('append_flag'):
# 需要解析message_log日志文件,获取最大id+1
req_list = read_own(self.log_set.get('message_log'))
if len(req_list) > 0:
self.id = req_list[-1].id + 1
else:
# 每次启动,都是http日志文件路径和异常日志文件路径
t = time.strftime('%Y%m%d-%H%M%S')
# 写入中间文件,方便日志窗口获取日志路径
self.log_set.update({'message_log': os.path.abspath('').replace('\\', '/') + '/mitm/log/' + t + '.log',
'err_log': os.path.abspath('').replace('\\', '/') + '/mitm/log/' + t + '_err.log'})
with open(self.log_set.get('message_log'), mode='w', encoding='utf-8') as f:
pass
with open(self.log_set.get('err_log'), mode='w', encoding='utf-8') as f:
pass
with open('mitm/log_set.json', mode='w', encoding='utf-8') as f:
f.write(json.dumps(self.log_set))
def response(self, flow):
# 请求处理
flow.request: http.Request
url = flow.request.url
print(url)
req = requestclass.Request(url=url)
req.id = self.id
req.send_time = time.strftime('%Y%m%d-%H:%M:%S')
req.method = flow.request.method
req.protocol_version = flow.request.http_version
for name, value in flow.request.headers.items():
# 注意这里应该是add直接添加,而不是自定义的update
req.headers.add(str(name).replace('\r', ''), str(value).replace('\r', ''))
try:
req.body = flow.request.content.decode('utf-8')
except Exception as e:
req.body = flow.request.content.decode('iso-8859-1')
# 响应处理
flow.response: http.Response
req.res = responseclass.Response()
req.res.protocol_version = flow.response.http_version
req.res.status_code = str(flow.response.status_code)
req.res.reason = flow.response.reason
req.res.headers = propertiesclass.Headers()
for name, value in flow.response.headers.items():
req.res.headers.add(str(name).replace('\r', ''), str(value).replace('\r', ''))
try:
print(flow.response.content, type(flow.response.content))
req.res.body = flow.response.content.decode('utf-8')
except Exception as e:
req.res.body = flow.response.content.decode('iso-8859-1')
httplog.write_own([req], self.log_set.get('message_log'), append_flag=True)
self.id = self.id + 1
addons = [
Counter()
]