Mr. Shock is feeling generous today, so here's an attached program that will give you the flag.
Author: Lurifos
Kita diberikan sebuah ELF executable x86-64. Awalnya, saya mencoba untuk langsung membuka file ini menggunakan Ghidra. Akan tetapi, decompilernya gagal membaca fungsi utama entry() dengan benar, dan yang kita dapatkan adalah fungsi berantakan ini.
Setelah iseng mencoba melakukan strings pada file, saya menemukan bahwa file ini telah di-pack menggunakan UPX versi 5.00.
Untuk unpack-nya sendiri cukup menjalankan ./upx -d <file> .
Setelah ini, kita decompile file yang baru menggunakan Ghidra. Sekarang, fungsi entry() tampak lebih jelas.
Fungsi ini memanggil fungsi lainnya yakni FUN_00401080() yang intinya adalah sebuah flag checker. Jika inputnya sama dengan flag, maka outputnya adalah benar.
undefined8 FUN_00401080(void)
{
char *__s;
size_t sVar1;
char *__dest;
ulong uVar2;
ulong uVar3;
bool bVar4;
char local_41b;
char local_41a;
char acStack_419 [1025];
puts("I\'m so sorry, I forgot what the flag is, could you please try to guess it first?");
__s = acStack_419 + 1;
printf("flag: ");
fgets(__s,0x400,stdin);
sVar1 = strlen(__s);
if ((sVar1 != 0) && (acStack_419[sVar1] == '\n')) {
acStack_419[sVar1] = '\0';
}
sVar1 = strlen(__s);
__dest = &local_41b;
bVar4 = sVar1 == 0x46;
for (uVar3 = 0; uVar3 < sVar1; uVar3 = uVar3 + 2) {
if (!bVar4) goto LAB_0040115f;
__dest = strncpy(__dest,__s + uVar3,2);
uVar2 = 0;
if ((local_41b != '\0') && (local_41a != '\0')) {
uVar2 = (uVar3 + 1) * ((long)local_41a + (long)local_41b * 0x100);
}
bVar4 = *(uint *)((long)&DAT_00402360 + uVar3 * 2) == uVar2;
}
if (bVar4) {
puts("\n Wow congrats, that is indeed the correct flag");
}
else {
LAB_0040115f:
puts("\n Uhmm, I\'m afraid that\'s wrong");
}
return 0;
}
Kalau dirapihkan, hasilnya akan seperti ini.
int check_flag() {
char input[0x401]; // acStack_419 + 1
size_t len;
bool correct;
uint16_t lo_hi; // packed local_41b (low byte) and local_41a (high byte)
uint32_t expected, computed;
puts("I'm so sorry, I forgot what the flag is, could you please try to guess it first?");
printf("flag: ");
fgets(input, 0x400, stdin);
// strip trailing newline if present
len = strlen(input);
if (len > 0 && input[len-1] == '\n') {
input[len-1] = '\0';
len--;
}
// Must be exactly 0x46 (70) characters long
correct = (len == 0x46);
// For each pair of characters in the input...
for (size_t i = 0; i < len; i += 2) {
if (!correct) break;
// copy two chars into lo_hi: low byte = input[i], high byte = input[i+1]
uint8_t b0 = input[i];
uint8_t b1 = input[i+1];
lo_hi = b0 | (b1 << 8);
// compute value = (position_index+1) * lo_hi
// note: position_index = i/2, so (i+1) in code = 2*(index)+1, but since they use (uVar2+1) with
// uVar2=0,2,4,..., it effectively counts bytes: (byte_offset+1) * lo_hi
computed = (uint32_t)(i + 1) * (uint32_t)lo_hi;
// load the expected 32-bit value from the FLAG table at offset i*2
// (they cast &FLAG + uVar2*2 to a uint*)
expected = *((uint32_t*)((uint8_t*)&FLAG + i*2));
if (computed != expected) {
correct = false;
}
}
if (correct) {
puts("\n Wow congrats, that is indeed the correct flag");
} else {
puts("\n Uhmm, I'm afraid that's wrong");
}
return 0;
}
Value "FLAG" adalah DAT_00402360 yang tampak seperti ini pada Ghidra.
Bytes yang ada pada DAT_00402360 , jika dijalankan pada algoritma yang sama dengan fungsi flag checker di atas, tentunya akan menghasilkan flag. Oleh karena itu, berikut adalah script yang saya gunakan.