MENU

http+https代理拦截数据包(混合代理)

August 15, 2016 • Security

前言

HTTP和HTTPS混合代理,这个代理保留了content_deal函数,通过这个函数,可以保存所有的请求,或者在这个函数里面处理所有请求。

同时,还保留了res_deal函数,通过这个函数可以编辑返回的http包,这里编辑的包是http返回包,str类型。

使用

由于可以走http流量,所以肯定要本地生成个:

openssl req -new -x509 -days 365 -nodes -out key.crt -keyout key.pem

如果中间f12中有任何飘红的现象的话,基本就是http证书不被信任的原因。点击进去,信任就好了。

运行

python mix_proxy.py (default 127.0.0.1) port
python mix_proxy.py bind_address port

示例:

python mix_proxy.py 10086
python mix_proxy.py 127.0.0.1 10086

Code:

#!/usr/bin/env python
#coding: utf-8
import os
import re
import ssl
import sys
import time
import json
import base64
import socket
import urlparse
import warnings
import requests
import threading
from hashlib import md5
 
 
warnings.filterwarnings("ignore")
 
'''
Mix proxy with HTTP and HTTPS.
Use local key file and cert file to get http flow.
If there is a "connect" method first, then http it is.
Else it's a http packet.
Request to remote server with python requests lib.
Function content_deal() is with a hook which can edit or save requests to somewhere.
Function res_deal() is whith a hook which can edit response to client.
'''
 
 
def http_things(sock):
    context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
    context.load_cert_chain(certfile = "key.crt", keyfile = "key.pem")
    connstream = context.wrap_socket(sock, server_side=True)
    client_conn(connstream, True)
 
 
def print_help():
    print 'Usage:'
    print '    python %s (default 127.0.0.1) port' % sys.argv[0]
    print '    python %s bind_address port'        % sys.argv[0]
    print 'Example:'
    print '    python %s 10086'                    % sys.argv[0]
    print '    python %s 127.0.0.1 10086'          % sys.argv[0]
    exit()
 
 
def get_str(res):
    code = str(res.status_code)
    reason = res.reason
    data = ''
    headers = res.headers
    if 'Content-Encoding' in headers.keys():
        del headers['Content-Encoding']
    if 'Transfer-Encoding' in headers.keys():
        del headers['Transfer-Encoding']
    headers['Content-Length'] = len(res.content)
    data += 'HTTP/1.1 %s %s\r\n' % (code, reason)
    for key in res.headers.keys():
        data += '%s: %s\r\n' % (key, headers[key])
    data += '\r\n' + res.content
    return data
 
 
def get_res(data, connstream, http):
    try:
        headers = {}
        post = ''
        if data[0:7] == 'CONNECT':
            connstream.sendall("HTTP/1.1 200 Connection established\r\n\r\n")
            http_things(connstream)
            return
        if not re.search('(GET|POST) (.*) HTTP',data):
            return
 
        methods = re.findall('(GET|POST) (.*) HTTP',data)[0]
        url = methods[1]
        method = methods[0]
 
        if method == 'GET':
            head = data.split('\r\n')[1:]
            for h in head:
                if ': ' in h[2:]:
                    headers[h.split(': ')[0]] = h.split(': ')[1]
            host = headers['Host'].replace(' ', '')
 
            if not http:
                uri = url
            else:
                uri = "http://%s%s" % (host, url)
            print uri
            content_deal(headers, host, method, postdata = '', uri = uri)
 
            if 'Host' in headers.keys():
                del headers['Host']
 
            res = requests.get(uri, headers = headers, verify = False)
            response = get_str(res)
            response = res_deal(response)
            connstream.sendall(response)
            connstream.close()
            return
 
        elif method == 'POST':
            body = data.split('\r\n\r\n')[1]
            head = data.split('\r\n\r\n')[0].split('\r\n')[1:]
            for h in head:
                if ': ' in h[2:]:
                    headers[h.split(': ')[0]] = h.split(': ')[1]
            host = headers['Host'].replase(' ', '')
 
            if not http:
                uri = url
            else:
                uri = "http://%s%s" % (host, url)
            print uri
            content_deal(headers, host, method, postdata = body, uri = uri)
 
            if 'Host' in headers.keys():
                del headers['Host']
 
            res = requests.post(uri, headers = headers, data = body, verify = False)
            response = get_str(res)
            response = res_deal(response)
            connstream.sendall(response)
            connstream.close()
            return
 
    except Exception, e:
        if 'url' in dir():
            print url
        print "Http Error: " + str(e)
        try:
            err  = "HTTP/1.1 500 Internal Server Error\r\n"
            err += "Content-Length-Type: text/html;\r\n"
            err += "Content-Length: 17\r\n\r\n"
            err += "HTTP Error"
            connstream.sendall()
            connstream.close()
        except Exception, e:
            pass
        finally:
            return 
 
def res_deal(response):
    return response
 
def content_deal(headers, host, method, postdata, uri):
    pass
 
def client_conn(connstream, http=False):
    try:
        connstream.settimeout(0.5)
        data = ""
        while True:
            tmp = connstream.recv(10240)
            data += tmp
            if tmp == '':
                break
    except Exception, e:
        pass
    connstream.settimeout(10)
    get_res(data, connstream, http)
 
 
def main(addr, port):
    try:
        bindsocket = socket.socket()
        bindsocket.bind((addr, port))
        bindsocket.listen(300)
    except Exception, e: 
        print e
        exit()
 
    while True:
        try:
            connstream, fromaddr = bindsocket.accept()
            t = threading.Thread(target = client_conn, args = (connstream,))
            t.start()
        except Exception, e:
            print e
            if 'connstream' in dir():
                connstream.close()
 
 
if __name__ == '__main__':
    port = 10086
    addr = '127.0.0.1'
    if len(sys.argv) == 1:
        print_help()
    if len(sys.argv) == 2:
        port = int(sys.argv[1])
    if len(sys.argv) >= 3:
        port = int(sys.argv[2])
        address = sys.argv[1]
    main(addr, port)

我本地随便生成的一对密钥对:

key.crt:

-----BEGIN CERTIFICATE-----
MIIDNzCCAqCgAwIBAgIJANOmV9H+R86YMA0GCSqGSIb3DQEBBQUAMHExCzAJBgNV
BAYTAjEyMQ0wCwYDVQQIEwR0ZXN0MQwwCgYDVQQHEwNmYXMxDjAMBgNVBAoTBWZm
YXNkMQwwCgYDVQQLEwNmYXMxDDAKBgNVBAMTA2ZhczEZMBcGCSqGSIb3DQEJARYK
ZmFzQHFxLmNvbTAeFw0xNjA3MjcwNDIzMjlaFw0xNzA3MjcwNDIzMjlaMHExCzAJ
BgNVBAYTAjEyMQ0wCwYDVQQIEwR0ZXN0MQwwCgYDVQQHEwNmYXMxDjAMBgNVBAoT
BWZmYXNkMQwwCgYDVQQLEwNmYXMxDDAKBgNVBAMTA2ZhczEZMBcGCSqGSIb3DQEJ
ARYKZmFzQHFxLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEArxT6CREF
8DNx0XIjwTvhWD2IOMy8T4J8WXRwLO9eaxhrVh4pqtfTT28pE4CKMXXxV22FIpMv
jygJN0To4XiFmRVO/7M45QpomZ3P20Yvsxl0H7FKctTtnfjXtoJUsADjlmX/h7yZ
lwbbVUhh2t4YeRmbUBI4KnKuML9xpG1wmbcCAwEAAaOB1jCB0zAdBgNVHQ4EFgQU
Uq+kj5r85A4MHBniudXWf5SsJagwgaMGA1UdIwSBmzCBmIAUUq+kj5r85A4MHBni
udXWf5SsJaihdaRzMHExCzAJBgNVBAYTAjEyMQ0wCwYDVQQIEwR0ZXN0MQwwCgYD
VQQHEwNmYXMxDjAMBgNVBAoTBWZmYXNkMQwwCgYDVQQLEwNmYXMxDDAKBgNVBAMT
A2ZhczEZMBcGCSqGSIb3DQEJARYKZmFzQHFxLmNvbYIJANOmV9H+R86YMAwGA1Ud
EwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAh1Fd/JA8k1XEPYtmcMGSM0lEHW0p
3CO+vdWBj5OiuOM447vvIaUfjFXooOwgz3bwDRsITcJsPLJZ/joemFjbeNksLexl
yqBEKlA/MTPDr1Ksy0RkOeMakzbMGspwcwTQ8KSsfqnM67h/rXX4AEX2AO1WJCng
2T82Nin2DaHlwuM=
-----END CERTIFICATE-----

key.pem:

-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCvFPoJEQXwM3HRciPBO+FYPYg4zLxPgnxZdHAs715rGGtWHimq
19NPbykTgIoxdfFXbYUiky+PKAk3ROjheIWZFU7/szjlCmiZnc/bRi+zGXQfsUpy
1O2d+Ne2glSwAOOWZf+HvJmXBttVSGHa3hh5GZtQEjgqcq4wv3GkbXCZtwIDAQAB
AoGBAI6eLsL96/FrZpavPHLmnTys+u8Rz3+REkwoLkxcPHROsvi2n0h8gLQfH720
Il4B7jNCkoXEkaQyf7dW2cD41RGyB4wJWjofobZ8vgQL2mV/snt/dH6WvGu5Kv25
z9oDvHZqP7ERpG0v6Z/diEjXhOTV6k77aCYoAysxI5RUY64ZAkEA233eVg51tQwp
YpGERVRCRLHLDoBDJiiRcSo3vsOtYKz575K9blWSGkzNg4XT8nsp3a+DlvW8yQfq
q9fXk7FHTQJBAMw0Gys3UVbUScLKmGwVgE9fIgpYcygymLvWkWFkp3B5KQ8ZVJQD
AmoZnG+rVodr71F8L/efH+oyvjo88NIYCxMCQENbjS+7oEO/R7QIFB9yjCOorDf3
BKRhLsEbw5+3TS2t58WtspR5jiykBS2nlDOFuINfqXJaV2UaGNpDktSwQsECQEFj
pheOnTNKw1vm+CwULoQ8GHBrpmSG3zW3HdKsIpn3klhNajIDTLChBuETYp/2xim3
tLx8bgHWwedwQEVmgZUCQC3lhI2zqj8m7KWMTTGONW5mZhwPOgcaiqafFvb6ipic
+ZTbwiRhREzfm4BPDEQAW68O1ZrI9eobXjxrTyza3Zo=
-----END RSA PRIVATE KEY-----

项目地址

http://github.com/rangeme/mix_proxy/

from:http://www.mottoin.com/87197.html

Archives QR Code
QR Code for this page
Tipping QR Code