这一关本身并不难,只是由于种种蛋疼的原因,也耗费了我不少时间。
原题参见这里。
题目就是它会输出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。