🛡️

MNCTF2024 Writeup

2024/10/23に公開

0. チュートリアル

このステージはCTFのシステムを理解するための練習用のステージとなります。競技開始の前に試していただくことをお薦め致します。

0-1. Misc - 練習問題

練習問題です。答えは「MNCTF2024@@@」となります。

正答:MNCTF2024@@@

1. ランサムウェアのインシデント

マクニキCSIRTのてしがわら君にチャットが届いた。

やはら君 デスクトップ上のファイルが開けなくなりました。
てしがわら君 それは大変ですね。どんなメッセージが表示されていますか?
やはら君 「このファイルを開く方法を選んでください。」というメッセージが表示されます。どうやらファイルが暗号化されているようです。
てしがわら君 それはランサムウェアの可能性が高いですね。他のファイルも同じ状況ですか?
やはら君 はい。
てしがわら君 了解しました。まず、パソコンをネットワークから切り離してください。それと、ランサムウェアの脅迫文や暗号化メッセージのスクリーンショットを撮って送ってください。
やはら君 わかりました。ネットワークから切り離しました。スクリーンショットも撮りましたので、送ります。

てしがわら君 ありがとうございます。次に、CSIRTチームで詳細な調査を行いますので、少しお待ちください。ファイルのバックアップは取っていましたか?
やはら君 直近のバックアップは取っていませんでした。すみません。
てしがわら君 いえ、まずは被害の拡大を防ぐことが重要です。今後の対策と対応については、順次お知らせします。まずはパソコンの電源をそのままにしておいてください。
やはら君 わかりました。ありがとうございます。
てしがわら君 こちらこそ、ご協力ありがとうございます。進展があり次第、連絡いたします。

てしがわら君は同端末から怪しいファイルを見つけた。

1-1. Binary - マルウェアのハッシュ値

調査をした結果、ダウンロードフォルダに「amrw.exe」というファイルが見つかり、ランサムウェア本体の可能性が高いことがわかった。
amrw.exeのSHA256のハッシュ値を求めよ。

ZIPファイルのパスワードは「infected」である。

問題にはamrw.exeが添付されています。
Windowsのcertutilコマンドを使用してamrw.exeのSHA256ハッシュ値を調べます。

$ certutil -hashfile amrw.exe sha256
SHA256 ハッシュ (対象 amrw.exe):
9966905e42e3c31dfdb093088a0d6cabc09c6087783f1b08851adadf8771b0a4
CertUtil: -hashfile コマンドは正常に完了しました。
$

正答:9966905e42e3c31dfdb093088a0d6cabc09c6087783f1b08851adadf8771b0a4

1-2. Binary - 通信先のURL

amrw.exeの通信先のURLを回答してください。

LinuxのstringsコマンドでURLが表示されるか確認します。

$ strings amrw.exe | grep http 
http://amrwc2.angrymusu.me/amrwc2/
http://7b6x2ffenbdx3yns6atoe5bdyg6hzbw6kfpyoqjwp5iepmz5fwi6edqd.onion/confirm/?id=%s
Tor Browser: https://www.torproject.org/download/
$

URLが3つ表示されました。
URLの1行前まで表示してみると、1つ目のURLがランサムウェアの通信先である可能性が高いと判断できます。

$ strings amrw.exe | grep http -B 1
WriteConsoleW
http://amrwc2.angrymusu.me/amrwc2/
--
Visit the following URL using Tor Browser.
http://7b6x2ffenbdx3yns6atoe5bdyg6hzbw6kfpyoqjwp5iepmz5fwi6edqd.onion/confirm/?id=%s
Tor Browser: https://www.torproject.org/download/
$

正答:http://amrwc2.angrymusu.me/amrwc2/

1-3. Misc - ビットコイン

AMRW_README.txtはデスクトップにあったランサムノートです。
攻撃者のビットコインのアドレスを調べて答えてください。

問題にはAMRW_README.txtが添付されており、内容は以下の通りです。

~~~ AMRW 1.0 the world's most successful ransomware from 2023 ~~~
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>> Your personal ID: 0000002c <<<<<<<
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

All your data are belong to us.
If you don't pay the ransom, the data will be published on our TOR
darknet sites. Keep in mind that once your data appears on our leak
site, it could be bought by your competitors at any second, so don't
hesitate for a long time. The sooner you pay the ransom, the sooner
your company will be safe.

Visit the following URL using Tor Browser.

http://7b6x2ffenbdx3yns6atoe5bdyg6hzbw6kfpyoqjwp5iepmz5fwi6edqd.onion/confirm/?id=0000002c

Tor Browser: https://www.torproject.org/download/

For the researchers, this dummy ransomware is created for the contest MNCTF2024, please contact @Sh1n0g1 in X for details.

Torブラウザでhttp://7b6x2ffenbdx3yns6atoe5bdyg6hzbw6kfpyoqjwp5iepmz5fwi6edqd.onion/confirm/?id=0000002cにアクセスします。
…と言いたいところなのですが、2024/10/22現在アクセスできません。
他の方々のWriteup[1][2]にある通り、イベント当日はアクセスでき、攻撃者のビットコインアドレスが表示されていたようです。
正答:3QAdox1ZpNNuDkhfJGg4M9yGKYRiFxgRPv

1-4. OSINT - 取引所

ランサムウェアの犯人のBitcoinウォレットはどこの取引所のものであるかを調査してください。取引所の名前を答えてください。

通常、ウォレットアドレスから取引所を割り出すことは難しいのですが、ブロックチェーン分析プラットフォームで検索すると分かることがあります。
今回はArkhamにてウォレットアドレス3QAdox1ZpNNuDkhfJGg4M9yGKYRiFxgRPvを検索してみます。

https://platform.arkhamintelligence.com/

正答:bitFlyer

1-5. Binary - ホスト名のチェック

amrw.exeは特定の文字列がコンピュータ名に含まれていないと発動しないようです。その文字列は何か答えてください。

Windows上のGhidraでamrw.exeをデコンパイルし、Defined Stringsで「hostname」を検索します。
すると、関数FUN_140001d00にてgethostnameという文字列を確認できます。

ここで、関数FUN_140001d00のデコンパイル結果は以下の通りです。

void FUN_140001d00(void)

{
  int iVar1;
  undefined (*pauVar2) [16];
  undefined auStack_2e8 [32];
  uint local_2c8;
  uint local_2c4;
  WSADATA local_2b8;
  char local_118 [256];
  ulonglong local_18;
  
  local_18 = DAT_14002a778 ^ (ulonglong)auStack_2e8;
  iVar1 = WSAStartup(0x202,&local_2b8);
  if (iVar1 == 0) {
    iVar1 = gethostname(local_118,0x100);
    if (iVar1 == 0) {
      pauVar2 = FUN_140003580((undefined (*) [16])local_118,(undefined (*) [16])s_MAKUNIKI_14002a0a0
                             );
      local_2c8 = (uint)(pauVar2 != (undefined (*) [16])0x0);
      local_2c4 = local_2c8;
      WSACleanup();
    }
    else {
      perror(s_gethostname_14002a688);
      WSACleanup();
    }
  }
  FUN_1400026e0(local_18 ^ (ulonglong)auStack_2e8);
  return;
}

ホスト名とs_MAKUNIKI_14002a0a0として定義されている文字列を比較しているように見えます。
s_MAKUNIKI_14002a0a0の内容を確認すると、MAKUNIKIとなっています。

正答:MAKUNIKI

1-6. Cryptography - 復号1 パスワード

このファイルを復号して中のパスワードを答えてください。

問題にはCAD_Password.txt.amrwが添付されています。
http://7b6x2ffenbdx3yns6atoe5bdyg6hzbw6kfpyoqjwp5iepmz5fwi6edqd.onion/confirm/?id=0000002cに100バイト未満の.amrwファイルを復号する機能があるようなのですが、「1-3. Misc - ビットコイン」で触れた通り現在アクセスできません。
この先の「1-7. Binary - 暗号化アルゴリズム」と「1-A. Network - 暗号鍵」が解ければ、本問題も解くことができます。

解法

「1-7. Binary - 暗号化アルゴリズム」より暗号化アルゴリズムはRC4、「1-A. Network - 暗号鍵」より暗号鍵は9e688c523f5dea24513ef54848a136e7であることが分かります。
したがって、CyberChefにて復号することができます。

正答:k4QjB7giAKx9Z2H

1-7. Binary - 暗号化アルゴリズム

amrw.exeが利用している暗号化アルゴリズムを答えてください。

Windows上のGhidraでamrw.exeをデコンパイルし、Defined Stringsで「encrypt」を検索します。
すると、関数FUN_140001e70にてEncrypting %sという文字列を確認できます。

ここで、関数FUN_140001e70のデコンパイル結果は以下の通りです。

void FUN_140001e70(ulonglong *param_1)

{
  char cVar1;
  int iVar2;
  BOOL BVar3;
  char *pcVar4;
  ulonglong *puVar5;
  undefined auStack_4f8 [32];
  CHAR *local_4d8;
  int local_4c8;
  ulonglong local_4c0;
  HANDLE local_4b8;
  CHAR *local_4b0;
  ulonglong local_4a8;
  size_t local_4a0;
  char *local_498;
  ulonglong local_490;
  _WIN32_FIND_DATAA local_488;
  ulonglong local_348 [34];
  char local_238 [272];
  ulonglong local_128 [34];
  ulonglong local_18;
  
  local_18 = DAT_14002a778 ^ (ulonglong)auStack_4f8;
  local_4b8 = (HANDLE)0xffffffffffffffff;
  pcVar4 = s_%s\*.*_14002a6b4;
  puVar5 = param_1;
  _snprintf(local_238,0x104,s_%s\*.*_14002a6b4);
  local_4b8 = FindFirstFileA(local_238,&local_488);
  if (local_4b8 != (HANDLE)0xffffffffffffffff) {
    do {
      if ((local_488.dwFileAttributes & 0x10) == 0) {
        local_4b0 = local_488.cFileName;
        local_490 = 7;
        local_4c8 = 0;
        for (local_4c0 = 0; local_4c0 < local_490; local_4c0 = local_4c0 + 1) {
          local_498 = (&PTR_DAT_14002a030)[local_4c0];
          local_4a8 = strlen(local_4b0);
          local_4a0 = strlen(local_498);
          if ((local_4a0 <= local_4a8) &&
             (iVar2 = strcmp(local_4b0 + (local_4a8 - local_4a0),local_498), iVar2 == 0)) {
            local_4c8 = 1;
            break;
          }
        }
        if (local_4c8 != 0) {
          FUN_14000d650((longlong)local_348,param_1);
          FUN_14000d5b0(local_348,(ulonglong *)&DAT_14002a6c4);
          FUN_14000d5b0(local_348,(ulonglong *)local_4b0);
          printf(s_Encrypting:_%s_14002a6c8,local_348);
          cVar1 = FUN_1400018d0(PTR_s_1a2b3c4d5e6f708090a0b0c0d0e0f1a2_14002a0b0,(char *)local_348,
                                pcVar4,puVar5);
          if (cVar1 != '\0') {
            FUN_1400017c0((LPCSTR)local_348);
          }
        }
      }
      else {
        iVar2 = strcmp(local_488.cFileName,&DAT_14002a684);
        if ((iVar2 != 0) && (iVar2 = strcmp(local_488.cFileName,&DAT_14002a694), iVar2 != 0)) {
          local_4d8 = local_488.cFileName;
          pcVar4 = s_%s\%s_14002a6bc;
          puVar5 = param_1;
          _snprintf((char *)local_128,0x104,s_%s\%s_14002a6bc);
          FUN_140001e70(local_128);
        }
      }
      BVar3 = FindNextFileA(local_4b8,&local_488);
    } while (BVar3 != 0);
    FindClose(local_4b8);
  }
  FUN_1400026e0(local_18 ^ (ulonglong)auStack_4f8);
  return;
}

printf(s_Encrypting:_%s_14002a6c8,local_348);の直後にあるFUN_1400018d0が暗号化に使われている関数かもしれないと予想できるので、次は関数FUN_1400018d0のデコンパイル結果を見てみます。

void FUN_1400018d0(char *param_1,char *param_2,undefined8 param_3,undefined8 param_4)

{
  ulonglong uVar1;
  size_t sVar2;
  undefined auStack_178 [32];
  int local_158;
  FILE *local_150;
  LPVOID local_148;
  LPVOID local_140;
  char *local_138;
  int local_130 [2];
  FILE *local_128;
  undefined local_118 [256];
  ulonglong local_18;
  
  local_18 = DAT_14002a778 ^ (ulonglong)auStack_178;
  local_140 = FUN_140001820(param_1,local_130,param_3,param_4);
  FUN_140001570((longlong)local_118,(longlong)local_140,local_130[0]);
  local_150 = (FILE *)FUN_140004aa4(param_2,&DAT_14002a4f4);
  if (local_150 == (FILE *)0x0) {
    printf(s_Error_opening_file:_%s_14002a5d8,param_2);
    FUN_14000cf04(local_140);
  }
  else {
    FUN_140004fe0(local_150,0,2);
    uVar1 = common_ftell<long>(local_150);
    local_158 = (int)uVar1;
    FUN_140004fe0(local_150,0,0);
    local_148 = _malloc_base((longlong)local_158);
    fread(local_148,1,(longlong)local_158,local_150);
    fclose(local_150);
    FUN_140001680((longlong)local_118,(longlong)local_148,local_158);
    sVar2 = strlen(param_2);
    local_138 = (char *)_malloc_base(sVar2 + 5);
    sprintf(local_138,s_%s.amrw_14002a5f0,param_2);
    local_128 = (FILE *)FUN_140004aa4(local_138,&DAT_14002a5f8);
    if (local_128 == (FILE *)0x0) {
      perror(s_Error_creating_encrypted_file_14002a600);
      FUN_14000cf04(local_148);
      FUN_14000cf04(local_140);
      FUN_14000cf04(local_138);
    }
    else {
      fwrite(local_148,1,(longlong)local_158,local_128);
      fclose(local_128);
      FUN_14000cf04(local_148);
      FUN_14000cf04(local_140);
      FUN_14000cf04(local_138);
    }
  }
  FUN_1400026e0(local_18 ^ (ulonglong)auStack_178);
  return;
}

まだ暗号化アルゴリズムの特定までは至らないので、手当たり次第に関数の内容を見ていくと、関数FUN_140001680のデコンパイル結果がRC4の暗号化処理になっていることが分かります。

void FUN_140001680(longlong param_1,longlong param_2,int param_3)

{
  undefined uVar1;
  undefined4 local_24;
  undefined4 local_20;
  undefined4 local_1c;
  
  local_24 = 0;
  local_20 = 0;
  for (local_1c = 0; local_1c < param_3; local_1c = local_1c + 1) {
    local_24 = local_24 + 1 & 0xff;
    local_20 = local_20 + *(byte *)(param_1 + (int)local_24) & 0xff;
    uVar1 = *(undefined *)(param_1 + (int)local_24);
    *(undefined *)(param_1 + (int)local_24) = *(undefined *)(param_1 + (int)local_20);
    *(undefined *)(param_1 + (int)local_20) = uVar1;
    *(byte *)(param_2 + local_1c) =
         *(byte *)(param_2 + local_1c) ^
         *(byte *)(param_1 +
                  (int)((uint)*(byte *)(param_1 + (int)local_24) +
                        (uint)*(byte *)(param_1 + (int)local_20) & 0xff));
  }
  return;
}

正答:RC4

1-8. Cryptography - 復号2 議事録

M5-800 開発会議議事録 2024-06-19.txt.amrwを部分的に復号し、会議が行われた場所を回答してください。

問題にはM5-800 開発会議議事録 2024-06-19.txt.amrwが添付されています。
http://7b6x2ffenbdx3yns6atoe5bdyg6hzbw6kfpyoqjwp5iepmz5fwi6edqd.onion/confirm/?id=0000002cに100バイト未満の.amrwファイルを復号する機能がありますが、M5-800 開発会議議事録 2024-06-19.txt.amrwのファイルサイズは2,161バイトなので、そのままでは復号できません。
ここで、RC4はストリーム暗号であり(ブロック暗号と異なり)、平文を先頭から順次暗号化していく暗号化方式のため、M5-800 開発会議議事録 2024-06-19.txt.amrwの先頭99バイト分だけ切り出せば復号できそうです。
…が、「1-3. Misc - ビットコイン」で触れた通り、そもそも復号サイトには現在アクセスできません。
この先の「1-A. Network - 暗号鍵」が解ければ、本問題も解くことができます。

解法

「1-7. Binary - 暗号化アルゴリズム」より暗号化アルゴリズムはRC4、「1-A. Network - 暗号鍵」より暗号鍵は9e688c523f5dea24513ef54848a136e7であることが分かります。
したがって、CyberChefにて復号することができます。

正答:本社会議室

1-9. Cryptography - 復号3 実験データ

このファイルは実験データが入っています。幸いにも部分的にのみ暗号化されているようです。暗号化がされていない領域からデータを抽出し、復元してください。実験データに含まれている実験プロジェクト(Experiment Project)の名前を答えてください。

問題にはExperiment Data.tar.amrwが添付されています。
問題文から暗号化されていない領域があるようなので、stringsコマンドで意味のある文字列があるか確認してみます(長いため一部省略しています)。

$ strings Experiment\ Data.tar.amrw 

~省略~

docProps/app.xmlPK
Experiment_Data_Stainless_Steel.xlsx
0000777

~省略~

docProps/app.xmlPK
Experiment_Data_Steel.xlsx
0000777

~省略~

$

Experiment_Data_Stainless_Steel.xlsxExperiment_Data_Steel.xlsxが含まれているようなので、binwalkで抽出します。

$ binwalk Experiment\ Data.tar.amrw                           

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
8715          0x220B          Zip archive data, at least v2.0 to extract, compressed size: 1882, uncompressed size: 8394, name: xl/theme/theme1.xml
10646         0x2996          Zip archive data, at least v2.0 to extract, compressed size: 2362, uncompressed size: 19472, name: xl/styles.xml
13051         0x32FB          Zip archive data, at least v2.0 to extract, compressed size: 433, uncompressed size: 731, name: xl/sharedStrings.xml
13534         0x34DE          Zip archive data, at least v2.0 to extract, compressed size: 314, uncompressed size: 581, name: docProps/core.xml
14159         0x374F          Zip archive data, at least v2.0 to extract, compressed size: 411, uncompressed size: 784, name: docProps/app.xml
15520         0x3CA0          End of Zip archive, footer length: 22
15872         0x3E00          POSIX tar archive (GNU), owner user name: "nt_Data_Stainless_Steel.xlsx"
$ binwalk -e Experiment\ Data.tar.amrw

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
8715          0x220B          Zip archive data, at least v2.0 to extract, compressed size: 1882, uncompressed size: 8394, name: xl/theme/theme1.xml
10646         0x2996          Zip archive data, at least v2.0 to extract, compressed size: 2362, uncompressed size: 19472, name: xl/styles.xml
13051         0x32FB          Zip archive data, at least v2.0 to extract, compressed size: 433, uncompressed size: 731, name: xl/sharedStrings.xml
13534         0x34DE          Zip archive data, at least v2.0 to extract, compressed size: 314, uncompressed size: 581, name: docProps/core.xml
14159         0x374F          Zip archive data, at least v2.0 to extract, compressed size: 411, uncompressed size: 784, name: docProps/app.xml
15872         0x3E00          POSIX tar archive (GNU), owner user name: "nt_Data_Stainless_Steel.xlsx"

WARNING: One or more files failed to extract: either no utility was found or it's unimplemented
$

抽出されたExperiment_Data_Stainless_Steel.xlsxまたはExperiment_Data_Steel.xlsxを開くと、Experiment Projectが書いてあります。
正答:M5-800-J8CDPP

1-A. Network - 暗号鍵

やはら君はたまたまランサムウェアに感染したタイミングでパケットキャプチャを取っていた。
ransom_traffic.pcapng
パケットを解析し、暗号化鍵を答えてください。
ヒント)すべてのバイトがそのまま鍵とは限りません。

問題にはransom_traffic.pcapngが添付されています。
Wiresharkで見てみると、以下のHTTPリクエスト・レスポンスが記載されています。

GET /amrwc2/ HTTP/1.1
Connection: Keep-Alive
User-Agent: A WinHTTP Example Program/1.0
Host: amrwc2.angrymusu.me

HTTP/1.1 200 OK
Server: nginx/1.25.4
Date: Wed, 19 Jun 2024 02:28:52 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 40
Connection: keep-alive
X-Powered-By: PHP/8.1.29

0000002c9e688c523f5dea24513ef54848a136e7

次に、Windows上のGhidraでamrw.exeをデコンパイルし、Defined Stringsで「/amrwc2/」を検索します。
すると、関数FUN_140002190にてhttp://amrwc2.angrymusu.me/amrwc2/という文字列を確認できます。

ここで、関数FUN_140002190のデコンパイル結果は以下の通りです。

void FUN_140002190(void)

{
  undefined auStack_268 [32];
  int local_248;
  char *local_240;
  ulonglong local_238 [34];
  ulonglong local_128 [34];
  ulonglong local_18;
  
  local_18 = DAT_14002a778 ^ (ulonglong)auStack_268;
  local_248 = FUN_140001d00();
  if (local_248 == 1) {
    local_240 = (char *)FUN_140001000(PTR_s_http://amrwc2.angrymusu.me/amrwc_14002a000);
    printf(s_[*]_Downloaded_ID_and_Key%s_14002a708,local_240);
    FUN_1400014d0(local_240,(longlong *)&PTR_s_ffffffff_14002a0e8,
                  (longlong *)&PTR_s_1a2b3c4d5e6f708090a0b0c0d0e0f1a2_14002a0b0);
    printf(s_[*]_ID:%s_Key:%s_14002a728,PTR_s_ffffffff_14002a0e8,
           PTR_s_1a2b3c4d5e6f708090a0b0c0d0e0f1a2_14002a0b0);
    FUN_140001e20(local_238,0x104,local_128);
    printf(s_[*]_Desktop_Path:_%s_14002a740,local_238);
    printf(s_[*]_Documents_Path:_%s_14002a758,local_128);
    FUN_140001e70(local_238);
    FUN_140001e70(local_128);
    FUN_1400020d0(local_238,PTR_s_ffffffff_14002a0e8);
  }
  FUN_1400026e0(local_18 ^ (ulonglong)auStack_268);
  return;
}

HTTPレスポンスの内容(ransom_traffic.pcapngによると0000002c9e688c523f5dea24513ef54848a136e7)をlocal_240に格納し、関数FUN_1400014d0を実行した後にIDとKeyを表示しているようです。
関数FUN_1400014d0のデコンパイル結果は以下の通りです。

void FUN_1400014d0(char *param_1,longlong *param_2,longlong *param_3)

{
  LPVOID pvVar1;
  size_t sVar2;
  
  pvVar1 = _malloc_base(9);
  *param_2 = (longlong)pvVar1;
  sVar2 = strlen(param_1);
  pvVar1 = _malloc_base(sVar2 - 7);
  *param_3 = (longlong)pvVar1;
  strncpy((char *)*param_2,param_1,8);
  *(undefined *)(*param_2 + 8) = 0;
  FUN_14000d650(*param_3,(ulonglong *)(param_1 + 8));
  return;
}

引数param_1を前半8バイトと後半に分割し、それぞれをparam_2(ID)・param_3(Key)に格納しているようです。
したがって、0000002c9e688c523f5dea24513ef54848a136e7の前半8バイトのID部分を除いた9e688c523f5dea24513ef54848a136e7が暗号化鍵です。
正答:9e688c523f5dea24513ef54848a136e7

1-B. Cryptography - 復号4 ボーナス

2024年夏季賞与のお知らせ.docx.amrwファイルを復号して、やはら君のボーナスを答えてください。

問題には2024年夏季賞与のお知らせ.docx.amrwが添付されています。
「1-7. Binary - 暗号化アルゴリズム」より暗号化アルゴリズムはRC4、「1-A. Network - 暗号鍵」より暗号鍵は9e688c523f5dea24513ef54848a136e7であることが分かっています。
したがって、CyberChefにて復号することができます。

復号結果を2024年夏季賞与のお知らせ.docxとして保存し、ファイルを開くとボーナスが書いてあります。

正答:514,000

1-C. Binary - 暗号化対象のディレクトリ

暗号化対象のディレクトリは複数あるようです。検体の中の、パスを取得する関数の定数の数値を調べて、十進数で答えてください。
例、2,8

「1-A. Network - 暗号鍵」でも見た関数FUN_140002190のデコンパイル結果を再度確認します。

void FUN_140002190(void)

{
  undefined auStack_268 [32];
  int local_248;
  char *local_240;
  ulonglong local_238 [34];
  ulonglong local_128 [34];
  ulonglong local_18;
  
  local_18 = DAT_14002a778 ^ (ulonglong)auStack_268;
  local_248 = FUN_140001d00();
  if (local_248 == 1) {
    local_240 = (char *)FUN_140001000(PTR_s_http://amrwc2.angrymusu.me/amrwc_14002a000);
    printf(s_[*]_Downloaded_ID_and_Key%s_14002a708,local_240);
    FUN_1400014d0(local_240,(longlong *)&PTR_s_ffffffff_14002a0e8,
                  (longlong *)&PTR_s_1a2b3c4d5e6f708090a0b0c0d0e0f1a2_14002a0b0);
    printf(s_[*]_ID:%s_Key:%s_14002a728,PTR_s_ffffffff_14002a0e8,
           PTR_s_1a2b3c4d5e6f708090a0b0c0d0e0f1a2_14002a0b0);
    FUN_140001e20(local_238,0x104,local_128);
    printf(s_[*]_Desktop_Path:_%s_14002a740,local_238);
    printf(s_[*]_Documents_Path:_%s_14002a758,local_128);
    FUN_140001e70(local_238);
    FUN_140001e70(local_128);
    FUN_1400020d0(local_238,PTR_s_ffffffff_14002a0e8);
  }
  FUN_1400026e0(local_18 ^ (ulonglong)auStack_268);
  return;
}

printf(s_[*]_Desktop_Path:_%s_14002a740,local_238);の行でデスクトップのパス、printf(s_[*]_Documents_Path:_%s_14002a758,local_128);の行でドキュメントのパスをそれぞれ表示しているようです。
これらの直前にある関数FUN_140001e20のデコンパイル結果を見てみます。

void FUN_140001e20(undefined8 param_1,undefined8 param_2,undefined8 param_3)

{
  FUN_140001dc0(0,param_1);
  FUN_140001dc0(5,param_3);
  return;
}

さらに、関数FUN_140001dc0のデコンパイル結果も見てみます。

void FUN_140001dc0(undefined4 param_1,undefined8 param_2)

{
  int iVar1;
  FILE *_File;
  
  iVar1 = SHGetFolderPathA(0,param_1,0,0,param_2);
  if (iVar1 != 0) {
    _File = (FILE *)__acrt_iob_func(2);
    FID_conflict:fprintf(_File,(wchar_t *)s_Failed_to_get_folder_path._14002a698);
  }
  return;
}

どうやら関数FUN_140001dc0がパスを取得する関数のようです。
関数FUN_140001e20のデコンパイル結果から、関数FUN_140001dc0には定数05が設定されています。

正答:0,5

2. 単体問題

2-1. OSINT - Crypt Currency

株式会社マクニキは、ファン向けのトークンとしてSolanaブロックチェーン上でmacnicoin(単位:MAC)を10億MAC発行しました。しかし、2024年6月19日(日本時間)の昼間に、macnicoinの管理システムがハッキングされ、1億MACが盗まれる事件が発生しました。
この事件により、macnicoinの価格は大幅に暴落し、取引所から上場廃止されてしまいました。
あなたの任務は、このハッキング事件の犯人が使用したウォレットアドレスを特定することです。以下の情報を基に、犯人のウォレットアドレスを見つけ出してください。

事件発生日時: 2024年6月19日(日本時間)
盗まれたトークン: 1億MAC

問題文に「Solonaブロックチェーン」とあるので、SOLSCANでmacnicoinを検索してみます。

https://solscan.io/

2件の入出金が記録されていますが、Change Amount列が100,000,000となっている入出金のTo列の値が答えです。

正答:39KASe2peeYt3xDR9V1orp2tLe4jikPwLJVDs81f9GdB

2-2. OSINT - マルウェア特定

この暗号化されたファイルからマルウェアの名称を調査して答えてください。

問題にはsecret.docx.tkucというファイルが添付されています。
stringsコマンドで意味のある文字列が含まれているか確認します(長いため一部省略しています)。

$ strings secret.docx.tkuc 
WOW!THIS FILE HAS BEEN ENCRYPTED...
mO?<

~省略~

$

「WOW!THIS FILE HAS BEEN ENCRYPTED」でGoogle検索すると、これがLODEINFOというマルウェアの特徴であることが分かります。

https://blogs.jpcert.or.jp/ja/2021/02/LODEINFO-3.html

正答:LODEINFO

3. 内部犯行

6月12日昼過ぎ、CSIRTのてしがわら君のメールボックスに以下の通知が届いた。

件名:Alert: Confidential File Accessed from Outside the Network
本文:
Dear Customer,

We would like to inform you that a confidential file has been accessed from outside our network.
This unauthorized access was detected by our monitoring systems and is a matter of serious concern.

Details of the Access:

File Name: check the system
Access Time: check the system
Access Location: check the system
User Account: check the system
Immediate action is required to investigate this incident and ensure the security of our confidential information.
Please review the details and take appropriate measures to safeguard our data.

If you have any questions or need further assistance, please contact our IT security team immediately.

Thank you for your prompt attention to this matter.

Best regards,

Mintel Beacon Detector

  • 株式会社マクニキでは機密文書にカナリートークンが仕込まれている。
  • 誰かが機密文書を開くとHTTPリクエストが発生し、記録される。
  • マクニキ外のIPアドレスから通信が発生した場合、上記のような通知メールが届く。

調査を開始してください。

3-1. Steganography - カナリートークンの特定

てしがわら君はカナリートークンの仕組みをおさらいすることにした。 次々世代ねじ M5-800 素材注文書.docxに含まれているカナリートークンのURLを調べてください。

問題には次々世代ねじ M5-800 素材注文書.docxが添付されています。
最初はWordファイルの拡張子を.zipにして展開し、grep -r "http" .で格納されているファイルにURLが含まれているか調べようとしていました。
しかし、Microsoftのドメイン等関係ないURLが大量に検索に引っかかってしまったので、Canary Token Scannerを使いました。

https://github.com/0xNslabs/CanaryTokenScanner

$ python CanaryTokenScanner.py "次々世代ねじ M5-800 素材注文書.docx"
CanaryTokenScanner.py:18: SyntaxWarning: invalid escape sequence '\s'
  urls = re.findall(b'https?://[^\s<>"\'{}|\\^`]+', decompressed_data)
CanaryTokenScanner.py:27: SyntaxWarning: invalid escape sequence '\s'
  streams = re.findall(b'stream[\r\n\s]+(.*?)[\r\n\s]+endstream', pdf_content, re.DOTALL)
URL Found in 次々世代ねじ M5-800 素材注文書.docx:
https://task.mnctf.info/mintel_beacon_receiver/draw.php?id=M5-800%20Order"
The file 次々世代ねじ M5-800 素材注文書.docx is suspicious.
$

正答:https://task.mnctf.info/mintel_beacon_receiver/draw.php?id=M5-800%20Order

3-2. Forensics - 外部に漏れた文書の特定

てしがわら君は外部に漏れた文書を特定することにした。
カナリートークン監視サイト:Mintel Beacon Detector
機密文書の情報:機密文書DB.xlsx
最初にカナリートークンが発信された文書のファイル名(拡張子あり)を答えてください。

問題には機密文書DB.xlsxが添付されています。
カナリートークン監視サイトにアクセスし、問題文にある通り2024/06/12昼頃のアクセスログを見てみます。

Date IP Address User-Agent ID Whois
2024-06-12 12:11:12 232.141.110.70 Mozilla/4.0 (compatible; ms-office; MSOffice rmj) MS-1000 Order Makuniki Inc

Whois列がMakuniki Incとなっているので、これではなさそうです。
もしかしてアクセスログはUTC+0000なのか…?と思い、少し前に遡るとWhois列がマクニキ以外になっている行を発見できました。

Date IP Address User-Agent ID Whois
2024-06-12 04:45:12 245.6.11.3 Mozilla/4.0 (compatible; ms-office; MSOffice 16) M5-30 Jerk Industry
2024-06-12 04:47:12 245.6.11.3 Mozilla/4.0 (compatible; ms-office; MSOffice 16) M5-800 Order Jerk Industry
2024-06-12 04:52:12 245.6.11.3 Mozilla/4.0 (compatible; ms-office; MSOffice 16) M5-60 Mk II Jerk Industry

機密文書DB.xlsxを開き、IDM5-30に対応するファイル名を調べると次々世代ねじ M5-30 設計書.docxであることが分かります。
正答:次々世代ねじ M5-30 設計書.docx

3-3. Forensics - アクセス者

機密文書はすべて「Hako」というクラウドストレージに格納されている。
てしがわら君はHakoのアクセスログを調査し、漏洩したファイルにアクセスしたユーザを特定することにした。 Hakoのアクセスログを調査し、ユーザ名を答えてください。

問題にはHako_access_logs.jsonが添付されています。
「3-2. Forensics - 外部に漏れた文書の特定」より、2024-06-12 04:45:12に初めて次々世代ねじ M5-30 設計書.docxのカナリートークンが発信されたので、その直前のアクセス者が答えです。

Hako_access_logs.json
{
  "username": "suzuki",
  "filename": "次々世代ねじ M5-30 設計書.docx",
  "access_time": "2024-06-11 14:08:25"
}

正答:suzuki

3-4. Forensics - EDRのログ

てしがわら君は、Hakoからダウンロードしたファイルの行方を追うために、
すずき君の端末のEDRのログを調べてみることにした。
EDRのログを調査し、機密文書がどこに保存されたのかを調べてください。
答えはファイル名を除くパスとなります。
例)C:\Users\suzuki\Desktop\

問題にはedr_logs.csvが添付されています。
以下の条件で絞ってみます。

  • Type列:file write
  • File列:M5-30を含む
Datetime Type File Process User
2024/5/19 7:28 file write C:\Users\suzuki\Documents\谺。縲・ク紋サ」縺ュ縺・M5-30 險ュ險域嶌.docx winword.exe suzuki
2024/5/27 6:26 file write C:\Users\suzuki\Documents\谺。縲・ク紋サ」縺ュ縺・M5-30 險ュ險域嶌.docx winword.exe suzuki
2024/6/3 4:02 file write C:\Users\suzuki\Documents\谺。縲・ク紋サ」縺ュ縺・M5-30 險ュ險域嶌.docx winword.exe suzuki
2024/6/11 14:08 file write E:\USBDRIVE\谺。縲・ク紋サ」縺ュ縺・M5-30 險ュ險域嶌.docx chrome.exe suzuki

最終行のE:\USBDRIVE\が答えです。
正答:E:\USBDRIVE\

3-5. Misc - 尋問

てしがわら君は出揃った情報を使って、すずき君を尋問することにした。
すずき君に証拠を突き付けて、自供をさせてください。
尋問部屋

尋問部屋にアクセスすると、対話型AIであるすずき君との逆転裁判的なやり取りを繰り広げることになります。



正答:MNCTF{Insider_threats}

脚注
  1. https://blog.hamayanhamayan.com/entry/2024/06/21/204346#1-3-ビットコイン ↩︎

  2. https://qiita.com/H4ppyR41nyD4y/items/8a3f091263c74cbfbfc6#攻撃者のbitcoinウォレットは ↩︎

Discussion