Add HTTPS decryption (Experimental)

This commit is contained in:
Namhyeon Go 2022-11-25 17:12:58 +09:00
parent 1105633d9d
commit 20bda58945
5 changed files with 142 additions and 40 deletions

View File

@ -15,7 +15,11 @@ HTTP proxy over the web hosting!
``` ```
[settings] [settings]
PORT=5555 PORT=5555
PROXY_URL=http://example.org SERVER_URL=http://example.org
CA_KEY=ca.key
CA_CERT=ca.crt
CERT_KEY=cert.key
CERT_DIR=certs/
``` ```
2. Run `python server.py` and set HTTP proxy in your web browser (e.g. Firefox) 2. Run `python server.py` and set HTTP proxy in your web browser (e.g. Firefox)

19
ca.crt Normal file
View File

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDFzCCAf+gAwIBAgIUIAYwMh8vYN/qC9An+j30JshXQjkwDQYJKoZIhvcNAQEL
BQAwGzEZMBcGA1UEAwwQcGhwLWh0dHBwcm94eSBDQTAeFw0yMjExMjUwNjE1MTla
Fw0zMjExMjIwNjE1MTlaMBsxGTAXBgNVBAMMEHBocC1odHRwcHJveHkgQ0EwggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCxyrzGXNu+2Vs9ll36RMnOOcHH
thQqGg9qOJj2wdH3kvOWviIDSn4qOGA2Ff+719AtB24pIS1XdqW2TMXPwjuh+T3Z
WeYMpUlaOhWgP4Kx5Auc9num9MFqS1Mf8S4t8ZTgt5/XFC8QOW4hKEe8ZFSZ6MTA
TXbKAl0G0fFVhDzPxcvjtE+u1GFXkSv2nq+2iZ3gajqdvoTmPwgrhtaiep6Pg+KV
8CvHMsvhBtGluvPo7IHI0opx1fhkcZbHsu3r1ZD/TRWvYvA4BkH9g5hXoi88eakF
fsruzWjmnHzMVxOX7thECinOKs7iv0hR6TOY4wlgbqhK3Phas/iPUL5FoIIbAgMB
AAGjUzBRMB0GA1UdDgQWBBSzqXvDv/BeSLGduMqiBXcp9bJjmjAfBgNVHSMEGDAW
gBSzqXvDv/BeSLGduMqiBXcp9bJjmjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3
DQEBCwUAA4IBAQArNyClOJJkKhn7Wp3zH89SoVZQJUdvXZ52XKSnBp4f4XDUuqz/
3PAE4G22uqUOkgcM+3B46HNn1OxG4/7DHcG2LfXQD3DxF56cj5ljkJRZ8CTuM01V
PqkRtncWakaoFLcvhw7SB95x9VpTZqnh8TSX/NU+YnjyAsBWdyVYUIG0xSEILzLL
jUVr94SQI9jNu5wKbC4rQY++fIAgXMJ9CdiWEWPm6wRPH0TFia+FRHmtTaqq/2DR
LF6UBDBvsFs/Z4IDq2htGqYXrkdjf6VdUGJEJLj4lJubUzcowGM6a4lbIOdhollK
fjh9nl7i86XUxIknkA7HzImH7TJOdsNBqFEz
-----END CERTIFICATE-----

28
ca.key Normal file
View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCxyrzGXNu+2Vs9
ll36RMnOOcHHthQqGg9qOJj2wdH3kvOWviIDSn4qOGA2Ff+719AtB24pIS1XdqW2
TMXPwjuh+T3ZWeYMpUlaOhWgP4Kx5Auc9num9MFqS1Mf8S4t8ZTgt5/XFC8QOW4h
KEe8ZFSZ6MTATXbKAl0G0fFVhDzPxcvjtE+u1GFXkSv2nq+2iZ3gajqdvoTmPwgr
htaiep6Pg+KV8CvHMsvhBtGluvPo7IHI0opx1fhkcZbHsu3r1ZD/TRWvYvA4BkH9
g5hXoi88eakFfsruzWjmnHzMVxOX7thECinOKs7iv0hR6TOY4wlgbqhK3Phas/iP
UL5FoIIbAgMBAAECggEARv1kku/Q7ktrmxPHQn7k9WsqbMvPEWCGdytSKHULmYcb
rD0O57F+3uzTvcTa7+4kOVaWLeYJbLr7P+c3tNUhanNSts6mhLYaq+Q1bl7tmIot
+OaSSP/BmueosUBj6ARmJbQsJnzwrdHAn4yt2BNXlHzU0tQbcl2vN2HssvCyN2Nf
T1TrpYQmchnEhwHudZP29nlmm1BbiNzEDEzvSdBDJiawZJWwiIZ8PNfQKZawiZst
SCid2hMU3aA7MfxVLSsMudZZM0PawvnEVErdJMVGhTjlWtCgxXvNv0S8qPDpdJHz
qyr1c1l+l1nt/4VvmElIyRq/MDPyss0e6w/8Ij4tAQKBgQC7YmuKMV3rQr39xB8t
EgWDbcIObI/uAOO/N56B4XlExFRSWB5pqjNpKXDukoASDHSWaWHAgVsjrOnhbtrk
32c8rBA4+SMXG8OV6w3G3qjVwJyOdgpo7s0DzR1k+N2VV1qy4/9Jl7LMK8GcvSQK
TceDdPluTJGICdUWOKW37ZRA8QKBgQDy5Rttf3/kczVqI7iq3/j8DsoC0qZYCdMO
8vVxuUL3HnCxZKgmdu6XMwuz8l7c2XVE87E4G6wRrWJeX+RowAsmplLTEdi3T968
hsSJjUyC8GdexRW6JKmRrgQuT3e/eGzvApv4aanYcbj7FSrBicm6LSorQD16vLg0
g3IOijEzywKBgQCk+VKauTnp3bntyJR2Fs651pEqJ9RUA35/pFUuHjepHnzqfmBQ
QSPAK1cdA+gze7nNjvwcAwcdkqfa7MFVDYcTuJ0Tu+xz9OKug+J+OxxEDK8JEc26
crwW46hEdIKJb/4PT4I75Y3qCYANIcywMag9CWhs/oaGUbnENZ1ZIJcM0QKBgBlc
mMePJ5B4AxzJDBAzgLD47ljrG9lXdUU7UyuDt51L/WJYa0JQ6sq41sD8TrFqt1by
xw9fvFDANOQ7yQKzArcPaNiHJYTGfzBaNg1SxqlpZrG7jHA6QcZnUCJxw8QnU+CE
+jou9kAWZ8U3yZYZyAl7i8qmU4UMTYOWMgOYpFiPAoGATiYTE9NA8kQRzvKLYTbj
L+oGSNlFrCFu3F2CrN6Czitzko8V8kjiBC8Ei3jBiHg3kU/lmAA8mO3zamzhSus3
qM/yY7bL2hrRFoNMZ4oH0VzPeb2z/SPy+slI0peKabJ4ig9qsQAc/D2kesuGPC+J
6xc1CD1cKRe/zST99+z+J4M=
-----END PRIVATE KEY-----

28
cert.key Normal file
View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEuwIBADANBgkqhkiG9w0BAQEFAASCBKUwggShAgEAAoIBAQC05OxXm2Icl3JU
5HrPWso+xtLj8xqwtTtIu4yDrr2X3SDWUZFhd1loB5rV817ZNr74ow8uU0FTz8x5
BcQTvMJawomuBjX0Xq4HQFpLJOxOssqu0nqcdn/9UdD8scj+0odhhwb1KsAVTZo0
mJAK2jlXNTy33BY24xu2Dn3wASux0FATwlrEoJ7F4K8wVRO8T0CqW7iDDBTb2a9Y
ytwpQCj2lsuWac5BmvqPD63yCYVd6TnVcTEIRVbqOCrwjNXnhIXKLMqRF+Iiihjv
yMyew5fFCmeNea9OZRlqMHWLuDPi0crfI26X3XJOUIgC97Dxb4swGMsVXUGCX1W9
GNWeSUWpAgMBAAECgf88VVlDkEEBlwt3bG519YNXu5ZMcRew7CPtgMerwYi14wsQ
vzeWrPzWK9qMbdq+l/oGVjUIyEXGmsNJS2fzLVC5Q4u74bjiF0+lQuUpjXXhGIXj
8J5+VfQLnT4+bHAnUq4jim+MkQRsPev1xk8xAKupL3rpiRwHCxr37KJjQu0BJeg7
H80VPHpPLH9RANjCMer0Y6ZeyR2adjf3WVheA91c8wKiGbkIV3cN7rO4VImya/0P
bXqmdgDGoSoRRRLgG3U5QDA5oMEwALXdS67TfwgtrhGsHxfsQ8yhGvG7UyjKf7iu
Yy/tkosR7Ly+tAmp1arP6kfW+1u/h4dGyhrVPhkCgYEA+9rhEy/p3nDlvKjXRx2J
1tWWkBtIY7OZuYyDdpowSh5FODiDIZZycttqzNhqmJWsSwZm0y24+awwzSNLFzlK
mC6IoXHeLjqXovPUsjSFf0GML6YNuFKxF5LKFdl/MuyfomaHhK8CIG2TVasxGa63
L12K3GVb2i0xB7XtIpXYnYcCgYEAt98SE8J/VUxWoFa2C5q5svQjSaUwtRCb0te5
FiZtu871lna1LLsb98D7Z3JRHvpn2cJ96OvLcYUC7tq3LHyPL0SlAEHoz+eFcrE2
CXHHDfUim6IfZ9v0fnf5aS301UF7zq1T4+PPwlgvtLeM5JNcur+C0ISNQ3jNw4oj
aA6MT08CgYEA8kVMTAvEOjF6HfCBHizhAqN18Wv9R8Nl9iKf98A9AZ960Kk0I2Q4
9hnx89mfOOaJ1aXz1eNe0/X6/+qael2nTxs8XalOpEPCyIMrsL1rSc4BD3j6K7yI
FHglI72UaaVLropYhJ9hOVaO61MBqYXzO4INaROrtwXP623rDmD8/hMCgYB4Lxms
ysPaKESzFxp06VSaERQDrjLxFwMTRKgZP1MYoEVMbRktPLwiLATn8APwILLC1mrg
VUesUsnBADscm+ondlH3oh0fz/AdMJHmiHUYvXM6kTS/+TiNdbQTuNNAlUXsqMSd
v6lsGaJNGHDCc0P4WPeTfiCryomMV32fJWs25wKBgA8B0ZZTmefhaS5AJfPcewJj
JzS+6HPdEGkDMbCMT5JvUrrRbYxBlnkG3FaYIw5gKib2pKaZBIWiCAN222xlyo+H
h2BUyy3NFCdOQ+7qm7hhKYqcbAsnPmfT2OowP0icE8qmXWBMWSMI/ihVZ5XQKdTp
pdM4tpCckvB/T0XZkl7x
-----END PRIVATE KEY-----

View File

@ -11,6 +11,8 @@ from _thread import *
import base64 import base64
import json import json
import ssl import ssl
import time
from subprocess import Popen, PIPE
from datetime import datetime from datetime import datetime
from platform import python_version from platform import python_version
@ -34,6 +36,11 @@ args = parser.parse_args()
max_connection = args.max_conn max_connection = args.max_conn
buffer_size = args.buffer_size buffer_size = args.buffer_size
cakey = config('CA_KEY')
cacert = config('CA_CERT')
certkey = config('CERT_KEY')
certdir = config('CERT_DIR')
def start(): #Main Program def start(): #Main Program
try: try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@ -49,14 +56,13 @@ def start(): #Main Program
try: try:
conn, addr = sock.accept() #Accept connection from client browser conn, addr = sock.accept() #Accept connection from client browser
data = conn.recv(buffer_size) #Recieve client data data = conn.recv(buffer_size) #Recieve client data
start_new_thread(conn_string, (conn,data, addr)) #Starting a thread start_new_thread(conn_string, (conn, data, addr)) #Starting a thread
except KeyboardInterrupt: except KeyboardInterrupt:
sock.close() sock.close()
print("\n[*] Graceful Shutdown") print("\n[*] Graceful Shutdown")
sys.exit(1) sys.exit(1)
def conn_string(conn, data, addr): def conn_string(conn, data, addr):
try:
first_line = data.split(b'\n')[0] first_line = data.split(b'\n')[0]
method, url = first_line.split()[0:2] method, url = first_line.split()[0:2]
@ -86,23 +92,40 @@ def conn_string(conn, data, addr):
scheme = b'https' scheme = b'https'
proxy_server(webserver, port, scheme, method, url, conn, addr, data) proxy_server(webserver, port, scheme, method, url, conn, addr, data)
except Exception as e:
print("[*] Warning: %s, Line %s" % (str(e), str(sys.exc_info()[-1].tb_lineno)))
def proxy_connect(webserver, conn): def proxy_connect(webserver, conn):
# TODO hostname = webserver.decode('utf-8')
certpath = "%s/%s.crt" % (certdir.rstrip('/'), hostname)
conn.send(b'HTTP/1.1 200 Connection Established\r\n')
try:
if not os.path.isfile(certpath):
epoch = "%d" % (time.time() * 1000)
p1 = Popen(["openssl", "req", "-new", "-key", certkey, "-subj", "/CN=%s" % hostname], stdout=PIPE)
p2 = Popen(["openssl", "x509", "-req", "-days", "3650", "-CA", cacert, "-CAkey", cakey, "-set_serial", epoch, "-out", certpath], stdin=p1.stdout, stderr=PIPE)
p2.communicate()
except Exception as e:
print("[*] Skipped generating the key. %s" % (str(e)))
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.load_cert_chain(certpath, certkey)
# what the heck? why hang?
conn = context.wrap_socket(conn, server_side=True)
return conn return conn
def proxy_server(webserver, port, scheme, method, url, conn, addr, data): def proxy_server(webserver, port, scheme, method, url, conn, addr, data):
try: try:
print("[*] Started Request. %s" % (str(addr[0]))) print("[*] Started Request. %s" % (str(addr[0])))
if scheme == b'https' and method == b'CONNECT': if scheme in [b'https', b'tls', b'ssl'] and method == b'CONNECT':
conn = proxy_connect(conn, url) conn = proxy_connect(webserver, conn)
data = { proxy_data = {
'headers': { 'headers': {
"User-Agent": "php-httpproxy/0.1.2 (Client; Python " + python_version() + ")", "User-Agent": "php-httpproxy/0.1.3-dev (Client; Python " + python_version() + ")",
}, },
'data': { 'data': {
"data": base64.b64encode(data).decode("utf-8"), "data": base64.b64encode(data).decode("utf-8"),
@ -116,12 +139,14 @@ def proxy_server(webserver, port, scheme, method, url, conn, addr, data):
"datetime": datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f") "datetime": datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
} }
} }
raw_data = json.dumps(data['data']) print (proxy_data)
raw_data = json.dumps(proxy_data['data'])
print("[*] Sending %s bytes..." % (str(len(raw_data)))) print("[*] Sending %s bytes..." % (str(len(raw_data))))
i = 0 i = 0
relay = requests.post(server_url, headers=data['headers'], data=raw_data, stream=True) relay = requests.post(server_url, headers=proxy_data['headers'], data=raw_data, stream=True)
for chunk in relay.iter_content(chunk_size=buffer_size): for chunk in relay.iter_content(chunk_size=buffer_size):
conn.send(chunk) conn.send(chunk)
i = i + 1 i = i + 1
@ -130,11 +155,9 @@ def proxy_server(webserver, port, scheme, method, url, conn, addr, data):
print("[*] Request Done. %s" % (str(addr[0]))) print("[*] Request Done. %s" % (str(addr[0])))
conn.close() conn.close()
except socket.error: except Exception as e:
sock.close() print("[*] f: proxy_server: %s" % (str(e)))
conn.close() conn.close()
print(sock.error)
sys.exit(1)
if __name__== "__main__": if __name__== "__main__":
start() start()