creversing

File descriptors in linux; Pwnable kr challenge


In order to understand the workings of C and linux, I was doing the pwnable.kr challenges, but there is something in the first challenge that doesn't quite add to me.

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

}

To my understanding, the 0 fd is for stdin, and the 1 and 2 fd are for stdout, yet all three of them allow me to solve the challenge. I understand the first one, but wouldn't the other 2 file descriptors just read what I print on my promt, and not allow me to write anything after?


Solution

  • Let's take a look at what /proc says:

    $ ls -al /proc/self/fd
    total 0
    dr-x------. 2 mrsam mrsam  0 Apr 23 15:25 .
    dr-xr-xr-x. 9 mrsam mrsam  0 Apr 23 15:25 ..
    lrwx------. 1 mrsam mrsam 64 Apr 23 15:25 0 -> /dev/pts/1
    lrwx------. 1 mrsam mrsam 64 Apr 23 15:25 1 -> /dev/pts/1
    lrwx------. 1 mrsam mrsam 64 Apr 23 15:25 2 -> /dev/pts/1
    

    For an interactive terminal all three file descriptors are, basically the same. All three are connected to the terminal device, after all, why won't they be? Input and output goes to the same screen.

    And, for simplicity, you can think of them as dup()s of each other. So, as a side effect, all three file descriptors are read/write.

    Now, of course, this is only true for programs launched from an interactive terminal. In an arbitrary program, launched in an unknown environment you can only rely on being able to read from 0 and write to 1 and 2.