0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AlpacaHack Round 12: RSARSARSARSARSARSA Upsolve

Posted at

RSARSARSARSARSARSA

authored by yu212

何度も言わないでもわかるよ……

from math import gcd
import os
from Crypto.Util.number import getPrime, bytes_to_long

e = 19
while True:
    p = getPrime(2048)
    q = getPrime(2048)
    if gcd((p - 1) * (q - 1), e) == 1:
        break
n = p * q

flag = os.environ.get("FLAG", "Alpaca{**** REDACTED ****}")
assert len(flag) == 26 and flag.startswith("Alpaca{") and flag.endswith("}")

m = bytes_to_long((flag * 1337).encode())
c = pow(m, e, n)

print(f"{n = }")
print(f"{e = }")
print(f"{c = }")

解法

ここで気になるのはflag * 1337というところです。
これがどういう関係になるのか実験をしてみましょう。

from Crypto.Util.number import bytes_to_long

flag = b"test"

print(hex(bytes_to_long(flag)))
print(hex(bytes_to_long(flag * 2)))
print(hex(bytes_to_long(flag * 3)))

hexにしてみたところ、以下のような出力が得られました。

0x74657374
0x7465737474657374
0x746573747465737474657374

今回、flagは26文字であることが確定しており、prefix(Alpaca{), suffix(})はすでに分かっていることから、
不明な文字数は18文字のみであるといえます。
つまり、平文$m$は既知部分$K$と未知部分$U$とすると、
$$
m = K + U
$$
となります。特に$U$は、未知18バイト$x$が線形に入るので、
$$
U = Cx
$$
と考えることができます。ただし、
$$
C = \sum_{i=0}^{1336} 256^{26i+1}
$$
とします。
すると、暗号文$c$は
$$
c \equiv m^e \equiv (K + Cx)^19 \pmod n
$$
となり、
$$
f(x) = (K + Cx)^19 - c \equiv 0 \pmod n
$$
と考えることができます。さて、$0 \leq x < 2^144$なので、小さい範囲の根となることがわかります。
以上の考えから、実装するとこのようになります。

from sage.all import *
import cuso
from Crypto.Util.number import bytes_to_long, long_to_bytes

n = 434245275129793896913302623186216967500119715299127153234221039838158526818290666891561167619572507897277032319251523352710966722158326513857889678449160348496647427753832233179173745189495799707833020232209447520485615893168704144655033371807912826948460011240258726843346618328839282439390863464375320181495406806870462330735361196286553150480225927729088313551861682406252457739974850015509783430978939475350707211461876140420181118923743456062581297038004651412953310377554877499792225388059857865550418697212704277742826280689987165702071346542831836616149138379224837551040036947064990027047482745931141458056028719767845142490618375017582275824317241572815337810658684051187938258804346960781372035972758516593800419459342799854863845667715099378564373594732798224797622583907677749880918106223965727445907355069025939554400938193579295415911074889648122298896605189398591684277376327938718166279159875826993866460251900514487349848332991005775574378131897581182876147580659857596204121970624162722935263271888969020482566142620134100258216288390250174699829806817678453601913377347867137739622906815272561714188564065071077762169177825466514512198167566882661748389120146622447920498988341055543170346944366105037929197965527
e = 19
c = 78338816976998323261765735600063671710448529902850366859501110834174319629348492230679353792803618614020892663940158627385470036549819116375194598599193512981265682997072278631964394686243958989105159463105190885437258093111178664394786430767942639437287236999171486583513816766766869843448941665224796216610702708658300011987744401747551989248270799179750556330952646223694000679475842632497149402602469848595868051660228892506097962300820851000134370939783634534516434054009303981106884637932006844265722691022870174977860945699441650254771777451995160642261482879537396171107016491225773397809485749640163676209732235156461483660111845782227127763086286553520914359194795617080980736767821995556156173267185240945707717461037831992544868933876015548419376861213017988005848033349136839971120363078490938026883354839573512645985195570831018461470031329716026531550172207332072481279548470657090575709419245114386419567236219816237412255505882075283974654569995321334498673793010812162088796252555619242463561750801895032793870706949913548310632113206159695535952422316840587214237406730422405058644629458566515378607614900910335034732797410592671297941526063690060922625005949094383664832255082556088451940780657576420871470920836

prefix = b"Alpaca{"
suffix = b"}"
unknown_len = 18
reps = 1337

block_len = len(prefix) + unknown_len + len(suffix)
assert block_len == 26

flag_guess = prefix + (b"\x00" * unknown_len) + suffix
repeated_flag_guess = flag_guess * reps
guess = Integer(bytes_to_long(repeated_flag_guess))

x = var("x")

coeff = Integer(0)
for i in range(reps):
    coeff += Integer(256) ** Integer(i * block_len + len(suffix))

m = guess + coeff * x
f = m**e - c
bounds = {x: (0, 2 ** (8 * unknown_len))}

roots = cuso.find_small_roots(
    relations=[f],
    bounds=bounds,
    modulus=n,
)

if not roots:
    raise RuntimeError("no roots found (try adjusting bounds/structure)")

x0 = Integer(roots[0][x]) if x in roots[0] else Integer(roots[0].get("x"))
flag = prefix + long_to_bytes(int(x0), unknown_len) + suffix
print(flag.decode())

Flag: Alpaca{cryptocryptocrypto}

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?