mitmproxy是一款支持HTTP(S)的中间人代理工具。不同于Fiddler2,burpsuite等类似功能工具,mitmproxy可在终端下运行。mitmproxy使用Python开发,是辅助web开发&测试,移动端调试,渗透测试的工具。

工作原理介绍(以HTTPS为例)

1.客户端发起一个到mitmproxy的连接,并且发出HTTP CONNECT请求,
2.mitmproxy作出响应(200),模拟已经建立了CONNECT通信管道,
3.客户端确信它正在和远端服务器会话,然后启动SSL连接。在SSL连接中指明了它正在连接的主机名(SNI),
4.mitmproxy连接服务器,然后使用客户端发出的SNI指示的主机名建立SSL连接,
5.服务器以匹配的SSL证书作出响应,这个SSL证书里包含生成的拦截证书所必须的通用名(CN)和服务器备用名(SAN),
6.mitmproxy生成拦截证书,然后继续进行与第3步暂停的客户端SSL握手,
7.客户端通过已经建立的SSL连接发送请求,
8.mitmproxy通过第4步建立的SSL连接传递这个请求给服务器。

配置

1. 设置系统\浏览器\终端等的代理地址和端口

2. 浏览器或移动端安装mitmproxy提供的证书

官方提供的安装方式:http://mitmproxy.org/doc/certinstall.html

mitmproxy 

mitmproxy会提供一个在终端下的图形界面,具有修改请求和响应,流量重放等功能,具体操作方式有点vim的风格,参考请点这

mitmdump

mitmdump可设定规则保存或重放请求和响应,点我查看用法

mitmdump的特点是支持inline脚本,由于拥有可以修改request和response中每一个细节的能力,批量测试,劫持等都可以轻松实现,下面是个篡改图片的例子:

from libmproxy.protocol.http import decoded

def response(context, flow):
    if flow.response.headers.get_first("content-type", "").startswith("image"):
     with decoded(flow.response):
            try:
             img = cStringIO.StringIO(open('freebuf.jpg', 'rb').read())
             flow.response.content = img.getvalue()
             flow.response.headers["content-type"] = ["image/jpg"]
            except:
                pass

判别header中是否存在image,如果有的话替换成指定图片。

mitmdump --script pic.py

效果如下:

libmproxy

libmproxy是mitmproxy的扩展api,新版本的libmproxy(笔者使用的:0.13 on Kali 2.0)与老版本有所差别,官方给出了几个样例,这里搜集和总结一些用法。

简单的例子:

#coding=utf-8
import os
from libmproxy import flow, proxy
from libmproxy.proxy.server import ProxyServer class MyMaster(flow.FlowMaster):
    def run(self):
        try:
            flow.FlowMaster.run(self)
        except KeyboardInterrupt:
            self.shutdown()     def handle_request(self, f):
        f = flow.FlowMaster.handle_request(self, f)
        if f:
            print f.request.url
            f.reply()
        return f     def handle_response(self, f):
        f = flow.FlowMaster.handle_response(self, f)
        if f:
            print f.request.url, f.response
            f.reply()
        return f def test_start():
    config = proxy.ProxyConfig(
        port=8080,
        # use ~/.mitmproxy/mitmproxy-ca.pem as default CA file.
        cadir="~/.mitmproxy/",
    )
    state = flow.State()
    server = ProxyServer(config)
    m = MyMaster(server, state)
    m.run() test_start()

当这个脚本运行后,将会监听127.0.0.1:8080,并输出经过此代理的request的url和response的摘要,运行下面的脚本做个测试:

#coidng=utf-8
import requests
import gevent
from gevent import monkey; monkey.patch_socket()
class test():
    def task(self, url):
        print gevent.getcurrent(), url
resp = requests.get(url)
        print url, resp
    def start(self):
        url_list = ['http://www.baidu.com',
                    'http://www.amazon.com',
                 'http://www.freebuf.com',
                    'http://www.google.com',
                    'http://jd.com']
threads = [gevent.spawn(self.task, url) for url in url_list]
gevent.joinall(threads)
get_test = test()
get_test.start()

效果:

由于libmproxy/flow.py 提供了处理request和response的能力,这样使用libmproxy提供的扩展可以方便的判别,修改数据。下面的代码可用来修改headers,伪造随机User-Aent(可用于扫描器,爬虫等):

            if f.request.headers['User-Agent']:
                UAlist = ["Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.8.1.6) Gecko/20070914 Firefox/2.0.0.7",
                      "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.7) Gecko/20070914 Firefox/2.0.0.7",
                      "Mozilla/5.0 (Windows; U; Windows NT 6.0; en) AppleWebKit/522.15.5 (KHTML, like Gecko) Version/3.0.3 Safari/522.15.5",
                      "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/103u (KHTML, like Gecko) safari/100",
                      "Opera/9.23 (X11; Linux x86_64; U; en)",
                      "Opera/9.23 (Windows NT 5.1; U; en)",
                      "Mozilla/4.0 (compatible; MSIE 6.1; Windows XP)",
                      "Mozilla/5.0 (Windows; U; MSIE 7.0; Windows NT 6.0)",
                      "Mozilla/5.0(iPad; U; CPU iPhone OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B314 Safari/531.21.10"]
        f.request.headers['User-Agent'] = [random.choice(UAlist)]

‍‍使用libmproxy的扩展脚本会独立运行,这时libmproxy/controller.py会在循环监测是否有请求:

‍‍     

‍‍当收到请求后,通过调试Queue中的数据看出proxy对请求和响应的处理流程:

‍‍

脑洞:利用libmproxy实现代理式扫描器

可以分为3个模块:

1,利用libmproxy代理抓到的resquest和response,判别后进存入数据库;
2,定时从数据库读取数据,对数据进行预处理,调用扫描模块(可参考FreeBuf《基于代理的Web扫描器的实现
》文章;
3,扫描模块(代理式扫描器的核心);

下面的代码会将请求和响应中的一些数据存入MongoDB(结构供参考,更细节的部分正在开发中)。

#coding=utf-8
import os
import pymongo
import time
from libmproxy import flow, proxy
from libmproxy.proxy.server import ProxyServer
from libmproxy.flow import FlowWriter class MyMaster(flow.FlowMaster):
    def run(self):
        self.db_init()
        try:
            flow.FlowMaster.run(self)
        except KeyboardInterrupt:
            self.shutdown()     def handle_request(self, f):
        f = flow.FlowMaster.handle_request(self, f)
        if f:
            print f.request.url
            f.reply()
        return f     def handle_response(self, f):
        f = flow.FlowMaster.handle_response(self, f)
        if f:
            self.db_insert(f)
            f.reply()
        return f     def db_init(self):
        self.client = pymongo.MongoClient('127.0.0.1', 27017)
        self.db = self.client['scan']
        self.coll = self.db['scan_res']
        return     def db_insert(self, flow):
        insert_dict = {}
        if flow:
            insert_dict = {
                'time': time.time(),
                'request': {
                    'url': flow.request.url,
                    'scheme': flow.request.scheme,
                    'path': flow.request.path,
                    'method': flow.request.method
                },
                'response': {
                    'msg': flow.response.msg,
                    'code': flow.response.code,
                    'header': dict(flow.response.headers),
                    'content': flow.response.content
                }
            }
            self.coll.insert(insert_dict)
        else:
            return
    
def test_start():
    config = proxy.ProxyConfig(
        port=8080,
        # use ~/.mitmproxy/mitmproxy-ca.pem as default CA file.
        cadir="~/.mitmproxy/",
    )
    state = flow.State()
    server = ProxyServer(config)
    m = MyMaster(server, state)
    m.run() test_start()

后记

老版本kali升级mitmproxy可能会产生某些库不可用的问题,并且libmproxy仍存在着些许不足(扩展性不够强),但mitmproxy仍为一个功能强大的工具,更多功能尚待研究,代理式扫描器已作为私人项目正在逐步开发。

参考来源

http://sigint.ru/writeups/2014/04/13/plaidctf-2014-writeups/

http://acsweb.ucsd.edu/~abuss/backdoor2014.html

http://lilydjwg.is-programmer.com/tag/mitmproxy

https://gist.github.com/yeukhon/8573005

* 作者:漏洞盒子安全团队gaba,转载请注明来自FreeBuf黑客与极客(FreeBuf.COM)

[转]mitmproxy套件使用攻略及定制化开发的更多相关文章

  1. kettle系列-4.kettle定制化开发工具类

    要说的话这个工具类还是比较简单的,每个方法体都比较小,但用起来还是可以的,把开发中一些常用的步骤封装了下,不用去kettle源码中找相关操作的具体实现了. 算了废话不多了,直接上重点,代码如下: im ...

  2. OpenStack Queens版本Horizon定制化开发

    工具环境 1.VMware workstation 12+: 2.Ubuntu系统+Linux Pycharm: 3.OpenStack Queens版本Horizon代码: 问题及解决 1.项目代码 ...

  3. VSCode插件开发全攻略(六)开发调试技巧

    更多文章请戳VSCode插件开发全攻略系列目录导航. 前言 在介绍完一些比较简单的内容点之后,我觉得有必要先和大家介绍一些开发中遇到的一些细节问题以及技巧,特别是后面一章节将要介绍WebView的知识 ...

  4. 免费提供UG、ProE二次开发、定制化开发服务

    免费提供UG.ProE二次开发,定制开发服务. 拥有六年UG.ProE二次开发经验,相关项目经验. 从事过智能设计.计算机图形学相关研究. 联系方式: QQ:1787326383 微信号:begtos ...

  5. kubeadm定制化开发,延长证书

    kubernetes离线安装包,仅需三步 修改kubeadm证书过期时间 本文通过修改kubeadm源码让kubeadm默认的一年证书过期时间修改为99年 我已经编译好了一个放在了github上,有需 ...

  6. VSCode插件开发全攻略(一)概览

    文章索引 VSCode插件开发全攻略(一)概览 VSCode插件开发全攻略(二)HelloWord VSCode插件开发全攻略(三)package.json详解 VSCode插件开发全攻略(四)命令. ...

  7. 解魔方的机器人攻略17 – 魔方CFOP算法

    由 动力老男孩 发表于 2010/01/03 17:38:09 本来我想把这个攻略做成一个NXT开发的教程,把传感器,电机,发声等部分都介绍一遍.不过现在看来有些同学很心急,希望早点看到“核心代码”, ...

  8. Oracle Sales Cloud:管理沙盒(定制化)小细节1——利用公式创建字段并显示在前端页面

    Oracle Sales Cloud(Oracle 销售云)是一套基于Oracle云端的CRM管理系统.由于 Oracle 销售云是基于 Oracle 云环境的,它与传统的管理系统相比,显著特点之一便 ...

  9. Yoshino: 一个基于React的可定制化的PC组件库

    Github: https://github.com/Yoshino-UI... Docs: https://yoshino-ui.github.io/#/ Cli-Tool: https://git ...

随机推荐

  1. 读C#程序

    阅读下面程序,请回答如下问题: 问题1:这个程序要找的是符合什么条件的数? 问题2:这样的数存在么?符合这一条件的最小的数是什么? 问题3:在电脑上运行这一程序,你估计多长时间才能输出第一个结果?时间 ...

  2. 给VMware下的Linux扩展磁盘空间(以CentOS6.3为例)

    参照这篇文章进行的,但是和作者的步骤有些不一样. #查看挂载点:df -h#显示: 文件系统 容量 已用 可用 已用%% 挂载点/dev/mapper/vg_dc01-lv_root 47G 12G ...

  3. Razor - 标记简述

    详情请参考:http://www.runoob.com/aspnet/razor-intro.html 1.Razor 不是一种编程语言.它是服务器端的标记语言.基于服务器的代码(Visual Bas ...

  4. Bean的加载

    ClassPathXmlApplicationContext存储内容 为了更理解ApplicationContext,拿一个实例ClassPathXmlApplicationContext举例,看一下 ...

  5. 阿里云视频直播PHP-SDK接入教程

    阿里云视频直播PHP-SDK接入教程 阿里云 视频直播 配置 及 PHP-SDK 接入教程        准备工作        域名管理        配置鉴权        地址生成器及DEMO演 ...

  6. JS 中的require 和 import 区别

    这两个都是为了JS模块化编程使用. 遵循规范 require 是 AMD规范引入方式 import是es6的一个语法标准,如果要兼容浏览器的话必须转化成es5的语法 调用时间 require是运行时调 ...

  7. JavaWeb开发之详解Servlet及Servlet容器

    自JavaEE诞生伊始,Servlet容器和Servlet技术,就构成了JavaEE应用的核心,配合其它组件,它们完善了Java企业级开发的全套解决方案.小到一个静态博客网站,大到分布式的集群应用,都 ...

  8. Java字节流与字符流

    九.字节流与字符流 9.1 IO的分类 <段落>根据数据的流向分为:输入流和输出流. 输入流 :把数据从其他设备上读取到内存中的流. 输出流 :把数据从内存 中写出到其他设备上的流. 数据 ...

  9. 【笔记】自学ST表笔记

    自学ST表笔记 说实话原先QBXT学的ST表忘的差不多了吧...... 我重新自学巩固一下(回忆一下) 顺便把原先一些思想来源的原博发上来 一.ST表简介 ST表,建表时间\(O(n\cdot log ...

  10. Two Bases CodeForces - 602A (BigInteger c++long long也可以)

    哇咔咔 卡函数的 标记一下 c++和java的进制转换函数都是1-36进制的 c++ long long暴力就过了... 自己写一个就好了 import java.math.BigInteger; i ...