DEADFACE CTF 2023 Writeup

この大会は2023/10/20 23:00(JST)~2023/10/22 11:00(JST)に開催されました。
今回もチームで参戦。結果は1860点で1107チーム中172位でした。
自分で解けた問題をWriteupとして書いておきます。

Starter 1 (Starter 5)

ルールのページの最下部にフラグが書いてあった。

flag{I_acknowledge_the_rules}

Starter 2 (Starter 5)

Ghost Townで"Where to even get started"というタイトルの投稿を検索する。投稿を開始したのはdaem0nで、5月18日。

flag{daem0n_0518}

Aurora Compromise (SQL 10)

sqlファイルのデータをMySQL環境に入れる。

$ mysql -u root -p -e "CREATE DATABASE IF NOT EXISTS aurora"
Enter password: 

$ mysql -u root -p -D aurora < aurora.sql
Enter password: 

Hansons Terraceという通りに住んでいる患者の姓名を答える問題。
PDFのデータベースの設計を見る。
patientsテーブルに以下のカラムがあるので、条件を指定して検索する。

・first_name
・last_name
・street
$ mysql -u root -p aurora                
Enter password: 
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 10
Server version: 10.11.4-MariaDB-1 Debian 12

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [aurora]> select first_name, last_name, street from patients where street like '%Hansons Terrace%';
+------------+-----------+-----------------------+
| first_name | last_name | street                |
+------------+-----------+-----------------------+
| Sandor     | Beyer     | 20263 Hansons Terrace |
+------------+-----------+-----------------------+
1 row in set (0.003 sec)
flag{Sandor Beyer}

Credit Compromise (SQL 15)

流出したクレジットカードの枚数を答える問題。
billingテーブルにcard_numのカラムがあり、このレコード数が求める答え。

MariaDB [aurora]> select count(*) from billing;
+----------+
| count(*) |
+----------+
|    10391 |
+----------+
1 row in set (0.002 sec)
flag{10391}

Starypax (SQL 50)

2023 年 10 月 20 日の時点で、Starypax の有効な処方箋を持つ患者の人数と、最も早く処方箋が期限切れになる患者の姓名を答える問題。
drugsテーブルにdrug_numのカラムがあり、それと紐づくprescriptionsテーブルから該当するpatient_idを絞る。その中で最もexpirationが早いpatient_idに該当する患者について、patientsテーブルからその患者の姓名を取得する。

MariaDB [aurora]> select drug_id from drugs where drug_name = 'Starypax';
+---------+
| drug_id |
+---------+
|      26 |
+---------+
1 row in set (0.000 sec)

MariaDB [aurora]> select patient_id, expiration from prescriptions where drug_id = 26 and expiration > '2023-10-20';
+------------+------------+
| patient_id | expiration |
+------------+------------+
|      10482 | 2023-10-31 |
|      13779 | 2023-11-26 |
|      18086 | 2023-11-20 |
|      10042 | 2023-10-26 |
|      11367 | 2023-11-04 |
|      14322 | 2023-12-19 |
|      12013 | 2023-10-28 |
+------------+------------+
7 rows in set (0.001 sec)

MariaDB [aurora]> select first_name, last_name from patients where patient_id = 10042;
+------------+-----------+
| first_name | last_name |
+------------+-----------+
| Renae      | Allum     |
+------------+-----------+
1 row in set (0.000 sec)
flag{7_Renae Allum}

Transaction Approved (SQL 100)

2023 年 10 月の時点で有効期限が切れていないクレジットカードの枚数を答える問題。
billingテーブルにcard_numとexpカラムがある。expが2023-10より大きいレコードの数を検索する。

MariaDB [aurora]> select count(*) from billing where exp > '2023-10';
+----------+
| count(*) |
+----------+
|     8785 |
+----------+
1 row in set (0.002 sec)
flag{8785}

City Hoard (SQL 100)

Remizideの在庫が最も多い施設がある都市を答える問題。
drugsテーブルにdrug_nameのカラムがあり、該当するdrug_idを確認する。inventoryテーブルでそのdrug_idでqtyが最も多い、facility_idを確認する。facilitiesテーブルでそのfacility_idに該当するレコードのcityを確認する。

MariaDB [aurora]> select drug_id from drugs where drug_name = 'Remizide';
+---------+
| drug_id |
+---------+
|      13 |
+---------+
1 row in set (0.000 sec)

MariaDB [aurora]> select facility_id, qty from inventory where drug_id = 13 order by qty desc limit 1;
+-------------+------+
| facility_id | qty  |
+-------------+------+
|         531 | 2999 |
+-------------+------+
1 row in set (0.002 sec)

MariaDB [aurora]> select city from facilities where facility_id = 531;
+-------+
| city  |
+-------+
| Miami |
+-------+
1 row in set (0.000 sec)
flag{Miami}

Counting STARs (SQL 150)

STAR(Starypax)を最も多く処方した医師の姓名とポジションを答える問題。
問題「Starypax」でStarypaxのdrug_idは26であることは確認済み。
prescriptionsテーブルにdrug_id、doctor_idカラムがある。drug_idが26でdoctor_idごとにレコード数を取得する。record数の合計が最も多いdoctor_id(=staff_id)を条件に、staffテーブルからfirst_name, last_nameを取得する。positions_assignedテーブルからstaff_idを元に、position_idを取得する。positionテーブルからposition_idを元に、position_nameを取得する。

MariaDB [aurora]> select doctor_id, count(*) from prescriptions where drug_id = 26 group by doctor_id order by 2 desc limit
1;
+-----------+----------+
| doctor_id | count(*) |
+-----------+----------+
|      1957 |        8 |
+-----------+----------+
1 row in set (0.001 sec)

MariaDB [aurora]> select first_name, last_name from staff where staff_id = 1957;
+------------+-------------+
| first_name | last_name   |
+------------+-------------+
| Alisa      | MacUchadair |
+------------+-------------+
1 row in set (0.000 sec)

MariaDB [aurora]> select position_id from positions_assigned where staff_id = 1957;
+-------------+
| position_id |
+-------------+
|          18 |
+-------------+
1 row in set (0.000 sec)

MariaDB [aurora]> select position_name from positions where position_id = 18;
+---------------+
| position_name |
+---------------+
| Dermatologist |
+---------------+
1 row in set (0.000 sec)
flag{Alisa MacUchadair Dermatologist}

Cereal Killer 05 (Reverse Engineering 10)

$ strings re05.bin            
        :
Dr. Geschichter, just because he is evil, doesn't mean he doesn't have a favorite cereal.
Please enter the passphrase, which is based off his favorite cereal and entity: 
notf1aq{you-guessed-it---this-is-not-the-f1aq}
Xen0M0rphMell0wz
9*2$"
GCC: (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0
        :

パスフレーズは Xen0M0rphMell0wz であると推測できる。

$ ./re05.bin
Dr. Geschichter, just because he is evil, doesn't mean he doesn't have a favorite cereal.
Please enter the passphrase, which is based off his favorite cereal and entity: Xen0M0rphMell0wz
flag{XENO-DO-DO-DO-DO-DO-DOOOOO}
flag{XENO-DO-DO-DO-DO-DO-DOOOOO}

Cereal Killer 01 (Reverse Engineering 50)

Ghidraでデコンパイルする。

undefined4 main(void)

{
  int iVar1;
  undefined4 uVar2;
  int in_GS_OFFSET;
  char *local_1090;
  char *local_108c;
  char *local_1088;
  char local_1078 [100];
  char local_1014 [4096];
  int local_14;
  undefined *local_10;
  
  local_10 = &stack0x00000004;
  local_14 = *(int *)(in_GS_OFFSET + 0x14);
  local_108c = "I&_9a%mx_tRmE4D3DmYw_9fbo6rd_aFcRbE,D.D>Y[!]!\'!q";
  puts("Bumpyhassan loves Halloween, so naturally, he LOVES SPOOKY CEREALS!");
  puts("He also happens to be a fan of horror movies from the 1970\'s to the 1990\'s.");
  printf("What is bumpyhassan\'s favorite breakfast cereal? ");
  fgets(local_1014,0xfff,_stdin);
  for (local_1090 = local_1014; *local_1090 != '\0'; local_1090 = local_1090 + 1) {
    *local_1090 = *local_1090 + '\a';
  }
  *local_1090 = '\0';
  iVar1 = memcmp(&DAT_00012039,local_1014,0xe);
  if (iVar1 == 0) {
    puts("You are correct!");
    local_1088 = local_1078;
    for (; *local_108c != '\0'; local_108c = local_108c + 2) {
      *local_1088 = *local_108c;
      local_1088 = local_1088 + 1;
    }
    *local_1088 = '\0';
    printf("flag{%s}\n",local_1078);
  }
  else {
    puts("Sorry, that is not bumpyhassan\'s favorite cereal. :( ");
  }
  uVar2 = 0;
  if (local_14 != *(int *)(in_GS_OFFSET + 0x14)) {
    uVar2 = __stack_chk_fail_local();
  }
  return uVar2;
}

                             DAT_00012039                                    XREF[3]:     main:0001121b(*), 
                                                                                          main:00011221(*), 
                                                                                          main:000112db(*)  
        00012039 4d              ??         4Dh    M
        0001203a 79              ??         79h    y
        0001203b 7c              ??         7Ch    |
        0001203c 70              ??         70h    p
        0001203d 7b              ??         7Bh    {
        0001203e 80              ??         80h
        0001203f 47              ??         47h    G
        00012040 52              ??         52h    R
        00012041 59              ??         59h    Y
        00012042 5c              ??         5Ch    \
        00012043 4c              ??         4Ch    L
        00012044 4e              ??         4Eh    N
        00012045 4c              ??         4Ch    L
        00012046 59              ??         59h    Y
        00012047 00              ??         00h

DAT_00012039の文字から'\a'(='\x07')だけ引けばよい。

>>> enc = 'My|p{\x80GRY\\LNLY'
>>> ''.join([chr(ord(c) - 7) for c in enc])
'Fruity@KRUEGER'

この文字列を入力する。

$ ./re01
Bumpyhassan loves Halloween, so naturally, he LOVES SPOOKY CEREALS!
He also happens to be a fan of horror movies from the 1970's to the 1990's.
What is bumpyhassan's favorite breakfast cereal? Fruity@KRUEGER
You are correct!
flag{I_am_REDDY_for_FREDDY!!!}
flag{I_am_REDDY_for_FREDDY!!!}

My Daily Macros (Reverse Engineering 70)

$ olevba HR_List.xlsm                
olevba 0.60.1 on Python 3.11.5 - http://decalage.info/python/oletools
===============================================================================
FILE: HR_List.xlsm
Type: OpenXML
WARNING  invalid value for PROJECTLCID_Id expected 0002 got 004A
WARNING  invalid value for PROJECTLCID_Lcid expected 0409 got 0004
WARNING  invalid value for PROJECTLCIDINVOKE_Id expected 0014 got 0002
WARNING  invalid value for PROJECTCODEPAGE_Id expected 0003 got 0014
WARNING  invalid value for PROJECTCODEPAGE_Size expected 0002 got 0004
WARNING  invalid value for PROJECTNAME_Id expected 0004 got 0000
ERROR    PROJECTNAME_SizeOfProjectName value not in range [1-128]: 131075
ERROR    Error in _extract_vba
Traceback (most recent call last):
  File "/usr/local/lib/python3.11/dist-packages/oletools/olevba.py", line 3526, in extract_macros
    for stream_path, vba_filename, vba_code in \
  File "/usr/local/lib/python3.11/dist-packages/oletools/olevba.py", line 2094, in _extract_vba
    project = VBA_Project(ole, vba_root, project_path, dir_path, relaxed)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/dist-packages/oletools/olevba.py", line 1752, in __init__
    projectdocstring_id = struct.unpack("<H", dir_stream.read(2))[0]
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
struct.error: unpack requires a buffer of 2 bytes
WARNING  For now, VBA stomping cannot be detected for files in memory
-------------------------------------------------------------------------------
VBA MACRO Module1 
in file: xl/vbaProject.bin - OLE stream: 'Module1'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
Sub Deadface()
function Invoke-RandomCode {
    $randomCodeList = @(
        {
            # Random code block 1
            Write-Host "Hello, World!"
            $randomNumber = Get-Random -Minimum 1 -Maximum 100
            Write-Host "Random number: $randomNumber"
        },
        {
            # Random code block 2
            # flag{youll_never_find_this_}
            $randomString = [char[]](65..90) | Get-Random -Count 5 | foreach { [char]$_ }
            Write-Host "Random string: $randomString"
        },
        {
            # Random code block 3
            $currentTime = Get-Date
            Write-Host "Current time: $currentTime"
        }
    )

    $randomIndex = Get-Random -Minimum 0 -Maximum $randomCodeList.Count
    $randomCodeBlock = $randomCodeList[$randomIndex]

    & $randomCodeBlock
}

Invoke -RandomCode

End Sub
-------------------------------------------------------------------------------
VBA MACRO ThisWorkbook 
in file: xl/vbaProject.bin - OLE stream: 'ThisWorkbook'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
(empty macro)
-------------------------------------------------------------------------------
VBA MACRO Sheet1 
in file: xl/vbaProject.bin - OLE stream: 'Sheet1'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
(empty macro)
+----------+--------------------+---------------------------------------------+
|Type      |Keyword             |Description                                  |
+----------+--------------------+---------------------------------------------+
|Suspicious|Write               |May write to a file (if combined with Open)  |
|Suspicious|Hex Strings         |Hex-encoded strings were detected, may be    |
|          |                    |used to obfuscate strings (option --decode to|
|          |                    |see all)                                     |
+----------+--------------------+---------------------------------------------+

コメントにフラグが入っていた。

flag{youll_never_find_this_}

Cereal Killer 02 (Reverse Engineering 100)

Ghidraでデコンパイルする。

undefined4 main(void)

{
  int iVar1;
  undefined4 uVar2;
  int in_GS_OFFSET;
  char local_2014 [4096];
  char local_1014 [4096];
  int local_14;
  undefined *local_10;
  
  local_10 = &stack0x00000004;
  local_14 = *(int *)(in_GS_OFFSET + 0x14);
  puts("Luciafer also loves Halloween, so she, too, LOVES SPOOKY CEREALS!");
  puts("She has different favorite villain from 70-80\'s horror movies.");
  printf("What is Luciafer\'s favorite breakfast cereal? ");
  fgets(local_2014,0xfff,_stdin);
  decode_str(local_2014,0x3f,&DAT_00012094,local_1014);
  iVar1 = strncmp(local_1014,"CORRECT!!!!!",0xc);
  if (iVar1 == 0) {
    puts(local_1014);
  }
  else {
    printf("%s",
           "INCORRECT....: I\'m afraid that is not Lucia\'s current favorite monster cereal.  She is  kind of capricious, you know, so it changes often.\n"
          );
  }
  uVar2 = 0;
  if (local_14 != *(int *)(in_GS_OFFSET + 0x14)) {
    uVar2 = __stack_chk_fail_local();
  }
  return uVar2;
}

void decode_str(int param_1,int param_2,int param_3,int param_4)

{
  int local_10;
  int local_c;
  
  local_10 = 0;
  local_c = 0;
  while (local_c < param_2) {
    *(byte *)(param_4 + local_c) = *(byte *)(param_3 + local_c) ^ *(byte *)(param_1 + local_10);
    local_c = local_c + 1;
    local_10 = local_10 + 1;
    if (0xb < local_10) {
      local_10 = 0;
    }
  }
  *(undefined *)(param_4 + local_c) = 0;
  return;
}

                             DAT_00012094                                    XREF[3]:     main:0001126e(*), 
                                                                                          main:00011274(*), 
                                                                                          main:000112d7(*)  
        00012094 08              ??         08h
        00012095 3d              ??         3Dh    =
        00012096 33              ??         33h    3
        00012097 3f              ??         3Fh    ?
        00012098 15              ??         15h
        00012099 36              ??         36h    6
        0001209a 32              ??         32h    2
        0001209b 47              ??         47h    G
        0001209c 52              ??         52h    R
        0001209d 12              ??         12h
        0001209e 1b              ??         1Bh
        0001209f 65              ??         65h    e
        000120a0 6b              ??         6Bh    k
        000120a1 48              ??         48h    H
        000120a2 41              ??         41h    A
        000120a3 0b              ??         0Bh
        000120a4 3c              ??         3Ch    <
        000120a5 14              ??         14h
        000120a6 01              ??         01h
        000120a7 1d              ??         1Dh
        000120a8 34              ??         34h    4
        000120a9 41              ??         41h    A
        000120aa 5b              ??         5Bh    [
        000120ab 29              ??         29h    )
        000120ac 1b              ??         1Bh
        000120ad 13              ??         13h
        000120ae 4c              ??         4Ch    L
        000120af 26              ??         26h    &
        000120b0 02              ??         02h
        000120b1 34              ??         34h    4
        000120b2 2b              ??         2Bh    +
        000120b3 16              ??         16h
        000120b4 06              ??         06h
        000120b5 40              ??         40h    @
        000120b6 17              ??         17h
        000120b7 0d              ??         0Dh
        000120b8 38              ??         38h    8
        000120b9 5f              ??         5Fh    _
        000120ba 22              ??         22h    "
        000120bb 02              ??         02h
        000120bc 3d              ??         3Dh    =
        000120bd 1c              ??         1Ch
        000120be 08              ??         08h
        000120bf 4b              ??         4Bh    K
        000120c0 35              ??         35h    5
        000120c1 5c              ??         5Ch    \
        000120c2 48              ??         48h    H
        000120c3 69              ??         69h    i
        000120c4 0f              ??         0Fh
        000120c5 13              ??         13h
        000120c6 4c              ??         4Ch    L
        000120c7 2f              ??         2Fh    /
        000120c8 31              ??         31h    1
        000120c9 11              ??         11h
        000120ca 4b              ??         4Bh    K
        000120cb 2d              ??         2Dh    -
        000120cc 1a              ??         1Ah
        000120cd 57              ??         57h    W
        000120ce 49              ??         49h    I
        000120cf 65              ??         65h    e
        000120d0 6a              ??         6Ah    j
        000120d1 53              ??         53h    S
        000120d2 1c              ??         1Ch
        000120d3 00              ??         00h

DAT_00012094とのXORが"CORRECT!!!!!"になればよい。

>>> key = '\x08=3?\x1562GR\x12\x1be'
>>> enc = 'CORRECT!!!!!'
>>> ''.join([chr(ord(c) ^ ord(k)) for c, k in zip(enc, key)])
'KramPuffs3:D'

この文字列を入力する。

$ ./re02.bin
Luciafer also loves Halloween, so she, too, LOVES SPOOKY CEREALS!
She has different favorite villain from 70-80's horror movies.
What is Luciafer's favorite breakfast cereal? KramPuffs3:D
CORRECT!!!!! : flag{GramPa-KRAMpus-Is-Comin-For-Da-Bad-Kids!!!}
flag{GramPa-KRAMpus-Is-Comin-For-Da-Bad-Kids!!!}

STARvin for Secrets 1: Lindsey's Lyrics (Reverse Engineering 100)

Ghidraでデコンパイルする。

int __cdecl main(int _Argc,char **_Argv,char **_Env)

{
  BOOL BVar1;
  undefined4 in_register_0000000c;
  longlong lVar2;
  SHELLEXECUTEINFO *pSVar3;
  char *in_stack_fffffffffffffd38;
  char *in_stack_fffffffffffffd40;
  SHELLEXECUTEINFO shellExecuteInfo;
  WCHAR moduleName [260];
  char *keyword;
  char *directory;
  
  __main(CONCAT44(in_register_0000000c,_Argc));
  BVar1 = IsRunAsAdmin();
  if (BVar1 == 0) {
    GetModuleFileNameW((HMODULE)0x0,moduleName,0x104);
    pSVar3 = &shellExecuteInfo;
    for (lVar2 = 0xe; lVar2 != 0; lVar2 = lVar2 + -1) {
      pSVar3->cbSize = 0;
      pSVar3->fMask = 0;
      pSVar3 = (SHELLEXECUTEINFO *)&pSVar3->hwnd;
    }
    shellExecuteInfo.cbSize = 0x70;
    shellExecuteInfo.lpFile = moduleName;
    shellExecuteInfo.nShow = 1;
    shellExecuteInfo.lpVerb = L"runas";
    ShellExecuteExW((SHELLEXECUTEINFOW *)&shellExecuteInfo);
    puts("Reran as admin\n");
                    /* WARNING: Subroutine does not return */
    exit(0);
  }
  oreos();
  milk();
  wishbone(in_stack_fffffffffffffd38,in_stack_fffffffffffffd40);
  ykk();
  cryptkeeper();
  enigma();
  exfil();
  return 0;
}

int oreos(void)

{
  size_t sVar1;
  DWORD arvin;
  HKEY hKey;
  wchar_t *meat;
  LONG stephanie;
  
  stephanie = RegCreateKeyExW((HKEY)0xffffffff80000001,L"Software\\MusicDownloader",0,(LPWSTR)0x0,0,
                              0xf003f,(LPSECURITY_ATTRIBUTES)0x0,(PHKEY)&hKey,&arvin);
  if (stephanie != 0) {
    printf("Failed to create registry key. Error code %d",(ulonglong)arvin);
  }
  meat = L"ZmxhZ3sxbnMxZGV";
  sVar1 = wcslen(L"ZmxhZ3sxbnMxZGV");
  stephanie = RegSetValueExW((HKEY)hKey,L"veggies",0,1,(BYTE *)meat,((int)sVar1 + 1) * 2);
  if (stephanie != 0) {
    printf("Failed to write values to key");
  }
  RegCloseKey((HKEY)hKey);
  return 0;
}

以下のbase64文字列がある。

ZmxhZ3sxbnMxZGV
int milk(void)

{
  longlong lVar1;
  undefined8 *puVar2;
  LOCALGROUP_MEMBERS_INFO_3 account;
  USER_INFO_1 userInfo;
  wchar_t password [256];
  wchar_t username [257];
  DWORD dwError;
  DWORD dwLevel;
  DWORD status;
  DWORD userFlags;
  
  userInfo.usri1_password = password;
  username[0] = L'm';
  username[1] = L'r';
  username[2] = L's';
  username[3] = L'a';
  username[4] = L'd';
  username[5] = L'a';
  username[6] = L'm';
  username[7] = L's';
  username[8] = L'\0';
  puVar2 = (undefined8 *)(username + 9);
  for (lVar1 = 0x3e; lVar1 != 0; lVar1 = lVar1 + -1) {
    *puVar2 = 0;
    puVar2 = puVar2 + 1;
  }
  password[0] = L'f';
  password[1] = L'd';
  password[2] = L'D';
  password[3] = L'N';
  password[4] = L'o';
  password[5] = L'X';
  password[6] = L'2';
  password[7] = L'1';
  password[8] = L'A';
  password[9] = L'd';
  password[10] = L'H';
  password[11] = L'I';
  password[12] = L'x';
  password[13] = L'e';
  password[14] = L'H';
  password[15] = L'0';
  password[16] = L'=';
  password[17] = L'\0';
  puVar2 = (undefined8 *)(password + 0x12);
  for (lVar1 = 0x3b; lVar1 != 0; lVar1 = lVar1 + -1) {
    *puVar2 = 0;
    puVar2 = puVar2 + 1;
  }
  *(undefined4 *)puVar2 = 0;
  userInfo.usri1_name = username;
  userInfo.usri1_priv = 1;
  userInfo.usri1_home_dir = (LPWSTR)0x0;
  userInfo.usri1_comment = (LPWSTR)0x0;
  userInfo.usri1_flags = 0x10201;
  userInfo.usri1_script_path = (LPWSTR)0x0;
  NetUserAdd(0,1,&userInfo,0);
  account.lgrmi3_domainandname = L"mrsadams";
  NetLocalGroupAddMembers(0,L"Administrators",3,&account,1);
  return 0;
}

passwordは以下の通り。

fdDNoX21AdHIxeH0=

先ほどのbase64文字列と結合して、デコードする。

$ echo ZmxhZ3sxbnMxZGVfdDNoX21AdHIxeH0= | base64 -d
flag{1ns1de_t3h_m@tr1x}
flag{1ns1de_t3h_m@tr1x}

Sometimes IT Lets You Down (Traffic Analysis 25)

smbでフィルタリングする。全部のユーザプロファイルフォルダを探索しており、No.13226のパケットから固有のユーザのものへのアクセスがある。

flag{mmeyers}

Git Rekt (Traffic Analysis 50)

httpでフィルタリングする。No.3240のパケットで、Sign inの情報をPOSTしている。

Form item: "login" = "spookyboi@deadface.io"
Form item: "password" = "SpectralSecrets#2023"
flag{SpectralSecrets#2023}

Creepy Crawling (Traffic Analysis 75)

No.5543パケットなどの情報を見ると、SSHプロトコル情報が書いてある。

SSH-2.0-9.29 FlowSsh: Bitvise SSH Server (WinSSHD) 9.29
flag{SSH-2.0-9.29 FlowSsh: Bitvise SSH Server}

UVB-76 (Hello, are you there?) (Traffic Analysis 75)

ICMPのパケットNo.2624にフラグがあった。
以下のそのままのフラグは通らなかった。

Flag{is_this_thing_on?}

先頭を小文字にする。

flag{is_this_thing_on?}

Keys to the Kingdom (Traffic Analysis 100)

pcapはjpgが分断されて送信されている。抽出して結合し、jpgを復元する。

#!/usr/bin/env python3
from scapy.all import *

packets = rdpcap('Thekeytothekingdom.pcap')

jpg = b''
for p in packets:
    jpg += p[Raw].load

with open('message.jpg', 'wb') as f:
    f.write(jpg)

CyberChefのMagicで問題のkeyを復号する。XOR({'option':'Hex','string':'90'},'Standard',false) の時に以下のように復号できた。

CTF{Thepassphraseis:Numuhukumakiakiaialunamor}

steghideでパスフレーズに Numuhukumakiakiaialunamor を指定して、データを抽出する。

$ steghide extract -sf message.jpg
Enter passphrase: 
wrote extracted data to "flag.txt".
$ cat flag.txt          
flag{Error404FlagNotFound}
flag{Error404FlagNotFound}

What's the Wallet (Forensics 20)

Bitcoin.txtの中に以下の記述がある。

function Store-BtcWalletAddress {
    `$global:BtcWalletAddress = [System.Convert]::FromBase64String([System.Text.Encoding]::UTF8.GetBytes('bjMzaGE1bm96aXhlNnJyZzcxa2d3eWlubWt1c3gy'))
}

以下の文字列をbase64デコードする。

'bjMzaGE1bm96aXhlNnJyZzcxa2d3eWlubWt1c3gy'
$ echo bjMzaGE1bm96aXhlNnJyZzcxa2d3eWlubWt1c3gy | base64 -d            
n33ha5nozixe6rrg71kgwyinmkusx2
flag{n33ha5nozixe6rrg71kgwyinmkusx2}

Host Busters 1 (Forensics 50)

$ ssh vim@gh0st404.deadface.io                                                                       
The authenticity of host 'gh0st404.deadface.io (143.244.179.162)' can't be established.
ED25519 key fingerprint is SHA256:YThY7nCjBBM0MQts+XQFO1Q2Hlg4zfukCCTwH2+1bBw.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'gh0st404.deadface.io' (ED25519) to the list of known hosts.
vim@gh0st404.deadface.io's password:

すぐにvimが立ち上がる。vim上で以下を入力する。

:!/bin/sh
$ id
uid=1002(vim) gid=1002(vim) groups=1002(vim),1004(deadface)
$ ls
hostbusters1.txt
$ cat hostbusters1.txt
flag{esc4P3_fr0m_th3_V1M}
flag{esc4P3_fr0m_th3_V1M}

You've Been Ransomwared (Steganography 10)

StegSolveで開き、Blue plane 5を見ると、2進数のコードが見える。

01010100 01101000 01101001 01110011 00100000 01110010 01100001 01101110 01110011 01101111 01101101 01110111 01100001 01110010
01100101 00100000 01100010 01110010 01101111 01110101 01100111 01101000 01110100 00100000 01110100 01101111 00100000 01111001
01101111 01110101 00100000 01100010 01111001 00100000 01101101 01101001 01110010 01110110 01100101 01100001 01101100 00101110

デコードする。

#!/usr/bin/env python3
enc = '''
01010100 01101000 01101001 01110011 00100000 01110010 01100001 01101110 01110011 01101111 01101101 01110111 01100001 01110010 
01100101 00100000 01100010 01110010 01101111 01110101 01100111 01101000 01110100 00100000 01110100 01101111 00100000 01111001 
01101111 01110101 00100000 01100010 01111001 00100000 01101101 01101001 01110010 01110110 01100101 01100001 01101100 00101110
'''

enc = enc.replace('\n', '').split(' ')

msg = ''
for c in enc:
    msg += chr(int(c, 2))
print(msg)

デコード結果は以下の通り。

This ransomware brought to you by mirveal
flag{mirveal}

Fetching Secrets (Steganography 20)

$ stegseek cyberdog.jpg dict/rockyou.txt      
StegSeek 0.6 - https://github.com/RickdeJager/StegSeek

[i] Found passphrase: "kira"           
[i] Extracting to "cyberdog.jpg.out".

$ file cyberdog.jpg.out
cyberdog.jpg.out: PNG image data, 500 x 100, 8-bit/color RGBA, non-interlaced
$ mv cyberdog.jpg.out flag.png

flag.pngにフラグが書いてあった。

flag{g00d_dawg_woofw00f}

Electric Steel (Steganography 150)

$ binwalk electric-steel.png 

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             PNG image, 1232 x 928, 8-bit/color RGB, non-interlaced
2767          0xACF           Zlib compressed data, default compression
1435378       0x15E6F2        TIFF image data, big-endian, offset of first image directory: 8
1435914       0x15E90A        Copyright string: "Copyright (c) 1998 Hewlett-Packard Company"
1467642       0x1664FA        gzip compressed data, from Unix, last modified: 2023-06-04 01:14:27

gzip compressed dataを抽出する。

#!/usr/bin/env python3
with open('electric-steel.png', 'rb') as f:
    data = f.read()

gz = data[1467642:-12]

with open('flag.gz', 'wb') as f:
    f.write(gz)

抽出したflag.gzを解凍する。

$ gzip -d flag.gz

gzip: flag.gz: decompression OK, trailing garbage ignored

$ cat flag      
flag.txt0000664000175000017500000000003614436762547012573 0ustar  syyntaxsyyntaxflag{3L3ctr1c_5t33L_b1G_H41R}
flag{3L3ctr1c_5t33L_b1G_H41R}

Terms and Conditions May Apply (Steganography 150)

Ghost Townで以下の掲示板が該当する。

https://ghosttown.deadface.io/t/predictive-programming/132

ここからビデオをダウンロードし、フレームごとに分割する。

#!/usr/bin/env python3
import cv2

movie = cv2.VideoCapture('Lytton Labs Update Infomercial 1 - VF.mp4')
nframe = int(movie.get(cv2.CAP_PROP_FRAME_COUNT))
for i in range(nframe):
    ret, frame = movie.read()
    cv2.imwrite('frames/frame_' + str(i).zfill(5) + '.png', frame)

QRコードのパーツの画像が16個入っていたので、収集して、結合する。

QRコードをリーダで読み取る。

https://files.lyttonlabs.org
flag{https://files.lyttonlabs.org}

Coin Code (Cryptography 10)

コインの写真からシーザー暗号と推測できる。https://www.geocachingtoolbox.com/index.php?lang=en&page=caesarCipherで復号する。

Rotation 18:
Next target for me will be Aurora Pharma
flag{Aurora Pharma}

Letter Soup (Cryptography 10)

ワードを縦横で探し、残りの文字を並べ、フラグの形式にする。

MSHN{HZISHJRMLHAOLYZZOPULPUAOLZBU}

シーザー暗号と推測し、https://www.geocachingtoolbox.com/index.php?lang=en&page=caesarCipherで復号する。

Rotation 7:
FLAG{ASBLACKFEATHERSSHINEINTHESUN}
FLAG{ASBLACKFEATHERSSHINEINTHESUN}

B1Tz and B0tZ (Cryptography 25)

2進数のコードになっているので、デコードする。さらに16進数デコードし、最後にrot13する。

#!/usr/bin/env python3
import codecs

with open('bitsandbots.txt', 'r') as f:
    codes = f.read().rstrip()

codes = codes.split(' ')

msg = ''
for code in codes:
    msg += chr(int(code, 2))
print('[+] message:', msg)

codes = msg[145:].split(' ')
msg = ''
for code in codes:
    msg += chr(int(code, 16))
print('[+] message:', msg)

flag = codecs.decode(msg, 'rot-13')
print('[*] flag:', flag)

実行結果は以下の通り。

[+] message: dont forget the basics! but you diddnt think it would be that easy did you? HAHAHAHAHA Silly Turbos! More Like Turbo TACKY!!!! Go ahead and ROT
73 79 6E 74 7B 73 79 76 63 76 67 6E 61 71 65 72 69 72 65 66 72 76 67 7D

[+] message: synt{syvcvgnaqerirefrvg}
[*] flag: flag{flipitandreverseit}
flag{flipitandreverseit}

Refill on Soup (Cryptography 75)

ワードを縦横斜めで探し、残りの文字を並べる。

NVAVAOLSHZASPULMVYAOLMSHNHUZDLYAOHANVLZPUZPKLAOLIYHJRLAZZAVWNQWKDDEVWZLZTJNTHXSKEADVUCBVTRKLHWEEBGBDTHHZAOLFMSFHJYVZZ

シーザー暗号と推測し、https://www.geocachingtoolbox.com/index.php?lang=en&page=caesarCipherで復号する。

Rotation 7:
GOTOTHELASTLINEFORTHEFLAGANSWERTHATGOESINSIDETHEBRACKETSSTOPGJPDWWXOPSESMCGMAQLDXTWONVUOMKDEAPXXUZUWMAASTHEYFLYACROSS

単語で区切る。

GO TO THE LAST LINE FOR THE FLAG ANSWER THAT GOES INSIDE THE BRACKETS STOPGJPDWWXOPSESMCGMAQLDXTWONVUOMKDEAPXXUZUWMAASTHEYFLYACROSS

最後の行の部分を取り出す。

ASTHEYFLYACROSS
flag{ASTHEYFLYACROSS}

HAM JAM (Cryptography 75)

wavファイルにはモールス信号が入っている。https://morsecode.world/international/decoder/audio-decoder-adaptive.htmlでデコードする。

THEKEYISHACKTHEPLANET

Ghost Townを調べると、関係する掲示板がある。

https://ghosttown.deadface.io/t/rendezvous-lets-goooooo/127

バーコードのような画像があるので、ダウンロードする。

調べると、Codablockというバーコードらしい。https://products.aspose.app/barcode/recognize/codablockでデコードする。

YEOOFIIGEHRJBMTJYYUSKPMOIK

Vigenere暗号と推測し、https://www.dcode.fr/vigenere-cipherで復号する。

暗号:YEOOFIIGEHRJBMTJYYUSKPMOIK
鍵 :HACKTHEPLANET

復号結果は以下の通り。

REMEMBERTHEFIFTHOFNOVEMBER
flag{NOVEMBER-5}

Color Me Impressed (Cryptography 75)

掲示板からflight_logs.zipをダウンロードする。しかし、このzipはパスワードがかかっているので、一旦保留。
掲示板からカラーテンプレートの画像をダウンロードする。左からRGBのコードをASCIIコードとしてデコードする。

#!/usr/bin/env python3
from PIL import Image

img = Image.open('image.png').convert('RGB')

password = ''
for i in range(7):
    r, g, b = img.getpixel((140 + i * 280, 140))
    password += chr(r) + chr(g) + chr(b)

print(password)

デコード結果は以下の通り。

Gl@55H#u$3$tOn3Sm@5h

これをパスワードとしてzipを解凍すると、flight_logs.jsonが展開された。このjsonファイルの最終行にフラグが書いてあった。

{"flag": "flag{D3@dF@c3Rulz!}"}
flag{D3@dF@c3Rulz!}

0ff Again On Aga1n (Cryptography 100)

Purple, Blackを0, Green, Pinkを1にして、上から行単位でデコードする。

>>> chr(int('01010100', 2))
'T'
>>> chr(int('00110011', 2))
'3'
>>> chr(int('01000011', 2))
'C'
>>> chr(int('01001000', 2))
'H'
>>> chr(int('01001110', 2))
'N'
>>> chr(int('00110000', 2))
'0'
>>> chr(int('01000111', 2))
'G'
>>> chr(int('00110001', 2))
'1'

以下のフラグは通らない。

flag{T3CHN0G1}

次にPurple, Greenを0, Black, Pinkを1にして、左から列単位でデコードする。

>>> chr(int('00110000', 2))
'0'
>>> chr(int('00111000', 2))
'8'
>>> chr(int('01000000', 2))
'@'
>>> chr(int('00110001', 2))
'1'
>>> chr(int('01010010', 2))
'R'
>>> chr(int('00110011', 2))
'3'
>>> chr(int('01001001', 2))
'I'
>>> chr(int('01001110', 2))
'N'
flag{T3CHN0G108@1R3IN}