RCTF 2018 Writeup

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

Number Game (Misc)

4つの数字を言うと、位置が合っている数と位置が違うが含まれている数を教えてもらい、正しい数字を推測するゲーム。Bulls and cows という名前らしい。
https://rosettacode.org/wiki/Bulls_and_cows/Player#Python を参考にコードを書く。チャンスは6回。

import socket
import re
import itertools
import string
import hashlib

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

def parse_score(score):
    score = score.strip().split(',')
    return tuple(int(s.strip()) for s in score)

def scorecalc(guess, chosen):
    bulls = cows = 0
    for g,c in itertools.izip(guess, chosen):
        if g == c:
            bulls += 1
        elif g in chosen:
            cows += 1
    return bulls, cows

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('149.28.139.172', 10002))

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

pattern = 'sha256\(\*\*\*\*\+(.+)\) == (.+)'
m = re.match(pattern, data)
text_tail = m.group(1)
h = m.group(2)

data = recvuntil(s, ':')
print data

for c in itertools.product(string.digits + string.letters, repeat=4):
    text_head = ''.join(c)
    text = text_head + text_tail
    if hashlib.sha256(text).hexdigest() == h:
        print text_head
        s.sendall(text_head + '\n')
        break

data = ''
for i in range(17):
    data += recvuntil(s, '\n')
print data

digits = '0123456789'

for round in range(8):
    choices = list(itertools.permutations(digits, 4))
    answers = []
    scores  = []

    data = ''
    for i in range(2):
        data += recvuntil(s, '\n')
    print data

    while True:
        ans = choices[0]
        answers.append(ans)
        dig_str = ' '.join(ans)
        print dig_str
        s.sendall(dig_str + '\n')
        data = recvuntil(s, '\n')
        print data
        if 'Nope.' in data:
            score = parse_score(data[6:])
            scores.append(score)
            choices = [c for c in choices if scorecalc(c, ans) == score]
        else:
            break

data = s.recv(1024)
print data

失敗することも多々あるが、8ラウンド成功すればよいので、このコードで何回も挑戦。

RCTF{0lD_GaM3_nAmed_Bu11s_4nd_C0ws}

ECDH (Crypto)

$ nc ECDH.2018.teamrois.cn 42000

Welcome to my GETFLAG system
1. visit Alice
2. visit Bob
3. about
input here: 1

Hello nobody...I'm Alice... you can:
1. ask for flag
2. ask me about my public key
3. ask me about Bob's public key
4. tell me Bob's public key
input here: 1
Bob sent me something.Bob said: Just kidding~

Welcome to my GETFLAG system
1. visit Alice
2. visit Bob
3. about
input here: 1

Hello nobody...I'm Alice... you can:
1. ask for flag
2. ask me about my public key
3. ask me about Bob's public key
4. tell me Bob's public key
input here: 2
pub: 03474f81154bb8b931ddc36f9746484517

Welcome to my GETFLAG system
1. visit Alice
2. visit Bob
3. about
input here: 1

Hello nobody...I'm Alice... you can:
1. ask for flag
2. ask me about my public key
3. ask me about Bob's public key
4. tell me Bob's public key
input here: 3
pub: 034320a6aeb0b093332d883a0c17fac4ce

Welcome to my GETFLAG system
1. visit Alice
2. visit Bob
3. about
input here: 1

Hello nobody...I'm Alice... you can:
1. ask for flag
2. ask me about my public key
3. ask me about Bob's public key
4. tell me Bob's public key
input here: 4

Alice have a new public key? Thank you for telling me!
input here with hex string (e.g deadbeef): deadbeef
Oops!

Welcome to my GETFLAG system
1. visit Alice
2. visit Bob
3. about
input here: 2

Hello nobody...I'm Bob... you can:
1. ask for flag
2. ask me about my public key
3. ask me about Alice's public key
4. tell me Alice's public key
input here: 1
I'v already told Alice...bye

Welcome to my GETFLAG system
1. visit Alice
2. visit Bob
3. about
input here: 2

Hello nobody...I'm Bob... you can:
1. ask for flag
2. ask me about my public key
3. ask me about Alice's public key
4. tell me Alice's public key
input here: 2
pub: 034320a6aeb0b093332d883a0c17fac4ce

Welcome to my GETFLAG system
1. visit Alice
2. visit Bob
3. about
input here: 2

Hello nobody...I'm Bob... you can:
1. ask for flag
2. ask me about my public key
3. ask me about Alice's public key
4. tell me Alice's public key
input here: 3
pub: 03474f81154bb8b931ddc36f9746484517

Welcome to my GETFLAG system
1. visit Alice
2. visit Bob
3. about
input here: 2

Hello nobody...I'm Bob... you can:
1. ask for flag
2. ask me about my public key
3. ask me about Alice's public key
4. tell me Alice's public key
input here: 4

Bob have a new public key? Thank you for telling me!
input here with hex string (e.g deadbeef): deadbeef
Oops!

Welcome to my GETFLAG system
1. visit Alice
2. visit Bob
3. about
input here: 3
ECDH.....https://github.com/esxgx/easy-ecc..secp128r1..AES...EBC.......

ECDHで共通鍵を渡し、AESのECBモードで暗号化したメッセージをBobが送っているということのようだ。

https://github.com/esxgx/easy-ecc
・public keyの2バイト目以降:l_public.x
・public keyの1バイト目:2 + (l_public.y[0] & 0x01)

上記の仕様に基づいているが、タイトル通りECDHの問題。

dA: Aliceの秘密鍵
dB: Bobの秘密鍵
QA: Aliceの公開鍵(QA = dA * G)
QB: Bobの公開鍵(QB = dB * G)

dA * QB = dA * (dB * G) = dB * (dA * G) = dB * QA

これが共通鍵になる。
Aliceの公開鍵をGにすると、dB * G、つまりBobの公開鍵が共通鍵となる。共通鍵を取得できたら、AESのECBモードで復号するとフラグが得られる。スクリプトにすると以下のようになる。

import socket
from Crypto.Cipher import AES

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

def send_data(s, data):
    r = recvuntil(s, ': ')
    print r + data
    s.sendall(data + '\n')

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('ECDH.2018.teamrois.cn', 42000))

# Alice's public key setting
send_data(s, '2')
send_data(s, '4')
send_data(s, '03161ff7528b899b2d0c28607ca52c5b86')

# get Bob's public key
send_data(s, '2')
send_data(s, '2')
r = recvuntil(s, '\n')
print r[:-1]
key = r[7:-1].decode('hex')

# get encrypted flag
send_data(s, '2')
send_data(s, '1')
send_data(s, '1')
send_data(s, '1')
r = recvuntil(s, '\n')
print r[:-1]
enc = r[32:-1].decode('hex')

# decrypt
aes = AES.new(key, AES.MODE_ECB)
flag = aes.decrypt(enc)
while True:
    if flag[-1] == '\x00':
        flag = flag[:-1]
    else:
        break
print flag
RCTF{UgotTHEpoint}