この大会は2024/4/28 16:00(JST)~2024/4/30 4:00(JST)に開催されました。
今回は個人で参戦。結果は2300点で500チーム中186位でした。
自分で解けた問題をWriteupとして書いておきます。
Buy an elephant (PWN, Easy)
Ghidraでデコンパイルする。
undefined8 FUN_00401302(void) { int iVar1; size_t sVar2; undefined8 local_148; undefined8 local_140; undefined8 local_138; undefined8 local_130; undefined8 local_128; undefined8 local_120; undefined8 local_118; undefined8 local_110; undefined8 local_108; undefined8 local_100; undefined8 local_f8; undefined8 local_f0; undefined8 local_e8; undefined8 local_e0; undefined8 local_d8; undefined8 local_d0; undefined8 local_c8; undefined8 local_c0; undefined8 local_b8; undefined8 local_b0; undefined8 local_a8; undefined8 local_a0; undefined8 local_98; undefined8 local_90; undefined8 local_88; undefined8 local_80; undefined8 local_78; undefined8 local_70; undefined8 local_68; undefined8 local_60; undefined8 local_58; undefined8 local_50; undefined8 local_48; undefined8 local_40; char local_38 [32]; time_t local_18; tm *local_10; puts(&DAT_004040a0); local_48 = 0; local_40 = 0; local_148 = 0; local_140 = 0; local_138 = 0; local_130 = 0; local_128 = 0; local_120 = 0; local_118 = 0; local_110 = 0; local_108 = 0; local_100 = 0; local_f8 = 0; local_f0 = 0; local_e8 = 0; local_e0 = 0; local_d8 = 0; local_d0 = 0; local_c8 = 0; local_c0 = 0; local_b8 = 0; local_b0 = 0; local_a8 = 0; local_a0 = 0; local_98 = 0; local_90 = 0; local_88 = 0; local_80 = 0; local_78 = 0; local_70 = 0; local_68 = 0; local_60 = 0; local_58 = 0; local_50 = 0; local_18 = time((time_t *)0x0); local_10 = localtime(&local_18); strftime(local_38,0x14,"%a, %y:%H:%M",local_10); printf("Enter your name: "); fflush(stdout); fgets((char *)&local_48,0x10,stdin); sVar2 = strcspn((char *)&local_48,"\n"); *(undefined *)((long)&local_48 + sVar2) = 0; DAT_004051a0 = '\0'; printf("(%s) %s: %s\n",local_38,s_Vanya_004050fe,"Buy an elephant"); while( true ) { memset(&local_148,0,0x100); memset(&DAT_00405120,0,0x80); local_18 = time((time_t *)0x0); local_10 = localtime(&local_18); strftime(local_38,0x14,"%a, %y:%H:%M",local_10); printf("(%s) %s: ",local_38,&local_48); fflush(stdout); fgets((char *)&local_148,0x100,stdin); sVar2 = strcspn((char *)&local_148,"\n"); *(undefined *)((long)&local_148 + sVar2) = 0; iVar1 = strcmp((char *)&local_148,"q"); if (iVar1 == 0) break; local_18 = time((time_t *)0x0); local_10 = localtime(&local_18); strftime(local_38,0x14,"%a, %y:%H:%M",local_10); sVar2 = strlen(&DAT_00405120); *(undefined8 *)(&DAT_00405120 + sVar2) = 0x656e6f7972657645; *(undefined8 *)(&DAT_00405128 + sVar2) = 0x22207379617320; strcat(&DAT_00405120,(char *)&local_148); sVar2 = strlen(&DAT_00405120); *(undefined8 *)(&DAT_00405120 + sVar2) = 0x7920747562202c22; *(undefined8 *)(&DAT_00405128 + sVar2) = 0x206465656e20756f; *(undefined8 *)(&DAT_00405130 + sVar2) = 0x6120797562206f74; *(undefined8 *)(&DAT_00405138 + sVar2) = 0x616870656c65206e; *(undefined2 *)(&DAT_00405140 + sVar2) = 0x746e; (&DAT_00405142)[sVar2] = 0; printf("(%s) %s: %s\n",local_38,s_Vanya_004050fe,&DAT_00405120); } if (DAT_004051a0 != '\0') { FUN_004012b6(); } return 0; } void FUN_004012b6(void) { char *pcVar1; pcVar1 = getenv("FLAG"); printf("Your flag: %s\n",pcVar1); fflush(stdout); return; }
名前は適当な16バイト以下のものを指定し、次の入力で129バイト入力すれば、DAT_004051a0が上書きされ、フラグ表示の条件を満たす。この条件を満たした上で"q"で抜ければ、フラグが表示される。
$ nc 62.173.140.174 47100 ████████ ████░░░░░░░░██████ ██████████ ██░░░░░░░░░░░░░░░░░░████ ████░░░░░░░░░░██░░░░░░░░░░░░░░░░░░░░░░░░██ ██░░░░░░░░░░░░░░██░░░░░░░░░░░░░░░░░░░░░░░░░░██ ██░░░░░░░░░░░░░░░░██░░░░░░░░░░░░░░░░░░░░░░░░░░░░██ ██░░░░░░░░░░░░░░░░░░░░██░░░░░░░░░░░░░░░░░░░░░░░░░░██ ██░░░░░░░░░░░░░░░░░░░░░░░░██░░░░░░░░░░░░░░░░░░██░░░░██ ██░░░░░░░░░░░░░░░░░░░░░░░░░░░░████░░░░██░░░░░░░░░░░░░░██ ██░░██░░░░░░░░░░░░░░░░░░░░░░░░░░░░████░░░░░░░░░░░░░░░░██ ██ ██░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░██░░░░░░██ ██░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░████░░██ ██░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░██ ██░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░████░░░░██ ██░░░░░░░░░░░░░░░░░░░░░░░░░░░░████░░░░██ ██░░░░████░░░░░░░░████░░░░██ ██░░██ ████ ██░░░░██ ████████ ██░░░░██ ██░░░░██░░░░██ ██░░░░██ ██░░░░██ ██░░░░░░██ ██░░░░░░██ ██░░░░░░██ ██████ ██░░░░░░ ██ ██░░░░░░ ██ ████████ ████████ Enter your name: hoge (Sun, 24:23:04) Vanya: Buy an elephant (Sun, 24:23:05) hoge: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa (Sun, 24:23:06) Vanya: Everyone says "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", but you need to buy an elephant (Sun, 24:23:06) hoge: q Your flag: CODEBY{D0_yoU_b2y_aN_elePh@nt}
CODEBY{D0_yoU_b2y_aN_elePh@nt}
Warm-up (Reverse-engineering, Easy)
$ file task_rev.exe task_rev.exe: PE32 executable (console) Intel 80386 Mono/.Net assembly, for MS Windows, 3 sections
dnSpyでデコンパイルする。
using System; using System.Text; using EncryptionLibrary; // Token: 0x02000002 RID: 2 internal class Program { // Token: 0x06000001 RID: 1 RVA: 0x00002050 File Offset: 0x00000250 private static void Main() { byte[] a = new byte[] { 90, 90, 131, 173, 3, 108, 139, 21, 101, 136, 11, 35, 101, 154, 191, 222, 178, 128, 45, 197, 220, 65, 122, 138, 18, 173, 210, 128, 16, 101, 247, 74 }; Console.Write("Введите пароль для шифрования: "); string plainText = Console.ReadLine(); byte[] bytes = Encoding.UTF8.GetBytes("CODEBY__PASSWORD"); byte[] bytes2 = Encoding.UTF8.GetBytes("IV82941840912841"); byte[] a2 = EncryptionHelper.EncryptStringToBytes_Aes(plainText, bytes, bytes2); bool flag = Program.ByteArraysAreEqual(a2, a); if (flag) { Console.WriteLine("Размялся? А теперь серьёзные таски! :)"); } else { Console.WriteLine("Попробуй ещё, ты точно справишься! UwU"); } Console.WriteLine("\n(Нажмите Enter для выхода)"); Console.ReadLine(); } // Token: 0x06000002 RID: 2 RVA: 0x000020E8 File Offset: 0x000002E8 private static void PrintByteArray(byte[] array) { for (int i = 0; i < array.Length; i++) { Console.Write("0x{0:X2}, ", array[i]); } Console.WriteLine(); } // Token: 0x06000003 RID: 3 RVA: 0x00002124 File Offset: 0x00000324 private static bool ByteArraysAreEqual(byte[] a1, byte[] a2) { bool flag = a1.Length != a2.Length; bool result; if (flag) { result = false; } else { for (int i = 0; i < a1.Length; i++) { bool flag2 = a1[i] != a2[i]; if (flag2) { return false; } } result = true; } return result; } }
AES暗号の鍵は"CODEBY__PASSWORD"、IVは"IV82941840912841"で、暗号化した結果が、aのバイト配列になればよい。つまりaのバイト配列をAES復号すればよい。
#!/usr/bin/env python3 from Crypto.Cipher import AES from Crypto.Util.Padding import unpad ct = [90, 90, 131, 173, 3, 108, 139, 21, 101, 136, 11, 35, 101, 154, 191, 222, 178, 128, 45, 197, 220, 65, 122, 138, 18, 173, 210, 128, 16, 101, 247, 74] ct = b''.join([bytes([c]) for c in ct]) key = b'CODEBY__PASSWORD' iv = b'IV82941840912841' cipher = AES.new(key, AES.MODE_CBC, iv) flag = unpad(cipher.decrypt(ct), 16).decode() print(flag)
CODEBY{p@sSw0rd_1n_EXE_anD_DLL}
Lasagna (Reverse-engineering, Easy)
$ strings lasagna.exe| grep python Failed to pre-initialize embedded python interpreter! Failed to allocate PyConfig structure! Unsupported python version? Failed to set python home path! Failed to start embedded python interpreter! bpython38.dll 4python38.dll $ python3 pyinstxtractor.py lasagna.exe [+] Processing lasagna.exe [+] Pyinstaller version: 2.1+ [+] Python version: 3.8 [+] Length of package: 6734601 bytes [+] Found 101 files in CArchive [+] Beginning extraction...please standby [+] Possible entry point: pyiboot01_bootstrap.pyc [+] Possible entry point: lasagna.pyc [!] Warning: This script is running in a different Python version than the one used to build the executable. [!] Please run this script in Python 3.8 to prevent extraction errors during unmarshalling [!] Skipping pyz extraction [+] Successfully extracted pyinstaller archive: lasagna.exe You can now use a python decompiler on the pyc files within the extracted directory $ decompyle3 lasagna.exe_extracted/lasagna.pyc # decompyle3 version 3.9.1 # Python bytecode version base 3.8.0 (3413) # Decompiled from: Python 3.11.2 (main, Mar 13 2023, 12:18:29) [GCC 12.2.0] # Embedded file name: lasagna.py import base64 from Crypto.Cipher import AES from Crypto.Util.Padding import pad from Crypto.Util.strxor import strxor_c t = b'B\xc8>\xcc,\xdc\xafA\x193\x9f\xb5Z/\x80\xa8\xa0\xaar\xacT%\xc9\xa4\x9aeg\xe4\xeb\x87\x87\xcd\xd0]\xf8\xb6\xdb/\xe0h\x0e\xc6!\xc4\x8aq\x82\xa7' ll = " ░░░░░░░░ ▒▒ \n ░░░░░░░░░░▒▒▒▒░░▒▒▒▒▒▒ \n ░░░░░░░░░░░░▒▒██▒▒▒▒▒▒▒▒▒▒▒▒ \n ░░░░░░░░░░▒▒▒▒▒▒██▒▒██████████▒▒░░ \n ░░░░░░░░░░▒▒▒▒▒▒██████▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░ \n ░░░░░░░░░░▒▒▒▒████▒▒██▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░\n ░░░░░░░░░░▒▒▒▒██▒▒▒▒▒▒▒▒██▒▒░░░░░░░░░░░░░░░░░░ \n ░░░░░░░░░░░░▒▒██▒▒▒▒▒▒░░▒▒▒▒██▒▒░░░░░░░░░░░░░░██░░\n ░░░░░░░░░░░░░░░░░░░░░░░░░░▒▒▒▒▒▒░░░░░░░░░░░░██░░ \n ██░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░██░░ \n ██████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░██░░██░░\n ░░░░░░██████░░░░░░░░░░░░░░░░░░░░░░░░░░░░██░░██░░ \n ██████░░░░░░████████░░░░░░░░░░░░░░░░░░░░████░░██░░\n ░░░░████████░░░░░░████████░░░░░░░░░░░░██░░██░░██░░\n ████░░░░██████████░░░░░░██████░░░░████░░██░░██░░ \n ░░██████░░░░░░░░████████░░░░████████░░██░░██░░ \n ░░░░██████████░░░░████████░░░░░░░░██░░████░░ \n ░░░░░░░░██████░░░░░░░░████▓▓████░░██░░ \n ░░░░░░░░████████░░░░░░░░░░██░░ \n ░░░░░░██████████████░░ \n ░░░░░░████████░░ \n ░░░░░░░░ \n " def c(t, s): r = "" for c in t: if c.isalpha(): o = ord("a") if c.islower() else ord("A") sc = chr((ord(c) - o + s) % 26 + o) r += sc else: r += c return r def e(i): s = 13 c_e = c(i, s) b_e = base64.b64encode(c_e.encode()).decode() x_k = 65 x_e = strxor_c(b_e.encode(), x_k) a_k = b'KEYrf87ijoasd8j1' a_i = b'IV89jf9198fj8912' cipher = AES.new(a_k, AES.MODE_CBC, a_i) a_e = cipher.encrypt(pad(x_e, AES.block_size)) return a_e print(ll) u_i = input("Enter the encryption flag: ") e_t = e(u_i) if e_t == t: print("This is your flag! :)") else: print("That's not it...") # okay decompiling lasagna.exe_extracted/lasagna.pyc
このスクリプトを元に以下の順に復号する。
・AES復号 ・XOR ・base64デコード ・シーザー暗号の復号
#!/usr/bin/env python3 import base64 from Crypto.Cipher import AES from Crypto.Util.Padding import unpad from Crypto.Util.strxor import strxor_c def c(t, s): r = "" for c in t: if c.isalpha(): o = ord("a") if c.islower() else ord("A") sc = chr((ord(c) - o + s) % 26 + o) r += sc else: r += c return r t = b'B\xc8>\xcc,\xdc\xafA\x193\x9f\xb5Z/\x80\xa8\xa0\xaar\xacT%\xc9\xa4\x9aeg\xe4\xeb\x87\x87\xcd\xd0]\xf8\xb6\xdb/\xe0h\x0e\xc6!\xc4\x8aq\x82\xa7' a_k = b'KEYrf87ijoasd8j1' a_i = b'IV89jf9198fj8912' cipher = AES.new(a_k, AES.MODE_CBC, a_i) x_e = unpad(cipher.decrypt(t), AES.block_size) x_k = 65 b_e = strxor_c(x_e, x_k) c_e = base64.b64decode(b_e).decode() s = 13 flag = c(c_e, s) print(flag)
CODEBY{L@sAgna_aND_2ncr3pt1on}
Earth Rumble 2 (Forensics, Easy)
sstvでデコードしてみる。
$ sstv -d task.wav -o flag.png [sstv] Searching for calibration header... Found! [sstv] Detected SSTV mode Robot 36 [sstv] Decoding image... [##########################################################################################] 100% [sstv] Drawing image data... [sstv] ...Done!
出力した画像にフラグが書いてあった。
CODEBY{al13ns_w4s_h3re}
Skeleton (Steganography, Easy)
gifアニメーションになっているので、Giamで全コマを保存する。各コマを見ていくと、53番目のコマにフラグが書いてあった。
CODEBY{4_S3CR37_1N_7H3_SK3L3T0N_W4S_F0UND}
All-seeing (Steganography, Easy)
StegSolveで開き、Alpha plane 1を見ると、フラグが現れた。
CODEBY{4nd_i_c4n_se3}
Letter to Santa Claus (Steganography, Medium)
PDFにはほとんど英大文字で書かれているが、英小文字がまぎれている。英小文字だけ取り出す。
#!/usr/bin/env python3 from string import * s = ''' THE NEW YEAR IS APPROACHING, AND CHILDREN ARE LOOKING FORWARD TO THE MIRACLE OF SANTA CLAUS WITH A SACK OF PRESENTS. THEY SINCERELY BELIEVE THAT THE KIND SANTA WILL FULFILL ANY WISH, AND PARENTS ON THE ONE HAND WANT TO SUPPORT THIS CHILD'S BELIEF IN MIRACLES, BUT ON THE OTHER HAND - CAN NOT ALWAYS GIVE THE CHILD WHAT HE WANTS. TO AVOID CHILDREN'S TEARS AND DISAPPOINTMENTS, IT IS WORTH PREPARING FOR NEW YEAR'S EVE IN ADVANCE. ALL CHILDREN KNOW THAT SANTA CLAUS NEEDS TO WRITE A LETTER. IN BOOKSTORES AND POST OFFICES THERE ARE EVEN SPECIAL COLORFUL FORMS, BUT IT IS NOT NECESsARY AT ALL. A CHILD CAN WRITE IN BLOCK LETTERS HIS REQUEST, AND A LITTLE ONE CAN WRITE HIS NAME, THE REST WILL BE WRItTEN BY MOM. A CHILD'S DRAWING OR APPLIQUE IS A GREAT ALTERNATIVE TO A READY-MADE FORM. THE MAIN THING - WHAT DOeS YOUR CHILD WANT TO RECEIVE AS A GIFT? WRITING A LETTER TOGETHER AND AT THE SAME TIME TALKING TO THE CHILD WILL HELP PARENTS TO ENCOURAgE THE CHILD TO CHOOSE A GIFT THAT THEY THEMSELVES PLANNED TO BUY HIM OR HER OR THAT THEY CaN AFFORD. IT IS GOOD IF THE CHILD CHOOSES SOMETHING THAT YOU AGREE WITH IMMEDIATELY. WARMLY SUPPORT HIS DESIRE, HELP TO FORMALIZE THE DRAWING. AND IF THE CHILD'S DESIRE DOES NOT CORRESPOnD TO YOUR PLANS AND POSSIBILITIES? THEN CAREFULLY START A CONVERSATION ABoUT WHAT CAN BRING FROM THE NORTH SANTA CLAUS. FOR EXAMPLE, THE cHILD ASKS FOR A LIVE DOG. ASK HIM A QUESTION: "WHAT IF THE DOG FREEZES oN THE ROAD? AND WHO WILL FEED AND CARE FOR HIM ON THE ROAD? SANTA CLAUS IS BUSY PREPARING PRESENTS..." FANTASIZE, THINK OF SOMETHING CONVINCING, REmEMBER WHAT ELSE YOUR CHILD HAS DREAMeD OF, REMIND HIM ABOUT IT, SMOOTHLY PUSH HIM TO CHOOSE A GIFT THAT YOU CAN BUY HIM. A SMARTPHONE? SANTA CLAUS DOEs NOT USE A SMARTPHONE AND DOES NOT GIVE THEM, SEE, WE WRITE HIM AN ORDINARY LETTER.... THE CHILD ASKS FOR SOMETHING VERY EXPENSIVE? EXPLAiN THAT DED MOROZ CAN NOT GIVE VERY EXPENSIVE GIFTS, HE WRITES A LOT OF CHILDREN, THERE ARE CHILDREN WHO DO NOT HAVE A SINGLE CAR (DOLL), AND nO ONE BUT DED MOROZ WILL NOT GIVE THEM A TOY. AND IF SANTA CLAUS GIVES EXPENSIVE GIFTS, HE WILL NOT BE ABLE TO GIVE THEm TO ALL CHILDREN. IF THE CHILD INSISTS ON HIS OWN OR HAS ALREADY WRITTEN A LETTER WITHOUT YOU (DREW OR OLDER CHILDREN HELPED HIM), YOU WILL HaVE TO WRITE AN ANSWER LETTER FROM SANTA CLAUS AnD PUT IT UNDER THE CHRISTMAS TREE. BEAUTIFULLY ORGANIZE AND IN THE LETTER WRITE HOW NICE IT WAS TO RECEIVE FROM THE CHILD HIS DRAWING, HOW SANTA CLAUS HAS BEEN WATCHING HIM ALL YEAR (SUCH A GOOD BOy: HELPED HIS PARENTS, ALWAYS CLEANED UP TOYS, LEARNED TO SWIM, ETC.). - EMPHASIZE EVERYTHING POSITIVE). AND fROM THEN SANTA CLAUS WRITES THAT THE LETTER IS A LITTLE LATE, AND HE HAS ALREADY BOUGHT THE CHILD A GIFT, BUT IT IS A GREAT GIFT, A SURPRISE THAT WILL DEFINITELY LIKE! THE LETTER CAN BE ACCOMPANIED BY A SMALL SURPRISE - A CHOCoLATE BAR, A FIGURINE OF SANTA CLAUS, SOME SMALL TOY. OF COURSE, THE CHILD MAY BE A LITTLE UPSET, BUT THIS DISAPPOINTMENT WILL NOT BE AS STrONG AS IT COULD BE ON NEW YEAR'S MORNING. THE MAIN THING IS HOW TO PRESENT THE GIFT. IT CAN BE A BEAUTIFUL PACKAGE, SEARCH FOR A GIFT BY NOTES, THE JOY OF THE WHOLE FAmILY AND THE JOINT EXPECTATION OF THE HOLIDAY - THAT'S WHAT IS IMPORTANT FOR THE CHILD, As LONG AS HE BELIEVES IN MIRACLES AND FAIRY TALES. ''' flag = '' for c in s: if c in ascii_lowercase: flag += c print(flag)
steganocomesinmanyforms
CODEBY{steganocomesinmanyforms}
Hills (Cryptography, Easy)
https://www.dcode.fr/hill-cipherで復号する。ここで、ALPHABET (27 CHAR, A=0) を選択する。
BTW_EXISTS_AN_INTERESTING_FILM_ABOUT_HILLS
CODEBY{BTW_EXISTS_AN_INTERESTING_FILM_ABOUT_HILLS}
A confusing cipher (Cryptography, Easy)
モールス信号が含まれているので、取り出す。
-.-. --- -.. . -... -.-- { -.. .---- -.. ..--.- -.-- ----- ..- ..--.- .-. ...-- -.-. ----- --. -. .---- --.. ...-- ..--.- -- ----- .-. ... ...-- ..--.- -.-. ----- -.. ...-- ..--.. }
これをデコードする。
CODEBY{D1D_Y0U_R3C0GN1Z3_M0RS3_C0D3?}
Custom (Cryptography, Medium)
換字式暗号。フラグの形式から対応を推測しながら復号する。
#!/usr/bin/env python3 ct = 'sgwahu{sfj70d_s1pm3v_1j_4kj0_fj3xf1}' C = 'adfghjkmpsuvwx' P = 'emuobslhpcyrdf' flag = '' for c in ct: if c in C: flag += P[C.index(c)] else: flag += c print(flag)
codeby{cus70m_c1ph3r_1s_4ls0_us3fu1}