Rating: 1.0

データを暗号化してくれるサーバが動いており、鍵とフラグは外部から読み込んでいる。サーバの Python コードが公開されている。

コードを見ると、”l33t please” で始まる文字列を渡すと、文字列の末尾にフラグを追加したうえで AES で暗号化して base64 で返してくれる。CBC などは特に使っていないようで、同じ文字列は毎回同じように返ってきた。

AES のブロックサイズは 128 ビットなので、16文字ごとに、望むものと一致すればその部分の暗号は同じになる。

フラグの i 文字目までがわかっているとき、 “l33t please”に続けて、適当な文字を適宜詰め、そのあとフラグの i 文字目までを埋めて最後のブロックが一文字だけ余る状態にし、残りの1文字を一通り試すことができる。
この時、”l33t please”とパディングのみを渡した結果(この場合はパディングの直後に正しいフラグを入れて暗号化してくれる)と比較すれば、正解の時だけ合致するブロックが多くなる。

これを順に試せば、フラグが出てくる。
    
#!/usr/bin/python
 
import commands
import sys
 
def encrypt(s):
    return commands.getoutput('echo -n \'' + s + '\' | (base64 -w 0; echo) | nc l33tcrypt.vuln.icec.tf 6001 | grep OH7').strip()
 
def sharestr(s, t):
    ret = 0
    for i in range(0, min(len(s), len(t))):
        if s[i] == t[i]:
            ret = i + 1
        else:
            break
    return ret
 
header = 'l33tserver please'
flag_cand = ''
cand_chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_{}'
 
cur_cand = ''
 
while True:
    cur_cand_len = 0
    tmphead = header + '/' * (16 - (len(header) + len(flag_cand) + 1) % 16)
    cur_enc = encrypt(tmphead)
 
    for i_loop in range(0, len(cand_chars)):
        now_cand = flag_cand + cand_chars[i_loop]
        print 'Trying: ', tmphead + now_cand
        tmp_enc = encrypt(tmphead + now_cand)
 
        tmp_len = sharestr(cur_enc, tmp_enc)
        print tmp_len
 
        if tmp_len > cur_cand_len:
            cur_cand_len = tmp_len
            cur_cand = now_cand
     
    if len(cur_cand) == len(flag_cand):
        sys.exit(1)
    flag_cand = cur_cand

Original writeup (https://blog.nhiroki.net/2016/08/27/icectf-2016-writeup).
norajAug. 27, 2016, 2:21 p.m.

not in english