SSL上的MITM代理在与客户端的wrap_socket上挂起

时间:2016-11-28 18:51:39

标签: python sockets ssl proxy pyopenssl

我处于相当困境中,你是我最后的希望。我开始用ssl做一个MITM代理项目。我的程序使用HTTP CONNECT方法。为了保持这种简洁,我的程序遵循以下图表......

      Client          Proxy             Server
           +              +             +
  CONNECT  |              |             |
           +------------> |             |
           |              |             |
           |    200 Established         |
           |  <-----------+             |
           |              |             |
           | <----------> |             |
           |  Handshake   |             |
           |              | <---------> |
           |              |  Handshake  |
           |              |             |
           |              |             |
           | <----------> | <---------> |
           | Data Exchange| Data Exchange
           |              |             |

我的代理与客户共享证书但是我的客户端似乎无法连接,当我在接受的套接字上调用do_handshake()时,我的代理挂起wrap_socket()。这是python的一部分,客户端连接到代理...

import ssl, socket
from _thread import *
port = 8000
def run():
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind(('localhost', port))
    sock.listen(10)
    while True:
        connection, addr = sock.accept()
        data = connection.recv(8192)
        connection.send(b"HTTP/1.0 200 OK")
        connection = ssl.wrap_socket(connection, keyfile='private.pem', certfile='cacert.pem', server_side=True)
        start_new_thread(connection_string, (connection, data, addr))  # start thread to handle CONNECT

我使用Openssl模拟客户端

openssl s_client -proxy 127.0.0.1:8000 -connect www.google.com:443 -state -verify 1 -CAfile cacert.pem -verify_return_error

当客户端连接到代理时,它们都会挂起。如果我杀了我收到的客户

Traceback (most recent call last):
  File "/mitm/mitm_proxy.py", line 100, in <module>
    run()
  File “/mitm/mitm_proxy.py", line 92, in run
    connection = ssl.wrap_socket(connection, keyfile='private.pem', certfile='cacert.pem', server_side=True)
  File "/usr/lib/python3.5/ssl.py", line 1069, in wrap_socket
    ciphers=ciphers)
  File "/usr/lib/python3.5/ssl.py", line 752, in __init__
    self.do_handshake()
  File "/usr/lib/python3.5/ssl.py", line 988, in do_handshake
    self._sslobj.do_handshake()
  File "/usr/lib/python3.5/ssl.py", line 633, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLEOFError: EOF occurred in violation of protocol (_ssl.c:645)

如果我杀了我的代理,我的客户说

CONNECTED(00000003)
s_client: HTTP CONNECT failed
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 140709212149056 bytes and written 39 bytes
Verification: OK
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
---

我将我的代码与其他有效的代码进行了比较,它们基本相同,这就是我在这里的原因。我无法弄清楚什么是错的。

1 个答案:

答案 0 :(得分:1)

我不确定这是否是您问题的主要原因,但这个肯定是错误的:

    connection.send(b"HTTP/1.0 200 OK")

服务器的正确响应应该是以\r\n,可选key:value\r\n对结尾的状态行,然后是\r\n以标记HTTP标头的结尾,即最低限度:< / p>

    connection.send(b"HTTP/1.0 200 OK\r\n\r\n")

由于客户端没有收到丢失的\r\n\r\n,它可能会等待它并且不启动TLS握手(即发送ClientHello)。服务器将等待客户端开始握手,这样两者将永远等待彼此。

除了你没有遵循标准openssl s_client -proxy ...似乎也没有遵循标准。它实际上需要响应来包含&#34;已建立的#34;如以下摘自OpenSSL 1.1.0c中apps / s_client.c中的惰性HTTP解析代码所示:

case PROTO_CONNECT:
        ...
        BIO_printf(fbio, "CONNECT %s HTTP/1.0\r\n\r\n", connectstr);
        (void)BIO_flush(fbio);
        /* wait for multi-line response to end CONNECT response */
        do {
            mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ);
            if (strstr(mbuf, "200") != NULL
                && strstr(mbuf, "established") != NULL)
                foundit++;
        } while (mbuf_len > 3 && foundit == 0);

请尝试使用以下行:

    connection.send(b"HTTP/1.0 200 established\r\n\r\n")
相关问题