28. Dezember 2007

24C3: Port Scanning improved

Category: CCC,Hacking — Christian @ 23:50

Fabs, einer der Mitarbeiter von FXs Firma hat einen neuen Portscanner namens „PortBunny“ entwickelt und vorgestellt. Dabei ist er clever und aggressiv das Problem von Nmap angegangen, bei Rechnern mit nur wenig offenen Ports sehr lange für den Portscan zu brauchen. Einfach nur mehr und schneller Anfragen zu senden ist dabei keine Lösung weil das Netz Pakete verwirft, wenn es überlastet ist.

Die Idee von Fabs ist dabei recht clever. Er streut in den Scanprozess alle paar gesendete Anfragen ein Paket ein von dem er weiß, dass es eine Antwort erzeugt. Das kann z.B. ICMP Echo Request, ein ICMP-Fehler als Antwort auf ein UDP-Paket oder ein TCP-RST sein. Wenn diese Antworten nicht mehr zurückkommen, dann sieht der Portscanner das Netz ist überlastet und sendet seine Anfragen langsamer. Außerdem können die letzten Anfragen neu gesendet werden. Das Verfahren ähnelt in gewisser Weise der TCP Congestion Control.

Mit dieser Technik ist PortBunny in der Lage, das Netz recht effizient auszulasten, insgesamt deutlich besser als Nmap. Allerdings erzeugen die Trigger ca. 10% zusätzlichen Netzwerkverkehr. Source Code wurde keiner veröffentlicht, eventuell passiert das im Januar. Da sich PortBunny direkt im Linux-Kernel befindet (/dev/portbunny), muss, falls es veröffentlicht wird, zumindest das Modul unter der GPL veröffentlicht werden … naja, mal sehen.

Insgesamt hat mich der Vortrag nicht sonderlich beeindruckt. Die Idee mit den Triggern ist zwar ganz clever, aber das hätte man gut auch in Nmap integrieren können (und kommt vermutlich auch irgendwann da rein). Ansonsten ist der Scan lediglich schneller als bei Nmap (im günstigsten Fall so Faktor 2-10). Gegen die großen IPv6-Netze hilft das nur leider auch nicht. Wenn nicht gerade FX für den Vortrag gestanden hätte (um seine Firma zu promoten?) hätte es der Inhalt meiner Meinung nach wohl kaum ins Programm geschafft. Tja, so ist der Stand halt: keine Präsentationsslides, kein Source Code. Enttäuschend.

9 Comments

  1. Du scheinst nicht richtig zugehört zu haben man kontne sich den Source Code einfach abholen nach dem Vortrag.
    Ich hab ihn z.B. bekommen und direkt mit meinem Kollegen analyisert.
    Und wie du richtig gemerkt hast hat FX den Vortrag eingeleitet und erklärt _warum_ man nen neuen portscanner entwickelt hat.Klar man kann wenn man will die Funktion in nmap einbauen aber man wollte halt nicht den fetten scanner sondern nur die funktion ports zu scannen. Wieso den kleinen code in das riesending einfügen wenn man den Rest doch eh nicht brauch?
    Naja is ja auch eh egal wir werden ja sehen wie es sich weiterentwickelt.

    Comment by Ich — 1. Januar 2008 @ 10:21

  2. Klar hat FX erklärt, _warum_ man den Portscanner entwickelt hat, aber nicht, warum sie die Funktion nicht in Nmap eingebaut haben (außer, daß es halt dann Fyodors Scanner ist und nicht als Marketinginstrument für seine Firma taugt). Es ist auch schlicht so, daß die Information „Port ist offen|geschlossen|gefiltert“ meistens nicht ausreicht. Ich will in der Regel zumindest ein brauchbares OS-Fingerprinting dahinter haben und nicht mit zwei oder drei oder vier Portscannern arbeiten. Nur weil Port 135 oder 445 offen ist, weiß ich nicht _welche_ Windows Version dahinter steckt und welche Angriffe relevant sein könnten. Die Funktion mit einer netten kleinen Option, meinetwegen „-sS -FX“ in Nmap und schon hätte man die Optimierung in Nmap gehabt und wer’s braucht kann „-sS -FX -O“ verwenden und hat das OS-Fingerprinting auch gleich mit drin.

    Unter „Veröffentlichen“ verstehe ich auch, daß der Source Code auf ’ner Webseite liegt und nicht selektiv ein paar Leuten rausgegeben wird, die dafür ihre E-Mail-Adresse oder sonstwas hinterlassen müssen. Das gleiche mit den Vortragsslides. Die meisten habe ihre Slides direkt nach dem Vortrag veröffentlicht, einige wenige sogar als PPT. Nur von FX gab es wie üblich nichts.

    Ich bin auch immer noch der Meinung, daß die paar Optimierungen auch keinen Vortrag auf dem CCC rechtfertigen würden, wenn nicht der Name „FX“ dahinter gestanden wäre. Fabs alleine hätte garantiert keinen Vortragsslot bekommen.

    Comment by Christian — 1. Januar 2008 @ 18:51

  3. Das stimmt natürlich nur hast du dir schonmal den nmap code angeguckt?Ich find ihn jedenfalls kaum lesbar ….
    Aber stimmtwohl größtenteils^^

    Comment by Ich — 1. Januar 2008 @ 19:42

  4. Joa, den habe ich mir mal angeschaut. Ist halt C++, ich habe Netzwerkprogrammierung auch noch in C gelernt, da muß ich auch umdenken. Aber ein paar Kommentare (und viele TODOs) sind schon drin. Relevant erscheint mir eh nur die scan_engine.cc und da vor allem die Funktion ultrascan_adjust_timing. Da findet man auch die Kommentare die Fabs angesprochen hat.
    Ein größeres Problem sehe ich darin, Nmap beizubringen die in einen Timeout gelaufenen Probes zu einem späteren Zeitpunkt zu scannen wie Fabs das macht.

    Zum Thema Portscanner im Kernel habe ich auch noch kein abgeschlossenes Meinungsbild. Auf der einen Seite hat Fabs recht, daß man beim Scannen genauere Timings bekommt und der Paketsniffer auch eingebaut ist. Auf der anderen Seite wissen wir wie viele Probleme eine unsaubere Netzwerkimplementierung verursachen kann und da ist mir ein Programmierfehler in einer Anwendung lieber als in einem Kernelmodul. Ich erinnere hier nur mal an die vielen lustigen Ethereal-Exploits, bei denen mittels geschickt erzeugter Pakete ein Overflow im Dissector erzeugt werden kann und man dann den Sniffer übernehmen kann. Von IDS (namentlich BlackICE) kennen wir das ja auch.

    Comment by Christian — 1. Januar 2008 @ 22:42

  5. Hallo,
    die Slides und den Source-code gibt es jetzt unter http://recurity-labs.com/portbunny

    – fabs

    Comment by fabs — 4. Januar 2008 @ 19:33

  6. Das ging jetzt viel schneller als ich das erwartet hatte … mea culpa. Nur die Einverständniserklärung ist juristisch natürlich völlig wertlos (vgl. Disclaimer und der Link zum BKA bekanntlich nicht mehr witzig).

    Ich habe jetzt nur einen kurzen Blick auf den Source Code geworfen, ein paar Kleinigkeiten sind mir aufgefallen:

    Beispiel 1:
    „new_ports = kmalloc(sizeof(int) * new_nports, GFP_KERNEL);
    new_ports[t] = simple_strtoul(cmd->argv[t+2], endp, 10);“
    in cmd_handlers.c. Ich bin mir jetzt nicht sicher, ob int bei Linux auf allen Prozessorarchitekturen immer der Größe von long entspricht. Bei 32/64-Bit CPUs mag das wohl stimmen, bei 16-Bit Embedded CPUs kann das m.E. fehlschlagen.

    Beispiel 2:
    Der Kommentar „Currently the ip-address passed to this handler is not validated. So if somebody enters something other than an ip-address, we’re fucked. This should definately be fixed but this has been delayed.“ im gleichen File ist lustig … wäre mir bei einem Portscanner im User-Mode jetzt egal, im Kernel macht mir das ein wenig Bauchschmerzen. Immerhin, es ist dokumentiert.

    Beispiel 3:
    sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &temp_sock);
    temp_sock->ops->connect(temp_sock, (struct sockaddr *)&whereto, sizeof(struct sockaddr), 0);
    our_ip = inet_sk(temp_sock->sk)->rcv_saddr;
    (Fehlerbehandlung ist gut, hab ich hier gekürzt) dient in „packet_submitter.c“ zur Ermittlung der eigenen IP-Adresse die als Absender-IP verwendet wird. Das nimmt zwar in der Regel die richtige Adresse wenn die Routingtabelle ok ist, mir wäre eine Option zum Setzen der IP-Adresse selbst jedoch lieber.
    Und natürlich ist our_ip als u32 deklariert, IPv6 darf also nicht verwendet werden.

    Beispiel 4:
    Trigger in „trigger_finding_methods.c“, da sind Echo Request/Reply, Timestamp und Address Mask drin, erfahrungsgemäß reicht das auch, entweder die Firewall erlaubt irgendwas davon oder eben nichts. Der Vollständigkeit halber könnte man natürlich auch noch Information Request bzw. Domain Name Request erwarten. Was ich auch Schade finde ist, daß kein Versuch unternommen wird, positive UDP-Replys zu bekommen. Beispielsweise in dem ein echter DNS-Request an Port 53 geschickt wird. Das gäbe sehr verläßliche Trigger auf UDP-Basis (und es gibt viele DNS-Server im Internet zum Scannen). Gleiches auch bei UDP 7, 13, 42 (im LAN), 123, 88 (Win2000 IPSec-Policy!) und 161 (mit Public und Private).

    Comment by Christian — 5. Januar 2008 @ 01:19

  7. Hi Christian,
    Danke fuer die Kommentare.

    Zu 1: richtig, das muss sizeof(long) sein, wird gefixed.

    Zu 2: Habe ich gerade gefixed, danke.

    Zu 3: our_ip als u64 zu deklarieren wuerde da auch nichts dran aendern 😉 Spass bei Seite, das ist richtig, wir sind momentan nur in der Lage IPV4 Netze zu scannen, das ist allerdings nichts, was man mal eben so aendert.

    Zu 4: Ja, es gibt eine Menge anderer Trigger, die man ausprobieren koennte. Wir haben uns fuer die erste Release erstmal auf die einfachsten beschraenkt. Wenn du Spass daran hast, dann schreib doch einfach mal einen neuen Trigger.

    – fabs

    Comment by fabs — 5. Januar 2008 @ 14:40

  8. Nee, our_ip als u64 zu deklarieren würde bei 128 Bit IPv6-Adressen sogar eher schädlich sein. 🙂 Und mir ist klar, daß man das nicht so ganz einfach ändern kann … wäre jedoch interessant zu sehen wie sich der Scanner bei sehr großen Netzen verhält … van Hauser von THC hat ja auf der 22C3 einen interessanten Vortrag zu IPv6 gehalten.

    Trigger-Programmierung … ich glaube es ist etwa 12 Jahre her, daß ich das letze mal so richtig Netwerkprogrammierung gemacht habe und so grob 10 Jahre her, daß ich das letzte mal einen Linux Kerneltreiber geschrieben habe (für eine Notebook-Netzwerkkarte die es längst nicht mehr gibt). Ich weiß gar nicht, was davon noch in meinem Kopf hängengeblieben ist. Na erstmal werde ich noch den restlichen Sourcecode lesen, gestern Abend hatte ich leider nur eine Stunde Zeit.

    Comment by Christian — 5. Januar 2008 @ 15:38

  9. Kommentare gesperrt wegen Spam

    Comment by Christian — 10. März 2009 @ 22:14

RSS feed for comments on this post.

Sorry, the comment form is closed at this time.