b t r o m b y r i q ------------------------------------------------------------------------------ "trojan eraser or i want my system call table clean" ------------------------------------------------------------------------------ i n t r o d u c t i o n ------------------------------------------------------------------------------ The other day, I started to play with the itf that appeared in P52-18 (read that article if you want to know what it does, etc). It occured to me one good way to determine if someone has installed the trojan (and to subsequently remove it) is by fixing the system call table. This program tries to do that. This works with the the linux x86 2.0 and 2.2 series. ------------------------------------------------------------------------------ i n t e r n a l s ------------------------------------------------------------------------------ The program first attempts to detect if you are using a BIG_KERNEL (a bzImage) or not (a zImage). One of the differences is the address of the kernel in memory. BIG_KERNEL starts at 0xc0000000 while the other starts at 0x00100000. The system call table (sct) has the entries of all the system calls. If you modify the sct, the new entry must be `out of range'. btrom will try to fix these `out of range' system calls with their original values. They are taken from the System.map. What i mean with "`out of range'" is an entry that has a value out of the start_of_the_kernel and the_start_of_the_kernel + some_value. This value is in the config.h ------------------------------------------------------------------------------ q u i c k i n s t a l l ------------------------------------------------------------------------------ compile: -------- 1) edit config.h and Makefile. Modify it if you want. $ vi config.h $ vi Makefile 2) make $ make use: ---- 1) be root $ su - 2) install the module mbtrom # insmod mbtrom 3) run btrom # ./btrom _nr_mbtrom_ [options] 4) uninstall the module mbtrom # rmmod mbtrom ------------------------------------------------------------------------------ c h a c h a r a ------------------------------------------------------------------------------ 1st part: detect trojans legends [ ] this is ok. dont worry [N] this is a null enter in the system call table. dont worry. [-] this is the entry of the module mbtrom. dont worry. [?] this entry has a system function, but it was supposed to be null. worry [*] this is probably a trojan in a reserved space. worry. [!] this is probably a trojan in a not reserved space. worry. 2nd part: clean trojans legends press 's' to fill this entry with the System.map's value. press 'c' to clean this entry. it will be filled with a null entry. press 'm' to put in this entry a manual hexa address. press 'i' to ignore, skip, what you want. ------------------------------------------------------------------------------ n o t e s ------------------------------------------------------------------------------ this program doesnt uninstall trojan modules. this program disables the trojans, so, after that, you can uninstall the trojan with 'rmmod'. ------------------------------------------------------------------------------ b u g s ------------------------------------------------------------------------------ if `insmod mbtrom' doesnt returns any value, is because you are redirecting that message with syslogd. Please check /etc/syslog.conf and see "kern". ------------------------------------------------------------------------------ h i s t o r y ------------------------------------------------------------------------------ * version 0.3 (01/12/98) compatible with kernel 2.0 y 2.2. works with BIG_KERNEL and with SMALL english version * version 0.2 (25/11/98) first version * version 0.1 (21/11/98) something really ugly * all this happened when i see the itf (intregated trojan facility in P52-18) ------------------------------------------------------------------------------ f e e d b a c k ------------------------------------------------------------------------------ riq@ciudad.com.ar <++> linenoise/btrom/Makefile # # Makefile del b t r o m # ## BUG. This must be the same as the one in config.h SYSTEM_MAP = "/usr/src/linux/System.map" AWK = awk CC = gcc #CFLAGS = -DSYSTEM_MAP=$(SYSTEM_MAP) all: parse btrom mbtrom parse: $(AWK) -f sys_null.awk $(SYSTEM_MAP) > sys_null.h btrom: btrom.o $(CC) btrom.c -O2 -Wall -o btrom mbtrom: $(CC) -c -O3 -Wall -fomit-frame-pointer mbtrom.c clean: rm -f mbtrom.o btrom.o btrom sys_null.h <--> <++> linenoise/btrom/btrom.c /* * btrom - Borra Trojanos Modulo * por Riq * 1/Dic/98: 0.3 - Compatible con kernel 2.2 y soporta BIG_KERNEL * 25/Nov/98: 0.2 - Version inicial. Soporta kervel 2.0 i386 */ #include #include #include #include #include #include #include #include #include "config.h" #include "sys_null.h" FILE *sm; FILE *au; int quiet; int borrar; int dif_n_s; unsigned int big_kernel; /*********************************************************************** System.map ************************************************************************/ int sm_b_x_nom( unsigned int *address, char *estoy ) { char buffer[200]; char sys_add[20]; fseek(sm,0L,SEEK_SET); while( fgets(buffer,200,sm) ) { if( fnmatch(estoy,buffer,0)==0 ) { strncpy(sys_add,buffer,8); sys_add[8]=0; *address = strtoul(sys_add,(char **)NULL,16); return 1; } } return 0; } int sm_busca_x_nombre( unsigned int *address, char *estoy) { char nombre[50]; sprintf(nombre,"*T sys_%s\n",estoy); return sm_b_x_nom(address, nombre); } FILE* sm_open() { return fopen( SYSTEM_MAP, "r" ); } /*********************************************************************** asm/unistd.h ************************************************************************/ void au_dame_el_nombre( char *dst, char *orig ) { int i,j; j=i=0; while( orig[i]!='_' ) i++; i=i+5; while( orig[i]!=' ' && orig[i]!='\t' ) dst[j++]=orig[i++]; dst[j]=0; } int au_b_x_num( char *nombre, int numero ) { char buffer[200]; char buscar[50]; /* FIXME: ?sera mas efectivo regexec() que fnmatch()? */ sprintf(buscar,AU_PREFIX"%i*",numero); while( fgets(buffer,200,au) ) { if( fnmatch(buscar,buffer,0)==0 ) { au_dame_el_nombre(nombre,buffer); return 1; } } /* No encontre... entonces una segunda pasada */ fseek(au,0L,SEEK_SET); while( fgets(buffer,200,au) ) { if( fnmatch(buscar,buffer,0)==0 ) { au_dame_el_nombre(nombre,buffer); return 1; } } return 0; } int au_busca_x_numero(char *nombre, int numero) { return au_b_x_num(nombre,numero); } FILE* au_open() { return fopen( ASM_UNISTD, "r" ); } /*****************************************/ /* Comun a la primer y segunda recorrida */ /*****************************************/ int comun_1er_2da( int j, int i , char *nombre , char *c, int clean, unsigned int retval) { int a; a = clean; /* bug fix */ nombre[0]=0; /* i!=0 porque el asm/unistd del kernel 2.2 no viene */ if( i!=0 && au && au_busca_x_numero(nombre,i)) { if( retval > big_kernel + LIMITE_SYSCALL ) { *c = '*' ; clean++; } else *c = ' '; } else { if( retval > big_kernel+LIMITE_SYSCALL ) *c = '!'; else *c = '?'; clean++; } if(i==j) { /* modulo btrom */ *c='-'; clean=a; } else if(retval==SYS_NULL || retval==0) {/* Null pointer */ *c='N'; clean=a; } return clean; } /********************************************************************** primer_recorrida: Detectar troyanos **********************************************************************/ int primer_recorrida(int j) { char nombre[50]; int address; int i,old_clean,clean; unsigned int retval; char c; old_clean=clean=0; printf( "\n1st part: Detect trojans\n" " [ ]=OK [N]=Null [-]=btrom\n" " [?] Mmm...syscall\n" " Address [*][!]=trojan routine\n" " now System.map Num [ ] Syscall Name\n" "----------------------------------------------\n"); for( i=0; i< NR_syscalls; i++ ){ __asm__ volatile ( "int $0x80":"=a" (retval):"0"(j), "b"((long) (i)), "c"((long) (0)), "d"((long) (0))); clean = comun_1er_2da(j,i,nombre,&c,clean,retval); if( !quiet || clean > old_clean ) { if( nombre[0]!=0 ) { if( sm && sm_busca_x_nombre(&address,nombre)) { if(retval!=address && retval < big_kernel + LIMITE_SYSCALL) { dif_n_s++; printf("%8x!%8x %3i [%c] %s\n",retval,address,i,c,nombre); } else printf("%8x %8x %3i [%c] %s\n",retval,address,i,c,nombre); } else printf("%8x %3i [%c] %s\n",retval,i,c,nombre); } else printf("%8x %3i [%c]\n",retval,i,c); old_clean = clean; } } return clean; } /********************************************************************** segunda_recorrida: Limpiar troyanos **********************************************************************/ int segunda_recorrida(int j) { char nombre[50],dire[50]; int address; int i,old_clean,clean,retval,key; char c; unsigned int k; old_clean=clean=0; printf( "\n2nd part: Clean Trojans\n" " s = System.map address\n" " c = clean address\n" " m = manual address\n" " i = ignore\n" " now System.map Num [ ] Syscall Name\n" "---------------------------------------\n"); for( i=0; i< NR_syscalls ; i++ ){ __asm__ volatile ( "int $0x80":"=a" (retval):"0"(j), "b"((long) (i)), "c"((long) (0)), "d"((long) (0))); clean = comun_1er_2da(j,i,nombre,&c,clean,retval); if( clean > old_clean ) { if( nombre[0]!=0 ) { if( sm && sm_busca_x_nombre(&address,nombre)) { if(retval!=address && retval < big_kernel + LIMITE_SYSCALL) { dif_n_s++; printf("%8x!%8x %3i [%c] %s ?",retval,address,i,c,nombre); } else printf("%8x %8x %3i [%c] %s ?",retval,address,i,c,nombre); } else printf("%8x %3i [%c] %s ?",retval,i,c,nombre); } else printf("%8x %3i [%c] ?",retval,i,c); old_clean = clean; fseek(stdin,0L,SEEK_END); key=fgetc(stdin); switch(key) { case 's': k = address; break; case 'c': k = SYS_NULL; break; case 'm': printf("Enter an hexa address (ex: 001a1b):"); fseek(stdin,0L,SEEK_END); fgets( dire,50,stdin ); k = strtoul(dire,(char **)NULL,16); break; default: k=1; break; } /* FIXME: 1 no se puede poner como address */ if(k!=1) __asm__ volatile ( "int $0x80":"=a" (retval):"0"(j), "b"((long) (i)), "c"((long) (1)), "d"((long) (k))); } } return clean; } void help() { printf( "\nUsage: btrom nr_of_mbtrom [-c][-v]\n" "\t1) Install the module mbtrom with`insmod mbtrom'\n" "\t2) The module must return a value.If not see the README->bugs\n" "\t btrom value_returned_by_mbtrom [-c][-v]\n" "\t `v' is verbose. Recommended\n" "\t `c' is clean. Cleans the trojans\n" "\t3) Uninstall the module mbtrom with 'rmmod mbtrom'\n" "\n" "\tExamples:\n" "\t btrom 215 -cv\n" "\t btrom 214 -v\n" "\t btrom 215\n" "\nWarning: Dont put random numbers. Be careful with that!" "\nRecommended: Do `btrom _number_ -v' before a cleaning\n\n" ); exit(-1); } void chequear_argumentos( char *parametros ) { int i,j; i=strlen(parametros); if(parametros[0]!='-') help(); for(j=1;j3 ) help(); quiet = 1; borrar = 0 ; if( argc==3) chequear_argumentos(argv[2]); au = au_open(); sm = sm_open(); if(!au && !quiet) printf("Error while opening `asm/unistd.h' in `"ASM_UNISTD"'\n"); if(!sm && !quiet) printf("Error while opening `System.map' in `"SYSTEM_MAP"'\n"); dif_n_s=0; /* __NR_mbtrom number */ i = atoi( argv[1] ); if(!i) help(); /* Chequeo si es BIG_KERNEL o no */ __asm__ volatile ( "int $0x80":"=a" (retval):"0"(i), "b"((long) (0)), "c"((long) (2)), "d"((long) (0))); big_kernel =(retval>BIG_KERNEL?BIG_KERNEL:SMALL_KERNEL); /* Primer recorrida */ clean = primer_recorrida( i ); /* Mensaje del senior btrom */ printf( "\nb t r o m s a y s:\n"); if(dif_n_s>0) { printf( "Your System.map seems to have a problem.\n"); if(dif_n_s <++> linenoise/btrom/config.h /* config.h usado por btrom.c y mbtrom.c */ /* Modificar segun los gustos */ /* Numero que uno supone que esta vacio en la sys_call_table */ #define NUMERO_VACIO 215 /* Path al archivo System.map */ /* Si Ud. nunca compilo el kernel tal vez sea /boot/System.map */ /* FIXME: Usar el define del Makefile para no definir esto en 2 partes */ #ifndef SYSTEM_MAP #define SYSTEM_MAP "/usr/src/linux/System.map" #endif /* Hay problemas con old y new. Gralmente no es problema de la System.map */ #define SYSMAP_LIMIT 8 /* Path al archivo asm/unistd.h */ #define ASM_UNISTD "/usr/include/asm/unistd.h" /* Prefijo a buscar en asm/unistd.h*/ #define AU_PREFIX "#define*__NR_*" /* Hasta donde llega el kernel space */ /* FIXME: No se cual es el limite realmente. Igual con esto anda :-) */ #define LIMITE_SYSCALL 0x00300000 /* No modificar */ /* Version del btrom */ #define VERSION "0.3" /* BIG_KERNEL y SMALL_KERNEL*/ #define BIG_KERNEL 0xc0000000 #define SMALL_KERNEL 0x00100000 <--> <++> linenoise/btrom/mbtrom.c /* * modulo del btrom - Borra Trojanos Modulo * 25/11/98 - por Riq * * compile with: * gcc -c -O3 -fomit-frame-pointer mbtrom.c * */ #define MODULE #define __KERNEL__ #include #ifdef MODULE #include #include #else #define MOD_INC_USE_COUNT #define MOD_DEC_USE_COUNT #endif #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "sys_null.h" extern void *sys_call_table[]; int __NR_mbtrom; int* funcion( int numero, int modo, unsigned int *address ) { switch(modo){ case 0: return sys_call_table[numero]; break; case 2: return (void *)&sys_call_table; case 1: default: sys_call_table[numero]=address; break; } return (void *)0; } int init_module(void) { __NR_mbtrom = NUMERO_VACIO ; /* Chequea direccion vacia desde NUMERO_VACIO hasta 0 */ while ( __NR_mbtrom!= 0 && sys_call_table[__NR_mbtrom] != 0 && sys_call_table[__NR_mbtrom] != (void *)SYS_NULL ) __NR_mbtrom--; if(!__NR_mbtrom ) { /* Si es 0 me voy */ printk("mbtrom: Oh no\n"); return 1; } sys_call_table[__NR_mbtrom] = (void *) funcion; if( __NR_mbtrom != NUMERO_VACIO ) printk("mbtrom: Mmm...\n"); printk("mbtrom: -> %i <-\n",__NR_mbtrom); return 0; } void cleanup_module(void) { sys_call_table[__NR_mbtrom] = 0; printk("mbtrom: Bye.\n"); } <--> <++> linenoise/btrom/sys_null.awk /sys_ni_syscall/ { print "#define SYS_NULL 0x"$1 } <-->