Keep Calm and Carry On

pwnable-kr-random

0x01 分析

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

rand标准用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main()
{
int i, n;
time_t t;

n = 5;

/* 初始化随机数发生器 */
srand((unsigned) time(&t));

/* 输出 0 到 49 之间的 5 个随机数 */
for( i = 0 ; i < n ; i++ ) {
printf("%d\n", rand() % 50);
}

return(0);
}
  1. 给srand()提供一个种子,否则默认为1;
  2. rand()产生伪随机数

0x02 利用思路

程序中并没有先调用srand并提供一个变化的种子,因此程序默认执行srand(1),那么每次执行rand函数产生的数就是固定的,使用gdb调试找到那个数便可以要过检查。

0x03 调试

main:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
gdb-peda$ disas main
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]
0x0000000000400619 <+37>: mov rsi,rdx
0x000000000040061c <+40>: mov rdi,rax
0x000000000040061f <+43>: mov eax,0x0
0x0000000000400624 <+48>: call 0x4004f0 <__isoc99_scanf@plt>
0x0000000000400629 <+53>: mov eax,DWORD PTR [rbp-0x8]
0x000000000040062c <+56>: xor eax,DWORD PTR [rbp-0x4]
0x000000000040062f <+59>: cmp eax,0xdeadbeef
...
0x0000000000400665 <+113>: leave
0x0000000000400666 <+114>: ret
End of assembler dump.

可以发现rand函数的返回值首先存储在eax,将断点下在0x0000000000400606,在此处读出eax的值便可以得到“随机数”,而input xor eax == 0xdeadbeef便会执行system("/bin/cat flag")执行,那么input = 0xdeadbeef xor eax即可得到应该输入的数。