One of my objective in 2020 is to level up in Reverse Engineering. Since I am starting from zero I got few people recommend http://pwnable.kr which appear to have a reasonable curve of difficulty making it ideal for learning.
If you have other recommandations for good ressources to learn and practices Reverse Engineering feels free to let me know below in a comment or contact me ;)
That being said, here is my write-up for the first challenge of pwnable.kr: FD.
Mommy! what is a file descriptor in Linux?
ssh [email protected] -p2222 (pw:guest)
This gives us an SSH access to a box with a hint that this challenge is going to be about File Descriptor
In Unix a file descriptor is abstract indicator (handle) used to access a file or other input/output resource. A file descriptor is a non-negative integer, generally represented in the C programming language as the type int.
You are surely familiar with the three most common file descriptor:
- 0 - stdin (Standard Input)
- 1 - stdout (Standard Output)
- 2 - stderr (Standard Error)
But file descriptor goes farther than that. To make it simple, file descriptor are used when you open a file.
When you do so, the OS will store the information about this file in a table entry. Theses table entries are represented with integers. The entry number is the file descriptor.
The first thing we notice when connecting to the box is that code source of the challenge is available:
[[email protected] ~]$ ssh [email protected] -p2222
Let’s a take a look to understand what it’s doing:
Let’s break things down. The first information we get is that the app need an extra arguments in a form of a number:
With the name of the challenge we can guess that is number will probably be a file descriptor.
Next we -almost- have a confirmation of this theory.
4660) gets subtracted to integer we passed as argument to get the actual file descriptor:
int fd = atoi( argv ) - 0x1234;
Note: Here is a quick way to convert hexadecimal to decimal:
read function is used to, well, read the file pointed by the file descriptor and store the content in the
len = read(fd, buf, 32);
buf variable gets check to see if it contains the string
If it does, then the program print out the flag:
But you might wonder own the binary get print the flag since it’s owned by
root ? It’s because the binary have the SUID bit set:
[email protected]:~$ ls -l fd
As a reminder:
setuidis is a Unix access rights flag that allow users to run an executable with the permissions of the executable’s owner. They are often used to allow users to run programs with temporarily elevated privileges in order to perform a specific task.
Thanks to this bit, the
fd binary will run as with
root privileges and will be allow to access the flag file.
Alright I think we now have all the needed informations to get the flag right ? To summarize:
- Create a file containing
- Get the file descriptor of this file
4660from this file descriptor
- Use this result as a command line argument:
Doesn’t look that scary. Let’s put it in practice now :)
First, we create our file. Let’s use
printf to make sure the newline gets included:
[email protected]:~$ printf "LETMEWIN\n" > /tmp/.hg8
Then we need to assign a file descriptor to our newly created file. It’s possible to do so using
exec X < filename:
[email protected]:~$ exec 10</tmp/.hg8
Final step is to add
4660 to the file descriptor we chose and pass it as a argument to the
[email protected]:~$ ./fd 4670
We also know that one of the most common file descriptor is
0 which correspond to the standard input. If we use
4660 as an argument, the binary will compare
LETMEWIN\n to the content in the file descriptor
0 which is the standard input. If everything goes fine we should be able to directly write our “secret” code there.
Let’s give it a try:
[email protected]:~$ ./fd 4660
We get a blank line with no error messages, let’s type
LETMEWIN then enter:
[email protected]:~$ ./fd 4660
A simple challenge like this one is a good occasion to try our hand on
pwntools which can probably comes very useful in the future.
Pwntools is a CTF framework and exploit development library. Written in Python, it is designed for rapid prototyping and development, and intended to make exploit writing as simple as possible.
After installing the tool let’s create a simple script to solve the challenge.
First let’s connect to the server:
from pwn import *
Pop a shell and run
./fd process with
4660 as argument, and then send the
shell = server.process(['./fd', str(4660)])
After closing the connection and printing the result the final script looks like this:
[[email protected] ~]$ python exploit.py
That’s it folks! As always do not hesitate to contact me for any questions or feedbacks!
See you next time ;)