这一关本身并不难,只是由于种种蛋疼的原因,也耗费了我不少时间。
原题参见这里。
题目就是它会输出20个随机数,让计算出生成这20个随机数的种子。由随机数算种子,想来应该是除了暴力对比没啥好办法了吧~~~
如果直接取前20个随机数,多进程对比,那只能说太靠人品了,还是规规矩矩反汇编吧,下面给出反汇编后仿写的代码:
int main() { seed = times(&tms); seed += (tms.utime + tms.stime + tms.cutime + tms.cstime); seed += clock(); seed += time(NULL); ass = (seed sar 0x1f) >> 0x18; // sar表示算术右移 seed = 0x80 - (((seed + ass) & 0xff) - ass); real_seed = seed + time(NULL); srand(real_seed); for (int i = 0; i < seed; ++i) { rand(); } printf("["); for (int i = 0; i < 20; ++i) { buffer[i] = rand(); printf(" %08x,", buffer[i]); } printf("]"); alarm(30); read(0, &ans, 4); if (ans == real_seed) { setresuid(geteuid(), geteuid(), geteuid()); execlp("/bin/sh", "sh", "-i", NULL); } else { printf("Nope, try again"); } }
从代码中可以看出,首先rand()了seed次之后,才rand()出输出的20个数,所以只有当seed<=0时,输出的才是前20次rand()的结果。
再仔细观察seed,会发现seed的范围是128-255~128+255,即-127~383。而对于time(NULL)而言,由于其精度是到秒的,那么也就是说我们只要在运行这个程序前输出time(NULL),那么得到的基本就是这个程序中的取到time(NULL)不会错了。这样,实际上我们需要尝试的范围就只有511个数,很轻易就可以得到结果。
启动程序如下:
#include <stdio.h> #include <unistd.h> int main() { printf("Time : %xn", time(NULL)); execl("/vortex/vortex10", "", NULL); return 0; }
暴力搜索结果的程序如下:
#include <stdio.h> #include <time.h> int main() { int i, j; unsigned int aim[20]; unsigned int tseed; int flag; scanf("Time : %xn[ ", &tseed); for (i = 0; i < 20; ++i) { scanf("%x,", aim + i); } for (i = 128 - 255; i <= 128 + 255; ++i) { srand(tseed + i); for (j = 0; j < i; ++j) { rand(); } flag = 1; for (j = 0; j < 20; ++j) { if (rand() != aim[j]) { flag = 0; break; } } if (flag != 0) { tseed += i; char *ans = (char *)&tseed; printf("%.4sn", ans); printf("cat /etc/vortex_pass/vortex11n"); break; } } return 0; }
然后运行./search | ./startup,并把startup的输出输入给search即可得到password。