1 . Primero, capturo el puerto especificado en el primer argumento:
Código:
if len(sys.argv) == 2:
pass
else:
sys.exit()
# CONSTANTS GLOBALS
global PORT_LISTEN, BUFFER_RECV, CONNECTIONS
PORT_LISTEN = int(sys.argv[1])
BUFFER_RECV = 8192
CONNECTIONS = 5
pass
else:
sys.exit()
# CONSTANTS GLOBALS
global PORT_LISTEN, BUFFER_RECV, CONNECTIONS
PORT_LISTEN = int(sys.argv[1])
BUFFER_RECV = 8192
CONNECTIONS = 5
2. Después con el puerto especificado, creo una conexion socket servidor bind(), y obtengo los datos recibidos, con ello, ejecuto un hilo, donde paso los datos de la conexion y datos a la funcion get_data.
Código:
print("[*] Listening Port "+str(PORT_LISTEN)+"....")
lister = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
lister.bind(("",PORT_LISTEN))
lister.listen(CONNECTIONS)
while True:
try:
conn, addr = lister.accept()
data = conn.recv(BUFFER_RECV)
thread_data = threading.Thread(target=get_data, name="get_data", args=(conn, addr, data))
thread_data.start()
except KeyboardInterrupt:
conn.close()
lister.close()
print("\n[\033[1;31m!\033[0m] Exiting Proxy Server....")
sys.exit()
lister = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
lister.bind(("",PORT_LISTEN))
lister.listen(CONNECTIONS)
while True:
try:
conn, addr = lister.accept()
data = conn.recv(BUFFER_RECV)
thread_data = threading.Thread(target=get_data, name="get_data", args=(conn, addr, data))
thread_data.start()
except KeyboardInterrupt:
conn.close()
lister.close()
print("\n[\033[1;31m!\033[0m] Exiting Proxy Server....")
sys.exit()
3. En la funcion get_data, obtengo la url, donde cogeré dominio donde estoy visitando
Código:
#get url
url = str(data).split('\\n')[0]
url = str(url).split(' ')[1]
#get FQDN
website = url.replace("http://","")
website = website.split("/")[0]
url = str(data).split('\\n')[0]
url = str(url).split(' ')[1]
#get FQDN
website = url.replace("http://","")
website = website.split("/")[0]
4. Una vez sé en que dominio estoy haciendo la petición, si el dominio contiene ":" cogeré el puerto especificado. Por defecto el puerto es 80, si no se detecto ":" en el dominio.
Código:
port = 80
if website.count(":") == 1:
list = website.split(":")
website = list[0]
port = list[1]
port = int(port)
print("\n\033[1;32mwebsite\033[0m: "+str(website)+" \033[1;32mport\033[0m: "+str(port))
if website.count(":") == 1:
list = website.split(":")
website = list[0]
port = list[1]
port = int(port)
print("\n\033[1;32mwebsite\033[0m: "+str(website)+" \033[1;32mport\033[0m: "+str(port))
5. Finalmente ejecuto la funcion send_data con sus argumentos, para que me haga una conexion socket cliente al servidor y envie los datos, con un bucle.
Código:
send_data(website, int(port), conn, data, addr, True)
def send_data(site, port, conn, data, addr):
sender = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sender.connect((site,port))
sender.send(data)
while True:
reply = sender.recv(8192)
if len(reply) > 0:
conn.send(reply)
else:
break
sender.close()
conn.close()
def send_data(site, port, conn, data, addr):
sender = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sender.connect((site,port))
sender.send(data)
while True:
reply = sender.recv(8192)
if len(reply) > 0:
conn.send(reply)
else:
break
sender.close()
conn.close()
Esto funciona correctamente en sitios web HTTP, pero como cabe esperar, el HTTPS no, por los certificados ssl.
Así que modifiqué el apartado 5. Y con una condicional, si el puerto es 443, ejecutará lo siguiente:
Código:
if port == 443:
send_data(website, int(port), conn, data, addr, True)
else:
send_data(website, int(port), conn, data, addr, False)
def send_data(site, port, conn, data, addr, SSL):
sender = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sender.connect((site,port))
sender.send(data)
while True:
reply = sender.recv(BUFFER_RECV)
if len(reply) > 0:
conn.send(reply)
else:
break
sender.close()
conn.close()
send_data(website, int(port), conn, data, addr, True)
else:
send_data(website, int(port), conn, data, addr, False)
def send_data(site, port, conn, data, addr, SSL):
sender = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sender.connect((site,port))
sender.send(data)
while True:
reply = sender.recv(BUFFER_RECV)
if len(reply) > 0:
conn.send(reply)
else:
break
sender.close()
conn.close()
En send_data añadí un argumento booleano llamada SSL, que antes de hacer nada, si este es True, sería https, lo que no sé muy bien, es que hacer aquí.
Me he mirado el funcionamiento de los sitios HTTPS en youtube.
En el minuto 2:16, explica con más profundidad como trabaja este protocolo. He pensado, si hay alguna forma de obtener el certificado que me da el servidor para obtener la llave publica.... pero no se muy bien.
Miré este enlace: https://soursop-dev.blogspot.com/2020/05/creacion-de-un-servidor-web-proxy-en.html
Donde te explica como hacer una conexion ssl con el modulo ssl.
Así que modifique la funcion send_data:
Código:
def send_data(site, port, conn, data, addr, SSL):
if SSL == True:
server_cert = "./ssl/sechome.csr"
client_cert = "./ssl/sechome.crt"
client_key = "./ssl/sechome.key"
context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cafile=server_cert)
context.load_cert_chain(certfile=client_cert, keyfile=client_key)
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sender = context.wrap_socket(s, server_side=False, server_hostname=site)
else:
sender = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sender.connect((site,port))
sender.send(data)
while True:
reply = sender.recv(BUFFER_RECV)
if len(reply) > 0:
conn.send(reply)
else:
break
sender.close()
conn.close()
:if SSL == True:
server_cert = "./ssl/sechome.csr"
client_cert = "./ssl/sechome.crt"
client_key = "./ssl/sechome.key"
context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cafile=server_cert)
context.load_cert_chain(certfile=client_cert, keyfile=client_key)
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sender = context.wrap_socket(s, server_side=False, server_hostname=site)
else:
sender = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sender.connect((site,port))
sender.send(data)
while True:
reply = sender.recv(BUFFER_RECV)
if len(reply) > 0:
conn.send(reply)
else:
break
sender.close()
conn.close()
Creé los certificados autofirmados:
Código:
$ cd ssl
ssl/$ openssl req -newkey rsa:2048 -nodes -keyout sechome.key -out sechome.csr -sha256
ssl/$ openssl x509 -signkey sechome.key -in sechome.csr -req -days 365 -out sechome.crt
ssl/$ openssl req -newkey rsa:2048 -nodes -keyout sechome.key -out sechome.csr -sha256
ssl/$ openssl x509 -signkey sechome.key -in sechome.csr -req -days 365 -out sechome.crt
Como bien me imaginaba esto no funciona, ya que tendría que coger el certificado que me da el dominio al hacer la peticion. No acabo de entender muy bien en las variables de crt y key, que llaves tengo que poner...
Código:
server_cert = "./ssl/sechome.csr"
client_cert = "./ssl/sechome.crt"
client_key = "./ssl/sechome.key"
client_cert = "./ssl/sechome.crt"
client_key = "./ssl/sechome.key"
CODE COMPLETE:
Código:
#!/usr/bin/python3
import socket, threading, re, sys, os
if len(sys.argv) == 2:
pass
else:
sys.exit()
# CONSTANTS GLOBALS
global PORT_LISTEN, BUFFER_RECV, CONNECTIONS
PORT_LISTEN = int(sys.argv[1])
BUFFER_RECV = 8192
CONNECTIONS = 5
def send_data(site, port, conn, data, addr, SSL):
if SSL == True:
server_cert = "./ssl/sechome.csr"
client_cert = "./ssl/sechome.crt"
client_key = "./ssl/sechome.key"
context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cafile=server_cert)
context.load_cert_chain(certfile=client_cert, keyfile=client_key)
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sender = context.wrap_socket(s, server_side=False, server_hostname=site)
else:
sender = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sender.connect((site,port))
sender.send(data)
while True:
reply = sender.recv(BUFFER_RECV)
if len(reply) > 0:
conn.send(reply)
else:
break
sender.close()
conn.close()
def get_data(conn, addr, data):
#get url
url = str(data).split('\\n')[0]
url = str(url).split(' ')[1]
#get FQDN
website = url.replace("http://","")
website = website.split("/")[0]
port = 80
if website.count(":") == 1:
list = website.split(":")
website = list[0]
port = list[1]
port = int(port)
print("\n\033[1;32mwebsite\033[0m: "+str(website)+" \033[1;32mport\033[0m: "+str(port))
if port == 443:
send_data(website, int(port), conn, data, addr, True)
else:
send_data(website, int(port), conn, data, addr, False)
print("[*] Listening Port "+str(PORT_LISTEN)+"....")
lister = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
lister.bind(("",PORT_LISTEN))
lister.listen(CONNECTIONS)
while True:
try:
conn, addr = lister.accept()
data = conn.recv(BUFFER_RECV)
thread_data = threading.Thread(target=get_data, name="get_data", args=(conn, addr, data))
thread_data.start()
except KeyboardInterrupt:
conn.close()
lister.close()
print("\n[\033[1;31m!\033[0m] Exiting Proxy Server....")
sys.exit()
import socket, threading, re, sys, os
if len(sys.argv) == 2:
pass
else:
sys.exit()
# CONSTANTS GLOBALS
global PORT_LISTEN, BUFFER_RECV, CONNECTIONS
PORT_LISTEN = int(sys.argv[1])
BUFFER_RECV = 8192
CONNECTIONS = 5
def send_data(site, port, conn, data, addr, SSL):
if SSL == True:
server_cert = "./ssl/sechome.csr"
client_cert = "./ssl/sechome.crt"
client_key = "./ssl/sechome.key"
context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cafile=server_cert)
context.load_cert_chain(certfile=client_cert, keyfile=client_key)
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sender = context.wrap_socket(s, server_side=False, server_hostname=site)
else:
sender = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sender.connect((site,port))
sender.send(data)
while True:
reply = sender.recv(BUFFER_RECV)
if len(reply) > 0:
conn.send(reply)
else:
break
sender.close()
conn.close()
def get_data(conn, addr, data):
#get url
url = str(data).split('\\n')[0]
url = str(url).split(' ')[1]
#get FQDN
website = url.replace("http://","")
website = website.split("/")[0]
port = 80
if website.count(":") == 1:
list = website.split(":")
website = list[0]
port = list[1]
port = int(port)
print("\n\033[1;32mwebsite\033[0m: "+str(website)+" \033[1;32mport\033[0m: "+str(port))
if port == 443:
send_data(website, int(port), conn, data, addr, True)
else:
send_data(website, int(port), conn, data, addr, False)
print("[*] Listening Port "+str(PORT_LISTEN)+"....")
lister = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
lister.bind(("",PORT_LISTEN))
lister.listen(CONNECTIONS)
while True:
try:
conn, addr = lister.accept()
data = conn.recv(BUFFER_RECV)
thread_data = threading.Thread(target=get_data, name="get_data", args=(conn, addr, data))
thread_data.start()
except KeyboardInterrupt:
conn.close()
lister.close()
print("\n[\033[1;31m!\033[0m] Exiting Proxy Server....")
sys.exit()