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...