You can find the code for this project here
Zeruel Devlog 1
Hi there! lately I have been working on a personal project I had the idea for some years ago. I thought it would be a good exercise since I’m getting back into software development and cybersecurity to try and finish a Burpsuite-like tool I’ve always wanted to make, Zeruel Proxy.
The idea is simple, create a proxy capable of intercepting, modifying, and repeating requests on the fly. All through a simple GUI.
I had already written a good portion of the GUI using tkinter
some years ago. So all that was left to do was write the proxy and the logic between the 2.
Proxy
Writing an HTTP MITM proxy to serve the aforementioned purpose is quite straight forward.
When writing the proxy I decided to use sockets, admittedly I could’ve probably used some sort of wrapper like http.server to make my life easier but I like a challenge!
HTTP
First things first, let’s setup our proxy server to capture and forward our requests to the remote server.
In the code above a socket is created and it’s options are set so that it can be reused for new socket bindings rapidly, then it is bound to 127.0.0.1
and the desired port, I’ve decided to default the port to 7121
for Zeruel.
If no exceptions are raised then handle_client()
is called.
First the proxy must accept incoming connections from the browser
If a connection is succesfully achieved the proxy can begin to receive data through the new socket through which the server can communicate with the client, while the old socket stays open listening for new connections.
The received data is then passed to the parser, which returns a dictionary that is then used to forward the request to the remote server.
In the code above a new socket is created for the remote connection, the request we got from the browser (which is passed as the data
arg) is then forwarded to the remote host. Then, once a response if received from the remote host, it is sent back through the client socket to the browser.
HTTPS
HTTPS is a bit trickier since we need to be able to decrypt the incoming requests from the browser to be able to display and modify them before they’re sent out as well as being able to decrypt any requests sent back from the remote target server.
To achieve this we first need to understand how HTTPS works so let’s take a look.
To implement HTTP/TLS we only really need to understand these terms and ideas:
Certificate: A document used to prove the validity of a public key. It contains information about it’s owner (also known as the subject) and a signature of the entity that has verified the certificate’s contents (called the issuer).
Certificate Authority: A CA is an entity that stores, signs and, issues certificates. Usually browsers have a set of trusted CA certificates and will let you install certificates of your own (very important later on!)
Public key: This key is shared openly, it’s used to encrypt data or verify a digital signature.
Private key: This key is to be kept secret, hence the ‘Private’. it is used to decrypt data encrypted with the public key or to create a digital signature.
Whenever you visit a site using HTTPS a certificate containing a public key signed by the CA is sent to the browser. The browser then must validate the certificate by referring to its trusted CAs and their public keys.
Your browser will then, assuming the CA is trusted, create a new private key encrypted with the public key signed by the CA.
From then on the server and browser both have this new private key, which will be used to encrypt communication between the two.
To better illustrate this process here’s a simplified diagram:
Man-In-The-Middle
The process described above is what prevents any 3rd party sniffing out requests from gathering any sensitive data from the HTTPS requests, as they can only be decrypted using the private key. But the proxy needs to be able to decrypt this data in order to modify it as well as re-encrypt it for it to be sent out to the target server.
In the case of google.com
we would need to have access to Google CA’s private key in order to:
- Be able to even visit the site without our browser screaming at us telling us it doesn’t trust our proxy because our certificate is invalid.
- Be able to decrypt any request passing through our proxy.
Suffice to say, would be quite difficult getting our hands on Google CA’s private key.
However, there is one way we can circumvent all of this trouble and it’s by using self-signed certificates!
Anyone can become their own CA, create key pairs, and sign certificates. It’s quite simple really, this is how Zeruel’s CA certificate is created using OpenSSL
openssl genrsa -out zeruelCA.key 2048 # Generate private key
openssl req -new -x509 -days 3650 -key zeruelCA.key -out zeruelCA.crt -subj “/CN=zeruelproxy CA/C=US” # Create self-signed certificate
NOTE: If you want a more detailed guide on how to setup your own CA I highly recommend reading through this gist
This new certificate can now be installed in our browser so that it is trusted and we can move on to the next challenge.
The proxy server must essentially impersonate every CA out there, which means that it needs to generate and sign certificates for each host we visit from the browser.
For that, it needs to…
Generate a new key pair
Create a Certificate Signing Request (CSR)
Finally, generate the certificate
The proxy is now able to generate certificates for each host dynamically and can now handle HTTPS connections between it and the browser. Because we are our own CA and have access to the private key the proxy is able to decrypt all incoming data from the browser.
Now that the proxy can view and modify the cleartext request we can simply forward out version of it out to the remote server and get a response back!
So far this project has taught me quite a lot and has made me appreciate the work that has gone into creating the protocols and tools I use every day, and I’m sure there’s plenty more I can learn from it. There’s much to be done still from optimizations and bug fixing to adding more features to play around with requests. I hope you found this devlog to be informative/helpful! I plan to write part 2 of this in the near future so stay tuned!