pwnable.kr fd Write-up
For those keen to enhance their cybersecurity skills, participating in Capture the Flag (CTF) challenges is an excellent approach. These challenges, especially the pwn (pronounced “pone”) category, often contain binary exploitation challenges. Binary exploitation refers to the process of exploiting runnable programs. Starting your journey without any knowledge can be overwhelming. That is why it can be beneficial to start small and try doing some beginner-friendly pwn challenges.
Introducing pwnable.kr for beginners
An excellent platform to start your pwn journey is pwnable.kr. The platform offers beginner-friendly pwn challenges, acting as a solid stepping stone before diving into more advanced CTF challenges.
This write-up will help you solve the pwnable.kr fd challenge.
Reading the ‘pwnable.kr fd’ CTF source code
Let’s start with your first challenge to give you an idea of pwning. Start by logging into the server:
ssh [email protected] -p2222
When prompted for a password, enter ‘guest‘.
Once logged in, you can start by checking the files and directories in the current directory. List the available files using
ls -l
You will see three different files.
-r-sr-x--- 1 fd_pwn fd 7322 Jun 11 2014 fd
-rw-r--r-- 1 root root 418 Jun 11 2014 fd.c
-r--r----- 1 fd_pwn root 50 Jun 11 2014 flag
Notice that the flag file can be read exclusively by users fd_pwn and root. Before a binary is compiled, it consists of source code. This specific piece of code is written in the programming language: C
. Since, we are the fd user, we are only able to execute the fd binary and read the content of its pre-compiled form: fd.c.
cat fd.c
You can read its content below:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char buf[32];
int main(int argc, char* argv[], char* envp[]){
if(argc<2){
printf("pass argv[1] a number\n");
return 0;
}
int fd = atoi( argv[1] ) - 0x1234;
int len = 0;
len = read(fd, buf, 32);
if(!strcmp("LETMEWIN\n", buf)){
printf("good job :)\n");
system("/bin/cat flag");
exit(0);
}
printf("learn about Linux file IO\n");
return 0;
}
Some points to note here:
- The user needs to input a number. Hence, this binary can only be run when a user runs the command with a parameter after the binary. E.g.: ./fd 1337
- The read command in C contains three parameters. The first one is the file descriptor (fd). In a Unix-based environment, you can have an input, output, and error stream. The values for this file descriptors are 0 for standard input. 1 for standard output. 2 for standard error. For example, if you run the find command to find a file or directory on the system, you will often see the following notation: find -type f -name flag 2>/dev/null. 2>/dev/null thus means to write the errors to /dev/null. In other words, to dispose of them.
- If the user inputs LETMEWIN, the system will return the flag.
Solving the ‘pwnable.kr fd’ CTF
In order to capture the flag, the user has to get some control over the input. This is possible when the fd variable is equal to 0. The prefix 0x is used in code to indicate that the number is being written in hex. So, the user has to provide the decimal value of HEX value 0x1234 to be able to send some input to the binary. The following command can calculate the decimal value:
echo $((16#1234))
This will return the value 4660. Now, to capture the flag, run the following command:
./fd 4660
Now provide the following:
LETMEWIN
If done correctly, the system will congratulate with:
good job :)
<YOUR_FLAG_HERE>
Congratulations! You’ve successfully solved your first pwn challenge. This challenge provided insights into the UNIX file descriptor, particularly the value associated with the standard input.