Ah, the age old "first program" one typically writes when learning a language and/or toolchain. Fitting that this would be the first reverse engineering task I attempt on Hacker1. We're going to use some tools to help us, namely edb. This tool can, of course, be found as an easily installable package as part of a Kali Linux install.
Let's look around in the binary (after downloading it locally and confirming that is an executable in ELF format. It's good to start at the beginning, but let's start at the beginning of the user code in hopes of saving some time searching around. Where is
After having done so many CTFs for microcorruption, I'm fairly sure what to look for in a challenge of difficulty
Moderate like this one. The program is bound to take some user input, and we'll want to find out where it puts it and what, if any, validation or defensive coding it has to prevent "errors". Looking at the disassembly shows that a memory buffer gets initialized with a fixed size (bad idea) and the user input is not checked for length (terrible idea). This is ripe for either a stack overflow or heap corruption.
Make It Go Boom
Hunting around in the disassembled code doesn't take long since the program is so short and since, well one obvious thing appears to be a reference to the ASCII string
"FLAGS". Even more obvious is the
edb says the function's name is
This code block uses the c stdlib function
getenv to get the value of an environment variable named
"FLAGS" and then attempts to print it out (whether it is found or not). If we manage to jump to that code with our stack overflow, we should be able to get the flag(s). Since we don't have the flags in our local environment, we'll have to trust that the server set the environment variable to the secret value and it will output on the page when exploited.
GETENV(3) Linux Programmer's Manual GETENV(3) NAME getenv, secure_getenv - get an environment variable SYNOPSIS #include <stdlib.h> char *getenv(const char *name); char *secure_getenv(const char *name); Feature Test Macro Requirements for glibc (see feature_test_macros(7)): secure_getenv(): _GNU_SOURCE DESCRIPTION The getenv() function searches the environment list to find the envi‐ ronment variable name, and returns a pointer to the corresponding value string.
OK, 40 bytes after the start of the user controllable memory is a return address. Let's just write a bunch of stuff until we get there and then write the address we want to jump to upon return,
0x004006ee1. Hmm, more segmentation faults. Aha! The addresses are 8 bytes and the upper 4 bytes of the address in the stack are not what we want, so we need to null those out.
A Couple Last Notes
%xx in the url? Remember we want to be able to write any bytes we want, and only inputting ASCII characters is going to restrict what values we can reasonably input. Rather than using the form input, I just use the URL since it was a GET anyways. You could also use
cURL or similar.
Why is the input that matters
"%ee%06%40%00 when we want to jump to address
0x004006ee? Because the target machine must be little endian so we have to input the bytes, which are written to memory in increasing order, in little endian order.
- Another thing that makes this challenge so easy it the fact that we don't have to worry about
NULLbytes in the input. This is because the code (on purpose, I'm sure) uses a custom function
read_all_stdininstead of something like
sprintfthat would terminate input upon encountering a value of