mitmproxy

Posted 20175211lyz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mitmproxy相关的知识,希望对你有一定的参考价值。

mitmproxy是什么

mitm也就是man-in-the-middle中间人攻击,顾名思义,mitmproxy就是一个可以用作中间人的基于python环境的工具包,可以用于查看流量,抓包改包,重放,可以实现和burpsuite一样的功能,但是我觉得mitmproxy最大的优势是基于python平台可以灵活地开发插件脚本。

技术图片

mitmproxy安装后包括3个工具:mitmproxymitmdumpmitmweb

  • mitmproxy
    mitmproxy是一个控制台工具,允许交互式检查和修改HTTP流量。它与mitmdump的不同之处在于所有流都保存在内存中,这意味着它旨在获取和处理小样本。
  • mitmdump
    mitmdump是mitmproxy的命令行版本。它提供了类似tcpdump的功能,可让您查看,记录和以编程方式转换HTTP流量。
  • mitmweb(处于测试阶段)
    mitmweb是mitmproxy基于Web的用户界面,它允许交互式检查和修改HTTP流量。像mitmproxy一样,它与mitmdump的不同之处在于所有流都保存在内存中,这意味着它旨在获取和处理小样本

mitmproxy能做什么

正向代理,反向代理,透明代理,代理链都可以
技术图片

mitmproxy脚本/命令规范

插件脚本

有两种加载方式,我这里只写官方建议的

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()
]

这是官网上一个例子,使用oop的方法,在addons数组中添加要加载的类,可以在命令行中使用mitmproxy -s addon.py来加载这个脚本,就可以在控制台的log中看到输出的http请求的数量

命令

在mitmproxy控制台中可以输入:command来执行命令,包括内置的和用户定义的

from mitmproxy import command
from mitmproxy import ctx


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

    @command.command("myaddon.inc")
    def inc(self) -> None:
        self.num += 1
        ctx.log.info("num = %s" % self.num)


addons = [
    MyAddon()
]

同样是官网上的例子,mitmproxy -s addon.py后,输入:myaddon.inc可以在控制台看到输出

事件

插件通过事件hook到mitmproxy的内部机制中,事件可以在不同层面上分为5类:HTTP,TCP,Websocket,Network,General。其中最常用的就是HTTP事件,包括

def http_connect(self, flow: mitmproxy.http.HTTPFlow):
    """
        (Called when) 收到了来自客户端的 HTTP CONNECT 请求。在 flow 上设置非 2xx 响应将返回该响应并断开连接。CONNECT 不是常用的 HTTP 请求方法,目的是与服务器建立代理连接,仅是 client 与 proxy 的之间的交流,所以 CONNECT 请求不会触发 request、response 等其他常规的 HTTP 事件
    """

def requestheaders(self, flow: mitmproxy.http.HTTPFlow):
    """
        (Called when) 来自客户端的 HTTP 请求的头部被成功读取。此时 flow 中的 request 的 body 是空的。
    """

def request(self, flow: mitmproxy.http.HTTPFlow):
    """
        (Called when) 来自客户端的 HTTP 请求被成功完整读取。
    """

def responseheaders(self, flow: mitmproxy.http.HTTPFlow):
    """
        (Called when) 来自服务端的 HTTP 响应的头部被成功读取。此时 flow 中的 response 的 body 是空的。
    """

def response(self, flow: mitmproxy.http.HTTPFlow):
    """
        (Called when) 来自服务端端的 HTTP 响应被成功完整读取。
    """

def error(self, flow: mitmproxy.http.HTTPFlow):
    """
        (Called when) 发生了一个 HTTP 错误。比如无效的服务端响应、连接断开等。注意与“有效的 HTTP 错误返回”不是一回事,后者是一个正确的服务端响应,只是 HTTP code 表示错误而已。
    """

现在就可以理解之前例子里,在Counter类中的request方法是如何生效的

常用API

参考https://mitmproxy.readthedocs.io/en/v2.0.2/scripting/api.html

mitmproxy.http.HTTPRequest

  • cookies
    返回一个MultiDictView对象
  • get_content(strict: bool = True) → bytes
    使用内容编码标头(例如gzip)解码的HTTP消息正文
  • get_text(strict: bool = True) → typing.Union[str, NoneType]
    使用内容编码标头(例如gzip)和内容类型标头字符集解码的HTTP消息正文。
  • headers
    返回mitmproxy.net.http.Headers对象
  • multipart_form
    多部分表单数据作为MultiDictView对象。
    键和值都是bytes。
  • pretty_url
  • urlencoded_form
    URL编码的表单数据作为MultiDictView对象。
  • replace(pattern, repl, flags=0, count=0)
    将header,请求路径和请求体中的repl替换为正则表达式模式。编码后的内容将在替换前进行解码,然后再进行编码。

mitmproxy.http.HTTPResponse

  • make(status_code: int = 200, content: AnyStr = b‘‘, headers: typing.Union[typing.Dict[AnyStr, AnyStr], typing.Iterable[typing.Tuple[bytes, bytes]]] = ())
    用于创建response对象的简化API。
  • status_code
    状态码
  • 大部分和mitmproxy.http.HTTPRequest差不多

mitmproxy.http.HTTPFlow

HTTPFlow是代表单个HTTP事务的对象的集合

  • request
  • response

mitmproxy.log.Log

中央记录器,在脚本中暴露为mitmproxy.ctx.log

  • debug
  • info
  • warn
  • error

使用实例

使用mitmproxy解决蚁剑连接问题
刷题记录:[ByteCTF 2019]BabyBlog

from mitmproxy import http                                                    
                                                                              
class add_request:                                                            
                                                                              
    def request(self, flow) -> None:                                          
        flow.request.urlencoded_form['find'] = "/ex00"                       
        flow.request.urlencoded_form['replace'] = "eval($_POST['a'])"         
        flow.request.urlencoded_form['id'] = "1"                              
        flow.request.urlencoded_form['regex'] = "1"                           
        flow.request.cookies['phpSESSID'] = "8192498e1b72a3004a2093fc26f10d28"
                                                                              
addons = [                                                                    
    add_request()                                                             
]

这只是我实际使用mitmproxy的一个最简陋的例子,更多例子可以参考使用 mitmproxy + python 做拦截代理

参考链接

官方文档
使用 mitmproxy + python 做拦截代理

以上是关于mitmproxy的主要内容,如果未能解决你的问题,请参考以下文章

MITMProxy如何配置二次代理

mitmproxy(TLS错误)

爬虫学习笔记(二十三)—— Appium+Mitmproxy

mitmproxy 抓包神器-4.拦截请求实现篡改请求和返回数据

mitmproxy 安装

mitmproxy