SSL 上的 MITM 代理在 wrap_socket 上与客户端挂起
MITM proxy over SSL hangs on wrap_socket with client
我很为难,你是我最后的希望。我开始做一个使用 ssl 制作 MITM 代理的项目。我的程序使用 HTTP CONNECT
方法。为了保持简洁,我的程序遵循下图......
Client Proxy Server
+ + +
CONNECT | | |
+------------> | |
| | |
| 200 Established |
| <-----------+ |
| | |
| <----------> | |
| Handshake | |
| | <---------> |
| | Handshake |
| | |
| | |
| <----------> | <---------> |
| Data Exchange| Data Exchange
| | |
我的代理与客户端共享一个证书,但是当我在接受的套接字上调用 wrap_socket()
时,我的客户端似乎无法连接并且我的代理挂在 do_handshake()
上。这是 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
---
我已经将我的代码与其他有效的代码进行了比较,它们本质上是相同的,这就是我来这里的原因。我不知道出了什么问题。
我不确定这是否是您遇到问题的主要原因,但这一个肯定是错误的:
connection.send(b"HTTP/1.0 200 OK")
服务器的正确响应应该是以\r\n
结尾的状态行,可选的key:value\r\n
对,然后是\r\n
来标记HTTP的结束header,即最低限度:
connection.send(b"HTTP/1.0 200 OK\r\n\r\n")
由于客户端没有收到丢失的 \r\n\r\n
,它可能会等待它并且不会启动 TLS 握手(即发送 ClientHello)。服务器将等待客户端开始握手,这样双方将永远等待对方。
除了你不符合标准外openssl s_client -proxy ...
好像也不符合标准。它实际上需要响应包含单词 "established" 如下摘自 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")
我很为难,你是我最后的希望。我开始做一个使用 ssl 制作 MITM 代理的项目。我的程序使用 HTTP CONNECT
方法。为了保持简洁,我的程序遵循下图......
Client Proxy Server
+ + +
CONNECT | | |
+------------> | |
| | |
| 200 Established |
| <-----------+ |
| | |
| <----------> | |
| Handshake | |
| | <---------> |
| | Handshake |
| | |
| | |
| <----------> | <---------> |
| Data Exchange| Data Exchange
| | |
我的代理与客户端共享一个证书,但是当我在接受的套接字上调用 wrap_socket()
时,我的客户端似乎无法连接并且我的代理挂在 do_handshake()
上。这是 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
---
我已经将我的代码与其他有效的代码进行了比较,它们本质上是相同的,这就是我来这里的原因。我不知道出了什么问题。
我不确定这是否是您遇到问题的主要原因,但这一个肯定是错误的:
connection.send(b"HTTP/1.0 200 OK")
服务器的正确响应应该是以\r\n
结尾的状态行,可选的key:value\r\n
对,然后是\r\n
来标记HTTP的结束header,即最低限度:
connection.send(b"HTTP/1.0 200 OK\r\n\r\n")
由于客户端没有收到丢失的 \r\n\r\n
,它可能会等待它并且不会启动 TLS 握手(即发送 ClientHello)。服务器将等待客户端开始握手,这样双方将永远等待对方。
除了你不符合标准外openssl s_client -proxy ...
好像也不符合标准。它实际上需要响应包含单词 "established" 如下摘自 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")