Target & Download
Daddy, teach me how to use random value in programming!
ssh random@pwnable.kr -p2222 (pw:guest)
scp 下载文件
scp -P 2222 -p random@pwnable.kr:/home/random/* ./
Analysis & IDA
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 ^ random) == 0xdeadbeef 即可
在 rand 被调用之前,srand 函数要先被调用,并且 srand 在整个程序中仅被调用一次。
这里并没有调用srand 这样其实每次运行rand 结果是不变的。
每次运行都会用同一个种子生成随机序列,那么每次程序运行得到的数就是一样的。tips
IDA pseudocode
.text:00000000004005F4 ; __unwind {
.text:00000000004005F4 push rbp
.text:00000000004005F5 mov rbp, rsp
.text:00000000004005F8 sub rsp, 10h
.text:00000000004005FC mov eax, 0
.text:0000000000400601 call _rand
.text:0000000000400606 mov [rbp+var_4], eax
.text:0000000000400609 mov [rbp+var_8], 0
.text:0000000000400610 mov eax, offset unk_400760
.text:0000000000400615 lea rdx, [rbp+var_8]
.text:0000000000400619 mov rsi, rdx
.text:000000000040061C mov rdi, rax
.text:000000000040061F mov eax, 0
.text:0000000000400624 call ___isoc99_scanf
.text:0000000000400629 mov eax, [rbp+var_8]
.text:000000000040062C xor eax, [rbp+var_4]
.text:000000000040062F cmp eax, 0DEADBEEFh
.text:0000000000400634 jnz short loc_400656
.text:0000000000400636 mov edi, offset s ; "Good!"
.text:000000000040063B call _puts
.text:0000000000400640 mov edi, offset command ; "/bin/cat flag"
.text:0000000000400645 mov eax, 0
.text:000000000040064A call _system
.text:000000000040064F mov eax, 0
.text:0000000000400654 jmp short locret_400665
.text:0000000000400656 ; ---------------------------------------------------------------------------
.text:0000000000400656
Debug & writeup
ELF 文件,使用gdb debug
.text:0000000000400601 call _rand
.text:0000000000400606 mov [rbp+var_4], eax
.text:0000000000400609 mov [rbp+var_8], 0
执行到0x400609 的时候已经获取到_rand 生成的伪随机数了。
在此处打断点,查看rbp+4h 的数据,即可获得
使用pwndbg
hispark@ubuntu:~/code/pwndbg$ gdb gdb/random
Reading symbols from gdb/random...(no debugging symbols found)...done.
pwndbg> b *0x400609
Breakpoint 1 at 0x400609
pwndbg> rub
Undefined command: "rub". Try "help".
pwndbg> run
Starting program: /home/hispark/code/pwndbg/gdb/random
Breakpoint 1, 0x0000000000400609 in main ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
─────────────────────────────────[ REGISTERS ]──────────────────────────────────
RAX 0x6b8b4567
RBX 0x0
RCX 0x7ffff7dcd1c8 (randtbl+8) ?— 0x6774a4cd16a5bce3
RDX 0x0
RDI 0x7ffff7dcd740 (unsafe_state) —? 0x7ffff7dcd1d4 (randtbl+20) ?— 0x61048c054e508aaa
RSI 0x7fffffffdd14 ?— 0x94e50d006b8b4567
R8 0x7ffff7dcd1d4 (randtbl+20) ?— 0x61048c054e508aaa
R9 0x7ffff7dcd240 (pa_next_type) ?— 0x8
R10 0x3
R11 0x7ffff7a264c0 (rand) ?— sub rsp, 8
R12 0x400510 (_start) ?— xor ebp, ebp
R13 0x7fffffffde30 ?— 0x1
R14 0x0
R15 0x0
RBP 0x7fffffffdd50 —? 0x400670 (__libc_csu_init) ?— mov qword ptr [rsp - 0x28], rbp
RSP 0x7fffffffdd40 —? 0x7fffffffde30 ?— 0x1
RIP 0x400609 (main+21) ?— mov dword ptr [rbp - 8], 0
───────────────────────────────────[ DISASM ]───────────────────────────────────
? 0x400609 <main+21> mov dword ptr [rbp - 8], 0
0x400610 <main+28> mov eax, 0x400760
0x400615 <main+33> lea rdx, [rbp - 8]
0x400619 <main+37> mov rsi, rdx
0x40061c <main+40> mov rdi, rax
0x40061f <main+43> mov eax, 0
0x400624 <main+48> call __isoc99_scanf@plt <__isoc99_scanf@plt>
0x400629 <main+53> mov eax, dword ptr [rbp - 8]
0x40062c <main+56> xor eax, dword ptr [rbp - 4]
0x40062f <main+59> cmp eax, 0xdeadbeef
0x400634 <main+64> jne main+98 <main+98>
───────────────────────────────────[ STACK ]────────────────────────────────────
00:0000│ rsp 0x7fffffffdd40 —? 0x7fffffffde30 ?— 0x1
01:0008│ 0x7fffffffdd48 ?— 0x6b8b456700000000
02:0010│ rbp 0x7fffffffdd50 —? 0x400670 (__libc_csu_init) ?— mov qword ptr [rsp - 0x28], rbp
03:0018│ 0x7fffffffdd58 —? 0x7ffff7a03bf7 (__libc_start_main+231) ?— mov edi, eax
04:0020│ 0x7fffffffdd60 ?— 0x1
05:0028│ 0x7fffffffdd68 —? 0x7fffffffde38 —? 0x7fffffffe1d7 ?— '/home/hispark/code/pwndbg/gdb/random'
06:0030│ 0x7fffffffdd70 ?— 0x100008000
07:0038│ 0x7fffffffdd78 —? 0x4005f4 (main) ?— push rbp
─────────────────────────────────[ BACKTRACE ]──────────────────────────────────
? f 0 0x400609 main+21
f 1 0x7ffff7a03bf7 __libc_start_main+231
f 2 0x400539 _start+41
────────────────────────────────────────────────────────────────────────────────
pwndbg>
rbp+4h 即 01:0008 0x6b8b456700000000 则random为 0x6b8b4567
hispark@ubuntu:~/code/pwndbg$ python
Python 2.7.17 (default, Feb 27 2021, 15:10:58)
[GCC 7.5.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> random = 0x6b8b4567
>>> res = 0xdeadbeef
>>> key = res ^ ramdom
>>> key = res ^ random
>>> print(key)
3039230856
>>>
利用异或的运算即可获得最终值3039230856
random@pwnable:~$ ./random
3039230856
Good!
Mommy, I thought libc random is unpredictable...
random@pwnable:~$
TIPS
int rand(void);
int rand_r(unsigned int *seedp);
void srand(unsigned int seed);
- 在rand函数的内部,是通过一个公式计算出一个值作为随机值,下次再调用rand的时候,再把这个随机值作为参数传给这个公式计算出一个新的随机值,周而复始。
- 在C库中,是通过一个静态全局变量来作为“种子”,而这个“种子”的值是通过srand函数改变的,如果不写srand函数,这个“种子”值默认赋值为1。
- 程序只要重新开始运行,“种子”值就会被默认赋值为1,那么通过公式算出来的序列肯定就一直相同了。
- 目前流传较广的意见是rand_r函数是线程安全的。
参考:
https://blog.csdn.net/lvyibin890/article/details/80141412
https://blog.csdn.net/w_y_x_y/article/details/80199694
|