Setting up mitmproxy and wireguard using mitmproxy's python API

223 views Asked by At

I'm trying to configure a mitmproxy instance to use wireguard to route through a remote server, where the data is processed with an Addon(). Essentially I would like to run the following command with custom keys through python:

mitmdump -s addon.py --mode wireguard

But to use my own keys/etc, I'd prefer to pass it through the python API (theoretically I could add it to /etc/wireguard/wg0.conf but I've had mixed results). I've had a hard time understanding how to use it though, as I've only had bits and pieces of code to go by. This is what I have so far:

wg_server = await mitmproxy_wireguard.start_server(
    "0.0.0.0",
    51820,
    server_privkey,
    [client_pubkey],
    handle_connection,
    receive_datagram,
)

options = Options()
master = DumpMaster(options)
# master.addons.add(Addon()) # when I uncomment this it no longer connects
master.server = wg_server

And the following callbacks:

async def handle_connection(rw: mitmproxy_wireguard.TcpStream):
    while True:
        data = await rw.read(4096)

        # check if the connection was closed
        if len(data) == 0:
            break

        rw.write(data)
        await rw.drain()

    rw.close()

def receive_datagram(_data, _src_addr, _dst_addr):
    master.server.send_datagram(data.upper(), dst_addr, src_addr)

This is all in an asyncio loop I left out for clarity.

No matter what I do I can't get it to connect properly. With and without the addon it will increment up in RX and TX byte counts on the client (so they are communicating), and with tcpdump I can see that some data is getting to the server, however it won't render a webpage on a browser on the client's machine. I can't even ping google from the client.

Client conf file wg0.conf:

[Interface]
PrivateKey = {clientPrivKey}
Address = 10.0.0.1/24
DNS = 8.8.8.8, 77.88.8.7

[PEER]
PublicKey = {serverPubKey}
AllowedIPs = 0.0.0.0/0
Endpoint = {serverIPAddr}:{portNumber}

I think the issue may have something to do with DNS, however I'm not completely sure. At the very least the DNS isn't getting through as well as everything else, as I only see it in tcpdump and not the destinations real address. If anyone has any insight into using the mitmproxy_wireguard package I'd really appreciate it.

Thanks you for your time/help, and let me know if you have any questions about my setup

1

There are 1 answers

0
haxonek On

So I am not aware of any way to do this from python, and have given up. What I did end up discovering is you can add a port and configuration path to wireguard through the terminal:

mitmdump -s addon.py --mode wireguard:/path/to/wireguard.conf@51820

Where wireguard.conf looks like:

{
    "server_key": "SERVER PRIVATE KEY",
    "client_key": "CLIENT PRIVATE KEY"
}

Unfortunately this still takes a server public key and a client public key, which is bad if you don't want to share your client private key with a server. What I ended up doing is forking mitmproxy and modifying the key reader such that it only needs the client public key.

My change can be viewed here, and you can see all I do is instead of converting the private key to a public key, I just leave it as a public key. however I would recommend creating your own fork as my fork may change at any given moment. The file which needs to be changed is mitmproxy/proxy/mode_servers.py

From here you can install it into any pip3 environment by cloning it, making your edits, and then running pip3 install .

To run in python, I then run the command using subprocess.run:

import subprocess

subprocess.run(["mitmdump", "-s", "addon.py", "--mode", f"wireguard:{conf_file_path}@{wg_port}"])

Not very elegant but it's working.