PWNABLE.KR fd writeup

Challenge Description

Mommy! what is a file descriptor in Linux?
ssh fd@pwnable.kr -p2222 (pw:guest)

We can see that we are provided with a ssh login and some hints for the challenge.

Understanding File Descriptors

File descriptors is a number that uniquely identifies an open file in a computer Operating System.
In C, file descriptors are represented as integers as follows:

  • stdin is represented with a 0
  • stdout is represented as 1
  • stderr is represented as 2
    So basically, when a program asks for an argument when you run it, that is stdin. When it provides an output, then that is stdout. When the program gives back an argument then that is stderr

Lets now look at our challenge by "sshing" into the machine.
we can see that we are provided with 3 files to work with. The binary fd, the source code fd.c and a flag file flag.

fd@pwnable:~$ ls
fd fd.c flag
fd@pwnable:~$

Trying to read the flag with cat flag, we are prompted with Permission denied. On the other hand, runing the fd binary, it asks for a number as an argument. Passing 1234 as our argument, we are told learn about Linux file IO. The only option remaining now is to try and analyse the source code, and find what is expected of us.

code analysis

#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; }

Breaking down the code

First, we can see char buf[32]. What this does is, it assigns a buffer of 32 chars to the variable buf

if(argc<2){
printf("pass argv[1] a number\n");

Now, this tries to check if we have passed an argument. If no argument is passed, then we get pass argv[1] a number

int fd = atoi( argv[1] ) - 0x1234;

We have a variable declared fd, which its value is atoi( argv[1] ) - 0x1234. It takes our argument then subtracts it with the integer value of 0x1234 which is equal to 4660 when converted.
The atoi() function stands for Ascii to Integer in C.

It then declares another integer len assigned a 0

int len = 0;

Then it takes the value of fd and puts it into buf

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;

We see it then takes fd and reads our input, and stores it in buf. The if statement, checks if the value of buf is equal to LETMEWIN. If yes, it prints good job :) and gives us the flag. Otherwise, it outputs learn about Linux file IO.

Exploitation

We can start by running the program with an argument and see its behaviour.

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More โ†’

we see that we get learn about Linux file IO. This is basically because we didn't get fd. In what we understood about file descriptors, is that we have three basic ones ranging from 0, 1, 2.

The rule of fd, is for our argument to subtract 4660. So if we supply the same as our argument, fd will be 0 which is the fd representation of standard input in C.

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More โ†’

We see after passing 4660 as the argument, we don't get learn about Linux file IO. So we have bypassed the line len = read(fd, buf, 32);

By the state of the program, it looks like it is waiting to be supplied with an input. We could try now and input the string LETMEWIN to make it execute the if statement.


aaand, we successfully pwned it.

Using Pwntools

#!/usr/bin/python3 # author: k0r3s from pwn import * shell =ssh('fd','pwnable.kr', password='guest', port=2222) process = shell.process(executable='./fd', argv=['fd','4660']) process.sendline('LETMEWIN') print (process.recv())

we just pwned it again.