— title: Mitmproxy精华笔记 date: 2022-02-23 18:57:01 categories:
- IT技术
- 编程语言
- python
- mitmproxy tags:
- IT技术
- 编程语言
- python
- mitmproxy
摘要:
Mitmproxy精华笔记
title: Mitmproxy精华笔记 copyright: true top: 0 date: 2019-05-12 22:41:37 tags: categories: 爬虫笔记 permalink: password: keywords: description: Mitmproxy一些常用的方法实践 是啊,世界那么残酷,无论你怎么反抗它,它都沉默无声地运转着,根本不管你会怎么想。你在大使的沙拉里放入了鱼胆,苦得他落荒而逃,可他选中的小羊还是被宰杀了,剥了皮泡在胡椒和香叶汤里;你吓得那些红男绿女落荒而逃,可不久之后他们又会聚在你家的舞厅里,就着靡靡之音跳贴面舞,喝醉的男男女女搂在一起,在午夜里高声调笑;你吓走了种马老爹带回来的女明星,可是几天之后卧室里换了新的画作,又有新的女人从老爹的豪车上下来,袅袅婷婷地踏入你家的房门,袅袅婷婷地跟着他走向卧室,流水般的裸女在老爹的大床上滚过。那么多年过去了你还是那么弱小,你自以为足够叛逆了,可你根本不曾改变这个世界,你只是躲开不去看它那残酷的一面。现在你回想起来了吧?你那被愤怒和不甘支配的童年。 介绍 中间代理抓包处理库~类似与burpsuite,fidder,wireshark
安装方法:
‘pip3 install mitmproxy’
安装好后,会有mitmproxy、mitmdump、mitmweb三个使用方法,在cmd命令下输入:
‘mitmdump –version’
出现如下结果表示安装成功:
Mitmproxy: 4.0.4
Python: 3.6.3
OpenSSL: OpenSSL 1.1.0g 2 Nov 2017
Platform: Windows-10-10.0.16299-SP0
注意mitmproxy是不支持windos的噢~mitmweb是web界面的管理器。分别介绍他们的功能:
mitmproxy:提供一个命令行界面,实时显示发生的请求
mitmweb:web页面的获取发生的请求,可视乎查看过滤内容
mitmdump:没有界面,程序默默运行,所以 mitmdump 无法提供过滤请求、查看数据的功能,只能结合自定义脚本,默默工作。
基础使用 首先要开启抓包,使用命令:
mitmdump -p 1080
# 流量走本地代理的1080端口
如果发现需证书有问题,我们还需要安装 mitmproxy 提供的证书,要不抓包失败。打开网址 http://mitm.it , 选择匹配的平台,下载 HTTPS 证书。并按照对应的步骤进行安装
注意不要有端口冲突!!
当启动mitmproxy后,会在根目录下生成证书
C:\Users\langzi\.mitmproxy
这个时候安装证书即可mitmproxy-ca-cert.p12
资料来自 碳基体
要捕获https证书,就得解决证书认证的问题,因此需要在通信发生的客户端安装证书,并且设置为受信任的根证书颁布机构。下面介绍6种客户端的安装方法。
当我们初次运行mitmproxy或mitmdump时,
会在当前目录下生成 ~/.mitmproxy文件夹,其中该文件下包含4个文件,这就是我们要的证书了。
$mitmproxy-ca.pem 私钥
mitmproxy-ca-cert.pem 非windows平台使用
mitmproxy-ca-cert.p12 windows上使用
mitmproxy-ca-cert.cer 与mitmproxy-ca-cert.pem相同,android上使用
1. Firefox上安装
preferences-Advanced-Encryption-View Certificates-Import (mitmproxy-ca-cert.pem)-trust this CA to identify web sites
2. chrome上安装
设置-高级设置-HTTPS/SSL-管理证书-受信任的根证书颁发机构-导入mitmproxy-ca-cert.pem
2. osx上安装
双击mitmproxy-ca-cert.pem - always trust
3.windows7上安装
双击mitmproxy-ca-cert.p12-next-next-将所有的证书放入下列存储-受信任的根证书发布机构
4.iOS上安装
将mitmproxy-ca-cert.pem发送到iphone邮箱里,通过浏览器访问/邮件附件
我将证书放在了vps上以供下载
http://tanjiti.com/crt/mitmproxy-ca-cert.pem mitmproxy iOS
http://tanjiti.com/crt/mitmproxy-ca-cert.cer mitmproxy android
http://tanjiti.com/crt/mitmproxy-ca-cert.p12 windows
http://tanjiti.com/crt/PortSwigger.cer BurpSuite (burpsuite的证书,随便附上)
5.iOS模拟器上安装
git clone https://github.com/ADVTOOLS/ADVTrustStore.gitcd ADVTrustStore/
DANI-LEE-2:ADVTrustStore danqingdani$ python iosCertTrustManager.py -a ~/iostools/mitmproxy-ca-cert.pem
subject= CN = mitmproxy, O = mitmproxyImport certificate to iPhone/iPad simulator v5.1 [y/N] yImporting to /Users/danqingdani/Library/Application Support/iPhone Simulator/5.1/Library/Keychains/TrustStore.sqlite3 Certificate added
实际上上面的操作就是给 ~/Library/Application\ Support/iPhone\ Simulator/5.1/Library/Keychains/TrustStore.sqlite3 数据库中表tsettings表中插入证书数据
6.Android上安装
将mitmproxy-ca-cert.cer 放到sdcard根目录下
选择设置-安全和隐私-从存储设备安装证书
然后再浏览器中设置本地代理,方法如下:

这个时候浏览器的请求都会被mitmproxy捕获噢~
mitmdump 命令最大的特点就是可以自定义脚本,你可以在脚本中对请求或者响应内容通过编程的方式来控制,实现数据的解析、修改、存储等工作
使用方法为:
mitmdump -p 1080 -s script.py 1 你的script.py 的文件内容为:
import mitmproxy.http from mitmproxy import ctx
class Counter: def init(self): self.num = 0
def request(self, flow: mitmproxy.http.HTTPFlow):
self.num = self.num + 1
ctx.log.info("We've seen %d flows" % self.num)
addons = [ Counter() ] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 然后在浏览器打开网站,浏览页面,这个时候显示数据如下:!
说明捕获到数据了噢~
还能这样这样写script.py,获取每次请求头:
def request(flow): print(flow.request.headers) # 打印请求头 1 2 这里我会重点说说自定义脚本的使用方法与功能
生命周期 即发起一次http请求的全部过程,从发起连接http_connect到获取到发起连接的响应头requestheaders,然后获取到想要发起连接的内容request。
发起连接后,得到获取内容的响应头responseheaders,然后获取到返回相应的内容response。
上面的script文件中的函数名,request都是mitm定义好的了函数名,我们每次要写对应功能的脚本时候,需要找到相关功能提供的函数名即可。
http_connect def http_connect(self, flow: mitmproxy.http.HTTPFlow): 1 (Called when) 收到了来自客户端的 HTTP CONNECT 请求。在 flow 上设置非 2xx 响应将返回该响应并断开连接。CONNECT 不是常用的 HTTP 请求方法,目的是与服务器建立代理连接,仅是 client 与 proxy 的之间的交流,所以 CONNECT 请求不会触发 request、response 等其他常规的 HTTP 事件。
requestheaders def requestheaders(self, flow: mitmproxy.http.HTTPFlow): 1 (Called when) 来自客户端的 HTTP 请求的头部被成功读取。此时 flow 中的 request 的 body 是空的。
request def request(self, flow: mitmproxy.http.HTTPFlow): 1 (Called when) 来自客户端的 HTTP 请求被成功完整读取。
responseheaders def responseheaders(self, flow: mitmproxy.http.HTTPFlow): 1 (Called when) 来自服务端的 HTTP 响应的头部被成功读取。此时 flow 中的 response 的 body 是空的。
response def response(self, flow: mitmproxy.http.HTTPFlow): 1 (Called when) 来自服务端端的 HTTP 响应被成功完整读取。
通用周期 即每次发起连接或者收到相应内容,都可以使用下面的函数
error def error(self, flow: mitmproxy.http.HTTPFlow): 1 (Called when) 发生了一个 HTTP 错误。比如无效的服务端响应、连接断开等。注意与“有效的 HTTP 错误返回”不是一回事,后者是一个正确的服务端响应,只是 HTTP code 表示错误而已。
configure def configure(self, updated: typing.Set[str]): 1 (Called when) 配置发生变化。updated 参数是一个类似集合的对象,包含了所有变化了的选项。在 mitmproxy 启动时,该事件也会触发,且 updated 包含所有选项。
done def done(self): 1 (Called when) addon 关闭或被移除,又或者 mitmproxy 本身关闭。由于会先等事件循环终止后再触发该事件,所以这是一个 addon 可以看见的最后一个事件。由于此时 log 也已经关闭,所以此时调用 log 函数没有任何输出。
load def load(self, entry: mitmproxy.addonmanager.Loader): 1 (Called when) addon 第一次加载时。entry 参数是一个 Loader 对象,包含有添加选项、命令的方法。这里是 addon 配置它自己的地方。
log def log(self, entry: mitmproxy.log.LogEntry): 1 (Called when) 通过 mitmproxy.ctx.log 产生了一条新日志。小心不要在这个事件内打日志,否则会造成死循环。
running def running(self): 1 (Called when) mitmproxy 完全启动并开始运行。此时,mitmproxy 已经绑定了端口,所有的 addon 都被加载了。
update def update(self, flows: typing.Sequence[mitmproxy.flow.Flow]): 1 (Called when) 一个或多个 flow 对象被修改了,通常是来自一个不同的 addon。
功能使用 response 1 获取返回信息
from mitmproxy import http def response(flow:http.HTTPResponse)->None: print(’-’*30) print(flow.request) # Request(GET langzi.fun:80/upload/TIM%E6%88%AA%E5%9B%BE20190422162029.png) # 请求发送 请求的url print(flow.response) # Response(200 OK, image/png, 61.29k) # 返回状态码 返回的信息类型 返回的文件大小 print(flow.client_conn) # <ClientConnection: 127.0.0.1:28055> # 本地发起连接 print(flow.server_conn) # <ServerConnection: langzi.fun:80> # 服务器端口 print(’-’*30) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 response 2 获取请求头,主机,查询
import mitmproxy def response(flow: mitmproxy.http.HTTPFlow)->None: print(flow.request.headers) # Headers[(b’Host’, b’www.syztfj.com’), (b’User-Agent’, b’Mozilla/5.0 (Windows NT 10.0; WOW64; rv:49.0) Gecko/20100101 Firefox/49.0’), (b’Accept’, b’/’), (b’Accept-Language’, b’zh-CN,zh;q=0.8,en-US;q=0.5,en;q # =0.3’), (b’Accept-Encoding’, b’gzip, deflate’), (b’Referer’, b’http://www.syztfj.com/css/stylelunbo_nei.css’), (b’Cookie’, b’online_service_status=1; ASPSESSIONIDCQTTRCBC=HDPJBKAAAFJOACLEDEGCNDAF’), (b’DNT’, # b'1’), (b’X-Forwarded-For’, b'8.8.8.8’), (b’Connection’, b’keep-alive’)]
print(flow.request.host)
# www.syztfj.com
print(flow.request.query)
# 访问网址 http://c.cnzz.com/core.php?web_id=1271804123&t=z ,返回的结果如下:
# MultiDictView[('web_id', '1271804123'), ('t', 'z')]
# 可以使用flow.request.query.keys()获取所有的键
1 2 3 4 5 6 7 8 9 10 11 12 13 14 resnose 3 获取url动态链接
from mitmproxy import http
import re
from urllib.parse import urljoin
def response(flow:http.HTTPFlow):
if “Content-Type” in flow.response.headers and flow.response.headers[“Content-Type”].find(“text/html”) != -1:
pageUrl = flow.request.url
pageText = flow.response.text
pattern = (r"<a\s+(?:[^>]?\s+)?href=(?P
def parser_data(self): result = dict() result[‘url’] = self.flow.request.url # 当前网址 result[‘path’] = ‘/{}’.format(’/’.join(self.flow.request.path_components)) # 当前路径 result[‘host’] = self.flow.request.host # 当前主机 result[‘port’] = self.flow.request.port # 主机端口 result[‘scheme’] = self.flow.request.scheme # http or https result[‘method’] = self.flow.request.method # 请求方式 result[‘status_code’] = self.flow.response.status_code # 状态码 result[‘content_length’] = int(self.flow.response.headers.get(‘Content-Length’, 0)) # 返回内容长度 result[‘request_header’] = self.parser_header(self.flow.request.headers) # 请求头 result[‘request_content’] = self.flow.request.content # 返回内容 result[‘query’] = self.flow.request.query # 查询参数 return result 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 重定向 from mitmproxy import http def request(flow: http.HTTPFlow) -> None: if flow.request.pretty_host == “example.org”: flow.request.host = “mitmproxy.org” # 在这里把提交的主机地址修改成Mitmproxy.org 1 2 3 4 5 使用日志 使用日志的时候,不能再print,因为log.xxx自动输出内容
from mitmproxy import ctx def load(l): ctx.log.info(“This is some informative text.”) ctx.log.warn(“This is a warning.”) ctx.log.error(“This is an error.”) 1 2 3 4 5 写入文件 import random import sys from mitmproxy import io, http import typing # noqa
class Writer: def init(self, path: str) -> None: self.f: typing.IO[bytes] = open(path, “wb”) self.w = io.FlowWriter(self.f)
def response(self, flow: http.HTTPFlow) -> None:
if random.choice([True, False]):
self.w.add(flow)
def done(self):
self.f.close()
addons = [Writer(sys.argv[1])] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 读取文件 from mitmproxy import io from mitmproxy.exceptions import FlowReadException import pprint import sys
with open(sys.argv[1], “rb”) as logfile: freader = io.FlowReader(logfile) pp = pprint.PrettyPrinter(indent=4) try: for f in freader.stream(): print(f) print(f.request.host) pp.pprint(f.get_state()) print("") except FlowReadException as e: print(“Flow file corrupted: {}".format(e)) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 获取路径 from pathod import pathoc
p = pathoc.Pathoc((“google.com”, 80)) p.connect() print(p.request(“get:/”)) print(p.request(“get:/foo”)) 1 2 3 4 5 6 使用案例
官方文档
参考链接 1
参考连接 2
欢迎关注公众号:【安全研发】获取更多相关工具,课程,资料分享哦~ ———————————————— 版权声明:本文为CSDN博主「浪子燕青啦啦啦」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/lzy98/article/details/114002234