Promiscuous Mode Detector
Transcrição
Promiscuous Mode Detector
Praktische Diplomarbeit 2004 — Sna04/2 Promiscuous Mode Detector H ALM R EUSSER [email protected] IT01 R ANKO V ESELINOVI Ć [email protected] IT01 25. Oktober 2004 Betreut durch Prof. Dr. A NDREAS S TEFFEN Zusammenfassung Im Zeitalter der kontinuierlichen Vernetzung und permanenter Erreichbarkeit der Rechner wird die Sicherheit der Netze immer wichtiger. Es vergeht kein Monat, in dem man nicht von Datendiebstahl bei Firmen liest. Sensible Daten werden unverschlüsselt über das lokale Netz geschickt. Diese grobe Fahrlässigkeit gewisser Administratoren erleichtert den Datendieben das Leben. Mit einer L INUX-LiveCD und einem normalen Arbeitsplatzrechner ist man schon genügend ausgestattet, um sensible Daten zu erhaschen. Die dazu notwendige Software ist ein NetworkAnalyser oder Sniffer. Beides sind passive Elemente, welche man theoretisch von aussen nicht detektieren kann. Da es aber keine fehlerfreie Software gibt, ist es möglich, Fehler der Implementierung auszunutzen und die unerwünschten Zuhörer zu detektieren. Bis jetzt existierte kein O PEN S OURCE Tool, welches in der Lage war, Sniffer aus der Ferne zu detektieren. Um dieses Manko zu beseitigen, wurde im Rahmen dieser Diplomarbeit ein solches Tool entwickelt. Es wurden vorhandene Methoden zusammengetragen, analysiert und bewertet. Die erfolgversprechendsten wurden dann in Form von Plugins in die Software eingebunden. Mit der vorliegenden Arbeit, halten Sie nun ein Tool zum Detektieren von Sniffern im Netzwerk in den Händen. Bei neun von zehn Betriebssystemen waren alle implementierten Methoden erfolgreich. Einzig S UN OS 5.7 war in der Lage drei von vier Testmethoden zu trotzen. In der Testphase mussten wir feststellen, dass viele embedded Systeme, wie es z.B. Netzwerkdrucker, Druckerserver und ADSL-Router sind, schlecht implementierte Networkstacks besitzen. Dies kann unter Umständen zu falschen Verdächtigungen führen. Im Netzwerk sollte dies jedoch kein Problem darstellen, da diese Geräte von vornherein bekannt sein sollten. Die Arbeit konnten wir erfolgreich abschliessen. Damit steht den Administratoren ein hilfreiches und mächtiges Werkzeug zur Verfügung, welches den Script-Kiddies das Leben schwer machen wird. Winterthur, 23. Oktober 2004 H ALM R EUSSER R ANKO V ESELINOVI Ć I Abstract In an era of continuous networking and permanent accessibility of computers, network security has become a serious issue. News about data theft in companies has become a common headline. Sensitive data is sent unencrypted over the wire. This culpable negligence of certain network administrators makes the life for data thieves easier. All you need is a L INUX-LiveCD and a common PC to start snooping around for sensitive data. The Software need is a network analyser or sniffer. Both of them are passive elements and theoretically not detectable from outside. As a matter of fact, accurate software does not exist. This makes it possible to exploit weakness of implementation and detect the unwanted listener. Up until now there was no open source tool that was able to detect a sniffer. Within the scope of our diploma thesis, existing methods should be collected, analysed and evaluated. Furthermore a tool had to be developed, which implements the auspicious methods and closes the gap. The document you’re holding in your hands provides you with a tool which is able to detect sniffers from outside. The testing of nine out of ten operating systems with all implemented methods was successful. S UN OS 5.7 though was able to defy three of four methods. During testing we discovered that some embedded systems, e.g. network printers, print servers and ADSL routers have a really bad network stack. Using such stacks can lead to false suspicion. However, administrators in a corporate network should have all the necessary information about such devices so they should not pose a challenge anymore. We successfully finished our diploma thesis. Network administrators are provided with a useful and powerful tool which will make the life for script-kiddies hard. III Erklärung betreffend das selbständige Verfassen einer Projekt- oder Diplomarbeit im Dept. T Mit der Abgabe dieser Projekt-/VDP-/SDP-Arbeit versichert der/die Studierende, dass er/sie die Arbeit selbständig und ohne fremde Hilfe verfasst hat. (Bei Gruppenarbeiten gelten die Leistungen der übrigen Gruppenmitglieder nicht als fremde Hilfe.) Der/die unterzeichnende Studierende erklärt, dass alle zitierten Quellen (auch Internetseiten) im Text oder Anhang korrekt nachgewiesen sind, d.h. dass die Projekt-/VDP-/SDP-Arbeit keine Plagiate enthält, also keine Teile, die teilweise oder vollständig aus einem fremden Text oder einer fremden Arbeit unter Vorgabe der eigenen Urheberschaft bzw. ohne Quellenangabe übernommen worden sind. Bei Verfehlungen aller Art werden die Paragraphen 35 und 36 (Unredlichkeit und Verfahren bei Unredlichkeit) des Reglements für Prüfungen am TWI sowie die Bestimmungen des Disziplinarverfahrens der Hochschulordnung (Paragraph 38) angewendet. Ort, Datum: ........................................................ Unterschriften: ......................................................... ......................................................... ......................................................... Dieses Formular ist bei allen abgegebenen Projekt- und Diplomarbeiten nach der Aufgabenstellung mit Original-Unterschrift und –Datum (keine Kopie) einzufügen. Inhaltsverzeichnis Vorbemerkungen I. XVII Einleitung 1 1. Aufgabenstellung 3 2. Pflichtenheft 2.1. Ziele . . . . . . . . . . . . . . . . . . . . . 2.2. Anforderungen an das zu entwickelnde Tool 2.3. Projektplan . . . . . . . . . . . . . . . . . 2.4. Dokumentation . . . . . . . . . . . . . . . . . . . 5 5 5 6 6 3. Was sind Sniffer? 3.1. Einsatz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 7 4. Wie funktioniert ein Sniffer? 4.1. shared und microsegmentiertes LAN . . . . . . . . . . . . . . . . . . . . . . . 4.2. promiscuous mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3. Implementation in L INUX? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 8 8 9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . II. Theorie: Sniffer Erkennung 11 5. Networkstack Tests 5.1. Grundlagen . . . . . . . . . . . . . . . . 5.1.1. Hardware-Filter . . . . . . . . . . 5.1.2. Software-Filter . . . . . . . . . . 5.1.3. Reaktionen . . . . . . . . . . . . 5.2. ARP-Test . . . . . . . . . . . . . . . . . 5.2.1. Das Address Resolution Protocol 5.2.2. Methode . . . . . . . . . . . . . 5.2.3. Erweiterungen . . . . . . . . . . 5.2.4. Voraussetzungen . . . . . . . . . 5.2.5. Evaluation . . . . . . . . . . . . 5.3. ICMP-Test . . . . . . . . . . . . . . . . . VII . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 14 14 15 16 18 18 21 21 22 22 22 Inhaltsverzeichnis 5.3.1. Internet Control Message Protocol Echo-Request & Echo-Reply 5.3.2. Methode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.3.3. Voraussetzungen . . . . . . . . . . . . . . . . . . . . . . . . . 5.3.4. Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.4. Source Route . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.4.1. Source Routing . . . . . . . . . . . . . . . . . . . . . . . . . . 5.4.2. Methode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6. DNS Test 6.1. Das Domain Name System 6.2. Methode . . . . . . . . . . 6.3. Erweiterungen . . . . . . . 6.4. Voraussetzungen . . . . . 6.5. Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 24 24 25 25 25 26 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 28 30 31 31 31 7. LATENCY-Tests 7.1. ICMP-Time-Delta- & Ping-Drop-Test . . . . . 7.1.1. Methode . . . . . . . . . . . . . . . . 7.1.2. Erweiterungen . . . . . . . . . . . . . 7.1.3. Voraussetzungen . . . . . . . . . . . . 7.1.4. Evaluation . . . . . . . . . . . . . . . 7.2. Timestamp-Request . . . . . . . . . . . . . . . 7.2.1. ICMP-Timestamp-Request und -Reply 7.2.2. Methode . . . . . . . . . . . . . . . . 7.2.3. Erweiterungen . . . . . . . . . . . . . 7.2.4. Voraussetzungen . . . . . . . . . . . . 7.2.5. Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 32 32 33 33 33 34 34 35 35 35 35 8. Weitere Methoden 8.1. Host . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.2. Decoy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.3. SNMP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 36 37 37 III. 38 SAD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . — Sniff And Die 9. Design 9.1. UML-Diagramm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 40 10. Das Framework 10.1. Der Option-Manager . . . . 10.2. Der Configfile-Parser . . . . 10.3. Der Kommandozeilen-Parser 10.4. Threads . . . . . . . . . . . 10.4.1. InjectionThread . . . 41 41 42 44 45 45 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . VIII . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Inhaltsverzeichnis 10.4.2. CaptureThread . . 10.5. Die Scan-Strategy . . . . . 10.5.1. Vorlage für Plugins 10.5.2. Thread Handling . 10.6. Exceptions . . . . . . . . . 10.6.1. SadEx . . . . . . . 10.6.2. Anwendung . . . . 10.7. SAD . . . . . . . . . . . . 10.7.1. Rating . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11. Plugin-HowTo 11.1. Das L INUX-Plugin-Interface . . . . . . . . . . . . 11.2. Probleme mit C++ . . . . . . . . . . . . . . . . . 11.3. Die Umsetzung bei SAD . . . . . . . . . . . . . . 11.4. Schreiben eines eigenen Plugins . . . . . . . . . . 11.4.1. Bekanntgabe der Optionen . . . . . . . . . 11.4.2. Implementieren der setLocalVal() Methode 11.4.3. Implementation der scan() Methode . . . . 12. SAD-Plugins 12.1. ARP . . . . . . . . 12.2. ICMP . . . . . . . 12.3. DNS . . . . . . . . 12.4. LATENCY . . . . 12.4.1. LatencyCT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 46 46 47 48 48 48 50 51 . . . . . . . 52 52 52 53 54 54 54 55 . . . . . 57 57 57 58 59 59 IV. Auswertung 61 13. Vorhandene Tools 63 14. SAD 14.1. LATENCY-Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14.1.1. Messungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14.1.2. Fazit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 64 64 67 15. Ausnahmen 15.1. Phänomen Surecom Router . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15.2. false positives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 68 69 16. Ausblick 16.1. Anti-SAD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16.2. Zukunft von SAD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 71 71 IX Inhaltsverzeichnis Schlusswort 73 V. 74 Anhang A. Projektplan 75 B. Ein einfacher L INUX-Sniffer 77 C. L INUX Networkstack-Walkthrough C.1. Ethernet Card and Lower-Kernel Reception — Layer 1 C.2. Network Core Processing — Layer 2 . . . . . . . . . . C.2.1. NAPI . . . . . . . . . . . . . . . . . . . . . . C.2.2. netif_rx() und netif_rx_schedule() . . . . . . . C.2.3. NET_RX softirq net_rx_action() . . . . . . . . C.3. Ausgewählte Passagen aus den Kernelsourcen . . . . . 80 80 81 81 82 83 83 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . D. Glossar 86 Literaturverzeichnis 87 E. The GNU General Public License 89 F. Code F.1. Makefile . . . . . . . . . F.2. Framework . . . . . . . F.2.1. optionMgr.hpp . F.2.2. optionMgr.cpp . F.2.3. Option . . . . . F.2.4. cfgParser.hpp . . F.2.5. cfgParser.cpp . . F.2.6. console.hpp . . . F.2.7. console.cpp . . . F.2.8. sadThread.hpp . F.2.9. captureT.hpp . . F.2.10. captureT.cpp . . F.2.11. injectionT.hpp . F.2.12. injectionT.cpp . . F.2.13. latencyCT.hpp . F.2.14. latencyCT.cpp . F.2.15. ScanStrategy.hpp F.2.16. ScanStrategy.cpp F.2.17. sadEx.hpp . . . . F.2.18. sad.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . X . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 98 100 100 100 101 102 102 105 105 108 108 109 111 111 113 113 115 116 120 121 Inhaltsverzeichnis F.3. Plugins . . . . . . F.3.1. arp.hpp . . F.3.2. arp.cpp . . F.3.3. icmp.hpp . F.3.4. icmp.cpp . F.3.5. dns.hpp . . F.3.6. dns.cpp . . F.3.7. latency.hpp F.3.8. latency.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . XI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125 125 125 129 129 133 133 137 137 Abbildungsverzeichnis 4.1. Ethernet-Frames in einem shared LAN . . . . . . . . . . . . . . . . . . . . . . 4.2. promiscuous mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3. Paket-Prozess-Kette . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 9 10 5.1. 5.2. 5.3. 5.4. 5.5. 5.6. 5.7. 5.8. 5.9. . . . . . . . . . 15 19 20 21 23 24 25 26 27 6.1. Der DNS-Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 7.1. Time-Delta-Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.2. ICMP Timestamp-Request/-Reply Nachricht . . . . . . . . . . . . . . . . . . . 33 34 9.1. UML-Diagramm von SAD . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 10.1. Flussdiagramm: SAD-Ablauf . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 14.1. 14.2. 14.3. 14.4. . . . . 66 66 67 67 C.1. Old API: Kernel <2.4.19 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C.2. New API (NAPI): Kernel ≥ 2.4.19 . . . . . . . . . . . . . . . . . . . . . . . . 81 82 Der L INUX Software-Filter . . . . . . . . . . Die Arbeitsweise von ARP . . . . . . . . . . ARP-Paket . . . . . . . . . . . . . . . . . . ARP-Detektion . . . . . . . . . . . . . . . . Aufbau eines ICMP Request/Reply Paketes . ICMP-Test . . . . . . . . . . . . . . . . . . . Format der source route Option im IP-Header Ablauf source routing . . . . . . . . . . . . . source routing Methode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Durchschnittliche Antwortzeit im unbelasteten Netzwerk Durchschnittliche Antwortzeit im belasteten Netzwerk . Durchschnittliche Drops im belasteten Netzwerk . . . . Erzeugte Netzlast . . . . . . . . . . . . . . . . . . . . . XII . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Tabellenverzeichnis 5.1. Reaktionen auf ARP-Scans . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 14.1. Analysierte Betriebssysteme . . . . . . . . . . . . . . . . . . . . . . . . . . . 14.2. Angaben zur Messreihe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14.3. Durschnittswerte der 10 Tests . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 65 65 XIII Listings 5.1. ARP Request . . . . . . . . . . . . . . . . . . . . . . . . 5.2. ARP Reply . . . . . . . . . . . . . . . . . . . . . . . . . 5.3. Echo Request . . . . . . . . . . . . . . . . . . . . . . . . 5.4. Echo Reply . . . . . . . . . . . . . . . . . . . . . . . . . 5.5. source routing . . . . . . . . . . . . . . . . . . . . . . . . 6.1. DNS-Query . . . . . . . . . . . . . . . . . . . . . . . . . 6.2. DNS-Response . . . . . . . . . . . . . . . . . . . . . . . 6.3. Reverse-DNS-Query . . . . . . . . . . . . . . . . . . . . 6.4. Reverse-DNS-Response . . . . . . . . . . . . . . . . . . . 7.1. ICMP Timestamp-Request . . . . . . . . . . . . . . . . . 7.2. ICMP Timestamp-Reply . . . . . . . . . . . . . . . . . . . 8.1. O PEN BSD: ifconfig -a . . . . . . . . . . . . . . . . . . . 8.2. L INUX: dmesg | grep -i promiscuous . . . . . . . . . . . . 10.1. Die Klasse OptionMgr . . . . . . . . . . . . . . . . . . . 10.2. Der Option-Struct . . . . . . . . . . . . . . . . . . . . . . 10.3. Aufbau einer Option . . . . . . . . . . . . . . . . . . . . 10.4. Aufbau von sad.conf . . . . . . . . . . . . . . . . . . . . 10.5. Die Klasse cfgParser . . . . . . . . . . . . . . . . . . . . 10.6. Die Klasse console . . . . . . . . . . . . . . . . . . . . . 10.7. CaptureT: nonblocking . . . . . . . . . . . . . . . . . . . 10.8. CaptureT: Konstruktor . . . . . . . . . . . . . . . . . . . 10.9. ScanStrategy::addThread() . . . . . . . . . . . . . . . . . 10.10.ScanStrategy::startThreads() . . . . . . . . . . . . . . . . 10.11.SadEx . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10.12.Ableitung von SadEx . . . . . . . . . . . . . . . . . . . . 10.13.Eine Exception werfen . . . . . . . . . . . . . . . . . . . 10.14.Eine Exception abfangen . . . . . . . . . . . . . . . . . . 10.15.S AD Verwaltungs-Konstrukte . . . . . . . . . . . . . . . . 10.16.Optionen von SAD . . . . . . . . . . . . . . . . . . . . . 10.17.Ausgabe von SAD . . . . . . . . . . . . . . . . . . . . . . 11.1. Das L INUX-Plugin-Interface . . . . . . . . . . . . . . . . 11.2. Definition der class factory functions im ScanStrategy.hpp 11.3. class factory functions am Beispiel vom ARP-Plugin . . . 11.4. Bekanntgabe der Optionen . . . . . . . . . . . . . . . . . 11.5. Setzen der lokalen Variablen . . . . . . . . . . . . . . . . XIV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 20 23 23 26 28 28 29 29 34 35 36 36 41 41 42 43 43 44 45 45 47 47 48 48 48 49 50 51 51 52 53 53 54 54 Listings 11.6. Eintrag in sad.conf . . . . . . 12.1. Optionen des Plugins ARP . . 12.2. Optionen des Plugins ICMP . 12.3. DNS-Test: Bau der IP-Adresse 12.4. Dynamischer Bau des Filters . 12.5. Optionen des Plugins DNS . . 12.6. Optionen des Plugins Latency 12.7. Latency CaptureThread . . . . 15.1. fake ICMP Request . . . . . . 15.2. Erwartete Antwort . . . . . . 15.3. Multicast korrigiertes Paket . . 15.4. Zweite Antwort . . . . . . . . B.1. Minisniffer . . . . . . . . . . B.2. Ausgabe . . . . . . . . . . . . C.1. net/core/dev.c . . . . . . . . . C.2. net/ethernet/eth.c . . . . . . . C.3. net/ipv4/arp.c . . . . . . . . . C.4. net/ipv4/ip_input.c . . . . . . Makefile . . . . . . . . . . . . . . . OptionMgr.hpp . . . . . . . . . . . OptionMgr.cpp . . . . . . . . . . . Option.hpp . . . . . . . . . . . . . cfgParser.hpp . . . . . . . . . . . . cfgParser.cpp . . . . . . . . . . . . console.hpp . . . . . . . . . . . . . console.cpp . . . . . . . . . . . . . sadThread.hpp . . . . . . . . . . . . captureT.hpp . . . . . . . . . . . . . captureT.cpp . . . . . . . . . . . . . injectionT.hpp . . . . . . . . . . . . injectionT.cpp . . . . . . . . . . . . latencyCT.hpp . . . . . . . . . . . . latencyCT.cpp . . . . . . . . . . . . ScanStrategy.hpp . . . . . . . . . . ScanStrategy.cpp . . . . . . . . . . sadEx.hpp . . . . . . . . . . . . . . sad.cpp . . . . . . . . . . . . . . . arp.hpp . . . . . . . . . . . . . . . arp.cpp . . . . . . . . . . . . . . . . icmp.hpp . . . . . . . . . . . . . . icmp.cpp . . . . . . . . . . . . . . . dns.hpp . . . . . . . . . . . . . . . dns.cpp . . . . . . . . . . . . . . . latency.hpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . XV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 57 57 58 58 58 59 60 68 68 68 69 77 79 83 84 84 85 98 100 100 101 102 102 105 105 108 108 109 111 111 113 113 115 116 120 121 125 125 129 129 133 133 137 Listings latency.cpp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138 XVI Vorbemerkungen Dieses Dokument wurde in LATEX 2ε geschrieben. Dabei haben wir uns an folgende Konventionen gehalten: Namen von Personen, Firmen und Produkten werden mit K APITÄLCHEN dargestellt. Schlüsselworte werden kursiv dargestellt. Verweise auf Literatur zum jeweiligen Thema, werden nur beim ersten Auftauchen des Begriffes gemacht (z.B. LATEX 2ε [1]). Code-Schnipsel werden in Schreibmaschinenschrift dargestellt. Listings werden in der Listing-Umgebung dargestellt. # i n c l u d e < s t d i o . h> i n t main ( v o i d ) { / ∗ H e l l o World ∗ / p r i n t f ( " H e l l o World \ n " ) ; return 0; } # zeigt, dass es sich um eine Root-Shell handelt. $ zeigt, dass es sich um eine User-Shell handelt. Wenn im Dokument von uns die Rede ist, bezieht sich das immer auf die Autoren dieses Dokumentes, d.h. auf die Herren H ALM R EUSSER & R ANKO V ESELINOVI Ć. XVII Teil I. Einleitung Zusammenfassung In diesem Kapitel wird kurz erklärt, was einen Sniffer ausmacht und wozu er eingesetzt wird. Es wird auch erklärt, was der Unterschied zwischen einem shared und einem microsegmentierten LAN ist. Des Weiteren werden der Begriff promiscuous mode eingeführt und eine kurze Information zur Implementation eines Sniffers in L INUX vorgestellt. 1. Aufgabenstellung 3 4 2. Pflichtenheft Angenehm sind die erledigten Arbeiten. (Marcus Tullius Cicero (106-43)) 2.1. Ziele Ziel dieser Diplomarbeit ist das Schreiben eines Promiscuous Mode Detectors. Des Weiteren sollen die vorhandenen Methoden analysiert und bewertet werden. Dies beinhaltet eine Untersuchung der Schwächen von Ethernet- und TCP/IP-Implementierungen und wie diese für unsere Ziele ausgenutzt werden können. Ausgiebige Tests an den Betriebssystemen • L INUX 2.2, 2.4 und 2.6 • O PEN BSD • F REE BSD • M AC OSX • S UN OS 5.7 • W INDOWS 2000/XP sollen die ganze Arbeit abrunden. An dieser Stelle sei nochmals darauf hingewiesen, dass nur Software-Sniffer auf IP-Basis erkannt werden sollen. Dies bedeutet implizit, dass HardwareNetwork-Analyser nicht erkannt werden können. 2.2. Anforderungen an das zu entwickelnde Tool Primär soll das Tool, welches wir liebevoll S NIFF A ND D IE genannt haben, unter L INUX laufen. Jedoch soll die Portabilität mit anderen U NIX-Derivaten nicht absichtlich, durch Einsatz von L INUX-Spezialitäten, verletzt werden. Features • Gegebenes Framework • Erweiterbarkeit durch Plugins • Multi-Threading • Konfiguration mittels einer Konfigurationsdatei 5 2.3. Projektplan 2.3. Projektplan Die Verteilung der Aufgaben und der genaue Ablauf der verrichteten Arbeiten, ist aus dem Projektplan im Anhang A ersichtlich. 2.4. Dokumentation Die vorliegende Arbeit lässt sich in vier Bereiche aufteilen. Der erste Teil führt in das verwendete Vokabular ein. Begriffe im Zusammenhang mit Sniffern und Network-Analysern und deren Funktionsweisen werden eingeführt. Im zweiten Teil werden dem Leser dann die Schwächen der Ethernet- und TCP/IP-Implementierung gezeigt. Des Weiteren werden Methoden gezeigt, wie man den Lauscher dazu bringt, sich zu verraten. Es wird erklärt, wie es dem Administrator damit möglich sein sollte, Sniffer zu detektieren. Der dritte Teil ist dem von uns entwickelten Tool SAD gewidmet. Der Leser lernt die Konzepte hinter SAD und deren Umsetzung kennen. Des Weiteren erfährt er, wie man selber Erweiterungen, in Form von Plugins, schreiben kann. Der vierte und letzte Teil fasst unsere Resultate zusammen. Es werden gängige Betriebssysteme ausgewertet und an ihnen die Funktionsweise von SAD gezeigt. 6 3. Was sind Sniffer? Microsoft isn’t evil, they just make really crappy operating systems. (Linus Torvalds) Die Sicherheit eines lokalen Netzwerkes verdient immer grössere Beachtung. Plain-Text Daten wie zum Beispiel Passwörter oder private E-Mails, können abgehört werden. Ein solches Mithören nennt man auch sniffen (engl. “to sniff” für riechen, schnüffeln). Es gibt einige, darunter auch freie Software, die den Datenverkehr eines Netzwerks empfangen und darstellen können. Da der ganze Datenverkehr aus einem binär codierten Strom besteht, sind Sniffer meistens mit einem Protokoll-Analyser ausgestattet, der die empfangenen Daten in eine für Menschen lesbare Form darstellt. 3.1. Einsatz • Diagnose von Netzwerkproblemen • Eindringungsversuche entdecken • Networktraffic-Analyse und Filterung nach verdächtigem Inhalt • Datenspionage 7 4. Wie funktioniert ein Sniffer? 4.1. shared und microsegmentiertes LAN Sniffer können in CSMA/CD und geswitchten Netzwerken arbeiten. In einem shared LAN hängen alle Geräte am gleichen Bus. Pakete, die an eine Maschine gesendet werden, können von allen anderen Rechnern im gleichen Segment abgehört werden. Abbildung 4.1.: Ethernet-Frames in einem shared LAN In einem geswitchten Netzwerk sieht dies anders aus. Der Switch, ein intelligentes Netzwerkgerät, merkt sich die Zuordnung MAC-Adresse↔Port. So werden Pakete nur dem dafür zuständigen Host gesendet und nicht wie oben gebroadcastet. Falls eine unbekannte MAC-Adresse auftritt, wird das Paket an alle Ports geflutet → shared LAN Verhalten. Eine andere Methode, um gezielt einen Host auszuschnüffeln, bietet das so genannte ARP poisoning. 4.2. promiscuous mode Ein Sniffer kennt zwei verschiedene Modi: • non-promiscuous mode: Es werden ankommende und abgehende Daten des eigenen Computers gesnifft. 8 4.3. Implementation in L INUX? • promiscuous mode: Es wird der gesamte Datenverkehr gesammelt. Es werden also nicht nur die an ihn adressierten Frames empfangen, sondern auch die nicht an ihn adressierten. Im non-promiscuous mode werden folgende Frames nicht verworfen: • Ziel-MAC-Adresse entspricht der Hardware-Adresse der Netzwerkkarte. • Ziel-MAC-Adresse entspricht der Broadcast-Adresse • Ziel-MAC-Adresse entspricht einer Multicast-Adresse Im promiscuous mode werden keine Frames hardwaremässig verworfen. Abbildung 4.2.: promiscuous mode 4.3. Implementation in L INUX? Wie man einen einfachen Sniffer unter L INUX implementieren kann, wird im Anhang B erläutert. Es gibt noch eine wichtige Eigenschaft, die es zu erklären lohnt. Falls auf dem Netzwerk sehr viele Daten auftreten, kann es soweit kommen, dass der Kernel beginnt Pakete zu verwerfen, da er nicht alle verarbeiten kann. Die Lösung für dieses Problem ist, möglichst früh in der Paket-Prozess-Kette einen Filter einzubauen. Der L INUX Kernel erlaubt es einen Filter namens LPF direkt in die Protokoll-ProzessRoutinen einzubauen. 9 4.3. Implementation in L INUX? Abbildung 4.3.: Paket-Prozess-Kette 10 Teil II. Theorie: Sniffer Erkennung Zusammenfassung Nebst der Funktionsweise der einzelnen Methoden wird in diesem Teil die nötige Theorie für das Verständnis von SAD vermittelt. Der Leser sollte danach in der Lage sein, die bei SAD angewandten Tricks zu verstehen. Überblick In der Theorie ist es unmöglich einen Sniffer zu detektieren, weil ein Sniffer ein rein “passives” Gerät ist. Dies ist aber so nicht ganz richtig. Natürlich gibt es Hardware-Protokoll-Analyser, die nur Daten sammeln, oder man kann einfach die Tx-Leitungen durchschneiden! Da die meisten Sniffer aber auf Rechnern laufen, die einen eigenen IP-Stack besitzen, gibt es ein paar Ansätze, die dazu dienen, herauszufinden, ob sich eine solche Maschine im promiscuous mode befindet. Diese Möglichkeiten lassen sich in folgende Kategorien aufteilen: Networkstack Es werden gezielt Schwächen des Networkstacks spezifischer Betriebssysteme ausgenutzt. Zur Auswertung sind vor allem Protokolle geeignet, die Antworten erzeugen, wie zum Beispiel ARP oder ICMP. DNS Reverse Lookups Um eine bessere Lesbarkeit der gesammelten Informationen zu erreichen, bieten viele Sniffer die Möglichkeit die IP-Adressen in Domainnamen umzusetzen. Um dies jedoch zu ermöglichen, muss der Sniffer agieren und DNS Namensauflösungen bewerkstelligen. Latenzzeiten und Packetdropping Ein Sniffer ist gezwungen die gesammelten Daten zu parsen und zu analysieren, was zwangsläufig Rechenleistung benötigt. Wenn ein Rechner zu viel Zeit verbraucht mit Filtern, kann es auch sein, dass er anfängt, Pakete zu verwerfen. Weitere Methoden Zum Schluss gibt es noch weitere Ansätze, wie z.B. das Aufspüren lokaler Sniffer. 13 5. Networkstack Tests Kluge Leute lernen auch von ihren Feinden. (Aristoteles) Sniffer arbeiten so, dass sie alle Pakete, die über das Netzwerk transferiert werden, mithören können. Um dies zu erreichen, muss die Netzwerkkarte in den promiscuous mode geschaltet werden. Somit werden alle Pakete “blind” akzeptiert und zum Kernel weitergeleitet. Der Networkstack1 muss je nach Protokoll gewisse Funktionen erledigen, wie zum Beispiel auf einen ICMP Request einen Reply senden. Der Kernel kann nun einige Fehler machen, indem er zum Beispiel auf Anfragen antwortet, die nicht für ihn bestimmt sind. 5.1. Grundlagen 5.1.1. Hardware-Filter Jede Ethernet Netzwerkkarte wird durch eine so genannte, sechs Byte lange, MAC-Adresse repräsentiert. Jede Netzwerkkarte besitzt ein Satz von Filtern, die es benutzt um verschieden Arten von Paketen zu bearbeiten: Unicast Alle Pakete, welche als Ziel-Adresse die MAC der Karte eingetragen haben. Broadcast Alle Pakete, welche als Ziel-Adresse FF:FF:FF:FF:FF:FF haben. Multicast Alle Pakete, welche an eine speziell konfigurierte Multicast-Adresse gesendet werden. Diese Adressen müssen in der Multicast Liste der Netzwerkkarte registriert werden. Beispiele: 01:00:5E:00:00:00 Multicast-Adresse 0 Weder benutzt noch registriert auf der Netzwerkkarte. 01:00:5E:00:00:01 Multicast-Adresse 1 Adresse, mit der jeder Host in einem LAN adressiert werden kann. Falls die Netzwerkkarte Multicast unterstützt, sollte diese Adresse in der Liste eingetragen sein. All Multicast Alle Pakete, welche das group bit2 gesetzt haben. Beispiel: 01:00:00:00:00:00 Promiscuous Alle Pakete. Die Ziel-Adresse wird nicht überprüft. 1 2 siehe Anhang C erstes Byte ungerade 14 5.1. Grundlagen 5.1.2. Software-Filter Der Software-Filter ist abhängig vom Kernel des jeweiligen Betriebssystems. Die Hauptaufgabe dieses Filters besteht darin herauszufinden, für wen das Paket bestimmt war und dieses für den Kernel richtig Kennzuzeichnen. So soll vermieden werden, dass auf gesniffte Pakete so reagiert wird, wie wenn es ein Paket für den Host wäre. L INUX Um genaueres zu Erfahren kann im Anhang ?? nachgeschaut werden. Trotzdem einige Erläuterungen, wie der L INUX Software-Filter aufgebaut ist. L INUX klassifiziert Pakete in folgende 4 Typen: • TO_US Pakete: Ziel-Adresse ist unsere MAC-Adresse. • BROADCAST Pakete: Ziel-Adresse = FF:FF:FF:FF:FF:FF. • MULTICAST Pakete: Das group bit ist gesetzt. • OTHERHOST Pakete: Alle Anderen. Abbildung 5.1.: Der L INUX Software-Filter Networkstack Routinen wie zum Beispiel arp_rcv() oder ip_rcv() prüfen nun einfach, ob der Pakettyp OTHERHOST ist. Falls nein, wird bei Bedarf eine Antwort generiert. Eine Frage, die sich stellt, lautet: Warum behandelt L INUX Adressen, bei denen das group bit gesetzt ist automatisch als Multicast-Adresse? Diese Behandlung ist kein Fehler, denn 01:00:5E:xx:xx:xx Adressen sind IP-Multicast-Adressen, aber die MAC-Adresse wird auch von anderen Protokollen in höheren Layern benutzt. 15 5.1. Grundlagen W INDOWS Da der M$ W INDOWS Quellcode offiziell nicht zugänglich ist, ist es schwer, den Software-Filter zu analysieren. Es bleibt nicht viel übrig als mit diversen Tests den Mechanismus zu erraten. Siehe Abschnitt 5.1.3. 5.1.3. Reaktionen Legende — Abweisung des Pakets → Weiterleiten des Pakets Antwort generieren Nutzbare, falsche Antwort 16 gr.bit our MAC other MAC Broadcast (FF:FF:FF:FF:FF:FF) Fake Broadcast (FF:FF:FF:FF:FF:FE) Fake 16 Broadcast (FF:FF:00:00:00:00) Fake 8 Broadcast (FF:00:00:00:00:00) MCast not in List (01:00:5E:00:00:00) MCast in List (01:00:5E:00:00:01) Group Bit set (01:00:00:00:00:00) off W INDOWS XP normal promisc hw sw res hw sw res → → → → — → — L INUX 2.6 normal promisc hw sw res hw sw res → → → → — → — O PEN BSD normal promisc hw sw res hw sw res → → → → — → — → → → → → — → → — → → — → — → → → — → → — → → — — → → — — → → → — on on → — → → — → → → → — → → — → → → — → → → → — → → → → → → → → → — → → Tabelle 5.1.: Reaktionen auf ARP-Scans → → 5.2. ARP-Test 5.2. ARP-Test In diesem Abschnitt wird die Funktionsweise von ARP erklärt. Sollten Sie mit ARP vertraut sein, können Sie getrost den Abschnitt 5.2.1 überspringen. Danach wird kurz darauf eingegangen, um was es beim ARP-Test geht und welche Ansätze existieren. 5.2.1. Das Address Resolution Protocol Das Address Resolution Protocol wird für die dynamische3 Zuordnung zwischen einer 32-BitIP-Adresse und einer 48-Bit-MAC-Adresse verwendet. Die Arbeitsweise von ARP wird anhand folgenden Beispiels gezeigt. Jedes Mal, wenn ein Befehl der Form $ f t p k e r m i t . zhwin . ch eingegeben wird, werden die folgenden Schritte ausgeführt. Diese nummerierten Schritte sind in Abbildung 5.2 dargestellt. 1. Die Anwendung (der FTP Client) verwendet die Funktion gethostbyname(3), um den Hostnamen in eine 32-Bit-IP-Adresse umzuwandeln. 2. Der FTP Client fordert sein TCP auf, eine Verbindung zu dieser IP-Adresse aufzubauen. 3. TCP sendet einen Teil einer Verbindungsanfrage zum Remote-Host in der Form eines IP-Datagramms zu dessen IP-Adresse. 4. Befindet sich der Ziel-Host in einem lokal angeschlossenen Netzwerk, kann das IP-Datagramm direkt zu diesem Host gesendet werden. Sollte sich der Ziel-Host jedoch in einem entfernten Netzwerk befinden, ermittelt die IP-Routing-Funktion die Internetadresse eines im lokalen Netzwerk angeschlossenen Routers und stellt diesem das IP-Datagramm zu. In beiden Fällen wird also das IP-Datagramm zu einem Host oder Router im lokalen Netzwerk gesendet. 5. In einem Ethernet muss der sendende Host die 32-Bit-IP-Adresse in eine 48-Bit-EthernetAdresse umwandeln. Eine Übersetzung einer logischen Internet-Adresse in die entsprechende physikalische Hardware-Adresse ist also erforderlich. Dies ist die Funktion von ARP. 6. ARP sendet ein bestimmtes Ethernet-Frame, genannt ARP Request, an alle Host im Netzwerk4 . In Abbildung 5.2 sind die Broadcasts durch gepunktete Linien dargestellt. Der ARP Request beinhaltet die IP-Adresse des Ziel-Hosts sowie die Anforderung “Falls Sie Besitzer dieser IP-Adresse sind, geben Sie mir bitte Ihre Hardware-Adresse zurück”. 3 Wir verwenden den Begriff dynamisch, da dieser Vorgang automatisch abläuft und normalerweise keine Aufgabe für den Anwender oder Systemadministrator ist. 4 Dieses Prinzip wird Broadcasting genannt. 18 5.2. ARP-Test 7. Der ARP-Layer des Ziel-Hosts empfängt diesen Broadcast, erkennt, dass der Absender nach der entsprechenden Hardware-Adresse fragt, und antwortet mit einem ARP Reply, welcher die IP-Adresse und die entsprechende Hardware-Adresse des Ziel-Hosts beinhaltet. 8. Der ARP Reply wird empfangen und das IP-Datagramm, welches den ARP Request/Reply ausgelöst hat, kann nun gesendet werden. 9. Das IP-Datagramm wird zum Ziel-Host gesendet. Abbildung 5.2.: Die Arbeitsweise von ARP 19 5.2. ARP-Test Format eines ARP-Pakets Abbildung 5.3 zeigt das Format einer ARP Request/Reply-Nachricht im Zusammenspiel mit Ethernet. Abbildung 5.3.: ARP-Paket Um die einzelnen Felder besser zu verstehen, schauen wir uns einen ARP Request/Reply an. # a r p −d 1 6 0 . 8 5 . 1 6 3 . 7 4 $ ping 160.85.163.74 Mit arp -d 160.85.163.74 versichern wir uns, dass der ARP-Cache gelöscht ist. Aus dem Ethernet-Frame ist ersichtlich, dass der ARP Request an die Broadcast-Adresse geschickt wird. Im ARP-Paket trägt der Sender seine MAC- und IP-Adresse ein. Als Ziel-MAC trägt er lauter Nullen ein, da diese noch nicht bekannt ist. Das Feld Opcode zeigt an, dass es ein Request ist. E t h e r n e t II , Src : 0 0 : 0 6 : 1 b : ca : ea : 2 3 , Dst : f f : f f : f f : f f : f f : f f Destination : ff : ff : ff : ff : ff : ff ( Broadcast ) Source : 0 0 : 0 6 : 1 b : ca : ea :23 ( 1 6 0 . 8 5 . 1 6 4 . 2 3 4 ) Type : ARP ( 0 x0806 ) Address R e s o l u t i o n P r o t o c o l ( r e q u e s t ) Hardware t y p e : E t h e r n e t ( 0 x0001 ) P r o t o c o l t y p e : I P ( 0 x0800 ) Hardware s i z e : 6 Protocol size : 4 Opcode : r e q u e s t ( 0 x0001 ) S e n d e r MAC a d d r e s s : 0 0 : 0 6 : 1 b : c a : e a : 2 3 ( 1 6 0 . 8 5 . 1 6 4 . 2 3 4 ) Sender IP a d d r e s s : 1 6 0 . 8 5 . 1 6 4 . 2 3 4 ( 1 6 0 . 8 5 . 1 6 4 . 2 3 4 ) T a r g e t MAC a d d r e s s : 0 0 : 0 0 : 0 0 : 0 0 : 0 0 : 0 0 ( 0 0 : 0 0 : 0 0 _00 : 0 0 : 0 0 ) T a r g e t IP a d d r e s s : 1 6 0 . 8 5 . 1 6 3 . 7 4 ( 1 6 0 . 8 5 . 1 6 3 . 7 4 ) Listing 5.1: ARP Request Der ARP Reply geht nicht mehr als Broadcast auf die Leitung. Er ist direkt an den Absender gerichtet. Es sind alle Felder des ARP-Pakets ausgefüllt. Man beachte, dass das Feld Opcode nun auf Reply gesetzt ist. E t h e r n e t I I , S r c : 0 0 : 0 2 : a5 : 9 9 : 4 2 : 0 5 , D s t : 0 0 : 0 6 : 1 b : c a : e a : 2 3 D e s t i n a t i o n : 0 0 : 0 6 : 1 b : ca : ea :23 ( 1 6 0 . 8 5 . 1 6 4 . 2 3 4 ) 20 5.2. ARP-Test S o u r c e : 0 0 : 0 2 : a5 : 9 9 : 4 2 : 0 5 ( 1 6 0 . 8 5 . 1 6 3 . 7 4 ) Type : ARP ( 0 x0806 ) Address R e s o l u t i o n P r o t o c o l ( r e p l y ) Hardware t y p e : E t h e r n e t ( 0 x0001 ) P r o t o c o l t y p e : I P ( 0 x0800 ) Hardware s i z e : 6 Protocol size : 4 Opcode : r e p l y ( 0 x0002 ) S e n d e r MAC a d d r e s s : 0 0 : 0 2 : a5 : 9 9 : 4 2 : 0 5 ( 1 6 0 . 8 5 . 1 6 3 . 7 4 ) Sender IP a d d r e s s : 1 6 0 . 8 5 . 1 6 3 . 7 4 ( 1 6 0 . 8 5 . 1 6 3 . 7 4 ) T a r g e t MAC a d d r e s s : 0 0 : 0 6 : 1 b : c a : e a : 2 3 ( 1 6 0 . 8 5 . 1 6 4 . 2 3 4 ) T a r g e t IP a d d r e s s : 1 6 0 . 8 5 . 1 6 4 . 2 3 4 ( 1 6 0 . 8 5 . 1 6 4 . 2 3 4 ) Listing 5.2: ARP Reply 5.2.2. Methode Die einfachste Variante der ARP-Detektion ist die, dass man einen ARP Request an eine fake Broadcast-Adresse sendet. Wenn der Rechner mit dem ARP Reply antwortet, so befindet sich dieser Rechner wahrscheinlich im promiscuous mode. Abbildung 5.4.: ARP-Detektion 5.2.3. Erweiterungen Eine Variation der klassischen ARP-Detektion macht sich den ARP-Cache zu nutzen. Ein $ / u s r / s b i n / a r p −a s t d m e i e r m i 1 2 . zhwin . ch ( 1 6 0 . 8 5 . 1 7 9 . 1 6 9 ) \ a u f 0 0 : A0 : C9 : B4 : 0 B : A5 [ e t h e r ] a u f e t h 0 21 5.3. ICMP-Test s t d r e u s s h a l . zhwin . ch ( 1 6 0 . 8 5 . 1 6 3 . 7 4 ) \ a u f 0 0 : 0 2 : A5 : 9 9 : 4 2 : 0 5 [ e t h e r ] a u f e t h 0 edugw . zhwin . ch ( 1 6 0 . 8 5 . 1 6 0 . 1 ) \ a u f 0 0 : D0 : 0 3 : 2 2 : 7 C : 0A [ e t h e r ] a u f e t h 0 zeigt den lokalen ARP-Cache an. Jeder Eintrag beinhaltet alle nötigen Einträge, um ein Paket an den Ziel-Host zu senden. Nun kann man einen non-broadcast ARP Request senden. Danach macht man einen broadcast Ping. Jeder der antwortet, ohne zuvor einen ARP Request an uns gestellt zu haben, muss die MAC-Adresse aus einem gesnifften ARP Request haben. 5.2.4. Voraussetzungen • Funktioniert im shared und switched LAN. Der Switch leitet unbekannte MAC-Adressen an alle Ports weiter. • Die zu testende Maschine muss einen IP-Stack mit Schwächen im Software-Filter besitzen. 5.2.5. Evaluation Dieser Test bietet eine hohe Trefferquote und ist einfach zu implementieren. 5.3. ICMP-Test In diesem Abschnitt werden kurz ICMP Requests besprochen. Der Ansatz besteht darin ICMP Anfragen, mit einer falschen MAC-Adresse, an die richtige IP-Adresse zu senden. 5.3.1. Internet Control Message Protocol Echo-Request & Echo-Reply ICMP-Nachrichten werden in der Regel entweder von der IP-Schicht oder einem Protokoll einer höheren Schicht (TCP oder UDP) beachtet. Das Prinzip eines ICMP Request’s & Reply’s ist, dass ein Host einem anderen Host eine Anfrage schickt um zu antworten. Eine Anfrage wird meistens von einem Userprogramm namens PING erstellt, die Antwort beim Ziel-Host wird in den meisten TCP/IP-Implementationen vom Kernel gehandhabt. 22 5.3. ICMP-Test Abbildung 5.5.: Aufbau eines ICMP Request/Reply Paketes Die beiden Felder Typ und Code identifizieren das ICMP-Paket entweder als Request (8/0) oder als Reply (0/0). Das Feld Kennung enthält eine eindeutige ID. Unter U NIX ist es die Prozess-ID des aufrufenden Ping Programmes5 . Die Sequenznummer wird für jede einzelne Anfrage inkrementiert. Zusammenhängende Request’s und Reply’s haben dieselbe Sequenznummer. Um das Ganze besser zu verstehen, folgt ein Mitschnitt eines ICMP Request’s & Reply’s: $ p i n g s t d v e s e l r a n . zwhin . ch E t h e r n e t I I , S r c : 0 0 : 0 2 : a5 : 9 9 : 4 2 : 0 5 , D s t : 0 0 : 0 6 : 1 b : c a : e a : 2 3 I n t e r n e t P r o t o c o l , S r c Addr : s t d r e u s s h a l . zhwin . ch ( 1 6 0 . 8 5 . 1 6 3 . 7 4 ) , D s t Addr : s t d v e s e l r a n . zhwin . ch ( 1 6 0 . 8 5 . 1 6 4 . 2 3 4 ) I n t e r n e t C o n t r o l Message P r o t o c o l Type : 8 ( Echo ( p i n g ) r e q u e s t ) Code : 0 Checksum : 0 xa8b3 ( c o r r e c t ) I d e n t i f i e r : 0 xa908 S e q u e n c e number : 0 x0001 Data (56 b y t e s ) Listing 5.3: Echo Request E t h e r n e t I I , S r c : 0 0 : 0 6 : 1 b : c a : e a : 2 3 , D s t : 0 0 : 0 2 : a5 : 9 9 : 4 2 : 0 5 I n t e r n e t P r o t o c o l , S r c Addr : s t d v e s e l r a n . zhwin . ch ( 1 6 0 . 8 5 . 1 6 4 . 2 3 4 ) , D s t Addr : s t d r e u s s h a l . zhwin . ch ( 1 6 0 . 8 5 . 1 6 3 . 7 4 ) I n t e r n e t C o n t r o l Message P r o t o c o l Type : 0 ( Echo ( p i n g ) r e p l y ) Code : 0 Checksum : 0 xb0b3 ( c o r r e c t ) I d e n t i f i e r : 0 xa908 S e q u e n c e number : 0 x0001 Data (56 b y t e s ) Listing 5.4: Echo Reply 5 Man beachte die Networkorder 23 5.3. ICMP-Test 5.3.2. Methode Das Prinzip ist sehr einfach: Es wird ein ICMP Request an den zu testenden Host gesendet. Man verändert nun das Paket aber so, dass zwar die richtige Ziel-IP-Adresse aber eine fake Broadcast als Ziel-MAC-Adresse übertragen wird. Abbildung 5.6.: ICMP-Test Falls nun ein ICMP Reply vom zu testenden Host zurückkommt, wurde der Hardware-Filter nicht angewandt, das heisst, er muss seine Netzwerkkarte in den promiscuous mode geschaltet haben. Erweiterungen Dieser Test kann mit einer Vielzahl von Nachrichten der ICMP-Reihe, die Antworten generieren, realisiert werden. Natürlich kann auch ein beliebiges anderes Protokoll verwendet werden, das Antworten erzeugt, wie zum Beispiel der Echo- oder TCP-Dienste, falls zum Beispiel ICMP Request’s von einer Firewall geblockt werden. 5.3.3. Voraussetzungen • Funktioniert in shared und switched LAN. Der Switch leitet unbekannte MAC-Adressen an alle Ports weiter. • Die zu testende Maschine muss einen IP-Stack mit Schwächen im Software-Filter besitzen. • Es darf kein Filter aktiviert sein, der überprüft, ob Ziel-MAC-Adresse und Ziel-IP-Adresse ein gültiges Paar bilden. 24 5.4. Source Route 5.3.4. Evaluation Dieser Test hat nicht eine ganz so hohe Trefferquote wie der ARP-Test, ist aber als Ergänzung sehr gut geeignet, weshalb er auch implementiert wird. 5.4. Source Route Dieser Abschnitt bietet einen Überblick über die IP-Option source routing. Der Ansatz ist in etwa wie folgt gedacht: ICMP-Anfragen mit der loose source route Option ausstatten. So kann man eine Umleitung über einen anderen Host im gleichen Segment erzwingen. Dieser Host muss das Routing deaktiviert haben, falls nun doch eine ICMP-Antwort zurückkommt, befindet sich der angefragte Host höchstwahrscheinlich im promiscuous mode. 5.4.1. Source Routing Normal ist IP-Routing dynamisch, wobei jeder Router den nächsten Pfad selbst auswählt. Applikationen haben keinen Einfluss auf die Wegwahl. Die Idee hinter source routing ist, dass der Sender die Route spezifizieren kann. Es werden folgende zwei Varianten unterstützt: • strict source souting: Der Sender spezifiziert den genauen Pfad, dem das IP-Datagramm folgen muss. • loose source routing: Der Sender spezifiziert einen Pfad, den das IP-Datagramm traversieren muss. Das Paket kann aber auch über beliebige Zwischenstationen gehen. source routing ist eine Option des IP-Protokolls. Abbildung 5.7.: Format der source route Option im IP-Header Der Code ist 0x83 für loose source routing und 0x89 für strict source routing. Das Len Feld enthält die Anzahl Bytes des source routing Optionsfeldes. Ptr bedeutet Pointer. Dies ist ein Index, welcher auf die nächste IP-Adresse zeigt. In der Grafik 5.7 sieht man, welche Werte der Pointer annehmen kann. Die nächste Figur 5.8 zeigt, wie sich die Ziel-Adresse und das source routing Optionsfeld ändert. # weist auf die aktuelle Zeigerposition hin. 25 5.4. Source Route Abbildung 5.8.: Ablauf source routing Um das Ganze besser zu verstehen, folgt ein Mitschnitt eines source routed ICMP Request’s: $ . / s r c r o u t e _ p i n g edugw . zhwin . ch m a i l . zhwin . ch E t h e r n e t I I , S r c : 0 0 : 0 2 : a5 : 9 9 : 4 2 : 0 5 , D s t : 0 0 : a0 : c5 : 4 e : 9 5 : c f I n t e r n e t P r o t o c o l , S r c Addr : s t d r e u s s h a l . zhwin . ch ( 1 6 0 . 8 5 . 1 6 3 . 7 4 ) , D s t Addr : edugw . zhwin . ch ( 1 6 0 . 8 5 . 1 6 0 . 1 ) Version : 4 H e a d e r l e n g t h : 28 b y t e s D i f f e r e n t i a t e d S e r v i c e s F i e l d : 0 x00 ( DSCP 0 x00 : D e f a u l t ; ECN : 0 x00 ) T o t a l L e n g t h : 36 I d e n t i f i c a t i o n : 0 x0042 ( 6 6 ) F l a g s : 0 x00 Fragment o f f s e t : 0 Time t o l i v e : 64 P r o t o c o l : ICMP ( 0 x01 ) H e a d e r checksum : 0 x 0 3 f 2 ( c o r r e c t ) S o u r c e : s t d r e u s s h a l . zhwin . ch ( 1 6 0 . 8 5 . 1 6 3 . 7 4 ) D e s t i n a t i o n : dove . zhwin . ch ( 1 6 0 . 8 5 . 1 9 6 . 1 5 ) Options : (12 bytes ) NOP Loose s o u r c e r o u t e ( 1 1 b y t e s ) Pointer : 4 edugw . zhwin . ch ( 1 6 0 . 8 5 . 1 6 0 . 1 ) <− ( c u r r e n t ) dove . zhwin . ch ( 1 6 0 . 8 5 . 1 9 6 . 1 5 ) I n t e r n e t C o n t r o l Message P r o t o c o l Listing 5.5: source routing 5.4.2. Methode Der Trick bei dieser Methode ist, ein source routed Paket über einen Rechner im gleichen Segment zu versenden, der das Routing deaktiviert hat und somit das Paket verwirft. 26 5.4. Source Route Abbildung 5.9.: source routing Methode Falls nun der Sniffer das Paket liest, schickt er eine Antwort zurück. Erweiterungen Um ganz sicher zu gehen, dass der Rechner, über den geroutet werden soll das Paket auch verworfen hat, kann man noch das TTL-Feld überprüfen. Falls das Paket mit einem um eins oder mehr dekrementierten TTL-Feld zurückkommt, wurde es geroutet und wurde somit auf “normale” Weise beantwortet. Ist das TTL-Feld allerdings unverändert, deutet dies darauf hin, das sich das Ziel im promiscuous mode befindet. Voraussetzungen • Funktioniert nur im shared LAN. • Es muss ein dritter Host vorhanden sein, der IP-Routing deaktiviert hat. • Der zu untersuchende Host darf source routed Pakete nicht verwerfen. Evaluation Die meisten Rechner ignorieren source routed Pakete, deswegen ist die Chance bei dieser Methode positive Resultate zu erzielen sehr gering. Unter L INUX lässt sich leicht feststellen, ob source routed Pakete akzeptiert werden: # cat / proc / sys / net / ipv4 / conf / a l l / a c c e p t _ s o u r c e _ r o u t e 0 27 6. DNS Test Manche Sniffer, lösen IP-Adressen in Domainnamen auf, um die gesammelten Daten besser darzustellen. Um dies zu erledigen, muss der Sniffer selbst aktiv werden. 6.1. Das Domain Name System Das Domain Name System ist eine verteilte Datenbank, die von TCP/IP-Applikationen benutzt wird, um Hostnamen und IP-Adressen aufzulösen und Informationen für die Zustellung von EMails bereitzustellen. Da auch eine kurze Einführung den Rahmen diese Arbeit sprengen würde, begrenzen wir uns auf einzelne Pakete, welche für die Detektion von Sniffern nötig sind und erklären diese hier. Wir wollen uns die Namensauflösung anhand folgenden Beispiels anschauen. $ p i n g m u s t a n g . zhwin . ch Zuerst wird eine Anfrage in folgender Form an den DNS-Server gesendet. E t h e r n e t I I , S r c : 0 0 : 0 6 : 1 b : c a : e a : 2 3 , D s t : 0 0 : d0 : 0 3 : 2 2 : 7 c : 0 a I n t e r n e t P r o t o c o l , S r c Addr : 1 6 0 . 8 5 . 1 6 4 . 2 3 4 ( 1 6 0 . 8 5 . 1 6 4 . 2 3 4 ) , D s t Addr : 1 6 0 . 8 5 . 1 9 5 . 1 9 5 ( 1 6 0 . 8 5 . 1 9 5 . 1 9 5 ) U s e r Datagram P r o t o c o l , S r c P o r t : 32770 ( 3 2 7 7 0 ) , D s t P o r t : domain ( 5 3 ) Domain Name System ( q u e r y ) T r a n s a c t i o n ID : 0 x e 4 c c F l a g s : 0 x0100 ( S t a n d a r d q u e r y ) Questions : 1 Answer RRs : 0 A u t h o r i t y RRs : 0 A d d i t i o n a l RRs : 0 Queries m u s t a n g . zhwin . ch : t y p e A, c l a s s i n e t Listing 6.1: DNS-Query Die Antwort des DNS-Servers sieht folgendermassen aus: E t h e r n e t I I , S r c : 0 0 : 3 0 : 4 8 : 5 1 : 4 9 : bf , D s t : 0 0 : 0 6 : 1 b : c a : e a : 2 3 I n t e r n e t P r o t o c o l , S r c Addr : 1 6 0 . 8 5 . 1 9 5 . 1 9 5 ( 1 6 0 . 8 5 . 1 9 5 . 1 9 5 ) , D s t Addr : 1 6 0 . 8 5 . 1 6 4 . 2 3 4 ( 1 6 0 . 8 5 . 1 6 4 . 2 3 4 ) U s e r Datagram P r o t o c o l , S r c P o r t : domain ( 5 3 ) , D s t P o r t : 32770 ( 3 2 7 7 0 ) Domain Name System ( r e s p o n s e ) 28 6.1. Das Domain Name System T r a n s a c t i o n ID : 0 xc55b F l a g s : 0 x8580 ( S t a n d a r d q u e r y r e s p o n s e , No e r r o r ) Questions : 1 Answer RRs : 1 A u t h o r i t y RRs : 3 A d d i t i o n a l RRs : 5 Queries m u s t a n g . zhwin . ch : t y p e A, c l a s s i n e t Answers m u s t a n g . zhwin . ch : t y p e A, c l a s s i n e t , a d d r 1 6 0 . 8 5 . 1 9 2 . 3 0 A u t h o r i t a t i v e nameservers Additional records Listing 6.2: DNS-Response Das DNS wird auch für die Umsetzung von IP-Adressen zu Namen verwendet. Dies nennt man Reverse-DNS-Lookup. Schauen wir uns nun folgendes Beispiel an: $ host 160.85.192.30 Die Query an den DNS-Server hat folgende Form: E t h e r n e t I I , S r c : 0 0 : 0 6 : 1 b : c a : e a : 2 3 , D s t : 0 0 : d0 : 0 3 : 2 2 : 7 c : 0 a I n t e r n e t P r o t o c o l , S r c Addr : 1 6 0 . 8 5 . 1 6 4 . 2 3 4 ( 1 6 0 . 8 5 . 1 6 4 . 2 3 4 ) , D s t Addr : 1 6 0 . 8 5 . 1 9 5 . 1 9 5 ( 1 6 0 . 8 5 . 1 9 5 . 1 9 5 ) U s e r Datagram P r o t o c o l , S r c P o r t : 32770 ( 3 2 7 7 0 ) , D s t P o r t : domain ( 5 3 ) Domain Name System ( q u e r y ) T r a n s a c t i o n ID : 0 x c f 9 8 F l a g s : 0 x0100 ( S t a n d a r d q u e r y ) Questions : 1 Answer RRs : 0 A u t h o r i t y RRs : 0 A d d i t i o n a l RRs : 0 Queries 3 0 . 1 9 2 . 8 5 . 1 6 0 . i n −a d d r . a r p a : t y p e PTR , c l a s s i n e t Listing 6.3: Reverse-DNS-Query Der DNS-Server liefert uns den dazugehörigen Namen mustang.zhwin.ch. E t h e r n e t I I , S r c : 0 0 : 3 0 : 4 8 : 5 1 : 4 9 : bf , D s t : 0 0 : 0 6 : 1 b : c a : e a : 2 3 I n t e r n e t P r o t o c o l , S r c Addr : 1 6 0 . 8 5 . 1 9 5 . 1 9 5 ( 1 6 0 . 8 5 . 1 9 5 . 1 9 5 ) , D s t Addr : 1 6 0 . 8 5 . 1 6 4 . 2 3 4 ( 1 6 0 . 8 5 . 1 6 4 . 2 3 4 ) U s e r Datagram P r o t o c o l , S r c P o r t : domain ( 5 3 ) , D s t P o r t : 32770 ( 3 2 7 7 0 ) Domain Name System ( r e s p o n s e ) T r a n s a c t i o n ID : 0 x c f 9 8 F l a g s : 0 x8580 ( S t a n d a r d q u e r y r e s p o n s e , No e r r o r ) Questions : 1 Answer RRs : 1 A u t h o r i t y RRs : 2 A d d i t i o n a l RRs : 2 Queries 3 0 . 1 9 2 . 8 5 . 1 6 0 . i n −a d d r . a r p a : t y p e PTR , c l a s s i n e t 29 6.2. Methode Answers 3 0 . 1 9 2 . 8 5 . 1 6 0 . i n −a d d r . a r p a : t y p e PTR , c l a s s i n e t , m u s t a n g . zhwin . ch A u t h o r i t a t i v e nameservers Additional records Listing 6.4: Reverse-DNS-Response 6.2. Methode Einige Sniffer bieten die Möglichkeit des automatischen Reverse-DNS-Lookups an. Dadurch generiert der Sniffer jedoch zusätzlichen DNS-Traffic. Der Administrator kann diese Eigenschaft wie folgt ausnutzen. Zuerst pingt er eine IP-Adresse an. Danach versetzt er sich selbst in den promiscuous mode und snifft nach DNS-Queries. Abbildung 6.1.: Der DNS-Test Da der Sniffer die Namensauflösung On-the-Fly macht, generiert er eine DNS-Query. Der Administrator braucht nur die gesnifften Pakete nach dem Eintrag Queries 9 9 . 1 . 1 6 8 . 1 9 2 . i n −a d d r . a r p a : t y p e PTR , c l a s s i n e t zu durchsuchen. Der Rechner, der diese Anfrage generiert hat, ist im promiscuous mode. 30 6.3. Erweiterungen 6.3. Erweiterungen Da viele Sniffer sich bereits aufgelöste Adressen merken, kann man den Test beliebig oft wiederholen indem man zufällige IP-Adressen anpingt. 6.4. Voraussetzungen • Nur im shared LAN möglich. • Plattform- und Betriebssystem unabhängig. • Sniffer muss On-the-Fly DNS-Lookups machen. • Es besteht die Möglichkeit, mit einem einzigen Test, das ganze Subnet nach Sniffern abzusuchen. 6.5. Evaluation Der DNS-Test ist ein sehr zuverlässiger Indikator für einen Sniffer. Die Implementation ist zwar nicht ganz ohne, aber dieser Test wird realisiert. 31 7. LATENCY-Tests Der Machine-Latency Test ist ein der mächtigsten Detektionsmethoden. Damit besteht das Potenzial, Rechner im promiscuous mode, unabhängig des installierten Betriebssystems, zu detektieren. Diese Unabhängigkeit erkauft man sich mit zeitweiliger überhöhter Netzlast und einer Menge von Evaluationen der Erfahrungswerte. Trotzdem werden hier einige Ansätze vorgestellt. Der Hardware-Filter vergleicht von jedem ankommenden Paket die MAC-Adresse mit der eigenen Adresse. Stimmen die Adressen nicht überein, so wird das Paket verworfen. Diese Filterung ist eine “billige” Operation, weil das System nur wenig belastet wird. Der Kernel wird nur belastet, wenn die MAC-Adressen übereinstimmen oder wenn es sich um einen Broad- oder Multicast handelt. Versetzt man nun die Netzwerkkarte in den promiscuous mode, so wird die ganze HardwareFilterung umgangen und es wird softwaremässig gefiltert. Jedes ankommende Paket wird per Interrupt Service Routine an den Kernel weiter geleitet. Des Weiteren kommt hinzu, dass viele Sniffer im User-Space arbeiten. Das bedeutet, dass bei jedem ankommenden Paket, ein ContextSwitch vom Kernel- in den User-Space stattfindet. Dies ist eine “teure” Operation. In der Abbildung 4.3 ist die Filterung von L INUX ersichtlich. 7.1. ICMP-Time-Delta- & Ping-Drop-Test Beim Time-Delta-Test geht es darum, Antwortzeiten in einem Netzwerk zu messen. Das Netzwerk muss sich dafür einmal in einem belasteten und einmal in einem unbelasteten Zustand befinden. 7.1.1. Methode Als Erstes misst man, am Besten über mehrere Versuche, den durchschnittlichen Round-TripDelay. Im nächsten Schritt flooded man einen zweiten Rechner im Netz mit einer möglichst grossen Anzahl von Datenpaketen. Falls der Host im promiscuous mode ist, versucht er alle Datenpakete zu filtern, was Verzögerungen verursacht. Wenn wir nun während des floodens nochmals eine Reihe von Zeitmessungen untersuchen, sollten wir erhebliche Unterschiede feststellen. Auch kann es sein, dass Antworten ganz ausfallen → dropping. Zu beachten ist, dass das belastete Netz nicht ungeachtet an uns vorbeigeht. Unsere Pakete treten auch verzögert ins Netz, vor allem wenn wir die Rolle des Verkehrsgenerators übernehmen. 32 7.1. ICMP-Time-Delta- & Ping-Drop-Test Abbildung 7.1.: Time-Delta-Test 7.1.2. Erweiterungen Für diesen Test gibt es eine ganze Reihe von Erweiterungen. Um möglichst weit nach oben im Networkstack zu kommen, ist es sinnvoll zum Beispiel einen TCP 3-Way Handshake auszuführen. Viele offene Session zu erzeugen, kann auch einen “positiven” Seiteneffekt haben. Falls der zu untersuchende Rechner sogar offene well known Ports, auf die man Abfragen stellen kann, aufweist, hat dies zur Folge, dass sehr viel im User-Space behandelt werden muss. 7.1.3. Voraussetzungen • Nur im shared LAN möglich. • Das Netz muss für eine gewisse Zeit überbeansprucht werden können. • Sehr viele Erfahrungswerte müssen gesammelt werden. 7.1.4. Evaluation Dieser Test wird ganz sicher implementiert, auch wenn vordergründig erstmals ein paar Erfahrungswerte gesammelt werden müssen. 33 7.2. Timestamp-Request 7.2. Timestamp-Request ICMP Timestamp-Request gibt einem System die Möglichkeit, die Uhrzeit von einem anderen System abzufragen. Der empfohlene Rückgabewert ist eine Anzahl von Millisekunden nach Mitternacht Universal Time Coordinated (UTC). 7.2.1. ICMP-Timestamp-Request und -Reply Abbildung 7.2 zeigt den Header einer ICMP-Timestamp-Request/-Reply Nachricht. Abbildung 7.2.: ICMP Timestamp-Request/-Reply Nachricht Das abfragende System trägt die lokale Zeit, bevor das Paket über die Leitung geht, in das Feld Timestamp auslösen ein. Das antwortende System trägt einen Wert für Timestamp empfangen ein, sobald die Anforderung eintrifft, und einen Wert für Timestamp senden ein, wenn die Antwort gesendet wird. In der Praxis setzen die meisten Implementierungen allerdings die beiden letzten Felder gleich. Ursprünglich waren die drei Felder dafür gedacht, dass der Absender festhalten kann, wann er die Anforderung gesendet hat, und unabhängig davon die Dauer bis zur Übertragung der Antwort ermitteln kann. E t h e r n e t II , Src : 0 0 : 0 6 : 1 b : ca : ea : 2 3 , Dst : 0 0 : 3 0 : 4 f : 1 6 : 4 f : 1 e I n t e r n e t P r o t o c o l , S r c Addr : 1 9 2 . 1 6 8 . 1 . 3 3 ( 1 9 2 . 1 6 8 . 1 . 3 3 ) , D s t Addr : 1 9 2 . 1 6 8 . 1 . 2 ( 1 9 2 . 1 6 8 . 1 . 2 ) I n t e r n e t C o n t r o l Message P r o t o c o l Type : 13 ( Timestamp r e q u e s t ) Code : 0 Checksum : 0 x78ed ( c o r r e c t ) I d e n t i f i e r : 0 x00f2 S e q u e n c e number : 0 x01a8 O r i g i n a t e t i m e s t a m p : 33387899 Receive timestamp : 0 Transmit timestamp : 0 Listing 7.1: ICMP Timestamp-Request 34 7.2. Timestamp-Request E t h e r n e t II , Src : 0 0 : 3 0 : 4 f : 1 6 : 4 f : 1 e , Dst : 0 0 : 0 6 : 1 b : ca : ea :23 I n t e r n e t P r o t o c o l , S r c Addr : 1 9 2 . 1 6 8 . 1 . 2 ( 1 9 2 . 1 6 8 . 1 . 2 ) , D s t Addr : 1 9 2 . 1 6 8 . 1 . 3 3 ( 1 9 2 . 1 6 8 . 1 . 3 3 ) I n t e r n e t C o n t r o l Message P r o t o c o l Type : 14 ( Timestamp r e p l y ) Code : 0 Checksum : 0 x8904 ( c o r r e c t ) I d e n t i f i e r : 0 x00f2 S e q u e n c e number : 0 x01a8 O r i g i n a t e t i m e s t a m p : 33387899 R e c e i v e t i m e s t a m p : 33387895 T r a n s m i t t i m e s t a m p : 33387895 Listing 7.2: ICMP Timestamp-Reply Hier sieht man schön, dass das abfragende System um vier Millisekunden dem abgefragten System voraus ist. Es gibt ein Detail, welches es zu beachten gilt. Ein System, welches die Zeit nicht standardkonform zurückgeben kann, muss das MSB setzen. 7.2.2. Methode Der Administrator sendet nun über einen längeren Zeitraum ICMP Requests und misst dabei den Round-Trip-Delay. Danach wird das Netz für kurze Zeit mit gefälschten Paketen geflutet und die Messung des RTD wiederholt. Da der abhörende Rechner die riesige Datenflut softwaremässig filtern muss, erhöht sich seine Reaktionszeit beträchtlich. 7.2.3. Erweiterungen Uns sind keine Erweiterungen bekannt. 7.2.4. Voraussetzungen • Funktioniert nur im shared LAN. 7.2.5. Evaluation Durch Tests haben wir festgestellt, dass die Felder Timestamp empfangen und Timestamp senden von den Betriebssystemen immer auf die gleichen Werte initialisiert werden. Dadurch ist diese Methode für uns nicht brauchbar. 35 8. Weitere Methoden Dieses Kapitel ist der vollständigkeitshalber aufgeführt. Die hier vorgestellten Methoden sind nicht Teil dieser Diplomarbeit. 8.1. Host Der Administrator kann mittels ifconfig den Status der Netzwerkschnittstellen überprüfen. Dies setzt jedoch voraus, dass der Rechner nicht gehackt wurde und die Systemprogramme nicht ersetzt wurden. Des Weiteren muss sichergestellt sein, dass keine Kernel-Module installiert sind, welche die System-Calls abfangen und die Ausgabe von ifconfig verfälschen. # i f c o n f i g −a l o 0 : f l a g s =8049 <UP , LOOPBACK, RUNNING, MULTICAST> mtu 33224 i n e t 1 2 7 . 0 . 0 . 1 netmask 0 xff000000 i n e t 6 : : 1 p r e f i x l e n 128 i n e t 6 f e 8 0 : : 1 % l o 0 p r e f i x l e n 64 s c o p e i d 0 x6 x l 0 : f l a g s =8943 <UP , BROADCAST, RUNNING, PROMISC , SIMPLEX , MULTICAST> \ mtu 1500 a d d r e s s : 0 0 : 0 4 : 7 5 : c1 : 1 a : 7 3 media : E t h e r n e t a u t o s e l e c t ( 1 0 0 baseTX ) status : active i n e t 6 f e 8 0 : : 2 0 4 : 7 5 f f : f e c 1 : 1 a73%x l 0 p r e f i x l e n 64 s c o p e i d 0 x1 i n e t 1 6 0 . 8 5 . 1 7 0 . 1 3 1 netmask 0 x f f f f e 0 0 0 b r o a d c a s t 1 6 0 . 8 5 . 1 9 1 . 2 5 5 x l 1 : f l a g s =8802 <BROADCAST, SIMPLEX , MULTICAST> mtu 1500 a d d r e s s : 0 0 : 0 4 : 7 5 : c1 : 0 b : d7 media : E t h e r n e t a u t o s e l e c t ( none ) s t a t u s : no c a r r i e r p f l o g 0 : f l a g s =0<> mtu 33224 p f s y n c 0 : f l a g s =0<> mtu 2020 e n c 0 : f l a g s =0<> mtu 1536 Listing 8.1: O PEN BSD: ifconfig -a Aus diesem Beispiel ist ersichtlich, dass sich das Interface xl0 im promiscuous mode befindet. Arbeitet man auf einem L INUX Rechner, so muss man Folgendes machen: $ dmesg | g r e p − i p r o m i s c u o u s d e v i c e e t h 0 e n t e r e d p r o m i s c u o u s mode d e v i c e e t h 0 l e f t p r o m i s c u o u s mode Listing 8.2: L INUX: dmesg | grep -i promiscuous 36 8.2. Decoy 8.2. Decoy Das Verb to decoy stammt aus dem Englischen und bedeutet ködern. Der Administrator legt einen Köder, in Form eines Testrechners, auf dem der Telnet-Login aktiviert ist, aus. Telnet hat die unangenehme Eigenschaft, dass der Username und das Passwort im Klartext gesendet werden. Auf dem Testrechner ist nur dieser Account zum Schein aktiviert. Er wird permanent geloggt. Der potenzielle Hacker snifft nun die Username/Passwort-Kombination und versucht sich auf dem Server einzuloggen. Et voilà. 8.3. SNMP So genannte Smart-Hubs bieten die Möglichkeit via SNMP überwacht zu werden, an. Es werden Optionen wie • Logging der Verbindungen. D. h., es werden alle MAC-Adressen mit dem dazugehörigen Port geloggt. • Überwachung der Bandbreite. • Statische Zuordnung der Anschlüsse. → Switch angeboten. Die Möglichkeiten sind von Hersteller zu Hersteller verschieden. 37 Teil III. SAD — Sniff And Die Zusammenfassung Dieser Teil beschäftigt sich mit der Implementierung von SAD. Die Designentscheidungen und das daraus folgende Framework werden dem Leser vorgestellt. Danach wird ihm gezeigt, wie er SAD mit eigenen Plugins erweitern kann. 9. Design Programmer: A device for converting coffee into software (unknown) Das im Rahmen dieser Diplomarbeit entwickelte Tool trägt den Name SAD, welcher für S NIFF A ND D IE steht. Der Name spielt auf eine düstere Zeit für Script-Kiddies an, denn von jetzt an können Sie detektiert werden. Es soll keine Anspielung auf SED, welches ein stream editor ist, sein1 . Bei der Entwicklung wurde grosser Wert auf modularen Aufbau, Erweiterbarkeit und Plattformunabhängigkeit gelegt. Daraus ergaben sich die zwei Komponenten von SAD: 1. Das Framework 2. Die Plugins Im Kapitel 10 wird auf die einzelnen Komponenten des Framework’s eingegangen. Kapitel 11 erklärt dem Leser das Schreiben von Plugins in C++ unter L INUX. Getrieben durch den Gedanken der Plattformunabhängigkeit, versuchten wir möglichst Bibliotheken, welche erfolgreich auf den meisten Plattformen laufen, einzusetzen. Infolgedessen fiel unsere Wahl auf folgende Bibliotheken: C++-STL [14, 15] als Basis für alle Container. B OOST [13] kam bei den Threads zum Einsatz. libConfuse [21] wurde für das Parsen der Konfigurationsdatei benutzt. libnet [16] wurde für das Bauen der Datenpakete verwendet. libpcap [19] übernahm das Fangen der Datenpakete. 1 Wir hoffen jedoch, dass es für Administratoren genau so nützlich ist 39 9.1. UML-Diagramm 9.1. UML-Diagramm Abbildung 9.1.: UML-Diagramm von SAD 40 10. Das Framework The trouble with doing something right the first time is that nobody appreciates how difficult it was. (unknown) Hier werden alle Klassen im Zusammenhang mit dem Framework beschrieben. Den Plugins ist ein eigenes Kapitel (Nr. 11) gewidmet. 10.1. Der Option-Manager Da jedes Plugin eigene Optionen zur Verfügung stellt, musste ein Weg gefunden werden, wie diese gemanagt werden sollen. Für diesen Zweck wurde die Klasse OptionMgr, welche als Singleton1 realisiert ist, geschaffen. c l a s s OptionMgr { private : OptionMgr ( ) ; s t a t i c OptionMgr ∗ i n s t a n c e ; multimap < s t r i n g , O p t i o n > o p t i o n s ; ... public : s t a t i c OptionMgr ∗ g e t I n s t a n c e ( v o i d ) ; void addOption ( s t r i n g , Option ) ; c o n s t multimap < s t r i n g , O p t i o n > ∗ c o n s t g e t O p t i o n s ( v o i d ) c o n s t ; friend class console ; ... }; Listing 10.1: Die Klasse OptionMgr Dass es sich um einen Singleton handelt, sieht man am privaten Konstruktor und dem Zeiger auf sich selbst. Alle Optionen von SAD und den Plugins, werden in der multimap verwaltet. Als Schlüssel dient der Plugin-Name. Die Optionen haben folgende Form: s t r u c t Option { 1 Infos zu Design-Patterns findet man unter [9] 41 10.2. Der Configfile-Parser string sopt ; string lopt ; arg has_arg ; s t r i n g argument ; string description ; Option ( s t r i n g s , s t r i n g l , arg at , s t r i n g a , s t r i n g d ) : s o p t ( s ) , l o p t ( l ) , h a s _ a r g ( a t ) , a r g u m e n t ( a ) , d e s c r i p t i o n ( d ) {} }; Listing 10.2: Der Option-Struct Eine Option hat den von getopt_long()2 her bekannten Aufbau. Bei uns ist es jedoch möglich, als Kurzoption auch mehrere Zeichen zu benutzen. Option example = { "− f i p " , "−−f a k e −i p " , REQ_ARG, " 1.1.1.1 " , " S p e c i f i e s t h e Fake I P " }; Listing 10.3: Aufbau einer Option void OptionMgr::addOption(String, Option) Mit dieser Methode können die Plugins ihre Optionen dem Option-Manager beifügen. Ein Beispiel für die Anwendung ist im Abschnitt 10.7 gezeigt. const multimap<string, Option>* const getOptions(void) const Diese Methode liefert einen Zeiger auf das private Attribut options. Damit ist es, sowohl dem Framework als auch den Plugins, möglich, auf die Optionen zu zugreifen. friend class console Der Kommandozeilen-Parser braucht Schreibzugriff auf den Option-Manager. Der Anwender möchte ja die Default-Werte überschreiben können. Um unnötige getter und setter Methoden zu schreiben, deklarierten wir die Klasse console als friend. Damit hat die Klasse console vollen Zugriff auf alle Elemente des Option-Managers. 10.2. Der Configfile-Parser LIB C ONFUSE ist eine, unter der LGPL[3] stehende, Bibliothek zum Parsen von Konfigurationsdateien. Es werden im Wesentlichen Sections und List of Values unterstützt. Des Weiteren ist 2 man 3 getopt_long 42 10.2. Der Configfile-Parser LIB C ONFUSE in der Lage sowohl, C-, C++- als auch shellartige Kommentare zu handhaben. Der Aufbau der Konfigurationsdatei von SAD ist wie folgt: p l u g i n ARP { p a t h = / u s r / l o c a l / l i b / sad / l i b a r p . so . 0 # Path t o t h e P l u g i n t r u s t = 0.8 / / How much do I t r u s t t h i s P l u g i n ? evaluation = " true " /∗ Should I e v a l u a t e t h e r e s u l t s ∗/ } Listing 10.4: Aufbau von sad.conf Hier sind die möglichen Kommentare gut ersichtlich. Die Klasse cfgParser hat die Aufgabe, diese Einträge zu parsen und zu verwalten. class cfgParser { private : cfgParser ( ) ; static cfgParser ∗ instance ; static string cfgfile_ ; struct cfgval { s t r i n g path ; float trust ; cfg_bool_t evaluation ; }; map< s t r i n g , c f g v a l > p l u g i n ; ... public : s t a t i c c f g P a r s e r ∗ g e t I n s t a n c e ( void ) ; vector < s t r i n g > g e t P a t h ( void ) ; vector < s t r i n g > getPlugInName ( void ) ; float getTrust ( string ); bool g e t E v a l u a t i o n ( s t r i n g ) ; ... }; Listing 10.5: Die Klasse cfgParser Da wir nur einen Parser brauchen, ist diese Klasse ebenfalls als Singleton implementiert. Die folgende Methoden werden von SAD benötigt und darum hier beschrieben. vector<string>getPath(void) 43 10.3. Der Kommandozeilen-Parser Diese Methode iteriert durch die map<string, cfgval> plugin durch und liefert alle eingetragenen Pfade der zu ladenden Plugins. Diese werden von SAD für das Laden der Plugins verwendet. vector<string>getPlugInName(void) Diese Methode extrahiert alle Plugin-Namen aus der map<string, cfgval> plugin. Nötig sind diese Namen für die Verwaltung der geladenen Plugins. float getTrust(string) Hiermit wir ein Wert zwischen 0 und 1 zurückgegeben. Die genaue Verwendung wird im Abschnitt 10.7.1 erläutert. bool getEvaluation(string) Da im Konfigurationsfile eingestellt werden kann, ob man das Resultat eines Plugins in die Gesamtbewertung mit einbeziehen will, braucht man diese Methode, um den Wert auszulesen. 10.3. Der Kommandozeilen-Parser Da getopt_long() Kurzoptionen mit nur einem Buchstaben unterstützt, wurde diese Klasse geschrieben. class console { private : OptionMgr ∗ o p t s _ ; ... public : i n t c m d p a r s e ( i n t , char ∗ ∗ ) ; / / r e t u r n s 0 on s u c c e s s ... }; Listing 10.6: Die Klasse console int cmdparse(int, char **) Diese Methode parst die Kommandozeile und unternimmt allfällige Änderungen am OptionManager. Ihr werden die Parameter argc und *argv[] übergeben. Der Aufbau der Kommandozeile hat folgende Form: # s a d [−PluginName ] [ P l u g I n O p t s i o n s ] [ s a d O p t i o n s ] T a r g e t −IP 44 10.4. Threads 10.4. Threads Damit wir eine einheitliche Thread Schnittstelle haben, wurde die abstrakte Klasse SadThread ins Leben gerufen. Sie schreibt vor, das der Aufrufoperator () überschrieben wird3 . Diese Methode kann man sich wie die run() Methode bei JAVA-Threads vorstellen. 10.4.1. InjectionThread Die Hauptaufgabe dieser Klasse besteht darin, vom Plugin gebaute und via addPacket(libnet_t *) hinzugefügte Pakete, ins Netz zu stellen. Dafür gibt es zwei Modi: • Die kontinuierliche Variante, die ohne Unterbruch alle angeforderten Pakete sendet. • Die unstetige Variante, welche nach jedem Paket eine vorgegebene Zeit wartet. 10.4.2. CaptureThread Der CaptureThread ist einfach gesagt eine Wrapperklasse für LIBPCAP. Nebst den Standardaufrufen für LIBPCAP müssen wir den Filter auf nonblocking setzen, weil wir bei unseren Tests nicht sicher gehen können, überhaupt eine Antwort zu fangen. i f ( p c a p _ s e t n o n b l o c k ( h a n d l e , C a p t u r e T : : NONBLOCK_TRUE, e r r b u f ) < 0 ) throw L i b p c a p E x ( e r r b u f ) ; Listing 10.7: CaptureT: nonblocking Mit Hilfe des Konstruktors können alle Eigenschaften dieses Threads gesetzt werden: C a p t u r e T ( char ∗ , s t r i n g , i n t /∗ Device : ∗ BPF F i l t e r S t r i n g : ∗ Z e i t i n ms : ∗ ∗ Anzahl Versuche : ∗ ∗ VorzeitigerAbbruch : ∗ ∗ ∗ Rueckgabewert : ∗/ , int , int , i n t &); zB " e t h 0 " man tcpdump Z e i t , d i e nach e i n e m e r f o l g l o s e n p c a p _ n e x t b i s zum n a e c h s t e n V e r s u c h g e w a r t e t w i r d . Wird f o r t l a u f e n d d e k r e m e n t i e r t . V e r s u c h e = 0 −−> Abbruch Nachdem d i e s A n z a h l P a k e t e g e f a n g e n wurde −−> V o r z e i t i g e r Abbruch Anzahl gefangener Pakete Listing 10.8: CaptureT: Konstruktor Der CaptureT fängt alle Pakete, die mit dem Filter übereinstimmen und inkrementiert jeweils den Rückgabewert. Falls (Zeit · AnzahlV ersuche) ms abgelaufen sind, ohne ein Paket zu fangen, beendet sich der Thread. 3 Handhabung von B OOST::Thread 45 10.5. Die Scan-Strategy 10.5. Die Scan-Strategy Die Klasse ScanStrategy ist das Kernstück der ganzen Plugin-Umgebung. Diese abstrakte Klasse hat folgende zwei Hauptaufgaben: 10.5.1. Vorlage für Plugins Die wichtigste Methode der ScanStrategy ist virtual void scan(void) = 0, welche alle Plugins implementieren müssen, und im eigentlichen Sinne die “main()” Funktion eines Plugins darstellt. Des Weiteren werden folgende, von allen Plugins gebrauchte, Member-Variablen zur Verfügung gestellt: • bool verbose • int loop Bestimmt, ob eine detaillierte Ausgabe erfolgen soll. Anzahl Wiederholungen des Tests. • char *device Das Interface auf das LIBNET und LIPCAP zugreifen. • u_int32_t ip_src Die IP-Quell-Adresse • u_int32_t ip_dst Die IP-Ziel-Adresse • libnet_t* context • char errbuf[] Ein LIBNET Kontext Ein Errorstring für diverse LIBNET Funktionen • stringstream filter Dient als Hilfe, um einen Filter zu bauen4 . Kommunikation mit dem Option-Manager Folgende Methoden bewirken das Zusammenspiel mit dem OptionMgr: void pushOpt(Option) Eine Hilfsmethode, die von den Plugins benutzt werden muss, um ihre Optionen global beim OptionMgr bekannt zu machen. void setGlobalVal(void) Setzt alle oben beschriebenen Variablen auf die von console eingelesenen oder standard Werte. setLocalVal(void) = 0 Ist eine rein abstrakte Methode, die von allen Plugins überschrieben werden muss und den Zweck hat, dass die Plugins ihre Werte auf die eingelesenen Werte setzen. void usage(void) const Das sich die Plugins nicht auch noch um die Ausgabe und Darstellung ihrer Optionen kümmern müssen, stellt ScanStrategy diese Funktion zur Verfügung. 4 stringstreams sind viel flexibler als strings in der Handhabung mit unterschiedlichen Datentypen 46 10.5. Die Scan-Strategy 10.5.2. Thread Handling Die Plugins müssen sich nicht um das Starten von Threads kümmern. Sie bekommen ein Interface zur Verfügung gestellt, welches ihnen einfaches Hinzufügen von beliebigen InjectionThreads und CaptureThreads ermöglicht. Das Plugin kann dann zu einem gewünschten Zeitpunkt mit Hilfe der Methode startThreads() alle hinzugefügten Threads starten. v o i d S c a n S t r a t e g y : : a d d T h r e a d ( S a d T h r e a d &t ) { i f ( dynamic_cast < C a p t u r e T ∗>(& t ) ) t h r e a d s . p u s h _ f r o n t (& t ) ; e l s e i f ( dynamic_cast < I n j e c t i o n T ∗>(& t ) ) t h r e a d s . p u s h _ b a c k (& t ) ; } Listing 10.9: ScanStrategy::addThread() CaptureThreads sollen vorne angefügt werden, sodass sie auch bestimmt vor den InjectionThreads gestartet werden. → Antworten werden sicher gefangen. void S c a n S t r a t e g y : : s t a r t T h r e a d s ( ) { try { boost : : thread_group threadg ; deque < S a d T h r e a d ∗ > : : i t e r a t o r d i ; f o r ( d i = t h r e a d s . b e g i n ( ) ; d i ! = t h r e a d s . end ( ) ; ++ d i ) { i f ( C a p t u r e T ∗ c t = dynamic_cast < C a p t u r e T ∗> ( r e i n t e r p r e t _ c a s t < S a d T h r e a d ∗ >(∗ d i ) ) ) threadg . c r e a t e _ t h r e a d (∗ c t ) ; e l s e i f ( I n j e c t i o n T ∗ i t = dynamic_cast < I n j e c t i o n T ∗> ( r e i n t e r p r e t _ c a s t < S a d T h r e a d ∗ >(∗ d i ) ) ) threadg . c r e a t e _ t h r e a d (∗ i t ) ; } threadg . join_all ( ) ; threads . clear ( ) ; } c a t c h ( b o o s t : : t h r e a d _ r e s o u r c e _ e r r o r bex ) throw BoostEx ( " t h r e a d _ r e s o u r c e _ e r r o r " ) ; } Listing 10.10: ScanStrategy::startThreads() Diese Methode startet alle Threads die vorhin hinzugefügt wurden, wartet anschliessend auf die Beendigung aller und entfernt sie aus der Queue. 47 10.6. Exceptions 10.6. Exceptions Exceptions bringen in einem objektorientierten Design erhebliche Vorteile: • Exception-Handling ist im Programmcode eindeutig erkennbar. • Regulärer Code wird durch Exception-Handling kaum belastet. • Jede Exception muss behandelt werden, ansonsten findet ein Abbruch statt. • durch Parametrisierung mit Typen und Objekten, fein dosierte Reaktion auf unterschiedliche Fehlerarten möglich. • Einheitliches Sprachmittel führt zu portablen Lösungen. 10.6.1. SadEx Wir haben eine Super-Klasse SadEx definiert, welche so aufgebaut ist: c l a s s SadEx { protected : s t r i n g errorMessage ; public : SadEx ( s t r i n g e ) : e r r o r M e s s a g e ( e ) {} s t r i n g operator ( ) ( ) { return errorMessage ; } }; Listing 10.11: SadEx Es ist eine ganz einfache Klasse, die im Wesentlichen einen String enthält, der die Fehlermeldung speichern kann. Durch den Aufrufoperator () kann man diese Fehlermeldung wieder auslesen. Nun kann man für jede Art von Fehlerklasse eine eigene Ableitung von SadEx definieren: c l a s s L i b n e t E x : p u b l i c SadEx { public : L i b n e t E x ( s t r i n g e ) : SadEx ( " L i b n e t : " + e ) {} }; Listing 10.12: Ableitung von SadEx 10.6.2. Anwendung In einem Plugin könnte ein Fehler auftreten: i f ( ( c o n t e x t = l i b n e t _ i n i t ( LIBNET_LINK , d e v i c e , e r r b u f ) ) == 0 ) throw L i b n e t E x ( e r r b u f ) ; Listing 10.13: Eine Exception werfen 48 10.6. Exceptions SAD muss diese Exception abfangen und behandeln: try s c a n r e s u l t s [ ∗ i t e r ] = s s t r a t [ ∗ i t e r ]−> s c a n ( ) ; c a t c h ( SadEx ex ) { c e r r << ex ( ) << e n d l ; e x i t ( EXIT_FAILURE ) ; } Listing 10.14: Eine Exception abfangen 49 10.7. SAD 10.7. SAD Hier treffen alle Klassen zusammen. Der Programmablauf ist folgender: Abbildung 10.1.: Flussdiagramm: SAD-Ablauf Für das ganze Management der Klasse sind folgende Konstrukte notwendig: map< s t r i n g , S c a n S t r a t e g y ∗> s s t r a t ; / / P o i n t e r t o O b j e c t s s t r u c t soManager { v e c t o r < v o i d ∗> p p t r ; v e c t o r < c r e a t e S S _ t ∗> c f u n c ; v e c t o r < d e s t r o y S S _ t ∗> d f u n c ; } mgr ; // // // // Pointer to PluginHandler CreateFunction DestroyFunction libmanager Listing 10.15: SAD Verwaltungs-Konstrukte 50 10.7. SAD Die STL-Map sstrat verwaltet die aus den Plugins kreierten Objekte. Der Schlüssel der Map ist der Plugin-Name. Der Wert zum Schlüssel ist ein Zeiger auf eine ScanStrategy. Die Struktur soManager beinhaltet einen Plugin-Handler und die Create- und Destroy-Funktionen. Mehr zu den Create- und Destroy-Funktionen finden Sie im Kapitel 11. SAD muss, wie jedes andere Plugin, seine globalen Optionen bekannt geben. Dem Administrator stehen folgende Optionen zur Verfügung: SAD O p t i o n s : −i f −− i n t e r f a c e −t i p −−t a r g e t −i p −s i p −−s o u r c e −i p −v −−v e r b o s e <Scanning device > < t a r g e t IP > < s o u r c e IP > verbose output Listing 10.16: Optionen von SAD 10.7.1. Rating Da es unter gewissen Umständen, welche durch das Netz gegeben sind, zu falschen Verdächtigungen5 kommen kann, mussten wir ein Rating einführen. Im Kapitel 10.2 ist der Aufbau eines Eintrages der Konfigurationsdatei beschrieben. Das Feld trust ist ein Erfahrungswert, welcher das Vertrauen in diese Methode widerspiegelt. Es kann ein Wert von 0. . .1 angegeben werden. Der boolean evaluation gibt an, ob der Test in die Schlussbewertung mit aufgenommen werden soll. Diese Option wurde eingeführt, da gewisse Sniffer einige Tests6 austricksen können. Dadurch hat der Administrator die Möglichkeit das Resultat des Tests anzuzeigen, jedoch nicht zu berücksichtigen. # . / sad 1 6 0 . 8 5 . 1 6 3 . 7 4 ScanResults : −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− Method Testresult % Trust Evaluation −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− ARP 100 % 0.8 1 DNS 100 % 1.0 0 ICMP 100 % 0.6 1 −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− Sum : 70 % Listing 10.17: Ausgabe von SAD Das Schlussresultat ist der Mittelwert der zu evaluierenden Tests. Sum := 5 6 N 1 X Evaluation · T rust · T estresult N i=1 weitere Informationen dazu, finden sich im Kapitel 15 wie z.B. der DNS-Test. Mehr dazu im Kapitel 12.3 51 11. Plugin-HowTo Plugins sind unter L INUX nichts anderes als dynamisch geladene Bibliotheken1 . Sie können zu jedem beliebigen Zeitpunkt zum Programm dazugeladen werden. 11.1. Das L INUX-Plugin-Interface Unter L INUX, besteht im Aufbau einer shared und einer dynamic loaded Library kein Unterschied. Einzig der Zeitpunkt des Ladens der Library variiert. L INUX stellt eine API zum öffnen, durchsuchen, behandeln von Fehlern und schliessen des Plugins zur Verfügung. Die Schnittstellen sind in <dlfcn.h> definiert. v o i d ∗ d l o p e n ( c o i n s t char ∗ f i l e n a m e , i n t f l a g ) ; v o i d ∗ dlsym ( v o i d ∗ h a n d l e , c o n s t char ∗ symbol ) ; char ∗ d l e r r o r ( v o i d ) ; i n t d l c l o s e ( void ∗ handle ) ; Listing 11.1: Das L INUX-Plugin-Interface 11.2. Probleme mit C++ Da das API in und für C geschrieben wurde, zieht das einige Probleme beim Laden von Klassen mit sich. Wie den meisten bekannt sein sollte, verfügt C++ über einen Mechanismus zum Überladen von Funktionen2 und Methoden. Um diese Mehrdeutigkeit zu handhaben, hängt der Compiler zusätzliche Zeichen an das entsprechende Symbol in der Symboltabelle an. Sei eine Funktion void foo ( void ) ; gegeben. Der C-Compiler trägt in die Symboltabelle ein Symbol mit dem Namen foo 1 2 auch shared objects genannt verschiedene Funktionen mit demselben Namen, aber unterschiedlicher Anzahl von Argumenten 52 11.3. Die Umsetzung bei SAD ein. Der C++-Compiler jedoch, verunstaltet den Namen und fügt in die Symboltabelle Folgendes ein: foo@5%6^ Dies wäre an und für sich nicht schlimm, würden dies alle Compiler gleich machen. Das macht es wiederum für den Programmierer unmöglich das gesuchte Symbol in einem Plugin zu finden. Bei Klassen kommt noch ein Problem, neben der Verunstaltung der Namen in der Symboltabelle, auf uns zu. Da wir mit Instanzen von Klassen arbeiten und nicht mit Zeigern auf Funktionen muss ein Weg geschaffen werden, um diese zu erstellen3 . extern "C" und class factory functions sind die Schlüsselmechanismen für die Lösung dieses Problems. Das C++ dlopen mini HOWTO[11] schreibt: The solution is achieved through polymorphism. We define a base, interface class with virtual members in the executable, and a derived, implementation class in the module. Generally the interface class is abstract (a class is abstract if it has pure virtual functions). 11.3. Die Umsetzung bei SAD Das Framework stellt die abstrakte Klasse ScanStrategy zur Verfügung. Diese definiert die Methoden, welche von den Plugins zur Verfügung gestellt werden müssen. Die Typen der class factory functions werden auch von der ScanStrategy vorgegeben. t y p e d e f S c a n S t r a t e g y ∗ c r e a t e S S _ t ( c o n s t char ∗ , OptionMgr ∗ ) ; typedef void d e s t r o y S S _ t ( S c a n S t r a t e g y ∗ ) ; Listing 11.2: Definition der class factory functions im ScanStrategy.hpp Die einzelnen Plugins implementieren nun die class factory functions wie folgt: e x t e r n "C" { return } e x t e r n "C" { delete } S c a n S t r a t e g y ∗ c r e a t e ( char ∗n , OptionMgr ∗ o p t ) new a r p ( n , o p t ) ; void d e s t r o y ( S c a n S t r a t e g y ∗p ) p; Listing 11.3: class factory functions am Beispiel vom ARP-Plugin 3 Weitere Informationen können in [11] nachgelesen werden 53 11.4. Schreiben eines eigenen Plugins 11.4. Schreiben eines eigenen Plugins Der Ablauf beim Schreiben eines Plugins besteht aus vier Schritten. 1. Bekanntgabe der Plugin-Optionen 2. Implementieren der setLocalVal() Methode. 3. Implementieren der scan() Methode. 4. Schreiben der class factory functions. Der Punkt 4 wurde im Kapitel 11.3 abgehandelt und wird hier nicht weiter erläutert. Jedes Plugin muss folgende Header-Files einbinden: # include # include # include # include # include < s a d / sadEx . hpp > < s a d / S c a n S t r a t e g y . hpp > < s a d / o p t i o n M g r . hpp > < s a d / i n j e c t i o n T . hpp > < s a d / c a p t u r e T . hpp > 11.4.1. Bekanntgabe der Optionen Der erste Schritt besteht darin, die Fähigkeiten des Plugins dem Option-Manager von SAD mitzuteilen. Dies macht man am besten im Konstruktor des Plugins. a r p : : a r p ( s t r i n g n , OptionMgr ∗ o p t ) : S c a n S t r a t e g y ( n , o p t ) { /∗ Declare Options ∗/ p u s h O p t ( O p t i o n ( "−a " , "−−a r p " ,NO_ARG, " " , " A c t i v a t e ARP−T e s t " ) ) ; p u s h O p t ( O p t i o n ( "−c " , "−−c o u n t " ,REQ_ARG, " 10 " , " Count t o r u n ARP−T e s t " ) ) ; p u s h O p t ( O p t i o n ( "−fm " , "−−f a k e −mac " ,REQ_ARG, " FF : FF : 0 0 : 0 0 : 0 0 : 0 0 " , " Faked D e s t i n a t i o n MAC" ) ) ; p u s h O p t ( O p t i o n ( "−sm " , "−−s o u r c e −mac " ,REQ_ARG, " " , " s o u r c e MAC" ) ) ; } Listing 11.4: Bekanntgabe der Optionen 11.4.2. Implementieren der setLocalVal() Methode Bei Kreieren des Objekts, werden die Attribute dem Framework bekannt gemacht. Danach folgt das Parsen der Kommandozeile. Der Parser liest die Argumente und setzt die entsprechenden Werte der Option. Diese müssen nun dem Plugin bekannt gegeben werden. Dies geschieht durch die Methode void arp : : s e t L o c a l V a l ( void ) { ... / / Libnet I n i t for getting default addresses 54 11.4. Schreiben eines eigenen Plugins i f ( ! ( c o n t e x t = l i b n e t _ i n i t ( LIBNET_LINK , d e v i c e , e r r b u f ) ) ) throw L i b n e t E x ( e r r b u f ) ; / / S e t d e f a u l t MAC S o u r c e A d d r e s s i f ( ! ( e t h _ s r c = ( u _ i n t 8 _ t ∗) libnet_get_hwaddr ( context ) ) ) throw L i b n e t E x ( l i b n e t _ g e t e r r o r ( c o n t e x t ) ) ; ... } Listing 11.5: Setzen der lokalen Variablen Das ganze Listing kann im Anhang F.3.2 angeschaut werden. 11.4.3. Implementation der scan() Methode Nach dem Laden und Kreieren der Plugins wird die Methode scan() jedes Plugins aufgerufen. Ihre Funktionsweise wird anhand einiger Codefragmente dargestellt. double arp : : scan ( void ) { / / Set Global Values & D e f a u l t s setGlobalVal ( ) ; setLocalVal ( ) ; / / Libnet I n i t i f ( ! ( c o n t e x t = l i b n e t _ i n i t ( LIBNET_LINK , d e v i c e , e r r b u f ) ) ) throw L i b n e t E x ( e r r b u f ) ; ... / / Building the Packets ... / / B u i l d i n g I n j e c t i o n −T h r e a d I n j e c t i o n T fakeArp ; / / A d d i n g l i b n e t −P a c k e t t o t h e T h r e a d fakeArp . addPacket ( c o n t e x t ) ; addThread ( fakeArp ) ; / / Building Filter f i l t e r << " a r p [ 7 ] = = 0 x02 and " ; f i l t e r << " s r c h o s t " << l i b n e t _ a d d r 2 n a m e 4 ( i p _ d s t , LIBNET_DONT_RESOLVE ) << " and " ; f i l t e r << " d s t h o s t " << l i b n e t _ a d d r 2 n a m e 4 ( i p _ s r c , LIBNET_DONT_RESOLVE ) ; / / B u i l d i n g C a p t u r e−T h r e a d CaptureT a rp ca p ( device , f i l t e r . s t r ( ) , 2 , 1000 , loop , examines ) ; addThread ( arpcap ) ; / / S t a r t i n g Threads startThreads (); / / C l e a n i n g up libnet_destroy ( context ); / / Returning the r e s u l t return r e s u l t ; } Die Attribute context und filter sind im Interface ScanStrategy.hpp definiert. Um das Plugin für SAD sichtbar zu machen, muss es nach /usr/local/lib/sad/ kopiert und folgender Eintrag in /etc/sad/sad.conf gemacht werden: 55 11.4. Schreiben eines eigenen Plugins p l u g i n ARP { p at h = / u s r / l o c a l / l i b / sad / l i b a r p . so t r u s t = 0.8 evaluation = " true " } Listing 11.6: Eintrag in sad.conf 56 12. SAD -Plugins The essence of the creative act is to see the familiar as strange. (unknown) In diesem Kapitel werden die Besonderheiten der implementierten Plugins beschrieben. Die Theorie für das Verständnis ist im Teil II abgehandelt. Der Ablauf innerhalb eines Plugins ist im Plugin-HowTo beschrieben. Darum wird an dieser Stelle getrost darauf verzichtet. 12.1. ARP Bei diesem Plugin haben wir die Option --fake-mac eingeführt um allfällige Verbesserungen, z.B. das Prüfen der ersten drei Words der Ethernet-Adresse, vorzubeugen. Diese Option ermöglicht es uns, des Weiteren auf Multicast-Adressen zu testen. Möchte der Administrator den unerwünschten Lauscher in flagranti erwischen, so sollte er ihn unerkannt testen. Dies wird mit der Option --source-mac erreicht. Sie ist nicht mit einem Standardwert gefüllt, deshalb wird im Normalfall die eigene MAC-Adresse für den Test genommen. Das Plugin stellt folgende Optionen zur Verfügung. ARP O p t i o n s : −a −−a r p −c −−c o u n t −fm −−f a k e −mac −sm −−s o u r c e −mac A c t i v a t e ARP−T e s t < Count t o r u n ARP−T e s t > < Faked D e s t i n a t i o n MAC> < s o u r c e MAC> Listing 12.1: Optionen des Plugins ARP 12.2. ICMP Der ICMP-Test unterscheidet sich vom ARP-Test nur dadurch, dass er anstelle eines ARP Requests einen ICMP Request absetzt. Er verfügt über folgende Optionen: ICMP O p t i o n s : −i −−icmp A c t i v a t e ICMP−T e s t 57 12.3. DNS −c −fm −sm −−c o u n t −−f a k e −mac −−s o u r c e −mac < Count t o r u n ICMP−T e s t > < Faked D e s t i n a t i o n MAC> < s o u r c e MAC> Listing 12.2: Optionen des Plugins ICMP 12.3. DNS Das Besondere an unserer Implementierung ist, dass wir zufällig IP-Adressen pingen. Bei jedem Durchgang wird diese wie folgt gebildet: q u e r y i p << r a n d ( ) % 200 + 1 << " . " << r a n d ( ) % 255 << " . " << r a n d ( ) % 255 << " . " << r a n d ( ) % 2 5 5 ; Listing 12.3: DNS-Test: Bau der IP-Adresse Dies hat zur Folge, dass der Filter dementsprechend auch dynamisch gebaut werden musste. void dns : : b u i l d F i l t e r ( void ) { unsigned i n t pos [ 4 ] , u o f f s e t = 21; string s [4]; f o r ( i n t i = 3 ; i >= 0 ; −−i ) { g e t l i n e ( queryip , s [ i ] , ’ . ’ ) ; pos [ i ] = s [ i ] . s i z e ( ) ; } f i l t e r << " d s t p o r t 53 " << " and " << " s r c h o s t " << l i b n e t _ a d d r 2 n a m e 4 ( i p _ d s t , LIBNET_RESOLVE ) ; f o r ( u n s i g n e d i n t i = 0 ; i < 4 ; ++ i ) { f o r ( u n s i g n e d i n t j = 0 ; j < s [ i ] . s i z e ( ) ; ++ j ) { f i l t e r << " and " << " udp [ " << u o f f s e t << " ]== " << s t a t i c _ c a s t < i n t > ( s [ i ] . a t ( j ) ) ; u o f f s e t ++; } ++ u o f f s e t ; } } Listing 12.4: Dynamischer Bau des Filters Das DNS-Plugin verfügt über folgende Optionen: DNS O p t i o n s : −d −−d n s A c t i v a t e DNS−T e s t 58 12.4. LATENCY −c −−c o u n t < Count t o r u n DNS−T e s t > Listing 12.5: Optionen des Plugins DNS 12.4. LATENCY Der LATENCY-Test wurde im Kapitel 7 ausführlich beschrieben, hier folgt nur der Ablauf der scan() Methode: 1. Baue eine Anzahl ICMP Request mit fortlaufenden Sequenznummern. 2. Erstelle ein Flood-Paket, zum Beispiel Telnet-Daten. 3. Starte alle ICMP Request und einen LatencyCaptureThread (siehe Abschnitt 12.4.1). 4. Berechne durschnittliche Antwortzeit. 5. Starte alle ICMP Request plus einen Flood-Thread. 6. Berechne durschnittliche Antwortzeit. 7. Vergleiche die berechneten Werte. Folgende Optionen werden zur Verfügung gestellt: LATENCY O p t i o n s : −l −−l a t e n c y −c −−c o u n t −s p −−s o u r c e −p o r t −dp −−d e s t i n a t i o n −p o r t −p −−p a y l o a d −f i p −−f a k e −i p A c t i v a t e L a t e n c y −T e s t < Count t o r u n L a t e n c y −T e s t > <TCP−S o u r c e−P o r t o f t h e f l o o d i n g Thread > <TCP−D e s t i o n a t i o n −P o r t o f t h e f l o o d i n g Thread > < P a y l o a d you want t o s e n d ( i n " Double Quote " ) > <Fake−IP > Listing 12.6: Optionen des Plugins Latency Um den Flood-Thread ein wenig den eigenen Bedürfnissen anzupassen, ist die Option --payload frei einstellbar. Dadurch wird ermöglicht, eine eigen Datenmenge anzugeben oder interessante Schlüsselwörter, wie zum Beispiel Password oder Login ins Netzwerk einzuschleusen. Mit der Option --fake-ip kann das “Opfer” ausgewählt werden, welches geflutet wird. Dabei ist zu beachten, dass diese IP-Adresse erreichbar ist, ansonsten unterbricht LIBNET das senden von Paketen. Des Weiteren muss damit gerechnet werden, dass dieser Host erhebliche Schwierigkeiten bekommen kann, seine Arbeit fortzusetzen → DoS. 12.4.1. LatencyCT Da der LATENCY-Test im Gegensatz zu den anderen Tests sehr zeitkritisch ist, mussten wir einen neuen CaptureThread kreieren, welcher eine Ableitung namens LatencyCT ist. Dieser Thread ist speziell auf den LATENCY-Test zugeschnitten. Die Aufgabe bestand darin, von allen ICMP Requests die Sendezeiten und von allen ICMP Replies die Empfangszeiten zu speichern. 59 12.4. LATENCY v o i d LatencyCT : : o p e r a t o r ( ) ( ) { struct pcap_pkthdr header ; c o n s t u _ c h a r ∗p ; unsigned short seq = 0 ; u n s i g n e d char t y p e = 0 ; w h i l e ( m a x _ a t t e m p t s && f i n i s h ) { i f ( ( p = p c a p _ n e x t ( h a n d l e , &h e a d e r ) ) ! = NULL) { / ∗ g e t s e q u e n c e number ∗ / s e q = ∗ ( p + 4 0 ) ; s e q <<= 8 ; s e q | = ∗ ( p + 4 1 ) ; / ∗ g e t ICMP Echo t y p e ∗ / type = ∗( p +34); i f ( t y p e == 8 ) /∗ request ∗/ memcpy ( ( v o i d ∗)& s e n d [ s e q ] , ( v o i d ∗)& h e a d e r . t s , s i z e o f ( t i m e v a l ) ) ; e l s e i f ( t y p e == 0 ) / ∗ r e p l y ∗ / memcpy ( ( v o i d ∗)& a r r i v e [ s e q ] , ( v o i d ∗)& h e a d e r . t s , s i z e o f ( t i m e v a l ) ) ; −−f i n i s h ; (∗ examines )++; } else { −−m a x _ a t t e m p t s ; } } } Listing 12.7: Latency CaptureThread 60 Teil IV. Auswertung Zusammenfassung Da, die in den vorangegangenen Kapiteln vorgestellten Tests, im Wesentlichen auf Schwächen der Ethernet- und TCP/IP-Implementierung beruhen, beschäftigt sich dieser Abschnitt mit den einzelnen Betriebssystemen und wie sie auf SAD reagieren. Es werden die gängigsten U NIX und W INDOWS-Derivate getestet und ausgewertet. Des Weiteren wird der LATENCY-Test ausgewertet und ein Blick in die Zukunft von SAD geworfen. 13. Vorhandene Tools Es war von vornherein klar, dass wir nicht die Einzigen sind, welche auf die Idee gekommen sind, einen Promiscuous Mode Detector zu schreiben. Folgende Tools wurden unter die Lupe genommen: A NTI S NIFF[5] Es bestand keine Möglichkeit, dieses Tool unter L INUX zum Laufen zu bringen. Auch unter W INDOWS 2000/XP hatten wir keine Chance. W INDOWS 98 bot dann zum ersten Mal, die Möglichkeit A NTI S NIFF zu untersuchen. Das Ergebnis fiel ziemlich nüchtern aus: Ausser dem, zum Teil erfolgreichen, ARP-Test und einem zugefluteten Netzwerk, schaute nicht viel heraus. NEPED [6] & NEPED - LIBNET [7] Dieses Programm gibt es in zwei verschiedenen Versionen. Eine davon wurde mittels ioctl()1 realisiert, die andere beruht auf LIBNET. Leider funktionierte hier der einzig angebotene Test (ARP) bei beiden Versionen nicht. Auch die Projekthomepage scheint tot zu sein und das Tool ist nur in einschlägigen Archiven auffindbar. SENTINEL [8] SENTINEL ist das funktionsreichste Tool, dass wir finden konnten. Der ARP- und ICMP-Test waren teilweise erfolgreich. Der DNS-Test funktionierte, solange man ihn nur einmal ausführte. Ein grosses Manko von SENTINEL ist ganz klar das Design und die Übersichtlichkeit des Quellcodes. 1 man 2 ioctl 63 14. SAD Als das Tool die erste Phase der Entwicklung hinter sich hatte, wurde es einem Praxistest unterzogen. Die folgende Tabelle dient als Übersicht über die getesteten Betriebssysteme und deren Variationen. W INDOWS 2000 SP4 W INDOWS XP SP1 W INDOWS XP SP2 L INUX 2.2 L INUX 2.4 L INUX 2.6 O PEN BSD 3.6 F REE BSD 4.6 M AC OSX Darwin Kernel 7.5.0 S UN OS 5.7 ARP — ICMP — — — — — — Tabelle 14.1.: Analysierte Betriebssysteme DNS 14.1. LATENCY-Test Wie schon im vorderen Teil dieses Dokumentes angekündigt, ist der LATENCY-Test sehr subjektiv. Man muss einige Tests machen um zu sehen, wie hoch man die Schwelle setzen kann, damit man herausfindet, ob ein Rechner im promiscuous mode läuft, oder ob überhaupt eine solche Schwelle existiert. Den LATENCY-Test, den wir implementiert haben, basiert darauf ICMP Antwortzeiten zu messen. Dies einmal in einem unbelasteten und danach im belasteten Netzwerk. 14.1.1. Messungen Um eine aussagekräftige Statistik zu erhalten, haben wir für beide Szenarien (promiscuous mode und normal mode) je 10 Tests gemacht. 64 14.1. LATENCY-Test Anzahl Wiederholungen pro Test Anzahl ICMP Requests pro Wiederholung ohne flooding Anzahl Telnet Pakete pro Wiederholung fürs flooding Grösse der Telnet Daten Anzahl ICMP Requests pro Wiederholung mit flooding 10 50 500000 713 Byte 50 Tabelle 14.2.: Angaben zur Messreihe regular Network drop count averrage RTD normal promisc normal promisc 0 0 162.8 186.5 0 0 163.6 181.9 0 0 162.1 167.1 0 0 167.9 165.9 0 0 165.5 166.3 0 0 162.4 166.0 0 0 162.4 166.6 0 0 163.9 165.8 0 0 162.5 165.5 0 0 180.5 171.0 0 0 165.4 170.3 flooded Network drop count averrage RTD normal promisc normal promisc 8.5 6.3 10658.9 1197.0 7.2 7.0 16998.0 3100.3 6.5 5.6 18780.2 31798.1 7.5 6.7 12569.4 13052.8 6.3 8.1 24574.8 10475.3 5.7 6.6 23406.8 9833.2 7.1 7.5 16300.8 10907.4 7.4 7.3 10672.2 9310.4 7.6 6.9 16994.1 37485.0 6.8 4.7 9120.1 99440.0 7.0 6.7 16007.5 22660.0 Tabelle 14.3.: Durschnittswerte der 10 Tests Schauen wir uns die Ergebnisse etwas genauer an. Die blaue gestrichelte Linie steht für die Messreihe im normalen Modus, die rote durchgezogene Linie für den promiscuous mode. Abbildung 14.1 zeigt die durchschnittliche Antwortzeit im unbelasteten Netz in µs. Man kann erkennen, dass hier kein deutlicher Unterschied zwischen den beiden Modi auszumachen ist. 65 14.1. LATENCY-Test Abbildung 14.1.: Durchschnittliche Antwortzeit im unbelasteten Netzwerk In Abbildung 14.2 ist dasselbe Szenario wie vorhin, aber in einem belasteten Netzwerk. Es sind deutliche Unterschiede zu erkennen, das Problem ist nur, dass nicht festzustellen ist, ob die höhere Latenzzeit nun dem promiscuous mode zuzuordnen ist. Abbildung 14.2.: Durchschnittliche Antwortzeit im belasteten Netzwerk Zum Schluss ist in Abbildung 14.3 noch dargestellt, wie sich die durchschnittliche Verlustrate der Antworten verhaltet. Es ist eindeutlich zu sehen, dass kein Unterschied besteht. 66 14.1. LATENCY-Test Abbildung 14.3.: Durchschnittliche Drops im belasteten Netzwerk Abbildung 14.4.: Erzeugte Netzlast 14.1.2. Fazit Obwohl wir eine starke Netzwerkbelastung (siehe Abbildung 14.4) erzeugt haben, konnten wir keine, für unser Tool brauchbaren Resultate erzielen. Die Tatsache, dass ICMP Anfragen mit zu hoher Priorität und sehr früh im Kernel behandelt werden, ziehen wir als Ursache in Betracht. Ein Lösungsansatz für dieses Problem wäre, die Anfrage-Antwort-Routine für die Zeitmessung auf ein anderes Protokoll zu verlegen. Zum Beispiel einen TCP 3-Way Handshake zu simulieren oder noch besser etwas auf Layer 7, wie etwa einen HTTP-Request. Denn je höher die Anfragen im Networkstack nach oben gehen, desto mehr gibt es zu rechnen. Jeder Context-Switch bringt zusätzliche Verluste. 67 15. Ausnahmen 15.1. Phänomen Surecom Router Ein Student hat einen Router mit einem integrierten USB-Printserver am Schulnetz angeschlossen, der aus unbekannten Gründen unsere gefakten IP-Pakete nochmals, mit einer MulticastAdresse versehen, ins Netz stellt. Das folgende Listing zeigt ein von uns erstellten ICMP Request mit einer “falschen” Ethernet-Ziel-Adresse. E t h e r n e t I I , S r c : 0 0 : 0 2 : a5 : 9 9 : 4 2 : 0 5 , D s t : f f : f f : 0 0 : 0 0 : 0 0 : 0 0 Destination : ff : ff :00:00:00:00 ( ff : ff :00:00:00:00) S o u r c e : 0 0 : 0 2 : a5 : 9 9 : 4 2 : 0 5 ( CompaqCo_99 : 4 2 : 0 5 ) Type : I P ( 0 x0800 ) I n t e r n e t P r o t o c o l , S r c Addr : s t d r e u s s h a l . zhwin . ch ( 1 6 0 . 8 5 . 1 6 3 . 7 4 ) , D s t Addr : s t d v e s e l r a n . zhwin . ch ( 1 6 0 . 8 5 . 1 6 4 . 2 3 4 ) I n t e r n e t C o n t r o l Message P r o t o c o l Listing 15.1: fake ICMP Request Der zu untersuchende Host (stdveselran.zhwin.ch) befindet sich im promiscuous mode und gibt erwartungsgemäss eine ICMP-Antwort. E t h e r n e t I I , S r c : 0 0 : 0 6 : 1 b : c a : e a : 2 3 , D s t : 0 0 : 0 2 : a5 : 9 9 : 4 2 : 0 5 D e s t i n a t i o n : 0 0 : 0 2 : a5 : 9 9 : 4 2 : 0 5 ( CompaqCo_99 : 4 2 : 0 5 ) Source : 0 0 : 0 6 : 1 b : ca : ea :23 ( P o r t a b l e _ c a : ea : 2 3 ) Type : I P ( 0 x0800 ) T r a i l e r : 00000000000000000000000000000000... I n t e r n e t P r o t o c o l , S r c Addr : s t d v e s e l r a n . zhwin . ch ( 1 6 0 . 8 5 . 1 6 4 . 2 3 4 ) , D s t Addr : s t d r e u s s h a l . zhwin . ch ( 1 6 0 . 8 5 . 1 6 3 . 7 4 ) I n t e r n e t C o n t r o l Message P r o t o c o l Listing 15.2: Erwartete Antwort Nun schaltet sich der S URECOM Router ein. Er stellt den gleichen ICMP Request nochmals ins Netz, ändert aber die Ethernet-Ziel-Adresse zu einer Multicast-Adresse. Dieser Router mappt die IP-Adresse in eine Multicast-Adresse. E t h e r n e t I I , S r c : 0 0 : 0 2 : 4 4 : 7 9 : a f : ab , D s t : 0 1 : 0 0 : 5 e : 5 5 : a4 : e a D e s t i n a t i o n : 0 1 : 0 0 : 5 e : 5 5 : a4 : e a ( 0 1 : 0 0 : 5 e : 5 5 : a4 : e a ) S o u r c e : 0 0 : 0 2 : 4 4 : 7 9 : a f : ab ( SurecomT_79 : a f : ab ) Type : I P ( 0 x0800 ) T r a i l e r : 00000000000000000000000000000000... 68 15.2. false positives I n t e r n e t P r o t o c o l , S r c Addr : s t d r e u s s h a l . zhwin . ch ( 1 6 0 . 8 5 . 1 6 3 . 7 4 ) , D s t Addr : s t d v e s e l r a n . zhwin . ch ( 1 6 0 . 8 5 . 1 6 4 . 2 3 4 ) I n t e r n e t C o n t r o l Message P r o t o c o l Listing 15.3: Multicast korrigiertes Paket Da das Paket an eine Multicast-Adresse gesendet wurde und sich der Host immer noch im promiscuous mode befindet, verarbeitet er auch diese Anfrage und sendet eine Antwort zurück. E t h e r n e t I I , S r c : 0 0 : 0 6 : 1 b : c a : e a : 2 3 , D s t : 0 0 : 0 2 : a5 : 9 9 : 4 2 : 0 5 D e s t i n a t i o n : 0 0 : 0 2 : a5 : 9 9 : 4 2 : 0 5 ( CompaqCo_99 : 4 2 : 0 5 ) Source : 0 0 : 0 6 : 1 b : ca : ea :23 ( P o r t a b l e _ c a : ea : 2 3 ) Type : I P ( 0 x0800 ) T r a i l e r : 00000000000000000000000000000000... I n t e r n e t P r o t o c o l , S r c Addr : s t d v e s e l r a n . zhwin . ch ( 1 6 0 . 8 5 . 1 6 4 . 2 3 4 ) , D s t Addr : s t d r e u s s h a l . zhwin . ch ( 1 6 0 . 8 5 . 1 6 3 . 7 4 ) I n t e r n e t C o n t r o l Message P r o t o c o l Listing 15.4: Zweite Antwort Das Problem ist nun, dass diese Antworten nicht zu unterscheiden sind. Die beiden Antworten sind identisch, was bedeutet, dass wir doppelt so viele Replies zurückbekommen, wie wir Requests abgesendet haben. Unser Tool SAD kann mit diesem Problem umgehen, indem wir nur schauen ob Antworten zurückkommen und nicht wie viele. 15.2. false positives Während unserer Testphase sind uns einige false positives aufgefallen. Folgende Hardware hat, ohne im promiscuous mode zu sein, Reaktionen auf unsere Tests gezeigt. Alle haben einen Fehler im Hardware-Filter. Falls das group bit gesetzt ist, wird die ganze Adresse als Multicast interpretiert und nicht verworfen. Z Y XEL ADSL-Router Versionen: ZyNOS F/W Version: V2.50(AJ.9) | 07/09/2002 ZyNOS F/W Version: V3.40(FU.4) | 11/26/2002 AXIS Network Printserver Version: AXIS OfficeBasic 6.15 69 15.2. false positives Netzwerkarten HP Omnibook xe4500, NatSemi DP8315 Diese Netzwerkkarte hat überhaupt keinen Hardware-Filter!!! 70 16. Ausblick 16.1. Anti-SAD Dieser Abschnitt soll beschreiben, was unternommen werden kann, um machen. Schauen wir uns kurz die vier Methoden an: SAD unbrauchbar zu ARP Die ARP-Routine1 im Kernel muss überprüfen, ob ein ARP Request an die richtige BroadcastAdresse (FF:FF:FF:FF:FF:FF) gesendet wurde. ICMP Die IP-Routine2 im Kernel muss überprüfen, ob Ziel-IP und MAC ein gültiges Paar bilden. DNS Falls der Sniffer die Namensauflösung deaktiviert, ist der DNS-Test machtlos. LATENCY Gegen den LATENCY-Test gibt es kein wirkungsvolles Mittel, da die Rechner im Vergleich zu den verfügbaren Bandbreiten aber immer schneller werden, wird es in Zukunft schwer sein, einen erfolgreichen LATENCY-Test durchzuführen. Was aber nicht heissen soll, dass unser Tool schnell unbrauchbar sein wird. Denn für die oben genannten Gegenmassnahmen sind tiefere Kerneleingriffe notwendig, welche auch nicht ganz ohne sind, weil immer noch überprüft werden muss, ob es sich um registrierte Multicast-Adressen handelt. 16.2. Zukunft von SAD Wir werden das Projekt ganz bestimmt weiterhin betreuen und wollen es gerne unter der GPLLizenz auf SOURCE FORGE[4] betreiben. Folgende Änderungen oder Erweiterungen sind in naher Zukunft geplant: 1 2 L INUX: arp_rcv() L INUX: ip_rcv() 71 16.2. Zukunft von SAD • LatencyCT ist ein dirty workarround für das LATENCY-Plugin → CaptureT flexibler gestalten, sodass LatencyCT überflüssig wird. • Einen LATENCY-Test auf TCP-Ebene implementieren. • Beim ARP-Test einen stärken Filter bauen, sodass keine false positives bei Tests in eine andere Broadcast-Domäne entstehen. • Differenzierterer Umgang mit den Exceptions. • Die Möglichkeit ein ganzes Subnetz oder einen Range zu scannen. • Umstieg auf GLIB um die Plattformunabhängigkeit zu verbessern (Laden der Plugins) • Auf AUTOTOOLS umsteigen. • Erstellen von Binärpaketen für .rpm, .deb. • Evtl. B OOST::Thread durch eine andere Thread Bibliothek ersetzten. 72 Schlusswort Irgendwie sind wir froh, dass diese Diplomarbeit endlich fertig gestellt und es sauber abgeschlossen ist. Auf der anderen Seite ist es auch traurig, dass die Zeit schon um ist. Denn trotz einiger Stunden, in denen unsere Köpfe rauchten und wir kurz vor dem Gang zur Klapsmühle standen, hatten wir jede Menge Spass. Nicht nur das es eine wahnsinnig interessante Aufgabe war, die wir zu lösen versuchten, nein, es war auch eine sehr gute Zusammenarbeit, in der es nicht nur beim Kaffee viel zu lachen gab. Die Betreuung durch Herr S TEFFEN war sehr gut. Obwohl unsere Meetings doch immer etwas kurz ausfielen, wussten wir es zu schätzen, dass Herr S TEFFEN jederzeit zur Stelle gewesen war, wenn Probleme oder Fragen auftraten. Des Weiteren verhinderten die regelmässigen Treffen, dass wir vom Weg abkamen. Die Implementierung unseres Tools SAD war wirklich eine Freude. Obwohl wir teilweise das Gefühl hatten wir würden die einen Netzwerkprotokolle Byte für Byte auswendig kennen, kam schon bald etwas Brauchbares heraus. Zum Schluss brachten uns noch einige ZHW-Netz-Eigenheiten zum Schwitzen. Aber wir denken, das muss so sein, ansonsten wäre es ja langweilig ;-) Unser Ziel ist, dass SAD im systemadministrativen Umfeld eingesetzt werden kann, dafür müssen wir aber nochmals ein wenig Zeit investieren. Trotz3 der anspruchsvollen Aufgabe und den zahlreichen Abenden, die wir an der ZHW verbrachten, hatten wir einen riesigen Spass mit der Arbeit. Wir gehen sogar so weit, zu behaupten, dass der Spass je länger je grösser wurde. Auch wenn wir zum Schluss noch einen kleinen Kampf gegen die Zeit führten, um die Dokumentation fertig zustellen, haben wir doch noch einen Sieg über den Projektplan erzielen können. 3 oder gerade wegen? 73 Teil V. Anhang Zusammenfassung Dieser Teil beinhaltet den Projektplan, einen einfachen L INUX-Sniffer, einen kleinen Exkurs in den L INUX-Networkstack und die Quellen. A. Projektplan Der Projektplan kann unter http://www.corleone.ch/sad/projektplan angeschaut werden. 75 B. Ein einfacher L INUX-Sniffer # include # include # include # include # include # include # include # include # include # include # include < s t d i o . h> < s t r i n g . h> < e r r n o . h> < u n i s t d . h> < s y s / s o c k e t . h> < s y s / t y p e s . h> < l i n u x / i n . h> < l i n u x / i f _ e t h e r . h> < n e t / i f . h> < l i n u x / f i l t e r . h> < s y s / i o c t l . h> i n t main ( i n t a r g c , char ∗∗ a r g v ) { i n t sock , n ; char b u f f e r [ 2 0 4 8 ] ; u n s i g n e d char ∗ i p h e a d , ∗ e t h h e a d ; struct ifreq ethreq ; / ∗ Unser F i l t e r ∗ tcpdump N o t a t i o n : udp and p o r t 53 and d s t h o s t 1 6 0 . 8 5 . 1 9 5 . 1 9 5 ∗ tcpdump −d l i e f e r t den BPF−Code i n m e n s c h e n l e s b a r e r Form ∗ tcpdump −dd l i e f e r t f o l g e n d e s C−Programm Fragment : ∗/ s t r u c t s o c k _ f i l t e r BPF_code [ ] = { { 0 x28 , 0 , 0 , 0 x0000000c } , { 0 x15 , 1 3 , 0 , 0 x000086dd } , { 0 x15 , 0 , 1 2 , 0 x00000800 } , { 0 x30 , 0 , 0 , 0 x00000017 } , { 0 x15 , 0 , 1 0 , 0 x00000011 } , { 0 x28 , 0 , 0 , 0 x00000014 } , { 0 x45 , 8 , 0 , 0 x 0 0 0 0 1 f f f } , { 0 xb1 , 0 , 0 , 0 x0000000e } , { 0 x48 , 0 , 0 , 0 x0000000e } , { 0 x15 , 2 , 0 , 0 x00000035 } , { 0 x48 , 0 , 0 , 0 x00000010 } , { 0 x15 , 0 , 3 , 0 x00000035 } , { 0 x20 , 0 , 0 , 0 x0000001e } , { 0 x15 , 0 , 1 , 0 x a 0 5 5 c 3 c 3 } , { 0x6 , 0 , 0 , 0 x00000060 } , { 0x6 , 0 , 0 , 0 x00000000 } , }; struct sock_fprog F i l t e r ; F i l t e r . len = 16; F i l t e r . f i l t e r = BPF_code ; i f ( ( s o c k = s o c k e t ( PF_PACKET , SOCK_RAW, h t o n s ( ETH_P_IP ) ) ) < 0 ) { perror ( " socket " ) ; exit (1); } / ∗ N e t z w e r k k a r t e i n den p r o m i s c u o u s mode v e r s e t z e n ∗ / 77 s t r n c p y ( e t h r e q . i f r _ n a m e , " e t h 0 " , IFNAMSIZ ) ; i f ( i o c t l ( sock , SIOCGIFFLAGS,& e t h r e q )== −1) { perror ( " ioctl " ); c l o s e ( sock ) ; exit (1); } e t h r e q . i f r _ f l a g s | = IFF_PROMISC ; i f ( i o c t l ( sock , SIOCSIFFLAGS ,& e t h r e q )== −1) { perror ( " ioctl " ); c l o s e ( sock ) ; exit (1); } / ∗ F i l t e r dem S o c k e t h i n z u f u e g e n ∗ / i f ( s e t s o c k o p t ( sock , SOL_SOCKET , SO_ATTACH_FILTER , &F i l t e r , s i z e o f ( F i l t e r ) ) < 0 ) { perror ( " setsockopt " ); c l o s e ( sock ) ; exit (1); } while ( 1 ) { n = r e c v f r o m ( sock , b u f f e r , 2 0 4 8 , 0 ,NULL, NULL ) ; p r i n t f ( "%d b y t e s r e a d \ n " , n ) ; / ∗ U e b e r p r u e f e , ob d a s P a k e t m i n d e s t e n s k o m p l e t t e ∗ E t h e r n e t ( 1 4 ) , IP ( 2 0 ) und TCP /UDP ( 8 ) ∗ Header e n t h a l t e n . ∗/ i f ( n < 42 ) { p e r r o r ( " recvfrom ( ) : " ) ; p r i n t f ( " I n c o m p l e t e p a c k e t ( e r r n o i s %d ) \ n " , e r r n o ) ; c l o s e ( sock ) ; exit (0); } ethhead = buffer ; p r i n t f ( " S o u r c e MAC a d d r e s s : " "%02x :%02 x :%02 x :%02 x :%02 x :%02 x \ n " , ethhead [0] , ethhead [1] , ethhead [2] , ethhead [3] , ethhead [4] , ethhead [ 5 ] ) ; p r i n t f ( " D e s t i n a t i o n MAC a d d r e s s : " "%02x :%02 x :%02 x :%02 x :%02 x :%02 x \ n " , ethhead [6] , ethhead [7] , ethhead [8] , ethhead [9] , ethhead [10] , ethhead [ 1 1 ] ) ; iphead = b u f f e r +14; / ∗ Ü b e r s p r i n g e E t h e r n e t −Header ∗ / i f ( ∗ i p h e a d ==0 x45 ) / ∗ Üü b e r p r f e ob I P v 4 ohne O p t i o n s ∗ / { p r i n t f ( " S o u r c e h o s t %d.%d.%d.%d \ n " , iphead [12] , iphead [13] , iphead [14] , iphead [ 1 5 ] ) ; p r i n t f ( " D e s t h o s t %d.%d.%d.%d \ n " , iphead [16] , iphead [17] , iphead [18] , iphead [ 1 9 ] ) ; p r i n t f ( " S o u r c e , D e s t p o r t s %d ,%d \ n " , ( i p h e a d [ 2 0 ] < <8 ) + i p h e a d [ 2 1 ] , ( i p h e a d [ 2 2 ] < <8 ) + i p h e a d [ 2 3 ] ) ; 78 p r i n t f ( " Layer −4 p r o t o c o l %d \ n " , i p h e a d [ 9 ] ) ; } } } Listing B.1: Minisniffer # ./ minisniffer 66 b y t e s r e a d S o u r c e MAC a d d r e s s : 0 0 : d0 : 0 3 : 2 2 : 7 c : 0 a D e s t i n a t i o n MAC a d d r e s s : 0 0 : 0 6 : 1 b : c a : e a : 2 3 Source host 160.85.191.180 Dest h o st 6 4. 236 .3 4. 196 Source , Dest p o r t s 32777 ,80 Layer −4 p r o t o c o l 6 ... Listing B.2: Ausgabe 79 C. L INUX Networkstack-Walkthrough In diesem Kapital wird möglichst kurz und einfach beschrieben, wie ein Paket, das von der Netzwerkkarte empfangen wurde, durch den L INUX Netzwerkstack hindurchgereicht wird. Es werden nicht alle Funktionen bis ins Detail besprochen und um das Dokument nicht unnötig aufzublähen, widmet sich das Kapitel vor allem dem Empfang von Paketen. Das Ziel liegt darin zu erklären, warum unsere Methoden, die auf Schwächen des Netzwerkstacks basieren, überhaupt funktionieren. Auch für den ICMP-Latency- und LATENCY-Test muss man sich kurz mit diesem Thema auseinander setzen. C.1. Ethernet Card and Lower-Kernel Reception — Layer 1 Wie schon bekannt, hat jede Netzwerkkarte, meistens eine fixe, Link-Layer oder MAC Adresse. Wenn die Netzwerkkarte nun ein Paket sieht, das an seine oder an die Broadcast-Adresse adressiert ist, beginnt sie das Paket in den FIFO-Buffer rx_ring zu laden. Falls nun aber die Netzwerkkarte in den promiscuous mode versetzt wurde, beginnt sie jedes empfangene Paket in den Speicher zu laden. Sobald ein Paket eingelesen wurde, generiert die Netzwerkkarte einen Interrupt-Request. Die ISR, die diesen Request bearbeitet, ist meistens der Netzwerkkarten-Treiber selbst, welcher im Modus interrupt disabled abläuft und folgende Operationen durchführt: • Platz für eine neue sk_buff Struktur1 allozieren, welche die Sicht des Kernels auf das Frame repräsentiert. • Daten aus dem Netzwerkkarten-Buffer holen und in die frisch allozierte sk_buff Struktur kopieren, evtl. mit Hilfe von DMA. • Die protokollunabhängige Empfangssteuerungsfunktion netif_rx() oder netif_rx_schedule() ausführen. • Interrupts aktivieren. Um einen echten Ethernet-Treiber in Aktion zu sehen, sollte man sich die Funktionen ei_interrupt() und ei_receive() in drivers/net/8390.c ansehen. 1 Das Herz des L INUX Netzwerkcodes 80 C.2. Network Core Processing — Layer 2 C.2. Network Core Processing — Layer 2 C.2.1. NAPI Der Interrupt Mechanismus führt zu einem Phänomen namens “Überlastkollaps”. Dies tritt auf, wenn so viele Pakete ankommen, dass vor lauter Interrupts so viel Zeit aufgefressen wird, dass der Prozessor keine anderen Aufgaben mehr erledigen kann. DoS-Attacken können so wirkungsvoll sein. Für die Lösung dieses Problems bietet das N EW API2 , dass folgende Strategie implementiert: Anstatt das die Netzwerkkarte jedes Mal den Prozessor unterbricht, wenn ein Frame ankommt, wird das Interface bei einer Poll-List registriert und die Interrupts werden ausgeschaltet. Diese Poll-List wird nun durch einen Scheduler abgearbeitet, wobei gewisse Quotas per Interface zur Verfügung stehen. Die beiden folgenden Grafiken sollen die Unterschiede zwischen der alten und der neuen API aufzeigen. Die Grafiken dienen auch zum besseren Verständnis der unten beschrieben Funktionen. Abbildung C.1.: Old API: Kernel <2.4.19 2 ab Kernel 2.4.19 81 C.2. Network Core Processing — Layer 2 Abbildung C.2.: New API (NAPI): Kernel ≥ 2.4.19 C.2.2. netif_rx() und netif_rx_schedule() Diese beiden Funktionen bereiten den Kernel für den nächsten Empfangsschritt vor. Bei der alten API wird netif_rx() aufgerufen, die folgende Funktionen ausführt: Sie hängt die allozierte sk_buff Struktur in die Empfangsqueue (backlog) für die aktuelle CPU. Falls die Queue voll ist, wird dieses Frame verworfen und gewartet, bis die Queue ganz leer ist. Da diese Funktion im Kontext der ISR läuft, muss sie möglichst einfach und kurz sein, da sonst ankommende Pakete nicht bearbeitet werden können, deshalb wird zum Schluss die Empfangsroutine (Soft-IRQ3 ) angekickt. Diese Funktion gibt einen so genannten “Überlast-Level” zurück: NET_RX_SUCCESS, NET_RX_CN_LOW, NET_RX_CN_MOD, NET_RX_CN_HIGH oder NET_RX_DROP. Der NAPI-Treiber funktioniert nach einem anderen Prinzip: Der Interrupt-Handler ruft die Methode netif_rx_schedule() auf. Anstatt das Paket der Queue hinzuzufügen, wird eine Referenz auf das Device in der receive poll list des aktuellen Prozessors angelegt. Wie bei der alten API wird ein Software-Interrupt gestartet. Dies ist der einzige negative Punkt des NAPI. Dadurch, dass ein Device immer nur mit einer CPU assoziiert wird, ist die SMP-Fähigkeit bei nur einem Device sehr 3 Es werden Soft-IRQs anstatt Bottom-Halves verwendet, das die Sequenzialisierung bei SMP so vermieden wird 82 C.3. Ausgewählte Passagen aus den Kernelsourcen eingeschränkt. Um Rückwärtskompatibilität zu gewährleisten, wird der backlog der alten API als ein Device behandelt. C.2.3. NET_RX softirq net_rx_action() Sobald die vorher gestartete Funktion ihre Arbeit wieder aufnimmt, erledigt sie einfach gesagt folgende Operationen: Bei älteren Kernelversionen: • Ein Paket aus der backlog queue herausnehmen. • Die Liste (Hashtable) der vorhandenen Packet-Handler z.B. für ARP oder IP hindurchiterieren und die dafür zuständige Funktion (arp_rcv(), ip_rcv(), icmp_rcv(), ...) aufrufen. Falls die Queue mehr als ein Paket enthaltet, führt rx_action() eine Schleife über alle Pakete aus, bis entweder ein Maximum an Paketen (netdev_max_backlog) erreicht wurde oder zu viel Zeit verbraucht wurde4 . Bei Kernelversionen, die das NAPI enthalten: • Durch die, für den aktuellen Prozessor, receive poll list hindurchiterieren und für jedes Device alle empfangenen Pakete aus dem rx_ring oder aus dem backlog holen. • Die poll Methode für das backlog device ist process_backlog(), welche die Pakete vorbereitet, um von netif_receive_skb aufgerufen zu werden. Für alle anderen Devices wird, für jedes Paket die Methode netif_receive_skb direkt aufgerufen. • Diese Routine ruft im eigentlichen Sinne wieder für jeden Paket-Typ die richtige Funktion auf. C.3. Ausgewählte Passagen aus den Kernelsourcen /∗∗ ∗ d e v _ s e t _ p r o m i s c u i t y − u p d a t e p r o m i s c u i t y c o u n t on a d e v i c e ∗ @dev : d e v i c e ∗ @inc : m o d i f i e r ∗ ∗ Add o r remove p r o m s i c u i t y f r o m a d e v i c e . W h i l e t h e c o u n t i n t h e d e v i c e ∗ r e m a i n s a b o v e z e r o t h e i n t e r f a c e r e m a i n s p r o m i s c u o u s . Once i t h i t s z e r o ∗ t h e d e v i c e r e v e r t s back t o normal f i l t e r i n g o p e r a t i o n . A n e g a t i v e i n c ∗ v a l u e i s u s e d t o d r o p p r o m i s c u i t y on t h e d e v i c e . ∗/ v o i d d e v _ s e t _ p r o m i s c u i t y ( s t r u c t n e t _ d e v i c e ∗ dev , i n t i n c ) { u n s i g n e d s h o r t o l d _ f l a g s = dev−> f l a g s ; 4 1 jiffy, 10ms bei den meisten Kernel 83 C.3. Ausgewählte Passagen aus den Kernelsourcen dev−> f l a g s | = IFF_PROMISC ; i f ( ( dev−> p r o m i s c u i t y += i n c ) == 0 ) dev−> f l a g s &= ~IFF_PROMISC ; i f ( dev−> f l a g s ^ o l d _ f l a g s ) { d e v _ mc _ u p l o ad ( dev ) ; p r i n t k ( KERN_INFO " d e v i c e %s %s p r o m i s c u o u s mode \ n " , dev−>name , ( dev−> f l a g s & IFF_PROMISC ) ? " e n t e r e d " : " left " ); } } Listing C.1: net/core/dev.c In diesem Abschnitt ist gut zu sehen, wie sich der Kernel merkt, ob er sich im promiscuous mode befindet oder nicht. u n s i g n e d s h o r t e t h _ t y p e _ t r a n s ( s t r u c t s k _ b u f f ∗ skb , s t r u c t n e t _ d e v i c e ∗ dev ) { ... i f ( ∗ e t h −>h _ d e s t &1) { i f ( memcmp ( e t h −>h _ d e s t , dev−>b r o a d c a s t , ETH_ALEN) = = 0 ) skb −>p k t _ t y p e =PACKET_BROADCAST ; else skb −>p k t _ t y p e =PACKET_MULTICAST ; } /∗ ∗ ∗ ∗ ∗ ∗ ∗/ T h i s ALLMULTI c h e c k s h o u l d be r e d u n d a n t by 1 . 4 s o don ’ t f o r g e t t o remove i t . Seems , you f o r g o t t o remove i t . A l l s i l l y d e v i c e s s e e m s t o s e t IFF_PROMISC . e l s e i f ( 1 / ∗ dev−> f l a g s&IFF_PROMISC ∗ / ) { i f ( memcmp ( e t h −>h _ d e s t , dev−>d e v _ a d d r , ETH_ALEN ) ) skb −>p k t _ t y p e =PACKET_OTHERHOST ; } ... Listing C.2: net/ethernet/eth.c Die Funktion eth_type_trans() wird von vielen Treibern aufgerufen, um einzelne Werte der sk_buff Struktur abzufüllen. Das erste if überprüft, ob das erste Byte der Ethernet-Ziel-Adresse ungerade ist, danach wird geprüft ob diese Adresse der Broadcast-Adresse (FF:FF:FF:FF:FF:FF) entspricht, falls nicht wird der pkt_type auf PACKET_MULTICAST gesetzt !!! Falls das erste Byte gerade ist, wird weiter unten noch überprüft, ob die Ethernet-Ziel-Adresse der eigenen MAC-Adresse entspricht. i n t a r p _ r c v ( s t r u c t s k _ b u f f ∗ skb , s t r u c t n e t _ d e v i c e ∗ dev , s t r u c t p a c k e t _ t y p e ∗ p t ) { ... a r p = skb −>nh . a r p h ; i f ( a r p −> a r _ h l n ! = dev−>a d d r _ l e n | | dev−> f l a g s & IFF_NOARP | | skb −>p k t _ t y p e == PACKET_OTHERHOST | | 84 C.3. Ausgewählte Passagen aus den Kernelsourcen skb −>p k t _ t y p e == PACKET_LOOPBACK | | a r p −> a r _ p l n ! = 4 ) goto f r e e s k b ; ... Listing C.3: net/ipv4/arp.c In der arp_rcv() Funktion wird nur auf PACKET_OTHERHOST geprüft, deshalb funktioniert der ARP-Test bei L INUX! /∗ ∗ Main IP R e c e i v e r o u t i n e . ∗/ i n t i p _ r c v ( s t r u c t s k _ b u f f ∗ skb , s t r u c t n e t _ d e v i c e ∗ dev , s t r u c t p a c k e t _ t y p e ∗ p t ) { struct iphdr ∗iph ; / ∗ When t h e i n t e r f a c e i s i n p r o m i s c . mode , d r o p a l l t h e c r a p ∗ t h a t i t r e c e i v e s , do n o t t r y t o a n a l y s e i t . ∗/ i f ( skb −>p k t _ t y p e == PACKET_OTHERHOST) goto drop ; ... Listing C.4: net/ipv4/ip_input.c Falls ein Paket vom Typ ETH_P_IP ankommt, wird die Funktion ip_rcv() aufgerufen. Hier wird auch nur auf PACKET_OTHERHOST geprüft, deshalb funktioniert der ICMP-Test bei L INUX! 85 D. Glossar API ARP BPF CSMA/CD DMA DNS DoS HTTP ICMP IP ISR LAN LPF MAC MSB NAPI OS pid RTD Rx SAD SMP SNMP TCP Tx UDP UTC Application Program(ming) Interface Address Resolution Protocol Berkeley Packet Filter Carrier Sense Multiple Access/Collision Detect(ion) Direct Memory Access Domain Name System Denial Of Service Hyper Text Transfer Protocol Internet Control Message Protocol Internet Protocol Interrupt Service Routine Local Area Network L INUX Packet Filter Media Access Control Most Significant Bit New Application Program(ming) Interface Operating System Process ID Round-Trip Delay Receive S NIFF A ND D IE Symmetric Multi-Processor Simple Network Management Protocol Transmission Control Protocol Transmit User Datagram Protocol Coordinated Universal Time 86 Literaturverzeichnis [1] H ELMUT KOPKA: LATEX 2ε Einführung Band 1, A DDISON -W ESLEY Verlag, 3. überarbeitete Auflage, 2000, ISBN 3-8273-1557-3 [2] W. R ICHARD S TEVENS: TCP/IP Illustrated Volume I: The Protocols, A DDISON W ESLEY, 1994, ISBN 3-8266-5042-5 [3] GNU Lesser General Public License [4] SOURCE FORGE. NET [5] A NTI S NIFF, L0pht Heavy Industries, Inc. [6] NEPED [7] NEPED - LIBNET [8] SENTINEL [9] Design Patterns [10] Program Library HOWTO [11] C++ dlopen mini HOWTO [12] Shared objects for the object disoriented! [13] B OOST::Thread (Version: 1.31.0-7) [14] B JARNE S TROUSTRUP: Die C++ Programmiersprache, A DDISON -W ESLEY Verlag, 4. aktualisierte Auflage, 2000, ISBN 0-8273-1660-X [15] R AY L ISCHNER: C++ in a Nutshell, O’R EILLY Verlag, May 2003, ISBN 0-596-00298-X [16] The Libnet Packet Construction Library (Version: 1.1.2.1-1) [17] Building packets for dummies and others with libnet 87 Literaturverzeichnis [18] The Libnet Reference Manual v.01 [19] The Libpcap Library (Version: 0.8.3-4) [20] Programming with pcap [21] libConfuse (Version: 2.2-1) [22] DAIJI S ANAI, Detection of Promiscuous Nodes Using ARP Packets, 2001 [23] M UDGE, Tactics to Discover “Passive” Monitoring Devices [24] The L INUX Kernel Archives [25] V INCENT G UFFENS: Path of a packet in the L INUX kernel, 2003 [26] L INUX Network Stack Walkthrough [27] L INUX 2.6 network stack [28] The L INUX Socket Filter: Sniffing Bytes over the Network Part I [29] Inside the L INUX Packet Filter Part II 88 E. The GNU General Public License Version 2, June 1991 c Copyright 1989, 1991 Free Software Foundation, Inc. 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software—to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation’s software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author’s protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they 89 have is not the original, so that any problems introduced by others will not reflect on the original authors’ reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone’s free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU G ENERAL P UBLIC L ICENSE T ERMS AND C ONDITIONS F OR C OPYING , D ISTRIBUTION AND M ODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The “Program”, below, refers to any such program or work, and a “work based on the Program” means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term “modification”.) Each licensee is addressed as “you”. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program’s source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients’ exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and “any later version”, you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. N O WARRANTY 11. B ECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE , THERE IS NO WARRAN - TY FOR THE PROGRAM , TO THE EXTENT PERMITTED BY APPLICABLE LAW. E XCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND / OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS ” WITHOUT WARRANTY OF ANY KIND , EITHER EXPRESSED OR IMPLIED , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WAR RANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE . T HE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU . S HOULD THE PROGRAM PROVE DEFECTIVE , YOU ASSUME THE COST OF ALL NECESSARY SERVICING , REPAIR OR CORRECTION . 12. I N NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER , OR ANY OTHER PARTY WHO MAY MODIFY AND / OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE , BE LIABLE TO YOU FOR DA MAGES , INCLUDING ANY GENERAL , SPECIAL , INCIDENTAL OR CONSEQUENTIAL DA MAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM ( INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS ), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES . E ND OF T ERMS AND C ONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the “copyright” line and a pointer to where the full notice is found. <one line to give the program’s name and a brief idea of what it does.> Copyright (C) <year> <name of author> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place Suite 330, Boston, MA 02111-1307, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) <year> <name of author> Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type ‘show w’. This is free software, and you are welcome to redistribute it under certain conditions; type ‘show c’ for details. The hypothetical commands show w and show c should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than show w and show c; they could even be mouse-clicks or menu items—whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a “copyright disclaimer” for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program ‘Gnomovision’ (which makes passes at compilers) written by James Hacker. <signature of Ty Coon>, 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. F. Code Der hier abgedruckte Code unterliegt den Bestimmungen der GPL welche im Anhang E beigefügt ist. 97 F.1. Makefile F.1. Makefile # ############################################################################## # M a k e f i l e − Sad # # Author : Ranko V e s e l i n o v i c <v e s e l r a n @ z h w i n . ch> # Halm R e u s s e r <r e u s s h a l @ z h w i n . ch> # Date : 05.10.2004 # #−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− # # C o p y r i g h t (C) 2004 Ranko V e s e l i n o v i c <v e s e l r a n @ z h w i n . ch> # Halm R e u s s e r <r e u s s h a l @ z h w i n . ch> # # T h i s program i s f r e e s o f t w a r e ; you can r e d i s t r i b u t e i t and / o r # m o d i f y i t u n d e r t h e t e r m s o f t h e GNU G e n e r a l P u b l i c L i c e n s e # a s p u b l i s h e d by t h e F r e e S o f t w a r e F o u n d a t i o n ; e i t h e r v e r s i o n 2 # o f t h e L i c e n s e , o r ( a t y o u r o p t i o n ) any l a t e r v e r s i o n . # # T h i s program i s d i s t r i b u t e d i n t h e hope t h a t i t w i l l be u s e f u l , # b u t WITHOUT ANY WARRANTY ; w i t h o u t e v e n t h e i m p l i e d w a r r a n t y o f # MERCHANTABILITY o r FITNESS FOR A PARTICULAR PURPOSE . S e e t h e # GNU G e n e r a l P u b l i c L i c e n s e f o r more d e t a i l s . # # You s h o u l d h a v e r e c e i v e d a c o p y o f t h e GNU G e n e r a l P u b l i c L i c e n s e # a l o n g w i t h t h i s program ; i f n o t , w r i t e t o t h e F r e e S o f t w a r e # F o u n d a t i o n , I n c . , 59 Temple P l a c e − S u i t e 3 3 0 , B o s t o n , MA 02111 −1307 , USA . # ############################################################################## SHELL = / b i n / b a s h CXX = g++ CXXFLAGS = −g −W −Wall #−O3 LIBFLAGS = −f P I C −s h a r e d −Wl,−soname , TRDFLAGS = −D_REENTRANT LDFLAGS = − l d l −l b o o s t _ t h r e a d − l n e t −l p c a p −l c o n f u s e −l c VPATH = . / p l u g i n s # c o n t a i n s t h e source−f i l e s i n t h e sad / s r c d i r e c t o r y f r a m e w o r k = $ ( w i l d c a r d ∗ . cpp ) # c o n t a i n s t h e source−f i l e s i n t h e sad / s r c / p l u g i n d i r e c t o r y p l u g i n s = $ ( n o t d i r $ ( w i l d c a r d $ (VPATH ) / ∗ . cpp ) ) # c o n t a i n s a l l source−f i l e s from sad / s r c /∗ s o u r c e s = $ ( framework ) $ ( p l u g i n s ) p o b j e c t s = $ ( p a t s u b s t %. cpp , % . o , $ ( p l u g i n s ) ) f o b j e c t s = $ ( p a t s u b s t %. cpp , % . o , $ ( f r a m e w o r k ) ) fmodules = S c a n S t r a t e g y . o captureT . o i n j e c t i o n T . o optionMgr . o latencyCT . o . PHONY: c l e a n i n s t a l l a l l : $ ( p o b j e c t s ) $ ( f o b j e c t s ) sad $( pobjects ): $( plugins ) $( fobjects ) $ (CXX) $ (CXXFLAGS) $ ( LIBFLAGS ) l i b $ ∗ . s o . 0 −o l i b $ ∗ . s o . 0 . 0 $ (VPATH ) / $ ∗ . cpp \ $ ( f m o d u l e s ) $ (LDFLAGS) $ ( f o b j e c t s ) : $ ( framework ) $ (CXX) −c $ (CXXFLAGS) $ (TRDFLAGS) $ ∗ . cpp 98 F.1. Makefile sad : $ ( f o b j e c t s ) $ (CXX) $ (CXXFLAGS) $ (TRDFLAGS) −o $@ $ ( f o b j e c t s ) $ (LDFLAGS) install : i n s t a l l −g r o o t −o r o o t −m 500 s a d / u s r / l o c a l / s b i n i n s t a l l −d −g r o o t −o r o o t −m 700 / u s r / l o c a l / l i b / s a d / i n s t a l l −g r o o t −o r o o t −m 700 $ ( w i l d c a r d ∗ . s o . ∗ ) / u s r / l o c a l / l i b / s a d / / s b i n / l d c o n f i g −n / u s r / l o c a l / l i b / s a d / i n s t a l l −d −g r o o t −o r o o t −m 700 / e t c / s a d / i n s t a l l −g r o o t −o r o o t −m 600 s a d . c o n f / e t c / s a d / i n s t a l l −d −g r o o t −o r o o t −m 755 / u s r / l o c a l / i n c l u d e / s a d i n s t a l l −g r o o t −o r o o t −m 644 $ ( w i l d c a r d ∗ . hpp ) / u s r / l o c a l / i n c l u d e / s a d / uninstall : rm −f rm − r f rm − r f rm − r f / usr / / usr / usr / etc l o c a l / sbin / sad / l o c a l / l i b / sad / l o c a l / i n c l u d e / sad / sad clean : rm − r f ∗ . o s a d ∗ . s o ∗ 99 F.2. Framework F.2. Framework F.2.1. optionMgr.hpp # i f n d e f OPTIONMGR_HPP # d e f i n e OPTIONMGR_HPP # i n c l u d e " o p t i o n . hpp " # i n c l u d e <map> # include < string > u s i n g namespace s t d ; / ∗ ∗∗ ∗ T h i s Class i s r e a l i s e d as a S i n g l e t o n g ∗∗ ∗ / c l a s s OptionMgr { private : OptionMgr ( ) ; s t a t i c OptionMgr ∗ i n s t a n c e ; multimap < s t r i n g , O p t i o n > o p t i o n s ; public : s t a t i c OptionMgr ∗ g e t I n s t a n c e ( v o i d ) ; ~ OptionMgr ( v o i d ) ; void addOption ( s t r i n g , Option ) ; c o n s t multimap < s t r i n g , O p t i o n > ∗ c o n s t g e t O p t i o n s ( v o i d ) c o n s t ; friend class console ; }; # endif F.2.2. optionMgr.cpp # i f n d e f OPTIONMGR_HPP # d e f i n e OPTIONMGR_HPP # i n c l u d e " o p t i o n . hpp " # i n c l u d e <map> # include < string > u s i n g namespace s t d ; / ∗ ∗∗ ∗ T h i s Class i s r e a l i s e d as a S i n g l e t o n g ∗∗ ∗ / c l a s s OptionMgr { private : OptionMgr ( ) ; s t a t i c OptionMgr ∗ i n s t a n c e ; multimap < s t r i n g , O p t i o n > o p t i o n s ; public : s t a t i c OptionMgr ∗ g e t I n s t a n c e ( v o i d ) ; ~ OptionMgr ( v o i d ) ; void addOption ( s t r i n g , Option ) ; c o n s t multimap < s t r i n g , O p t i o n > ∗ c o n s t g e t O p t i o n s ( v o i d ) c o n s t ; 100 F.2. Framework friend class console ; }; # endif F.2.3. Option # i f n d e f OPTION_HPP # d e f i n e OPTION_HPP # include < string > # i n c l u d e <map> u s i n g namespace s t d ; enum a r g {NO_ARG, REQ_ARG} ; s t r u c t Option { string sopt ; string lopt ; arg has_arg ; s t r i n g argument ; string description ; / / S h o r t O p t i o n ; e . g . −h / / Long O p t i o n ; e . g . −−h e l p / / D e f a u l t V a l u e o f Argument ; e . g . 1 2 7 . 0 . 0 . 1 / / D e s c r i p t i o n o f O p t i o n ; e . g . p r i n t s o u t t h e Help Option ( s t r i n g s , s t r i n g l , arg at , s t r i n g a , s t r i n g d ) : s o p t ( s ) , l o p t ( l ) , h a s _ a r g ( a t ) , a r g u m e n t ( a ) , d e s c r i p t i o n ( d ) {} }; # endif 101 F.2. Framework F.2.4. cfgParser.hpp # i f n d e f CFGPARSER_HPP # d e f i n e CFGPARSER_HPP # include < string > # include <vector > # i n c l u d e <map> u s i n g namespace s t d ; e x t e r n "C" { # i n c l u d e < c o n f u s e . h> } / ∗ ∗∗ ∗ T h i s Class i s r e a l i s e d as a S i n g l e t o n g ∗∗ ∗ / class cfgParser { private : cfgParser ( ) ; static cfgParser ∗instance ; s t a t i c cfg_opt_t sad_opts [ ] ; static cfg_opt_t opts [ ] ; static string cfgfile_ ; struct cfgval { s t r i n g path ; float trust ; cfg_bool_t evaluation ; }; map< s t r i n g , c f g v a l > p l u g i n ; public : s t a t i c c f g P a r s e r ∗ g e t I n s t a n c e ( void ) ; ~ c f g P a r s e r ( void ) ; vector < s t r i n g > g e t P a t h ( void ) ; vector < s t r i n g > getPlugInName ( void ) ; float getTrust ( string ); bool g e t E v a l u a t i o n ( s t r i n g ) ; }; # endif F.2.5. cfgParser.cpp # i n c l u d e " c f g P a r s e r . hpp " # include < string > # include <vector > # i n c l u d e <map> u s i n g namespace s t d ; e x t e r n "C" { # i n c l u d e < c o n f u s e . h> } 102 F.2. Framework cfgParser ∗ cfgParser : : instance = 0; s t r i n g c f g P a r s e r : : c f g f i l e _ = " / e t c / sad / sad . conf " ; c f g P a r s e r ∗ c f g P a r s e r : : g e t I n s t a n c e ( void ) { i f ( i n s t a n c e == 0 ) i n s t a n c e = new c f g P a r s e r ; return i n s t a n c e ; } cfg_opt_t cfgParser : : sad_opts [] = { CFG_STR ( " p a t h " , 0 , CFGF_NONE ) , CFG_FLOAT ( " t r u s t " , 0 , CFGF_NONE ) , CFG_BOOL( " e v a l u a t i o n " , c f g _ t r u e , CFGF_NONE ) , CFG_END ( ) }; cfg_opt_t cfgParser : : opts [] = { CFG_SEC ( " p l u g i n " , s a d _ o p t s , CFGF_TITLE | CFGF_MULTI ) , CFG_END ( ) }; cfgParser : : cfgParser () { c f g _ t ∗ cfg , ∗ c f g _ s a d ; c f g v a l tmp ; c f g = c f g _ i n i t ( o p t s , CFGF_NONE ) ; c f g _ p a r s e ( cfg , c f g f i l e _ . c _ s t r ( ) ) ; f o r ( u n s i g n e d i n t i = 0 ; i < c f g _ s i z e ( c f g , " p l u g i n " ) ; i ++) { c f g _ s a d = c f g _ g e t n s e c ( cfg , " p l u g i n " , i ) ; tmp . p a t h = c f g _ g e t s t r ( c f g _ s a d , " p a t h " ) ; tmp . t r u s t = c f g _ g e t f l o a t ( c f g _ s a d , " t r u s t " ) ; tmp . e v a l u a t i o n = c f g _ g e t b o o l ( c f g _ s a d , " e v a l u a t i o n " ) ; p l u g i n [ c f g _ t i t l e ( c f g _ s a d ) ] = tmp ; } } c f g P a r s e r : : ~ c f g P a r s e r ( void ) { delete instance ; } / ∗ ∗∗ ∗ paths of plugins ∗∗ ∗ / vector < s t r i n g > c f g P a r s e r : : g e t P a t h ( void ) { vector < string > path ; f o r ( map< s t r i n g , c f g v a l > : : c o n s t _ i t e r a t o r i t e r ! = p l u g i n . end ( ) ; ++ i t e r ) { p a t h . p u s h _ b a c k ( i t e r −>s e c o n d . p a t h ) ; } return path ; } 103 i t e r = plugin . begin ( ) ; F.2. Framework / ∗ ∗∗ ∗ r e t u r n s v e c t o r w i t h t h e P l u g i n −Names ∗∗ ∗ / vector < s t r i n g > c f g P a r s e r : : getPlugInName ( void ) { v e c t o r < s t r i n g > name ; f o r ( map< s t r i n g , c f g v a l > : : c o n s t _ i t e r a t o r i t e r = p l u g i n . b e g i n ( ) ; i t e r ! = p l u g i n . end ( ) ; ++ i t e r ) { name . p u s h _ b a c k ( i t e r −> f i r s t ) ; } r e t u r n name ; } f l o a t c f g P a r s e r : : g e t T r u s t ( s t r i n g pname ) { r e t u r n p l u g i n [ pname ] . t r u s t ; } b o o l c f g P a r s e r : : g e t E v a l u a t i o n ( s t r i n g pname ) { r e t u r n p l u g i n [ pname ] . e v a l u a t i o n ; } 104 F.2. Framework F.2.6. console.hpp # i f n d e f CONSOLE_HPP # d e f i n e CONSOLE_HPP # i n c l u d e " o p t i o n M g r . hpp " # include < string > # include <vector > e x t e r n "C" { # i n c l u d e < g e t o p t . h> } class console { private : OptionMgr ∗ o p t s _ ; s t r i n g whichPlugIn ( s t r i n g &); public : console ( ) ; ~ console ( void ) ; i n t c m d p a r s e ( i n t , char ∗ ∗ ) ; / / r e t u r n s 0 on s u c c e s s }; # endif F.2.7. console.cpp # include # include # include # include " c o n s o l e . hpp " " o p t i o n M g r . hpp " " o p t i o n . hpp " " sadEx . hpp " # include # include # include # include <map> <string > <vector > <cctype > u s i n g namespace s t d ; console : : console () { o p t s _ = OptionMgr : : g e t I n s t a n c e ( ) ; } console : : ~ console ( void ) { } s t r i n g console : : whichPlugIn ( s t r i n g &s t r ) { s t r i n g tmp ; f o r ( multimap < s t r i n g , O p t i o n > : : i t e r a t o r m i t e r = o p t s _ −> o p t i o n s . b e g i n ( ) ; m i t e r ! = o p t s _ −> o p t i o n s . end ( ) ; ++ m i t e r ) { i f ( m i t e r −>s e c o n d . s o p t == s t r | | m i t e r −>s e c o n d . l o p t == s t r ) { tmp = m i t e r −>s e c o n d . l o p t . s u b s t r ( 2 , m i t e r −>s e c o n d . l o p t . s i z e ( ) − 2 ) ; f o r ( u n s i g n e d i n t i = 0 ; i < tmp . l e n g t h ( ) ; i ++) 105 F.2. Framework tmp [ i ] = t o u p p e r ( tmp [ i ] ) ; i f ( tmp == m i t e r −> f i r s t ) r e t u r n m i t e r −> f i r s t ; } } r e t u r n "SAD" ; } i n t c o n s o l e : : c m d p a r s e ( i n t a r g c , char ∗∗ a r g v ) { int i = 1; bool t i p s e t = f a l s e ; string s , plugin ; while ( i < argc ) { / / 1 . Which P l u g i n ? I f no P l u g I n −> t h r o w e x c e p t i o n ! ! ! s = argv [ i ] ; plugin = whichPlugIn ( s ) ; i f ( p l u g i n ! = "SAD" ) { / / Set PlugIn to e x p l i c i t f o r ( multimap < s t r i n g , O p t i o n > : : i t e r a t o r m i t e r = o p t s _ −> o p t i o n s . l o w e r _ b o u n d ( p l u g i n ) ; m i t e r ! = o p t s _ −> o p t i o n s . u p p e r _ b o u n d ( p l u g i n ) ; ++ m i t e r ) { i f ( s == m i t e r −>s e c o n d . s o p t | | s == m i t e r −>s e c o n d . l o p t ) m i t e r −>s e c o n d . a r g u m e n t = " e x p l i c i t " ; } / / 2. get next option i f (++ i >= a r g c ) break ; s = argv [ i ] ; } / / 3 . go i n t o P l u g I n f o r ( multimap < s t r i n g , O p t i o n > : : i t e r a t o r m i t e r = o p t s _ −> o p t i o n s . l o w e r _ b o u n d ( p l u g i n ) ; m i t e r ! = o p t s _ −> o p t i o n s . u p p e r _ b o u n d ( p l u g i n ) ; ++ m i t e r ) { / / 4. option of PlugIn ? i f ( s == m i t e r −>s e c o n d . s o p t | | s == m i t e r −>s e c o n d . l o p t && m i t e r −>s e c o n d . s o p t ! = "− t i p " ) { / / 5 . t r u e −> g e t & a s s i g n V a l u e i f ( m i t e r −>s e c o n d . h a s _ a r g == REQ_ARG) { i f (++ i >= a r g c ) throw C o n s o l e E x ( s + " u s a g e ! " ) ; s = argv [ i ] ; i f ( s [ 0 ] == ’− ’ ) throw C o n s o l e E x ( s + " no v a l i d a r g u m e n t " ) ; m i t e r −>s e c o n d . a r g u m e n t = s ; i f (++ i >= a r g c ) { if ( tipset ) return 0; / / e x i t success else throw C o n s o l e E x ( " no I P " ) ; 106 F.2. Framework } s = argv [ i ] ; m i t e r = o p t s _ −> o p t i o n s . l o w e r _ b o u n d ( p l u g i n ) ; continue ; } e l s e i f ( m i t e r −>s e c o n d . h a s _ a r g == NO_ARG) { m i t e r −>s e c o n d . a r g u m e n t = " t r u e " ; i f (++ i >= a r g c ) { if ( tipset ) return 0; / / e x i t success else throw C o n s o l e E x ( " no I P " ) ; } s = argv [ i ] ; m i t e r = o p t s _ −> o p t i o n s . l o w e r _ b o u n d ( p l u g i n ) ; continue ; } } e l s e i f ( p l u g i n == "SAD" && m i t e r −>s e c o n d . s o p t == "− t i p " && ! t i p s e t ) { i f ( a r g v [ a r g c − 1 ] [ 0 ] == ’− ’ ) throw C o n s o l e E x ( s + " no I P " ) ; else m i t e r −>s e c o n d . a r g u m e n t = a r g v [ a r g c −1]; t i p s e t = true ; −−a r g c ; continue ; } } i f ( p l u g i n == "SAD" && i < a r g c ) throw C o n s o l e E x ( " no s u c h a r g u m e t n " ) ; } return 0; } 107 F.2. Framework F.2.8. sadThread.hpp # i f n d e f SADTHREAD_HPP # d e f i n e SADTHREAD_HPP c l a s s SadThread { protected : S a d T h r e a d ( ) {} v i r t u a l ~ S a d T h r e a d ( ) {} v i r t u a l void operator ( ) ( ) {}; }; # endif F.2.9. captureT.hpp # i f n d e f CAPTURET_HPP # d e f i n e CAPTURET_HPP # i n c l u d e " s a d T h r e a d . hpp " # include < string > # include <vector > e x t e r n "C" { # i n c l u d e < p c a p . h> # i n c l u d e <pcap−b p f . h> } u s i n g namespace s t d ; c l a s s CaptureT : public SadThread { protected : pcap_t ∗handle ; char e r r b u f [ PCAP_ERRBUF_SIZE ] ; s t r u c t bpf_program f i l t e r ; / / p c a p _ d u m p e r _ t ∗dump ; int sleep ; int max_attempts ; int finish ; i n t ∗ examines ; s t a t i c c o n s t i n t PSIZE = 6 5 5 3 5 ; s t a t i c c o n s t i n t PROMISC = 1 ; s t a t i c c o n s t i n t NONBLOCK_TRUE = 1 ; public : C a p t u r e T ( char ∗ , s t r i n g , i n t /∗ Device : ∗ BPF F i l t e r S t r i n g : ∗ Z e i t i n ms : ∗ ∗ Anzahl Versuche : ∗ ∗ VorzeitigerAbbruch : ∗ ∗ üRckgabewert : ∗/ v i r t u a l ~CaptureT ( ) ; , int , int , i n t &); zB " e t h 0 " man tcpdump Z e i t , d i e nach e i n e m e r f o l g l o s e n p c a p _ n e x t b i s zum ä n c h s t e n V e r s u c h g e w a r t e t w i r d . Wird f o r t l a u f e n d d e k r e m e n t i e r t . V e r s u c h e = 0 −−> Abbruch Nachdem d i e s A n z a h l P a k e t e g e f a n g e n wurde −−> V o r z e i t i g e r Abbruch Anzahl gefangener Pakete 108 F.2. Framework v i r t u a l void operator ( ) ( ) ; }; # endif F.2.10. captureT.cpp # i n c l u d e " c a p t u r e T . hpp " # i n c l u d e " sadEx . hpp " # i n c l u d e < b o o s t / t h r e a d / t h r e a d . hpp > # i n c l u d e < b o o s t / t h r e a d / x t i m e . hpp > # include <vector > # include <iostream > e x t e r n "C" { # i n c l u d e < p c a p . h> # i n c l u d e <pcap−b p f . h> # i n c l u d e < s y s / t i m e . h> # i n c l u d e < t i m e . h> } u s i n g namespace s t d ; C a p t u r e T : : C a p t u r e T ( char ∗ dev , s t r i n g u s e r _ f i l t e r , i n t ms , i n t a t t e m p t s , i n t f i n , i n t &ex ) : s l e e p ( ms ) , m a x _ a t t e m p t s ( a t t e m p t s ) , f i n i s h ( f i n ) , e x a m i n e s (& ex ) { i f ( ! ( h a n d l e = p c a p _ o p e n _ l i v e ( dev , C a p t u r e T : : PSIZE , C a p t u r e T : : PROMISC , 0 , e r r b u f ) ) ) throw L i b p c a p E x ( e r r b u f ) ; i f ( p c a p _ c o m p i l e ( h a n d l e , & f i l t e r , c o n s t _ c a s t < char ∗ >( u s e r _ f i l t e r . c _ s t r ( ) ) , 0 , 0 ) < 0) throw L i b p c a p E x ( p c a p _ g e t e r r ( h a n d l e ) ) ; i f ( p c a p _ s e t f i l t e r ( handle , &f i l t e r ) < 0) throw L i b p c a p E x ( p c a p _ g e t e r r ( h a n d l e ) ) ; // p c a p _ f r e e c o d e (& f i l t e r ) ; FIXME /∗ s e t nonblocking ∗/ i f ( p c a p _ s e t n o n b l o c k ( h a n d l e , C a p t u r e T : : NONBLOCK_TRUE, e r r b u f ) < 0 ) throw L i b p c a p E x ( e r r b u f ) ; // // } i f ( ( dump = pcap_dump_open ( h a n d l e , " − " ) ) == NULL ) throw LibpcapEx ( p c a p _ g e t e r r ( handle ) ) ; CaptureT : : ~ CaptureT ( ) { /∗ Destruktor ∗/ i f ( ! handle ) { pcap_close ( handle ) ; handle = 0; } // } p c a p _ d u m p _ c l o s e ( dump ) ; 109 F.2. Framework void CaptureT : : operator ( ) ( ) { struct pcap_pkthdr header ; boost : : xtime xt ; c o n s t u _ c h a r ∗p ; // // // w h i l e ( m a x _ a t t e m p t s && f i n i s h ) { i f ( ( p = p c a p _ n e x t ( h a n d l e , &h e a d e r ) ) ! = NULL) { pcap_dump ( ( u _ c h a r ∗ ) dump , &h e a d e r , p ) ; i f ( p c a p _ d u m p _ f l u s h ( dump ) < 0 ) throw LibpcapEx ( " pcap_dump_flush " ) ; −−f i n i s h ; (∗ examines )++; } else { −−m a x _ a t t e m p t s ; if ( sleep ) { /∗ Sleep ∗/ i f ( b o o s t : : x t i m e _ g e t (& x t , b o o s t : : TIME_UTC ) ! = b o o s t : : TIME_UTC ) throw BoostEx ( " x t i m e _ g e t " ) ; x t . n s e c += ( s l e e p ∗ 1 0 0 0 ∗ 1 0 0 0 ) ; boost : : thread : : sleep ( xt ) ; } } } } 110 F.2. Framework F.2.11. injectionT.hpp # i f n d e f INJECTIONT_HPP # d e f i n e INJECTIONT_HPP # i n c l u d e " s a d T h r e a d . hpp " # include < string > # include < l i s t > e x t e r n "C" { # i n c l u d e < l i b n e t . h> # i n c l u d e < s y s / t i m e . h> # i n c l u d e < t i m e . h> } u s i n g namespace s t d ; c l a s s I n j e c t i o n T : public SadThread { private : l i s t < l i b n e t _ t ∗> p a c k e t s ; int sleep ; public : InjectionT (); InjectionT ( int ); ~ InjectionT () {}; void addPacket ( l i b n e t _ t ∗ ) ; v i r t u a l void operator ( ) ( ) ; }; # endif F.2.12. injectionT.cpp # i n c l u d e " sadEx . hpp " # i n c l u d e " i n j e c t i o n T . hpp " # i n c l u d e < b o o s t / t h r e a d / t h r e a d . hpp > # i n c l u d e < b o o s t / t h r e a d / x t i m e . hpp > # include <iostream > e x t e r n "C" { # i n c l u d e < l i b n e t . h> # i n c l u d e < s y s / t i m e . h> # i n c l u d e < t i m e . h> } u s i n g namespace s t d ; InjectionT : : InjectionT ( ) : sleep (0) { /∗ Konstruktor ∗/ } InjectionT : : InjectionT ( int s ): sleep ( s ) { /∗ Konstruktor ∗/ 111 F.2. Framework } void I n j e c t i o n T : : addPacket ( l i b n e t _ t ∗ packet ) { p a c k e t s . push_back ( packet ) ; } void I n j e c t i o n T : : operator ( ) ( ) { boost : : xtime xt ; l i s t < l i b n e t _ t ∗ >:: i t e r a t o r i t e r ; f o r ( i t e r = p a c k e t s . b e g i n ( ) ; i t e r ! = p a c k e t s . end ( ) ; ++ i t e r ) { i f ( l i b n e t _ w r i t e (∗ i t e r ) < 0) throw L i b n e t E x ( l i b n e t _ g e t e r r o r ( ∗ i t e r ) ) ; if ( sleep ) { /∗ Sleep ∗/ i f ( b o o s t : : x t i m e _ g e t (& x t , b o o s t : : TIME_UTC ) ! = b o o s t : : TIME_UTC ) throw BoostEx ( " x t i m e _ g e t " ) ; x t . n s e c += ( s l e e p ∗ 1 0 0 0 ∗ 1 0 0 0 ) ; boost : : thread : : sleep ( xt ) ; } l i b n e t _ d i a g _ d u m p _ c o n t e x t (& i t e r −>s e c o n d ) ; // } } 112 F.2. Framework F.2.13. latencyCT.hpp # i f n d e f LATENCYCT_HPP # d e f i n e LATENCYCT_HPP # i n c l u d e " c a p t u r e T . hpp " # include < string > # include <vector > e x t e r n "C" { # i n c l u d e < s y s / t i m e . h> # i n c l u d e < t i m e . h> } u s i n g namespace s t d ; c l a s s LatencyCT : p u b l i c C a p t u r e T { private : timeval∗ arrive ; t i m e v a l ∗ send ; public : LatencyCT ( char ∗ , s t r i n g , i n t , i n t , i n t & ) ; / ∗ D e v i c e zB " e t h 0 " ∗ BPF F i l t e r S t r i n g ∗ Anzahl Versuche , b i s Abgebrochen wird ∗ A n z a h l e r f o l g r e i c h e r C a p t u r e s , s o d a s s v o r z e i t i g e r Abbruch ö m g l i c h i s t ∗ üRckgabewert ü f r Auswertung ∗/ v i r t u a l ~ LatencyCT ( ) ; void setTimeval ( t i m e v a l ∗ , t i m e v a l ∗ ) ; v i r t u a l void operator ( ) ( ) ; }; # endif F.2.14. latencyCT.cpp # i n c l u d e " l a t e n c y C T . hpp " # i n c l u d e " sadEx . hpp " # i n c l u d e < b o o s t / t h r e a d / t h r e a d . hpp > # i n c l u d e < b o o s t / t h r e a d / x t i m e . hpp > # include <vector > # include <cstring > # include <iostream > e x t e r n "C" { # include # include # include # include } < p c a p . h> <pcap−b p f . h> < s y s / t i m e . h> < t i m e . h> u s i n g namespace s t d ; LatencyCT : : LatencyCT ( char ∗ dev , s t r i n g u s e r _ f i l t e r , i n t a t t e m p t s , i n t f i n , i n t &ex ) 113 F.2. Framework : C a p t u r e T ( dev , u s e r _ f i l t e r , 0 , a t t e m p t s , f i n , ex ) { /∗ Konstruktor ∗/ } LatencyCT : : ~ LatencyCT ( ) { /∗ Destruktor ∗/ } v o i d LatencyCT : : s e t T i m e v a l ( t i m e v a l ∗ s , t i m e v a l ∗ a ) { send = s ; arrive = a ; } v o i d LatencyCT : : o p e r a t o r ( ) ( ) { struct pcap_pkthdr header ; c o n s t u _ c h a r ∗p ; unsigned short seq = 0 ; u n s i g n e d char t y p e = 0 ; w h i l e ( m a x _ a t t e m p t s && f i n i s h ) { i f ( ( p = p c a p _ n e x t ( h a n d l e , &h e a d e r ) ) ! = NULL) { / ∗ g e t s e q u e n c e number ∗ / s e q = ∗ ( p + 4 0 ) ; s e q <<= 8 ; s e q | = ∗ ( p + 4 1 ) ; / ∗ g e t ICMP Echo t y p e ∗ / type = ∗( p +34); i f ( t y p e == 8 ) /∗ request ∗/ memcpy ( ( v o i d ∗)& s e n d [ s e q ] , ( v o i d ∗)& h e a d e r . t s , s i z e o f ( t i m e v a l ) ) ; e l s e i f ( t y p e == 0 ) / ∗ r e p l y ∗ / memcpy ( ( v o i d ∗)& a r r i v e [ s e q ] , ( v o i d ∗)& h e a d e r . t s , s i z e o f ( t i m e v a l ) ) ; −−f i n i s h ; (∗ examines )++; } else { −−m a x _ a t t e m p t s ; } } } 114 F.2. Framework F.2.15. ScanStrategy.hpp # i f n d e f SCANSTRATEGY_HPP # d e f i n e SCANSTRATEGY_HPP # include # include # include # include # include # include # include " o p t i o n M g r . hpp " " o p t i o n . hpp " " s a d T h r e a d . hpp " <vector > <deque > <string > <sstream > e x t e r n "C" { # i n c l u d e < l i b n e t . h> } class ScanStrategy { private : deque < S a d T h r e a d ∗> t h r e a d s ; protected : s t r i n g name ; OptionMgr ∗ o p t m g r ; /∗ Global Val ∗/ bool verbose ; int loop ; char ∗ d e v i c e ; u_int32_t ip_src , ip_dst ; /∗ Libnet S t u f f ∗/ libnet_t ∗context ; char e r r b u f [ LIBNET_ERRBUF_SIZE ] ; /∗ Libpcap S t u f f ∗/ stringstream f i l t e r ; void addThread ( SadThread &); void s t a r t T h r e a d s ( ) ; void pushOpt ( Option ) ; v i r t u a l void s e t L o c a l V a l ( void ) = 0; void s e t G l o b a l V a l ( void ) ; s t r i n g getUnique ( string , i n t ) ; s t r i n g mac2string ( u_int8_t ∗); // public : S c a n S t r a t e g y ( s t r i n g , OptionMgr ∗ ) ; virtual ~ScanStrategy ( ) ; void usage ( ) const ; v i r t u a l double scan ( void ) = 0 ; }; /∗ Class Factories ∗/ t y p e d e f S c a n S t r a t e g y ∗ c r e a t e S S _ t ( c o n s t char ∗ , OptionMgr ∗ ) ; typedef void d e s t r o y S S _ t ( S c a n S t r a t e g y ∗ ) ; # endif 115 F.2. Framework F.2.16. ScanStrategy.cpp # include # include # include # include # include # include # include # include " S c a n S t r a t e g y . hpp " " s a d T h r e a d . hpp " " i n j e c t i o n T . hpp " " c a p t u r e T . hpp " " sadEx . hpp " " o p t i o n M g r . hpp " " o p t i o n . hpp " " l a t e n c y C T . hpp " # include # include # include # include # include # include # include # include # include <iostream > <iomanip > <sstream > <vector > <deque > <map> <string > < b o o s t / t h r e a d / e x c e p t i o n s . hpp > < b o o s t / t h r e a d / t h r e a d . hpp > e x t e r n "C" { # i n c l u d e < l i b n e t . h> } u s i n g namespace s t d ; S c a n S t r a t e g y : : S c a n S t r a t e g y ( s t r i n g n , OptionMgr ∗ OptionMgr_ ) : name ( n ) , o p t m g r ( OptionMgr_ ) { } ScanStrategy ::~ ScanStrategy () { /∗ Destruktor ∗/ } v o i d S c a n S t r a t e g y : : a d d T h r e a d ( S a d T h r e a d &t ) { i f ( dynamic_cast < C a p t u r e T ∗>(& t ) ) t h r e a d s . p u s h _ f r o n t (& t ) ; e l s e i f ( dynamic_cast < I n j e c t i o n T ∗>(& t ) ) t h r e a d s . p u s h _ b a c k (& t ) ; } void S c a n S t r a t e g y : : s t a r t T h r e a d s ( ) { try { boost : : thread_group threadg ; deque < S a d T h r e a d ∗ > : : i t e r a t o r d i ; f o r ( d i = t h r e a d s . b e g i n ( ) ; d i ! = t h r e a d s . end ( ) ; ++ d i ) { i f ( LatencyCT ∗ c t = dynamic_cast < LatencyCT ∗> ( r e i n t e r p r e t _ c a s t < S a d T h r e a d ∗ >(∗ d i ) ) ) { t h r e a d g . c r e a t e _ t h r e a d (∗ c t ) ; } e l s e i f ( C a p t u r e T ∗ c t = dynamic_cast < C a p t u r e T ∗> ( r e i n t e r p r e t _ c a s t < S a d T h r e a d ∗ >(∗ d i ) ) ) 116 F.2. Framework { i f ( verbose ) c o u t << " [ S c a n S t r a t e g y ] s t a r t i n g c a p t u r e t h r e a d t h r e a d g . c r e a t e _ t h r e a d (∗ c t ) ; . . . " << e n d l ; } i f ( I n j e c t i o n T ∗ i t = dynamic_cast < I n j e c t i o n T ∗> ( r e i n t e r p r e t _ c a s t < S a d T h r e a d ∗ >(∗ d i ) ) ) { i f ( verbose ) c o u t << " [ S c a n S t r a t e g y ] s t a r t i n g i n j e c t i o n t h r e a d t h r e a d g . c r e a t e _ t h r e a d (∗ i t ) ; } . . . " << e n d l ; } threadg . join_all ( ) ; i f ( verbose ) c o u t << " [ S c a n S t r a t e g y ] t h r e a d s j o i n e d . . . " << e n d l ; / ∗ remove a l l t h r e a d s ∗ / threads . clear ( ) ; } c a t c h ( b o o s t : : t h r e a d _ r e s o u r c e _ e r r o r bex ) { throw BoostEx ( " t h r e a d _ r e s o u r c e _ e r r o r " ) ; } } void S c a n S t r a t e g y : : pushOpt ( Option opt ) { optmgr −>a d d O p t i o n ( name , o p t ) ; } void S c a n S t r a t e g y : : s e t G l o b a l V a l ( void ) { /∗ Defaults ∗/ device = 0; verbose = false ; multimap < s t r i n g , O p t i o n > : : c o n s t _ i t e r a t o r iter ; /∗ get the i n t e r f a c e ∗/ f o r ( i t e r = optmgr −>g e t O p t i o n s ()−> l o w e r _ b o u n d ( "SAD" ) ; i t e r ! = optmgr −>g e t O p t i o n s ()−> u p p e r _ b o u n d ( "SAD" ) ; + + i t e r ) { i f ( i t e r −>s e c o n d . s o p t == "− i f " ) d e v i c e = c o n s t _ c a s t < char ∗ >( i t e r −>s e c o n d . a r g u m e n t . c _ s t r ( ) ) ; } / ∗ L i b n e t i n i t f o r g e t t i n g some d e f a u l t a d r e s s e s ∗ / i f ( ( c o n t e x t = l i b n e t _ i n i t ( LIBNET_LINK , d e v i c e , e r r b u f ) ) == 0 ) throw L i b n e t E x ( e r r b u f ) ; / ∗ s e t d e f a u l t IP s o u r c e ∗ / i f ( ( i p _ s r c = l i b n e t _ g e t _ i p a d d r 4 ( c o n t e x t ) ) == ( u _ i n t 3 2 _ t ) ( − 1 ) ) throw L i b n e t E x ( l i b n e t _ g e t e r r o r ( c o n t e x t ) ) ; / ∗ s e t d e f a u l t IP t a r g e t ∗ / ip_dst = ip_src ; 117 F.2. Framework f o r ( i t e r = optmgr −>g e t O p t i o n s ()−> l o w e r _ b o u n d ( "SAD" ) ; i t e r ! = optmgr −>g e t O p t i o n s ()−> u p p e r _ b o u n d ( "SAD" ) ; + + i t e r ) { i f ( i t e r −>s e c o n d . s o p t == "−v " && i t e r −>s e c o n d . a r g u m e n t == " t r u e " ) verbose = true ; i f ( ( i t e r −>s e c o n d . s o p t == "−s i p " ) && ( i t e r −>s e c o n d . a r g u m e n t ! = " " ) ) i f (( ip_src = libnet_name2addr4 ( context , c o n s t _ c a s t < char ∗ >( i t e r −>s e c o n d . a r g u m e n t . c _ s t r ( ) ) , LIBNET_RESOLVE ) ) == ( u _ i n t 3 2 _ t ) ( − 1 ) ) throw L i b n e t E x ( l i b n e t _ g e t e r r o r ( c o n t e x t ) ) ; i f ( ( i t e r −>s e c o n d . s o p t == "− t i p " ) && ( i t e r −>s e c o n d . a r g u m e n t ! = " " ) ) i f (( ip_dst = libnet_name2addr4 ( context , c o n s t _ c a s t < char ∗ >( i t e r −>s e c o n d . a r g u m e n t . c _ s t r ( ) ) , LIBNET_RESOLVE ) ) == ( u _ i n t 3 2 _ t ) ( − 1 ) ) throw L i b n e t E x ( l i b n e t _ g e t e r r o r ( c o n t e x t ) ) ; } /∗ destroy the context ∗/ libnet_destroy ( context ); i f ( verbose ) { c o u t << " [ S c a n S t r a t e g y ] c o u t << " [ S c a n S t r a t e g y ] LIBNET_RESOLVE ) c o u t << " [ S c a n S t r a t e g y ] LIBNET_RESOLVE ) } D e v i c e : " << d e v i c e << e n d l ; S o u r c e−I P : " << l i b n e t _ a d d r 2 n a m e 4 ( i p _ s r c , << e n d l ; D e s t i n a t i o n −I P : " << l i b n e t _ a d d r 2 n a m e 4 ( i p _ d s t , << e n d l ; } void S c a n S t r a t e g y : : usage ( ) const { multimap < s t r i n g , O p t i o n > : : c o n s t _ i t e r a t o r i t e r ; c o u t << name << " O p t i o n s : " << e n d l ; f o r ( i t e r = optmgr −>g e t O p t i o n s ()−> l o w e r _ b o u n d ( name ) ; i t e r ! = optmgr −>g e t O p t i o n s ()−> u p p e r _ b o u n d ( name ) ; + + i t e r ) { c o u t << s e t w ( 2 ) << " " ; c o u t << l e f t << s e t w ( 8 ) << i t e r −>s e c o n d . s o p t << s e t w ( 2 0 ) << i t e r −>s e c o n d . l o p t ; i f ( i t e r −>s e c o n d . h a s _ a r g ! = NO_ARG) c o u t << " < " ; c o u t << i t e r −>s e c o n d . d e s c r i p t i o n ; i f ( i t e r −>s e c o n d . h a s _ a r g ! = NO_ARG) c o u t << " > " ; c o u t << e n d l ; } c o u t << e n d l ; } /∗ s t r i n g ScanStrategy : : getUnique ( s t r i n g s , i n t i ) { s t a t i c s t r i n g s t r e a m stream ; stream . s t r ( " " ) ; s t r e a m << s << s e t w ( 6 ) << s e t f i l l ( ’ 0 ’ ) << i ; return stream . s t r ( ) ; } ∗/ 118 F.2. Framework s t r i n g S c a n S t r a t e g y : : m a c 2 s t r i n g ( u _ i n t 8 _ t ∗mac ) { s t a t i c s t r i n g s t r e a m stream ; stream . s t r ( " " ) ; f o r ( i n t i = 0 ; i < 5 ; ++ i ) s t r e a m << s e t w ( 2 ) << s e t f i l l ( ’ 0 ’ ) << hex << ( i n t ) ∗ ( mac ++) << " : " ; s t r e a m << s e t w ( 2 ) << s e t f i l l ( ’ 0 ’ ) << hex << ( i n t ) ∗ mac ; return stream . s t r ( ) ; } 119 F.2. Framework F.2.17. sadEx.hpp # i f n d e f SADEX_HPP # d e f i n e SADEX_HPP # include < string > using s t d : : s t r i n g ; c l a s s SadEx { protected : s t r i n g errorMessage ; public : SadEx ( s t r i n g e ) : e r r o r M e s s a g e ( e ) {} s t r i n g operator ( ) ( ) { return errorMessage ; } }; c l a s s L i b n e t E x : p u b l i c SadEx { public : L i b n e t E x ( s t r i n g e ) : SadEx ( " L i b n e t : " + e ) {} }; c l a s s L i b p c a p E x : p u b l i c SadEx { public : L i b p c a p E x ( s t r i n g e ) : SadEx ( " L i b p c a p : " + e ) {} }; c l a s s BoostEx : p u b l i c SadEx { public : BoostEx ( s t r i n g e ) : SadEx ( " B o o s t : " + e ) {} }; c l a s s C o n s o l e E x : p u b l i c SadEx { public : C o n s o l e E x ( s t r i n g e ) : SadEx ( " C o n s o l e : " + e ) { } }; # endif 120 F.2. Framework F.2.18. sad.cpp # include # include # include # include # include " S c a n S t r a t e g y . hpp " " s a d . hpp " " sadEx . hpp " " c f g P a r s e r . hpp " " c o n s o l e . hpp " # include # include # include # include # include <iostream > <map> <iomanip > <string > <vector > # include < cstdlib > # include <cstring > e x t e r n "C" { # i n c l u d e < d l f c n . h> # i n c l u d e < u n i s t d . h> # i n c l u d e < s y s / t y p e s . h> } v o i d u s a g e ( OptionMgr ∗ , map< s t r i n g , S c a n S t r a t e g y ∗> & ) ; d o u b l e g e t R e s u l t ( c f g P a r s e r ∗ , map< s t r i n g , double > & ) ; u s i n g namespace s t d ; i n t main ( i n t a r g c , char ∗ a r g v [ ] ) { map< s t r i n g , S c a n S t r a t e g y ∗> s s t r a t ; soManager mgr ; c f g P a r s e r ∗cfgp = c f g P a r s e r : : g e t I n s t a n c e ( ) ; v e c t o r < s t r i n g > p a t h = c f g p −> g e t P a t h ( ) ; v e c t o r < s t r i n g > pname ; c o n s o l e cmd ; map< s t r i n g , double > s c a n r e s u l t s ; OptionMgr ∗ optMgr = OptionMgr : : g e t I n s t a n c e ( ) ; // // // // // // // // PlugIns libmanager c o n f i g F i l e −P a r s e r paths of Plugins PlugInNames command l i n e p a r s e r scan r e s u l t s P o i n t e r t o O p t i o n Manager optMgr −>a d d O p t i o n ( "SAD" , O p t i o n ( "− i f " , "−− i n t e r f a c e " , REQ_ARG, " e t h 0 " , " S c a n n i n g d e v i c e " ) ) ; optMgr −>a d d O p t i o n ( "SAD" , O p t i o n ( "− t i p " , "−−t a r g e t −i p " , REQ_ARG, " " , " t a r g e t I P " ) ) ; optMgr −>a d d O p t i o n ( "SAD" , O p t i o n ( "−s i p " , "−−s o u r c e −i p " , REQ_ARG, " " , " s o u r c e I P " ) ) ; optMgr −>a d d O p t i o n ( "SAD" , O p t i o n ( "−v " , "−−v e r b o s e " , NO_ARG, " f a l s e " , " v e r b o s e o u t p u t " ) ) ; / / u s e r == r o o t ? i f ( g e t u i d ( ) != 0) { c e r r << " You must be r o o t t o r u n " << a r g v [ 0 ] << e n d l ; e x i t ( EXIT_FAILURE ) ; } / / loading PlugIns int i = 0; f o r ( v e c t o r < s t r i n g > : : i t e r a t o r i t e r = p a t h . b e g i n ( ) ; i t e r ! = p a t h . end ( ) ; ++ i t e r ) { / / PlugInPointer mgr . p p t r . p u s h _ b a c k ( d l o p e n ( i t e r −> c _ s t r ( ) , RTLD_LAZY ) ) ; i f ( ! mgr . p p t r [ i ] ) { 121 F.2. Framework c e r r << " C a n n o t l o a d l i b r a r y " << d l e r r o r ( ) << e n d l ; e x i t ( EXIT_FAILURE ) ; } // Create− & D e s t r o y F u n c t i o n s mgr . c f u n c . p u s h _ b a c k ( ( c r e a t e S S _ t ∗ ) dlsym ( mgr . p p t r [ i ] , " c r e a t e " ) ) ; mgr . d f u n c . p u s h _ b a c k ( ( d e s t r o y S S _ t ∗ ) dlsym ( mgr . p p t r [ i ] , " d e s t r o y " ) ) ; i f ( ! mgr . c f u n c [ i ] | | ! mgr . d f u n c [ i ] ) { c e r r << " C a n n n o t l o a d s y m b o l s [ " << ∗ i t e r << " ] : " << d l e r r o r ( ) << e n d l ; } ++ i ; } / / creating Objects pname = c f g p −>g e t P l u g I n N a m e ( ) ; i = 0; f o r ( v e c t o r < c r e a t e S S _ t ∗ > : : c o n s t _ i t e r a t o r i t e r = mgr . c f u n c . b e g i n ( ) ; i t e r ! = mgr . c f u n c . end ( ) ; ++ i t e r ) { s s t r a t [ pname [ i ] ] = ( ( ∗ i t e r ) ( pname [ i ] . c _ s t r ( ) , optMgr ) ) ; ++ i ; } i f ( argc < 2) { u s a g e ( optMgr , s s t r a t ) ; e x i t ( EXIT_FAILURE ) ; } e l s e i f ( s t r c m p ( a r g v [ 1 ] , "−h " ) == 0 | | s t r c m p ( a r g v [ 1 ] , "−−h e l p " ) == 0 ) { u s a g e ( optMgr , s s t r a t ) ; e x i t ( EXIT_SUCCESS ) ; } try { cmd . c m d p a r s e ( a r g c , a r g v ) ; } c a t c h ( C o n s o l e E x ex ) { c e r r << ex ( ) << e n d l ; u s a g e ( optMgr , s s t r a t ) ; e x i t ( EXIT_FAILURE ) ; } / / i s t option e x p l i c i t ? v e c t o r < s t r i n g > exp ; f o r ( multimap < s t r i n g , O p t i o n > : : c o n s t _ i t e r a t o r i t e r = optMgr −>g e t O p t i o n s ()−> b e g i n ( ) ; i t e r ! = optMgr −>g e t O p t i o n s ()−> end ( ) ; ++ i t e r ) { i f ( i t e r −>s e c o n d . a r g u m e n t == " e x p l i c i t " && i t e r −> f i r s t ! = "SAD" ) exp . p u s h _ b a c k ( i t e r −> f i r s t ) ; } / / j a −> s c a n n u r d i e s e r p l u g i n s try { i f ( ! exp . empty ( ) ) { f o r ( v e c t o r < s t r i n g > : : i t e r a t o r i t e r = exp . b e g i n ( ) ; i t e r ! = exp . end ( ) ; ++ i t e r ) { s c a n r e s u l t s [ ∗ i t e r ] = s s t r a t [ ∗ i t e r ]−> s c a n ( ) ; 122 F.2. Framework } } else { / / s c a n −> a l l e f o r ( v e c t o r < s t r i n g > : : i t e r a t o r i t e r = pname . b e g i n ( ) ; i t e r ! = pname . end ( ) ; ++ i t e r ) s c a n r e s u l t s [ ∗ i t e r ] = s s t r a t [ ∗ i t e r ]−> s c a n ( ) ; } } c a t c h ( SadEx ex ) { c e r r << ex ( ) << e n d l ; e x i t ( EXIT_FAILURE ) ; } catch ( . . . ) { u s a g e ( optMgr , s s t r a t ) ; e x i t ( EXIT_FAILURE ) ; } / / p r i n t i n g out s c a n r e s u l t s c o u t << " S c a n R e s u l t s : " << e n d l ; c o u t << s e t w ( 8 0 ) << s e t f i l l ( ’− ’ ) << " " << e n d l ; c o u t << s e t f i l l ( ’ ’ ) << s e t w ( 2 2 ) << l e f t << " Method " << s e t w ( 1 7 ) << r i g h t << " T e s t r e s u l t %" << s e t w ( 1 5 ) << r i g h t << " T r u s t " << s e t w ( 1 8 ) << r i g h t << " E v a l u a t i o n " << e n d l ; c o u t << s e t w ( 8 0 ) << s e t f i l l ( ’− ’ ) << " " << e n d l ; f o r ( map< s t r i n g , double > : : c o n s t _ i t e r a t o r i t e r = s c a n r e s u l t s . b e g i n ( ) ; i t e r ! = s c a n r e s u l t s . end ( ) ; ++ i t e r ) { c o u t << s e t w ( 2 ) << s e t f i l l ( ’ ’ ) << " " ; c o u t << s e t w ( 2 0 ) << l e f t << s e t f i l l ( ’ ’ ) << i t e r −> f i r s t ; c o u t << s e t w ( 1 5 ) << r i g h t << s e t f i l l ( ’ ’ ) << s e t p r e c i s i o n ( 5 ) << i t e r −>s e c o n d ∗100 << " %" ; c o u t << s e t w ( 1 5 ) << r i g h t << s e t f i l l ( ’ ’ ) << c f g p −> g e t T r u s t ( i t e r −> f i r s t ) ; c o u t << s e t w ( 1 8 ) << r i g h t << s e t f i l l ( ’ ’ ) << c f g p −> g e t E v a l u a t i o n ( i t e r −> f i r s t ) << e n d l ; } c o u t << s e t w ( 8 0 ) << s e t f i l l ( ’− ’ ) << " " << e n d l ; c o u t << s e t w ( 2 ) << s e t f i l l ( ’ ’ ) << " " << s e t w ( 5 0 ) << l e f t << "Sum : " << s e t w ( 1 8 ) << r i g h t << s e t p r e c i s i o n ( 5 ) << 100 ∗ g e t R e s u l t ( c f g p , s c a n r e s u l t s ) << " %" << e n d l ; / / destroying all objects i = 0; for ( vector < destroySS_t ∗ >:: c o n s t _ i t e r a t o r i t e r ! = mgr . d f u n c . end ( ) ; ++ i t e r ) { ( ∗ i t e r ) ( s s t r a t [ pname [ i ] ] ) ; ++ i ; } i t e r = mgr . d f u n c . b e g i n ( ) ; / / closing all Libraries f o r ( v e c t o r < v o i d ∗ > : : c o n s t _ i t e r a t o r i t e r = mgr . p p t r . b e g i n ( ) ; i t e r ! = mgr . p p t r . end ( ) ; ++ i t e r ) { 123 F.2. Framework d l c l o s e (∗ i t e r ) ; } } v o i d u s a g e ( OptionMgr ∗o , map< s t r i n g , S c a n S t r a t e g y ∗> &s ) { multimap < s t r i n g , O p t i o n > : : c o n s t _ i t e r a t o r i t e r ; c o u t << " Usage : s a d [− PluginName ] [ P l u g I n O p t s i o n s ] [ s a d O p t i o n s ] T a r g e t I P " << e n d l << e n d l ; c o u t << s e t w ( 2 ) << " " << l e f t << s e t w ( 8 ) << "−h " << s e t w ( 2 0 ) << "−−h e l p " << " p r i n t t h i s m e s s a g e " << e n d l << e n d l ; c o u t << "SAD" << " O p t i o n s : " << e n d l ; f o r ( i t e r = o−>g e t O p t i o n s ()−> l o w e r _ b o u n d ( "SAD" ) ; i t e r ! = o−>g e t O p t i o n s ()−> u p p e r _ b o u n d ( "SAD" ) ; + + i t e r ) { c o u t << s e t w ( 2 ) << " " ; c o u t << l e f t << s e t w ( 8 ) << i t e r −>s e c o n d . s o p t << s e t w ( 2 0 ) << i t e r −>s e c o n d . l o p t ; i f ( i t e r −>s e c o n d . h a s _ a r g ! = NO_ARG) c o u t << " < " ; c o u t << i t e r −>s e c o n d . d e s c r i p t i o n ; i f ( i t e r −>s e c o n d . h a s _ a r g ! = NO_ARG) c o u t << " > " ; c o u t << e n d l ; } c o u t << e n d l ; f o r ( map< s t r i n g , S c a n S t r a t e g y ∗ > : : c o n s t _ i t e r a t o r i t e r ! = s . end ( ) ; ++ i t e r ) { i t e r −>s e c o n d −>u s a g e ( ) ; } i t e r = s . begin ( ) ; } d o u b l e g e t R e s u l t ( c f g P a r s e r ∗c , map< s t r i n g , double > &s r ) { i n t num = 0 ; double r e s = 0 ; f o r ( map< s t r i n g , double > : : c o n s t _ i t e r a t o r i t e r = s r . b e g i n ( ) ; i t e r ! = s r . end ( ) ; ++ i t e r ) { i f ( c−> g e t E v a l u a t i o n ( i t e r −> f i r s t ) ) { r e s += i t e r −>s e c o n d ∗ s t a t i c _ c a s t < double > ( c−> g e t T r u s t ( i t e r −> f i r s t ) ) ; ++num ; } } i f ( num ) r e t u r n r e s / num ; else return 0 . 0 ; } 124 F.3. Plugins F.3. Plugins F.3.1. arp.hpp # i f n d e f ARP_HPP # d e f i n e ARP_HPP # i n c l u d e " . . / S c a n S t r a t e g y . hpp " # i n c l u d e " . . / o p t i o n M g r . hpp " # include < string > e x t e r n "C" { # i n c l u d e < l i b n e t . h> } u s i n g namespace s t d ; class arp : public ScanStrategy { private : /∗ arp s p e c i f i c ∗/ u _ i n t 8 _ t zero_mac [ 6 ] ; u_int8_t ∗eth_src , ∗ eth_dst ; v i r t u a l void s e t L o c a l V a l ( ) ; public : a r p ( s t r i n g , OptionMgr ∗ ) ; virtual ~arp ( ) ; v i r t u a l double scan ( void ) ; }; e x t e r n "C" { S c a n S t r a t e g y ∗ c r e a t e ( char ∗ , OptionMgr ∗ ) ; v o i d d e s t r o y ( S c a n S t r a t e g y ∗p ) ; } # endif F.3.2. arp.cpp # include # include # include # include # include # include " a r p . hpp " " . . / sadEx . hpp " " . . / S c a n S t r a t e g y . hpp " " . . / o p t i o n M g r . hpp " " . . / i n j e c t i o n T . hpp " " . . / c a p t u r e T . hpp " # include # include # include # include <iostream > <string > <vector > <cstdlib > e x t e r n "C" { # i n c l u d e < l i b n e t . h> } u s i n g namespace s t d ; 125 F.3. Plugins a r p : : a r p ( s t r i n g n , OptionMgr ∗ o p t ) : S c a n S t r a t e g y ( n , o p t ) { /∗ Declare Options ∗/ p u s h O p t ( O p t i o n ( "−a " , "−−a r p " , NO_ARG, " " , " A c t i v a t e ARP−T e s t " ) ) ; p u s h O p t ( O p t i o n ( "−c " , "−−c o u n t " , REQ_ARG, " 10 " , " Count t o r u n ARP−T e s t " ) ) ; p u s h O p t ( O p t i o n ( "−fm " , "−−f a k e −mac " , REQ_ARG, " FF : FF : 0 0 : 0 0 : 0 0 : 0 0 " , " Faked D e s t i n a t i o n MAC" ) ) ; p u s h O p t ( O p t i o n ( "−sm " , "−−s o u r c e −mac " , REQ_ARG, " " , " s o u r c e MAC" ) ) ; } arp : : ~ arp ( ) { /∗ Destruktor ∗/ if (! eth_src ) { delete ( eth_src ); e t h _ s r c =0; } if (! eth_dst ) { delete ( eth_dst ); e t h _ d s t =0; } } void arp : : s e t L o c a l V a l ( ) { /∗ Defaults ∗/ memset ( ( v o i d ∗ ) zero_mac , 0 x00 , 6 ) ; /∗ Libnet i n i t for g e t t i n g d e f a u l t addresses ∗/ i f ( ( c o n t e x t = l i b n e t _ i n i t ( LIBNET_LINK , d e v i c e , e r r b u f ) ) == 0 ) throw L i b n e t E x ( e r r b u f ) ; / ∗ S e t d e f a u l t MAC S o u r c e ∗ / i f ( ( e t h _ s r c = ( u _ i n t 8 _ t ∗ ) l i b n e t _ g e t _ h w a d d r ( c o n t e x t ) ) == 0 ) throw L i b n e t E x ( l i b n e t _ g e t e r r o r ( c o n t e x t ) ) ; i n t dummy ; multimap < s t r i n g , O p t i o n > : : c o n s t _ i t e r a t o r i t e r ; f o r ( i t e r = optmgr −>g e t O p t i o n s ()−> l o w e r _ b o u n d ( name ) ; i t e r ! = optmgr −>g e t O p t i o n s ()−> u p p e r _ b o u n d ( name ) ; + + i t e r ) { i f ( i t e r −>s e c o n d . s o p t == "−c " ) l o o p = a t o i ( i t e r −>s e c o n d . a r g u m e n t . c _ s t r ( ) ) ; i f ( i t e r −>s e c o n d . s o p t == "−fm " ) if (( eth_dst = libnet_hex_aton ( r e i n t e r p r e t _ c a s t < i n t 8 _ t ∗ >( c o n s t _ c a s t < char ∗> ( i t e r −>s e c o n d . a r g u m e n t . c _ s t r ( ) ) ) , &dummy ) ) == 0 ) throw L i b n e t E x ( " [ARP] s e t L o c a l V a l : l i b n e t _ h e x _ a t o n " ) ; i f ( ( i t e r −>s e c o n d . s o p t == "−sm " ) && ( i t e r −>s e c o n d . a r g u m e n t ! = " " ) ) if (( eth_src = libnet_hex_aton ( r e i n t e r p r e t _ c a s t < i n t 8 _ t ∗ >( c o n s t _ c a s t < char ∗> ( i t e r −>s e c o n d . a r g u m e n t . c _ s t r ( ) ) ) , &dummy ) ) == 0 ) throw L i b n e t E x ( " [ARP] s e t L o c a l V a l : l i b n e t _ h e x _ a t o n " ) ; } 126 F.3. Plugins /∗ Destroy the context ∗/ libnet_destroy ( context ); } double arp : : scan ( void ) { /∗ Set Global Values & D e f a u l t s ∗/ setGlobalVal ( ) ; /∗ Set Local Values ∗/ setLocalVal ( ) ; i f ( verbose ) { c o u t << " [ARP] S o u r c e−MAC: " << m a c 2 s t r i n g ( e t h _ s r c ) << e n d l ; c o u t << " [ARP] Fake−MAC: " << m a c 2 s t r i n g ( e t h _ d s t ) << e n d l ; c o u t << " [ARP] Loop : " << l o o p << e n d l ; } /∗ Libnet I n i t ∗/ i f ( ( c o n t e x t = l i b n e t _ i n i t ( LIBNET_LINK , d e v i c e , e r r b u f ) ) == 0 ) throw L i b n e t E x ( e r r b u f ) ; / ∗ B u i l d Fake ARP R e q u e s t ∗ / i f ( l i b n e t _ a u t o b u i l d _ a r p ( ARPOP_REQUEST , e t h _ s r c , ( u _ i n t 8 _ t ∗)& i p _ s r c , zero_mac , ( u _ i n t 8 _ t ∗)& i p _ d s t , c o n t e x t ) < 0 ) throw L i b n e t E x ( l i b n e t _ g e t e r r o r ( c o n t e x t ) ) ; /∗ Build Ethernet ∗/ i f ( l i b n e t _ b u i l d _ e t h e r n e t ( e t h _ d s t , e t h _ s r c , ETHERTYPE_ARP , 0 , 0 , c o n t e x t , 0 ) < 0 ) throw L i b n e t E x ( l i b n e t _ g e t e r r o r ( c o n t e x t ) ) ; // i f ( verbose ) { c o u t << " [ARP] R e q u e s t P a c k e t : " << e n d l ; libnet_diag_dump_context ( context ); } /∗ I n j e c t i o n ∗/ I n j e c t i o n T fakeArp ; f o r ( i n t i = 0 ; i < l o o p ; ++ i ) fakeArp . addPacket ( c o n t e x t ) ; /∗ Capture ∗/ i n t examines = 0; /∗ Build F i l t e r ∗/ f i l t e r << " a r p [ 7 ] = = 0 x02 and " ; f i l t e r << " s r c h o s t " << l i b n e t _ a d d r 2 n a m e 4 ( i p _ d s t , LIBNET_RESOLVE ) << " and " ; f i l t e r << " d s t h o s t " << l i b n e t _ a d d r 2 n a m e 4 ( i p _ s r c , LIBNET_RESOLVE ) ; i f ( verbose ) c o u t << " [ARP] F i l t e r : " << f i l t e r . s t r ( ) << e n d l ; CaptureT arpcap ( device , f i l t e r . s t r ( ) , 2 , 1000 , loop , examines ) ; / ∗ Add T h r e a d s ∗ / addThread ( fakeArp ) ; addThread ( arpcap ) ; 127 F.3. Plugins /∗ S t a r t Threads ∗/ startThreads (); / ∗ CleanUp I n j e c t i o n ∗ / libnet_destroy ( context ); / ∗ Examine ∗ / i f ( verbose ) c o u t << " [ARP] Examines c o u n t : " << e x a m i n e s << e n d l ; / ∗ ARP T e s t R e s u l t ∗ / i f ( examines ) return 1 . 0 ; else return 0; } e x t e r n "C" S c a n S t r a t e g y ∗ c r e a t e ( char ∗n , OptionMgr ∗ o p t ) { r e t u r n new a r p ( n , o p t ) ; } e x t e r n "C" v o i d d e s t r o y ( S c a n S t r a t e g y ∗p ) { delete p ; } 128 F.3. Plugins F.3.3. icmp.hpp # i f n d e f ICMP_HPP # d e f i n e ICMP_HPP # i n c l u d e " . . / S c a n S t r a t e g y . hpp " # i n c l u d e " . . / o p t i o n M g r . hpp " # include < string > e x t e r n "C" { # i n c l u d e < l i b n e t . h> } u s i n g namespace s t d ; c l a s s icmp : p u b l i c S c a n S t r a t e g y { private : / ∗ icmp s p e c i f i c ∗ / u_int16_t id ; u_int8_t ∗eth_src , ∗ eth_dst ; v i r t u a l void s e t L o c a l V a l ( ) ; public : icmp ( s t r i n g , OptionMgr ∗ ) ; v i r t u a l ~ icmp ( ) ; v i r t u a l double scan ( void ) ; }; e x t e r n "C" { S c a n S t r a t e g y ∗ c r e a t e ( char ∗ , OptionMgr ∗ ) ; v o i d d e s t r o y ( S c a n S t r a t e g y ∗p ) ; } # endif F.3.4. icmp.cpp # include # include # include # include # include # include " icmp . hpp " " . . / sadEx . hpp " " . . / S c a n S t r a t e g y . hpp " " . . / o p t i o n M g r . hpp " " . . / i n j e c t i o n T . hpp " " . . / c a p t u r e T . hpp " # include # include # include # include <iostream > <string > <vector > <cstdlib > e x t e r n "C" { # i n c l u d e < s y s / t y p e s . h> # i n c l u d e < u n i s t d . h> # i n c l u d e < l i b n e t . h> } u s i n g namespace s t d ; 129 F.3. Plugins icmp : : icmp ( s t r i n g n , OptionMgr ∗ o p t ) : S c a n S t r a t e g y ( n , o p t ) { /∗ Declare Options ∗/ p u s h O p t ( O p t i o n ( "−i " , "−−icmp " , NO_ARG, " " , " A c t i v a t e ICMP−T e s t " ) ) ; p u s h O p t ( O p t i o n ( "−c " , "−−c o u n t " , REQ_ARG, " 10 " , " Count t o r u n ICMP−T e s t " ) ) ; p u s h O p t ( O p t i o n ( "−fm " , "−−f a k e −mac " , REQ_ARG, " FF : FF : 0 0 : 0 0 : 0 0 : 0 0 " , " Faked D e s t i n a t i o n MAC" ) ) ; p u s h O p t ( O p t i o n ( "−sm " , "−−s o u r c e −mac " , REQ_ARG, " " , " s o u r c e MAC" ) ) ; } icmp : : ~ icmp ( ) { /∗ Destruktor ∗/ if (! eth_src ) { delete ( eth_src ); e t h _ s r c =0; } if (! eth_dst ) { delete ( eth_dst ); e t h _ d s t =0; } } v o i d icmp : : s e t L o c a l V a l ( ) { /∗ Defaults ∗/ id = getpid ( ) ; / ∗ L i b n e t I n i t f o r g e t t i n g some d e f a u l t a d r e s s e s ∗ / i f ( ( c o n t e x t = l i b n e t _ i n i t ( LIBNET_LINK , d e v i c e , e r r b u f ) ) == 0 ) throw L i b n e t E x ( e r r b u f ) ; / ∗ S e t d e f a u l t MAC S o u r c e ∗ / i f ( ( e t h _ s r c = ( u _ i n t 8 _ t ∗ ) l i b n e t _ g e t _ h w a d d r ( c o n t e x t ) ) == 0 ) throw L i b n e t E x ( l i b n e t _ g e t e r r o r ( c o n t e x t ) ) ; i n t dummy ; multimap < s t r i n g , O p t i o n > : : c o n s t _ i t e r a t o r i t e r ; f o r ( i t e r = optmgr −>g e t O p t i o n s ()−> l o w e r _ b o u n d ( name ) ; i t e r ! = optmgr −>g e t O p t i o n s ()−> u p p e r _ b o u n d ( name ) ; + + i t e r ) { i f ( i t e r −>s e c o n d . s o p t == "−c " ) l o o p = a t o i ( i t e r −>s e c o n d . a r g u m e n t . c _ s t r ( ) ) ; i f ( i t e r −>s e c o n d . s o p t == "−fm " ) if (( eth_dst = libnet_hex_aton ( r e i n t e r p r e t _ c a s t < i n t 8 _ t ∗ >( c o n s t _ c a s t < char ∗> ( i t e r −>s e c o n d . a r g u m e n t . c _ s t r ( ) ) ) , &dummy ) ) == 0 ) throw L i b n e t E x ( " [ ICMP ] s e t L o c a l V a l : l i b n e t _ h e x _ a t o n " ) ; i f ( ( i t e r −>s e c o n d . s o p t == "−sm " ) && ( i t e r −>s e c o n d . a r g u m e n t ! = " " ) ) if (( eth_src = libnet_hex_aton ( r e i n t e r p r e t _ c a s t < i n t 8 _ t ∗ >( c o n s t _ c a s t < char ∗> ( i t e r −>s e c o n d . a r g u m e n t . c _ s t r ( ) ) ) , &dummy ) ) == 0 ) throw L i b n e t E x ( " [ARP] s e t L o c a l V a l : l i b n e t _ h e x _ a t o n " ) ; } 130 F.3. Plugins /∗ Destroy the context ∗/ libnet_destroy ( context ); } d o u b l e icmp : : s c a n ( v o i d ) { /∗ Set Global Values & Defauls ∗/ setGlobalVal ( ) ; /∗ Set Local Values ∗/ setLocalVal ( ) ; i f ( verbose ) { c o u t << " [ ICMP ] S o u r c e−MAC: " << m a c 2 s t r i n g ( e t h _ s r c ) << e n d l ; c o u t << " [ ICMP ] Fake−MAC: " << m a c 2 s t r i n g ( e t h _ d s t ) << e n d l ; c o u t << " [ ICMP ] Loop : " << l o o p << e n d l ; } /∗ Libnet I n i t ∗/ i f ( ( c o n t e x t = l i b n e t _ i n i t ( LIBNET_LINK , d e v i c e , e r r b u f ) ) == 0 ) throw L i b n e t E x ( e r r b u f ) ; / ∗ B u i l d ICMP e c h o r e q u e s t ∗ / i f ( l i b n e t _ b u i l d _ i c m p v 4 _ e c h o ( ICMP_ECHO , 0 , 0 , i d , 0 , 0 , 0 , c o n t e x t , 0 ) < 0 ) throw L i b n e t E x ( l i b n e t _ g e t e r r o r ( c o n t e x t ) ) ; / ∗ B u i l d IP p a c k e t ∗ / i f ( l i b n e t _ b u i l d _ i p v 4 ( LIBNET_IPV4_H + LIBNET_ICMPV4_ECHO_H , 0 , i d , 0 , 8 , IPPROTO_ICMP , 0 , i p _ s r c , i p _ d s t , 0 , 0 , c o n t e x t , 0 ) < 0 ) throw L i b n e t E x ( l i b n e t _ g e t e r r o r ( c o n t e x t ) ) ; /∗ Build Ethernet ∗/ i f ( l i b n e t _ b u i l d _ e t h e r n e t ( e t h _ d s t , e t h _ s r c , ETHERTYPE_IP , 0 , 0 , c o n t e x t , 0 ) < 0 ) throw L i b n e t E x ( l i b n e t _ g e t e r r o r ( c o n t e x t ) ) ; /∗ I n j e c t i o n ∗/ I n j e c t i o n T fakeICMP ; f o r ( i n t i = 0 ; i < l o o p ; ++ i ) fakeICMP . a d d P a c k e t ( c o n t e x t ) ; /∗ Capture ∗/ i n t examines = 0; /∗ Build F i l t e r ∗/ f i l t e r << " icmp [ i c m p t y p e ] = icmp−e c h o r e p l y and " << " s r c h o s t " << l i b n e t _ a d d r 2 n a m e 4 ( i p _ d s t , LIBNET_RESOLVE ) << " and " << " d s t h o s t " << l i b n e t _ a d d r 2 n a m e 4 ( i p _ s r c , LIBNET_RESOLVE ) << " and " << " icmp [ 4 : 2 ] = = " << i d << " and " << " icmp [ 6 : 2 ] = = 0 " ; i f ( verbose ) c o u t << " [ ICMP ] F i l t e r : " << f i l t e r . s t r ( ) << e n d l ; CaptureT icmpcap ( device , f i l t e r . s t r ( ) , 2 , 1000 , loop , examines ) ; / ∗ Add T h r e a d s ∗ / a d d T h r e a d ( fakeICMP ) ; addThread ( icmpcap ) ; /∗ S t a r t Threads ∗/ startThreads (); 131 F.3. Plugins / ∗ CleanUp I n j e c t i o n ∗ / libnet_destroy ( context ); /∗ Examines ∗/ i f ( verbose ) c o u t << " [ ICMP ] Examines c o u n t : " << e x a m i n e s << e n d l ; / ∗ ICMP T e s t R e s u l t ∗ / i f ( examines ) return 1 . 0 ; else return 0; } e x t e r n "C" S c a n S t r a t e g y ∗ c r e a t e ( char ∗n , OptionMgr ∗ o p t ) { r e t u r n new icmp ( n , o p t ) ; } e x t e r n "C" v o i d d e s t r o y ( S c a n S t r a t e g y ∗p ) { delete p ; } 132 F.3. Plugins F.3.5. dns.hpp # i f n d e f DNS_HPP # d e f i n e DNS_HPP # include # include # include # include # include " . . / S c a n S t r a t e g y . hpp " " . . / o p t i o n M g r . hpp " <string > <sstream > <vector > e x t e r n "C" { # i n c l u d e < l i b n e t . h> } u s i n g namespace s t d ; c l a s s dns : publ ic S c a n S t r a t e g y { private : /∗ dns s p e c i f i c ∗/ s t a t i c stringstream queryip ; u_int16_t id ; u _ i n t 1 6 _ t seq ; v e c t o r < l i b n e t _ t ∗> gc ; / / ; −) ü G r s s e an J a v a v i r t u a l void s e t L o c a l V a l ( void ) ; void b u i l d F i l t e r ( void ) ; public : d n s ( s t r i n g , OptionMgr ∗ ) ; v i r t u a l ~dns ( ) ; v i r t u a l double scan ( void ) ; }; e x t e r n "C" { S c a n S t r a t e g y ∗ c r e a t e ( char ∗ , OptionMgr ∗ ) ; v o i d d e s t r o y ( S c a n S t r a t e g y ∗p ) ; } # endif F.3.6. dns.cpp # include # include # include # include # include # include " d n s . hpp " " . . / sadEx . hpp " " . . / S c a n S t r a t e g y . hpp " " . . / o p t i o n M g r . hpp " " . . / i n j e c t i o n T . hpp " " . . / c a p t u r e T . hpp " # include # include # include # include # include <string > <vector > <sstream > <cstdlib > <ctime > # include <iostream > e x t e r n "C" { # i n c l u d e < l i b n e t . h> 133 F.3. Plugins # i n c l u d e < s y s / t y p e s . h> # i n c l u d e < u n i s t d . h> } u s i n g namespace s t d ; s t r i n g s t r e a m dns : : q u e r y i p ; d n s : : d n s ( s t r i n g n , OptionMgr ∗ o p t ) : S c a n S t r a t e g y ( n , o p t ) { /∗ Declare Options ∗/ p u s h O p t ( O p t i o n ( "−d " , "−−d n s " , NO_ARG, " " , " A c t i v a t e DNS−T e s t " ) ) ; p u s h O p t ( O p t i o n ( "−c " , "−−c o u n t " , REQ_ARG, " 5 " , " Count t o r u n DNS−T e s t " ) ) ; } dns : : ~ dns ( ) { /∗ Destruktor ∗/ vector < l i b n e t _ t ∗ >:: i t e r a t o r i t e r ; f o r ( i t e r = gc . b e g i n ( ) ; i t e r ! = gc . b e g i n ( ) ; ++ i t e r ) l i b n e t _ d e s t r o y (∗ i t e r ) ; } void dns : : s e t L o c a l V a l ( ) { multimap < s t r i n g , O p t i o n > : : c o n s t _ i t e r a t o r i t e r ; f o r ( i t e r = optmgr −>g e t O p t i o n s ()−> l o w e r _ b o u n d ( name ) ; i t e r ! = optmgr −>g e t O p t i o n s ()−> u p p e r _ b o u n d ( name ) ; + + i t e r ) { i f ( i t e r −>s e c o n d . s o p t == "−c " ) l o o p = a t o i ( i t e r −>s e c o n d . a r g u m e n t . c _ s t r ( ) ) ; } } double dns : : scan ( void ) { v e c t o r <CaptureT > caps ; InjectionT fakePing ; i n t examines = 0; / / Set Global Values & D e f a u l t s setGlobalVal ( ) ; / / Set Local Values setLocalVal ( ) ; s r a n d ( s t a t i c _ c a s t <unsigned int >( time ( 0 ) ) ) ; f o r ( i n t i = 0 ; i < l o o p ; ++ i ) { / / Libnet I n i t i f ( ! ( c o n t e x t = l i b n e t _ i n i t ( LIBNET_RAW4 , d e v i c e , e r r b u f ) ) ) throw L i b n e t E x ( e r r b u f ) ; / / B u i l d Fake ICMP−Header id = getpid ( ) ; seq = i ; queryip . s t r ( " " ) ; queryip . clear ( ) ; q u e r y i p << r a n d ( ) % 200 + 1 << " . " << r a n d ( ) % 255 << " . " << r a n d ( ) % 255 << " . " << r a n d ( ) % 2 5 5 ; 134 F.3. Plugins i f ( verbose ) c o u t << " [DNS] q u e r y−I P : " << q u e r y i p . s t r ( ) << e n d l ; i f ( l i b n e t _ b u i l d _ i c m p v 4 _ e c h o ( ICMP_ECHO , 0 , 0 , i d , seq , 0 , 0 , c o n t e x t , 0 ) < 0 ) throw L i b n e t E x ( l i b n e t _ g e t e r r o r ( c o n t e x t ) ) ; / / B u i l d Fake IP−Header u_int32_t tqip = libnet_name2addr4 ( context , c o n s t _ c a s t < char ∗ >( q u e r y i p . s t r ( ) . c _ s t r ( ) ) , LIBNET_RESOLVE ) ; i f ( t q i p == ( u _ i n t 3 2 _ t ) −1) throw L i b n e t E x ( l i b n e t _ g e t e r r o r ( c o n t e x t ) ) ; i f ( l i b n e t _ b u i l d _ i p v 4 ( LIBNET_IPV4_H + LIBNET_ICMPV4_ECHO_H + 0 , 0 , i d , 0 , 6 4 , IPPROTO_ICMP , 0 , i p _ s r c , t q i p , 0 , 0 , c o n t e x t , 0 ) < 0 ) throw L i b n e t E x ( l i b n e t _ g e t e r r o r ( c o n t e x t ) ) ; // Injection fakePing . addPacket ( context ) ; buildFilter (); i f ( verbose ) c o u t << " [DNS] F i l t e r : " << f i l t e r . s t r ( ) << e n d l ; caps . push_back ( CaptureT ( device , gc . p u s h _ b a c k ( c o n t e x t ) ; f i l t e r . s t r ( ) , 1 , 2000 , 1 , examines ) ) ; } for ( v e c t o r <CaptureT > : : i t e r a t o r addThread (∗ i t e r ) ; i t e r = caps . begin ( ) ; i t e r ! = c a p s . end ( ) ; ++ i t e r ) addThread ( fakePing ) ; startThreads (); / ∗ DNS T e s t R e s u l t ∗ / i f ( examines ) return 1 . 0 ; else return 0; } void dns : : b u i l d F i l t e r ( void ) { filter . str ("" ); f i l t e r . clear (); / / Building Filter unsigned i n t pos [ 4 ] , u o f f s e t = 21; string s [4]; f o r ( i n t i = 3 ; i >= 0 ; −−i ) { g e t l i n e ( queryip , s [ i ] , ’ . ’ ) ; pos [ i ] = s [ i ] . s i z e ( ) ; } f i l t e r << " d s t p o r t 53 " << " and " << " s r c h o s t " << l i b n e t _ a d d r 2 n a m e 4 ( i p _ d s t , LIBNET_RESOLVE ) ; f o r ( u n s i g n e d i n t i = 0 ; i < 4 ; ++ i ) { f o r ( u n s i g n e d i n t j = 0 ; j < s [ i ] . s i z e ( ) ; ++ j ) { f i l t e r << " and " << " udp [ " << u o f f s e t << " ]== " 135 F.3. Plugins << s t a t i c _ c a s t < i n t > ( s [ i ] . a t ( j ) ) ; u o f f s e t ++; } ++ u o f f s e t ; } } e x t e r n "C" S c a n S t r a t e g y ∗ c r e a t e ( char ∗n , OptionMgr ∗ o p t ) { r e t u r n new d n s ( n , o p t ) ; } e x t e r n "C" v o i d d e s t r o y ( S c a n S t r a t e g y ∗p ) { delete p ; } 136 F.3. Plugins F.3.7. latency.hpp # i f n d e f LATENCY_HPP # d e f i n e LATENCY_HPP # include # include # include # include " . . / S c a n S t r a t e g y . hpp " " . . / o p t i o n M g r . hpp " <string > <fstream > e x t e r n "C" { # i n c l u d e < l i b n e t . h> # i n c l u d e < s y s / t i m e . h> # i n c l u d e < t i m e . h> } u s i n g namespace s t d ; class latency : public ScanStrategy { private : /∗ latency s p e c i f i c ∗/ char e r r b u f t c p [ LIBNET_ERRBUF_SIZE ] ; u_short src_port , dst_port ; u_int8_t ∗payload ; u_short payload_s ; u_int32_t ip_fake ; u_int16_t id ; l i b n e t _ t ∗flood ; s t a t i c c o n s t u n s i g n e d i n t PACKETS = 5 0 0 0 0 0 ; s t a t i c c o n s t u n s i g n e d i n t ACOUNT = 5 0 ; t i m e v a l t v b [ACOUNT] , t v e [ACOUNT ] ; l i b n e t _ t ∗ i p a c k [ACOUNT ] ; ofstream f i l e ; v i r t u a l void s e t L o c a l V a l ( ) ; v o i d buildICMP ( v o i d ) ; void buildTCP ( void ) ; void r e s e t T i m e r ( void ) ; unsigned i n t average ( void ) ; public : l a t e n c y ( s t r i n g , OptionMgr ∗ ) ; virtual ~latency ( ) ; v i r t u a l double scan ( void ) ; }; e x t e r n "C" { S c a n S t r a t e g y ∗ c r e a t e ( char ∗ , OptionMgr ∗ ) ; v o i d d e s t r o y ( S c a n S t r a t e g y ∗p ) ; } # endif F.3.8. latency.cpp 137 F.3. Plugins # include # include # include # include # include # include " l a t e n c y . hpp " " . . / l a t e n c y C T . hpp " " . . / sadEx . hpp " " . . / S c a n S t r a t e g y . hpp " " . . / o p t i o n M g r . hpp " " . . / i n j e c t i o n T . hpp " # include < string > # include <vector > # include < cstdlib > # include <iostream > # include <fstream > # i n c l u d e <iomanip > e x t e r n "C" { # i n c l u d e < l i b n e t . h> # i n c l u d e < s y s / t i m e . h> # i n c l u d e < s y s / t y p e s . h> # i n c l u d e < t i m e . h> # i n c l u d e < u n i s t d . h> } u s i n g namespace s t d ; l a t e n c y : : l a t e n c y ( s t r i n g n , OptionMgr ∗ o p t ) : S c a n S t r a t e g y ( n , o p t ) { /∗ Declare Options ∗/ p u s h O p t ( O p t i o n ( "−l " , "−−l a t e n c y " , NO_ARG, " " , " A c t i v a t e L a t e n c y −T e s t " ) ) ; p u s h O p t ( O p t i o n ( "−c " , "−−c o u n t " , REQ_ARG, " 1 " , " Count t o r u n L a t e n c y −T e s t " ) ) ; p u s h O p t ( O p t i o n ( "−s p " , "−−s o u r c e −p o r t " , REQ_ARG, " 23 " , "TCP−S o u r c e−P o r t o f t h e f l o o d i n g T h r e a d " ) ) ; p u s h O p t ( O p t i o n ( "−dp " , "−−d e s t i n a t i o n −p o r t " , REQ_ARG, " 23 " , "TCP−D e s t i o n a t i o n −P o r t o f t h e f l o o d i n g T h r e a d " ) ) ; p u s h O p t ( O p t i o n ( "−p " , "−−p a y l o a d " , REQ_ARG, " p a s s w o r d : Buhhh − G o t c h a ! ! ! " , " P a y l o a d you want t o s e n d ( i n \ " Double Quote \ " ) " ) ) ; p u s h O p t ( O p t i o n ( "−f i p " , "−−f a k e −i p " , REQ_ARG, " 1 . 1 . 1 . 1 " , " Fake−I P " ) ) ; id = getpid ( ) ; f i l e . open ( " R e p o r t . t x t " , i o s : : app ) ; f i l e << "ND\ tNA \ tFD \ tFA " << e n d l ; } latency ::~ latency () { /∗ Destruktor ∗/ f i l e . close ( ) ; } void l a t e n c y : : s e t L o c a l V a l ( ) { i f ( ( c o n t e x t = l i b n e t _ i n i t ( LIBNET_LINK , d e v i c e , e r r b u f ) ) == 0 ) throw L i b n e t E x ( e r r b u f ) ; multimap < s t r i n g , O p t i o n > : : c o n s t _ i t e r a t o r i t e r ; f o r ( i t e r = optmgr −>g e t O p t i o n s ()−> l o w e r _ b o u n d ( name ) ; i t e r ! = optmgr −>g e t O p t i o n s ()−> u p p e r _ b o u n d ( name ) ; + + i t e r ) { i f ( i t e r −>s e c o n d . s o p t == "−c " ) 138 F.3. Plugins l o o p = a t o i ( i t e r −>s e c o n d . a r g u m e n t . c _ s t r ( ) ) ; e l s e i f ( i t e r −>s e c o n d . s o p t == "−s p " ) s r c _ p o r t = s t a t i c _ c a s t < u _ s h o r t > ( a t o i ( i t e r −>s e c o n d . a r g u m e n t . c _ s t r ( ) ) ) ; e l s e i f ( i t e r −>s e c o n d . s o p t == "−dp " ) d s t _ p o r t = s t a t i c _ c a s t < u _ s h o r t > ( a t o i ( i t e r −>s e c o n d . a r g u m e n t . c _ s t r ( ) ) ) ; e l s e i f ( i t e r −>s e c o n d . s o p t == "−p " ) { p a y l o a d = r e i n t e r p r e t _ c a s t < u _ i n t 8 _ t ∗> ( c o n s t _ c a s t < char ∗ >( i t e r −>s e c o n d . a r g u m e n t . c _ s t r ( ) ) ) ; p a y l o a d _ s = i t e r −>s e c o n d . a r g u m e n t . s i z e ( ) ; } e l s e i f ( i t e r −>s e c o n d . s o p t == "−f i p " ) { i f (( ip_fake = libnet_name2addr4 ( context , c o n s t _ c a s t < char ∗ >( i t e r −>s e c o n d . a r g u m e n t . c _ s t r ( ) ) , LIBNET_RESOLVE ) ) == ( u _ i n t 3 2 _ t ) ( − 1 ) ) throw L i b n e t E x ( l i b n e t _ g e t e r r o r ( c o n t e x t ) ) ; } } libnet_destroy ( context ); } v o i d l a t e n c y : : buildICMP ( v o i d ) { f o r ( u n s i g n e d i n t i = 0 ; i < l a t e n c y : : ACOUNT; ++ i ) { / / Libnet I n i t i f ( ! ( i p a c k [ i ] = l i b n e t _ i n i t ( LIBNET_RAW4 , d e v i c e , e r r b u f ) ) ) throw L i b n e t E x ( e r r b u f ) ; / / B u i l d i n g ICMP−Header i f ( l i b n e t _ b u i l d _ i c m p v 4 _ e c h o ( ICMP_ECHO , 0 , 0 , i d , s t a t i c _ c a s t < u _ i n t 1 6 _ t >( i ) , 0 , 0 , i p a c k [ i ] , 0) < 0) throw L i b n e t E x ( e r r b u f ) ; / / B u i l d i n g IP−Header i f ( l i b n e t _ b u i l d _ i p v 4 ( LIBNET_IPV4_H + LIBNET_ICMPV4_ECHO_H + 0 , 0 , i d , 0 , 6 4 , IPPROTO_ICMP , 0 , i p _ s r c , i p _ d s t , 0 , 0 , i p a c k [ i ] , 0 ) < 0 ) throw L i b n e t E x ( l i b n e t _ g e t e r r o r ( i p a c k [ i ] ) ) ; } } void l a t e n c y : : buildTCP ( void ) { i f ( ! ( f l o o d = l i b n e t _ i n i t ( LIBNET_RAW4 , d e v i c e , e r r b u f t c p ) ) ) throw L i b n e t E x ( e r r b u f t c p ) ; i f ( l i b n e t _ b u i l d _ t c p ( s r c _ p o r t , d s t _ p o r t , 0 x01010101 , 0 x02020202 , TH_ACK | TH_PUSH , 3 2 7 6 7 , 0 , 0 , LIBNET_TCP_H + p a y l o a d _ s , p a y l o a d , p a y l o a d _ s , flood , 0) < 0) throw L i b n e t E x ( e r r b u f t c p ) ; i f ( l i b n e t _ b u i l d _ i p v 4 ( LIBNET_IPV4_H + LIBNET_TCP_H + p a y l o a d _ s , 0 , 2 4 2 , 0 , 6 4 , IPPROTO_TCP , 0 , i p _ s r c , i p _ f a k e , NULL, 0 , f l o o d , 0 ) < 0 ) throw L i b n e t E x ( e r r b u f t c p ) ; } unsigned i n t l a t e n c y : : average ( void ) { u n s i g n e d i n t avg = 0 ; int valid = 0 , drops = 0; 139 F.3. Plugins i f ( verbose ) { f o r ( u n s i g n e d i n t i = 0 ; i < l a t e n c y : : ACOUNT; ++ i ) { i f ( t v e [ i ] . t v _ s e c && t v b [ i ] . t v _ s e c ) c o u t << i << " D e l t a : " << 1 0 0 0 0 0 0 ∗ ( t v e [ i ] . t v _ s e c − t v b [ i ] . t v _ s e c ) + ( t v e [ i ] . t v _ u s e c − t v b [ i ] . t v _ u s e c ) << e n d l ; else c o u t << i << " d r o p p e d " << e n d l ; } } f o r ( u n s i g n e d i n t i = 0 ; i < l a t e n c y : : ACOUNT; ++ i ) { i f ( t v e [ i ] . t v _ s e c && t v b [ i ] . t v _ s e c ) { avg += 1 0 0 0 0 0 0 ∗ ( t v e [ i ] . t v _ s e c − t v b [ i ] . t v _ s e c ) + ( tve [ i ] . tv_usec − tvb [ i ] . tv_usec ) ; ++ v a l i d ; } else ++ d r o p s ; } i f ( verbose ) c o u t << " Droped : " << d r o p s << " V a l i d : " << v a l i d << e n d l ; f i l e << d r o p s << " \ t " << avg / v a l i d << " \ t " ; r e t u r n avg / v a l i d ; } double l a t e n c y : : scan ( void ) { i n t examines = 0; setGlobalVal ( ) ; setLocalVal ( ) ; buildICMP ( ) ; buildTCP ( ) ; filter . str ("" ); f i l t e r . clear (); f i l t e r << " ( icmp [ i c m p t y p e ] = icmp−e c h o and " << " s r c h o s t " << l i b n e t _ a d d r 2 n a m e 4 ( i p _ s r c , << " d s t h o s t " << l i b n e t _ a d d r 2 n a m e 4 ( i p _ d s t , << " ) o r ( " ; f i l t e r << " icmp [ i c m p t y p e ] = icmp−e c h o r e p l y and " << " s r c h o s t " << l i b n e t _ a d d r 2 n a m e 4 ( i p _ d s t , << " d s t h o s t " << l i b n e t _ a d d r 2 n a m e 4 ( i p _ s r c , f i l t e r << " and icmp [ 4 : 2 ] = = " << i d ; LIBNET_RESOLVE ) << " and " LIBNET_RESOLVE ) LIBNET_RESOLVE ) << " and " LIBNET_RESOLVE ) << " ) " ; i f ( verbose ) c o u t << " [LATENCY] F i l t e r : " << f i l t e r . s t r ( ) << e n d l ; f o r ( i n t i = 0 ; i < l o o p ; ++ i ) { examines = 0; LatencyCT c a p ( d e v i c e , f i l t e r . s t r ( ) , 1 0 0 0 0 0 0 0 , 2∗ l a t e n c y : : ACOUNT, e x a m i n e s ) ; resetTimer ( ) ; cap . s e t T i m e v a l ( tvb , t v e ) ; I n j e c t i o n T ping ( 2 0 0 ) ; 140 F.3. Plugins f o r ( u n s i g n e d i n t k = 0 ; k < l a t e n c y : : ACOUNT; ++k ) ping . addPacket ( ipack [ k ] ) ; addThread ( cap ) ; addThread ( ping ) ; startThreads (); i f ( verbose ) c o u t << " [LATENCY NORMAL] A v e r a g e : " << a v e r a g e ( ) << e n d l ; examines = 0; I n j e c t i o n T floodT ; i f ( verbose ) c o u t << " [LATENCY] B u i l d i n g Flood−P a c k e t s " << e n d l ; f o r ( u n s i g n e d i n t k = 0 ; k < l a t e n c y : : PACKETS ; ++k ) floodT . addPacket ( flood ) ; i f ( verbose ) c o u t << " [LATENCY] done " << e n d l ; resetTimer ( ) ; addThread ( floodT ) ; addThread ( ping ) ; addThread ( cap ) ; startThreads (); i f ( verbose ) c o u t << " [LATENCY FLOOD] A v e r a g e : " << a v e r a g e ( ) << e n d l ; f i l e << e n d l ; } libnet_destroy ( flood ) ; f o r ( u n s i g n e d i n t k = 0 ; k < l a t e n c y : : ACOUNT; ++k ) libnet_destroy ( ipack [ k ] ) ; return 0 . 0 ; } void l a t e n c y : : r e s e t T i m e r ( void ) { f o r ( u n s i g n e d i n t i = 0 ; i < l a t e n c y : : ACOUNT; ++ i ) { tvb [ i ] . tv_sec = tve [ i ] . tv_sec = 0; tvb [ i ] . tv_usec = tve [ i ] . tv_usec = 0; } } e x t e r n "C" S c a n S t r a t e g y ∗ c r e a t e ( char ∗n , OptionMgr ∗ o p t ) { r e t u r n new l a t e n c y ( n , o p t ) ; } e x t e r n "C" v o i d d e s t r o y ( S c a n S t r a t e g y ∗p ) { delete p ; } 141