見出し画像

#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} 

フラグが取れました!

この記事が気に入ったらサポートをしてみませんか?