Page cover

ARKAVIDIA Quals

circle-info

Team: DitmawaITS, jadi reimburse biaya transport dan akomodasi lomba kah? :Clueless:

Rank: 3rd / 151

Challenge
Category
Points
Solves

WWW 0

Binary Exploitation

996 pts

3

WWW 0

Description

Namanya bukan "WWW 3" karena takutnya koch zafir udah bikin :D

Author: msfir

nc 20.195.43.216 8002

Analysis

we're given an elf binary with protection as follows

thankfully we're also given the source code and it's quite small

in the dockerfile we can see that the challenge is hosted in alpine

upon further inspection it was then revealed that alpine uses musl for its libraries instead of the usual glibc which will affect the behaviour of our exploitation later on.

additionally, in the middle of the competition the author thankfully provided us with the debug library since the one within the docker doesn't contain debug symbol.

Exploitation

No Positional Argument Format String

while POSIX specifies that positional parameters (like %1$p) should be supported, musl deliberately does not implement them.

and after spamming as many %p as I can into a 32 bytes buffer, nothing came out was from the lib's memory addresses. So the easiest way is to leak using the %s and inserting one of the GOT's entry address into the stack as it guaranteed to contain one of the function address from the lib's memory region.

also good thing to note is that it seems the binary only loads the linker which acts both as the linker and the standard library (I think...) that implements most of the IO and other functions.

musl code execution after exit via FSOP

after some googling and reading, I found a similar FSOP technique to gain execution after exit.

from the above blog quote:

However, I offer another solution here: we can use FSOP in musl. The FILE struct in musl is similar to that in glibc. The difference is that musl does not use vtable, it keeps the pointers in the data structure. What we can do is to use the arbitrary allocation to overwrite its write pointer with system and replace its flag with E;sh;\x00. When puts is called, the write function will be called with its flag as the first argument. After the overwite, it becomes system("E;sh;\x00") and gives us a shell. (“E;” is here because the original flag is 0x45(“E”), I want to preserve the flag)

further googling leads me to this blog that details about the FSOP techniques in gaining code execution.

if you're familiar with glibc's FSOP, this one is simpler and have less security checks on them.

first is the FILE structure, in musl they don't have a vtable rather the methods are directly within the structure itself as we can see in the definition below

on exit the, it will perform some cleanup on these files

so depending on the checks it will either calls write or seek

to gain shell we need to write /bin/sh to the start of the structure and overwrite one of the method then trigger said method.

which the current challenge present its problem, as it either requires a huge write buffer or multiple writes in order to be successfully executed.

Failed attempts to hijack functions from existing files

if you notice from the source code, it continuously flushes stdout which will empties both of rpos and rend.

this means seek can only be triggered if we corrupt stdin and not the others.

meanwhile, write will not be able to be triggered at all as wpos and wbase are also null when examined at exit

so we can only overwrites the stdin's seek to control execution flow. I then think we're able to gain multiple writes if we're able to go back to main multiple times.

However this deemed to be fruitless as when we exit the first time, the main thread gets locked from the call to __libc_exit_fini(); and was never released. as the program exit for the second time, it will be a deadlock and will hang indefinitely.

so since we're able to control execution flow, I thought of using one_gadget, however the tool fails to run on the library, I then tried every offset within execvpe and system addresses but nothing seems to work.

Flashback to Cyber Jawara Qualifier

another national competition named Cyber Jawara held its qualifier back in January, there zafirr also created a WWW challenge which is similar in concept to this. both uses scanf to take inputs and flushes stdout but not stdin

the current author (msfir) solves that challenge by creating a fake file within the stdin's buffer in the heap and then uses the 8 write bytes to link the file such that when exit is called, the cleanup function will traverse all of the files and this includes the fake file which fully customised to gain shell.

in this challenge the same concept is applied, just with musl instead.

FSOP code execution by linking fake file in musl

in glibc's implementation, all opened files are linked in a global head variable. in musl's implementation standard's IO are stored in global variable and not linked to subsequent opened files.

to examine the global head variable which contains linked files we need to examine the return value of __ofl_lock()

as can be seen, the head contains null pointer as the program doesn't load any of the or open any files. we can then write to this address of where our fake file will be located.

as for our fake file, it will be located within the stdin's buffer and is pointed by rpos and rend.

further examining the code execution we can confirm that it will call close_file with the crafted fake file as its argument and subsequently will call write that has been substituted with system.

here's the exploit being ran againts the remote server

here's the full exploit script:

circle-check

Last updated