SpartanCTF 2024 Writeup

この大会は2024/4/18 1:00(JST)~2024/4/22 14:00(JST)に開催されました。
今回は個人で参戦。結果は2338点で168チーム中8位でした。
あと1問で全問制覇だったのに残念です。
自分で解けた問題をWriteupとして書いておきます。

Day by Day (Misc 99)

日付がランダムに並んでいるので、空いている日付を答える問題。まず日付順にソートする。

$ cat dates | sort > dates_sorted

ソートした日付を順に見ていき、次の行が次の日になっていない箇所を探す。

#!/usr/bin/env python3
from datetime import datetime, timedelta

with open('dates_sorted', 'r') as f:
    lines = f.read().splitlines()

tdt = datetime.strptime(lines[0], '%Y%m%d')
for line in lines[1:]:
    next = tdt + timedelta(days=1)
    tdt = datetime.strptime(line, '%Y%m%d')
    if next != tdt:
        DATE = datetime.strftime(next, '%Y%m%d')
        flag = 'spartanCTF{%s}' % DATE
        print(flag)
        break
spartanCTF{19990918}

Down the Rabbit Hole (Misc 170)

zipを解凍すると、zipが複数展開されることが繰り返されるので、スクリプトで解凍する。さらに末端にはrabbitファイルが展開されるので、その内容を確認し、フラグを探す。

#!/usr/bin/env python3
import os
import zipfile

def unzip(dir_path, fname):
    out_dir = fname.split('.')[0]
    with zipfile.ZipFile(dir_path + '/' + fname) as zf:
        zf.extractall(dir_path + '/' + out_dir)

def dir_unzip(dir_path):
    files = os.listdir(dir_path)
    for file in files:
        ext = file.split('.')[-1]
        if ext == 'zip':
            unzip(dir_path, file)

    files = os.listdir(dir_path)
    for file in files:
        if os.path.isdir(dir_path + '/' + file):
             dir_unzip(dir_path + '/' + file)
        elif file == 'rabbit':
             with open(dir_path + '/' + file, 'rb') as f:
                 flag = f.read()
             if b'spartanCTF{' in flag:
                 flag = flag.decode()
                 print(dir_path + '/' + file)
                 print(flag)

dir_unzip('./out')

実行結果は以下の通り。

./out/hole/hole1/hole2/hole4/hole9/rabbit
spartanCTF{th4nk_y0u_m0rpheus_11ec1158}
spartanCTF{th4nk_y0u_m0rpheus_11ec1158}

Bittersweet Symphony (Misc 180)

楽譜が添付されているので、復号する問題。楽譜は次のようになっている。

Solfa Cipherと推測して、https://garden.solsarratea.world/seeds/solfaを参考に考える。
8分音符は長さ1つ分、4分音符は長さ2つ分、4分音符点付きは長さ3つ分、2分音符は長さ4つ分である。
これを数字部分に当てはめられると理解した。まず音符の種類を書き出してみる。

2 | 1 3 2 2 | 3 1 4 | 3 1 4 | 4 4 | 2 2

これを4の長さごとにして位置を考え、音階と合わせ書き出す。

F3 B1 D2 E1 C3 C1 G4 E1 F1 A4 G1 C1 C1 G1 C3
m  o  z  a  r  t  w  a  s  b  e  t  t  e  r
spartanCTF{mozartwasbetter}

Talk to Me [I] (Interactive 80)

$ nc 0.cloud.chals.io 33987

 ____                   _               ____ _____ _____ 
/ ___| _ __   __ _ _ __| |_ __ _ _ __  / ___|_   _|  ___|
\___ \| '_ \ / _' | '__| __/ _' | '_ \| |     | | | |_   
 ___) | |_) | (_| | |  | || (_| | | | | |___  | | |  _|  
|____/| .__/ \__,_|_|   \__\__,_|_| |_|\____| |_| |_|    
      |_|                                                

Congrats! You've successfully connected to the challenge server!
Here's a flag, if you're interested in one: spartanCTF{g00d_j0b_w1th_g3tting_h3r3}

Would you like another (YES/NO)? NO 

i GUEss YOu CANnot apPReciaTe THE faCt tHAT i Was rEAlly tRyINg TO MakE the wHOlE fLaG acqUisiTIon THINg EAsY FOR yoU. buT I guess YOU jUsT cAn'T SAY YeS. For oNCe. YOu do kNoW WhAT The POInT of tHiS CTF Is RIghT? YOu SHouLd Be DOInG eveRyTHING yOU CaN TO gET aS many POints As POSsIble, As SOON As POSSibLe. tHEre is oNLY oNe FiRsT PLACe WINnER. YoU SimplY cANnOT Win WIThOut aNY FLAgS.

But that's fine. Have it your way.
spartanCTF{g00d_j0b_w1th_g3tting_h3r3}

Talk to Me [II] (Interactive 90)

$ nc 0.cloud.chals.io 33987

 ____                   _               ____ _____ _____ 
/ ___| _ __   __ _ _ __| |_ __ _ _ __  / ___|_   _|  ___|
\___ \| '_ \ / _' | '__| __/ _' | '_ \| |     | | | |_   
 ___) | |_) | (_| | |  | || (_| | | | | |___  | | |  _|  
|____/| .__/ \__,_|_|   \__\__,_|_| |_|\____| |_| |_|    
      |_|                                                

Congrats! You've successfully connected to the challenge server!
Here's a flag, if you're interested in one: spartanCTF{g00d_j0b_w1th_g3tting_h3r3}

Would you like another (YES/NO)? YES
Well. . . Too bad! Enjoy this wall of meaningless text!

fgoU84zaj0-gHG7AKYzGw-qbNnD0VA_txGMPCkTNhdQANkcNrqteGUvlWlyVth1kstnRLfU9oBvo155S2ZXUYWWyVQ9OhkuZNF9N6GCTeZW_h73QruZfqBEV_KAKdm5LHAo657p2VIhZgLeEfus4WuZhIGgVbEtZUGK44SYE737eChDhjYjJDCijQf8jFomA8TmwJ4BijQbDEZu9Ma7T8IDhCMl9Z-6jJS49zdERv5RpBYkY79Ji5PQYGYlHtXVkDd7zcohxHggIL0IqgEoc2slJBnU5epHA0u4F4lh0_KKjvSs89NDb9W066TKGTyqGiGLju4455rpTJ_2j9SnmBRT46l63noHRVByzA2tYbYQmwwQHr4OSPhrXiYas_mx6eLdOM57_4DNr5USiXFS1Rsua0rFdUF5r_ouAgzRAjX83uDVTlgz7wWTWpBhJfu17B0fLjKlFvZkm0lC1RpL7H0m2FVwuWSSQh7l2wu0qz94Tl-qtsBl-JqEH7nUT9s39dBkpmkQfPVA2EWHABjDACy03Jm8HxMQGMhp1MwpY_vOD0dHCTer1zwkHRs4rdWcfYV961I6k2ZdKF5k1H_yD920PZNHulqLCOEMlGlbtTkC7ioG84SHKpXZXofr3C8nGit6-S5W6Ws22gKlIBs0R5JcckKnB2mt0BPdkCpgJ-CCsixn0ws3dUsGbSaQEw93D8mOFy1gfizB8XdC_g5tXbCXiraGdwAtqBxu-mY7EoyegPtkXUb39UA5PUtngsqFkuVf2oAM0mKOeo_Gb7Os1NG2Dpiq6aMc8gg9hJDhVujH4preQ0hPA2_bEBkoos0ddpii0-bxHIXARY3tMcO6hOFvpv1fjLj5J1-HewBCeMXLt4P9XDYRqSFpDzOMhnkg0vKIH3I9EWzsMxbMcVNVucvKJISkPqZ302ldjkYWiphPhP7OtllEVKsPrcgz8Z7BQqpjEzs1Ldj-CPIZwR4mYQ8StjqQkgjCVOJHUTEouIxy0RRd5RrwRHtpvz9PosrDkWTMQMqVnlG6SNXqvpm-t8XwASeGk66YsY3b3LGrkCNWNNcZYctPw92DBaMSklv4y9qSZepDm9QktE9ikC1sccD1WmaIlnTdCyFignjx2F862mXTeWskeJlC0fKyybJf9gEtiKd3IyW19OVJxeIpE9XKvEenXVeeFzChi96lswyGg0VAIjEdNGADBjNnzUOq71qRx4MBNwh8gAFCi4_Gvl7fT1VyMUaM7sjGa5BgnyEjIuO0nFC6fpfYyMakDnqpkGsgUUO4JHBYYt5LqC2so7Z5iwmKZBV9cQfN0d-9uObR6XbCRV9kkDqdfjij3M-N1JPRcYzDIzFUdipKiuQfQrE7tJI_C2rqvMGVNq-ATdY_mtKUougUKr0jZLgs2t-ovqeGM-ejNUCIEDL3VGd72-PpC_ESmn0QcB9RzLimMTC6ALz1PCQAXth-ouX1P4hh-T8Dxu8N2sg77g68PQtMDuVvstJJ-FLP4NdtDWg9AuFrUyq0IhNsg2ZkZQ3xHgAubW-QYwPU6P7OJYWbPzBl-zfI9KTLAQYIx53WHfM3ZwNLUP-iFeVqAjOeiqmOmg9EvbSShMie5hSET1srj9PNIBWWtfv20YsW2alxXLaDprDRzpJWaiITUeAaJoFw-DdC6anldLu83NOJxqdnTZe0DvhmbxEN5Oox2XKaeFMGRHTIZxkwO4MakXqf7HPQxHUg8hiIgwWsyi6hw7LEhKQEfKzRia6dOH4QzU4rMWFCeLtAGrjIVU4ZOOja5j7HmDBGX1UGs8ZFs9jP7N_YPJdzNHCv4H_I2fu74RddIPwx01nzRUii-3ta19BDP7AlrzpE9gWiY2hjty7-YpwKTFXSCTxR5cMJ3sgbihuB42LmaHxqCm-y1NvagKRqf_sYH3wss6in5Qph2jFwdtAV402g8hg1YUc1XcjMk91oB6f4ZB4MESE8RdQ9LwXFzkJY70tB7-T-rddBALNcO3c4GrR28GISQ_7ju7lKdJHHRueDRdJwUWU5It0ZXIqgC5glnriAG7UOJg78etKmfClSQLklNO4jIDbdC_MljqF635bj8USZoBOW-jvzaWdZV-LxBBkkXAUyuV40HkMjwf_RE0dp7tEEGmBlONUU4aFYvkFlBihEB4gFOTFugREd1ell3Hy2KUu3pHxmmpCHFn4sUo9MnAuT8gvRPsLoGEuOpt4w7Ca8eSs9uGpIfA_onU2LN5bFfo4I-c9JuC2h5E40DSriNj4H_SRkLapuACKSgniHcQK-1vgjpy_QEfNV3f5vFCSrXChn-rP4coUocTd-uPv_uyGfSkuw6m311F5D6ZmiFL6qD8M54584o3QNxv5hdUlK4qItAfrr22Lp7hXGN5ZNmWbZMuiizeZGY9jN7DcNNAZBc-BDpJUUK8FjRJx1QivZQjLeDC_O5akB5ih6K9HCXDeTSQXrRMwtzMbTR4SW4rzj9C6-WvlUuT8SjXC5CjzYZ3t47qR46ZPAeAZAHpcubgODCTscgtLUpWi-JkwK5CqPlGPYG1j4lw1HUi_p_a0ejUXRUauhecP9lbAFvyddUVF6pvGjw3l2GpFPh7pkfnjynTMKWACJzF65mrdjMdc05Owa49R6fj8o9BGGLp_8IoKdBbYaVczDjdVfTQNB7D86GOiIKKfWGmngM7mFhk50-Qd06FMkEio2YJuGQ5B4vWRmnE9LNTFe_yvpPOE2VgaJs4JuQw3ywYJSTtUvhvIvtBqIQY5SOuvEh25SwR3zX3aG6r3Mlu-jaEuiBBayEHjA8WT2HkTu3RAQq4cGcBjZ9wqfeewqp7SjJpYCwCxHCpPvdIKtwz81_133G_86PdKywSkMkWQHPIoLrHUhk91X7v2SK8QcGxidSk4MEhiasdngepmsJLhKku-kAEq804aqJPG93ZRczc-A-1if-zNdkBlCuojXruk-nm7bg9j3XK6WeYQfkDdj5InxJekFSwOR2Fwk5y8wSonxb6dSki2w6KWZH0kJlxS_H-B7KPb0FQIkTF2zOI3pqZj4qmfC28PhaQsm4ZjXHJP0pDh-miEZt1BwOw4hG7F3W30xYYhIj_VwyhSpy6vUVJNqItiroSQfcSY2dy-ptzQMnZqG9lswgJYqHdiCJx-J9Gw0y8Ck6reYcsXDZT_enjkrWsGcCr5l9_HrUhtNZVC4wd3uCLKQfZnu2EGchhUBhvtKHBmpmlUKdDhCNksrwOwBqjetF8972rYyYfHaPpG9q742z5g7gv2GYyyyRcq1L2zRlNzFrAuv7tV19Dl7C8YqDB_gM0gNkrDj-45LGHVpeOBoos30lwvM1r_yFTRPY5vdg728Cm_wy0iCM1RhNfSkXGtCNpQyXPfrACC02o58-p8X9Twu-D8CKPKrNhjZBP8Dhxq5Q69slMxLrgxYniSL3DVyEq1ib1MdlorIKsj6fAgPunbNWXl8kfvgS0bPsQHmyTvMi8bv95MG05mCZJ_Slfq_LjHrttiiZNvAg30mbiGzQNC_x0HMFZ4bsA1yvCqlPjJLhJeU5KkvddpOA8_-JWJ4EIVZzwfGTeUjld6b1oGqKrFignJ_T93EgrRTR16P4BH2-1nJQ9M5EBJzHvlxlLnCHPDDaJn198UKDYwd7HkIE4rVO67BFNYERIf5P2dKhJOzy-x_0sLlVTBkQVWFeHpFrZnBmj-WZZhVUOofTvjQRcFNrFAnGPUs6phEFgc6UvXDRYEmxH0sH4eNMeAVTGIFAYX-lfkNSZDNfgc3BoTAJTWDNSrJ1X6MRIdv9Lrm3vw7iiuiHlSTOoJWo71sEhhPgPmb_qR9aMb_MLEBuzxcdAp6VO_f5WtXnnfV0PKmCTaa6fvNO-23N-BFip9Qsiz5qzmlE2ZVLvyfgha_Q_lRBIs_AnI1KpLJQusej1_naEB3YDTeZAAjbepDeMiNfV4uV_NLd6fGH3tTJwuCU2gFFkC2s5UWzF40coHqmx9GbGOjrFuPc-FymNW2S45JBS2Z2a8wVw-mZykIR6eXSrLQI3UrGByE0cSzKAmzoBMPF97d5OVlK7casgPd8Vyoqy6FwZHh_dVin3yD2mWMZQHIFblkmXFmTKUMaOioP4fkGmmrVeb1NNVXyuvu45lKF7M8eIszj07eeGCskwraWvzK2xjFzhQJtb0Ul5hliUbPgBxdMOSCKvOrDjFw-g1Y0OVmYv4AQ5V3YCN4VqyeFwFH2Pd7eq2_CmBFHvppFThTCSleqd5RBrExaCjGMO9DJiLiug-j7dOZ1wg-cG9g6L-dWACxVh1JWoS_i43cooG21bJeSib_OA7MWvZnHwUHLE_CQ0GNvk1IYf92QUowCxZQ-eyuGd2MC3KUwnOlJ6d_m0iOLx5tNHWH2kddK4wSyTmSdok0ttuws2NDoZLJXDceVSDc1Yb0MjV7iQN19RxRLRreQ86Mio46DMBSrt747qYvm6ZGjVHnFG5S2ZORa5fUKvLDIH2EJ2UM9Htob5jT8a3gjgDEHtfFotx1h544hCpTSCDjY3oe_maIr92eNqn4Ukoopr9EL76FhF2fB7onRAkIbcJUfhPCBgkSXriz4Q6WuTZQIM8lJNwCCgCGq_31cEW7LY3mD_DEeeePqh0qSgfsg1t069Uu7_hSKEqcDcul9GlIbe3vkiieb7JhqYCrCaVyW7TGIAlwogQmpFW7GbjjJ9KhpPYrUJa51t5_9TXFK4nq98DLWjHCKmun0FjrHl-P4mpHJiNGoLVBWWreuI3JfmQmahtJmJlLbQHCuUohoElSdDfc_DQ8ZS3h6WmAHFwE0XkvVelWSzdTdaXMRteZR6vfj2OjdbPUNUeMj6Y7LFZsv3REdaq6Jekl1gPz4HD9GoRH642Uu5WQzNF_0eOIDhJ55LnFLsx-x4N_kJHGksUTdlkSmfQJBriWHU6vn95g3LYIMn_7LmeAyV0ShU81_BZiz-lhJhFqseu-ShOEWtUPJDiJBdTVa96F0htjDm3lHdttvrWMOPuIjOs8G96MAYoGiXrNXysesHAZd0w5jqO1ho5NIZGMpB9ByKizYzx17EsnniIpX4_fND10D1LSiUbFmRwfrnnXOL5uLBEX4P69BMAItlAlt5rvpc01qNgNfEr0BrMSGop5kWW7LHh2dsAKDtlo7ZlqIykGSNCGtcVbgsub0E-NZWzTsbNWMmLyayjsqLmmv2QwQUx1I1DRB9AyJ7vLHVE1m66ncDqjxXFdPK-94OimmLWk1oOKYNJ7y2gYmSFx5wdNw1KBoOJrx2U5wkDPPULKUz6VLQM77-vExbzbc8sCCOLo80v3RbJVFzV6EPx3y806MZru6PJBtkM2YX8bq6tg4KkTSRYJot1F6Md-M76RfPBg0YI5aW2atQ83dDCTrJGWuq93rpVogOxEXD-sB3N0iPTdAoOaTlLIH_NkKZTsc0wVDLtL4LHapSdHBVQidQYm4j5NKl67QVB4MpKSyqkkDXKl1HlAisVs3mmqSTtvx3h_0Pqkx0DJ-Z7yMRbCt7Xd6yZS5rp4HA5Nz88WBN9wAxlBUwfEj_YfAzVigxelTyfLJ2CPrLAdto5Uz-SZdWgDcKOEIjdWimDjCL92Vt5VXfJ6Do1zxQrMTNmBWhoGkSvTQZQ3aPJFUVec9TS0x2KzWg5uAuvpkhnKIHPF4AolKFeHdr3xONW0-PyFAxegZrj1Ya8Q6yVKr7s-i_mR_Z4bjqBQGS2Kp49L5XdmSUp68yMU-ke8SHm1Zg69YTJ_D2Dteu7PP-GMXJFkMc2N_8cFq3C3cnpDBdamleolgCV40kdvSyyxqfK6w3vJSdqyR-NjxW_Uod6z0TaE8xTq41zNb-yP7YVjU9_HXtC6S7c8K5X-0nc6NtRYmnYKIjhmutFl-AKTS3K2uSnal4HZu9mZpwEPdfJSxQRlvcqDVGWPRLGazGweHBeNqMgbEGrlVqfUwo7z0_C7eaHKb02BCC5Orj8PBmmeqs1ruNNaVkB03XpZE_Q53IWrIfNfNlIp_8EE9wbruESbN3z4iQ8ACsXU-f5-2_NQOqD0JZj_O8E1Eh-gWOULbmgkVV7sj8rEvuU7e_AoQd9tbeQ5A4xF8GU1kDrcAYmDqZRH3hdSkXXpvAhYAErTguwxFWhZZxmQVTj87fNhba7zbtKMSctOvBr0uUeNloyjr2J3IN04TP_Ss8QlAhaLS5jrNQNZLy6wmNN_oeuJJYAFDwxptnqWB2qsUjuUFuZ_WzNP0MtyEzoZRIlKKPGQATiGASTJjV_QUW0OVapBNIGgWhjlsuJ56a8TbkA6evvKh2NeF1ClYXi_nkAYEpYtmSB7dGMXG1Lm2vrWMWuHjsj5F78xSH01a1xXTxABxcS9BXiW4axcHExNtnfmtRrebnwbeOnLdtYy4pqeze0Jep3QuLt6IH84NHgh3J-8SVNdd4WMCY9ELZPgdsjJMD3U1_ceCJsMbJN48wOnTk-ptaS3_XM0CtG8BDDfP7conPoETvNVOy2yazE9pQ9wMdZoPyn41ao9dSSxhDygeAXVCL2s-cjD8EBSjLYh3TugWKhlHLg-SbNPrYkwHs6KDFTjYOeWDlAjT53MNyU67-P5hFytp2Ly59JvSs4wNGAyCW_jkyAk1x1kzBmcRpK99Put_RJYlmeJMXgYGK_tb1XDZuk8yU6x4VIU5RzMspartanCTF{f1nding_mean1ng_1n_cha0s}qdOfvJDBfs_eYxQ6L8GzoqAQGqTIplaK4k46_PmoGHNMAsrraP5E4ZBZq3QlRbEJlrKRvXeDAf_C_Sec82pFHXQ2jG4e6i7KJCGj8pUNIGRT7mCbxg-fYLbzDI9KOljjTM_axxgl_V3b-Ab485q1-XNr4I4OZpYiwh3w7xP6cciBARQG8pyadc69sXE7CR7Dulqb_ebrjgL_9g3MTClA4YcB8K8BysGkiVw--hHZOuV0_HSfLqBG6AuNPyMtw_oz-j124A-F3LT0rU8J2qZqAdH2q19KSek9ngv2wA1Ot5m8tWAYhlX0T_v5Ubs_NUTkstuTKqdlYMcCX4wheq2rRDEEwmYGC265kVtIlvKWkSEQS-EBhqJXZ9eSrvWBmqQEeMoo9tS13nkEbO293U3MOgQZff3gktGDtW4ebsxDk9AR0jhOargsNoIRAN8mRGY6Kp9FN9wdhx3gPPlkC7PQDtyMsCDLldPSqzPwAmqyiktcNty35cr3E4_Y5JrCN6HdL-XFlbFsJhJhPtxNg4G3GXkopNqHDJGbmyubNFJVLynCSoJREoG6Po6tckDr6kq2tW9oMCuk3AcNF9jUgQiW0OLWUwqOol_Vkbc41YYiyjCHMYb8igKrYAbbUYHpLBKSba6z6j4OqRk91f76_96hjlNdY5jQIB-VeRjrfg9QCV5KLYXQTmm47MkWN6ydxZvCHeqtY4WNKSqJB6M6l6UIMHZvtpf0oDvkMb1i70HYDDWkw55m1PJ1YBWH_xpyTDrx2018bP5ygRU-P7XpsTLEOn9C1qXAlv3ndmtD7OekdJ4gG1g4hanPog8YK-EJT2cW5Cic8aqKzhxIuqYAefvn0tXh46WRXh8Ka1oIGeDy_ZheaGtG_h8rj4cN6GCrwYMwT03czUZvr4v7aZDAk8kVEzI38m3mNa06i1_5zR2O-7erW80upUO9AGzg2hLnevjIk30MHu-KmLlnZIgAultsHyMx1jSfyGaedZigOZ7JRLRrY6r2erOMMzMCwCRcpKoqFprWiNI9KnmBRW15n7GFaAfV67qV0LuZpx0n7Fggo02vfXJewos5_nkkUimiM3koabKDTQqkGVNVWrHRSnN-SwMPIxE6Vw_K8QlteZh_CRgVZk-RGk-rWWMmuf_g_X9Pthi3ZoKreBlQ4TtC3SUdSWKRjJ5MvwwOekV9J13nw0eyK_cncDJUgpgZbnnXUP3ZBaloQAy6haIu0iJ7HbiEM-pRnEBnRynz8yk93nIAC-Kka0p12AYWfV0mH2o_eKxoaBCfPV5YkJxX0Ka7HgHrJyW1ZMl1Cjbr651QBElr16F_Iw2Y3_p42zptK9jjGDhcz-YXoeLArQsdrg5C7WWanmc8Y-FpNWgiJGUV-Du_LJJMc1zAycHKico_KPNPcUHdQepvOFUyFD7aKpa-TbHgbrFDVJADIGHBP9cg8tZYvYqELb6RC-BC9I8jFYKi0sm4dqgfv7qociZPBfwXxorSZMzZsQNjF6LBm3HLFNFU7STg6Xy5c5lYQosIdRkivkV29F9Oo9-LsASlfpQVZp3ynQ9ADoPJp365xjyQcBu0JrwYC0nC9asMMOw-5eGRCTbMw-REdZ10g7UdQm8OG-RGLaFK2ybxOh_bsUh3AtwDpZlk225RwJTc1Xlm427p5L3rVvgxMxWVklhSs5d9hl5HVI44JHBzTtxbYS8mqTi8Ba7yPnwbPaSCMduahtPjTHMs3NeBeJvwfSRgYy69Z0gvlGuHyo-FX_65a4qyZXHumWJp_SjbTGWCwrDasztnfFtbZl3HrMrRaqyUNBuD95GoeB-1fkrDSIH2GN-qHeNBbUNxdLx39BpLKio8opGuekyJ4AoNNuoHRAchZVldaON6yO4FFTlvndRacDM5RDSOheXzroXzGDtJrjcYKzrQcw0G4x-_xSUKojaMS_z8NSevo80eBtDicSadTnHNZVZFMHlqOeIqrh4iC-uJa1XWTNj7aDbkAZn9EZ1EX55GWguulv3EBYw1VGbMy5XfstQktFWKb-OivAbUd2WeTbimHlta399QDkqD5kQdFVA5QehEcEhNY1CCf3G_Cz-4KA3gXK5tFAIQEcNfhbFUyCzmGGkdpgRSBp1LUqMzVvoeC2Mpmx1Z0hsbfYUkrNDOmkM9VwIc3j2VU2mZfOw5XBUXUfpS1nQHKNGdcJYwsDsKQsYBae8Dx6cQ4cno4f5oDZ1XQycTY32yVqhd4RSpv9nw83OxSSqdJfEM1PC8gLgcmyR_jWKLIjA75xS2T1ls7uFdbf4X2fS4vPekGSn0dYPGldO33liQtHUMHozhJraSRAV8BVwSo1umnaCNuUibZzLn5F9KjCcD9OOBLy5yr-AD8D3QI70AFfoVMOJCtKbmG0XoYemGsRplmC6lGVBUukRYZqYGpW04FWPpraYg2qyjYNrywDD0M0mCSeGle93JQ8QSHaPes58D07tp5YLtk_Llk9smS7TJ9gln0U1wNW3fjFgMy7S40ilUJDDaFtpQGOWqAb4oobsSZTx5WpAC6Qdkdo25WJMdx_MTh0cVcCuLPt5my7krCcJ60rTv615ZM1dgSsORvTQO_fVNYJdznI-JQAr9V_XqnEKvfW_5uVy6wXhze-7r8251j1V6iMYeu7xjE_YuRkELdnqopOZMrna_hJefsmn8qfi_bXaL4hX1XleYoqAmA5gU_5vANT8OH99-QdxOzPJXZKSQ7DbFI-P4XF7OLGbHS8FcjLeM1sQOeqsbVwoTNlOdY5bW7SIUnHMzd5Jm8sBibcfGlCCGQOO0_9tbjXkk-8YqLGIDn0hgJjCotjR9kXkjRVGTyov-ffChv9ZMio86rKfT0RMoayk6HoQe78JAThYNXjEWW3EkAyD8fhttAnWt90nHBzaxU87xoDIndmUVJO8HQfFhHyiE0rgmkiOMnJ-SRa6EbC-ddbVtGVybCcUG4_-8j1FkvTlIOQPNeQk0CoQ2mMUb2BDlyq35-V25tPoJxhjsWaqBRfXd4iBVpNCdQ0AEFVqBcD2jZsExpXDC1E_v4v6v2i4O6Ox4cMKQYFWiJiIBbfYZcIxeQ6dHGXNz6y8YMJMArlrZ4xR17VG0im276UC7xbytJtiCUzXDtt3ouXEejVrvkfkXTkNJTtdmVbP225bHNRo4W6GnCTGUNQT_Ge3_fuoJRxnKNMA2nleWTRPz_V6EQ4Dgctr4lZjGUF-GqO0X9vntQO65qlQJJsV60iOnCMV5lpln0o9iCaHot1Ecpv-16ZUdiVTzB9dnA2tcNXLF7hqWpRFii1F6Q1HBbzcO80kL2SzZtlzXmlTwP-GKiFI5Pd5yGSekxQpJVmKgy71O4sh8LWhSA2Lc2LNzUGfZS7FFjErYbqa_94VwexYhJub_-TNbREA49iGAs7AItMfS-GUI2oN4IW9145AHAvDdyj4AjPYljphUQhM70ciSylSvi_pZdw17hqjMgUclHcsEGvWCbuG0mLnADuRFl2N-oAH_F0GkF75zsssfp7YUZ21IV5-C1rktGBJafnFqSqSzuhRyMU9BQ3qbSWU-xysGwclJDBPgVYVsN76nXWTgWM1nnjucTRK72UvCUcgmKunQGifsu2gR95hoqDeqw6VlCOlqJTrqBVs8j8XweDNNS6kO5HlmNWE00tmttVU3g8KCUqUYbrX9oBZi-TB2e93o3beAwx6wqIB4o0M_DXyl03W3oe3DIQqm-SWldzfeuFAVaQOuWTiQ9yBB2BbQLQqMbTrx8WgcFnWqcNve5whTFF4fG3pSQf5upZf1fVqJ9iEkAfS0wfe1lAwxQi5lV78TYbRrDvQbDcjbxaGGc3hQM0KFIzbpoWr5XaCQD-zzm2q5EyqLe5rougY1zJRig1txgzmaidp2cVWnF9cUz2Ae-lGVQ3U5s__kwS7qESWNF5QR60KHWacIDmqrf0HFXSGob9JOuSpsIYyYpQZMBrS8HQGVhK99UJ0Q4UR3GQf3oQob_0bpgK_oUMwddk9PC43HX3Nb06mwiQURFNIklTMcc7POfaIY7hQoemD14b2anZyRQiwQ__USfMjkoieskL4F8vv7HM_C9CPAsJZ38usQS_Pu7TIq7adlhcTvy3ZPQWGz60TWHnQeLdpcCJgKQsI4aj9FHJtAAgw6HOH-xitvp_0y2kqVabSQzU1iwEyuXqXyh5VR9b7zO7tejT65jtTntBc7bmidcKlrxRG8fPT2C9285CSZ9JFBuvx5BNkpiXScL6Ng-WKU_4lavjPtc3ziiMVBi_C79VStSeATjjLGauoy6h5vBtEH16hnWnemtxLof8HrBRRFx-FNXrL1pGeRAG-4fdKeLwLFcYzNclmCJ7LvQr19Fj3-td0CaHB1DUm9mr-0-Bg04PTx_2Sqmy9ACijZF3tOEuPT9i_yDxyzoXIttFnXvxEhMWLJsJkuXEGzNIYz3aUUz_MRqyMD-k-Tprdo_F1mcQO46kCZQZVFPVvFitLvmj97kxibDfP6UW7BLBHCZ99GbKz1_yRQNVdN3frZzOdD8gf9yb1u1879Es2xLkxxnlewMJisYBzRpW91HdH3jS1iUmuXWeH70zAaGUDOhvZkGivKiIgCavnbzgWC9vvtyS6txM7ij1wB9r47WlYQ4mRNss4gHVUYtMWlizu62Vvi8ZXcpWFgTeNrN7V-ygjTiPSibTiRtxGvP1Ghu-Yl1l_lR_tSsLOlwB0YcSawQnqfGBkZpltfdHBoPkNjevanrw2w09IkSMNF9-PgVUKoZ6mwaWDIayTFoQOBv66l6NkWGFJLHa_3aQNAjYiDz_8RHdgGdknmfORlozsUwaYzcd7fr31d6oWZZmYZEF5wdOlw4PMyJOQKqVM4AgaZFalHd6ZuxTYyg0FD1Pa4sTT1MDynq4v-ttN-1kH0fAJmYcFmIkS7I4xJFQOET15Kidt8n61Dh51ZmSPUF42-mRbrNloekysSSrFzOwGNG6Nv3IEdQ7pQTODD6RRSpZpB2L3egS8Gopv8BYHbqmJNb8ow6_Mi9FZfmsHWiVPKexxie-v_mduz7h5mgoQv7fxnKLp2Pmf4QMixwBO611Zsn9LauPVx4XrJAra7hKJkdMcJfUwXQQqLnmiU7dEq0KIpe06UtlP0Y2VfyShOMJkl4mL-W06JWhZsWEjsdzzvalAmqa8kMkHK9ds-AqCVPErINlL4paIUr6KAE_p9mbLslD-NrnVBiX_8N1Qj6FKEsw7kkMldvyjIdRvpbQuEAFsAUa1Pp-OacftzoCfzh_4VJPiNYMFGL_zQNL1Ue5MS00x0KfSee9gVBxv0atJjNO7cpHC5bNRJctXJFCPJ5AgJBU1-xDexudorCyOmtQsP05z8H01CfblqVbkhFA-KJljZjyoqRvb2oPaPqHnjCjQAjF0OZA8eZJEAD8gnXGTONcfMEo5Rg-nYCwnyVZi3EH5V4bm119Ceeuble0sXyVVOh4AgwVDezoAuy0hno1O7AQA7-JZpm2FLpzVGWpDEL6YErqba0Y6scYqVdwPAh5Dd-J05V4BmZ-ZtDd9MIIjEMzOij7mk0faOrIOHrRzcQOdlLri8DCFEZWxAlmziGWB9SW274xWfUGBU7cgN9KttLa5e7k2qgrxWJDwljx0dqhmLpts_NlweA_gVAxe941aRhZwTNkxnFlqHJjWWFMzbsPLokrfjQSoUlMslflyQ1QyQNNtJ9PVh19FX8_cFoNyRbB7-MPDp4YT6-R-NPDYjlTcGmUzp5rqnLoCiHIGT3Zoh4oPyDsocCa4gu-3abyPgUlZ4Xx95967IzrJh54XUuE3BIQG-dtiEkGacEkgrp7ijU_0KvNtV75Jc5JEE2fc6MXujyW0aAcP8waYpF3vQ5fsskq4yn7cCzS5psvU7f8pyEFq9V_Fdpcm2fHHkvK4uXv33CgaUoHWFtB0fMTz8hA6d-jyJppD37JqqN4PzUAaUBsGq0fGoY0MczmFvpLttyxbVkKUt33bR5SwWWeD74MGYImDYnE5fMHKb3AJQEaryAZRvhHjsj3X3ZPfWSRR6tmJjSsvUhSlMCi0YCrg-0JXPDcBdiE5FRXrvmb9JZXgabYPHeGX71KSsDoFUuo0BAU1O63wNyPVu98jMeKrwO81HwaWyJ53GeBI2gFcQ_11-HsWzTfte_ffHpiVPbfKkS-R-XNnI_eTpPqx_bFnjeeMtZefa4AmseIJ5w7X7Ns7rLaHmou0JRcx7qUrQAn0u_l_KdrguebXCZHv77cGQkugTbwMRdAQfAhtdqi42ihK0nMsYe-aijfiz5aW3t8yty9A9blxs-kGb1cQRgNiQxZHe16RDb4371Jc4L6FqTAr2dNJ9NH5gI-c2jRVAWZlD_FZlJmGDfaQIlIhUCmeVYD9-cGm4kzkfkAfdJ5J22H7KOAXZZ_GtLFIma1ushXJL0bv8ezsplDD_wdY4VFQSsLevp9yeg2dL08XTZSyfFmBi44vq2SRcV__Xd0-B0oVKT-kO0s1gfACW-deuB4XqifId99mIG1fA4pMXuaWwOjw0ZIl3BgUnQ7z7GekEA8WYNS2jKGmZGkmewYzZiExmWnPUm6y9Jd5l_j0m2C0r7XvsNBZyBLLilGhHtEb7S7EQmiitZYtWlbgNHUbQ4tBPas1128n5EPuYh-5BRgeraN_xeQgK9YgWT1BT24k

この長い文字列中にフラグが紛れ込んでいた。

spartanCTF{f1nding_mean1ng_1n_cha0s}

Talk to Me [III] (Interactive 100)

Talk to Me [I]」で表示された以下の文で小文字を"0"、大文字を"1"にしてデコードする。

i GUEss YOu CANnot apPReciaTe THE faCt tHAT i Was rEAlly tRyINg TO MakE the wHOlE fLaG acqUisiTIon THINg EAsY FOR yoU. buT I guess YOU jUsT cAn'T SAY YeS. For oNCe. YOu do kNoW WhAT The POInT of tHiS CTF Is RIghT? YOu SHouLd Be DOInG eveRyTHING yOU CaN TO gET aS many POints As POSsIble, As SOON As POSSibLe. tHEre is oNLY oNe FiRsT PLACe WINnER. YoU SimplY cANnOT Win WIThOut aNY FLAgS.
#!/usr/bin/env python3
from string import *

s = "i GUEss YOu CANnot apPReciaTe THE faCt tHAT i Was rEAlly tRyINg TO MakE the wHOlE fLaG acqUisiTIon THINg EAsY FOR yoU. buT I guess YOU jUsT cAn'T SAY YeS. For oNCe. YOu do kNoW WhAT The POInT of tHiS CTF Is RIghT? YOu SHouLd Be DOInG eveRyTHING yOU CaN TO gET aS many POints As POSsIble, As SOON As POSSibLe. tHEre is oNLY oNe FiRsT PLACe WINnER. YoU SimplY cANnOT Win WIThOut aNY FLAgS."

bin_flag = ''
for c in s:
    if c in ascii_lowercase:
        bin_flag += '0'
    elif c in ascii_uppercase:
        bin_flag += '1'

flag = ''
for i in range(0, len(bin_flag), 8):
    flag += chr(int(bin_flag[i:i+8], 2))
print(flag)
spartanCTF{y0u_cant_get_what_y0u_want}

Eightyfour (Interactive 140)

出題される計算式に答えていく。

#!/usr/bin/env python3
import socket

def recvuntil(s, tail):
    data = b''
    while True:
        if tail in data:
            return data.decode()
        data += s.recv(1)

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('0.cloud.chals.io', 24386))

for _ in range(4):
    data = recvuntil(s, b'\n').rstrip()
    print(data)

for i in range(10):
    print('Round %d' % (i + 1))
    data = recvuntil(s, b'= ')
    print(data, end='')
    answer = eval(data[:-3])
    print(answer)
    s.sendall(str(answer).encode() + b'\n')

for _ in range(4):
    data = recvuntil(s, b'\n').rstrip()
    print(data)

実行結果は以下の通り。

Launching computational intelligence benchmarks.

Please respond to each question with an immediate response. If a reply takes too long, the test will be terminated.

Round 1
654050919262795248 + 333111857139109945 = 987162776401905193
Round 2
327674781586996111 + 451991449093278596 = 779666230680274707
Round 3
620395274353857848 + 164297346893514715 = 784692621247372563
Round 4
308289783000397819 + 482988808666491610 = 791278591666889429
Round 5
408896797767172917 + 825717191706866999 = 1234613989474039916
Round 6
249224077449216570 + 201272982942158454 = 450497060391375024
Round 7
192596142621718374 + 662717274944450725 = 855313417566169099
Round 8
93698272602889979 + 904723096742383268 = 998421369345273247
Round 9
521319513171522720 + 929022107614600343 = 1450341620786123063
Round 10
556243972330491330 + 555005377563543896 = 1111249349894035226

NO COMPUTATIONAL ERRORS DETECTED. TEST SUCCESS.

spartanCTF{n0_y0u_cant_b0rr0w_my_c4lculat0r}
spartanCTF{n0_y0u_cant_b0rr0w_my_c4lculat0r}

Chocolate Chocolate Chip (Interactive 150)

https://spartan-chocolate-chocolate-chip-service.chals.io/にアクセスすると、クッキーのsessionに以下が設定されている。

eyJ1c2VyIjoiZ3Vlc3QifQ.ZiDPag.27qgulW6Rcz61QZWK9fg43L4qIE

https://spartan-chocolate-chocolate-chip-service.chals.io/loginにアクセスすると、以下のように表示される。

SERVICE UPDATE 4/17/24
Login mechanism temporarily disabled for security audit. Admins should know how to bypass this anyway. --baker

Flaskのsession情報と思われる。このHMAC Keyをクラックする。

$ cat session.txt     
eyJ1c2VyIjoiZ3Vlc3QifQ.ZiDPag.27qgulW6Rcz61QZWK9fg43L4qIE
$ hashcat -m 29100 session.txt /usr/share/wordlists/rockyou.txt
hashcat (v6.2.6) starting

OpenCL API (OpenCL 3.0 PoCL 3.1+debian  Linux, None+Asserts, RELOC, SPIR, LLVM 15.0.6, SLEEF, DISTRO, POCL_DEBUG) - Platform #1 [The pocl project]
==================================================================================================================================================
* Device #1: pthread-sandybridge-Intel(R) Core(TM) i7-10700 CPU @ 2.90GHz, 1433/2930 MB (512 MB allocatable), 4MCU

Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 256

Hashes: 1 digests; 1 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1

Optimizers applied:
* Zero-Byte
* Not-Iterated
* Single-Hash
* Single-Salt

Watchdog: Temperature abort trigger set to 90c

Host memory required for this attack: 0 MB

Dictionary cache hit:
* Filename..: /usr/share/wordlists/rockyou.txt
* Passwords.: 14344385
* Bytes.....: 139921507
* Keyspace..: 14344385

eyJ1c2VyIjoiZ3Vlc3QifQ.ZiDPag.27qgulW6Rcz61QZWK9fg43L4qIE:webdesign
                                                          
Session..........: hashcat
Status...........: Cracked
Hash.Mode........: 29100 (Flask Session Cookie ($salt.$salt.$pass))
Hash.Target......: eyJ1c2VyIjoiZ3Vlc3QifQ.ZiDPag.27qgulW6Rcz61QZWK9fg43L4qIE
Time.Started.....: Thu Apr 18 17:24:24 2024 (1 sec)
Time.Estimated...: Thu Apr 18 17:24:25 2024 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........:  1279.9 kH/s (0.28ms) @ Accel:256 Loops:1 Thr:1 Vec:8
Recovered........: 1/1 (100.00%) Digests (total), 1/1 (100.00%) Digests (new)
Progress.........: 382976/14344385 (2.67%)
Rejected.........: 0/382976 (0.00%)
Restore.Point....: 381952/14344385 (2.66%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:0-1
Candidate.Engine.: Device Generator
Candidates.#1....: womendeai -> virgo74
Hardware.Mon.#1..: Util: 47%

Started: Thu Apr 18 17:24:01 2024
Stopped: Thu Apr 18 17:24:27 2024

ヘッダ部のデータを確認する。

$ echo eyJ1c2VyIjoiZ3Vlc3QifQ== | base64 -d
{"user":"guest"}

baker用のクッキーを作成してみる。

$ flask-unsign --sign --cookie "{'user': 'baker'}" --secret 'webdesign'
eyJ1c2VyIjoiYmFrZXIifQ.ZiDcsg.uk11ci7v9W1OTkKP-gYJUonD7Lo

このデータをクッキーのsessionに設定し、https://spartan-chocolate-chocolate-chip-service.chals.io/にアクセスすると、以下のように表示される。

Here are your cookies!

「cookies」のリンク先のhttps://spartan-chocolate-chocolate-chip-service.chals.io/pantryにアクセスすると、クッキーが焼けるような動画GIFが表示される。
クッキーのsessionを見ると、以下が設定されている。

eyJjb29raWUiOiJjaG9jb2xhdGVfY2hpcCIsImZsYWciOiJzcGFydGFuQ1RGezN2M3J5X2IwZHlfbDB2ZXNfYV9jMDBrMWV9IiwidXNlciI6ImJha2VyIn0.ZiDesw.uVJXIPjJKfQ5MH_oKefH6GYX4EU

https://jwt.io/で内容を確認すると、ヘッダ部にフラグが含まれていた。

{
  "cookie": "chocolate_chip",
  "flag": "spartanCTF{3v3ry_b0dy_l0ves_a_c00k1e}",
  "user": "baker"
}
spartanCTF{3v3ry_b0dy_l0ves_a_c00k1e}

Excavator (Interactive 150)

https://spartan-excavator-service.chals.io/robots.txtにアクセスすると、以下のように表示された。

User-agent: *
Disallow: /index.html
Disallow: /portfolio.html
Disallow: /login
Allow: about.html
Allow: contact.html
# Disallow: /login.old.html

https://spartan-excavator-service.chals.io/login.old.htmlにアクセスする。HTMLソースを見ると、スクリプトに以下のように書いてある。

    <script>
    
      function authenticate(){
        var authorised;
        
        var username = document.getElementById("username").value;
        var password = document.getElementById("password").value;

        if(username == "ExcavationAdmin" && btoa(password) == "U3VwM3JTM2N1cmVQYXNzdzByZDE="){
          authorised = true;
        }else{ 
          authorised = false;
          alert("Sorry, credentials are incorrect.");
        }
        //return result
        return authorised;
      }
    </script>
$ echo U3VwM3JTM2N1cmVQYXNzdzByZDE= | base64 -d                                
Sup3rS3curePassw0rd1

https://spartan-excavator-service.chals.io/loginで以下を入力し、ログインすると、ポップアップでフラグが表示された。

Username: ExcavationAdmin
Password: Sup3rS3curePassw0rd1
spartanCTF{y0u_dug_th3_passw0rd_up!}

Destroy After Use (Interactive 250)

$ nc 0.cloud.chals.io 13998
MDS v1.0.0
=========================================
Welcome to our proprietary message delivery service. For authorized staff members only.

•Enter "RETRIEVE" to receive an encrypted message left by a client. Public key used for encryption included.
•Enter "QUIT" to terminate this session.

>RETRIEVE

PUBLIC KEY:
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAMtU42MYyRVcPCunNpMQ/avI4TeekEHttN88dzDw15q4FJ313R+FXVCq
V2VC6QBDh/1dpg1z78R/85cfptysA62g73awWw4WF+xRm1N6O1FhYcVLB9GzZwQe
EJfDMQXJM+A/k8s/7kplkZNoB4N9DmNNmaQ7tRy4KCJ5IiK507MvAgMBAAE=
-----END RSA PUBLIC KEY-----

MESSAGE:
qdqih2tpdSoPwf1A4shbo4Z2wE7cAJG5A9zA3oK0iAU/ribRvg8vCyauPfpY+mKhoxq4vlUcT8V9fa83cOIncroPPWkg+ZUrKRodbB7HVvCZmsk2+ba1QcyNmE/4QeJjovGKEHX+70vn06+bv2mPlUzwxmJRYvFFCiEE8TP+YEc=

>RETRIEVE

PUBLIC KEY:
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBANWxT1paYAPKmaGR1X1uf4uYHz8BMwHQHbk8c5cmyz7slqb2GtM5dTN1
DvxMLXGjDZ5HY120WRt8G71znmxQsQrRwzjasReMk5oIyHjiCSYUDuV32y2QFbgq
PWFVVYjVF48BaOc07YDv55ZfDIn69RILy9Be6mgiWP33BvpiltSrAgMBAAE=
-----END RSA PUBLIC KEY-----

MESSAGE:
zhT+LePqZHC97DShZ67IN/pmQ8e0raaGDvDd80ubIlTN1gmQBOH2bpSI3kA4/j8ZY+ikQ7NVUUXQkPCG4hnpJSk80eWXWl/KgTY7DbS1bBFK2oMOClUkjTky7nH9MYRBE+yW0Ur7cO3YfstAgAv1FP0ZU2dJ1f9xMUvBtWfdcN4=

> 

RETRIEVEで毎回異なる公開鍵で暗号化されているようだ。公約数を取れば、素因数分解できるので、復号できる。

#!/usr/bin/env python3
from Crypto.PublicKey import RSA
from Crypto.Util.number import *
from base64 import *

pub_data1 = '''-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAMtU42MYyRVcPCunNpMQ/avI4TeekEHttN88dzDw15q4FJ313R+FXVCq
V2VC6QBDh/1dpg1z78R/85cfptysA62g73awWw4WF+xRm1N6O1FhYcVLB9GzZwQe
EJfDMQXJM+A/k8s/7kplkZNoB4N9DmNNmaQ7tRy4KCJ5IiK507MvAgMBAAE=
-----END RSA PUBLIC KEY-----'''

pub_data2 = '''-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBANWxT1paYAPKmaGR1X1uf4uYHz8BMwHQHbk8c5cmyz7slqb2GtM5dTN1
DvxMLXGjDZ5HY120WRt8G71znmxQsQrRwzjasReMk5oIyHjiCSYUDuV32y2QFbgq
PWFVVYjVF48BaOc07YDv55ZfDIn69RILy9Be6mgiWP33BvpiltSrAgMBAAE=
-----END RSA PUBLIC KEY-----'''

c1 = 'qdqih2tpdSoPwf1A4shbo4Z2wE7cAJG5A9zA3oK0iAU/ribRvg8vCyauPfpY+mKhoxq4vlUcT8V9fa83cOIncroPPWkg+ZUrKRodbB7HVvCZmsk2+ba1QcyNmE/4QeJjovGKEHX+70vn06+bv2mPlUzwxmJRYvFFCiEE8TP+YEc='
c1 = bytes_to_long(b64decode(c1))

pubkey1 = RSA.importKey(pub_data1)
n1 = pubkey1.n
e1 = pubkey1.e

pubkey2 = RSA.importKey(pub_data2)
n2 = pubkey2.n
e2 = pubkey2.e

assert e1 == e2

p = GCD(n1, n2)
q = n1 // p
phi = (p - 1) * (q - 1)
d = inverse(e1, phi)
m = pow(c1, d, n1)
flag = long_to_bytes(m)
flag = flag[flag.index(b'spartanCTF{'):].decode()
print(flag)
spartanCTF{n3v3r_r3us3_pr1m3_n4mb3rs_plz_f023e56a}

Touch Base (OSINT 25)

HTMLソース見て、"spartan"で検索すると、以下が見つかった。

data-code="&lt;!-- spartanCTF{w3lc0m3_t0_th3_c1ub_bb78d66e} --&gt;"
spartanCTF{w3lc0m3_t0_th3_c1ub_bb78d66e}

Evesdropper (OSINT 30)

問題文にある数値の羅列をASCIIコードとしてデコードする。

#!/usr/bin/env python3

ct = '78 105 99 101 32 106 111 98 32 114 101 99 111 110 103 105 122 105 110 103 32 65 83 67 73 73 44 32 98 117 116 32 116 104 105 115 32 119 97 115 32 106 117 115 116 32 97 32 114 101 100 32 104 101 114 114 105 110 103 33 32 82 101 109 101 109 98 101 114 44 32 104 97 99 107 105 110 103 32 105 115 32 97 98 111 117 116 32 102 105 110 100 105 110 103 32 116 104 101 32 101 97 115 105 101 115 116 32 119 97 121 32 116 111 32 103 101 116 32 116 104 101 32 100 97 116 97 32 121 111 117 32 110 101 101 100 46 32 73 110 32 97 32 114 101 97 108 32 119 111 114 108 100 32 115 99 101 110 97 114 105 111 44 32 121 111 117 32 109 105 103 104 116 32 116 114 121 32 103 111 111 103 108 105 110 103 32 66 111 98 32 116 111 32 115 101 101 32 119 104 111 32 104 101 39 115 32 107 110 111 119 110 32 116 111 32 98 101 32 114 101 103 117 108 97 114 108 121 32 105 110 32 99 111 110 116 97 99 116 32 119 105 116 104 32 40 115 111 99 105 97 108 32 109 101 100 105 97 47 98 108 111 103 32 112 111 115 116 115 44 32 112 105 99 116 117 114 101 115 44 32 98 117 115 105 110 101 115 115 32 112 114 111 102 105 108 101 115 44 32 101 116 99 41 46 32 77 97 121 98 101 32 121 111 117 32 99 111 117 108 100 32 101 118 101 110 32 116 114 121 32 103 111 111 103 108 105 110 103 32 115 101 118 101 114 97 108 32 111 102 32 116 104 101 32 110 97 109 101 115 32 112 114 111 118 105 100 101 100 32 116 111 103 101 116 104 101 114 32 97 110 100 32 115 101 101 32 119 104 97 116 32 121 111 117 32 103 101 116 46 46 46'
ct = ct.split(' ')

msg = ''
for c in ct:
    msg += chr(int(c))
print(msg)
Nice job recongizing ASCII, but this was just a red herring! Remember, hacking is about finding the easiest way to get the data you need. In a real world scenario, you might try googling Bob to see who he's known to be regularly in contact with (social media/blog posts, pictures, business profiles, etc). Maybe you could even try googling several of the names provided together and see what you get...

BobとEveとのやりとりによく出てくるのはAlice。

spartanCTF{alice}

Recovery (OSINT 60)

以下のハッシュが提示されている。

07fc8e7f9f675b4281b1ac40ca187eb5da698024cb6bf893be62a96da33cfad5

CrackStationでクラックする。

bigdork!
spartanCTF{bigdork!}

Hide and Seek (OSINT 150)

https://twitter.com/dstein1971を見ると、2023/12/22に以下のメッセージがある。

New blog post just dropped. You know where to find it.

以下にブログについてのリポジトリがある。

https://www.github.com/dstein1971

コミット履歴の「update README」を見てみると、フラグが書いてあった。

spartanCTF{th1s_1s_n0t_a_great_1d3a_dcccfd40}

In Plain Sight (Forensics 50)

$ steghide extract -sf in_plain_sight.jpg        
Enter passphrase: 
wrote extracted data to "flag".
$ cat flag            
# almost there!
c3BhcnRhbkNURntoMWRkZW5fMW5fcGxhMW5fc2lnaHRfYWJiNTA2NWF9Cg==
$ echo c3BhcnRhbkNURntoMWRkZW5fMW5fcGxhMW5fc2lnaHRfYWJiNTA2NWF9Cg== | base64 -d
spartanCTF{h1dden_1n_pla1n_sight_abb5065a}
spartanCTF{h1dden_1n_pla1n_sight_abb5065a}

Desist (Forensics 60)

$ strings letter_v2.pdf | grep spartanCTF                        
/Producer (spartanCTF{n3v3r_f0rget_th3_m3tadata_5b1bfc6e})
  <pdf:Producer>spartanCTF{n3v3r_f0rget_th3_m3tadata_5b1bfc6e}</pdf:Producer>
spartanCTF{n3v3r_f0rget_th3_m3tadata_5b1bfc6e}

(Lack of) Authority (Forensics 99)

$ openssl x509 -text -noout -in cert.pem
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            0c:00:e8:06:9d:7f:a0:6b:a8:e4:50:c3:d8:c4:ed:bc:9c:c4:b8:6e
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = US, ST = TEXAS, L = AUSTIN, O = SPARTANCTF, OU = 2024, CN = spartanCTF{w3lc0me_t0_th3_w0rld_0f_auth0r1ty}
        Validity
            Not Before: Mar 11 21:41:07 2024 GMT
            Not After : Mar 11 21:41:07 2025 GMT
        Subject: C = US, ST = TEXAS, L = AUSTIN, O = SPARTANCTF, OU = 2024, CN = spartanCTF{w3lc0me_t0_th3_w0rld_0f_auth0r1ty}
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                :
                :

証明書のCNにフラグが設定されていた。

spartanCTF{w3lc0me_t0_th3_w0rld_0f_auth0r1ty}

Can You Hear the Music? (Forensics 120)

Audacityで開く。チャネルの1つ目がDTMFの音声のようなので、切り出す。
切り出したwavファイルをhttps://dtmf.netlify.app/でデコードする。

1151129711411697110678470123108511169510951951045211851959711712095110511201169511649109101955652985151989748125

ASCIIコードが結合されているような文字列なので、その前提で文字にする。

#!/usr/bin/env python3
enc = '1151129711411697110678470123108511169510951951045211851959711712095110511201169511649109101955652985151989748125'

flag = ''
code = ''
for c in enc:
    code += c
    if int(code) > 31 and int(code) < 127:
        flag += chr(int(code))
        code = ''

print(flag)
spartanCTF{l3t_m3_h4v3_aux_n3xt_t1me_84b33ba0}

Whose Encoding Is It Anyway? [I] (Crypto 30)

CyberChefの「From Base32」でデコードする。

spartanCTF{just_an0ther_0bs0l3t3_enc0d1ng_4a809cb9}

Crossing the Rubicon [I] (Crypto 30)

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

Rotation 23:
This one's probably best left to history. Nice work! Flag: spartanCTF{3_7u_Bru7e?37284749}
spartanCTF{3_7u_Bru7e?37284749}

Something’s Fishy Here (Crypto 30)

Deadfish Languageと推測し、https://www.dcode.fr/deadfish-languageでデコードする。ASCII Charactersとしでデコードすると、以下のようになった。

115 112 97 114 116 97 110 67 84 70 123 115 119 49 109 109 49 110 103 95 119 49 116 104 95 116 104 51 95 102 49 115 104 49 51 115 56 55 50 57 52 55 54 52 50 57 50 125

これをASCIIコードとしてデコードする。

>>> codes = '115 112 97 114 116 97 110 67 84 70 123 115 119 49 109 109 49 110 103 95 119 49 116 104 95 116 104 51 95 102 49 115 104 49 51 115 56 55 50 57 52 55 54 52 50 57 50 125'
>>> codes = codes.split(' ')
>>> ''.join([chr(int(code)) for code in codes])
'spartanCTF{sw1mm1ng_w1th_th3_f1sh13s87294764292}'
spartanCTF{sw1mm1ng_w1th_th3_f1sh13s87294764292}

Crossing the Rubicon [II] (Crypto 35)

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

Rotation 13:
How'd you like the sequel? ROT-13 is reciprocal, but not very safe. Nice hack! Here's your prize: spartanCTF{13_12n't_LuCK7_4ft3r_411.27453829}
spartanCTF{13_12n't_LuCK7_4ft3r_411.27453829}

Whose Encoding is it Anyway? [II] (Crypto 50)

Chappe Alphabet。https://www.dcode.fr/chappe-alphabetで復号する。

spartanCTF{who_is_this_chappe_guy}

Almost Large Enough (Crypto 80)

$ openssl rsa -pubin -text < uploads.pub
Public-Key: (1044 bit)
Modulus:
    0b:0e:a2:4a:68:f8:be:dc:fb:26:ce:59:dc:00:ac:
    0e:a9:5d:14:86:18:57:7d:cd:08:43:e4:af:69:df:
    16:9a:11:58:a1:73:91:a0:af:b0:8e:d6:71:1a:71:
    b2:0f:4a:90:e4:60:44:85:de:e3:1a:3b:9a:77:bf:
    98:0a:dc:f5:4e:ba:01:5f:44:3e:42:c2:12:24:7e:
    54:df:75:04:73:c3:43:2d:f9:4f:20:6d:fb:36:ee:
    9e:c7:79:a4:67:78:e0:a6:e6:51:8d:b6:e2:c8:ce:
    9d:ae:15:d6:12:2e:9d:b7:48:03:c0:e2:94:81:38:
    32:1d:49:e5:b4:bf:62:6f:6a:db:1f
Exponent: 65537 (0x10001)
writing RSA key
-----BEGIN PUBLIC KEY-----
MIGhMA0GCSqGSIb3DQEBAQUAA4GPADCBiwKBgwsOokpo+L7c+ybOWdwArA6pXRSG
GFd9zQhD5K9p3xaaEVihc5Ggr7CO1nEacbIPSpDkYESF3uMaO5p3v5gK3PVOugFf
RD5CwhIkflTfdQRzw0Mt+U8gbfs27p7HeaRneOCm5lGNtuLIzp2uFdYSLp23SAPA
4pSBODIdSeW0v2JvatsfAgMBAAE=
-----END PUBLIC KEY-----

nは以下の値になっている。

n = 0x0b0ea24a68f8bedcfb26ce59dc00ac0ea95d148618577dcd0843e4af69df169a1158a17391a0afb08ed6711a71b20f4a90e4604485dee31a3b9a77bf980adcf54eba015f443e42c212247e54df750473c3432df94f206dfb36ee9ec779a46778e0a6e6518db6e2c8ce9dae15d6122e9db74803c0e2948138321d49e5b4bf626f6adb1f
  = 130268447115800793670969941660122023743138867500338107215168957059882598899049986121633175112078836299883375143848298686533154709548789077575282105358896390203127587810012637937058130600063960122373086865292975173802950727976807192933591320309038955899332929955344975932115610894739698545200885848588197476910684959

nをfactordbで素因数分解する。

n = 968857 * 134455804226837184095248258164127444755148455861224212876790854646126929876183983933266906377389889632715018979940588432073210710712508737177191376393932634230983094316305334984479784529671520278403404078510012492868349744055941375180848484667024087042084569709817832695759653792809154029130084056355269639287

秘密鍵を生成する。

$ python3 rsatool.py -f PEM -o uploads.pri -p 968857 -q 134455804226837184095248258164127444755148455861224212876790854646126929876183983933266906377389889632715018979940588432073210710712508737177191376393932634230983094316305334984479784529671520278403404078510012492868349744055941375180848484667024087042084569709817832695759653792809154029130084056355269639287
Using (p, q) to calculate RSA paramaters

n =
b0ea24a68f8bedcfb26ce59dc00ac0ea95d148618577dcd0843e4af69df169a1158a17391a0afb08
ed6711a71b20f4a90e4604485dee31a3b9a77bf980adcf54eba015f443e42c212247e54df750473c
3432df94f206dfb36ee9ec779a46778e0a6e6518db6e2c8ce9dae15d6122e9db74803c0e29481383
21d49e5b4bf626f6adb1f

e = 65537 (0x10001)

d =
2a11808d1dab515902c7b3682edf922db1ffa743201998f00c9318c713c8de796f45905cc9699083
412387c13bcfcc5aac94b8ffe28f24604e98bf4b5d23f718d75bfa1d6e898051cb765bc3d9bd295f
822b68c9b679fd2f48e729a37269bd7ed752e5280058a634c7fe938f580b01be9a1c5b3d87b19ae0
3d8ad00b7b37d0d6f0e1

p = 968857 (0xec899)

q =
bf78af09c43035dd0541e88e57ec13a86e3c4139310082258336354fd4dcd8a18c2edc85215c7716
fab40b26e71737970c1de78db2d236d6ec3f17213b88f4aa3fe1c5a34177a758293003bb9e2a69d6
761f7bf95f48418eddeb2c3d715d8ba2619d16e9790e2b40dd15c7f887370e770b8f4775814ddd67
f806f20887ddfc77

Saving PEM as uploads.pri

生成した秘密鍵で復号する。

$ openssl pkeyutl -decrypt -in file.enc -inkey uploads.pri
spartanCTF{n3v3r_us3_small_pr1m3_numb3rs_62036ce9}
spartanCTF{n3v3r_us3_small_pr1m3_numb3rs_62036ce9}

Numbers on the Orient Express (Crypto 80)

CyberChefで以下の順で復号する。

・ROT13
 ・Rotate lower case chars: チェックあり
 ・Rotate upper case chars: チェックあり
 ・Rotate numbers: チェックあり
 ・Amount: 8
・Rail Fence Cipher Decode
 ・Key: 8
 ・Offset: 0
spartanCTF{A11_A80ARD!48937298}