zacheller@home:~/blog$

pwnable.kr - mistake


Prompt

We all make mistakes, let’s move on. (don’t take this too seriously, no fancy hacking skill is required at all)

This task is based on real event Thanks to dhmonkey

hint : operator priority

ssh mistake@pwnable.kr -p2222 (pw:guest)

Source Code Analysis

We are given an executable mistake and its source mistake.c. We are also given two additional files named password and flag.

mistake.c:

#include <stdio.h>
#include <fcntl.h>

#define PW_LEN 10
#define XORKEY 1

void xor(char* s, int len){
        int i;
        for(i=0; i<len; i++){
                s[i] ^= XORKEY;
        }
}

int main(int argc, char* argv[]){

        int fd;
        if(fd=open("/home/mistake/password",O_RDONLY,0400) < 0){
                printf("can't open password %d\n", fd);
                return 0;
        }

        printf("do not bruteforce...\n");
        sleep(time(0)%20);

        char pw_buf[PW_LEN+1];
        int len;
        if(!(len=read(fd,pw_buf,PW_LEN) > 0)){
                printf("read error\n");
                close(fd);
                return 0;
        }

        char pw_buf2[PW_LEN+1];
        printf("input password : ");
        scanf("%10s", pw_buf2);

        // xor your input
        xor(pw_buf2, 10);

        if(!strncmp(pw_buf, pw_buf2, PW_LEN)){
                printf("Password OK\n");
                system("/bin/cat flag\n");
        }
        else{
                printf("Wrong Password\n");
        }

        close(fd);
        return 0;
}

The program first attempts to open the password file and save its contents to pw_buf.

if(fd=open("/home/mistake/password",O_RDONLY,0400) < 0){...}

Upon successful completion, the open() function opens the file and return a non-negative integer representing the lowest numbered unused file descriptor. Upon failure, the function returns -1. But, comparison operators like < are given higher priority than assignment operators =, so the conditional statement is interpreted like the following:

fd=(open("/home/mistake/password",O_RDONLY,0400) < 0) == (non_neg_int < 0) == 0
fd=0

The file descriptor fd is not being set to the response code of open(), but rather to 0–the file descriptor for stdin. So when read() is called, it reads 10 bytes from stdin to the buffer pw_buf.

if(!(len=read(fd,pw_buf,PW_LEN) > 0)){...}

Then 10 characters are saved into pw_buf2 by scanf, and the xor() function XORs every byte. Lastly, the XORed supplied password in pw_buf2 is strncmped with what’s stored in pw_buf.

Solution

When you run mistake it waits for input. Enter an easily XORed 10-character string. Then, it asks to input the password. Enter the XORed version of the 10-character string.

mistake@pwnable:~$ ./mistake
do not bruteforce...
1111111111
0000000000
input password : Password OK
{flag}