Pwnable.kr: ‘random’ Walkthrough

I got the CTF zoomies so I’m moving right along to the ‘random’ challenge in the Pwnable.kr “Toddler’s Bottle” CTF series. Our hint is:

Daddy, teach me how to use random value in programming!

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

If we ssh in and print out the random.c file, we see:

random@ubuntu:~$ cat random.c
#include

int main(){
	unsigned int random;
	random = rand();	// random value!

	unsigned int key=0;
	scanf("%d", &key);

	if( (key ^ random) == 0xdeadbeef ){
		printf("Good!\n");
		system("/bin/cat flag");
		return 0;
	}

	printf("Wrong, maybe you should try 2^32 cases.\n");
	return 0;
}

lol im so random

You’ve likely heard about random not being actually, truly random. I experienced this during a recent hobby project where I forgot to provide the rand() function with a seed, and got the same value every time.

If we make our own file in a tmp folder:

$ mkdir /tmp/jl
$ cd /tmp/jl
$ vi randtest.c

Let’s make our own copy of the program, and use it to print up the output to rand().

#include

int main(){
        unsigned int random;
        random = rand();        // random value!

        printf("random is %x\n", random);
        return 0;
}

We compile it:

$ gcc randtest.c -o randtest

If we run it:

random@ubuntu:/tmp/jl$ ./randtest
6b8b4567

And we run it again, and again, and again:

random@ubuntu:/tmp/jl$ ./randtest
6b8b4567
random@ubuntu:/tmp/jl$ ./randtest
6b8b4567
random@ubuntu:/tmp/jl$ ./randtest
6b8b4567

Just like I thought… not very random. It’s the same value every time.

What’s this ^ thing about?

So we have the not-random value of random. We know that we have to enter a key value to get past this if statement:

if( (key ^ random) == 0xdeadbeef ){

The ^ symbol is the bitwise XOR operator in C. XOR is the equivalent of the English “or”… meaning “one or the other, but not both.”  Alternatively, bitwise OR is “one or the other or both.”

The equation being bitwise XOR allows us to solve for key.

Here’s an example of how XOR works with a small set of numbers:

a =     00101010
b =     10100110
a ^ b = 10001100

We can see that:

0 ^ 0 = 0
1 ^ 0 = 1
0 ^ 1 = 1
1 ^ 1 = 0

0xdeadbeef

If we convert 0xdeadbeef into binary, we get 11011110101011011011111011101111.

If we convert 0x6b8b4567 (“random”), we get 01101011100010110100010101100111.

There’s probably a quicker way to do this, but I lined the values up and solved for key (the top line) by hand. Then I checked my math using this calculator, since my first couple tries didn’t work with my computed value.

1011 0101 0010 0110 1111 1011 1000 1000   # key
0110 1011 1000 1011 0100 0101 0110 0111   # "random" value
1101 1110 1010 1101 1011 1110 1110 1111   # deadbeef

I convert key into decimal, which is 3039230856. Then, I run the program again, and provide the key value, and voila!

random@ubuntu:~$ ./random
3039230856
Good!
Mommy, I thought libc random is unpredictable...