Wednesday, October 3, 2012

A Simple Number Guessing Game

Recently I across a few wargame codes where we have to exploit the vulnerability due to improper seeding of PRNG. rand() function is commonly used to generate pseudo-random integer in the range [0, RAND_MAX]. RAND_MAX is defined as 0x7FFFFFFF. This is what man page says about rand()

The rand() function returns a pseudo-random integer in the range [0, RAND_MAX].
The srand() function sets its argument as the seed for a new sequence of pseudo-random integers to be returned by rand().These sequences are repeatable by calling srand() with the same seed value.
If no seed value is provided, the rand() function is automatically seeded with a value of 1.

A common way to seed rand() is to use current time of the system. time() function returns UNIX Epoch in seconds. Check man 2 time for information on time() function.
Lets play a small number guessing game, the source code is given below

/* game.c */
/* A Simple Number Guessing Game */
#include<stdio.h>
#include<time.h>
#include<stdlib.h>

int main(int argc, char **argv)
{
 int rand_num;
 srand(time(0)); //seed with current time
 rand_num = rand();
 if(argc < 2)
  return -1;
 if(rand_num == atoi(argv[1]))
  printf("You won. Guess was right!\n");
 else
  printf("Sorry. Try agan, wrong guess!\n");
 return 0;
}
The program generates random number using rand() and current time is used as seed. A player wins if he can correctly guess this number.
[root@renorobert Rand]# gcc -o game game.c
[root@renorobert Rand]# ./game 6526346234
Sorry. Try agan, wrong guess!
[root@renorobert Rand]# ./game 123451345
Sorry. Try agan, wrong guess!
[root@renorobert Rand]# ./game 76234566
Sorry. Try agan, wrong guess!
Hmmm, not that easy to guess the number but not impossible. The man page of rand() says that, same sequence of random numbers are generated if same seed value is used. So we have to find the seed to win the game. time(0) returns the same value if called any number of times within a second.
/* time.c */
#include<stdio.h>
#include<time.h>
int main(void)
{
 time_t a = time(0);
 printf("%d",(int) a);
 return 0;
}
[root@renorobert Rand]# gcc -o time time.c 
[root@renorobert Rand]# ./time 
1349281735[root@renorobert Rand]# ./time 
1349281736[root@renorobert Rand]# ./time 
1349281736[root@renorobert Rand]# ./time 
1349281736[root@renorobert Rand]# ./time 
1349281737[root@renorobert Rand]# ./time 
1349281737[root@renorobert Rand]# 
We can see that same value is returned during multiple run of program if called within a second, just that you have to hammer the keyboard faster. This idea is used to generate same seed for rand() function and thus same random numbers. Below is the code that will do the guessing for us.
/* guess.c */
#include<stdio.h>
#include<time.h>
#include<stdlib.h>

int main(void)
{
 int rand_num;
 srand(time(0)); //seed with current time
 rand_num = rand();
 printf("%d", rand_num);
 return 0;
}
Now lets start playing the game again. This time we will pass the ouput from the program above to the game.
[root@renorobert Rand]# gcc -o guess guess.c 
[root@renorobert Rand]# 
[root@renorobert Rand]# ./game `./guess`
You won. Guess was right!
[root@renorobert Rand]# time ./game `./guess`
You won. Guess was right!

real 0m0.004s
user 0m0.002s
sys 0m0.002s
Yeah, we won the game this time!. Though this is just a demo game, such improper usage of PRNG can be found in many practical applications. More information on this is available in internet. Hope I explained a bit on this.

1 comment :

  1. Good one machi... I think first post of you to understand :)

    ReplyDelete