Performing security assessments of complex systems sometimes requires some technical gymnastics to "man-in-the-middle" (MITM) communications between components. MITM techniques are essential for observing and manipulating communications in ways that a developer may not have anticipated. As system defenses improve the task of setting up a MITM environment for a system becomes more difficult.
A recent assessment was a bit more challenging to MITM. This system required the critical authentication steps to be sent over the cellular network. Usually we will MITM cellular devices over WiFi but enabling WiFi resulted in Android sending _all_ communications over WiFi including the critical authentication step.
The solution is based on:
- BURP for inspecting and manipulating traffic. Eventually I wrote a functioning exploit using mitmproxy which is perfect for Python scripted traffic manipulation.
- SSH (shown in orange) to function as a tunnel to BURP and a SOCKS proxy for traffic leaving BURP.
- ADB (shown in blue) to provide a non-WiFi connection between my Mac and the target device. ADB carried SSH traffic over a "forward" tunnel to the device.
iptablesscripts on the target device to send packets into this contraption as required.
Create a Shorter Duration BURP CA Certificate
The first task was convincing Android 7 to trust the BURP CA Certificate. The standard CA Certificate has an expiration date so far in the future that Android simple rejects the certificate. You must make a new certificate, add it to Burp, and then add it to Android.
Use this script to make the cert:
#!/usr/bin/env sh export KEYNAME=burp_short # Make private key openssl genrsa -out $KEYNAME.key 2048 # Make certificate openssl req -x509 -new -nodes -key $KEYNAME.key -sha256 -days 180 -out $KEYNAME.pem # Combine both for mitmproxy cat $KEYNAME.pem $KEYNAME.key > mitmproxy-ca.pem # Make der for import to Mac openssl x509 -outform der -in $KEYNAME.pem -out $KEYNAME.der # Make PKCS#12 file for burp import. echo "" echo "You must have a password or else burp will not import it." echo "" openssl pkcs12 -export -out $KEYNAME.pkcs12 -inkey $KEYNAME.key -in $KEYNAME.pem # openssl version` < 1.0: export CERTFP=`openssl x509 -inform PEM -subject_hash -in $KEYNAME.pem | head -1` # else # openssl x509 -inform PEM -subject_hash_old -in $KEYNAME.pem | head -1 cp $KEYNAME.pem $CERTFP.0 echo "Install this certificate to Android: $CERTFP.0" echo "Import this certificate+private key to Burp: $KEYNAME.pkcs12"
Setup BURP (or whatever attack proxy you prefer) and then:
- Enable transparent proxying. This is required because our
iptablesrules rudely shove packets at BURP without establishing a proxy connection. A proxy connection would explicitly inform BURP where the connection is intended to go. Without this hint BURP has to infer this from parsing the HTTP request.
- Import your new shorter duration CA certificate.
- In Project Options -> Connections configure BURP use
localhost:37760as the upstream SOCKS proxy. This sends traffic from BURP back over ADB+SSH and then out over the cellular network.
Add New CA Certificate to Device
You'll need root access on your target device.
adb push $KEYNAME.0 /sdcard/
- On device, as root:
mount -o rw,remount /system
mv /sdcard/$KEYNAME.0 /system/etc/security/cacerts/
chown root:root $KEYNAME.0(from dir)
chmod 644 $KEYNAME.0
ls -lZto make sure SELinux context is correct
- Reboot device
Install Termux and SSH on Device
You'll need a real SSH daemon on the device so that you have a reliable SOCKS proxy. There are various apps that provide proxy services on Android but I've found good old SSH to be the most reliable. You can easily install it using Termux.
- Install Termux
- Start Termux and then install ssh:
pkg install sshd
- Start SSH:
sshdin the Termux shell
- You need to install your SSH key in the Termux user directory:
- Make a
- Copy your public ssh key to your clipboard
cat > .ssh/authorized_keysthen paste your clipboard. Now
Control-Dto terminate cat.
- Fix permissions on the
.ssh/authorized_keysfile so SSH is happy.
drwx------ 2 u0_a116 u0_a116 4096 2017-10-10 10:35 .ssh -rw------- 1 u0_a116 u0_a116 404 2017-10-10 10:45 authorized_keys
At this point if your device is on WiFi you can test the SSH connection:
ssh -i $SSH_PRIVATE_KEY -p 8022 $DEVICE_IP
It does not matter what user account. You'll always end up the Termux user.
$ ssh -p 8022 root@localhost Enter passphrase for key '/Users/rbdixon/.ssh/id_rsa': Welcome to Termux! Wiki: https://wiki.termux.com Community forum: https://termux.com/community IRC channel: #termux on freenode Gitter chat: https://gitter.im/termux/termux Mailing list: email@example.com Search packages: pkg search <query> Install a package: pkg install <package> Upgrade packages: pkg upgrade Learn more: pkg help bash-4.4$
Setup ADB Tunnel
Disable WiFi on the target device. When you turn off WiFi you'll lose the ability to SSH into your device unless you can tunnel over ADB.
You must have a recent version of ADB for this stuff to work right.
$ adb --version Android Debug Bridge version 1.0.39 Revision 3db08f2c6889-android
Establish the ADB tunnel from your development machine to the target device:
adb forward tcp:8022 tcp:8022
adb forward --list
This should let your SSH into the device with WiFi disabled. Try it out:
ssh -i $SSH_PRIVATE_KEY -p 8022 localhost
Add something like this to your
Host device # localhost:8022 is the tunnel provided by ADB Hostname localhost Port 8022 # Tunnel from the device to reach BURP RemoteForward :8080 localhost:8080 # SOCKS proxy to send traffic from BURP out the device cellular connection DynamicForward localhost:37760
ssh device to establish the connection. As long as this ssh connection is open you can:
- Tunnel from the device to BURP over port 8080.
- Proxy requests over SOCKS from the Mac to the device so that you can use the device's cellular connection.
Use the Tunnel
Just because you have these tunnels does not mean that any traffic will be sent over them. You've got to mangle
iptables rules to redirect traffic over the tunnel.
The example below is only for IPv4 because ADB seems to only be able to forward IPv4 traffic. The systems I've tested have been dual stack so I fixed this by adding the IPv4 address for the server to
/etc/hosts on the device. This forced the usage of IPv4.
You could also handle this by using
socat to tunnel IPv6 to IPv4 but I did not try that.
Anyways, adapt the script below and run it on the device as
root to start using the tunnels.
#!/bin/sh # On your Mac make sure burp is listening on this port # with transparent proxying enabled BURP=127.0.0.1:8080 # Android username for the application that you are hacking. # All traffic originated by processes run by this user will # be sent to burp. APP_USER=u0_a111 # Android username for the sshd process. Run `ps|grep ssh` to find it. SSH_USER=u0_a116 # Create table iptables -t nat -N burp # Flush table iptables -t nat -F burp # Setup forwarding rules # General HTTP/HTTPS capture #iptables -t nat -A burp -p tcp --dport 80 -j DNAT --to-destination $BURP #iptables -t nat -A burp -p tcp --dport 443 -j DNAT --to-destination $BURP # If you want to capture _any_ traffic to a target IP address # use a rule like this. This is useful for running Chrome through # burp. iptables -t nat -A burp -p tcp -d 18.104.22.168 -j DNAT --to-destination $BURP # This rule sends any traffic originated by your target application # to burp iptables -t nat -A burp -p tcp -m owner --uid-owner $APP_USER -j DNAT --to-destination $BURP # The rules above are added to a special "burp" chain. Packets will # not use that chain unless they are "jumped" onto that chain. We # want to send all packets to that chain _unless_ they are coming # from SSH. Why? That's the return path back from Burp. If we don't # filter those out your packets will just travel in a little boring # loop. # The rule below jumps all packets routed out of the device that are # not owned by SSH to the burp chain. iptables -t nat -A OUTPUT -m owner ! --uid-owner $SSH_USER -j burp # Print iptables -t nat -L
Check by running these as root on the device:
curl -v http://google.com. Check in Burp for traffic.
curl -v https://google.com. Check Burp. TLS cert should be the one you created.
curl -v http://ip-api.com/json. You should be on the cellular network.
Next run your target app on the device and make sure you've got Burp traffic as expected.