この大会は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)) {
__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
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
逆算していけばよい。
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!!!}
Baby Crypto (Crypto-Stego 200)
暗号化処理は以下の通り。
ct: 現在時刻(小数第2位まで)
ctをシードにランダム値をとる。
k1: flagの長さだけ256までのランダム値の配列
ciphertext: flag+c1とk1+[0x99]*len(ct)でXOR
末尾18桁を0x99とXORすれば時刻がわかり、ランダム値もわかるので、復号できる。
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}