Stack overflow is a common attack in programming world.
To understand how it could be done we should be aware about the function's stack and how the function is being executed and how it passes the execution of the code in the parent function after its call.
The stack of the function, at least in *nix, should look like
|function parameters| <--top of the stack(higher memory addresses) |---return point---| <--%esp |--local variables--| |-------------------| <--bottom of the stack(lower memory addresses)Let's examine simple program written in asm. It has a function pc that puts giver character onto stdout and adds '\n'. In main this function is called with argument which value is '*'.
1 .text 2 3 pc: 4 pushl %ebp 5 movl %esp, %ebp 6 7 subl $4, %esp /*4 bytes for local variables*/ 8 9 pushl 8(%ebp)/*get value of the function parameter*/ 10 call putchar 11 pushl $0x0a /*new line*/ 12 call putchar 13 addl $8, %esp/*allign stack*/ 14 15 movl %ebp, %esp 16 popl %ebp 17 ret 18 19 20 .global main 21 22 main: 23 pushl $0x0000002a /*character '*'*/ 24 call pc 25 addl $4, %esp/*allign stack*/ 26 27 movl $1, %eax 28 movl $0, %ebx 29 int $0x80/*exit(0)*/I set a breakpoint on line 4 in gdb and got the information about the registers
(gdb) i r eax 0xbfae0a34 -1079113164 ecx 0x312f6668 825189992 edx 0x1 1 ebx 0xb7fa4ff4 -1208332300 esp 0xbfae09a4 0xbfae09a4 ebp 0xbfae0a08 0xbfae0a08 esi 0xb7fe2ca0 -1208079200 edi 0x0 0 eip 0x8048384 0x8048384 <pc>Address of %esp is 0xbfae09a4, so here is the top of the stack of our function pc.
In *nix world stack of the process grows from the higher memory addresses to the lower ones. So to get function parameter we should add 4 bytes to %esp(the size of return point is 4 bytes)[Note, on line 9 I pushed the address of %ebp + 8 because after 'pushl %ebp' value of %esp increased with 4 bytes.]
(gdb) x/c 0xbfae09a4 + 4 0xbfae09a8: 42 '*'Yes, here we have '*' _because_ we indeed pushed it onto the stack on line 23. In %esp we can find the address of the return point
(gdb) x/x 0xbfae09a4 0xbfae09a4: 0x080483a70x080483a7 is the address of the next instruction after the call of pc in main. Let's check.
Going through instruction in gdb I got out from pc
(gdb) n pc () at fcall.s:17 17 ret (gdb) n main () at fcall.s:25 25 addl $4, %esp/*allign stack*/ (gdb) i r eax 0xa 10 ecx 0xffffffff -1 edx 0xb7fa60b0 -1208328016 ebx 0xb7fa4ff4 -1208332300 esp 0xbfae09a8 0xbfae09a8 ebp 0xbfae0a08 0xbfae0a08 esi 0xb7fe2ca0 -1208079200 edi 0x0 0 eip 0x80483a7 0x80483a7 <main+7>You can see that value of %eip is 0x80483a7, so we were right. To make a program run any other code rather than return to the parent function the address of the return point has to be overwritten.
The following code attempts to do so.
It has function evil which address will be written to the return point of the function pc. Function evil writes '%\n' on the output and calls exit syscall with exit code 1.
1 .text 2 3 evil: 4 pushl %ebp 5 movl %esp, %ebp 6 7 pushl $0x00000025 /*character '%'*/ 8 call putchar 9 pushl $0x0a /*new line*/ 10 call putchar 11 12 movl $1, %eax 13 movl $1, %ebx 14 int $0x80/*exit(1)*/ 15 16 pc: 17 pushl %ebp 18 movl %esp, %ebp 19 20 subl $4, %esp /*4 bytes for local variables*/ 21 22 pushl 8(%ebp) 23 call putchar 24 pushl $0x0a /*new line*/ 25 call putchar 26 addl $8, %esp/*allign stack*/ 27 28 movl %ebp, %esp 29 popl %ebp 30 31 movl $evil, (%esp) 32 33 ret 34 35 36 .global main 37 38 main: 39 pushl $0x0000002a /*character '*'*/ 40 call pc 41 addl $4, %esp/*allign stack*/ 42 43 movl $1, %eax 44 movl $0, %ebx 45 int $0x80/*exit(0)*/The result of the exucution of this program should be
$gcc fcall.s -o fcall -g $./fcall * % $echo $? 1
2 comments:
Thanks a lot! It helped me a lot to understand more asm.
Hello, Ubay.
I'm glad that you liked this article.
Thank you!
Post a Comment