この大会は2019/10/11 4:00(JST)~2019/10/17 4:00(JST)に開催されました。
今回もチームで参戦。結果は 2050点で223チーム中40位でした。
自分で解けた問題をWriteupとして書いておきます。
Decode me (snake oil 150)
pycと、pngの暗号化ファイルが添付されている。まずEasy Python Decompilerでpycをデコンパイルする。
# Embedded file name: ./encoder.py import base64 import string import sys from random import shuffle def encode(f, inp): s = string.printable init = lambda : (list(s), []) bag, buf = init() for x in inp: if x not in s: continue while True: r = bag[0] bag.remove(r) diff = (ord(x) - ord(r) + len(s)) % len(s) if diff == 0 or len(bag) == 0: shuffle(buf) f.write(''.join(buf)) f.write('\x00') bag, buf = init() shuffle(bag) else: break buf.extend(r * (diff - 1)) f.write(r) shuffle(buf) f.write(''.join(buf)) if __name__ == '__main__': with open(sys.argv[1], 'rb') as r: w = open(sys.argv[1] + '.enc', 'wb') b64 = base64.b64encode(r.read()) encode(w, b64)
スクリプト処理の概要は以下の通り。
・base64エンコードした文字列をencodeする。 ・encode処理 ・bagはprintableの各文字の配列(初期化) ・bufはから配列(初期化) ・base64エンコードした各文字に対して、以下を実行 ・r = bag[0] ・bagからrを削除 ・diff = (ord(x) - ord(r) + len(s)) % len(s) ・diffが0 またはbagの長さが0の場合 ・bufをシャッフル ・bufの結合文字列をファイル書き込み ・\x00をファイル書き込み ・bag, bufを初期化 ・bagをシャッフル ・diffが0でなくbagの長さが0でない場合 ループから抜ける ・r * (diff - 1)をbufに追加 ・rをファイル書き込み ・bufをシャッフル ・bufの結合文字列を書き込み
復号はまず\x00区切りで考える。bagはシャッフルされるが、そのリストで使われた文字は後ろで複数の文字として現れる。そして使われた文字は削除されるので、どこまでがbugでどこからがbufかは区別できる。
あとは逆算すれば復号できる。
import string s = string.printable b64 = string.letters + string.digits + '+/=' def split_list_and_data(block): for i in range(len(s)): lst = block[:i] data = block[i:] err = False for c in s: if c in data and c not in lst: err = True break if err == False: return lst, data def decrypt(lst, data): dec = '' for c in lst: diff = data.count(c) + 1 code = diff + ord(c) if chr(code) not in b64 and code - len(s) > 0: code -= len(s) elif chr(code) not in b64 and code - len(s) <= 0: code += len(s) dec += chr(code) return dec with open('decodeme.png.enc', 'rb') as f: enc = f.read() blocks = enc.split('\x00') flag = '' for block in blocks: lst, data = split_list_and_data(block) flag += decrypt(lst, data) with open('decodeme.png', 'wb') as f: f.write(flag.decode('base64'))
復号したPNG画像にフラグが書いてある。
flag-6f38426c5963729d
Go cipher (go, not web 1000)
鍵は24バイトで、そのmd5が暗号化データの先頭32バイトに記載される。story4の暗号の先頭32バイトがflagの暗号の先頭32バイトと同じなので、同じ鍵になっている。xのシフトから1バイトごとの可能性のある鍵を絞る。またyとzのXORの組み合わせまでは考慮する必要がないので、yとzのXORを一つのパラメータとして、ブルートフォースして鍵を絞る。
def get_join_info(list1, list2, idx1, idx2): for l1 in list1: bin_l1 = bin(l1[0])[2:].zfill(8) for l2 in list2: bin_l2 = bin(l2[0])[2:].zfill(8) if bin_l1[:7] == bin_l2[1:]: print '%d: %s -> %d: %s' % (idx1, str(l1), idx2, str(l2)) with open('story4.txt', 'rb') as f: pt = f.read() with open('story4.txt.enc', 'rb') as f: ct = f.read() h = ct[:32] ct = ct[32:].decode('hex') key_list = [] for j in range(64): if j < 12: round = 4 else: round = 3 keys = [] for i in range(round): key = [] for x in range(256): for yz in range(256): code = ((ord(pt[i * 64 + j]) - x) % 256) ^ yz if code == ord(ct[i * 64 + j]): key.append((x, yz)) keys.append(key) if j < 12: key = set(keys[0]) & set(keys[1]) & set(keys[2]) & set(keys[3]) else: key = set(keys[0]) & set(keys[1]) & set(keys[2]) key_list.append(list(key)) for i in range(63): get_join_info(key_list[i], key_list[i+1], i, i+1)
実行結果は以下の通り。
0: (52, 176) -> 1: (26, 97) 0: (52, 176) -> 1: (154, 225) 1: (26, 97) -> 2: (141, 195) 1: (26, 97) -> 2: (13, 67) 2: (141, 195) -> 3: (198, 134) 2: (141, 195) -> 3: (70, 6) 3: (198, 134) -> 4: (99, 12) 3: (198, 134) -> 4: (227, 140) 4: (99, 12) -> 5: (49, 153) 4: (99, 12) -> 5: (177, 25) 4: (227, 140) -> 5: (113, 89) 4: (227, 140) -> 5: (241, 217) 5: (113, 89) -> 6: (56, 19) 5: (113, 89) -> 6: (184, 147) 5: (177, 25) -> 6: (216, 179) 5: (177, 25) -> 6: (88, 51) 6: (88, 51) -> 7: (44, 103) 6: (88, 51) -> 7: (172, 231) 7: (44, 103) -> 8: (150, 207) 7: (44, 103) -> 8: (22, 79) 8: (150, 207) -> 9: (203, 30) 8: (150, 207) -> 9: (75, 158) 9: (75, 158) -> 10: (165, 61) 9: (75, 158) -> 10: (37, 189) 10: (165, 61) -> 11: (82, 251) 10: (165, 61) -> 11: (210, 123) 10: (37, 189) -> 11: (146, 59) 10: (37, 189) -> 11: (18, 187) 11: (210, 123) -> 12: (105, 118) 11: (210, 123) -> 12: (233, 246) 12: (233, 246) -> 13: (244, 108) 12: (233, 246) -> 13: (116, 236) 13: (116, 236) -> 14: (58, 217) 13: (116, 236) -> 14: (186, 89) 13: (117, 237) -> 14: (58, 217) 13: (117, 237) -> 14: (186, 89) 14: (58, 217) -> 15: (157, 51) 14: (58, 217) -> 15: (29, 179) 14: (186, 89) -> 15: (221, 115) 14: (186, 89) -> 15: (93, 243) 15: (157, 51) -> 16: (206, 38) 15: (157, 51) -> 16: (78, 166) 15: (29, 179) -> 16: (14, 230) 15: (29, 179) -> 16: (142, 102) 16: (14, 230) -> 17: (7, 140) 16: (14, 230) -> 17: (135, 12) 16: (142, 102) -> 17: (199, 76) 16: (142, 102) -> 17: (71, 204) 17: (199, 76) -> 18: (99, 217) 17: (199, 76) -> 18: (227, 89) 17: (71, 204) -> 18: (35, 153) 17: (71, 204) -> 18: (163, 25) 17: (7, 140) -> 18: (3, 185) 17: (7, 140) -> 18: (131, 57) 17: (135, 12) -> 18: (67, 249) 17: (135, 12) -> 18: (195, 121) 18: (35, 153) -> 19: (145, 179) 18: (35, 153) -> 19: (17, 51) 19: (17, 51) -> 20: (136, 102) 19: (17, 51) -> 20: (8, 230) 20: (136, 102) -> 21: (196, 204) 20: (136, 102) -> 21: (68, 76) 21: (196, 204) -> 22: (226, 152) 21: (196, 204) -> 22: (98, 24) 22: (226, 152) -> 23: (241, 177) 22: (226, 152) -> 23: (113, 49) 23: (113, 49) -> 24: (56, 98) 23: (113, 49) -> 24: (184, 226) 23: (114, 48) -> 24: (185, 227) 23: (114, 48) -> 24: (57, 99) 24: (56, 98) -> 25: (28, 197) 24: (56, 98) -> 25: (156, 69) 24: (57, 99) -> 25: (28, 197) 24: (57, 99) -> 25: (156, 69) 25: (28, 197) -> 26: (14, 138) 25: (28, 197) -> 26: (142, 10) 26: (16, 136) -> 27: (136, 20) 26: (16, 136) -> 27: (8, 148) 26: (144, 8) -> 27: (200, 84) 26: (144, 8) -> 27: (72, 212) 26: (141, 11) -> 27: (198, 86) 26: (141, 11) -> 27: (70, 214) 26: (15, 137) -> 27: (135, 21) 26: (15, 137) -> 27: (7, 149) 26: (14, 138) -> 27: (135, 21) 26: (14, 138) -> 27: (7, 149) 26: (142, 10) -> 27: (71, 213) 26: (142, 10) -> 27: (199, 85) 26: (143, 9) -> 27: (71, 213) 26: (143, 9) -> 27: (199, 85) 26: (13, 139) -> 27: (6, 150) 26: (13, 139) -> 27: (134, 22) 27: (71, 213) -> 28: (35, 203) 27: (71, 213) -> 28: (163, 75) 27: (22, 166) -> 28: (139, 83) 27: (22, 166) -> 28: (11, 211) 27: (87, 229) -> 28: (43, 179) 27: (87, 229) -> 28: (171, 51) 27: (230, 118) -> 28: (243, 251) 27: (230, 118) -> 28: (115, 123) 27: (23, 165) -> 28: (139, 83) 27: (23, 165) -> 28: (11, 211) 27: (118, 6) -> 28: (59, 163) 27: (118, 6) -> 28: (187, 35) 27: (199, 85) -> 28: (227, 11) 27: (199, 85) -> 28: (99, 139) 27: (6, 150) -> 28: (3, 235) 27: (6, 150) -> 28: (131, 107) 27: (198, 86) -> 28: (227, 11) 27: (198, 86) -> 28: (99, 139) 27: (151, 37) -> 28: (203, 19) 27: (151, 37) -> 28: (75, 147) 27: (183, 69) -> 28: (219, 3) 27: (183, 69) -> 28: (91, 131) 27: (70, 214) -> 28: (35, 203) 27: (70, 214) -> 28: (163, 75) 27: (102, 246) -> 28: (179, 59) 27: (102, 246) -> 28: (51, 187) 27: (247, 133) -> 28: (251, 227) 27: (247, 133) -> 28: (123, 99) 27: (39, 181) -> 28: (147, 91) 27: (39, 181) -> 28: (19, 219) 27: (215, 101) -> 28: (107, 115) 27: (215, 101) -> 28: (235, 243) 27: (38, 182) -> 28: (147, 91) 27: (38, 182) -> 28: (19, 219) 27: (135, 21) -> 28: (195, 43) 27: (135, 21) -> 28: (67, 171) 27: (150, 38) -> 28: (203, 19) 27: (150, 38) -> 28: (75, 147) 27: (167, 53) -> 28: (83, 155) 27: (167, 53) -> 28: (211, 27) 27: (214, 102) -> 28: (107, 115) 27: (214, 102) -> 28: (235, 243) 27: (231, 117) -> 28: (243, 251) 27: (231, 117) -> 28: (115, 123) 27: (182, 70) -> 28: (219, 3) 27: (182, 70) -> 28: (91, 131) 27: (55, 197) -> 28: (27, 195) 27: (55, 197) -> 28: (155, 67) 27: (7, 149) -> 28: (3, 235) 27: (7, 149) -> 28: (131, 107) 27: (246, 134) -> 28: (251, 227) 27: (246, 134) -> 28: (123, 99) 27: (134, 22) -> 28: (195, 43) 27: (134, 22) -> 28: (67, 171) 27: (119, 5) -> 28: (59, 163) 27: (119, 5) -> 28: (187, 35) 27: (86, 230) -> 28: (43, 179) 27: (86, 230) -> 28: (171, 51) 27: (166, 54) -> 28: (83, 155) 27: (166, 54) -> 28: (211, 27) 27: (103, 245) -> 28: (179, 59) 27: (103, 245) -> 28: (51, 187) 27: (54, 198) -> 28: (27, 195) 27: (54, 198) -> 28: (155, 67) 28: (195, 43) -> 29: (225, 215) 28: (195, 43) -> 29: (97, 87) 28: (67, 171) -> 29: (161, 151) 28: (67, 171) -> 29: (33, 23) 29: (161, 151) -> 30: (208, 142) 29: (161, 151) -> 30: (80, 14) 29: (97, 87) -> 30: (176, 174) 29: (97, 87) -> 30: (48, 46) 30: (176, 174) -> 31: (216, 92) 30: (176, 174) -> 31: (88, 220) 31: (216, 92) -> 32: (108, 56) 31: (216, 92) -> 32: (236, 184) 32: (108, 56) -> 33: (182, 49) 32: (108, 56) -> 33: (54, 177) 32: (236, 184) -> 33: (246, 241) 32: (236, 184) -> 33: (118, 113) 33: (118, 113) -> 34: (59, 227) 33: (118, 113) -> 34: (187, 99) 33: (182, 49) -> 34: (219, 67) 33: (182, 49) -> 34: (91, 195) 34: (59, 227) -> 35: (157, 199) 34: (59, 227) -> 35: (29, 71) 35: (157, 199) -> 36: (78, 142) 35: (157, 199) -> 36: (206, 14) 35: (29, 71) -> 36: (142, 78) 35: (29, 71) -> 36: (14, 206) 36: (78, 142) -> 37: (167, 157) 36: (78, 142) -> 37: (39, 29) 36: (206, 14) -> 37: (231, 221) 36: (206, 14) -> 37: (103, 93) 37: (231, 221) -> 38: (115, 27) 37: (231, 221) -> 38: (243, 155) 37: (103, 93) -> 38: (51, 219) 37: (103, 93) -> 38: (179, 91) 37: (167, 157) -> 38: (211, 123) 37: (167, 157) -> 38: (83, 251) 37: (39, 29) -> 38: (19, 187) 37: (39, 29) -> 38: (147, 59) 38: (19, 187) -> 39: (137, 183) 38: (19, 187) -> 39: (9, 55) 38: (115, 27) -> 39: (57, 103) 38: (115, 27) -> 39: (185, 231) 38: (147, 59) -> 39: (201, 247) 38: (147, 59) -> 39: (73, 119) 38: (51, 219) -> 39: (153, 135) 38: (51, 219) -> 39: (25, 7) 38: (211, 123) -> 39: (233, 215) 38: (211, 123) -> 39: (105, 87) 38: (179, 91) -> 39: (89, 71) 38: (179, 91) -> 39: (217, 199) 38: (243, 155) -> 39: (121, 167) 38: (243, 155) -> 39: (249, 39) 38: (83, 251) -> 39: (169, 151) 38: (83, 251) -> 39: (41, 23) 39: (201, 247) -> 40: (100, 47) 39: (201, 247) -> 40: (228, 175) 39: (233, 215) -> 40: (244, 95) 39: (233, 215) -> 40: (116, 223) 39: (105, 87) -> 40: (180, 159) 39: (105, 87) -> 40: (52, 31) 39: (169, 151) -> 40: (84, 63) 39: (169, 151) -> 40: (212, 191) 39: (73, 119) -> 40: (36, 111) 39: (73, 119) -> 40: (164, 239) 39: (137, 183) -> 40: (196, 143) 39: (137, 183) -> 40: (68, 15) 39: (9, 55) -> 40: (132, 207) 39: (9, 55) -> 40: (4, 79) 39: (41, 23) -> 40: (148, 255) 39: (41, 23) -> 40: (20, 127) 40: (196, 143) -> 41: (98, 207) 40: (196, 143) -> 41: (226, 79) 40: (164, 239) -> 41: (210, 95) 40: (164, 239) -> 41: (82, 223) 41: (210, 95) -> 42: (233, 254) 41: (210, 95) -> 42: (105, 126) 41: (82, 223) -> 42: (41, 62) 41: (82, 223) -> 42: (169, 190) 42: (105, 126) -> 43: (52, 221) 42: (105, 126) -> 43: (180, 93) 42: (169, 190) -> 43: (84, 253) 42: (169, 190) -> 43: (212, 125) 43: (84, 253) -> 44: (42, 58) 43: (84, 253) -> 44: (170, 186) 43: (212, 125) -> 44: (234, 250) 43: (212, 125) -> 44: (106, 122) 44: (234, 250) -> 45: (245, 245) 44: (234, 250) -> 45: (117, 117) 45: (245, 245) -> 46: (122, 235) 45: (245, 245) -> 46: (250, 107) 45: (117, 117) -> 46: (58, 43) 45: (117, 117) -> 46: (186, 171) 46: (122, 235) -> 47: (189, 214) 46: (122, 235) -> 47: (61, 86) 46: (58, 43) -> 47: (29, 54) 46: (58, 43) -> 47: (157, 182) 46: (250, 107) -> 47: (253, 22) 46: (250, 107) -> 47: (125, 150) 46: (186, 171) -> 47: (93, 118) 46: (186, 171) -> 47: (221, 246) 47: (189, 214) -> 48: (94, 45) 47: (189, 214) -> 48: (222, 173) 47: (125, 150) -> 48: (62, 13) 47: (125, 150) -> 48: (190, 141) 48: (222, 173) -> 49: (239, 91) 48: (222, 173) -> 49: (111, 219) 49: (239, 91) -> 50: (247, 54) 49: (239, 91) -> 50: (119, 182) 49: (111, 219) -> 50: (55, 118) 49: (111, 219) -> 50: (183, 246) 50: (247, 54) -> 51: (123, 172) 50: (247, 54) -> 51: (251, 44) 50: (119, 182) -> 51: (59, 108) 50: (119, 182) -> 51: (187, 236) 50: (55, 118) -> 51: (155, 140) 50: (55, 118) -> 51: (27, 12) 50: (183, 246) -> 51: (91, 76) 50: (183, 246) -> 51: (219, 204) 51: (59, 108) -> 52: (157, 89) 51: (59, 108) -> 52: (29, 217) 51: (251, 44) -> 52: (253, 249) 51: (251, 44) -> 52: (125, 121) 52: (30, 216) -> 53: (15, 179) 52: (30, 216) -> 53: (143, 51) 52: (157, 89) -> 53: (78, 242) 52: (157, 89) -> 53: (206, 114) 52: (29, 217) -> 53: (14, 178) 52: (29, 217) -> 53: (142, 50) 52: (159, 91) -> 53: (79, 243) 52: (159, 91) -> 53: (207, 115) 52: (158, 88) -> 53: (79, 243) 52: (158, 88) -> 53: (207, 115) 52: (31, 219) -> 53: (15, 179) 52: (31, 219) -> 53: (143, 51) 53: (14, 178) -> 54: (135, 229) 53: (14, 178) -> 54: (7, 101) 53: (142, 50) -> 54: (71, 37) 53: (142, 50) -> 54: (199, 165) 53: (15, 179) -> 54: (135, 229) 53: (15, 179) -> 54: (7, 101) 53: (143, 51) -> 54: (71, 37) 53: (143, 51) -> 54: (199, 165) 54: (71, 37) -> 55: (163, 107) 54: (71, 37) -> 55: (35, 235) 54: (7, 101) -> 55: (131, 75) 54: (7, 101) -> 55: (3, 203) 55: (3, 203) -> 56: (129, 151) 55: (3, 203) -> 56: (1, 23) 56: (129, 151) -> 57: (64, 47) 56: (129, 151) -> 57: (192, 175) 56: (125, 147) -> 57: (62, 45) 56: (125, 147) -> 57: (190, 173) 57: (64, 47) -> 58: (160, 222) 57: (64, 47) -> 58: (32, 94) 57: (65, 46) -> 58: (160, 222) 57: (65, 46) -> 58: (32, 94) 58: (32, 94) -> 59: (16, 61) 58: (32, 94) -> 59: (144, 189) 59: (144, 189) -> 60: (72, 123) 59: (144, 189) -> 60: (200, 251) 59: (145, 188) -> 60: (72, 123) 59: (145, 188) -> 60: (200, 251) 60: (72, 123) -> 61: (36, 118) 60: (72, 123) -> 61: (164, 246) 61: (169, 243) -> 62: (212, 238) 61: (169, 243) -> 62: (84, 110) 61: (164, 246) -> 62: (210, 236) 61: (164, 246) -> 62: (82, 108) 61: (165, 247) -> 62: (210, 236) 61: (165, 247) -> 62: (82, 108) 61: (168, 242) -> 62: (212, 238) 61: (168, 242) -> 62: (84, 110) 62: (210, 236) -> 63: (233, 88) 62: (210, 236) -> 63: (105, 216) 62: (178, 204) -> 63: (217, 72) 62: (178, 204) -> 63: (89, 200)
このことから0~63まで一貫してつながるものを探す。
0: (52, 176) -> 1: (26, 97) 1: (26, 97) -> 2: (141, 195) 2: (141, 195) -> 3: (198, 134) 3: (198, 134) -> 4: (99, 12) 4: (99, 12) -> 5: (177, 25) 5: (177, 25) -> 6: (88, 51) 6: (88, 51) -> 7: (44, 103) 7: (44, 103) -> 8: (150, 207) 8: (150, 207) -> 9: (75, 158) 9: (75, 158) -> 10: (165, 61) 10: (165, 61) -> 11: (210, 123) 11: (210, 123) -> 12: (233, 246) 12: (233, 246) -> 13: (116, 236) 13: (116, 236) -> 14: (58, 217) 14: (58, 217) -> 15: (29, 179) 15: (29, 179) -> 16: (142, 102) 16: (142, 102) -> 17: (71, 204) 17: (71, 204) -> 18: (35, 153) 18: (35, 153) -> 19: (17, 51) 19: (17, 51) -> 20: (136, 102) 20: (136, 102) -> 21: (196, 204) 21: (196, 204) -> 22: (226, 152) 22: (226, 152) -> 23: (113, 49) 23: (113, 49) -> 24: (56, 98) 24: (56, 98) -> 25: (28, 197) 25: (28, 197) -> 26: (14, 138) 26: (14, 138) -> 27: (135, 21) 27: (135, 21) -> 28: (195, 43) 28: (195, 43) -> 29: (97, 87) 29: (97, 87) -> 30: (176, 174) 30: (176, 174) -> 31: (216, 92) 31: (216, 92) -> 32: (236, 184) 32: (236, 184) -> 33: (118, 113) 33: (118, 113) -> 34: (59, 227) 34: (59, 227) -> 35: (157, 199) 35: (157, 199) -> 36: (78, 142) 36: (78, 142) -> 37: (39, 29) 37: (39, 29) -> 38: (147, 59) 38: (147, 59) -> 39: (73, 119) 39: (73, 119) -> 40: (164, 239) 40: (164, 239) -> 41: (82, 223) 41: (82, 223) -> 42: (169, 190) 42: (169, 190) -> 43: (212, 125) 43: (212, 125) -> 44: (234, 250) 44: (234, 250) -> 45: (245, 245) 45: (245, 245) -> 46: (122, 235) 46: (122, 235) -> 47: (189, 214) 47: (189, 214) -> 48: (222, 173) 48: (222, 173) -> 49: (239, 91) 49: (239, 91) -> 50: (119, 182) 50: (119, 182) -> 51: (59, 108) 51: (59, 108) -> 52: (29, 217) 52: (29, 217) -> 53: (14, 178) 53: (14, 178) -> 54: (7, 101) 54: (7, 101) -> 55: (3, 203) 55: (3, 203) -> 56: (129, 151) 56: (129, 151) -> 57: (64, 47) 57: (64, 47) -> 58: (32, 94) 58: (32, 94) -> 59: (144, 189) 59: (144, 189) -> 60: (72, 123) 60: (72, 123) -> 61: (164, 246) 61: (164, 246) -> 62: (210, 236)
結果は上記の通りだが、62バイト目から63バイト目の関係を1つに絞れなく、以下のどちらかである。
62: (210, 236) -> 63: (233, 88) 62: (210, 236) -> 63: (105, 216)
右シフトなので、56バイト目までで全貌が分かり、割り出すことが可能である。そのことを考慮して、flagの方を復号する。
with open('flag.txt.enc', 'rb') as f: ct = f.read() h = ct[:32] ct = ct[32:].decode('hex') xs = [52, 26, 141, 198, 99, 177, 88, 44, 150, 75, 165, 210, 233, 116, 58, 29, 142, 71, 35, 17, 136, 196, 226, 113, 56, 28, 14, 135, 195, 97, 176, 216, 236, 118, 59, 157, 78, 39, 147, 73, 164, 82, 169, 212, 234, 245, 122, 189, 222, 239, 119, 59, 29, 14, 7, 3, 129, 64, 32, 144, 72, 164, 210] yzs = [176, 97, 195, 134, 12, 25, 51, 103, 207, 158, 61, 123, 246, 236, 217, 179, 102, 204, 153, 51, 102, 204, 152, 49, 98, 197, 138, 21, 43, 87, 174, 92, 184, 113, 227, 199, 142, 29, 59, 119, 239, 223, 190, 125, 250, 245, 235, 214, 173, 91, 182, 108, 217, 178, 101, 203, 151, 47, 94, 189, 123, 246] last_xyz = {233: 88, 105: 216} bin_all_x = '' init = True for x in xs: bin_x = bin(x)[2:].zfill(8) if init: init = False bin_all_x += bin_x else: bin_all_x = bin_x[0] + bin_all_x if len(bin_all_x) == 64: break bin_all_x2 = bin_all_x * 2 for i in range(64): val = int(bin_all_x2[120-i:128-i], 2) if i != 63: assert val == xs[i] else: xs.append(val) yzs.append(last_xyz[val]) flag = '' for i in range(len(ct)): code = ((ord(ct[i]) ^ yzs[i]) + xs[i]) % 256 flag += chr(code) print flag
復号結果は以下の通り。
Yes, you did it! flag-742CF8ED6A2BF55807B14719
flag-742CF8ED6A2BF55807B14719