mitmproxy 使用

mitmproxy 使用

powershell無法啟動(dòng)虛擬環(huán)境

0. 準(zhǔn)備工作

參考文檔:

什么是mitmproxy茴晋?

  • mitmMan-In-The-Middle attack悉患;

  • mitmproxy 即為 中間人攻擊代理。

為什么要用mitmproxy涨缚?相比Fiddler 和 Charles它有什么優(yōu)勢黍檩?

  • mitmproxy 不僅可以截獲請(qǐng)求幫助開發(fā)者查看、分析,更可以通過自定義腳本進(jìn)行二次開發(fā)。舉例來說失乾,利用 Fiddler 可以過濾出瀏覽器對(duì)某個(gè)特定 url 的請(qǐng)求,并查看谋币、分析其數(shù)據(jù)仗扬,但實(shí)現(xiàn)不了高度定制化的需求症概,類似于:“截獲對(duì)瀏覽器對(duì)該 url 的請(qǐng)求蕾额,將返回內(nèi)容置空,并將真實(shí)的返回內(nèi)容存到某個(gè)數(shù)據(jù)庫彼城,出現(xiàn)異常時(shí)發(fā)出郵件通知”诅蝶。而對(duì)于 mitmproxy退个,這樣的需求可以通過載入自定義 python 腳本輕松實(shí)現(xiàn)。

特征

  • 攔截HTTP和HTTPS請(qǐng)求和響應(yīng)并即時(shí)修改它們
  • 保存完整的HTTP對(duì)話以供以后重播和分析
  • 重播HTTP對(duì)話的客戶端
  • 重播先前記錄的服務(wù)器的HTTP響應(yīng)
  • 反向代理模式將流量轉(zhuǎn)發(fā)到指定的服務(wù)器
  • macOS和Linux上的透明代理模式
  • 使用Python對(duì)HTTP流量進(jìn)行腳本化更改
  • 實(shí)時(shí)生成用于攔截的SSL / TLS證書
  • 還有更多……

1. 安裝

1.1 模塊安裝

安裝:

pip install mitmproxy

查看安裝成功與否:

  • cmd窗口调炬,查看版本
mitmdump --version

出現(xiàn)以下字眼语盈,則是成功安裝了。

Mitmproxy: 5.2
Python:    3.7.6
OpenSSL:   OpenSSL 1.1.1g  21 Apr 2020
Platform:  Windows-10-10.0.18362-SP0

1.2 證書安裝

模塊安裝完成后缰泡,首次運(yùn)行 mitmproxymitmdump刀荒,在當(dāng)前用戶下面會(huì)生成幾個(gè)ca證書。

Windows用戶界面的 .mitmproxy中棘钞,點(diǎn)擊進(jìn)去缠借,可以看到有多個(gè)證書,

證書 作用
mitmproxy-ca.pem PEM格式的證書和私鑰宜猜。
mitmproxy-ca-cert.pem PEM格式的證書泼返。使用它可以在大多數(shù)非Windows平臺(tái)上分發(fā)。
mitmproxy-ca-cert.p12 PKCS12格式的證書姨拥。適用于Windows(安裝這個(gè)
mitmproxy-ca-cert.cer 與.pem相同的文件绅喉,但某些Android設(shè)備需要擴(kuò)展名。

Windows端:

  • mitmproxy-ca-cert.p12

手機(jī)端:

  • 配置好wifi連接之后叫乌,訪問 mitm.it
  • 下載對(duì)應(yīng)手機(jī)系統(tǒng)的證書柴罐,然后安裝即可。

抓包示例:

  • Windows
    • 要使用代理 + 走指定的端口哦W劢妗@鲂!
  • 手機(jī)
    • 配置Windows端的ip + 指定代理0蛎辍屠阻!

2. 組件

當(dāng)我們談?wù)摗?mitmproxy“時(shí),我們通常指這三種工具中的任何一種--它們只是同一核心代理的不同前端额各。

Tools Description
mitmproxy 供交互式界面(Windows系統(tǒng)不可用
mitmdump 提供簡單明了的終端輸出
mitmweb 提供基于瀏覽器的圖形界面

正常使用用mitmdump就足夠了国觉。

所以后面的案例也是使用 mitmdump 去做展示。

mitmproxy默認(rèn)綁定的端口為 127.0.0.1:8080

注意一下:

  • 如果端口被占用了虾啦,會(huì)提示報(bào)錯(cuò)哦麻诀!

2.1 mitmproxy

Windows系統(tǒng)不可用,這里暫不展示傲醉。

2.2 mitmdump

查看所有命令:

mitmdump --help

查看版本:

mitmdump --version

常用命令:

-p 8888         # 指定端口
-s xxx.py       # 執(zhí)行指定腳本
-w outfile      # 指定輸出文件
-q quiet        # 僅匹配腳本過濾后的數(shù)據(jù)包
"~m post"       # 僅匹配Post請(qǐng)求

帶有顏色的print:

  • log蝇闭,帶有輸出不同顏色的功能(個(gè)人覺得沒有什么用
    • info 白色
    • warn 黃色
    • error 紅色

注意這里要使用cmd,使用PowerShell顯示出來的顏色效果不完整硬毕。

mitmDemoOne.py

class Demo:
    def request(self, flow: mitmproxy.http.HTTPFlow):
        """Print different colors"""
        url = flow.request.url
        if 'sunrise' in url:
            print(type(url))
            ctx.log.info('Color White:' + url)
            ctx.log.warn('Color Yellow:' + url)
            ctx.log.error('Color Red:' + url)


addons = [
    Demo()
]

2.3 mitmweb

監(jiān)聽的端口是 127.0.0.1:8080呻引,

同時(shí)提供一個(gè) web 交互界面在 127.0.0.1:8081

用 百度一下 示例吐咳。

介紹:

  • 攔截

    • 修改請(qǐng)求前數(shù)據(jù)
    • 修改請(qǐng)求后數(shù)據(jù)
  • 篩選

  • 高亮

  • 重放請(qǐng)求


3. 簡單使用示例

3.1 使用示例

正常使用用mitmdump就足夠了逻悠。所以這里主要用 mitmdump 來做一個(gè)展示元践,

后面的案例也是使用 mitmdump 去做展示。

基本操作的話童谒,那只看 常規(guī)代理 方式就可以了单旁;

操作模式:https://docs.mitmproxy.org/stable/concepts-modes/

腳本編寫:https://docs.mitmproxy.org/stable/addons-scripting/

如何工作:https://docs.mitmproxy.org/stable/concepts-howmitmproxyworks/

測試網(wǎng)站:

常用的兩個(gè)函數(shù)簡單演示:

這里介紹一下使用的比較多的兩個(gè)函數(shù),其他的可以通過官方文檔去進(jìn)行一個(gè)系統(tǒng)的學(xué)習(xí)饥伊。

def request(flow):
    pass
    
def response(flow):
    pass
  • request
common Description
request = flow.request
request.url url
request.host 域名
request.headers 請(qǐng)求頭
request.method 方式:POST象浑、GET等
request.scheme 類型:http、https
request.path 路徑琅豆,URL除域名之外的內(nèi)容
request.query 返回MultiDictView類型的數(shù)據(jù)融柬,URL的鍵值參數(shù)
request.query.keys() 獲取所有請(qǐng)求參數(shù)鍵值的鍵
request.query.values() 獲取所有請(qǐng)求參數(shù)鍵值的值
request.query.get('wd') 獲取請(qǐng)求參數(shù)中wd 鍵的值(前提是要有 wb 參數(shù)
request.query.set_all('wd', ['python']) wd 參數(shù)的值修改為 python

修改請(qǐng)求頭:

mitmDemoTwo.py

flow.request.headers['User-Agent'] = 'Mozilla/5.0'

將百度搜索修改為python:

mitmDemoThree.py

def request(flow):
    if 'https://www.baidu.com' in flow.request.url:
        # 取得請(qǐng)求參數(shù)wd的值
        print(flow.request.query.get('wd'))
        # 獲取所有請(qǐng)求參數(shù)鍵值的鍵
        print(list(flow.request.query.keys()))
        # 獲取所有請(qǐng)求參數(shù)鍵值的值
        print(list(flow.request.query.values()))
        # 修改請(qǐng)求參數(shù)
        flow.request.query.set_all('wd',['python'])
        # 打印修改過后的參數(shù)
        print(flow.request.query.get('wd'))

  • response
common Description
response = flow.response
response.status_code 響應(yīng)碼
response.text 文本(同下)
response.content Bytes類型
response.headers 響應(yīng)頭
response.cookies 響應(yīng)cookie
response.set_text() 修改響應(yīng)的文本
response.get_text() 文本(同上)
flow.response= flow.response.make(404) 響應(yīng)404

修改文本

mitmDemoFour.py

flow.response.set_text(text)

拒絕響應(yīng)

mitmDemoFour.py

# 同下
flow.response = mitmproxy.http.HTTPResponse.make(401)
# 同下
flow.response= flow.response.make(404)

拒絕響應(yīng):在百度搜索 十八禁

mitmDemoFive.py

if flow.request.query.get('wd') == '十八禁':
    flow.response = mitmproxy.http.HTTPResponse.make(
        404,                                    # (optional) status code
        b"You son of a bitch, Please leave.",   # (optional) content
        {"Content-Type": "text/html"}           # (optional) headers
    )

3.1.1 簡單應(yīng)用

需求

1. 修改請(qǐng)求(如果是搜索雷鋒,則修改為 是小菜一碟吖
2. 修改響應(yīng)(將頁面所有 Python 字眼 替換為 是小菜一碟吖
3. 如果存在少兒不宜字眼(例:十八禁趋距、迷藥等)粒氧,則拒絕響應(yīng),引導(dǎo)他向好

代碼:

mitmDemoSix.py

import mitmproxy.http
from mitmproxy import ctx


class Demo:
    def request(self, flow: mitmproxy.http.HTTPFlow):
        """Do somethings"""
        request = flow.request
        if 'https://www.baidu.com/' in request.url:
            keyword = request.query.get('wd')
            filter_words = ['迷藥', '十八禁']
            if keyword == '雷鋒':
                # 修改請(qǐng)求參數(shù)
                flow.request.query.set_all('wd', ['是小菜一碟吖'])
            if keyword in filter_words:
                flow.response = mitmproxy.http.HTTPResponse.make(
                    status_code=400,
                    content=''' <title>娘希匹=诟M舛ⅰ!</title>
                                <h1>警告R砣浮1ス丁!即將查水表</h1>
                                <h2>望你善良狼渊,愿你向上</h2>
                                <a>點(diǎn)擊跳轉(zhuǎn):</a>
                                <a  target="_blank">是小菜一碟吖的學(xué)習(xí)頻道</a>
                                ''',
                    # content="你可拉倒吧O浒尽!狈邑!查詢的什么娘希匹玩意兒3切搿!米苹!"
                    headers={"Content-Type": "text/html"}
                )

    def response(self, flow: mitmproxy.http.HTTPFlow):
        """Do somethings"""
        response = flow.response
        if flow.request.host == 'www.baidu.com':
            replace_words = ['你好', 'python', 'Python']
            text = response.get_text()
            text = list(map(lambda x: text.replace(x, '是小菜一碟吖'), replace_words))[0]
            flow.response.set_text(text=text)


addons = [
    Demo()
]

當(dāng)然糕伐,這里超綱了,也就是覺得有趣蘸嘶,就拉出來講一講良瞧。


3.2 報(bào)錯(cuò)解決

502 Bad Gateway
Certificate verification error for xxx: unable to get local issuer certificate (errno: 20, depth: 0)

網(wǎng)關(guān)證書驗(yàn)證錯(cuò)誤,解決方法有二:

  1. 執(zhí)行--ssl-insecure
  2. 下載最新的cacert.pem替換( Python安裝路徑\Lib\site-packages\certifi )的目錄證書

4. 案例展示

4.1 mitmproxy + Selenium

電腦端自動(dòng)化爬蟲

案例說明:

  • Selenium 自動(dòng)翻頁训唱,
  • mitmproxy 進(jìn)行信息采集褥蚯,
  • 在指定網(wǎng)站,輸入 指定關(guān)鍵詞 以及 爬取的頁碼數(shù)量况增,即可赞庶。

注意點(diǎn):

  • 評(píng)論數(shù)量是另外一個(gè)文件,需要另外進(jìn)行解析。
  • 返回評(píng)論適量的鏈接有兩個(gè)尘执,要區(qū)別做判斷。

selenium JD:

"""輸入關(guān)鍵詞 + 頁碼數(shù)量 Jd自動(dòng)翻頁程序"""

import time
from selenium import webdriver


class JdSpider:
    """OK"""

    def __init__(self, keyword=None, page=None):
        self.url = 'https://www.jd.com/'
        self.browser = None
        self.page = int(page)
        self.keyword = keyword

    def __del__(self):
        self.browser.close()

    def open_browser(self):
        """打開瀏覽器"""
        self.browser = webdriver.Chrome()
        # self.browser.maximize_window()
        self.browser.set_window_size(1350, 850)

    def search_keyword(self):
        '''搜索關(guān)鍵字'''
        self.browser.get(self.url)
        # 輸入內(nèi)容
        self.browser.find_element_by_xpath('//*[@id="key"]').send_keys(self.keyword)
        # 模擬點(diǎn)擊
        self.browser.find_element_by_xpath('//*[@id="search"]/div/div[2]/button').click()

    def turn_page(self):
        '''翻頁'''
        self.browser.execute_script('window.scrollTo(0,document.body.scrollHeight)')
        time.sleep(3)
        if self.browser.page_source.find('pn-next disabled') == -1:
            self.browser.find_element_by_class_name('pn-next').click()

    def main(self):
        '''函數(shù)啟動(dòng)接口'''
        self.open_browser()
        self.search_keyword()
        for count in range(self.page):
            self.turn_page()


if __name__ == '__main__':
    keyword = input("Enter the keywords to search:")
    page = input("Enter the Page to download:")
    spider = JdSpider(keyword=keyword, page=page)
    spider.main()

網(wǎng)頁解析 及 保存:

import re
import os
import csv
import json
from lxml import etree


def format_common(_list: list):
    """格式化函數(shù)"""
    _str = ''.join(_list)
    _str = _str.replace('\n', '').replace('\t', '').replace('¥', '')
    return _str


def format_state(_list: list):
    """格式化函數(shù)"""
    _str = ' '.join(_list)
    _str = _str.replace('\n', '').replace('\t', '').replace('¥', '')
    return _str


class SaveData:
    """OK"""

    def __init__(self, data):
        self.comment_data = data[0]
        self.other_data = data[1]

    def judge_exists(self, path):
        """判斷文件是否已存在"""
        if os.path.exists(path):
            return
        title = ["商鋪名稱", "說明", "價(jià)格", "評(píng)價(jià)人數(shù)", "商品名稱"]
        with open(path, 'a+', encoding='utf-8', newline='') as f:
            writer = csv.writer(f)  # 創(chuàng)建寫 對(duì)象
            writer.writerow(title)  # 寫入單行

    def save_to_csv(self, data: list):
        """保存為csv"""
        path = r'./data/JdGoodsInfo.csv'
        self.judge_exists(path)
        with open(path, 'a+', encoding='utf-8', newline='') as f:
            writer = csv.writer(f)  # 創(chuàng)建寫 對(duì)象
            writer.writerows(data)  # 寫入多行

    def parse_data(self):
        """解析網(wǎng)頁"""
        if not self.other_data or not self.comment_data:
            return

        comments_item = json.loads(re.findall("jQuery\d+\((.*?)\);", self.comment_data)[0])['CommentsCount']
        if len(comments_item) != 30:
            return

        _data = list()
        xpath_html = etree.HTML(self.other_data)
        xpath_items = xpath_html.xpath('//li[@class="gl-item"]')
        for xpath_item, comment_item in zip(xpath_items, comments_item):
            _parse = xpath_item.xpath
            shop = format_common(_parse('.//div[@class="p-shop"]//text()'))
            icons = format_state(_parse('.//div[@class="p-icons"]//text()'))
            price = format_common(_parse('.//div[@class="p-price"]//text()'))
            name = format_common(_parse('.//div[@class="p-name p-name-type-2"]//text()'))
            comment = comment_item['CommentCountStr']
            _data.append((shop, icons, price, comment, name))
        self.save_to_csv(data=_data)

    def main(self):
        """開始干活"""
        self.parse_data()

mitm代碼:

# -*- coding:utf-8 -*-
# author   : SunriseCai
# datetime : 2020/11/21 10:47
# software : PyCharm

import json
import mitmproxy.http
from mitmSaveData import SaveData


class Demo:
    def __init__(self):
        self.other_data = None

    def response(self, flow: mitmproxy.http.HTTPFlow):
        url = flow.request.url
        if 'jd.com' not in url:
            return
        # 商品信息鏈接
        if 'https://search.jd.com/s_new.php?keyword=' in url:
            self.other_data = flow.response.text or None
            # 評(píng)論鏈接
        if 'https://club.jd.com/comment' in url:
            comment_data = flow.response.text
            SaveData([comment_data, self.other_data]).main()
            comment_data, self.other_data = None, None


addons = [
    Demo(),
]

遺留問題:

  • 搜索的首頁不是 XHR 形式加載出來的宴凉,這個(gè)不想做適配了誊锭。

4.2 mitmproxy + Appium

手機(jī)端自動(dòng)化爬蟲

案例說明:

  • Appium 自動(dòng)翻頁,
  • mitmproxy 進(jìn)行信息采集弥锄,
  • 在指定 App丧靡,輸入 指定關(guān)鍵詞 以及 向下滑動(dòng)的數(shù)量次數(shù),即可籽暇。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末温治,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子戒悠,更是在濱河造成了極大的恐慌熬荆,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,843評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件绸狐,死亡現(xiàn)場離奇詭異卤恳,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)寒矿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,538評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門突琳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人符相,你說我怎么就攤上這事拆融。” “怎么了啊终?”我有些...
    開封第一講書人閱讀 163,187評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵镜豹,是天一觀的道長。 經(jīng)常有香客問我蓝牲,道長逛艰,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,264評(píng)論 1 292
  • 正文 為了忘掉前任搞旭,我火速辦了婚禮散怖,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘肄渗。我一直安慰自己镇眷,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,289評(píng)論 6 390
  • 文/花漫 我一把揭開白布翎嫡。 她就那樣靜靜地躺著欠动,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上具伍,一...
    開封第一講書人閱讀 51,231評(píng)論 1 299
  • 那天翅雏,我揣著相機(jī)與錄音,去河邊找鬼人芽。 笑死望几,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的萤厅。 我是一名探鬼主播橄抹,決...
    沈念sama閱讀 40,116評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼楼誓,長吁一口氣:“原來是場噩夢啊……” “哼疟羹!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起禀倔,我...
    開封第一講書人閱讀 38,945評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤蹋艺,失蹤者是張志新(化名)和其女友劉穎捎谨,沒想到半個(gè)月后涛救,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體检吆,經(jīng)...
    沈念sama閱讀 45,367評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡臂寝,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,581評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了帚呼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,754評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖酌儒,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情柔袁,我是刑警寧澤捶索,帶...
    沈念sama閱讀 35,458評(píng)論 5 344
  • 正文 年R本政府宣布辅甥,位于F島的核電站璃弄,受9級(jí)特大地震影響夏块,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜政己,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,068評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望果港。 院中可真熱鬧赦肃,春花似錦他宛、人聲如沸镜撩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,692評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽锯梁。三九已至,卻和暖如春合敦,著一層夾襖步出監(jiān)牢的瞬間蛤肌,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,842評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留爪膊,地道東北人权悟。 一個(gè)月前我還...
    沈念sama閱讀 47,797評(píng)論 2 369
  • 正文 我出身青樓,卻偏偏與公主長得像推盛,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子榔昔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,654評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容