GFSJ0202-【zorropub】
寻找seed
main函数 能看到我们的比较是比较一个md5值 一般这种题目都是爆破
int __fastcall main(int a1, char **a2, char **a3)
{
size_t v3; // rax
int v5; // [rsp+1Ch] [rbp-104h] BYREF
int v6; // [rsp+20h] [rbp-100h] BYREF
signed int i; // [rsp+24h] [rbp-FCh]
unsigned int seed; // [rsp+28h] [rbp-F8h]
int v9; // [rsp+2Ch] [rbp-F4h]
_BYTE v10[96]; // [rsp+30h] [rbp-F0h] BYREF
char v11[16]; // [rsp+90h] [rbp-90h] BYREF
char v12[32]; // [rsp+A0h] [rbp-80h] BYREF
char s[32]; // [rsp+C0h] [rbp-60h] BYREF
char s1[40]; // [rsp+E0h] [rbp-40h] BYREF
unsigned __int64 v15; // [rsp+108h] [rbp-18h]
v15 = __readfsqword(0x28u);
seed = 0;
puts("Welcome to Pub Zorro!!");
printf("Straight to the point. How many drinks you want?");
__isoc99_scanf("%d", &v5);
if ( v5 <= 0 )
{
printf("You are too drunk!! Get Out!!");
exit(-1);
}
printf("OK. I need details of all the drinks. Give me %d drink ids:", v5);
for ( i = 0; i < v5; ++i )
{
__isoc99_scanf("%d", &v6);
if ( v6 <= 16 || v6 > 0xFFFF )
{
puts("Invalid Drink Id.");
printf("Get Out!!");
exit(-1);
}
seed ^= v6;
}
i = seed;
v9 = 0;
while ( i )
{
++v9;
i &= i - 1;
}
if ( v9 != 10 )
{
puts("Looks like its a dangerous combination of drinks right there.");
puts("Get Out, you will get yourself killed");
exit(-1);
}
srand(seed);
MD5_Init(v10);
for ( i = 0; i <= 29; ++i )
{
v9 = rand() % 1000;
sprintf(s, "%d", v9);
v3 = strlen(s);
MD5_Update((__int64)v10, (__int64)s, v3);
v12[i] = v9 ^ LOBYTE(dword_6020C0[i]);
}
v12[i] = 0;
MD5_Final(v11, v10);
for ( i = 0; i <= 15; ++i )
sprintf(&s1[2 * i], "%02x", (unsigned __int8)v11[i]);
if ( strcmp(s1, "5eba99aff105c9ff6a1a913e343fec67") )
{
puts("Try different mix, This mix is too sloppy");
exit(-1);
}
return printf("\nYou choose right mix and here is your reward: The flag is nullcon{%s}\n", v12);
}
然后第一个接收 收了一个总数 然后第二个接收 是drink id 然后对每一个id进行xor 然后有一个判断 v9 必须等于10 那v9是什么呢
v9 = 0;
while ( i )
{
++v9;
i &= i - 1;
}
这是经典的计算bit数量 也就是 seed 的二进制必须正好有 10 个 1 然后利用这个seed初始化随机数
然后循环 30 次
for (i = 0; i <= 29; ++i)
{
v9 = rand() % 1000;
sprintf(s, "%d", v9);
MD5_Update(v10, s, strlen(s));
v12[i] = v9 ^ LOBYTE(dword_6020C0[i]);
}
这里做了两件事 第一件事 生成 30 个随机数 每个都是
rand() % 1000
然后把这些数字的十进制字符串拼起来算 MD5 比如随机数是
12 345 6
那么 MD5 算的是
"123456"
不是数组 也不是加分隔符 最后要求 MD5 必须等于
5eba99aff105c9ff6a1a913e343fec67
所以我们只要爆破 seed 找到哪个 seed 生成的 30 个随机数能满足这个 MD5
exp ai写的 嘿嘿有点懒
from hashlib import md5
enc = [
0x3c8,0x32,0x2ce,0x302,0x7f,0x1b8,0x37e,0x188,0x349,0x27f,
0x5e,0x234,0x354,0x1a3,0x96,0x340,0x128,0x2fc,0x300,0x28e,
0x126,0x1b,0x32a,0x2f5,0x15f,0x368,0x1eb,0x79,0x11d,0x24e
]
target = "5eba99aff105c9ff6a1a913e343fec67"
def glibc_rand(seed, n):
if seed == 0:
seed = 1
r = [0] * (344 + n)
r[0] = seed
for i in range(1, 31):
r[i] = (16807 * r[i - 1]) % 2147483647
for i in range(31, 34):
r[i] = r[i - 31]
for i in range(34, 344 + n):
r[i] = (r[i - 31] + r[i - 3]) & 0xffffffff
return [r[i] >> 1 for i in range(344, 344 + n)]
for seed in range(0x10000):
if seed.bit_count() != 10:
continue
nums = [x % 1000 for x in glibc_rand(seed, 30)]
if md5("".join(map(str, nums)).encode()).hexdigest() == target:
print('nullcon{'+"".join(chr((nums[i] ^ enc[i]) & 0xff) for i in range(30))+'}')
break
flag
nullcon{nu11c0n_s4yz_x0r1n6_1s_4m4z1ng}
评论