1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

pwnable.kr random ~疑似乱数シード~

Posted at

#問題文
ssh random@pwnable.kr -p2222 にアクセスして、flagを入手する
#解法
##ファイル構成

  • -r--r----- 1 random_pwn root flag
  • -r-sr-x--- 1 random_pwn random random
  • -rw-r--r-- 1 root root random.c

例によってflag はrootでしか読み取れず、random.cも買い替えは不能。よって./random という実行ファイルに対して何らかの攻撃をすればflagはゲットできると予想する。
##random.c

random.c
#include <stdio.h>

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

ユーザーの入力keyとrand()で生成したrandomの排他的論理和が0xdeadbeefであればcatコマンドでflagを表示してくれる。
#方針
間違ったときに出てくるメッセージによると、2^32 のブルートフォースアタックをすればいいようにも見えるが、(unsunged intなので32乗)約42億となってしまうので少しやりたくない。(やったらどれくらい時間がかかるかどうかはわかりません)
というわけでどうにかして、randomを特定してそれに対応したkeyを入力してやることによるflag入手を目指す。
#rand()関数の脆弱性
さて、randomはrand()関数を使用して乱数を生成しているわけだが、この関数は通常これだけでは使ってはいけない。コンピュータが乱数を生成すると言っても、人間のように思いつきで生成しているわけではなく、擬似乱数というものを計算で生成しており、そのために乱数のシード(seed:種)を使う。
今回のrand()関数が使う方法では、シードが同じなら、必ず同じ値が生成されてしまうという特徴があり、コード中にはシードを設定している箇所はない。
つまり、これを実行しても、randomは乱数ではなく、「定数」となってしまうのだ。
以上から、randomを特定してやり、それを入力してやることでflagゲットを目指す。
#デバッガによるrandom特定
random.cは書き換えできないので、何らかの手段で実行中の変数の内容を観測してやる必要がある。
そのためにGDBというデバッガを使う。
main関数のディスアセンブリ結果の抜粋(下)

  • rand関数周辺

0x0000000000400601 <+13>: call 0x400500 <rand@plt>
0x0000000000400606 <+18>: mov DWORD PTR [rbp-0x4],eax

  • if文周辺

0x0000000000400629 <+53>: mov eax,DWORD PTR [rbp-0x8]
0x000000000040062c <+56>: xor eax,DWORD PTR [rbp-0x4]
0x000000000040062f <+59>: cmp eax,0xdeadbeef

以上から、[rbp-0x8]にkeyが、[rbp-0x4]にrandomがあるということが推測される。
よってmain+18直後の[rbp-0x8]を調べればrandomがわかることになる。
##答え
(私の環境では)randomは0x6b8b4567となり、これと0xdeadbeefの排他的論理和である3039230856を入力してやることでflagが表示された。

#rand()の正しい(?)利用法
rand()関数を使ってやる際には前述のように毎回違うシードを使ってやる必要があり、慣習的に時間をシードとする方法が知られている。
srand()関数でシードを指定する際にtime()関数で現在時間を表示するなどがある。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?