secure Prime Generator writeup - Codegate CTF 2023 Preliminary
2023-6-22 23:36:40 Author: furutsuki.hatenablog.com(查看原文) 阅读量:34 收藏

サーバ側で何やら素数(?)を2つ生成して、さらにそれを加工した値をあたかもRSA nとして扱ってくれるので、その Nを使って暗号化されたフラグを復号せよ、という問題です。 より具体的には以下のような処理を実行するスクリプトでした。

validity checkに答えるのがなかなか難しくて、これを通過できないとだめなので、どうにかして p_1, q_1の具体的な値を知る必要がありそうです。まず最初に考えたのは X_0として p_1^{e_s}を送り N = p_1 (q_1 + 1)をもらって (q_1 + 1)^{e_s} \mod N_s q_1^{e_s} \mod N_sから q_1を求める方法でしたが、これは多項式のGCDがタイムアウトに微妙に届かなかったので不採用になりました。

次に考えたのは X_0として p_1^{4e_s}を送り N = p_1^4 + p_1q_1 = p_1(p_1^3 + q_1)とする方法で、これは p_1 \approx N^{1/4}とする近似がうまく行きました。当然 q_1も計算できるし、validity checkも通過できます。

あとはこのmodulus で flag ^ {65537} \mod Nが復号できれば良いので、 p_1^3 + q_1素数になるまでガチャを回しました。

solution scriptはこちら

from ptrlib import Socket, Process
from random import randrange
from Crypto.Util.number import long_to_bytes, isPrime
from hashlib import sha256
from itertools import product as iterprod
from gmpy2 import iroot

def POW(sock):
    b_postfix = sock.recvlineafter("b = ").decode()[6:].strip()
    h = sock.recvlineafter(" = ").decode().strip()
    for brute in iterprod('0123456789abcdef', repeat=6):
        b_prefix = ''.join(brute)
        b_ = b_prefix + b_postfix
        if sha256(bytes.fromhex(b_)).hexdigest() == h:
            sock.sendlineafter(b' > ', b_prefix.encode())
            return True

    assert 0, "Something went wrong.."

while True:
    try:
        
        sock = Socket("nc 43.200.47.102 9001")
        POW(sock)
        SERVER_N = int(sock.recvlineafter("SERVER_N = "))
        SERVER_E = int(sock.recvlineafter("SERVER_E = "))

        
        for p in [2,3,5,7,11,13]:
            cands = [1] + [-1-x for x in range((p + 1) // 2 - 1)]
            sock.sendlineafter(" > ", " ".join([str(x) for x in cands]))

        
        for p in [2,3,5,7,11,13]:
            if p == 2:
                cands = [0] + [-1-x for x in range((p + 1) // 2 - 1)]
            else:
                cands = [1] + [-1-x for x in range((p + 1) // 2 - 1)]
            sock.sendlineafter(" > ", " ".join([str(x) for x in cands]))

        p1_enc = int(sock.recvlineafter("p1_enc = "))
        q1_enc = int(sock.recvlineafter("q1_enc = "))
        r = randrange(2**1536)

        X = [ pow(p1_enc, 4, SERVER_N) ]
        sock.sendlineafter("X > ", " ".join([str(x) for x in X + [0 for _ in range(12  - len(X))]]))

        N = int(sock.recvlineafter("N = "))  
        p, _ = iroot(N, 4)
        q = (N - p**4) // p

        assert pow(p, SERVER_E, SERVER_N) == p1_enc, "p"
        assert pow(q, SERVER_E, SERVER_N) == q1_enc, "q"
        assert N == p*(p**3 + q), "N"

        for _ in range(20):
            b = int(sock.recvlineafter("b = "))
            digest = sha256(long_to_bytes(pow(b, N - (p+q) + 1, N))).hexdigest()
            sock.sendlineafter("digest > ", digest)
            line = sock.recvline()
            assert b"good" in line

        c = int(sock.recvlineafter("FLAG_ENC = "))
        if isPrime(p**3 + q) and (p**3 + q) > 2**(127 * 8):
            print(p)
            print(q)
            print(N)
            print(c)

            d = pow(65537, -1, p**3 + q - 1)
            m = pow(c, d, p**3 + q)
            print(long_to_bytes(m))

            quit()
    except AssertionError as e:
        print(e)
        continue

 p_1, q_1 \mod 2,3,5,7,11,13で満たすべき値を制御できたのはなんの意味があったんだろう…


文章来源: https://furutsuki.hatenablog.com/entry/2023/06/23/003640
如有侵权请联系:admin#unsafe.sh