quick transparent mitmproxy on docker

Getting Started


set -x

iptables -t nat -A PREROUTING -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 8080
iptables -t nat -A PREROUTING -p tcp -m tcp --dport 443 -j REDIRECT --to-ports 8080

docker run --rm -it --network host -v ~/.mitmproxy:/home/mitmproxy/.mitmproxy mitmproxy/mitmproxy mitmweb --web-host --mode transparent --showhost

iptables -t nat -D PREROUTING -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 8080
iptables -t nat -D PREROUTING -p tcp -m tcp --dport 443 -j REDIRECT --to-ports 8080

Additional Steps

  • Change default gateway to the box running the mitmproxy or run mitmproxy on the gateway itself.
  • Go to mitm.it, install the certificate.

Enjoy mitmproxy running on the box:8081.

Making your life easier with oathtool

oathtool is a CLI application, that can generate onetime passwords based on provided secrets.
How ever it’s a bit tricky to generate the OTP, as it requires the secret being passed as argument and you do not really want the secret to appear in your .bash_history / .zsh_history.

To solve this problem I stored the secrets in a folder inside of my home directory (e.g. ~/.oath-secrets/) and encrypted them using gpg.
So if you have the secret “1234567890”, store it in a file called “my-secret” inside this directory and encrypt it using gpg like this:

# pwd should be ~/.oath-secrets/
gpg -e -r mygpgkeyid my-secret
shred -uz my-secret

This should create a file called “my-secret.gpg” and delete the original unencrypted file.

Paste the following function into your .zshrc or .bashrc file:

t () {
        oathtool --totp -b $(gpg -d ~/.oath-secrets/"${1}".gpg) | xclip && echo "\n${GREEN}[ + ]${NOCOLOR} Clipped!"
        echo "[ ? ] You have 10 seconds."
        sleep 10
        xclip -i /dev/null && echo "${GREEN}[ + ]${NOCOLOR} Clipboard deleted.\n"

Start a new terminal (or sourcing your .zshrc or .bashrc file) and get your OTP token by running “t my-secret”

$ t my-secret
gpg: encrypted with 4096-bit RSA key, ID XXXXXXXXXXXXXXX, created 1970-01-01 "Max Mustermann max@mustermann.com"
[ + ] Clipped!
[ ? ] You have 10 seconds.
[ + ] Clipboard deleted.

The 2FA token has been copied into your mouse clipboard. Now you can paste it with middle click.
It will be deleted after 10 seconds, so hurry up 😉

Downside: This might compromise the safety of 2 factor authentication depending on how you’re using it.

pamu2fcfg: No U2F device available, please insert one now

$ pamu2fcfg
No U2F device available, please insert one now, you have 13 seconds

Yubikey needs to be in FIDO or OTP+FIDO mode:

$ ykman mode
Current connection mode is: OTP
Supported USB interfaces are: OTP, FIDO, CCID

To set the correct mode, run:

$ ykman mode OTP+FIDO
Set mode of YubiKey to OTP+FIDO? [y/N]: y

Test in verbose + debug mode:

$ pamu2fcfg -v -d
Setting origin to pam://localhost
Setting appid to pam://localhost
USB send: 00ffffffff8600xxxxxxxxxxxxxxxxxxxxx000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
USB write returned 65
now trying with timeout 2
USB read rc read 64
USB recv: ffffffff86001xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx00000000000000000000000000000000000000000000000000000000000000000000000000000000
device /dev/hidraw9 discovered as 'YubiKey OTP+FIDO'

Working with Docker filters in python

I needed to man-in-the-middle traffic of Docker containers to automatically extract game server status information from plaintext http requests to their master server.
So I wrote a python script for that, but I had some weird behavior on the Docker network “name” filter.
The behavior seems not to be documented on the documentation.


Game servers are running inside an overlay network called “condor2”.
On the Docker host, I run a python script to extract game server information from network traffic flowing through the Docker overlay network.


# docker version
 Client: Docker Engine - Community
  Version:           19.03.2
  OS/Arch:           linux/amd64
 Server: Docker Engine - Community
   Version:          19.03.2
   API version:      1.40 (minimum version 1.12)
   Version:          1.2.6
# pip3 freeze | grep docker
# python3 --version
 Python 3.5.3


Running this piece of script

import docker
d = docker.from_env()
n = d.networks.list(filters={"name":"condor2"})

returns an object like that one:

>>> print (n)
[<Network: 228e98c554>, <Network: b9aafep0a6>]

Both networks have “condor2” in their name:

# docker network inspect 228e98c554 | grep Name    
"Name": "condor2",
# docker network inspect b9aafep0a6 | grep Name
        "Name": "prod_dvaec_condor2-bots_default",


To get exact matches for your filter, you need to use regex inside the filter:

#!/usr/bin/env python3
import docker
d = docker.from_env()
n = d.networks.list(filters={"name":"^condor2$"})

The result looks like that now:

>>> print (n)
[<Network: 228e98c554>]

Bingo. That’s what I actually needed.

Simple podcast downloader

This simple python3 script will fetch all RSS attachments and save them in the format “Podcast Title” – “Episode Name”.mp3

Installing the dependencies:

pip3 install feedparser
import feedparser
import subprocess

feedURL = ''

d = feedparser.parse(feedURL)

for entry in d['entries']:
    episodeName = d['feed']['title'] + " - " + entry['title']
    for link in entry['links']:
        if link['type'] != 'text/html':
            url = link['href']
            subprocess.run(["wget", "-c", "-O", episodeName + ".mp3", url])