vuln-storage (499 pts)

A Heap exploitation challenge.

We were given a target binary which:

  • Has all protections enabled(NX/Canary/Full RELRO/PIE)
  • Perform size checks that prevents you from OOB-write (except for a small off-by-one bug when copying a nullbyte terminator of a string on the heap)
  • UAF mitigations / no dangling pointers to free’d chunks.

Useful reading

ptmalloc/glibc allocator pwnables are kinda new to me. I thought it’d be useful to share the stuff I found while trying to solve this challenge as this can be useful in order to understand the logic behind the technique implemented in the solve.py file:

This one was my favorite chall in the CTF since I don’t have much experience with ptmalloc and it was a good opportunity to gain some hands-on skills :^)

Note: in the solve.py file, the D chunk is represented as the hax variable. But for simplicity, we will call it D here.

I also added comments so it will be easier to follow.

Solution

./solve.py:

  • We allocate 3 chunks: A(0x70), B(0x210) and C(0x100). Then, we free B.

  • The off-by-one bug gives us the abillity to overflow past A in memory and land a nullbyte, which will corrupt the size field of a free chunk(B) on the heap.

    • We abuse the overflow to shrink a free chunk(from 0x210 to 0x200), followed by multiple smaller allocations(B1, B2) which will occupy part of the corrupted free’d chunk space(B).
  • Then, we free B1, A and C.

    • ptmalloc never updated C’s prev_size, this will trigger backward consolidation between A, B(with the original size 0x210) and C.
  • After having a successful consolidation between the chunks: we allocate one big chunk with the size of A+B+C(we will call it D) which ends up overlapping B2. At this point we yield a UAF(user-after-free) every time we edit/view chunk D due to the overlap.

    Now, we are able to leak libc addresses because B1(which we previously free’d) belongs to the unsorted bin. And this bin, free chunks on the heap holds fd/bk pointers to main_arena+216(which, resides in the libc address space).

  • Using the leak in the D chunk, we are able to calc the address of system/'/bin/sh' string and overcome ASLR.

  • Then, we create a ‘fastbin-dup’ primitive by:

    • freeing the inner/smaller chunk(B2)
    • We corrupt the 0x70 freelist by editing the overlapping ‘parent’/bigger chunk(D).
  • By poisoning the freelist with a forged pointer of our choice, we make malloc return any address we want in the next allocations, hence, achieving a write-what-where abillity. We’ll choose to write to __malloc_hook.

    • We replace the value in __malloc_hook@libc with the address system@libc
  • finally, pop a shell by giving the binary a command to allocate a new chunk with a size argument that points to a /bin/sh string.

Combining everything together:

solve.gif

flag:

TamilCTF{Th3_1n7en7eD_S0lu7i0N_W4S_70_Cr347e_0v3rl4PP1Ng_ChuNkS_bY_h0uSe_0f_3iNh3rj4r_M37h0d_0R_by_P0is0N_NuLL_By73S_4nD_7urN_7h47_70_F4S7BiN_DuP_70_C0D3_3x3cuTi0N}

thanks for the challenge :D

stress-rope (341pts)

Classic SROP challenge (Sigreturn Oriented Programming).

Obstacles: the binary is very small, and it does not include libc / other useful libraries to jump to.

./solve.py:

  • first, we adjust the rax register to be SYS_sigreturn by sending 0xf bytes to the program’s read()
  • overflowing into the stack return address in order to jump to a syscall gadget
  • crafting a sigreturn frame, which will trigger another jump to the syscall gadget
  • on the 2nd syscall, we call mprotect to modify the permissions of the .text segment to rwx
  • then, we jump back to main to create another overflow:
    • we overflow with our shellcode
    • change the return address to be where the shellcode is placed.

nameserver (214pts)

Obstacles: libc is randomized, the binary gets an input once & exit immediately(in other words, you have one shot).

./solve.py: This one was a straight-forward OOB write on the stack. We were required to construct a ROP chain to leak libc address, followed by another ROP to create a ret2libc attack.