Pwnable.kr - mistake

Write-up for mistake of pwnable.kr.

0x00 Puzzle

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)

0x01 Explore

ssh

ssh mistake@pwnable.kr 2222
mistake@ubuntu:~$ ls -l
total 24
-r-------- 1 mistake_pwn root      51 Jul 29  2014 flag
-r-sr-x--- 1 mistake_pwn mistake 8934 Aug  1  2014 mistake
-rw-r--r-- 1 root        root     792 Aug  1  2014 mistake.c
-r-------- 1 mistake_pwn root      10 Jul 29  2014 password

As usual, the goal is to pwn the binary mistake and let it cat the flag file.

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

It seems that the program:

  • open the password and read 10 bytes as password.
  • scanf 10 bytes and flip the last bit of every byte.
  • if those two match, cat the flag.

But there is a hint in the puzzle: operator priority.

So don't be hurry, let's look at the program carefully, until we find the vulnerable part:

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

Simplify version of this line: if(fd = open(...) < 0).

Notice that this line means to compare the fd and 0, but there are no parentheses outside the assignment statement. And we should know that '<' is of higher priority comparing to '='.

So this line actually assigns the value of (open(...) < 0) to fd.

If the "/home/mistake/password" opens correctly, open() < 0 always return false, which is 0x00 in c. Then fd will be set to 0;

So it's actually read 10 bytes of password not from "/home/mistake/password" but from stdin (which file descriptor = 0, remember?).

0x02 Solution

We need to run ~/mistake, give 10 bytes to stdin as password, then input 10 bytes to match its flipping check.

Trick: '-' means open stdin in Linux. It also can be used to keep bash open sometimes.

We just try:

mistake@ubuntu:~$ ./mistake -
do not bruteforce...
0000000000
1111111111
input password : Password OK
Mommy, the operator priority always confuses me :(

Be patient and wait for several seconds (there is sleep() inside the program), and we are done.

Done.