攻防 re_parallel-comparator-200
是一个c语言源文件,打开看到具体代码:
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h> //linux的线程库 ,所以要在linux中才可运行
#define FLAG_LEN 20
void * checking(void *arg) {
char *result = malloc(sizeof(char));
char *argument = (char *)arg;
*result = (argument[0]+argument[1]) ^ argument[2]; //对 first_letter、 differences[i]、 user_string[i]进行简单操作
return result;
}
int highly_optimized_parallel_comparsion(char *user_string)
{
int initialization_number;
int i;
char generated_string[FLAG_LEN + 1];
generated_string[FLAG_LEN] = '\0';
while ((initialization_number = random()) >= 64); //无用循环
int first_letter;
first_letter = (initialization_number % 26) + 97; //initialization_number从0~25取值 +97后ASCII对应小写的a~z
pthread_t thread[FLAG_LEN]; //创建数组型的线程标识符 ,20线程句柄
char differences[FLAG_LEN] = {0, 9, -9, -1, 13, -13, -4, -11, -9, -1, -7, 6, -13, 13, 3, 9, -13, -11, 6, -7}; //定义20个元素的char数组
char *arguments[20]; //定义20个char型的指针数组
for (i = 0; i < FLAG_LEN; i++) {
arguments[i] = (char *)malloc(3*sizeof(char)); //每个指针指向3个char字节划分的数组头
arguments[i][0] = first_letter; //first_letter由于 initialization_number = random()而未确定
arguments[i][1] = differences[i]; //已确定
arguments[i][2] = user_string[i]; //用户输入字符,未确定
pthread_create((pthread_t*)(thread+i), NULL, checking, arguments[i]); //调用上面checking函数对arguments三字节数组进行简单操作
}
void *result; //定义一个数组,用上面的异步线程赋值
int just_a_string[FLAG_LEN] = {115, 116, 114, 97, 110, 103, 101, 95, 115, 116, 114, 105, 110, 103, 95, 105, 116, 95, 105, 115}; //定义一个20个元素的数组
for (i = 0; i < FLAG_LEN; i++) {
pthread_join(*(thread+i), &result); //阻塞线程,让线程一个个执行
generated_string[i] = *(char *)result + just_a_string[i]; //把 just_a_string数组加到result中 赋值给 generated_string数组
free(result);
free(arguments[i]);
}
int is_ok = 1;
for (i = 0; i < FLAG_LEN; i++) {
if (generated_string[i] != just_a_string[i]) //这里比较generated_string和 just_a_string数组,而generated_string数组在前面赋值中= *(char *)result + just_a_string[i],所以result等于0才行
return 0;
}
return 1;
}
int main()
{
char *user_string = (char *)calloc(FLAG_LEN+1, sizeof(char)); //分配21个字符空间,除去0结尾就是20个字符
fgets(user_string, FLAG_LEN+1, stdin); //获取用户输入
int is_ok = highly_optimized_parallel_comparsion(user_string);
if (is_ok)
printf("You win!\n");
else
printf("Wrong!\n");
return 0;
}
这里补充一下里面出现的我个人没见过的函数:
#include <pthread.h>
int pthread_create(
pthread_t *restrict tidp, //新创建的线程ID指向的内存单元。
const pthread_attr_t *restrict attr, //线程属性,默认为NULL
void *(*start_rtn)(void *), //新创建的线程从start_rtn函数的地址开始运行
void *restrict arg //默认为NULL。若上述函数需要参数,将参数放入结构中并将地址作为arg传入。
);
pthread_create((pthread_t*)(thread+i), NULL, checking, arguments[i]); //调用上面checking函数对arguments三字节数组进行简单操作
解题思路
从后往前看,发现 is_ok == 1 的时候符合条件,找到和它相关的部分,即为以下函数:
int highly_optimized_parallel_comparsion(char *user_string)
{
int initialization_number;
int i;
char generated_string[FLAG_LEN + 1];
generated_string[FLAG_LEN] = '\0';
while ((initialization_number = random()) >= 64); //无用循环
int first_letter;
first_letter = (initialization_number % 26) + 97; //initialization_number从0~25取值 +97后ASCII对应小写的a~z
pthread_t thread[FLAG_LEN]; //创建数组型的线程标识符 ,20线程句柄
char differences[FLAG_LEN] = {0, 9, -9, -1, 13, -13, -4, -11, -9, -1, -7, 6, -13, 13, 3, 9, -13, -11, 6, -7}; //定义20个元素的char数组
char *arguments[20]; //定义20个char型的指针数组
for (i = 0; i < FLAG_LEN; i++) {
arguments[i] = (char *)malloc(3*sizeof(char)); //每个指针指向3个char字节划分的数组头
arguments[i][0] = first_letter; //first_letter由于 initialization_number = random()而未确定
arguments[i][1] = differences[i]; //已确定
arguments[i][2] = user_string[i]; //用户输入字符,未确定
pthread_create((pthread_t*)(thread+i), NULL, checking, arguments[i]); //调用上面checking函数对arguments三字节数组进行简单操作
}
void *result; //定义一个数组,用上面的异步线程赋值
int just_a_string[FLAG_LEN] = {115, 116, 114, 97, 110, 103, 101, 95, 115, 116, 114, 105, 110, 103, 95, 105, 116, 95, 105, 115}; //定义一个20个元素的数组
for (i = 0; i < FLAG_LEN; i++) {
pthread_join(*(thread+i), &result); //阻塞线程,让线程一个个执行
generated_string[i] = *(char *)result + just_a_string[i]; //把 just_a_string数组加到result中 赋值给 generated_string数组
free(result);
free(arguments[i]);
}
int is_ok = 1;
for (i = 0; i < FLAG_LEN; i++) {
if (generated_string[i] != just_a_string[i]) //这里比较generated_string和 just_a_string数组,而generated_string数组在前面赋值中= *(char *)result + just_a_string[i],所以result等于0才行
return 0;
}
return 1;
}
当generated_string[i] == just_a_string[i]的时候返回1,is_ok == 1
又因为
generated_string[i] = *(char *)result + just_a_string[i];
所以成功的条件是result == 0;然后寻找result有关的函数
pthread_create((pthread_t*)(thread+i), NULL, checking, arguments[i]);
在上面代码中,调用了checking函数:
void * checking(void *arg) {
char *result = malloc(sizeof(char));
char *argument = (char *)arg;
*result = (argument[0]+argument[1]) ^ argument[2]; //对 first_letter、 differences[i]、 user_string[i]进行简单操作
return result;
}
arguments[ i ] [ 0 ] = first_letter; //(initialization_number % 26) + 97
arguments[ i ] [ 1 ] = differences[i]; //{0, 9, -9, -1, 13, -13, -4, -11, -9, -1, -7, 6, -13, 13, 3, 9, -13, -11, 6, -7};
arguments[ i ] [ 2 ] = user_string[i]; //用户输入
因为result == 0,所以 (argument[0]+argument[1]) == argument[2]
即 first_letter + differences[i] == user_string[i]
由代码可知first_letter是一个范围在97~122的整数
综上编写如下c语言脚本(爆破方法):
#include <stdio.h>
int main()
{
char differences[20] = {0, 9, -9, -1, 13, -13, -4, -11, -9, -1, -7, 6, -13, 13, 3, 9, -13, -11, 6, -7};
char flag[50] = {0};
int i,j;
for(i=97;i<122;i++)
{
for(j=0;j<20;j++)
{
flag[j] = i+differences[j];
}
printf("%d %s\n",i,flag);
}
return 0;
}
第108个看起来比较有意义,即为最终的flag