この大会は2020/11/20 2:00(JST)~2020/11/22 4:00(JST)に開催されました。
今回もチームで参戦。結果は3750点で546チーム中14位でした。
自分で解けた問題をWriteupとして書いておきます。
Common (Misc 150)
違いがある文字のfile3.txt側の文字を拾っていくと、フラグの逆順になるので、逆にしてフラグにする。
with open('file2.txt', 'rb') as f: data1 = f.read() with open('file3.txt', 'rb') as f: data2 = f.read() flag = '' for i in range(len(data1)): if data1[i] != data2[i]: flag += data2[i] flag = flag[::-1] print flag
JISCTF{s0m3_c0mm0n_dt4_b3t33n_tw0_f1l3s_jisctf_2019}
Oh my rain!!! (Misc 150)
パスワード付きzipになっているので、クラックする。
$ zip2john OH-MY-R41N.zip > hash.txt ver 81.9 OH-MY-R41N.zip/data.txt is not encrypted, or stored with non-handled compression type $ john --wordlist=dict/rockyou.txt hash.txt Warning: detected hash type "ZIP", but the string is also recognized as "ZIP-opencl" Use the "--format=ZIP-opencl" option to force loading these as that type instead Using default input encoding: UTF-8 Loaded 1 password hash (ZIP, WinZip [PBKDF2-SHA1 128/128 AVX 4x]) Will run 2 OpenMP threads Press 'q' or Ctrl-C to abort, almost any other key for status management (OH-MY-R41N.zip/data.txt) 1g 0:00:00:01 DONE (2020-11-21 09:57) 0.5235g/s 9650p/s 9650c/s 9650C/s chatty..sweetgurl Use the "--show" option to display all of the cracked passwords reliably Session completed
パスワード management で解凍すると、data.txtが展開される。その内容にはアルファベット大文字と数字、最後に=のパディングがあることからbase32と推測する。
import base64 with open('data.txt', 'r') as f: data = f.read().replace('\n', '') while True: try: data = base64.b32decode(data) data = data.replace('\n', '') except: break print data
何回もbase32デコードすると、brainf*ck言語になる。
-[------->+<]>+.-.++++++++++.--[->++++<]>-.>-[--->+<]>-.[----->+<]>++.>--[-->+++++<]>.>-[--->+<]>-.------------.[--->++<]>+.>-[--->+<]>--.+[-->+<]>+++.++++.>-[--->+<]>--.+[-->+<]>+++.---[->++<]>-.>-[----->+<]>--.+[-->+++<]>++.+++.----.-[--->++<]>+.------.-[-->+++<]>+.+++++.[++>-----<]>.[-->+++<]>--..-[--->++<]>+.+[-->+++<]>.-------.>-[----->+<]>.>--[-->+++<]>.
https://sange.fi/esoteric/brainfuck/impl/interp/i.htmlで実行すると、フラグが表示された。
JISCTF{TH1S-1S-S1MPL3-CH4LL3NG3}
Baby Reverse (Reversing 100)
Ghidraでデコンパイルする。
undefined8 main(int param_1,long param_2) { size_t sVar1; long in_FS_OFFSET; int local_134; int local_130; int local_12c; char *local_118 [4]; char *local_f8; char *local_f0; char *local_e8; char *local_e0; char *local_d8; char *local_d0; char *local_c8; char *local_c0; char *local_b8; char *local_b0; char *local_a8; char *local_a0; char *local_98; char *local_90; char *local_88; char *local_80; char *local_78; char *local_70; char *local_68; char *local_60; char *local_58; char local_48 [4]; undefined local_44; undefined local_43; undefined local_42; undefined local_28; long local_20; local_20 = *(long *)(in_FS_OFFSET + 0x28); if (param_1 == 1) { puts("Try harder!!"); } else { if (param_1 == 2) { local_130 = 0; local_134 = 0; while( true ) { sVar1 = strlen(*(char **)(param_2 + 8)); if (sVar1 <= (ulong)(long)local_134) break; if (*(char *)((long)local_134 + *(long *)(param_2 + 8)) == '-') { local_130 = local_130 + 1; } local_134 = local_134 + 1; } if (local_130 == 3) { puts("drink water!!"); } else { puts("First argument must be in the format number-number-number-number"); } } else { if (2 < param_1) { puts("Think out of the BOX!"); } } } local_118[0] = "AFLdfgArTkdwelkfkmkasFFEWSWasCFsfsdfewRRWDSCFAWDHg"; local_118[1] = "sddgrlksjpothjafkgpOEWFKQW0EOG9AWRI90VA8RUGWE9R8BIhDJFOIBSDF"; local_118[2] = "SDSL;FKOKEIER0T9W85690843GJDKVJASFQLIGUQWO;ECLDskvjar;lgksjg1dflb"; local_118[3] = "kjhKKHJLKlkjhlksriufer9erudskjhLKHJW3EROIWUEOIUkjkhsdllkejgrgpdffSljk"; local_f8 = "sdrdgkj4598fgjkksdffvggvljkt66yhpooijjKJWEROJISDOVIHEERGNoqiqwjedqwkd_jaasfefn"; local_f0 = "wewro3k34j4r39vjwewlkrfjwefoiasjALDLADSLFKWJEFWk23eqwqfweoryirut0h9dfbjlkwelkw1kj3e3f" ; local_e8 = "xdlkjefwi9eru8239r2efjkldsvjlwk4g439berflklkjwff1982eiuqukKJSDFKJWEEF0OSDVJLKSKSLKJEFSJW0"; local_e0 = "098765432QWERTYUIOPASDFGHJKLZXCVBNM,W453948573498EWIFUERRGKHJFGBKDJGNBDDGksljgerogijdflkb_ckdfbj" ; local_d8 = "dflfkgdjflgkjdflgsktjhworepgqajrlvLKLSADDKGJWREOGSJIFDLBKXDFGJBLKEKRTHHJOPSFGBJLSKFDGBJSLsdlfkdf4ldkfgj" ; local_d0 = "DSLDFKGJWREGPOIWERJBSDFLKJBDFGLBKJklsdjff3948tueg98idduvvoierrguj0eer9gjgodfbbojiereoigsdfkgjdfdfdfdfdfNdb" ; local_c8 = "dglkjerge9r0gwe9fwfoiuiSKDFJFWER9GDEORIJGDFOIBJRTOIBJDFOBIKJER90GGU3U3EGF09USEDGOISDFJGDOetewrtwertwfwFIJB_DF" ; local_c0 = "XFLLKVJERGPERG9W8UER0G9SPUDFBOIIJDFOIIBSRT9BURERFBOIDFDBKSJDFBSDFOIBUJSFOIBJDDFLKLKBJSRT09HWRBBOJIDFJOIdfdfsdeffsdWOI" ; local_b8 = "DFDVLKJWWEFF983R7239812IUEASDFKJSDKJSFrgsdfgsdfgsdfgsddRTOISIJFBDFKGJBDFOGOLNIJDdherethdrgbrffbPWRGQ98ETW98EFSIUDdfsd4fsdfVH" ; local_b0 = "XDKXDJVER9847T398289341092E09EFUFDVJW5Rdfgdfg947T98EREGIUUDFVHJEE9R88TUEED99FVIUHJW9E8FFUQW039DID0CVIDKDFV0E9RUVE09UUJdsfsdfSsdfs" ; local_a8 = "REZEVkxLSldXRUZGOTgzUjcyMzk4MTJJVUVBU0RT0lTSUpGQkRGS0dKQkRGT0dPTE5JSkRkaGVyZXRoZHJnYnJmZmJQV1JHUTk4RVRXOThFRlNJVURWSAsdfsdfsdfsdfysd==" ; local_a0 = "3158117bae155dab40b42244b9554d0d92ad05e8f11d5fe22d3334b84fd3aa5b0289431069ae8757448ae6dfd61c8edasfsdfsdfsdefweoifusiodfjsdfdfsdfsdfsdf_sdfk" ; local_98 = "sdldfkerjguwoierfhjKJLJSDFHROIGEHVSDOIHkjsdhgeorighsdslvkndfljkbfjgbldhkfjghdflgkjsdfpogewrigwweroiojdflkvjdfklgdfjgdlfkgjdfgdlfSDFDRGERGDFRGEkj21" ; local_90 = "xlxdkfjddrgloeiut9348ut398gf3jur9gfeirjklefejlkKLSDSJGEORIGEJRGOIEJRGOEIRGJDLFKGDRGEIOWUERWEIORUWEksehj9f38ru239r2e9jf3948fj34oiferjgDRGSDFGDSFGSD3FGSDFGSDeoirjg" ; local_88 = "dfgldkjgw958yt3u4ro09eijusdikjhOSIDHFWW9E8FWOJEFSWJFDLKFDJskdgher49g383egijoigjerlgkejrglgeworigjwregvdfmvdfoigerugeoirjgrolgDFGDSFGSDFGSDFGSDFGSDFGWERTIWjidfdlkvvgdjfge0rg" ; local_80 = "dlkfjdflfkdfjfgjoi4353KSDJDHFW938RR23IFHWksdjdhgweoituweoigjeglksdgjdslkgjweoijdskvgjdfsklbjhdfgwoeireruqwopqiuyiuIUQWY293R23OIF23R9O32R2378R23IUR2H3sfsdfsdfsdfsdfsfsdfsdfs3dfsR" ; local_78 = "SDSFLKSDFLRKGJkjsdhfw933r823urowieruwoeitueoriteuergoidfjgdlfkgjeeroigerjgoijgvdlllllllllllllllllllkoerieurtoieruteroituDFSDFSDFSDFSDFSDFSDFSERTWEReeewereeeeeeorituwpoqwiposfkjsRld" ; local_70 = "fdghjkytrewqdfgbh9u8toiu4jrwefud98uvgijerkwefiudsvosoifjwrek3efoiusdvffijkewioiduvjekwiosdouvijsdfkelodsviudjsfqeudvs9oijfkiodvdknfdhewuwksam,m,.fgm,glkflkflkvoicxjdksedhsfvoijnfsdskehdvio" ; local_68 = "KSJDFHSIDFWEUIshf3w894efiowejknefioewuwghjkfkkdfkjvdfkdvbfiourifiuruifodrjifjoonvjfkiivojiodjdoivvjdfovdifjdvooooooooooooooooooooooooooooooooffijvdlfkvdjfl2329382@@@@@##$#$#$$%vdfkjvdlfkvj1df" ; local_60 = "lxkcvjdfolvekjvkldkfvjdlllllllllllllllkeowfiefwjeofwoejwfeeeeeeeeeeeeeeeeeeeeeeeeidjsdlvskdfjsdlkfjweoiweifjovdjivoeijrveorijverlkjelrbkkbjerlkejervl%$$%TRGEFGFHFGHFGHJFGHkvjeerlgjerovjervoerNijve" ; local_58 = "LKSDJFWKERJ329FWJEFLSSKDFJSDLKsksejfeh4foeiwrjverlg4jrtlgelkjSLKDFJGBRTORJTBLKDFJBE9RTG3U4GFWOIJjveroibjrthhjtie0orithrjtbrhoithjrotiwjer0oihgeirtDFGDFGDDFGWERGRETHRTYJR^TYUJTYJT%%oidjfgblektrjbelgrgkbjdfnglkjdflg" ; local_12c = 0; bzero(local_48,0x23); local_48[0] = 'J'; local_48[1] = 0x49; local_48[2] = 0x53; local_48[3] = 0x43; local_44 = 0x54; local_43 = 0x46; local_42 = 0x7b; local_134 = 7; while (local_134 < 0x20) { if (local_12c == 0) { local_48[local_134] = local_118[0][8]; } else { sVar1 = strlen(local_118[local_12c + -1]); local_48[local_134] = local_118[local_12c][sVar1]; } local_134 = local_134 + 1; local_12c = local_12c + 1; } local_28 = 0x7d; if (local_20 != *(long *)(in_FS_OFFSET + 0x28)) { /* WARNING: Subroutine does not return */ __stack_chk_fail(); } return 0; }
このコードからlocal_48のデータを算出する。
data = [ 'AFLdfgArTkdwelkfkmkasFFEWSWasCFsfsdfewRRWDSCFAWDHg', 'sddgrlksjpothjafkgpOEWFKQW0EOG9AWRI90VA8RUGWE9R8BIhDJFOIBSDF', 'SDSL;FKOKEIER0T9W85690843GJDKVJASFQLIGUQWO;ECLDskvjar;lgksjg1dflb', 'kjhKKHJLKlkjhlksriufer9erudskjhLKHJW3EROIWUEOIUkjkhsdllkejgrgpdffSljk', 'sdrdgkj4598fgjkksdffvggvljkt66yhpooijjKJWEROJISDOVIHEERGNoqiqwjedqwkd_jaasfefn', 'wewro3k34j4r39vjwewlkrfjwefoiasjALDLADSLFKWJEFWk23eqwqfweoryirut0h9dfbjlkwelkw1kj3e3f', 'xdlkjefwi9eru8239r2efjkldsvjlwk4g439berflklkjwff1982eiuqukKJSDFKJWEEF0OSDVJLKSKSLKJEFSJW0', '098765432QWERTYUIOPASDFGHJKLZXCVBNM,W453948573498EWIFUERRGKHJFGBKDJGNBDDGksljgerogijdflkb_ckdfbj', 'dflfkgdjflgkjdflgsktjhworepgqajrlvLKLSADDKGJWREOGSJIFDLBKXDFGJBLKEKRTHHJOPSFGBJLSKFDGBJSLsdlfkdf4ldkfgj', 'DSLDFKGJWREGPOIWERJBSDFLKJBDFGLBKJklsdjff3948tueg98idduvvoierrguj0eer9gjgodfbbojiereoigsdfkgjdfdfdfdfdfNdb', 'dglkjerge9r0gwe9fwfoiuiSKDFJFWER9GDEORIJGDFOIBJRTOIBJDFOBIKJER90GGU3U3EGF09USEDGOISDFJGDOetewrtwertwfwFIJB_DF', 'XFLLKVJERGPERG9W8UER0G9SPUDFBOIIJDFOIIBSRT9BURERFBOIDFDBKSJDFBSDFOIBUJSFOIBJDDFLKLKBJSRT09HWRBBOJIDFJOIdfdfsdeffsdWOI', 'DFDVLKJWWEFF983R7239812IUEASDFKJSDKJSFrgsdfgsdfgsdfgsddRTOISIJFBDFKGJBDFOGOLNIJDdherethdrgbrffbPWRGQ98ETW98EFSIUDdfsd4fsdfVH', 'XDKXDJVER9847T398289341092E09EFUFDVJW5Rdfgdfg947T98EREGIUUDFVHJEE9R88TUEED99FVIUHJW9E8FFUQW039DID0CVIDKDFV0E9RUVE09UUJdsfsdfSsdfs', 'REZEVkxLSldXRUZGOTgzUjcyMzk4MTJJVUVBU0RT0lTSUpGQkRGS0dKQkRGT0dPTE5JSkRkaGVyZXRoZHJnYnJmZmJQV1JHUTk4RVRXOThFRlNJVURWSAsdfsdfsdfsdfysd==', '3158117bae155dab40b42244b9554d0d92ad05e8f11d5fe22d3334b84fd3aa5b0289431069ae8757448ae6dfd61c8edasfsdfsdfsdefweoifusiodfjsdfdfsdfsdfsdf_sdfk', 'sdldfkerjguwoierfhjKJLJSDFHROIGEHVSDOIHkjsdhgeorighsdslvkndfljkbfjgbldhkfjghdflgkjsdfpogewrigwweroiojdflkvjdfklgdfjgdlfkgjdfgdlfSDFDRGERGDFRGEkj21', 'xlxdkfjddrgloeiut9348ut398gf3jur9gfeirjklefejlkKLSDSJGEORIGEJRGOIEJRGOEIRGJDLFKGDRGEIOWUERWEIORUWEksehj9f38ru239r2e9jf3948fj34oiferjgDRGSDFGDSFGSD3FGSDFGSDeoirjg', 'dfgldkjgw958yt3u4ro09eijusdikjhOSIDHFWW9E8FWOJEFSWJFDLKFDJskdgher49g383egijoigjerlgkejrglgeworigjwregvdfmvdfoigerugeoirjgrolgDFGDSFGSDFGSDFGSDFGSDFGWERTIWjidfdlkvvgdjfge0rg', 'dlkfjdflfkdfjfgjoi4353KSDJDHFW938RR23IFHWksdjdhgweoituweoigjeglksdgjdslkgjweoijdskvgjdfsklbjhdfgwoeireruqwopqiuyiuIUQWY293R23OIF23R9O32R2378R23IUR2H3sfsdfsdfsdfsdfsfsdfsdfs3dfsR', 'SDSFLKSDFLRKGJkjsdhfw933r823urowieruwoeitueoriteuergoidfjgdlfkgjeeroigerjgoijgvdlllllllllllllllllllkoerieurtoieruteroituDFSDFSDFSDFSDFSDFSDFSERTWEReeewereeeeeeorituwpoqwiposfkjsRld', 'fdghjkytrewqdfgbh9u8toiu4jrwefud98uvgijerkwefiudsvosoifjwrek3efoiusdvffijkewioiduvjekwiosdouvijsdfkelodsviudjsfqeudvs9oijfkiodvdknfdhewuwksam,m,.fgm,glkflkflkvoicxjdksedhsfvoijnfsdskehdvio', 'KSJDFHSIDFWEUIshf3w894efiowejknefioewuwghjkfkkdfkjvdfkdvbfiourifiuruifodrjifjoonvjfkiivojiodjdoivvjdfovdifjdvooooooooooooooooooooooooooooooooffijvdlfkvdjfl2329382@@@@@##$#$#$$%vdfkjvdlfkvj1df', 'lxkcvjdfolvekjvkldkfvjdlllllllllllllllkeowfiefwjeofwoejwfeeeeeeeeeeeeeeeeeeeeeeeeidjsdlvskdfjsdlkfjweoiweifjovdjivoeijrveorijverlkjelrbkkbjerlkejervl%$$%TRGEFGFHFGHFGHJFGHkvjeerlgjerovjervoerNijve', 'LKSDJFWKERJ329FWJEFLSSKDFJSDLKsksejfeh4foeiwrjverlg4jrtlgelkjSLKDFJGBRTORJTBLKDFJBE9RTG3U4GFWOIJjveroibjrthhjtie0orithrjtbrhoithjrotiwjer0oihgeirtDFGDFGDDFGWERGRETHRTYJR^TYUJTYJT%%oidjfgblektrjbelgrgkbjdfnglkjdflg' ] flag = '' flag += 'J' flag += chr(0x49) flag += chr(0x53) flag += chr(0x43) flag += chr(0x54) flag += chr(0x46) flag += chr(0x7b) for i in range(7, 0x20): if i == 7: flag += data[0][8] else: l = len(data[i-8]) flag += data[i-7][l] flag += chr(0x7d) print flag
JISCTF{Th1S_1S_4N_e4Sy_R3v3Rs1Ng}
Rev 102 (Reversing 150)
$ file be_true be_true: python 2.7 byte-compiled $ mv be_true be_true.pyc $ uncompyle6 be_true.pyc # uncompyle6 version 3.7.4 # Python bytecode 2.7 (62211) # Decompiled from: Python 2.7.17 (default, Sep 30 2020, 13:38:04) # [GCC 7.5.0] # Embedded file name: be_true.py # Compiled at: 2019-12-06 22:36:32 import operator flag = 0 power = (12 * flag + 44) / 4 - 1234 / 617 * flag - sum([1, 4, 7]) flag *= power ppc = filter(lambda cc22: not any(cc22 % uu22 == 0 for uu22 in range(2, cc22)), range(2, 10000)) dat = reduce(operator.mul, (ppc[i] ** int(str(flag)[i]) for i in range(len(str(flag))))) print dat == 3560267726635400465627540581996487760054035685444946475657505105403063442856963534755133504166293811169018648637812735995934052617540980495952470560844800443626277335201401028364068797946796579956457852457279957300619892623751175557650873016730889125068146398488627192356718363004881175012104986391177956396290571688585499385019181192105543180552708742672275440530116680223358366613050183523086165910780504269235376773473500L # okay decompiling be_true.pyc
逆算していけばよい。
ppcは2-10000の素数の配列。 flagは数値。 dat = 2**(flagの1桁目) * 3**(flagの2桁目) * 5**(flagの3桁目) * ...
期待値を素因数分解すればpowerを掛けた後のflagの値がわかる。
flag = 27390185364980124152929536025508671562111273743374147056
この値をCとする。
power = (12 * flag + 44) / 4 - 1234 / 617 * flag - sum([1, 4, 7]) = (3 * flag + 11) - 2 * flag - 12 = flag - 1 C = flag * (flag - 1)
2次方程式を解けばフラグがわかる。
JISCTF{5233563352533350594343304433}
このままだとフラグが通らない。この数値を2桁ずつ16進数としてデコードする。
from sympy import * ppc = filter(lambda cc22: not any(cc22 % uu22 == 0 for uu22 in range(2, cc22)), range(2, 10000)) target = 3560267726635400465627540581996487760054035685444946475657505105403063442856963534755133504166293811169018648637812735995934052617540980495952470560844800443626277335201401028364068797946796579956457852457279957300619892623751175557650873016730889125068146398488627192356718363004881175012104986391177956396290571688585499385019181192105543180552708742672275440530116680223358366613050183523086165910780504269235376773473500 fac = factorint(target) C = '' mal = 1 for i in range(len(ppc)): if ppc[i] in fac: power = fac[ppc[i]] C += str(power) mal *= pow(ppc[i], power) else: C += '0' if mal == target: break C = int(C) x = symbols('x') ans = solve(x**2 - x - C, x) for i in range(len(ans)): if ans[i] > 0: flag = ans[i] break print '[+] flag =', flag flag = str(flag) msg = '' for i in range(0, len(flag), 2): msg += chr(int(flag[i:i+2], 16)) flag = 'JISCTF{%s}' % msg print '[*] flag =', flag
実行結果は以下の通り。
[+] flag = 5233563352533350594343304433 [*] flag = JISCTF{R3V3RS3PYCC0D3}
JISCTF{R3V3RS3PYCC0D3}
Malicious (Forensics 100)
docxが添付されている。ZIP解凍したら、バーコードの画像が入っているので、読み取る。
JISCTF{B4RC0D3_1M4G3_2019}
So Easy (Forensics 100)
No.182のパケットで認証情報をPOSTしていて、usernameにフラグが設定されていた。
Form item: "username" = "JISCTF{V3RY_34SY_PC4P_F1L3}"
JISCTF{V3RY_34SY_PC4P_F1L3}
Malicious 2 (Forensics 100)
docxが添付されている。
$ file mycv.docx mycv.docx: CDFV2 Encrypted
パスワードがかかっているので、johnでクラックする。
$ office2john.py mycv.docx > hash.txt $ john --wordlist=dict/rockyou.txt hash.txt Warning: detected hash type "Office", but the string is also recognized as "office-opencl" Use the "--format=office-opencl" option to force loading these as that type instead Using default input encoding: UTF-8 Loaded 1 password hash (Office, 2007/2010/2013 [SHA1 128/128 AVX 4x / SHA512 128/128 AVX 2x AES]) Cost 1 (MS Office version) is 2007 for all loaded hashes Cost 2 (iteration count) is 50000 for all loaded hashes Will run 2 OpenMP threads Press 'q' or Ctrl-C to abort, almost any other key for status princess101 (mycv.docx) 1g 0:00:00:22 DONE (2020-11-21 07:16) 0.04349g/s 434.6p/s 434.6c/s 434.6C/s sammy2..nopassword Use the "--show" option to display all of the cracked passwords reliably Session completed
パスワード princess101 で開くと、フラグが書いてあった。
JISCTF{H4PPY_HUNT1NG}
Unknow Ransomware (Forensics 150)
13回base64デコードすると、PNGファイルの逆順の内容になっているので、元に戻す。
with open('flag.enc', 'rb') as f: data = f.read() for _ in range(13): data = data.decode('base64') with open('flag.png', 'wb') as f: f.write(data[::-1])
生成された画像に逆順でフラグが書いてあった。
JISCTF{R3V3RS3_1M4G3_C0NT3NTS}
Colorfull (Forensics 300)
No.524パケットからFTPで送受信しているfiles.zipを保存する。パスワード付きZIPになっているが、パスワードはパケットに見当たらないので、クラックしてみる。
$ zip2john files.zip > hash.txt ver 81.9 files.zip/secret_data.txt is not encrypted, or stored with non-handled compression type $ john --wordlist=dict/rockyou.txt hash.txt Warning: detected hash type "ZIP", but the string is also recognized as "ZIP-opencl" Use the "--format=ZIP-opencl" option to force loading these as that type instead Using default input encoding: UTF-8 Loaded 1 password hash (ZIP, WinZip [PBKDF2-SHA1 128/128 AVX 4x]) Will run 2 OpenMP threads Press 'q' or Ctrl-C to abort, almost any other key for status labeba (files.zip/secret_data.txt) 1g 0:00:00:01 DONE (2020-11-21 10:29) 0.9900g/s 10138p/s 10138c/s 10138C/s toodles..11221122 Use the "--show" option to display all of the cracked passwords reliably Session completed
パスワード labeba で解凍すると、secret_data.txtが展開された。その内容は数字が3個、"-"区切りで10693行並んでいる。
34-177-76 34-177-76 34-177-76 34-177-76 34-177-76 34-177-76 34-177-76 34-177-76 34-177-76 34-177-76 34-177-76 34-177-76 : 34-177-76 29-100-17 0-0-0 8-100-66 34-177-76 29-100-17 0-0-31 24-177-66 20-40-0 0-0-17 20-152-76 :
RGBを表していると推測する。画像にするためには、縦、横を知る必要があるので、行数を素因数分解してみる。
10693 = 17 * 17 * 37
横:17 * 17、縦:37で画像にしてみる。
from PIL import Image WIDTH = 17 * 17 HEIGHT = 37 with open('secret_data.txt', 'r') as f: lines = f.readlines() img = Image.new('RGB', (WIDTH, HEIGHT), (255, 255, 255)) i = 0 for y in range(HEIGHT): for x in range(WIDTH): r = int(lines[i].rstrip().split('-')[0]) g = int(lines[i].rstrip().split('-')[1]) b = int(lines[i].rstrip().split('-')[2]) img.putpixel((x, y), (r, g, b)) i += 1 img.save('flag.png')
生成した画像にフラグが書いてあった。
JISCTF{EXF1LT3R4T3D_D4T4_1N_1M4G3_F1L3}
Hidden (Crypto-Stego 100)
StegSolveで開き、[Analyse]-[Data Extract]で、RGB、それぞれのLSBのみチェックを入れると、フラグが現れる。
JISCTF{G00D_J0B_Y0U_EXTR4KT_M3!!!}
Upside Down!! (Crypto-Stego 150)
{}の中がAtbash暗号で暗号化されている。https://www.dcode.fr/atbash-cipherで復号する。
JISCTF{upside_down_english_characters_cryptography}
Baby Crypto (Crypto-Stego 200)
暗号化処理は以下の通り。
ct: 現在時刻(小数第2位まで) ctをシードにランダム値をとる。 k1: flagの長さだけ256までのランダム値の配列 ciphertext: flag+c1とk1+[0x99]*len(ct)でXOR
末尾18桁を0x99とXORすれば時刻がわかり、ランダム値もわかるので、復号できる。
#!/usr/bin/python3 import random with open('flag.enc', 'rb') as f: enc = f.read() ct = '' for i in range(18): ct += chr(enc[-18+i] ^ 0x99) print('[+] ct =', ct) random.seed(ct) k1 = [random.randrange(256) for _ in range(len(enc) - 18)] flag = '' for i in range(len(k1)): flag += chr(enc[i] ^ k1[i]) print(flag)
実行結果は以下の通り。
[+] ct = 1605733600.6308804 JISCTF{B4BY_ENCRYPT10N_JISCTF2020_QUALIFICATION_RND_101}
JISCTF{B4BY_ENCRYPT10N_JISCTF2020_QUALIFICATION_RND_101}
Logic (Crypto-Stego 200)
1バイトの鍵のXOR暗号と推測し、復号する。
with open('ciphertext.txt', 'rb') as f: enc = f.read() key = ord(enc[0]) ^ ord('J') flag = '' for i in range(len(enc)): flag += chr(ord(enc[i]) ^ key) print flag
JISCTF{W34K_X0R_3NKRYPT10N_M4N_$!}
Not baby crypto (Crypto-Stego 300)
暗号化処理の概要は以下の通り。
■generate_key() ・ran: ランダム32バイト文字列の16進数文字列 ・key_list: ranを2バイトごとにした配列 ・key_listの各要素を10で割った余りを結合して返す。 ■encrypt(key) ・file: 'plainData'ディレクトリのファイル ・enc_file: fileの拡張子をencにしたもの ・平文の各文字と鍵のXORをとる。(A) ・(A)の各要素と鍵の2倍のXORをとる。
各文字のASCIIコードは末端6bitしか影響しないので、それより前の情報から1ビットずつ鍵を導く。その後に末端6ビットを条件を満たすようにして鍵を求める。鍵が分かればXORで復号できる。
with open('flag.enc', 'r') as f: enc = f.read() enc_l = [int(enc[i:i+32]) for i in range(0, len(enc), 32)] b_enc_base = bin(enc_l[0] - (enc_l[0] & 0b1111111))[2:] k1 = '0' k2 = '1' for i in range(len(b_enc_base)-7): c = int(b_enc_base[i+1]) k1 += k2[-1] k2 += str(c ^ int(k1[-1])) k1 += '0' * 6 k1_base = int(k1, 2) for i in range(64): key = k1_base + i cb0 = ord('J') ^ key ct0 = cb0 ^ (key * 2) if ct0 == enc_l[0]: break flag = '' for c in enc_l: code = c ^ key ^ (key * 2) flag += chr(code) print flag
JISCTF{R4ND0M_NUMB3RS_4S_K3Y_!!!}
Not that easy!! (Crypto-Stego 400)
Fを0、Tを1として逆順にすると、2進数としてデコードできそう。このあと、また0, 1の文字列になる。いろいろ試した結果、ベーコニアン暗号と推測できるので、対応付けて復号する。
bacon = {'00000': 'A', '00001': 'B', '00010': 'C', '00011': 'D', '00100': 'E', '00101': 'F', '00110': 'G', '00111': 'H', '01000': 'I', '01001': 'K', '01010': 'L', '01010': 'M', '01100': 'N', '01101': 'O', '01110': 'P', '01111': 'Q', '10000': 'R', '10001': 'S', '10010': 'T', '10011': 'U', '10100': 'W', '10101': 'X', '10110': 'Y', '10111': 'Z'} with open('my_data.dat', 'r') as f: data = f.read().rstrip() data = data.replace('F', '0') data = data.replace('T', '1') data = data[::-1] b64 = '' for i in range(0, len(data), 8): b64 += chr(int(data[i:i+8], 2)) ct = b64.decode('base64').rstrip() flag = '' for i in range(0, len(ct), 5): flag += bacon[ct[i:i+5]] flag = 'JISCTF{%s}' % flag print flag
JISCTF{BACONCIPHERISNOTGOODTOENCRYPTDATA}