CTFZone 2017 Writeup

この大会は2017/7/15 18:00(JST)~2017/7/17 6:00(JST)に開催されました。
今回もチームで参戦。結果は1153点で55チーム中24位でした。
自分で解けた問題をWriteupとして書いておきます。

MPRSA (CRYPTO)

Multi-Prime RSAの問題。まず素因数分解したいが、factordbではできなかった。
暗号化のプログラムから、deltaの値(5~15)は総当たりで素数の構成を作り、nと同じ値になるものを探す。数時間かかったが、次のようなプログラムで素因数を割り出すことができた。ちなみに delta=14の場合に該当するnが見つかった。

from gmpy2 import next_prime

def compute_module(primes):
    n = 1
    for prime in primes:
        n *= prime
    return n

with open('public.txt', 'r') as f:
    data = f.read()

n = int(data.split('\n')[1].split(' = ')[1])

delta = 14
p = 177739015005173300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

adjust = pow(2, 1024)
p0 = p
while True:
    #print p
    P = [next_prime(p)]
    for i in range(1, 4):
        P.append(next_prime(P[i-1] * delta))
    mul = compute_module(P)
    print mul
    if mul == n:
        print 'P[0] =', P[0]
        print 'P[1] =', P[1]
        print 'P[2] =', P[2]
        print 'P[3] =', P[3]
        break
    else:
        diff = n - mul
        if diff < 0:
            if adjust == 1:
                print 'Not Found (delta = %d)' % delta
                break
            else:
                adjust /= 2
                p = p0
        else:
            p0 = p
            p = next_prime(p + adjust)

素因数分解の結果は以下の通り。

P[0] = 177739015005173306533752250332928388271426563815093455666936081629571193511808970499241559574326686383600364964248435983786753776661738101198468295487687752622214814554023747926012377837938347566934895426939099916675611018615527164379921811922640194594903892753383803569371101697376356302460080232868430713251
P[1] = 2488346210072426291472531504660997435799971893411308379337105142813996709165325586989381834040573609370405109499478103773014552873264333416778556136827628536711007403756332470964173289731136865937088535977147398833458554260617380301318905366916962724328654498547373249971195423763268988234441123260158029986729
P[2] = 34836846941013968080615441065253964101199606507758317310719471999395953928314558217851345676568030531185671532992693452822203740225700667834899785915586799513954103652588654593498426056235916123119239503680063583668419759648643324218464675136837478140601162979663225499596735932685765835282175725642212419814243
P[3] = 487715857174195553128616174913555497416794491108616442350072607991543354996403815049918839471952427436599401461897708339510852363159809349688597002818215193195357451136241164308977964787302825723669353051520890171357876635081006539058505451915724693968416281715285156994354303057600721693950460158990973877400281

この結果から、Muti-Prime RSAの復号プログラムを書く。

import gmpy

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 * gmpy.invert(p, n_i) * p
    return sum % prod

with open('data.enc', 'r') as f:
    c = int(f.read())

with open('public.txt', 'r') as f:
    pub = f.read()

e = int(pub.split('\n')[0].split(' = ')[1])
n = int(pub.split('\n')[1].split(' = ')[1])

primes = [
    177739015005173306533752250332928388271426563815093455666936081629571193511808970499241559574326686383600364964248435983786753776661738101198468295487687752622214814554023747926012377837938347566934895426939099916675611018615527164379921811922640194594903892753383803569371101697376356302460080232868430713251,
    2488346210072426291472531504660997435799971893411308379337105142813996709165325586989381834040573609370405109499478103773014552873264333416778556136827628536711007403756332470964173289731136865937088535977147398833458554260617380301318905366916962724328654498547373249971195423763268988234441123260158029986729,
    34836846941013968080615441065253964101199606507758317310719471999395953928314558217851345676568030531185671532992693452822203740225700667834899785915586799513954103652588654593498426056235916123119239503680063583668419759648643324218464675136837478140601162979663225499596735932685765835282175725642212419814243,
    487715857174195553128616174913555497416794491108616442350072607991543354996403815049918839471952427436599401461897708339510852363159809349688597002818215193195357451136241164308977964787302825723669353051520890171357876635081006539058505451915724693968416281715285156994354303057600721693950460158990973877400281]

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

m = chinese_remainder(n_ary, a_ary)
flag = ('%x' % m).decode('hex')
print flag

実行結果は次の通り。

Mr.D (12:10):
Okey, see you later ;)

Mr.D (19:30):
So can you help me?

Anonymous (19:31):
Yeah, we will have 10,000 falsified voters. Transfer 100000$ to my bank account: ctfzone{3177809746931830}
ctfzone{3177809746931830}