Hello World!
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.
Flag 0
The page presented is simple enough. A link labeled "Download Binary" and a single entry form to submit.
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 main
? Aha
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
Well, since the stack appears to be so easily overwritten, let's go ahead and crash the thing. Yep, boom! š„
What comes after the user input in the stack? Ah, that looks interesting, there is a return address of course. So can we write something to that memory and jump elsewhere in the code upon return?
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 print_flags
.
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.
The Payload
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, 0x004006ee
1. 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.
http://35.190.155.168/{ctf}/?stdin=%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%ee%06%40%00%00%00%00%00
Flag captured!
A Couple Last Notes
Why the %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
NULL
bytes in the input. This is because the code (on purpose, I'm sure) uses a custom functionread_all_stdin
instead of something likegets
orsprintf
that would terminate input upon encountering a value ofNULL (0x00)
↩