Description
Greetings, mere mortal! Are you ready to embark on a journey to unveil the flag and gain the wisdom of the floating Viking head? Harness the power of the oracle’s gaze and use his words to guide you towards victory. (100 points)
Given file: FloatingVikingHead
Writeup
Running file
on our file tells us that it is an unstripped ELF executable. Running it reveals the following:
Cool ASCII art, but this shows me that this challenge is a prime candidate for the use of angr. Anytime where the program hits a failure and success point, angr
could be used to solve for the flag.
Opening Ghidra, and looking inside the main method shows us everything we need: the success address, failure address, and base address. Let me explain.
|
|
success_addr
= line 21, the address of the call to the fwrite
function
fail_addr
= line 18, the address of the call to the fwrite
function
To find an address of a function, simply click on the name of the function and the corresponding assembly code will be revealed
base_addr
= scroll ALL the way up to the beginning of the assembly code in Ghidra (usually it’s 00100000)
flag_len
= this could just be the length of the char array (40), line 6. But, if you really wanna get it fully accurate then open encrypt()
that reveals:
|
|
This is a for loop iterating through the chars of our input with local_10
being i
. local_10 < 0x1b
is i < 27
. So our flag is maximum 27 in length.
Slap all our findings in an angr template or write your own (GIGACHAD move) and run it! (just make sure your binary file is in the same folder as the python file)
import angr
import claripy
base_adr = 0x00100000
success_adr = 0x00101245
fail_adr = 0x0010126f
flag_len = 27 # 40
flag_chars = [claripy.BVS(f"flag_char{i}", 8) for i in range(flag_len)]
flag = claripy.Concat(*flag_chars + [claripy.BVV(b"\n")])
# angr boilerplate
project = angr.Project("./FloatingVikingHead", main_opts={"base_addr": base_adr})
state = project.factory.full_init_state(
args=["./FloatingVikingHead"],
add_options=angr.options.unicorn,
stdin=flag
)
sim_manager = project.factory.simulation_manager(state)
sim_manager.explore(find=success_adr, avoid=fail_adr)
# adding only printable chars
for c in flag_chars:
state.solver.add(c >= ord("!"))
state.solver.add(c <= ord("~"))
# using stdin file descriptor to interact with program
if len(sim_manager.found) > 0:
for found in sim_manager.found:
print(found.posix.dumps(0))
Flag
vikeCTF{n0_57R1n95_F0r_Y0u}
solve.py
Personal note
I am by no means an angr expert, but I got the flag using a typical angr template in 5 mins. Mastering angr could mean you would be solving a LOT of rev challanges with ease and I really wanna work towards that.