<style> img[alt=chall-sc] { display: block; margin: 0 auto; width: 100em; } p { text-align: justify; } p::first-line { text-indent: 0; } </style> # ITSEC ASIA FINAL 2025 WRITEUP ![chall-sc](https://hackmd.io/_uploads/rkRmFGkKgg.png) Last week, I had the opportunity to participate in the ITSEC Asia 2025 Final Round, held from Saturday, August 9th to Sunday, August 10th. The competition was organized by PT ITSEC Asia Tbk and brought together skilled cybersecurity enthusiasts from across the region. I joined the event as part of the team SNI - FLAREITO, where I focused on solving all of the cryptography challenges. After an intense and exciting competition, our team proudly finished in first place in the final round. In this writeup, I documented all of the cryptography challenges that I personally solved during the final competition. Each solution offers insight into how I approached and overcame the problems during the qualification round. Hope you enjoy reading it! # Venture Into the Dungeon ![chall-sc](https://hackmd.io/_uploads/rkYF29FOgx.png) Given `chall.py` and `secrets.py`. The flag variable is defined in the `secrets.py` ## chall.py ```python # !/usr/bin/env python3 from Crypto.Util.number import getPrime, bytes_to_long, inverse from secrets import FLAG assert FLAG.startswith(b'ITSEC{') and FLAG.endswith(b'}') class Dungeon: def __init__(self, key_len: int = 1024): while True: try: p,q = getPrime(key_len//2), getPrime(key_len//2) self.n = p*q self.e = 0x10001 et = (p-1)*(q-1) self._d = inverse(self.e, et) break except ValueError: continue def sloth(self, m: int) -> int: return pow(m, self.e, self.n) def shadow(self, c: int) -> int: p = pow(c, self._d, self.n) total_bits = p.bit_length() top_mask = ((1 << 128) - 1) << (total_bits - 128) bottom_mask = (1 << 128) - 1 mask = top_mask | bottom_mask return p & mask if __name__ == '__main__': Aid = Dungeon(1024) mystery = Aid.sloth(bytes_to_long(FLAG)) print(""" You take your first cautious steps inside, and the echo of your boots fills the silence. The corridors twist like the roots of some massive, underground tree, until the path splits into a dimly lit chamber where two odd figures wait. There's a tablet between these to figures. """) print(f"mystery: {mystery}") print(f"n: {Aid.n}") for _ in range(2014): print("What will you do") print('1. speak "the weight of sloth"') print('2. speak "the toll of secrets"') print("3. turn back and run") menu = "" while menu not in ["1","2","3"]: menu = input("(1|2|3): ") if menu == "1": userInput = "" userInput = input("...: ") if userInput.isdigit() and int(userInput) == bytes_to_long(FLAG): print("...Huh. You're still alive. Figures.") print("Well... guess you didn't really need me after all. Good job, I guess.") break print("...") elif menu == "2": userInput = "" while not userInput.isdigit(): userInput = input("payment: ") if int(userInput) < 1: print("Coin? Trinkets? Do you take me for a merchant?") print("Offer me coin again, and I will offer you silence.") continue if int(userInput) % mystery == 0: print("Secrets weigh more than gold. They stain more than blood. I do not want your glittering junk-bring me something that whispers. Something that hurts to say.") continue decrypted = Aid.shadow(int(userInput)) print(f"(whisper): {decrypted}") elif menu == "3": print("Running already? How predictable...") break ``` Given a challenge that implements RSA, the server generates a key and prints the modulus and the ciphertext. It exposes a decryption oracle that returns the top 128 bits and the bottom 128 bits, with the middle zeroed. Because the bottom window is preserved exactly, the oracle leaks the least significant bit (LSB) of the plaintext each time. Using RSA malleability (multiplicative homomorphism), for any integer $m$: $$ (mystery \times s^{e})^{d} \equiv m \times s \ (\text{mod}\ n) $$ So by multiplying the known ciphertext by $s$ to the power $e$, we control how the decrypted value changes without knowing $d$. The oracle always preserves the bottom 128 bits of $p = c$ to the power $d$ mod $n$. In particular, it reveals the least significant bit $p \ \&\ 1$ (the parity of $p$) exactly. For RSA moduli $n$ (odd), if we choose $s = 2$ to the power $i$ then: $$ p_i = \left( mystery \times (2^{i})^{e} \right)^{d} \equiv 2^{i} \times m \ (\text{mod}\ n) $$ Because $2$ to the power $i$ multiplied by $m$ equals $n$ multiplied by $$ \text{floor} \left( \frac{2^{i} \times m}{n} \right) $$ together with the remainder $2^{i} \times m \bmod n$, and $2^{i} \times m$ is even for $i \ge 1$ while $n$ is odd, we get: $$ \text{parity}(p_i) = \text{parity} \left( (2^{i} \times m) - n \times \text{floor} \left( \frac{2^{i} \times m}{n} \right) \right) $$ $$ = \text{parity} \left( -n \times \text{floor} \left( \frac{2^{i} \times m}{n} \right) \right) $$ $$ = \text{parity} \left( \text{floor} \left( \frac{2^{i} \times m}{n} \right) \right) $$ So the LSB tells us the parity of the integer: $$ \text{floor} \left( \frac{2^{i} \times m}{n} \right) $$ This is the classic parity (LSB) oracle for RSA: each query reveals one bit of information that allows us to halve the interval containing the unknown ratio $m/n$. I used a bisection attack on $m/n$ using only parity to retrieve the flag. ## Solver ```python #!/usr/bin/env python3 from pwn import * from fractions import Fraction import re, math context.log_level = 'debug' host, port = "nc 52.77.234.0 20256".split(" ")[1:3] e = 65537 def parse(io): b = b"" b += io.recvuntil(b"mystery:"); b += io.recvline() b += io.recvuntil(b"n:") ; b += io.recvline() b += io.recvuntil(b"(1|2|3): ") c = int(re.search(rb"mystery:\s*([0-9]+)", b).group(1)) n = int(re.search(rb"n:\s*([0-9]+)", b).group(1)) return c, n def parity_oracle(io, payment: int) -> int: io.sendline(b"2") io.recvuntil(b"payment: ") io.sendline(str(payment).encode()) while True: line = io.recvline(timeout=20) if not line: raise EOFError("server closed") if b"(whisper):" in line: v = int(line.split(b":", 1)[1].strip()) return v & 1 # lsb if b"(1|2|3):" in line: payment += 1 io.sendline(b"2") io.recvuntil(b"payment: ") io.sendline(str(payment).encode()) io = remote(host, port) c, n = parse(io) mystery = c g = pow(2, e, n) # g = (2 ** e) % n # interval for m/n (as rationals) L, U = Fraction(0), Fraction(1) steps = n.bit_length() + 4 for _ in range(steps): c = (c * g) % n p = parity_oracle(io, c) # parity of decrypted value mid = (L + U) / 2 if p == 0: # even => value < n/2 => keep lower half U = mid else: # odd => value >= n/2 => keep upper half L = mid m = math.floor(U * n) for cand in (m-2, m-1, m, m+1, m+2): if pow(cand, e, n) == mystery: m = cand break flag = m.to_bytes((m.bit_length() + 7)//8, "big") print(flag) io.close() ``` ![chall-sc](https://hackmd.io/_uploads/SJC1kiYdle.png) # Not So Simple RSA ![chall-sc](https://hackmd.io/_uploads/HyNpJiYOlx.png) Given `chal.py` and `output.txt` which is the output of the flag after the `chal.py` was run by the problem setter with the flag variable defined by him. ## chall.py ```python import random import gmpy2 import hashlib def find_p(e: int, bits: int, max_attempts=1_000_000): low_k = (1 << (bits - 1)) - 1 low_k = (low_k // e) + 1 high_k = (1 << bits) - 1 high_k = high_k // e if low_k > high_k: raise ValueError("Impossible: parameters give no k range") k = random.randrange(low_k, high_k + 1) for attempt in range(max_attempts): p = k * e + 1 if p.bit_length() != bits: k = low_k + ((k - low_k + 1) % (high_k - low_k + 1)) continue if gmpy2.is_prime(p): return int(p), int(k) k += 1 if k > high_k: k = low_k raise RuntimeError(f"Failed to find p in {max_attempts} attempts") def find_q_or_r(bits: int, e: int, max_attempts=10000): lower = 1 << (bits - 1) upper = (1 << bits) - 1 for _ in range(max_attempts): q = gmpy2.next_prime(random.randrange(lower, upper)) if (q - 1) % e != 0: return int(q) raise RuntimeError("Failed to find q with (q-1)%e != 0 in budget") def generate_challenge(): e = int(gmpy2.next_prime(2**28)) bits_p = 1024//3 bits_q = 1024//3 bits_r = 1024//3 p, k = find_p(e, bits_p) q = find_q_or_r(bits_q, e) r = find_q_or_r(bits_r, e) n = p * q * r phi_n = (p - 1) * (q - 1) * (r - 1) subset_length = 40 max_value = phi_n // (subset_length // 2) min_value = max_value // 100 values = [] solution_indices = set() num_in_solution = random.randint(subset_length // 3, 2 * subset_length // 3) solution_indices = set(random.sample(range(subset_length), num_in_solution)) remaining = phi_n solution_list = sorted(list(solution_indices)) for i in range(subset_length): if i in solution_indices: if i == solution_list[-1]: val = remaining else: num_remaining = len(solution_list) - solution_list.index(i) max_for_this = remaining // num_remaining val = random.randint(min_value, min(max_value, max_for_this)) remaining -= val else: val = random.randint(min_value, max_value) values.append(val) combined = list(zip(values, [1 if i in solution_indices else 0 for i in range(subset_length)])) random.shuffle(combined) values, solution = zip(*combined) values = list(values) solution = list(solution) subset_sum = sum(v * s for v, s in zip(values, solution)) if subset_sum != phi_n: diff = phi_n - subset_sum for i in range(len(values)): if solution[i] == 1: values[i] += diff break moduli = [1000000007, 1000000009, 1000000021] m = int.from_bytes(b"REDACTED_FLAG", "big") c = pow(m, e, n) print("n =", n) print("e =", e) print("e =", e) print("values =", values) print("size =", sum(solution)) print("phi_modular =", [(m, phi_n % m) for m in moduli]) print("phi_bits_high =", hex(phi_n >> (phi_n.bit_length() - 128))) print("phi_bits_low =", hex(phi_n & ((1 << 128) - 1))) print("verification_hash =", hashlib.sha256(str(phi_n).encode()).hexdigest()) if __name__ == "__main__": generate_challenge() ``` ## output.txt ```python n = 60419902565764548844188543053799539736520575597932824532389761522643875892236763090936952699801022241009608452637384156029134178007050986959672545796812659544119079405754458335003514178145056915824767178945504412120793435627631704573586996782481630193258573823429410349772037605005907442534016230552638558203 e = 268435459 c = 42077426242195692288259542826753875723706187537047968345077398360129407326191750134323576198720474598541102760396899177709744067388778715704602945081394301040443564303932191107115332093409897959823980390797003657503917523358293660420758330312005347193969217945630493348089893460949825739139342103857726182647 values = [2006121808675033655629912205539451731968788048689055659997112288437921349871706616002370887120200272996176639502330512162087050079360893814704031582967569895118118013898018846387830801348517233180122509405830333820662044128151568318688530795042907395181846553870038715532769117226055221064455551490950410774, 732828375666091792035482464097098683081812325032273526754649019175538590561093891163942860721380022094311226260495976886071736080266650350355174200287631871127070124310732575730594810294112385558803754155074092119958373224323895618603355556955287554755519430206474930206279761890888936446145908613396143934, 532889160593473743158032230072735506005255409608069924504987746744938724818092572883460758004024799244096357677865546298528380398704360328635766829721484968015359353975907368728049568484129428576888199179017490661469115249897516263106048466929168405153122393852178479766668792505486780351734593310079320492, 1030264944408296642185556806491437633124025784602025323877006239522425666584766787922950566607522476893455386830554318666181265558244795659553367390633368065461281537186487340676370434121708201979771321791483650758940333329922611156326460165069909758107226376956121274429040707249960854172406330587994294353, 1335896378626534116986459113203290907572858006074102489413845619865986503384086403066246181138448587861431155916589465622667329499004866346710929883867591407340148859951242422352314889562357995469976289283945444026336324649156092316269445890379712677685628144872391464438193695231700003689558464947545067862, 1733337624422861630058816559767634943911487910943519314346202359909202958359957209774602445258433905173361042937888576917072110945871100270554564438327802223819475266679080707493942230613200968395790589197363352087794570880816625087046308981864482123285598860327188020623406125595477139463653980548341669393, 1712118521984373787984190214471893185899626741865136138457076334613025444431770957054892731372950299543941807442598680965448418792367431719332565016121291887805587417326073046959962924819635595643129218281051906400369743947301197574027760510525488628454401113736351471859327651680706188693681925199887487263, 1499735939960529860036928790576639812556654726793121787648367519328260934859008521579568361171641038091567842656853405473313800616130546203262540417551043440628247542775260266483441253985140025395290342730935784277120212893520390114470744811836532151844893966210338552670399770776545942069954713172366751354, 1913607523649527314705197237356999006414033820957149969404326981075572004246375366088602616980833189335395867234004310860320300824419040902138319156508878409141834481748369822406214632656504561469132609528061013752179827379079963934388552439087369413481257942606586453435714157061142217876959859484703177907, 26534797870276653852900122929036730877138814935286353786516964807939373038909235889043220230276055509158798892611176229823627440457599507963947042723857916618002680578678158045432064576712385822197972859101120055120293609893483670245242427874608988509274231221368812818485481079452384538691805599778452564528, 2163879814490791191142637542952198904137191495088175137999784482950200139352923732282737897683289098041082685772697632200453475228184661538056464673939140597669257561521106307793756891507120965722865224017052438804843260511235759572961618156868424037244036412612217711880125692833996353284835121958890493404, 2267797909614375525177596920022706441678332927021309551762061692437948198914328107460765986576474869689782807793535342716587087883230359861578783484673165869485942694243252438709061405022590279573487469882240648498613779331593505112588177642816410319434153199783076342198162552767827391907508848457206335434, 2257873971918662586355251641685854523138098623719692377104551938617631229736984651428301172660578587083528331182055750521207663613194978599474415304848209608983919864270292827671337872078286455643654566282933694206490937840392768431053129365259113765114206135166276387468316236530006800000231209826291861813, 394228353826392440284155018623206752379851301703655698141381529417397582775642198320659388233500243975584591683636719142301324444974101655759137692947637420775809443486337083243354769811657717651468168172441758392019863595924159031443822992716153917678054285570494586890596947227541216007648902886193332045, 1340312858171251060540574107472764544434572510310285384150564143136675036273927394913038217291370145557326975629261980462070547749669063792111974018224012606560634330297287049879887776882312936149939187151451738470273674008009270272948667540728858515883248846131115317191092605091645119772730608269047361618, 2619779902953282128243808782556463430170203648957681464775952445478269257099778352730144013337891943200335585462882767390240104010467069391727419665311309494704645350127371412478143121071465675314231910213427154236157478037775541293424798959225083965741092451656020204969780065767598830666393422165676083306, 1585808686745266881665668161447359413626732092473994604224812585387873398900715405233299083720399218441383266250402142673313956965421484920085981706340554293882691270878738828946639882142942653855807423720129058519944764858050743267930455181191175813334951913635442779241748517513919704501100921077733140416, 2818129461302877093027126464636730451885368102579325558630221030887230415294829869915866092137101788362338048332271147163903350711745993438814370874454291348480865221685615864328933475128360613552133262158753117578808025052586884129775612187024993730501801946902655061721082663208174182984189344997107158750, 1054407176599413787166398792292140295757940801679843054045887733053629199922657731014478061123773877561515598540056428056503561220354303615466483445852272544243755817903159065670989035959000677838201255601373918523037864395508991250918462164851394849818466093498965213465981168413433018716771202139663336228, 1338810440859849583467944323254056262731332563952140448343236534355682429588990169650547948327093998548990270212556607458393207631044785054012839926459715577634172470071268283912521886343746137763979907723928040263845656671180203524135887394471067141940892753984934748261196469611794356291556093620778244162, 2472499912476914517399274422036557205633428334583173335296564652270378142366825998058745495516160543621597127995280514556912849068652840324321633028654677610467794632900856529494191769954356614780740431563974390141324910466161728273418144612636820742914683911827230419884786016178041942595369934975670968791, 2743686548924733730740944092306868198727468405427576785739348929998779106784831331674845961268529437794178797480350514071524096857342210851935354954327692066701718547233301490192495278552958496491674510762194923592625077348859903411489987431960772977862930716353433899302769525241793801142127919782987843255, 2574559817199801908424116008094318451838088049594702267200851759127422903511714293952238014714750752457052382141972394360952181692361422399589663194329530351195346936761837754366616179270825540992265020567857767446551449249673062177371241850026020596275177768411357378286844788747829883032947952440286351020, 2706150821408267359841777068547710009348261984503186825318970607545907141578566006827403867360014141015171247975423370455794376885219889812010844858397110342594537140647188529710784352970491346019562272647192352372120551675413538057894757032214607027654992879687604742917484317056119133742357476603853001875, 1575222739086124202848070409742501093606055299693574123527293510619898520382728501334200102949437881936442231797976105718815603116761097215345747692286535420003141586589468225962932368926432467798910201327430889664756562747656619750862228652805337862518080721003987670356250705244525422049678847324918360345, 2296899187515959856682476463368411513164435438881598932288378431928557566342457066038509873722394968012502011510386865714416050544467011808612915772490457008871651141904708931366689314018934248270214019030206585181920575656027405651330155821614772732070724413122790860776692558729027259205647521262391789431, 618120550943427568042108853048928540406977929265292788929929232302673817538717718841254184771332277674433690803062512342709882726046535423509981778933076304102089834170781341133093250230757093921679842642253202858591286467194592193096463005177846707455419911946279009074468290528936157716103446017482479494, 2339160651886900591925623314001320481479073145553725509276306736737592699671185794594354569001993336056950864571821823129519206454618724536329202239951035386788357861663854970373018424983048237571688157895622009605082095330898134475482151306114866504942723953658112098168344124301956889573038069638671649584, 1787980697494771636063550532501107133030634631988974664974878114274511623053333303192703636444818653428345753887964019505612940881649800230905993342591138724533649233729369769535041048810844018706578315680030300052049943551621170026630841326363235251829117483929241725158104348343432260896042382577829688820, 417232524642445833843022621759007851468233549329897105246515833316757168925063387485331898800350393755694412761807955173725192932454006437958359609761209304289198341844853177830754415746222657817653115246753374340963275630932785162437778654527440578826876079554917301377922692446723918683271569955366442932, 1226489912213405655462825393585268481453124851498443282263759667409965163057624770363280089714871815596458671927102222887133987147461511243720363782767703015987411863706007673819998360558875758819348917416037785505659154640681364782316505917924414689731627028282309439591838178765814370579154997589950490573, 256111103981007551621677927829150614847290304466898859214333968724310379610402472083333264703578978763839759864394945385482115951764054572839204578891682271123051926402863909504442241018004258096490921445020452850412802600910090701089006447875715092717066115688298703080167139068242520413663166172247437997, 1718245258750852164670726725851519706399409559243640348091925977305688377573217461677440183495614711049705876318403403470938246132605222655150838637757016990172276538325952737283386384020449278260953395546420360692736251080405720501888527032382109981745279859584229383699507768528391913759030379675258783988, 105943004880333425615219901114283767701285111222501951601869975713322570920808124928559708613506711289143478445291227272883771549808909408473604057062780859260674234297248476627998590151388553470525248145026184624335729337214061383853094209051557077123876926829070973097603725534471972555512401585492216313, 1898724734343173094623662462148875382445097098880752001277864245286518187958263813789429447326782932651787998184847478149724128903635881073576527363403807241028287772273848512742894401639165220611722192239823984196630998904363650165103297124148253651606192852122245968463990830486981130570543343949648112139, 2587346975779885222612311889303881203206492747880508308420612731171850299406149775439023266596164860827086419698723475567067494628491222771314678042977241305516099834266701586385092690332562368268571193475607449262234494088523126229103753634136837937825238247518713243158644237945578351670768822288563937966, 2982041317246555112019664170454157759070309038214474509651562930181281589092030966060940190658848623233065655586494541321335755593065397549889309281596581539274251811164623055592603958594868116433245094560247537917911332759480920023089651692752381003796372790674128918800696211835991097418218212283762775208, 116703490885819703040500404265324782952304908687795473326935079637396611215134894675403609519711933598746452760352967180851327435292507625901248507533663492324426703446040748392413051573100306606527311831431480790135110568664510947551072761257904891241777388261834808856928902039659188690398438757067118549, 2755792470545369426645727938300512676365665051378704840733954601949693231010297975191298544786648533669876094486417460391873642025287697696994036525998531994367091474834868572289273847172323815098220119938769618494219451120173048760931334098453337815146485640655322484484340447816159306814188466386939437679, 443002664753715531972806486205089772634968518652989474506731159534967469758026320212794178326884071398682826364159425383042562980682387350170279880348871299411597684292427178702410274926298601966944046998106907689449758464027091517805285734443165218231288449618326236983827367861763131251970826346026472351] size = 22 phi_modular = [[1000000007, 178665113], [1000000009, 220473329], [1000000021, 600707014]] phi_bits_high_128 = 0xac14e3612f4408f33f6cb42a74deba17 phi_bits_low_128 = 0x6f7e9819bf986d14ec1471514d302f40 verification_hash = 3b4da3d329e974b94561514dd5740335a4c05933723a337259c24117a13b8aba ``` Given an RSA challenge, the generator picks a large prime exponent e near two to the power of twenty-eight. It then builds a triple modulus of 1023 bits n equal to p × q × r where each factor has 341 bits. The prime p is chosen so that p − 1 is divisible by e exactly once, while q and r are chosen so that neither q − 1 nor r − 1 has e as a factor. ![chall-sc](https://hackmd.io/_uploads/Hk6hliFuex.png) ## Factoring $n$ from a Multiset of Values We are given a multiset of forty values that can be combined to reconstruct $\varphi(n)$. The approach I used is a **meet-in-the-middle attack** ([this is the paper reference](https://drops.dagstuhl.de/storage/00lipics/lipics-vol275-approx-random2023/LIPIcs.APPROX-RANDOM.2023.39/LIPIcs.APPROX-RANDOM.2023.39.pdf)). ### Meet-in-the-Middle Reconstruction of $\varphi(n)$ 1. **Split the forty values** into two halves of twenty values each. 2. For each half, compute all partial sums for every possible subset size, and for each sum store four fingerprints instead of the raw sum: the residues modulo each of three small moduli, and the low 64 bits of the sum. 3. **Join the two tables** by finding pairs of sums whose combined fingerprints match the public targets for $\varphi(n)$. This produces the candidate for $\varphi(n)$. ### Exploiting the Structure of $e$ Given that $e$ is prime, we define: $$ D = \frac{\varphi(n)}{e} $$ We then pick a random $a$ from the multiplicative group modulo $n$ and compute: $$ x = a^{D} \bmod n $$ ### Why This Works? Notice that: * $e \mid (p - 1)$ * $e \nmid (q - 1)$ and $e \nmid (r - 1)$ This means: * Raising $a$ to $D$ **wipes out** the $q$ and $r$ components (so $x \equiv 1 \ (\text{mod}\ q)$ and $x \equiv 1 \ (\text{mod}\ r)$). * However, $x \not\equiv 1 \ (\text{mod}\ p)$ in general. Therefore: $$ x - 1 \quad\text{shares the factors}\quad q \times r \quad\text{with}\quad n $$ ### Extracting the Factors We compute: $$ g = \gcd(x - 1, n) $$ With high probability, $g = q \times r$. From here: * $p = \frac{n}{g}$ * We can also confirm $p$ as the unique prime factor such that $p - 1 \mid \varphi(n)$. ### Recovering $q$ and $r$ Let: $$ n_1 = q \times r $$ $$ \varphi_1 = (q - 1)(r - 1) $$ From $\varphi_1$, we can compute: $$ S = q + r = n_1 - \varphi_1 + 1 $$ We solve the quadratic equation: $$ t^{2} - S t + n_1 = 0 $$ The two roots of this equation are $q$ and $r$. ## factorize.py ```python #!/usr/bin/env python3 from pwn import * import gmpy2 from hashlib import sha256 from math import prod import random n = 60419902565764548844188543053799539736520575597932824532389761522643875892236763090936952699801022241009608452637384156029134178007050986959672545796812659544119079405754458335003514178145056915824767178945504412120793435627631704573586996782481630193258573823429410349772037605005907442534016230552638558203 e = 268435459 c = 42077426242195692288259542826753875723706187537047968345077398360129407326191750134323576198720474598541102760396899177709744067388778715704602945081394301040443564303932191107115332093409897959823980390797003657503917523358293660420758330312005347193969217945630493348089893460949825739139342103857726182647 values = [2006121808675033655629912205539451731968788048689055659997112288437921349871706616002370887120200272996176639502330512162087050079360893814704031582967569895118118013898018846387830801348517233180122509405830333820662044128151568318688530795042907395181846553870038715532769117226055221064455551490950410774, 732828375666091792035482464097098683081812325032273526754649019175538590561093891163942860721380022094311226260495976886071736080266650350355174200287631871127070124310732575730594810294112385558803754155074092119958373224323895618603355556955287554755519430206474930206279761890888936446145908613396143934, 532889160593473743158032230072735506005255409608069924504987746744938724818092572883460758004024799244096357677865546298528380398704360328635766829721484968015359353975907368728049568484129428576888199179017490661469115249897516263106048466929168405153122393852178479766668792505486780351734593310079320492, 1030264944408296642185556806491437633124025784602025323877006239522425666584766787922950566607522476893455386830554318666181265558244795659553367390633368065461281537186487340676370434121708201979771321791483650758940333329922611156326460165069909758107226376956121274429040707249960854172406330587994294353, 1335896378626534116986459113203290907572858006074102489413845619865986503384086403066246181138448587861431155916589465622667329499004866346710929883867591407340148859951242422352314889562357995469976289283945444026336324649156092316269445890379712677685628144872391464438193695231700003689558464947545067862, 1733337624422861630058816559767634943911487910943519314346202359909202958359957209774602445258433905173361042937888576917072110945871100270554564438327802223819475266679080707493942230613200968395790589197363352087794570880816625087046308981864482123285598860327188020623406125595477139463653980548341669393, 1712118521984373787984190214471893185899626741865136138457076334613025444431770957054892731372950299543941807442598680965448418792367431719332565016121291887805587417326073046959962924819635595643129218281051906400369743947301197574027760510525488628454401113736351471859327651680706188693681925199887487263, 1499735939960529860036928790576639812556654726793121787648367519328260934859008521579568361171641038091567842656853405473313800616130546203262540417551043440628247542775260266483441253985140025395290342730935784277120212893520390114470744811836532151844893966210338552670399770776545942069954713172366751354, 1913607523649527314705197237356999006414033820957149969404326981075572004246375366088602616980833189335395867234004310860320300824419040902138319156508878409141834481748369822406214632656504561469132609528061013752179827379079963934388552439087369413481257942606586453435714157061142217876959859484703177907, 26534797870276653852900122929036730877138814935286353786516964807939373038909235889043220230276055509158798892611176229823627440457599507963947042723857916618002680578678158045432064576712385822197972859101120055120293609893483670245242427874608988509274231221368812818485481079452384538691805599778452564528, 2163879814490791191142637542952198904137191495088175137999784482950200139352923732282737897683289098041082685772697632200453475228184661538056464673939140597669257561521106307793756891507120965722865224017052438804843260511235759572961618156868424037244036412612217711880125692833996353284835121958890493404, 2267797909614375525177596920022706441678332927021309551762061692437948198914328107460765986576474869689782807793535342716587087883230359861578783484673165869485942694243252438709061405022590279573487469882240648498613779331593505112588177642816410319434153199783076342198162552767827391907508848457206335434, 2257873971918662586355251641685854523138098623719692377104551938617631229736984651428301172660578587083528331182055750521207663613194978599474415304848209608983919864270292827671337872078286455643654566282933694206490937840392768431053129365259113765114206135166276387468316236530006800000231209826291861813, 394228353826392440284155018623206752379851301703655698141381529417397582775642198320659388233500243975584591683636719142301324444974101655759137692947637420775809443486337083243354769811657717651468168172441758392019863595924159031443822992716153917678054285570494586890596947227541216007648902886193332045, 1340312858171251060540574107472764544434572510310285384150564143136675036273927394913038217291370145557326975629261980462070547749669063792111974018224012606560634330297287049879887776882312936149939187151451738470273674008009270272948667540728858515883248846131115317191092605091645119772730608269047361618, 2619779902953282128243808782556463430170203648957681464775952445478269257099778352730144013337891943200335585462882767390240104010467069391727419665311309494704645350127371412478143121071465675314231910213427154236157478037775541293424798959225083965741092451656020204969780065767598830666393422165676083306, 1585808686745266881665668161447359413626732092473994604224812585387873398900715405233299083720399218441383266250402142673313956965421484920085981706340554293882691270878738828946639882142942653855807423720129058519944764858050743267930455181191175813334951913635442779241748517513919704501100921077733140416, 2818129461302877093027126464636730451885368102579325558630221030887230415294829869915866092137101788362338048332271147163903350711745993438814370874454291348480865221685615864328933475128360613552133262158753117578808025052586884129775612187024993730501801946902655061721082663208174182984189344997107158750, 1054407176599413787166398792292140295757940801679843054045887733053629199922657731014478061123773877561515598540056428056503561220354303615466483445852272544243755817903159065670989035959000677838201255601373918523037864395508991250918462164851394849818466093498965213465981168413433018716771202139663336228, 1338810440859849583467944323254056262731332563952140448343236534355682429588990169650547948327093998548990270212556607458393207631044785054012839926459715577634172470071268283912521886343746137763979907723928040263845656671180203524135887394471067141940892753984934748261196469611794356291556093620778244162, 2472499912476914517399274422036557205633428334583173335296564652270378142366825998058745495516160543621597127995280514556912849068652840324321633028654677610467794632900856529494191769954356614780740431563974390141324910466161728273418144612636820742914683911827230419884786016178041942595369934975670968791, 2743686548924733730740944092306868198727468405427576785739348929998779106784831331674845961268529437794178797480350514071524096857342210851935354954327692066701718547233301490192495278552958496491674510762194923592625077348859903411489987431960772977862930716353433899302769525241793801142127919782987843255, 2574559817199801908424116008094318451838088049594702267200851759127422903511714293952238014714750752457052382141972394360952181692361422399589663194329530351195346936761837754366616179270825540992265020567857767446551449249673062177371241850026020596275177768411357378286844788747829883032947952440286351020, 2706150821408267359841777068547710009348261984503186825318970607545907141578566006827403867360014141015171247975423370455794376885219889812010844858397110342594537140647188529710784352970491346019562272647192352372120551675413538057894757032214607027654992879687604742917484317056119133742357476603853001875, 1575222739086124202848070409742501093606055299693574123527293510619898520382728501334200102949437881936442231797976105718815603116761097215345747692286535420003141586589468225962932368926432467798910201327430889664756562747656619750862228652805337862518080721003987670356250705244525422049678847324918360345, 2296899187515959856682476463368411513164435438881598932288378431928557566342457066038509873722394968012502011510386865714416050544467011808612915772490457008871651141904708931366689314018934248270214019030206585181920575656027405651330155821614772732070724413122790860776692558729027259205647521262391789431, 618120550943427568042108853048928540406977929265292788929929232302673817538717718841254184771332277674433690803062512342709882726046535423509981778933076304102089834170781341133093250230757093921679842642253202858591286467194592193096463005177846707455419911946279009074468290528936157716103446017482479494, 2339160651886900591925623314001320481479073145553725509276306736737592699671185794594354569001993336056950864571821823129519206454618724536329202239951035386788357861663854970373018424983048237571688157895622009605082095330898134475482151306114866504942723953658112098168344124301956889573038069638671649584, 1787980697494771636063550532501107133030634631988974664974878114274511623053333303192703636444818653428345753887964019505612940881649800230905993342591138724533649233729369769535041048810844018706578315680030300052049943551621170026630841326363235251829117483929241725158104348343432260896042382577829688820, 417232524642445833843022621759007851468233549329897105246515833316757168925063387485331898800350393755694412761807955173725192932454006437958359609761209304289198341844853177830754415746222657817653115246753374340963275630932785162437778654527440578826876079554917301377922692446723918683271569955366442932, 1226489912213405655462825393585268481453124851498443282263759667409965163057624770363280089714871815596458671927102222887133987147461511243720363782767703015987411863706007673819998360558875758819348917416037785505659154640681364782316505917924414689731627028282309439591838178765814370579154997589950490573, 256111103981007551621677927829150614847290304466898859214333968724310379610402472083333264703578978763839759864394945385482115951764054572839204578891682271123051926402863909504442241018004258096490921445020452850412802600910090701089006447875715092717066115688298703080167139068242520413663166172247437997, 1718245258750852164670726725851519706399409559243640348091925977305688377573217461677440183495614711049705876318403403470938246132605222655150838637757016990172276538325952737283386384020449278260953395546420360692736251080405720501888527032382109981745279859584229383699507768528391913759030379675258783988, 105943004880333425615219901114283767701285111222501951601869975713322570920808124928559708613506711289143478445291227272883771549808909408473604057062780859260674234297248476627998590151388553470525248145026184624335729337214061383853094209051557077123876926829070973097603725534471972555512401585492216313, 1898724734343173094623662462148875382445097098880752001277864245286518187958263813789429447326782932651787998184847478149724128903635881073576527363403807241028287772273848512742894401639165220611722192239823984196630998904363650165103297124148253651606192852122245968463990830486981130570543343949648112139, 2587346975779885222612311889303881203206492747880508308420612731171850299406149775439023266596164860827086419698723475567067494628491222771314678042977241305516099834266701586385092690332562368268571193475607449262234494088523126229103753634136837937825238247518713243158644237945578351670768822288563937966, 2982041317246555112019664170454157759070309038214474509651562930181281589092030966060940190658848623233065655586494541321335755593065397549889309281596581539274251811164623055592603958594868116433245094560247537917911332759480920023089651692752381003796372790674128918800696211835991097418218212283762775208, 116703490885819703040500404265324782952304908687795473326935079637396611215134894675403609519711933598746452760352967180851327435292507625901248507533663492324426703446040748392413051573100306606527311831431480790135110568664510947551072761257904891241777388261834808856928902039659188690398438757067118549, 2755792470545369426645727938300512676365665051378704840733954601949693231010297975191298544786648533669876094486417460391873642025287697696994036525998531994367091474834868572289273847172323815098220119938769618494219451120173048760931334098453337815146485640655322484484340447816159306814188466386939437679, 443002664753715531972806486205089772634968518652989474506731159534967469758026320212794178326884071398682826364159425383042562980682387350170279880348871299411597684292427178702410274926298601966944046998106907689449758464027091517805285734443165218231288449618326236983827367861763131251970826346026472351] size = 22 phi_mods = [[1000000007, 178665113], [1000000009, 220473329], [1000000021, 600707014]] phi_hi = int("ac14e3612f4408f33f6cb42a74deba17", 16) phi_lo = int("6f7e9819bf986d14ec1471514d302f40", 16) phi_sha = "3b4da3d329e974b94561514dd5740335a4c05933723a337259c24117a13b8aba" import random import time import math import gmpy2 from hashlib import sha256 from array import array import random def reconstruct_phi(values, size, phi_mods, phi_hi, phi_lo, phi_sha): """ Meet-in-the-middle with strong pruning: - residues modulo 3 small moduli - low 64 bits """ (m1, r1), (m2, r2), (m3, r3) = [(int(m), int(r)) for (m, r) in phi_mods] MASK64 = (1 << 64) - 1 vals = [] for v in values: v = int(v) vals.append((v, v % m1, v % m2, v % m3, v & MASK64)) half = len(vals) // 2 L, R = vals[:half], vals[half:] # mapsL[c][(m1,m2,m3,low64)] = sum mapsL = [dict() for _ in range(half + 1)] mapsL[0][(0, 0, 0, 0)] = 0 for v, vm1, vm2, vm3, vl in L: for c in range(half - 1, -1, -1): dct = mapsL[c] if not dct: continue nd = mapsL[c + 1] for (a1, a2, a3, a64), s in dct.items(): k = ((a1 + vm1) % m1, (a2 + vm2) % m2, (a3 + vm3) % m3, (a64 + vl) & MASK64) if k not in nd: nd[k] = s + v mapsR = [dict() for _ in range(len(R) + 1)] mapsR[0][(0, 0, 0, 0)] = 0 for v, vm1, vm2, vm3, vl in R: for c in range(len(R) - 1, -1, -1): dct = mapsR[c] if not dct: continue nd = mapsR[c + 1] for (a1, a2, a3, a64), s in dct.items(): k = ((a1 + vm1) % m1, (a2 + vm2) % m2, (a3 + vm3) % m3, (a64 + vl) & MASK64) if k not in nd: nd[k] = s + v # join for cR in range(0, min(len(R), size) + 1): cL = size - cR if cL < 0 or cL > half: continue left = mapsL[cL] if not left: continue right = mapsR[cR] for (b1, b2, b3, b64), sR in right.items(): need = ((r1 - b1) % m1, (r2 - b2) % m2, (r3 - b3) % m3, (phi_lo - b64) & MASK64) sL = left.get(need) if sL is None: continue phi = sL + sR return int(phi) # random-base order attack def random_base_factor(n: int, e: int, phi: int, tries: int = 32) -> int: """ Try random a in Z_n* and compute g = gcd(a^{phi/e} - 1, n). With overwhelming prob, g = q*r (nontrivial). Return g. """ D = phi // e for _ in range(tries): a = random.randrange(2, n - 1) if gmpy2.gcd(a, n) != 1: continue x = int(gmpy2.powmod(a, D, n)) g = int(gmpy2.gcd(x - 1, n)) if 1 < g < n: return g def recover_qr(n: int, p: int, phi: int): n1 = n // p phi_n1 = phi // (p - 1) # = (q-1)(r-1) S = n1 - phi_n1 + 1 # = q + r disc = S * S - 4 * n1 D = gmpy2.isqrt(disc) q = (S + D) // 2 r = (S - D) // 2 return int(q), int(r) phi = reconstruct_phi(values, size, phi_mods, phi_hi, phi_lo, phi_sha) log.info(f"φ(n) = {phi}") assert phi % e == 0, "φ(n) must be divisible by e" g = random_base_factor(n, e, phi, tries=64) cand1, cand2 = int(g), int(n // g) # p is the one with φ % (p-1) == 0 choose = [] for cand in (cand1, cand2): if 1 < cand < n and phi % (cand - 1) == 0 and gmpy2.is_prime(cand): choose.append(cand) p = int(choose[0]) q, r = recover_qr(n, p, phi) log.info(f"p = {p}") log.info(f"q = {q}") log.info(f"r = {r}") ``` ![chall-sc](https://hackmd.io/_uploads/rys1fiKdel.png) ## Recovering the Plaintext with Shumow’s Special Case After obtaining the prime factors $p, q, r$, the challenge falls under the **single affected prime** structure: * $e \mid (p - 1)$ * $e$ is coprime to $q - 1$ and $r - 1$ This matches **Shumow’s special case** ([this is the paper reference](https://eprint.iacr.org/2020/1059)), where: $$ \gcd\left( \frac{\varphi(N)}{e}, e \right) = 1 $$ $$ \varphi(N) = (p - 1)(q - 1)(r - 1) $$ --- ### Reduced Totient and Inverse Exponent We compute: $$ \tilde{\varphi} = \frac{\varphi(N)}{e} $$ and confirm $\gcd(\tilde{\varphi}, e) = 1$. Then: $$ d = e^{-1} \bmod \tilde{\varphi} $$ --- ### Roots Per Prime From the ciphertext $c$: * **Modulo $p$**: Since $e \mid (p - 1)$, the $e$-th roots are not unique: $$ a_p = c^{d} \bmod p $$ * **Modulo $q$ and $r$**: Since $e$ is coprime to $q - 1$ and $r - 1$, the $e$-th root is unique: $$ a_q = c^{e^{-1} \bmod (q - 1)} \bmod q $$ $$ a_r = c^{e^{-1} \bmod (r - 1)} \bmod r $$ --- ### Generator of Exact Order $e$ (mod $p$) Find $g_E$ such that: $$ g_E = g^{\tilde{\varphi}} \bmod p $$ with: $$ g_E^e \equiv 1 \ (\bmod\ p) \quad\text{and}\quad g_E \not\equiv 1 \ (\bmod\ p) $$ This gives a generator of the subgroup of order $e$ modulo $p$. --- ### Enumerating Candidates Given an initial exponent $i$ such that $a_p \cdot g_E^i$ is a promising candidate start point, iterate $k$ from $i$ to $e-1$: 1. Compute: $$ m_p = a_p \cdot g_E^k \bmod p $$ 2. Use **CRT** to combine: $$ m_k = \text{CRT}(m_p, a_q, a_r) $$ 3. Check if it starts with `ITSEC{}` ## Solver ```python #!/usr/bin/env python3 import math from hashlib import sha256 from tqdm import tqdm N = 60419902565764548844188543053799539736520575597932824532389761522643875892236763090936952699801022241009608452637384156029134178007050986959672545796812659544119079405754458335003514178145056915824767178945504412120793435627631704573586996782481630193258573823429410349772037605005907442534016230552638558203 e = 268435459 c = 42077426242195692288259542826753875723706187537047968345077398360129407326191750134323576198720474598541102760396899177709744067388778715704602945081394301040443564303932191107115332093409897959823980390797003657503917523358293660420758330312005347193969217945630493348089893460949825739139342103857726182647 p = 4466054086694205224060229493741618510822562767362299820045196957222381007815796096595501338871401718569 q = 4230817059039673574688898677053507572161261199083369921571579034080470278052948429785264270802981855581 r = 3197656400540271876542568319421192210490384740990543931526314714177621097079511045918579371468320101727 phi = 60419902565764548844188543053799539736520575597932824532389761522643875892236763090936952699801022240962903789136974518188761097556289389575127026002954879057305475324383545234245465589206481151570914285906250106656186512023735391121198807841933514848680339770734949294557341480916358076784744828741530693440 def crt3(mp, mq, mr, p, q, r): N = p*q*r Np, Nq, Nr = N//p, N//q, N//r return (mp*pow(Np,-1,p)*Np + mq*pow(Nq,-1,q)*Nq + mr*pow(Nr,-1,r)*Nr) % N phi = (p-1)*(q-1)*(r-1) phi_red = phi // e assert phi % e == 0 and math.gcd(phi_red, e) == 1 # find element of exact order e mod p g = 1 while True: g += 1 gE_p = pow(g, phi_red, p) if gE_p != 1 and pow(gE_p, e, p) == 1: break # roots per-prime d = pow(e, -1, phi_red) # inverse modulo phi/e a_p = pow(c, d, p) # one of the e roots mod p a_q = pow(c, pow(e, -1, q-1), q) # unique root mod q a_r = pow(c, pow(e, -1, r-1), r) # unique root mod r # i = 1 (initial) i = 246_492_539 # sekitar 28 menit dapet i yang memenuhi gi_p = pow(gE_p, i, p) bar = tqdm(range(i, e), total=e-i, desc="Shumow Attack", dynamic_ncols=True, leave=False) for k in bar: mp = (a_p * gi_p) % p cand = crt3(mp, a_q, a_r, p, q, r) s = cand.to_bytes((cand.bit_length()+7)//8, "big") if s.startswith(b"ITSEC{"): print(s) break gi_p = (gi_p * gE_p) % p ``` ![chall-sc](https://hackmd.io/_uploads/rJYqEiFdgx.png)