この大会は2019/4/13 5:00(JST)~2019/4/15 8:00(JST)に開催されました。
今回もチームで参戦。結果は856点で586チーム中53位でした。
自分で解けた問題をWriteupとして書いておきます。
can you read (Intro 1)
問題にフラグが書いてあった。
WPI{y3s_y0u_cAN_r33d}
Discord (Intro 5)
Discordに入ってピン止めされたメッセージを見る。その中にフラグがあった。
WPI{Welcome_to_our_discord}
WebInspect (Web 25)
HTMLソースのコメントにフラグがあった。
WPI{Inspect0r_Gadget}
strings (Reversing 50)
$ strings strings | grep WPI{ WPI{ warbleglarblesomejunkWPI{What_do_you_mean_I_SEE_AHH_SKI}0x13376969
WPI{What_do_you_mean_I_SEE_AHH_SKI}
zoomercrypt (Crypto 50)
顔文字をUnicodeに置き換える。
U+1F603 U+1F601 U+1F615 U+1F617 U+1F608 U+1F617 U+1F607 U+1F60B U+1F604 U+1F617 { U+1F606 U+1F613 U+1F604 U+1F613 U+1F602 U+1F608 _ U+1F60E U+1F603 U+1F603 U+1F601 U+1F613 U+1F606 U+1F607 }
フラグの部分が"WPI{"になるようにコードを変換して復号する。
unicodes = [0x1F603, 0x1F601, 0x1F615, 0, 0x1F617, 0x1F608, 0, 0x1F617, 0x1F607, 0, 0x1F60B, 0x1F604, 0x1F617, 1, 0x1F606, 0x1F613, 0x1F604, 0x1F613,0x1F602, 0x1F608, 2, 0x1F60E, 0x1F603, 0x1F603, 0x1F601, 0x1F613, 0x1F606, 0x1F607, 3] unicode_base1 = 0x1F5B4 unicode_base2 = 0x1F5CE msg = '' for unicode in unicodes: if unicode == 0: msg += ' ' elif unicode == 1: msg += '{' elif unicode == 2: msg += '_' elif unicode == 3: msg += '}' elif unicode < 0x1F610: code = unicode - unicode_base1 msg += chr(code) else: code = unicode - unicode_base2 msg += chr(code) print msg
実行結果は以下の通り。
OMG IT IS WPI{REPENT_ZOOMERS}
WPI{REPENT_ZOOMERS}
jocipher (Crypto 100)
Easy Python Decompilerでデコンパイルする。
# Embedded file name: ./jocipher.py import argparse, re num = '' first = '' second = '' third = '' def setup(): global third global second global num global first num += '1' num += '2' num += '3' num += '4' num += '5' num += '6' num += '7' num += '8' num += '9' num += '0' first += 'q' first += 'w' first += 'e' first += 'r' first += 't' first += 'y' first += 'u' first += 'i' first += 'o' first += 'p' second += 'a' second += 's' second += 'd' second += 'f' second += 'g' second += 'h' second += 'j' second += 'k' second += 'l' third += 'z' third += 'x' third += 'c' third += 'v' third += 'b' third += 'n' third += 'm' def encode(string, shift): result = '' for i in range(len(string)): char = string.lower()[i] if char in num: new_char = num[(num.index(char) + shift) % len(num)] result += new_char elif char in first: new_char = first[(first.index(char) + shift) % len(first)] if string[i].isupper(): result += new_char.upper() else: result += new_char elif char in second: new_char = second[(second.index(char) + shift) % len(second)] if string[i].isupper(): result += new_char.upper() else: result += new_char elif char in third: new_char = third[(third.index(char) + shift) % len(third)] if string[i].isupper(): result += new_char.upper() else: result += new_char else: result += char print result return 0 def decode(string, shift): result = '' shift = -1 * shift for i in range(len(string)): char = string.lower()[i] if char in num: new_char = num[(num.index(char) + shift) % len(num)] result += new_char elif char in first: new_char = first[(first.index(char) + shift) % len(first)] if string[i].isupper(): result += new_char.upper() else: result += new_char elif char in second: new_char = second[(second.index(char) + shift) % len(second)] if string[i].isupper(): result += new_char.upper() else: result += new_char elif char in third: new_char = third[(third.index(char) + shift) % len(third)] if string[i].isupper(): result += new_char.upper() else: result += new_char else: result += char print result return 0 def main(): parser = argparse.ArgumentParser() parser.add_argument('--string', '-s', type=str, required=True, help='the string to encode or decode') parser.add_argument('--shift', '-t', type=int, required=True, help='the shift value to use') parser.add_argument('--encode', '-e', required=False, action='store_true', help='encode the string') parser.add_argument('--decode', '-d', required=False, action='store_true', help='decode the string') args = parser.parse_args() setup() p = re.compile('[a-zA-Z0-9\\-{}]') if p.match(args.string) is not None: if args.encode: ret = encode(args.string, args.shift) elif args.decode: ret = decode(args.string, args.shift) if ret is not 0: print 'Sorry, this cipher only uses the [a-zA-Z0-9\\-{}]' else: print 'Sorry, this cipher only uses the [a-zA-Z0-9\\-{}]' return if __name__ == '__main__': main()
デコードする処理もあるので、そのまま使う。num, first, second, thirdでそれぞれシフトするのだが、構成する数が異なり、10, 10, 9, 7になっている。シフト数は最小公倍数の630回までパターンがあるので、全候補を確認する。
num = '' first = '' second = '' third = '' def setup(): global third global second global num global first num += '1' num += '2' num += '3' num += '4' num += '5' num += '6' num += '7' num += '8' num += '9' num += '0' first += 'q' first += 'w' first += 'e' first += 'r' first += 't' first += 'y' first += 'u' first += 'i' first += 'o' first += 'p' second += 'a' second += 's' second += 'd' second += 'f' second += 'g' second += 'h' second += 'j' second += 'k' second += 'l' third += 'z' third += 'x' third += 'c' third += 'v' third += 'b' third += 'n' third += 'm' def decode(string, shift): result = '' shift = -1 * shift for i in range(len(string)): char = string.lower()[i] if char in num: new_char = num[(num.index(char) + shift) % len(num)] result += new_char elif char in first: new_char = first[(first.index(char) + shift) % len(first)] if string[i].isupper(): result += new_char.upper() else: result += new_char elif char in second: new_char = second[(second.index(char) + shift) % len(second)] if string[i].isupper(): result += new_char.upper() else: result += new_char elif char in third: new_char = third[(third.index(char) + shift) % len(third)] if string[i].isupper(): result += new_char.upper() else: result += new_char else: result += char return result enc = 'PIY{zsxh-sqrvufwh-nfgl}' setup() for i in range(630): flag = decode(enc, i) if flag.startswith('WPI{'): print flag
実行結果は以下の通りで、意味の通りそうなものがフラグとなる。
WPI{mdzj-deycogrj-bgha} WPI{vsbh-seymofrh-xfgl} WPI{zaxg-aeyvodrg-ndfk} WPI{blnf-leyzosrf-csdj} WPI{xkcd-keyboard-mash}★ WPI{njms-jeyxolrs-vlag} WPI{chva-heynokra-zklf} WPI{mgzl-geycojrl-bjkd} WPI{vfbk-feymohrk-xhjs} WPI{zdxj-deyvogrj-ngha} WPI{bsnh-seyzofrh-cfgl} WPI{xacg-aeybodrg-mdfk} WPI{nlmf-leyxosrf-vsdj} WPI{ckvd-keynoard-zash} WPI{mjzs-jeycolrs-blag} WPI{vhba-heymokra-xklf} WPI{zgxl-geyvojrl-njkd} WPI{bfnk-feyzohrk-chjs} WPI{xdcj-deybogrj-mgha} WPI{nsmh-seyxofrh-vfgl} WPI{cavg-aeynodrg-zdfk} WPI{mlzf-leycosrf-bsdj} WPI{vkbd-keymoard-xash} WPI{zjxs-jeyvolrs-nlag} WPI{bhna-heyzokra-cklf} WPI{xgcl-geybojrl-mjkd} WPI{nfmk-feyxohrk-vhjs} WPI{cdvj-deynogrj-zgha} WPI{mszh-seycofrh-bfgl} WPI{vabg-aeymodrg-xdfk} WPI{zlxf-leyvosrf-nsdj} WPI{bknd-keyzoard-cash} WPI{xjcs-jeybolrs-mlag} WPI{nhma-heyxokra-vklf} WPI{cgvl-geynojrl-zjkd} WPI{mfzk-feycohrk-bhjs} WPI{vdbj-deymogrj-xgha} WPI{zsxh-seyvofrh-nfgl} WPI{bang-aeyzodrg-cdfk} WPI{xlcf-leybosrf-msdj} WPI{nkmd-keyxoard-vash} WPI{cjvs-jeynolrs-zlag} WPI{mhza-heycokra-bklf} WPI{vgbl-geymojrl-xjkd} WPI{zfxk-feyvohrk-nhjs} WPI{bdnj-deyzogrj-cgha} WPI{xsch-seybofrh-mfgl} WPI{namg-aeyxodrg-vdfk} WPI{clvf-leynosrf-zsdj} WPI{mkzd-keycoard-bash} WPI{vjbs-jeymolrs-xlag} WPI{zhxa-heyvokra-nklf} WPI{bgnl-geyzojrl-cjkd} WPI{xfck-feybohrk-mhjs} WPI{ndmj-deyxogrj-vgha} WPI{csvh-seynofrh-zfgl} WPI{mazg-aeycodrg-bdfk} WPI{vlbf-leymosrf-xsdj} WPI{zkxd-keyvoard-nash} WPI{bjns-jeyzolrs-clag} WPI{xhca-heybokra-mklf} WPI{ngml-geyxojrl-vjkd} WPI{cfvk-feynohrk-zhjs}
WPI{xkcd-keyboard-mash}