#125 [HTB] Simple Encryptor
Hack The Boxのリバーシング問題「Simple Encryptor」を解きました。
問題では、実行ファイル「encrypt」と暗号化されたファイル「flag.enc」が与えられます。実行ファイルの暗号化処理を読み解いて、暗号化データを復号するのがゴールでしょう。
解析
とりあえず、IDAでデコンパイルしてみました。
int __fastcall main(int argc, const char **argv, const char **envp)
{
char v3; // al
char v5; // [rsp+7h] [rbp-39h]
unsigned int seed[2]; // [rsp+8h] [rbp-38h] BYREF
__int64 i; // [rsp+10h] [rbp-30h]
FILE *stream; // [rsp+18h] [rbp-28h]
size_t size; // [rsp+20h] [rbp-20h]
void *ptr; // [rsp+28h] [rbp-18h]
FILE *s; // [rsp+30h] [rbp-10h]
unsigned __int64 v12; // [rsp+38h] [rbp-8h]
v12 = __readfsqword(0x28u);
stream = fopen("flag", "rb");
fseek(stream, 0LL, 2);
size = ftell(stream);
fseek(stream, 0LL, 0);
ptr = malloc(size);
fread(ptr, size, 1uLL, stream);
fclose(stream);
seed[0] = time(0LL);
srand(seed[0]);
for ( i = 0LL; i < (__int64)size; ++i )
{
*((_BYTE *)ptr + i) ^= rand();
v3 = rand();
v5 = *((_BYTE *)ptr + i);
seed[1] = v3 & 7;
*((_BYTE *)ptr + i) = __ROL1__(v5, v3 & 7);
}
s = fopen("flag.enc", "wb");
fwrite(seed, 1uLL, 4uLL, s);
fwrite(ptr, 1uLL, size, s);
fclose(s);
return 0;
}
ざっとみたところ、ランダム値でフラグが暗号化されているみたいです。しかし、シード値がそのままファイルに書き込まれています。これを使えば、ランダム値が復元できてしまいます。
PoC
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
FILE *stream;
size_t size;
char *contents;
int seed;
int result;
int r;
int r2;
int key;
stream = fopen("flag.enc", "rb");
fseek(stream, 0, 2);
size = ftell(stream);
fseek(stream, 0, 0);
contents = malloc(size);
fread(contents, sizeof(char), size, stream);
fclose(stream);
memcpy(&seed, contents, sizeof(seed));
printf("seed: %d\n", seed);
srand(seed);
for (int i=4; i < size; i++) {
r = rand();
r2 = rand();
key = r2 & 7;
contents[i] = ((unsigned char)contents[i] >> key) | ((contents[i]) << (8 - key));
contents[i] = contents[i] ^ r;
}
for (int i = 4; i < size; i++) {
printf("%c", contents[i]);
}
return 0;
}
シード値さえわかれば、生成したランダム値を使って1文字づつ復元できます。暗号化処理と逆をやればよいですね。
コンパイル
$ gcc poc.c
実行
$ ./a.out
seed: 1655780698
HTB{vRy_s1MplE_F1LE3nCryp0r}
フラグが取れました!