v12 = __readfsqword(0x28u); fd = open("/dev/urandom", 0, a3); if ( fd < 0 || read(fd, &dest[0x14], 4uLL) != 4 ) { puts("Fatal error!"); exit(1); } close(fd); srand(*(_DWORD *)&dest[0x14]); puts("||| CTF Simulator 2022 |||"); puts("This CTF training simulator will hone your guessing skills so you can be more competitive in CTF competitions!"); printf("What's the name of your CTF team?\n[>] "); fflush(stdout); src = sub_1349(); if ( !src ) { puts("Invalid team name!"); exit(1); } strncpy(dest, src, 0x14uLL); for ( i = 10; i <= 999999999; i *= 10 ) { printf("Okay %s, I'm thinking of a number between 1 and %d. What is it?\n[>] ", dest, (unsignedint)i); fflush(stdout); v7 = rand() % i + 1; v4 = 0; src = sub_1349(); if ( (unsignedint)__isoc99_sscanf(src, "%d", &v4) != 1 ) { puts("Bad guess!"); exit(1); } if ( v7 > v4 ) { puts("Too low!"); exit(1); } if ( v7 < v4 ) { puts("Too high!"); exit(1); } puts("That's it!"); } puts("Wow, did you hack into my brain? Great guessing! You'll be a CTF star in no time!"); stream = fopen("flag.txt", "r"); if ( !stream ) { puts("Flag file is missing!"); exit(1); } if ( !fgets(s, 100, stream) ) { puts("Error reading from flag file!"); exit(1); } fclose(stream); v10 = strchr(s, 10); if ( v10 ) *v10 = 0; printf("Here's a reward for you: %s\n", s); return0LL; }
요약하자면 for ( i = 10; i <= 999999999; i *= 10 ) 동안 랜덤한 수를 맞춰야 한다.
Vulnerability
CTF team name을 입력할 때 srand 인자 leak이 가능하다. &dest[0x14]에 4바이트로 srand의 인자로 /dev/urandom의 랜덤한 값을 입력한다. 후에 CTF team name을 사용자에게 src에 입력받고 strncpy(dest, src, 0x14uLL); 에서 dest에 복사한다. printf는 공백까지 출력하기 때문에 CTF team name에 0x14를 꽉꽉 채워서 입력해주면 &dest[0x14]도 출력할 수 있다.