All Articles

CTFZone 2023 Writeup

8/12 から開催されていた CTFZone に出場していました。

image-20230818111048893

今回はほとんど解けずで残念でしたが、いつも通り復習を兼ねて Writeup を書きます。

もくじ

strcmp(Rev)

You can solve easy tasks, but do you understand how functions work?

問題バイナリとして与えられた PE を実行すると、以下のような文字入力を求める GUI アプリケーションが起動しました。

ここで誤ったパスワードを入力した場合、警告ダイアログが表示されます。

image-20230812190715251

とりあえず検証の処理がどうなっているのかを調べてみたところ、以下のようなシンプルな実装でした。

image-20230812190649465

デコンパイル結果を見てわかる通り、入力した文字列と param2 の値を lstrcmpA で単純比較する処理を行っていることがわかります。

これなら動的解析で Flag を余裕で取得できる、とデバッガを仕掛けてみたところ、それっぽい文字列が引数のメモリ領域から取得できました。

image-20230818182056429

しかし、上記の文字列では何度やっても正しい入力値として検証をパスできません。

そこで、 lstrcmpA の呼び出し先についてさらに深く見てみることにしました。

すると、以下のようにライブラリ関数呼び出しのためのテーブル情報が改ざんされており、lstrcmpA を呼び出した際に実際にジャンプするアドレスがオフセット 0x1003 の関数になっていることがわかりました。

image-20230818185726355

デバッガ上でも、実際にこのオフセットの関数にジャンプすることを確認できます。

image-20230818190736774

オフセット 0x1003 の関数のデコンパイル結果を Ghidra で取得したところ、以下のようにハードコードされたバイト値を 0x6c で XOR した結果と入力値を比較していることがわかりました。

int FUN_00401003(char *param_1,undefined4 param_2)
{
  int iVar1;
  int iVar2;
  undefined2 *puVar3;
  undefined2 local_1c;
  undefined4 local_1a;
  undefined local_16;
  undefined4 local_15;
  undefined local_11;
  undefined4 local_10;
  undefined4 local_c;
  undefined4 local_8;
  
  iVar2 = 0;
  local_c = 0x5c043329;
  local_1a = 0x580f3339;
  iVar1 = 0;
  local_15 = 0x25d2a33;
  local_8 = 0x1f075c;
  local_10 = 0x15c4833;
  local_11 = 0x28;
  local_1c = 0x335;
  local_16 = 0x22;
  do {
    *(byte *)((int)&local_1c + iVar1) = *(byte *)((int)&local_1c + iVar1) ^ 0x6c;
    iVar1 = iVar1 + 1;
  } while (iVar1 < 0x17);
  puVar3 = &local_1c;
  if (*param_1 == (char)local_1c) {
    do {
      if (0x16 < iVar2) break;
      puVar3 = (undefined2 *)((int)puVar3 + 1);
      iVar2 = iVar2 + 1;
    } while (param_1[iVar2] == *(char *)puVar3);
    if ((iVar2 == 0x17) && (*(char *)puVar3 == '\0')) {
      return 0;
    }
  }
  iVar1 = (*DAT_00451eb0)(param_1,param_2);
  if (iVar1 == 0) {
    iVar1 = -1;
  }
  return iVar1;
}

Solver を書いてもいいですが、面倒だったのでそのままデバッガで検証を行う処理にブレークポイントをセットし、以下のように正しい Flag を取得することができました。

image-20230812190413085

Rans00kit(Forensic)

An international company has been attacked. One of the computers has been hacked with the BlueKeep exploit. The attacker was able to gain a foothold in the system using a ring0 rootkit and has encrypted several important files. Your target: Bypass the rootkit, write a decryptor and find the flag.

Password for windows account login: ctfzone

問題バイナリとして OVA ファイルが与えられます。

Virtual Box で起動するとロシア語がシステム言語に設定されている Windows 7 のマシンでした。

ロシア語表示に苦戦しながら一通り端末内の探索を行ったものの、ring0 rootkit に関連すると思われるファイルや痕跡はありませんでした。

イベントログもクリアされており、調査は困難でした。

ring0 rootkit とのことで OS 内部で隠蔽されているのかと思いデバッガを仕掛けようと思ったのですが、デバッグモードを有効化して再起動すると OS が起動しなくなってしまうため断念しました。

Rootkit を見つけるために、以下のコマンドでファイルを VHDX に変換してローカルマウントします。

mv Ransookit.ova Ransookit.tar
tar -xvf Ransookit.tar
qemu-img convert -f vmdk -O vhdx Ransookit-disk1.vmdk out.vhdx

参考:NahamCon 2023 Writeup - かえるのひみつきち

続いて、マウントしたフォルダに対して Defender のスキャンをかけてみたところ、以下の 2 つのファイルが検知されました。

  • C:\Program Files\VMware\VMware Tools\VMware VGAuth\agony.sys
  • C:\Program Files\VMware\VMware Tools\VMware VGAuth\VGAuthCGI.exe

image-20230818094924045

端末を探索していた時に C:\Program Files\VMware\VMware Tools\VMware VGAuth\ 配下のモジュールは明らかに怪しい感じがあったのですが(言い訳)、普通に VMWare の署名がついてたのでスルーしてしまってました。

確かに改めて見てみると、この 2 ファイルだけ隠しファイルに設定されている上に署名がついていないファイルでした。

image-20230818100900910

このバイナリを実行してみたところ、Agony rootkit という古い rootkit のプログラムであることがわかります。

image-20230818104447925

Ghidra でデコンパイルすると、同梱されている agony.sys をシステムにインストールした上で、プロセスやファイルの隠蔽などの操作を実行できる Malware であることがわかります。

処理を追っていくと、システムにインストールしたドライバ agony.sys のハンドルを取得し、DeviceIoControl でドライバに対して命令を発行しています。

image-20230818165611086

この命令によって agony.sys がファイルやプロセスを隠蔽するようです。

しかし、問題文を読むと、何らかの Malware が重要なファイルを暗号化したと記載されていますが、agony.sys の処理を探してもファイルの暗号化を行うような処理は見当たらず、少し行き詰りました。

ただ、予想ですがこの rootkit によって隠蔽された Malware によって暗号化が行われているのではと考え、agony.sys と同様に隠しファイルに設定されているファイルをマウントしたディスクから探すことにしました。

その結果、aliasStore というファイルと、暗号化されたファイルと見られる VGAuth.sys.config が見つかりました。

image-20230818172431665

aliasStore は .NET バイナリでしたので、ILSpy でデコンパイルしていきます。

Main 関数を見ると、KEYGEN 関数で生成したランダムなキーを Software\Wow6432Node\Microsoft\Active Setup\Status の INFO に埋めていることがわかります。

image-20230818173417212

続けて ENCRYPTION 関数ですが、ここでは GETCIPHERKEY として受け取った文字列の SHA256 をキーとして CIPHER 関数を呼び出し、Key と IV を生成することで AES の CBC モードでの暗号化を行っています。

image-20230818173538270

つまり、レジストリから収集した情報を利用することで、Key と IV を特定して暗号化されたファイルを復号できるというわけです。

レジストリハイブから収集した INFO の文字列と、ILSpy でデコンパイルした結果をそのまま流用し、以下の Solver スクリプトを作成しました。

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using Microsoft.Win32;

public class Solver
{
    public static void Main()
    {
        string INFO = "HF48K!SP%hHudfQrk?*wvYvn*F-$DrooyKUdie0ZcY82OR%bW6$Mbk15hR?E@bLZ/q(TL!IGTmTXm/ZtKtqU0bNNfl(RgwjAMj9uWyQjy7)*QeTo/b)T8+wnc4*x+$wuCTKDF1XjcHs/iY&ASeYF2PPV9WSo9qr7KV9?UPjOEg+0V3ED7!fkpr+!E@Q6i5w8m84Nm=3C(KBVYl=GRO3=LHSqd-)e-z2V7FNj-+o8Hcpfqtlp$KpUCxxfqO6nFYDSe3lTXmHZx%/6p9A7kbo!KiSJe5)6HA25YWA!HSRaCPtH5+@3O=D16PH(kb*ptXSxPJhS8NzSJN8(@Lbn)MsI?B-IOFZ2dz41&&/vgt%AW7rseMGZAXvg2K0NKZD3!&*hgG-/S2HWRs8Mgd0C-A2FDY=9T1lHpONZ&KMYONGUQYPKYn34vB4!R6dHHLwoR=3DeiQWQc*7)i*1J@l2?3jogZIN3EQCopCRsM2$XhoSN&)5%y-Rx%qlnPtFZCpLL8TbguJ?KvenPQbjgZSFF=cu=n1cpxnU+cGb0oZXoBHBmCWW*Kv=7kFMgwc/)4ekIJw9K=6+A(nE/aH&ReofBnkdX%(DMhd7uu)dcjM*a3=*?BUFpfxlQ=isvSmQE22po2hVg1q5SzEUnvgVw$l37/ruLY4K?&7vBhXRr=v**+Tn%OEA9QqOR-4wL9JI&g8V+gSFYP1xRx//vDz?T3Y3dtdDzxF5@n+fG?wl(-ztl/&rG@AIJM*PIE/UCPdxJ&715k9xeOCVE1Rkx9?!x?v0zyWCEbj2sBkpHS8tCZ0(JqKe9fuPSq=MXHCGN7tD2W0CQzceBb7XU0qJn/Pw3TjBBYRAQ1fS3xQ!@INKCPO+5z/un)qVs&Wi!yA/hcOW(pqtk3Tf1FtnFsSZgujXLKx7a4AOHVzxB+&QJVJ7wKqmZ6dSfyj!/+L8+6T23EYgc&mNvCQLkzxArKhqb46g8@4J2LZZBdDs9JKdUPtdiYZQRKR4Z0b-V/unOchk0$JGvEOh=DWLLc?kmn/s%rAYCFW%luO/4I0rOSsM&64VdP9/%KAyj@qI$8Ep4T(c*deDzdWT(2vK!2%9SdAbtnf/or1dODez!bgA86Qn!324QgUK$SWbTr5Y-mlHy)F/X&WiV%AjNjo$7yyIWqm(3DfTsICWUI*%x!gUJ9@&R!N7C/nW!d8IeKLUnC@N+1PFuuP&Se-k1p1)$vQ0s2i$X3mnzL3H&yEmuHMfzqEgeXd@gSd/8MsMTY5+HzUGx+oCkOV6i8BByBj=ZxGg5*V7G/TWYVY=V?5n5bcS?ugALqlR@5ogs*Y9t4(r%-hNjB30S&R-V*iKfUvneChp3+ehw&)Bf7X-NSnK98-)oqL3cNeYIfN/o+hstWDWCPqlok?M3l0tDoBN3xEips/=tfhV8(nn4z$Y=xP/QRrt1r*=$T*&Rr4gXq+ICza7-N*bxzNFhMSXBWVBqhfoGrVM(hBg5H@o+6un3kZOG6lEYhfAU@psT91e+ygPx3WaX1gRy4VFHQiXFR*kBAL/oTUEFQwEEJnZjL4tANZnrjkCbdZx!(Nwse8DhbMiIRA-0I*%jRj*yvYF6R0y+-QJ($4FZ0LwB+fZimZSpeNtiZ-&F3UQxkrJA+C9a5r5F!97Q-tT+hJj8uys/7=tg(=oXVZrkm/6!eounO3GKAZPaHYdPg%p5?ZK!Vk%wB6bpZvdFDF1D)jft7NP?(cEsZA@Fe7R19hIR?xBj%XMaQl@l)oDHU&0w26PY5XyT!=RjaNvKM2DuQ0c!LbL@3Jg$3jmOhz0tv)mQUdL3/)(p)GgBdbNeM8m0qa2$yhzkCg-WNMq4Pf?!O+?xDk7FlVh!d8w)xUEiQimjHJ!R8fO3*zmzdF!Nxu-3-L)bmwH(amt2bkq%wpTGG0-1W?nsh+7tk5k(Pj2MYTcYF6X)m/nHa/xUNOFoImlj1ASs=u1N9G5!XwwmxuFob0SsIP4BdOD94)uFo1)+NZUTJ!?npq+lg&IB4xk6$07vD(FeCr-(1NaBf-iVSRi!Wpc78tX+RJBkpwQ";
        byte[] array = null;
        byte[] salt = new byte[1648]
        {
            180, 0, 176, 3, 205, 16, 180, 11, 183, 0,
            179, 4, 205, 16, 235, 0, 190, 102, 0, 232,
            60, 0, 190, 185, 0, 232, 54, 0, 190, 2,
            1, 232, 48, 0, 190, 85, 1, 232, 42, 0,
            235, 0, 190, 72, 3, 232, 34, 0, 191, 132,
            3, 180, 0, 205, 22, 180, 14, 60, 13, 116,
            7, 205, 16, 136, 5, 71, 235, 239, 198, 5,
            0, 160, 132, 3, 190, 100, 3, 232, 2, 0,
            235, 216, 180, 14, 183, 0, 179, 7, 138, 4,
            60, 0, 116, 7, 205, 16, 131, 198, 1, 235,
            243, 195, 45, 45, 45, 45, 45, 45, 45, 45,
            45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
            45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
            45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
            45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
            45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
            45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
            45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
            45, 45, 10, 13, 0, 32, 32, 32, 32, 32,
            32, 32, 32, 79, 111, 111, 111, 111, 112, 115,
            33, 32, 89, 111, 117, 114, 32, 115, 121, 115,
            116, 101, 109, 32, 104, 97, 118, 101, 32, 98,
            101, 101, 110, 32, 101, 110, 99, 114, 121, 112,
            116, 101, 100, 32, 98, 121, 32, 67, 82, 89,
            76, 73, 78, 69, 32, 82, 65, 78, 83, 79,
            77, 87, 65, 82, 69, 10, 13, 0, 45, 45,
            45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
            45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
            45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
            45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
            45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
            45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
            45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
            45, 45, 45, 45, 45, 45, 45, 45, 10, 13,
            0, 32, 84, 104, 101, 32, 104, 97, 114, 100,
            32, 100, 114, 105, 118, 101, 32, 111, 102, 32,
            121, 111, 117, 114, 32, 99, 111, 109, 112, 117,
            116, 101, 114, 32, 104, 97, 118, 101, 32, 98,
            101, 101, 110, 32, 101, 110, 99, 114, 121, 112,
            116, 101, 100, 32, 119, 105, 116, 104, 32, 97,
            110, 32, 109, 105, 108, 105, 116, 97, 114, 121,
            32, 103, 114, 97, 100, 101, 10, 13, 32, 101,
            110, 99, 114, 121, 112, 116, 105, 111, 110, 32,
            97, 108, 103, 111, 114, 105, 116, 104, 109, 46,
            32, 84, 104, 101, 114, 101, 32, 105, 115, 32,
            110, 111, 32, 119, 97, 121, 32, 116, 111, 32,
            114, 101, 115, 116, 111, 114, 101, 32, 121, 111,
            117, 114, 32, 100, 97, 116, 97, 32, 119, 105,
            116, 104, 111, 117, 116, 32, 97, 32, 115, 112,
            101, 99, 105, 97, 108, 10, 13, 32, 101, 110,
            99, 114, 121, 112, 116, 105, 111, 110, 32, 107,
            101, 121, 33, 32, 89, 111, 117, 32, 99, 97,
            110, 32, 112, 117, 114, 99, 104, 97, 115, 101,
            32, 116, 104, 105, 115, 32, 101, 110, 99, 114,
            121, 112, 116, 105, 111, 110, 32, 107, 101, 121,
            32, 111, 110, 32, 116, 104, 101, 32, 84, 101,
            108, 101, 103, 114, 97, 109, 32, 112, 97, 103,
            101, 10, 13, 32, 115, 104, 111, 119, 110, 32,
            105, 110, 32, 116, 104, 101, 32, 110, 101, 120,
            116, 32, 115, 116, 101, 112, 58, 32, 10, 13,
            32, 10, 13, 32, 32, 32, 49, 46, 32, 83,
            105, 103, 110, 32, 117, 112, 32, 105, 110, 32,
            116, 104, 101, 32, 84, 101, 108, 101, 103, 114,
            97, 109, 32, 97, 116, 32, 34, 104, 116, 116,
            112, 115, 58, 47, 47, 116, 101, 108, 101, 103,
            114, 97, 109, 46, 111, 114, 103, 47, 34, 46,
            32, 73, 116, 32, 115, 111, 32, 101, 97, 115,
            121, 33, 10, 13, 32, 32, 32, 50, 46, 32,
            87, 114, 105, 116, 101, 32, 116, 111, 32, 116,
            104, 101, 32, 117, 115, 101, 114, 32, 64, 68,
            97, 114, 120, 105, 115, 32, 97, 98, 111, 117,
            116, 32, 116, 104, 105, 115, 32, 105, 110, 99,
            105, 100, 101, 110, 116, 10, 13, 32, 32, 32,
            51, 46, 32, 87, 114, 105, 116, 101, 32, 116,
            104, 101, 32, 114, 101, 99, 101, 105, 118, 101,
            100, 32, 101, 110, 99, 114, 121, 112, 116, 105,
            111, 110, 32, 107, 101, 121, 32, 104, 101, 114,
            101, 10, 13, 32, 10, 13, 32, 73, 102, 32,
            121, 111, 117, 32, 97, 108, 114, 101, 97, 100,
            121, 32, 112, 117, 114, 99, 104, 97, 115, 101,
            100, 32, 121, 111, 117, 114, 32, 107, 101, 121,
            44, 32, 112, 108, 101, 97, 115, 101, 32, 101,
            110, 116, 101, 114, 32, 105, 116, 32, 98, 101,
            108, 111, 119, 33, 10, 13, 32, 10, 13, 0,
            32, 69, 110, 116, 101, 114, 32, 116, 104, 101,
            32, 100, 101, 99, 114, 121, 112, 116, 105, 111,
            110, 32, 107, 101, 121, 58, 32, 0, 32, 32,
            61, 62, 32, 69, 114, 114, 111, 114, 33, 32,
            73, 110, 118, 97, 108, 105, 100, 32, 107, 101,
            121, 32, 118, 97, 108, 117, 101, 10, 13, 0,
            32, 205, 16, 235, 0, 190, 201, 105, 118, 101,
            46, 46, 0, 232, 2, 0, 235, 20, 180, 14,
            183, 0, 179, 7, 138, 4, 60, 0, 116, 7,
            205, 16, 131, 198, 1, 235, 243, 195, 181, 0,
            182, 0, 177, 7, 187, 0, 32, 142, 195, 187,
            0, 0, 180, 2, 176, 128, 205, 19, 187, 172,
            232, 190, 0, 0, 38, 1, 52, 38, 192, 36,
            4, 137, 216, 38, 246, 36, 38, 1, 28, 38,
            192, 44, 2, 38, 41, 52, 137, 240, 38, 246,
            36, 38, 1, 20, 38, 208, 36, 70, 131, 254,
            255, 117, 217, 187, 0, 32, 142, 195, 187, 0,
            0, 180, 3, 176, 128, 205, 19, 254, 193, 128,
            249, 63, 117, 176, 254, 198, 128, 254, 65, 117,
            167, 190, 247, 2, 232, 137, 255, 254, 197, 128,
            253, 5, 117, 152, 235, 0, 187, 0, 128, 142,
            195, 187, 0, 0, 180, 2, 176, 1, 182, 0,
            181, 0, 177, 6, 205, 19, 114, 234, 235, 0,
            187, 0, 128, 142, 195, 187, 0, 0, 180, 3,
            176, 1, 182, 0, 181, 0, 177, 1, 205, 19,
            114, 234, 234, 0, 0, 255, 255, 87, 105, 110,
            100, 111, 119, 115, 32, 104, 97, 115, 32, 101,
            110, 99, 111, 117, 110, 116, 101, 114, 101, 100,
            32, 97, 32, 112, 114, 111, 98, 108, 101, 109,
            32, 99, 111, 109, 109, 117, 110, 105, 99, 97,
            116, 105, 110, 103, 32, 119, 105, 116, 104, 32,
            97, 32, 100, 101, 118, 105, 99, 101, 32, 99,
            111, 110, 110, 101, 99, 116, 101, 100, 32, 116,
            111, 32, 121, 111, 117, 114, 32, 99, 111, 109,
            112, 117, 116, 101, 114, 46, 32, 10, 13, 84,
            104, 105, 115, 32, 101, 114, 114, 111, 114, 32,
            99, 97, 110, 32, 98, 101, 32, 99, 97, 117,
            115, 101, 100, 32, 98, 121, 32, 117, 110, 112,
            108, 117, 103, 103, 105, 110, 103, 32, 97, 32,
            114, 101, 109, 111, 118, 97, 98, 108, 101, 32,
            115, 116, 111, 114, 97, 103, 101, 32, 100, 101,
            118, 105, 99, 101, 32, 115, 117, 99, 104, 32,
            97, 115, 32, 97, 110, 32, 32, 32, 32, 101,
            120, 116, 101, 114, 110, 97, 108, 32, 85, 83,
            66, 32, 100, 114, 105, 118, 101, 32, 119, 104,
            105, 108, 101, 32, 116, 104, 101, 32, 100, 101,
            118, 105, 99, 101, 32, 105, 115, 32, 105, 110,
            32, 117, 115, 101, 44, 32, 111, 114, 32, 98,
            121, 32, 102, 97, 117, 108, 116, 121, 32, 104,
            97, 114, 100, 119, 97, 114, 101, 32, 115, 117,
            99, 104, 32, 97, 115, 32, 97, 32, 32, 104,
            97, 114, 100, 32, 100, 114, 105, 118, 101, 32,
            111, 114, 32, 67, 68, 45, 82, 79, 77, 32,
            100, 114, 105, 118, 101, 32, 116, 104, 97, 116,
            32, 105, 115, 32, 102, 97, 105, 108, 105, 110,
            103, 46, 32, 89, 111, 117, 32, 109, 97, 121,
            32, 99, 97, 110, 99, 101, 108, 32, 116, 104,
            101, 32, 100, 114, 105, 118, 101, 32, 99, 104,
            101, 99, 107, 44, 32, 98, 117, 116, 32, 105,
            116, 32, 105, 115, 32, 115, 116, 114, 111, 110,
            103, 108, 121, 32, 114, 101, 99, 111, 109, 109,
            101, 110, 100, 101, 100, 32, 116, 104, 97, 116,
            32, 121, 111, 117, 32, 99, 111, 110, 116, 105,
            110, 117, 101, 46, 32, 10, 13, 32, 10, 13,
            73, 102, 32, 121, 111, 117, 32, 99, 111, 110,
            116, 105, 110, 117, 101, 32, 116, 111, 32, 114,
            101, 99, 101, 105, 118, 101, 32, 116, 104, 105,
            115, 32, 116, 104, 105, 115, 32, 101, 114, 114,
            111, 114, 32, 109, 101, 115, 115, 97, 103, 101,
            44, 32, 119, 97, 105, 116, 32, 102, 111, 114,
            32, 116, 104, 101, 32, 104, 97, 114, 100, 32,
            100, 114, 105, 118, 101, 32, 32, 32, 32, 32,
            99, 104, 101, 99, 107, 32, 116, 111, 32, 102,
            105, 110, 105, 115, 104, 32, 97, 110, 100, 32,
            99, 111, 110, 116, 97, 99, 116, 32, 116, 104,
            101, 32, 104, 97, 114, 100, 119, 97, 114, 101,
            32, 109, 97, 110, 117, 102, 97, 99, 116, 117,
            114, 101, 114, 46, 10, 13, 32, 10, 13, 87,
            105, 110, 100, 111, 119, 115, 32, 119, 105, 108,
            108, 32, 110, 111, 119, 32, 99, 104, 101, 99,
            107, 32, 116, 104, 101, 32, 100, 114
        };

        byte[] GET_CIPHER_KEY = Encoding.UTF8.GetBytes(INFO);
		GET_CIPHER_KEY = SHA256.Create().ComputeHash(GET_CIPHER_KEY);

        using MemoryStream memoryStream = new MemoryStream();
        using RijndaelManaged rijndaelManaged = new RijndaelManaged();
        Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(GET_CIPHER_KEY, salt, 4096);
        rijndaelManaged.KeySize = 256;
        rijndaelManaged.BlockSize = 128;
        rijndaelManaged.Key = rfc2898DeriveBytes.GetBytes(rijndaelManaged.KeySize / 8);
        rijndaelManaged.IV = rfc2898DeriveBytes.GetBytes(rijndaelManaged.BlockSize / 8);

        Console.WriteLine(BitConverter.ToString(rijndaelManaged.Key));
        Console.WriteLine(BitConverter.ToString(rijndaelManaged.IV));
    }
}

これを適当なオンラインコンパイラなどで実行すると、Key と IV を取得できます。

最後に、抽出した Key と IV を使用して、暗号化されたファイルを復号しました。

image-20230818181059216

復号されたデータは PE バイナリでしたので、これを実行、、ではなく単純に strings にかけてみたところ Flag を取得できました。

image-20230818180756359

また、後日以下の Writeup を参照したところ、中々含蓄のある画像が貼られていました。

img

参考:CTFzonequals2023/Rans00kit.md at main · hoanga2dtk68/CTFzonequals2023

今回の問題についてはどうやらファイルシステムのどこかにオリジナルの Flag の生データを含む情報が残されたままになっていたようで、以下のように vmdk ファイルを展開したファイルに対して文字列検索をかけるだけでも Flag を取得できたようです。

# rustup install stable && cargo install ripgrep --features 'pcre2'
7z x Ransookit-disk1.vmdk
rg -aloP 'ctfzone{.{1,100}}' 1.ntfs

このあたりはテクニックとして覚えておきたいところですね。

まとめ

最近 Rev の Writeup が全く見つからなくて復習ができないことが多いのでつらい。。