I once played this online game, it was an old-school MUD. You log in, chat, kill some goblins.
It had a casino. You go into the casino and you bet X gold, and there was a 40% chance you win double your bet. Obviously in the long run, the casino will always win, right?
But here's the thing. I knew the game was written in C++, and I knew the rand() algorithm.
So here's what I would do. I went into the casino, and bet 1 gold about 10 times in a row, as fast as possible. if I lost, I recorded a 0, if I won I recorded a 1.
Then I go and enter that data into a program I wrote. It goes through all of the random numbers in the rand() sequence, starting from seed 0. If it generated a number less than 0.4, that was a 0. If it was 0.4 through 1.0, then it was a 1. And I compared the sequence in the chain to the sequence I recorded in the casino. If all 10 bits match, bingo. I found the current seed that the game was using.
Of course, this took a minute or so to calculate, so as people were mucking about killing goblins, the game continued along for another few hundred seeds as it generated more numbers. So I did my test again, another 10 rapid-fire bets, another 10 gold down the drain. Enter my second sequence into the program, and this time it finds the current seed within microseconds (because we're starting from the seed we found the last time), and this time it prints out the next 30 or so bets, whether they're going to be winners or losers.
So what I do is I bet 1 if the next number is going to lose. Then I bet half my money if it's going to win. Blamo, instantly increased money by 150%. Repeat, repeat, repeat, I suddenly have an exponentially-growing bank account.
Now there's a few problems with this method. Number one, if the game generated a random number inbetween your initial "probes" of 10 bets, it wouldn't find a sequence. Not a big deal, just do it again. You'll find one eventually.
Second problem; if you're not fast, the game will generate a new random number somewhere else and throw off your sequence when you're betting for real. I lost a lot of money in some of those instances. So this is where macros in my telnet client really helped.
Third problem... The game used 32-bit ints to store money. After about 100 bets, you end up overflowing the counter. I surpassed 2 billion gold and found myself with negative 2 billion gold. And the game wasn't programmed to ever handle negative gold; but the number parsing system could.
So I went around and started giving people negative amounts of gold. Hey Zethryr, here's negative one million! Boom, his whole life savings wiped out in an instant.
It was pretty hilarious, but it highlights why pseudo-random numbers can be dangerous. If there's any way for the random numbers to be surfaced to the user on a regular basis (ie: the bet command), then they're going to be able to somewhat easily figure out where in the rand() seed chain your program currently is. And once they do that, they can gain an edge in your system by guessing what the next random number is.
Sometimes web developers will generate record ID's, salt strings, and temporary passwords based on a random number generator. If they use a pseudo-RNG, then an attacker can create a few accounts or records in a row and examine their ID number, probably encoded into the URL. Then they can guess the ID's of other people's accounts or records, or even their passwords. And that can be pretty dangerous.
rand
with their own. (LD_PRELOAD) $\endgroup$makeKey
function with their own so there's no point trying to defend against that. (Or they can replace yourmain
function. Or they can just run their own program.) $\endgroup$