Back to writeups

pwnable.kr: fd writeup

📅 Nov 2025 🏆 1 point 📂 Toddler's Bottle
file descriptors Linux I/O stdin

Challenge Description

First, we get this hint:

Mommy! what is a file descriptor in Linux?

ssh fd@pwnable.kr -p2222

In the terminal, I run ssh fd@pwnable.kr -p2222 and connect to the server. In /home/fd there are three files: fd, fd.c and flag. Running cat flag gives “permission denied”, so we cannot read it directly.

Source Code Analysis

Opening fd.c shows:

#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");
        setregid(getegid(), getegid());
        system("/bin/cat flag");
        exit(0);
    }
    printf("learn about Linux file IO\n");
    return 0;
}

Our only option is to run the binary and hit the correct path to read the flag.

The program expects a number in argv[1], so we run ./fd <some-number>. That string is converted to an integer with atoi, then 0x1234 is subtracted and the result is stored in fd. The program then calls read(fd, buf, 32). If buf equals "LETMEWIN\n" the program prints the flag.

Understanding File Descriptors

To get "LETMEWIN\n" we need to understand file descriptors and how they are used in Linux.

A file descriptor (FD) represents an open file in the operating system. Every time a new file is opened, the OS assigns a file descriptor to it. Common FDs are: 0 = stdin, 1 = stdout, 2 = stderr.

In this case, we want to read some word from a file into the buffer. The easiest way is to read from standard input. When we call read(0, ...) the program waits for user input. So we want fd to be equal to 0. This happens when argv[1] == 0x1234.

Solution

When passing 0x1234 as an argument, we get the "learn about Linux file IO" message. That is because atoi converts only decimal numbers. When the input starts with 0x..., atoi returns 0, so fd becomes a negative number.

When we pass the decimal number 4660 (which is equivalent to 0x1234), with ./fd 4660, the program stops and waits for input. If we type LETMEWIN and press Enter, we get the flag.

Alternative Solutions