pwnable.kr(6) - random

Problem

Points: 1 pt

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

ssh [email protected] -p2222 (pw:guest)

Link

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#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;
}

Thinking

L32產生一個亂數放入random
L37如果輸入的keyrandom互斥或(XOR)運算後等於0xdeadbeef,則獲得flag。

Prepare

C rand

1
2
#include <stdlib.h>
int rand (void);
1
An integer value between 0 and RAND_MAX.

rand()所產生的,是使用Linear congruential generator(線性同餘法, LCG)所產生的偽亂數。

Solution

本題只有使用rand()取亂數,而rand()在呼叫前會檢查是否呼叫過srand()
如果有的話,則把seed拿來取亂數。
否的話,則自動呼叫srand(1)再取亂數。

所以按照L34來看,程式每次執行的random變數都會是一樣,因為每次使用的seed都是1

進入gdb來看大略的程式:

main
1
2
3
4
5
6
7
8
9
10
11
gdb-peda$ disass
Dump of assembler code for function main:
0x00000000004005f4 <+0>: push rbp
0x00000000004005f5 <+1>: mov rbp,rsp
0x00000000004005f8 <+4>: sub rsp,0x10
0x00000000004005fc <+8>: mov eax,0x0
0x0000000000400601 <+13>: call 0x400500 <rand@plt>
0x0000000000400606 <+18>: mov DWORD PTR [rbp-0x4],eax
0x0000000000400609 <+21>: mov DWORD PTR [rbp-0x8],0x0
0x0000000000400610 <+28>: mov eax,0x400760
0x0000000000400615 <+33>: lea rdx,[rbp-0x8]

可以看到在+13的部份呼叫了rand方法。
而下面的+18,+21則是在把值放進去,高位元0x8放入了0x0,低位元0x4放入了EAX的值。
這個時候我們只需要察看EAX裏面是什麼,就可以知道rand所產生的數是多少了。

1
2
3
4
gdb-peda$ xinfo $eax
0x6b8b4567

gdb-peda$

所以0x6b8b4567就是實際rand出來的數值。

1
2
3
4
1 ^ 1 = 0
1 ^ 0 = 1
A ^ B = C
C ^ B = A

key ^ EAX = 0xdeadbeef 然後0xdeadbeef ^ EAX = key
於是套入0xdeadbeef ^ 0x6b8b4567 = 0xb526fb88
XOR完的結果還需要轉換成十進位,因為key的輸入是採十進位輸入。
最終結果是3039230856
直接開啟程式,輸入就可以獲得flag了。

Reference

Cplusplus - rand