ISITDTU CTF 2019 Quals Writeup

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

Welcome (Welcome)

Discordに入り、ピン止めされたメッセージを見ると、フラグが書いてあった。

ISITDTU{Welcome_everyone_to_ISITDTUCTF}

Old story (Crypto)

各要素の値は2の累乗になっているようだったので、2の何乗かを出してみる。

[19, 22, 14, 10, 22, 5, 18, 21, 22, 24, 46, 51, 13, 23, 13, 52, 24, 55, 14, 41, 26, 20, 21, 54, 25, 36, 2, 34, 29, 39, 18, 32, 14, 7, 58, 37, 24, 55, 10, 52, 14, 36, 18, 62]

64以下の値で構成されている。

$ echo 'ISITDTU' | base64
SVNJVERUVQo=

Base64のインデックスになっているように見えるので、それを前提にデコードする。

import string

enc = [524288, 4194304, 16384, 1024, 4194304, 32, 262144, 2097152, 4194304, 16777216, 70368744177664, 2251799813685248, 8192, 8388608, 8192, 4503599627370496, 16777216, 36028797018963968, 16384, 2199023255552, 67108864, 1048576, 2097152, 18014398509481984, 33554432, 68719476736, 4, 17179869184, 536870912, 549755813888, 262144, 4294967296, 16384, 128, 288230376151711744, 137438953472, 16777216, 36028797018963968, 1024, 4503599627370496, 16384, 68719476736, 262144, 4611686018427387904]

log = {}
for i in range(64):
    log[2**i] = i

codes = []
for e in enc:
    codes.append(log[e])

b64tbl = string.uppercase + string.lowercase + string.digits + '+/'

b64enc = ''
for code in codes:
    b64enc += b64tbl[code - 1]

flag = b64enc.decode('base64')
print flag
ISITDTU{r1c3_che55b0ard_4nd_bs64}

Easy RSA 1 (Crypto)

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

# wiener_attack.sage
def wiener(e, n):
    m = 12345
    c = pow(m, e, n)
    q0 = 1

    list1 = continued_fraction(Integer(e)/Integer(n))
    conv = list1.convergents()
    for i in conv:
        k = i.numerator()
        q1 = i.denominator()

        for r in range(30):
            for s in range(30):
                d = r*q1 + s*q0
                m1 = pow(c, d, n)
                if m1 == m:
                    return d
        q0 = q1
    return None

n = 137709853388874260067664060306224801065880567280896538344708662296491187670268243771581008615887329285442080267493172576517227603581814922784005894668293664250883858847270414696279127204843462302026428548409668060539273696154323753582118715764251826181439387752900169898505518594134423187783089073450520527969
e = 85605944479801539190292577400294315989703364683792339737453887619652946907819548388390076584246192710348319524405250340541547224543819349494488596679810310694697763188201375896240755682682520811114377302206659716598003967368992125832908158096663258971132148617761060030524535044970322206572134828548118438019
c = 22066874366908131522623165919721031154048372827959879486746669804284618882326621205522887800063326155288431192110879403482210420111408801477749097399368616494107231276644736023482237804800287810317122448198973027350599454646050497733117161743355379588761228932055556016302337519814538743706899009493572298224

d = wiener(e, n)
m = pow(c, d, n)

flag = ('%x' % m).decode('hex')
print flag
ISITDTU{Thank5_f0r_4tt3nd1ng_0ur_C0nt3st}

Chaos (Crypto)

$ nc 104.154.120.223 8085
Your cipher key: 88/cc/,,/oo 00/xx/UU/II 33/cc/OO/DD 88/mm/~~/rr 00/uu/KK/$$/,, 88/pp/DD/LL 22/ii/UU/SS 77/ee/CC/__/$$ 11/yy/KK/DD 88/77/tt 33/xx/KK/OO 44/mm/||/ii 55/ff/**/pp 55/ii/GG/??/%% 11/88/zz 77/88/oo 88/ww/^^/dd 66/kk/((/gg 33/qq/DD/<</,, 99/rr/,,/gg 33/ll/EE/VV 44/xx/__/hh 88/nn/KK/&&/++ 44/cc/CC/II 88/mm/LL/++/__ 77/oo/``/oo 11/66/ww 66/hh/((/ww 77/pp/__/vv 11/ee/RR/((/## 55/mm/II/MM 44/uu/ZZ/ZZ 55/cc/++/pp 99/pp/PP/../%% 22/vv/CC/$$/<< 22/ss/AA/,,/?? 66/11/ff 99/qq/<</jj 22/88/ww 99/mm/PP/MM 88/dd/))/hh 22/vv/PP/NN 99/66/uu 44/tt/HH/!!/== 22/cc/CC/``/++ 77/bb/ZZ/MM 33/oo/SS/BB 22/vv/OO/HH 88/ss/HH/RR 11/aa/%%/rr 22/qq/??/mm 99/nn/%%/ll 22/kk/CC/OO 77/vv/@@/ee 33/ff/YY/DD 66/ee/XX/BB 99/bb/RR/@@/(( 77/rr/$$/hh 99/dd/DD/##/## 77/ii/JJ/WW 44/hh/EE/XX 44/ff/__/tt 33/00/gg 55/pp/HH/LL
WELCOME TO CHAOS TOOL: 
Description: This is a tool which helps you hide the content of the message
Notes:
- Message cannot contain whitespace characters
- Message can use all characters including punctuation marks and number
- Decrypt the above key to get the flag, len(key) = 64
- All punctuation marks use in plain key: ~`!@#$%^&*()_-+=<,>.?|
- Key is not a meaningful sentence
- Find the rule in this tool
**FEATURES**
<1> Encrypt message 
<2> Get the flag 
Your choice: 1
Enter your message: 123

Here is your cipher: 11/00/jj 22/77/aa 33/00/aa
**FEATURES**
<1> Encrypt message 
<2> Get the flag 
Your choice: 2
Please enter the key to get flag: 123
WRONG KEY

何回か試してみると、この暗号の特徴は以下のようになっていることがわかった。

"/"区切りで3つの場合は数字で、平文は"/"区切りの1番目の文字
"/"区切りで4つの場合で、4つ目が英小文字の場合は英小文字で、平文は"/"区切りの2番目の文字
"/"区切りで4つの場合で、4つ目が英大文字の場合は英大文字で、平文は"/"区切りの3番目の文字
"/"区切りで5つの場合は記号で、平文は"/"区切りの5番目の文字

これを元に復号して、キーを指定する。

import socket
import string

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(('104.154.120.223', 8085))

data = recvuntil(s, 'Your choice: ')
print data + '1'
s.sendall('1\n')

ct = data.split('\n')[0].split(': ')[1]
ct = ct.split(' ')

chars = string.letters + string.digits + '~`!@#$%^&*()_-+=<,>.?|'
data = recvuntil(s, ': ')
print data + chars
s.sendall(chars + '\n')

pt = ''
for c in ct:
    elems = c.split('/')
    if len(elems) == 3:
        pt += elems[0][0]
    elif len(elems) == 4:
        if elems[3][0] in string.lowercase:
            pt += elems[1][0]
        else:
            pt += elems[2][0]
    else:
        pt += elems[4][0]

data = recvuntil(s, 'Your choice: ')
print data + '2'
s.sendall('2\n')

data = recvuntil(s, ': ')
print data + pt
s.sendall(pt + '\n')

data = s.recv(8192)
print data

実行結果は以下の通り。

Your cipher key: 44/66/yy 44/qq/HH/../&& 00/rr/~~/zz 55/ww/--/gg 77/ll/LL/JJ 55/rr/QQ/||/.. 77/dd/GG/II 55/uu/LL/YY 66/nn/II/==/## 55/44/kk 99/99/ww 22/ee/``/yy 00/tt/))/rr 11/yy/ZZ/LL 77/dd/../uu 33/rr/GG/II 33/cc/**/tt 88/11/xx 88/77/zz 77/qq/QQ/((/?? 55/xx/SS/DD 66/aa/@@/dd 00/hh/||/vv 22/33/bb 33/oo/ZZ/**/!! 66/44/bb 44/bb/__/zz 99/mm/__/mm 55/88/ww 00/rr/EE/BB 99/ii/PP/||/)) 22/rr/<</ss 00/ll/BB/XX 77/ll/++/qq 99/tt/KK/GG 55/ww/&&/yy 99/bb/DD/LL 44/jj/>>/uu 22/dd/UU/TT 44/vv/NN/??/~~ 55/aa/JJ/--/|| 77/pp/II/FF 99/cc/HH/EE 22/jj/RR/MM 55/22/rr 33/yy/MM/AA 33/bb/KK/AA 33/qq/>>/ll 88/ff/++/ee 22/oo/TT/||/** 55/88/ii 22/aa/CC/KK 11/vv/UU/JJ 44/bb/SS/||/== 66/ll/ZZ/__/^^ 33/bb/EE/NN 11/cc/SS/,,/%% 55/ii/HH/++/.. 22/ff/))/pp 99/yy/>>/yy 99/uu/KK/QQ 22/qq/~~/ee 22/uu/++/zz 00/ww/PP/<</++
WELCOME TO CHAOS TOOL:
Description: This is a tool which helps you hide the content of the message
Notes:
- Message cannot contain whitespace characters
- Message can use all characters including punctuation marks and number
- Decrypt the above key to get the flag, len(key) = 64
- All punctuation marks use in plain key: ~`!@#$%^&*()_-+=<,>.?|
- Key is not a meaningful sentence
- Find the rule in this tool
**FEATURES**
<1> Encrypt message
<2> Get the flag
Your choice: 1
Enter your message: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~`!@#$%^&*()_-+=<,>.?|

Here is your cipher: 77/aa/``/vv 55/bb/~~/ii 44/cc/@@/oo 00/dd/$$/qq 99/ee/,,/ll 44/ff/--/vv 44/gg/++/zz 66/hh/||/uu 00/ii/##/ii 00/jj/__/kk 77/kk/))/ee 44/ll/!!/dd 11/mm/,,/ff 44/nn/##/tt 88/oo/!!/vv 44/pp/>>/gg 77/qq/%%/qq 55/rr/../cc 66/ss/@@/ee 66/tt/``/ii 88/uu/%%/ll 11/vv/##/yy 33/ww/,,/ff 77/xx/??/uu 11/yy/##/ee 33/zz/&&/vv 66/cc/AA/WW 77/gg/BB/LL 55/ii/CC/KK 33/cc/DD/CC 22/gg/EE/HH 66/hh/FF/XX 77/dd/GG/OO 88/pp/HH/MM 22/xx/II/PP 55/zz/JJ/TT 11/kk/KK/OO 00/hh/LL/EE 22/tt/MM/II 88/yy/NN/LL 11/qq/OO/GG 11/tt/PP/TT 55/nn/QQ/LL 55/uu/RR/GG 66/uu/SS/AA 55/ww/TT/TT 77/oo/UU/YY 33/gg/VV/VV 44/mm/WW/WW 55/yy/XX/KK 55/ss/YY/PP 55/gg/ZZ/YY 00/99/jj 11/77/xx 22/22/uu 33/22/xx 44/88/ee 55/44/aa 66/77/yy 77/22/uu 88/11/ll 99/77/qq 00/ll/KK/++/~~ 44/cc/UU/**/`` 11/cc/FF/**/!! 77/bb/WW/>>/@@ 22/aa/FF/--/## 77/nn/GG/##/$$ 99/qq/JJ/__/%% 99/hh/RR/((/^^ 11/ii/QQ/++/&& 44/aa/EE/~~/** 44/hh/EE/,,/(( 88/ww/OO/%%/)) 88/ww/MM/~~/__ 44/gg/ZZ/$$/-- 99/gg/CC/@@/++ 77/qq/PP/==/== 99/xx/JJ/--/<< 44/uu/XX/~~/,, 66/uu/RR/--/>> 11/zz/OO/++/.. 33/ff/TT/&&/?? 00/qq/KK/``/||
**FEATURES**
<1> Encrypt message
<2> Get the flag
Your choice: 2
Please enter the key to get flag: 4&rwL.GL#59etZdGc88?Sah2!6bm5E)rBlKwDjU~|IHR5MKqf*5CU=^E%.fyKqu+
Good job! Here is your flag: ISITDTU{Hav3_y0u_had_a_h3adach3??_Forgive_me!^^}
ISITDTU{Hav3_y0u_had_a_h3adach3??_Forgive_me!^^}

decrypt to me (Crypto)

prgの生成はフラグのbit長にのみ依存する。暗号化のbit長がわかるので、それから+8bit以内で正しいprgが得られるので、逆算してフラグを導く。

from Crypto.Util.number import *

def generate_prg_bit(n):
    state = n
    while True:
        last_bit = state & 1
        yield last_bit
        middle_bit = state >> len(bin(n)[2:])//2 & 1
        state = (state >> 1) | ((last_bit ^ middle_bit) << (len(bin(n)[2:])-1))

enc = 'OKQI+f9R+tHEJJGcfko7Ahy2AuL9c8hgtYT2k9Ig0QyXUvsj1B9VIGUZVPAP2EVD8VmJBZbF9e17'
n = bytes_to_long(enc.decode('base64'))
enc_bin_text = bin(n)[2:]

prg_n = len(enc_bin_text)
tmp_enc_bin_text = enc_bin_text
while True:
    prg = generate_prg_bit(prg_n)
    flag_bits = []
    for i in range(prg_n):
        flag_bits.append(int(tmp_enc_bin_text[i]) ^ next(prg))
    plaintext = '0b' + ''.join(map(str, flag_bits))
    n = int(plaintext, 2)
    flag = long_to_bytes(n)
    if 'ISITDTU{' in flag:
        print flag
        break

    tmp_enc_bin_text = '0' + tmp_enc_bin_text
    prg_n += 1
ISITDTU{Encrypt_X0r_N0t_Us3_Pseud0_Rand0m_Generat0r!!!!!}

Do you like math? (Programming)

$ nc 104.154.120.223 8083

  #    #####        #         #            
 ##   #     #   #   #    #   ##            
# #         #   #   #    #  # #      ##### 
  #    #####  ##### #    #    #            
  #         #   #   #######   #      ##### 
  #   #     #   #        #    #            
#####  #####             #  #####          
                                           
>>>

ASCIIアートで算数の問題が出題される。
全文字のパターンを見てみる。

$ nc 104.154.120.223 8083

  #   #######        #####   #####           
 ##   #             #     # #     #          
# #   #                   #       #    ##### 
  #   ######  #####  #####   #####           
  #         #             # #          ##### 
  #   #     #       #     # #                
#####  #####         #####  #######          
                                             
>>>

$ nc 104.154.120.223 8083

#######   ###            #####    ###            
#        #   #   #   #  #     #  #   #           
#       #     #   # #         # #     #    ##### 
######  #     # #######  #####  #     #          
      # #     #   # #         # #     #    ##### 
#     #  #   #   #   #  #     #  #   #           
 #####    ###            #####    ###            
                                                 
>>>

$ nc 104.154.120.223 8083

 #####          #        #####           
#     #  #   #  #    #  #     #          
#     #   # #   #    #  #          ##### 
 #####  ####### #    #  ######           
#     #   # #   ####### #     #    ##### 
#     #  #   #       #  #     #          
 #####               #   #####           
                                         
>>>

$ nc 104.154.120.223 8083

#       #######         #        #####           
#    #  #    #   #   #  #    #  #     #          
#    #      #     # #   #    #        #    ##### 
#    #     #    ####### #    #   #####           
#######   #       # #   ####### #          ##### 
     #    #      #   #       #  #                
     #    #                  #  #######          
                                                 
>>>

$ nc 104.154.120.223 8083

 #####   #####          #     #            
#     # #     #   #    ##    ##            
      # #     #   #   # #   # #      ##### 
 #####   ###### #####   #     #            
      #       #   #     #     #      ##### 
#     # #     #   #     #     #            
 #####   #####        ##### #####          
                                           
>>>

縦にスペースが並ぶ列を区切りとして、各数字と記号のパターンを比較し、数式をパースする。あとは計算して答えていく。

import socket

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

def get_char(s):
    if s == '  ###   #   # #     ##     ##     # #   #   ###  ':
        return '0'
    elif s == '  #   # #    ########      #      #':
        return '1'
    elif s == ' #  ####  #  ##  #  ##  #  ##  #  ##  #  # ##   #':
        return '2'
    elif s == ' #   # #  #  ##  #  ##  #  ##  #  ##  #  # ## ## ':
        return '3'
    elif s == '#####      #      #      #      #   ######    #  ':
        return '4'
    elif s == '#### # #  #  ##  #  ##  #  ##  #  ##  #  ##   ## ':
        return '5'
    elif s == ' ##### #  #  ##  #  ##  #  ##  #  ##  #  # #  ## ':
        return '6'
    elif s == '##     #      #   ####  #   # #    ##     #      ':
        return '7'
    elif s == ' ## ## #  #  ##  #  ##  #  ##  #  ##  #  # ## ## ':
        return '8'
    elif s == ' ##  # #  #  ##  #  ##  #  ##  #  ##  #  # ##### ':
        return '9'
    elif s == '   #      #    #####    #      #   ':
        return '+'
    elif s == '   #      #      #      #      #   ':
        return '-'
    elif s == '   #    # # #   ###     #     ###   # # #    #   ':
        return '*'
    elif s == '  # #    # #    # #    # #    # #  ':
        return '='
    else:
        return ''

def get_formula(lines):
    formula = ''
    char_str = ''
    for x in range(len(lines[0])):
        sp_flg = True
        tmp_char = ''
        for y in range(len(lines)):
            tmp_char += lines[y][x]
            if lines[y][x] != ' ':
                sp_flg = False
        if sp_flg:
           formula += get_char(char_str)
           char_str = ''
        else:
           char_str += tmp_char
    return formula

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('104.154.120.223', 8083))

for i in range(100):
    print '\nRound %d' % (i+1)
    data = ''
    for j in range(9):
        data += recvuntil(s, '\n')
    print data
    d = data.split('\n')[1:-2]
    formula = get_formula(d)
    ans = str(eval(formula.rstrip('=')))

    data = recvuntil(s, '>>> ')
    print data + ans
    s.sendall(ans + '\n')

data = s.recv(8192)
print data

100回正解したら、フラグが表示された。

ISITDTU{sub5cr1b3_b4_t4n_vl0g_4nd_p3wd13p13}

Pytecode (Reverse)

Pythonアセンブラが添付されている。チェック処理を上から見ていく。

  9           6 LOAD_GLOBAL              0 (ord)
              9 LOAD_FAST                0 (flag)
             12 LOAD_CONST               1 (0)
             15 BINARY_SUBSCR       
             16 CALL_FUNCTION            1
             19 LOAD_CONST               2 (52)
             22 BINARY_ADD          
             23 LOAD_GLOBAL              0 (ord)
             26 LOAD_FAST                0 (flag)
             29 LOAD_CONST               3 (-1)
             32 BINARY_SUBSCR       
             33 CALL_FUNCTION            1
             36 COMPARE_OP               3 (!=)
             39 POP_JUMP_IF_TRUE        78
             42 LOAD_GLOBAL              0 (ord)
             45 LOAD_FAST                0 (flag)
             48 LOAD_CONST               3 (-1)
             51 BINARY_SUBSCR       
             52 CALL_FUNCTION            1
             55 LOAD_CONST               4 (2)
             58 BINARY_SUBTRACT     
             59 LOAD_GLOBAL              0 (ord)
             62 LOAD_FAST                0 (flag)
             65 LOAD_CONST               5 (7)
             68 BINARY_SUBSCR       
             69 CALL_FUNCTION            1
             72 COMPARE_OP               3 (!=)
             75 POP_JUMP_IF_FALSE       88

ord(flag[0]) + 52 = ord(flag[-1])
ord(flag[-1]) - 2 = ord(flag[7])
★まだ具体的な文字はわからないので保留(1)

 11     >>   88 LOAD_FAST                0 (flag)
             91 LOAD_CONST               5 (7)
             94 SLICE+2             
             95 LOAD_CONST               6 ('ISITDTU')
             98 COMPARE_OP               3 (!=)
            101 POP_JUMP_IF_FALSE      120

flag[:7] = 'ISITDTU'

ここで保留(1)を考える。
・flag[-1] == chr(73 + 52) == '}'
・flag[7] = chr(73 + 52 - 2) == '{'

          11111111112222222222
012345678901234567890123456789
ISITDTU{                     }

 13     >>  120 LOAD_FAST                0 (flag)
            123 LOAD_CONST               7 (9)
            126 BINARY_SUBSCR       
            127 LOAD_FAST                0 (flag)
            130 LOAD_CONST               8 (14)
            133 BINARY_SUBSCR       
            134 COMPARE_OP               3 (!=)
            137 POP_JUMP_IF_TRUE       180
            140 LOAD_FAST                0 (flag)
            143 LOAD_CONST               8 (14)
            146 BINARY_SUBSCR       
            147 LOAD_FAST                0 (flag)
            150 LOAD_CONST               9 (19)
            153 BINARY_SUBSCR       
            154 COMPARE_OP               3 (!=)
            157 POP_JUMP_IF_TRUE       180
            160 LOAD_FAST                0 (flag)
            163 LOAD_CONST               9 (19)
            166 BINARY_SUBSCR       
            167 LOAD_FAST                0 (flag)
            170 LOAD_CONST              10 (24)
            173 BINARY_SUBSCR       
            174 COMPARE_OP               3 (!=)
            177 POP_JUMP_IF_FALSE      193

flag[9] == flag[14]
flag[14] == flag[19]
flag[19] == flag[24]
→"_"のことを言っているのか?

          11111111112222222222
012345678901234567890123456789
ISITDTU{ _    _    _    _    }

 15     >>  193 LOAD_GLOBAL              0 (ord)
            196 LOAD_FAST                0 (flag)
            199 LOAD_CONST              12 (8)
            202 BINARY_SUBSCR       
            203 CALL_FUNCTION            1
            206 LOAD_CONST              13 (49)
            209 COMPARE_OP               3 (!=)
            212 POP_JUMP_IF_TRUE       235
            215 LOAD_FAST                0 (flag)
            218 LOAD_CONST              12 (8)
            221 BINARY_SUBSCR       
            222 LOAD_FAST                0 (flag)
            225 LOAD_CONST              14 (16)
            228 BINARY_SUBSCR       
            229 COMPARE_OP               3 (!=)
            232 POP_JUMP_IF_FALSE      245

ord(flag[8]) == 49
flag[8] == flag[16]
→flag[8] == flag[16] == '1'

          11111111112222222222
012345678901234567890123456789
ISITDTU{1_    _ 1  _    _    }


 17     >>  245 LOAD_FAST                0 (flag)
            248 LOAD_CONST              15 (10)
            251 LOAD_CONST               8 (14)
            254 SLICE+3             
            255 LOAD_CONST              16 ('d0nT')
            258 COMPARE_OP               3 (!=)
            261 POP_JUMP_IF_FALSE      277

flag[10:14] == 'd0nT'

          11111111112222222222
012345678901234567890123456789
ISITDTU{1_d0nT_ 1  _    _    }

 19     >>  277 LOAD_GLOBAL              4 (int)
            280 LOAD_FAST                0 (flag)
            283 LOAD_CONST              17 (18)
            286 BINARY_SUBSCR       
            287 CALL_FUNCTION            1
            290 LOAD_GLOBAL              4 (int)
            293 LOAD_FAST                0 (flag)
            296 LOAD_CONST              18 (23)
            299 BINARY_SUBSCR       
            300 CALL_FUNCTION            1
            303 BINARY_ADD          
            304 LOAD_GLOBAL              4 (int)
            307 LOAD_FAST                0 (flag)
            310 LOAD_CONST              19 (28)
            313 BINARY_SUBSCR       
            314 CALL_FUNCTION            1
            317 BINARY_ADD          
            318 LOAD_CONST               7 (9)
            321 COMPARE_OP               3 (!=)
            324 POP_JUMP_IF_TRUE       347
            327 LOAD_FAST                0 (flag)
            330 LOAD_CONST              17 (18)
            333 BINARY_SUBSCR       
            334 LOAD_FAST                0 (flag)
            337 LOAD_CONST              19 (28)
            340 BINARY_SUBSCR       
            341 COMPARE_OP               3 (!=)
            344 POP_JUMP_IF_FALSE      357

int(flag[18]) + int(flag[23]) + int(flag[28]) == 9
flag[18] == flag[28]
★まだ具体的な文字はわからないので保留(2)

          11111111112222222222
012345678901234567890123456789
ISITDTU{1_d0nT_ 1  _    _    }


 21     >>  357 LOAD_FAST                0 (flag)
            360 LOAD_CONST              20 (15)
            363 BINARY_SUBSCR       
            364 LOAD_CONST              21 ('L')
            367 COMPARE_OP               3 (!=)
            370 POP_JUMP_IF_FALSE      386

flag[15] == 'L'

          11111111112222222222
012345678901234567890123456789
ISITDTU{1_d0nT_L1  _    _    }


 23     >>  386 LOAD_GLOBAL              0 (ord)
            389 LOAD_FAST                0 (flag)
            392 LOAD_CONST              22 (17)
            395 BINARY_SUBSCR       
            396 CALL_FUNCTION            1
            399 LOAD_CONST              23 (-10)
            402 BINARY_XOR          
            403 LOAD_CONST              24 (-99)
            406 COMPARE_OP               3 (!=)
            409 POP_JUMP_IF_FALSE      422

ord(flag[17]) == (-10) ^ (-99)
→flag[17] == chr(107) == 'k'

          11111111112222222222
012345678901234567890123456789
ISITDTU{1_d0nT_L1k _    _    }

 25     >>  422 LOAD_GLOBAL              0 (ord)
            425 LOAD_FAST                0 (flag)
            428 LOAD_CONST              25 (20)
            431 BINARY_SUBSCR       
            432 CALL_FUNCTION            1
            435 LOAD_CONST               4 (2)
            438 BINARY_ADD          
            439 LOAD_GLOBAL              0 (ord)
            442 LOAD_FAST                0 (flag)
            445 LOAD_CONST              26 (27)
            448 BINARY_SUBSCR       
            449 CALL_FUNCTION            1
            452 COMPARE_OP               3 (!=)
            455 POP_JUMP_IF_TRUE       502
            458 LOAD_GLOBAL              0 (ord)
            461 LOAD_FAST                0 (flag)
            464 LOAD_CONST              26 (27)
            467 BINARY_SUBSCR       
            468 CALL_FUNCTION            1
            471 LOAD_CONST              27 (123)
            474 COMPARE_OP               4 (>)
            477 POP_JUMP_IF_TRUE       502
            480 LOAD_GLOBAL              0 (ord)
            483 LOAD_FAST                0 (flag)
            486 LOAD_CONST              25 (20)
            489 BINARY_SUBSCR       
            490 CALL_FUNCTION            1
            493 LOAD_CONST              28 (97)
            496 COMPARE_OP               0 (<)
            499 POP_JUMP_IF_FALSE      515

ord(flag[20]) + 2 == ord(flag[27])
ord(flag[27]) <= 123
ord(flag[20]) >= 97
★まだ具体的な文字はわからないので保留(3)

          11111111112222222222
012345678901234567890123456789
ISITDTU{1_d0nT_L1k _    _    }

 27     >>  515 LOAD_GLOBAL              0 (ord)
            518 LOAD_FAST                0 (flag)
            521 LOAD_CONST              26 (27)
            524 BINARY_SUBSCR       
            525 CALL_FUNCTION            1
            528 LOAD_CONST              29 (100)
            531 BINARY_MODULO       
            532 LOAD_CONST               1 (0)
            535 COMPARE_OP               3 (!=)
            538 POP_JUMP_IF_FALSE      551

ord(flag[27]) % 100 == 0
→ord(flag[27]) == 100
→flag[27] == 'd'

ここで保留(3)を考える。
flag[20] == 'b'

          11111111112222222222
012345678901234567890123456789
ISITDTU{1_d0nT_L1k _b   _  d }

 29     >>  551 LOAD_FAST                0 (flag)
            554 LOAD_CONST              30 (25)
            557 BINARY_SUBSCR       
            558 LOAD_CONST              31 ('C')
            561 COMPARE_OP               3 (!=)
            564 POP_JUMP_IF_FALSE      580

flag[25] = 'C'

          11111111112222222222
012345678901234567890123456789
ISITDTU{1_d0nT_L1k _b   _C d }

 31     >>  580 LOAD_GLOBAL              0 (ord)
            583 LOAD_FAST                0 (flag)
            586 LOAD_CONST              32 (26)
            589 BINARY_SUBSCR       
            590 CALL_FUNCTION            1
            593 LOAD_CONST               4 (2)
            596 BINARY_MODULO       
            597 LOAD_CONST               1 (0)
            600 COMPARE_OP               3 (!=)
            603 POP_JUMP_IF_TRUE       675
            606 LOAD_GLOBAL              0 (ord)
            609 LOAD_FAST                0 (flag)
            612 LOAD_CONST              32 (26)
            615 BINARY_SUBSCR       
            616 CALL_FUNCTION            1
            619 LOAD_CONST              33 (3)
            622 BINARY_MODULO       
            623 LOAD_CONST               1 (0)
            626 COMPARE_OP               3 (!=)
            629 POP_JUMP_IF_TRUE       675
            632 LOAD_GLOBAL              0 (ord)
            635 LOAD_FAST                0 (flag)
            638 LOAD_CONST              32 (26)
            641 BINARY_SUBSCR       
            642 CALL_FUNCTION            1
            645 LOAD_CONST              34 (4)
            648 BINARY_MODULO       
            649 LOAD_CONST               1 (0)
            652 COMPARE_OP               3 (!=)
            655 POP_JUMP_IF_TRUE       675
            658 LOAD_FAST                0 (flag)
            661 LOAD_CONST              32 (26)
            664 BINARY_SUBSCR       
            665 LOAD_ATTR                5 (isdigit)
            668 CALL_FUNCTION            0
            671 UNARY_NOT           
            672 POP_JUMP_IF_FALSE      685

ord(flag[26]) % 2 == 0
ord(flag[26]) % 3 == 0
ord(flag[26]) % 4 == 0
flag[26]は数値
→flag[26]は'0'

          11111111112222222222
012345678901234567890123456789
ISITDTU{1_d0nT_L1k _b   _C0d }

 33     >>  685 LOAD_GLOBAL              4 (int)
            688 LOAD_FAST                0 (flag)
            691 LOAD_CONST              18 (23)
            694 BINARY_SUBSCR       
            695 CALL_FUNCTION            1
            698 LOAD_CONST              33 (3)
            701 COMPARE_OP               3 (!=)
            704 POP_JUMP_IF_FALSE      720

int(flag[23]) == 3

ここで保留(2)を考える。
int(flag[18]) + int(flag[28]) == 9 - 3
flag[18] == flag[28]
→ flag[18] == flag[28] == '3'

          11111111112222222222
012345678901234567890123456789
ISITDTU{1_d0nT_L1k3_b  3_C0d3}

 35     >>  720 LOAD_FAST                0 (flag)
            723 LOAD_CONST              35 (22)
            726 BINARY_SUBSCR       
            727 LOAD_FAST                0 (flag)
            730 LOAD_CONST              36 (13)
            733 BINARY_SUBSCR       
            734 LOAD_ATTR                6 (lower)
            737 CALL_FUNCTION            0
            740 COMPARE_OP               3 (!=)
            743 POP_JUMP_IF_FALSE      756

flag[22] == flag[13].lower()

          11111111112222222222
012345678901234567890123456789
ISITDTU{1_d0nT_L1k3_b t3_C0d3}

 42         791 LOAD_FAST                2 (tmp)
            794 LOAD_GLOBAL              0 (ord)
            797 LOAD_FAST                3 (i)
            800 CALL_FUNCTION            1
            803 INPLACE_ADD         
            804 STORE_FAST               2 (tmp)
            807 JUMP_ABSOLUTE          785
        >>  810 POP_BLOCK           

 43     >>  811 LOAD_FAST                2 (tmp)
            814 LOAD_CONST              37 (2441)
            817 COMPARE_OP               3 (!=)
            820 POP_JUMP_IF_FALSE      833

フラグ全体のASCIIコードの合計は2441。
このことから残りの文字のASCIIコードを算出し、文字を割り出す。
tmp_flag = 'ISITDTU{1_d0nT_L1k3_b\x00t3_C0d3}'

sum_code = 0
for c in tmp_flag:
    sum_code += ord(c)

code = 2441 - sum_code
flag = tmp_flag.replace('\x00', chr(code))
print flag
ISITDTU{1_d0nT_L1k3_b:t3_C0d3}

Survey (Thank you)

アンケートに答えたら、フラグが表示された。

ISITDTU{thank_you_for_your_feedback}