# CryptoCTF 2024 > Author:堇姬 > Rank: 29th # Warm-up 🤑 ## Welcome! 👋 Crtl+c Crtl+v > CCTF{Harn3sS_Y0ur_CrYptO9rAphy_Pr0wEs5_💪_⚡_💥_🔥!} # Easy 😁 ## Alibos ### source code ```python= from Crypto.Util.number import * from gmpy2 import * from secret import d, flag get_context().precision = 1337 def pad(m, d): if len(str(m)) < d: m = str(m) + '1' * (d - len(str(m))) return int(m) def genkey(d): skey = getRandomRange(10 ** (d - 1), 10 ** d) pkey = int(10**d * (sqrt(skey) - floor(sqrt(skey)))) return pkey, skey def encrypt(m, pkey): m = pad(m, len(str(pkey))) d = len(str(pkey)) c = (pkey + d ** 2 * m) % (10 ** d) return c pkey, skey = genkey(d) m = bytes_to_long(flag) c = encrypt(m, pkey) print(f'pkey = {pkey}') print(f'enc = {c}') ``` ### output.txt ``` pkey = 8582435512564229286688465405009040056856016872134514945016805951785759509953023638490767572236748566493023965794194297026085882082781147026501124183913218900918532638964014591302221504335115379744625749001902791287122243760312557423006862735120339132655680911213722073949690947638446354528576541717311700749946777 enc = 6314597738211377086770535291073179315279171595861180001679392971498929017818237394074266448467963648845725270238638741470530326527225591470945568628357663345362977083408459035746665948779559824189070193446347235731566688204757001867451307179564783577100125355658166518394135392082890798973020986161756145194380336 ``` ### 分析 給了你 $pkey、c$ $d=len(str(pkey))$ $c = (pkey + d^2 \times m) \pmod {10^d}$ $(c-pkey) \times inv(d^2) = m \pmod {10^d}$ 簡單的移項,直接計算就可以了(要注意右邊他pad了很多的1要刪掉) ```python def pad(m, d): if len(str(m)) < d: m = str(m) + '1' * (d - len(str(m))) return int(m) ``` ### script ```python= from Crypto.Util.number import * pkey = 8582435512564229286688465405009040056856016872134514945016805951785759509953023638490767572236748566493023965794194297026085882082781147026501124183913218900918532638964014591302221504335115379744625749001902791287122243760312557423006862735120339132655680911213722073949690947638446354528576541717311700749946777 enc = 6314597738211377086770535291073179315279171595861180001679392971498929017818237394074266448467963648845725270238638741470530326527225591470945568628357663345362977083408459035746665948779559824189070193446347235731566688204757001867451307179564783577100125355658166518394135392082890798973020986161756145194380336 d = len(str(pkey)) m=((enc-pkey)*pow(d,-2,10**d))%(10**d) print(int(str(m))) #6170704326493336128242608193100736601774626903966803036318189045381903593682775829229200905376968543264526051111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 print(long_to_bytes(617070432649333612824260819310073660177462690396680303631818904538190359368277582922920090537696854326452605)) ``` > CCTF{h0M3_m4De_cRyp70_5ySTeM_1N_CryptoCTF!!!} ## Mashy ### source code ```python= #!/usr/bin/env python3 import sys from hashlib import md5 from binascii import * from secret import salt, flag def die(*args): pr(*args) quit() def pr(*args): s = " ".join(map(str, args)) sys.stdout.write(s + "\n") sys.stdout.flush() def sc(): return sys.stdin.buffer.readline() def xor(s1, s2): return bytes([s1[_] ^ s2[_] for _ in range(len(s1))]) def main(): border = "┃" pr( "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓") pr(border, ".: Hi all, she did Mashy, you should do it too! Are you ready? :. ", border) pr( "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛") REC = [] cnt, STEP = 0, 7 sh = md5(salt).digest() while True: pr(border, f'Please send your first input: ') d1 = sc().strip() pr(border, f'Please send your second input: ') d2 = sc().strip() try: d1 = hexlify(unhexlify(d1)) d2 = hexlify(unhexlify(d2)) h1 = md5(unhexlify(d1)).digest() h2 = md5(unhexlify(d2)).digest() except: die(border, 'Your inputs are not valid! Bye!!!') if d1 != d2 and d1 not in REC and d2 not in REC: if md5(xor(d1, d2)).hexdigest() != 'ae09d7510659ca40eda3e45ca70e9606': if hexlify(xor(xor(h1, h2), sh)) == b'a483b30944cbf762d4a3afc154aad825': REC += [d1, d2] if cnt == STEP: die(border, f'Congrats! the flag: {flag}') pr(border, 'Good job, try next level :P') cnt += 1 else: die(border, 'Your input is not correct! Bye!') else: die(border, 'No this one! Sorry!!') else: die(border, 'Kidding me!? Bye!!') if __name__ == '__main__': main() ``` ### 分析 輸入八組的 $d_1、d_2$ 要求 $md5(d_1 ⊕ d_2)\ne ae09d7510659ca40eda3e45ca70e9606$ 並且 $md5(x1) ⊕ md5(x2) ⊕ md5(salt) = a483b30944cbf762d4a3afc154aad825$ ``` a483b30944cbf762d4a3afc154aad825 -> emelinjulca ``` 當下還真沒看出來這要怎麼解,後來才知道 $md5(salt) = a483b30944cbf762d4a3afc154aad825$,所以就只是要找八組碰撞的來解... ### 解法 https://github.com/cr-marcstevens/hashclash 直接拿八組送就可以了 > CCTF{mD5_h4Sh_cOlL!Si0N_CrYp7o_ch41lEnGe!!!} # Medium 🤔 ## Bada ``` ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ Hey! It's time to solve the equation of a function f: N x N -> Z. ┃ ┃ Function f has given certain conditions. In each step, solve the ┃ ┃ equation f(x, y) = z with the given value of z. We know f(a+1, b) = ┃ ┃ f(a, b) + a, and f(a, b+1) = f(a, b) - b, for every `a' and `b'. ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┃ We know: f(1, 1) = 394111134899 and f(x, y) = 1085928033286 ┃ Please send x, y separated by comma: ``` ### 分析 $f(x, y) = z$ 對所有a b滿足 $f(a+1, b) = f(a, b) + a$ $f(a, b+1) = f(a, b) - b$ 給定 $f(1,1)跟f(x,y)$,要求x跟y 這題其實很簡單, $t=f(x,y)-f(1,1)$ $x=t+1$ $y=t$ 因為我們可以知道 $f(x,y)=f(1,1)+(1+2+...+x-1)-(1+2+...+y-1)$ 如果設成這樣可以得 $f(x,y)=f(1,1)+(1+2+...+t)-(1+2+...+t-1)$ $f(x,y)-f(1,1)=t$ 得證 ### script ```python= from pwn import * r=remote('01.cr.yp.toc.tf', 17113) r.recvlines(6) for i in range(100): a=r.recvline().split() print(a) n1=int(a[6].decode()) n2=int(a[11].decode()) m=n2-n1 print(m) r.sendlineafter(b'Please send x, y separated by comma: ',f'{m+1},{m}'.encode()) r.recvlines(2) r.interactive() ``` > CCTF{BADA_iZ_4_K0r3An_5!ngeR!!} ## RM2 ### source code ```python= import sys from Crypto.Util.number import * from string import * from random import * from flag import flag def die(*args): pr(*args) quit() def pr(*args): s = " ".join(map(str, args)) sys.stdout.write(s + "\n") sys.stdout.flush() def sc(): return sys.stdin.buffer.readline() def randstr(l): return ''.join([printable[randint(0, 90)] for _ in range(l)]) def encrypt(msg, p, q): e = 65537 m1, m2 = msg[:len(msg) >> 1], msg[len(msg) >> 1:] m1, m2 = bytes_to_long(m1), bytes_to_long(m2) c1, c2 = pow(m1, e, (p - 1) * (q - 1)), pow(m2, e, (2*p + 1) * (2*q + 1)) return (c1, c2) def main(): border = "┃" pr( "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓") pr(border, ".: Welcome to RM2 task! Your mission is break our cryptosystem :. ", border) pr( "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛") nbit, _b = 1024, False pr(border, f"Please provide your desired {nbit}-bit prime numbers p, q:") inp = sc().decode() try: p, q = [int(_) for _ in inp.split(',')] if p.bit_length() == q.bit_length() == nbit and isPrime(p) and isPrime(q) and p != q: _b = True except: die(border, f"The input you provided is is not valid!") if _b: e, n = 65537, p * q s = randstr(nbit >> 4).encode() m = bytes_to_long(s) assert m < n >> 2 c1, c2 = encrypt(s, p, q) pr(border, f'c1 = {c1}') pr(border, f'c2 = {c2}') pr(border, f'Now, send us the secret string to get the flag: ') _m = sc().strip() if _m == s: die(border, f'Congrats, you got the flag: {flag}') else: die(border, f'The secret string is not correct! Bye!!') else: die(border, f"Your input does not meet the requirements!!!") if __name__ == '__main__': main() ``` ### 流程 我們需要先輸入一組`(p,q)` 1024 bits的質數。 $e = 65537$ $n = p \times q$ 並產生了一個64 bytes 隨機字串,並拆成兩半m1、m2,來做加密 $C_1={m_1}^e \pmod {(p-1)(q-1)}$ $C_2={m_2}^e \pmod {(2p+1)(2q+1)}$ 印出 $C_1、C_2$ 給你,如果你能提交正確的m,就可以拿到flag ### 分析 一開始使用getprime來隨機生成質數,當你把產生的`p-1`、`q-1`、`2p+1`、`2q+1`丟入factorDB是沒辦法全部分解的。 仔細分析後可以採用一個策略: 如果`(p-1)/2`和`(q-1)/2`是個質數,模數可以分解為`2*2*((p-1)/2)*((q-1)/2)`,那可以發現`p、q`是個safe prime。 因為`p=2k+1`、`q=2k+1`,這裡`k`是個質數 另外有個東西叫做Sophie Germain prime就滿足後面的`p`是個質數,`2p+1`是個質數 https://en.wikipedia.org/wiki/Safe_and_Sophie_Germain_primes 總之這題就是要找到同時滿足他是safe prime又是Sophie Germain prime 所以可以先生成safe prime再看看他是不是Sophie Germain prime 報錯可以看 https://blog.csdn.net/kulala082/article/details/68484314 ```python= import gensafeprime from Crypto.Util.number import * while True: a=gensafeprime.generate(1024) if(isPrime(2*a+1)): print(a) ``` 找到 ``` 179038869479476343977624700131648035601030062609971358083068495264644773504891672033533628862180996104202480213255611201971674539999191838522787167917937277791863007890816459071795930442010669455816651153734397964768807485960692876685651034343992232617890851248047651749184487885382752475267482617769156174759 152626939093408062491455965189078085895710089466647132413566213985550098559310878828326396205570489809521107684567398503589855307057076999293252855393269557521587237138401310097549911211946862768385413685627911058536556141489179850863603684246330469754375715654686482993778608649026542257474853574317156591723 ``` 找到後直接搞就行了 ### script ```python= from Crypto.Util.number import * import gmpy2 p=179038869479476343977624700131648035601030062609971358083068495264644773504891672033533628862180996104202480213255611201971674539999191838522787167917937277791863007890816459071795930442010669455816651153734397964768807485960692876685651034343992232617890851248047651749184487885382752475267482617769156174759 q=152626939093408062491455965189078085895710089466647132413566213985550098559310878828326396205570489809521107684567398503589855307057076999293252855393269557521587237138401310097549911211946862768385413685627911058536556141489179850863603684246330469754375715654686482993778608649026542257474853574317156591723 e=65537 p1=(p-1)//2 q1=(q-1)//2 d1=gmpy2.invert(e,(p1-1)*(q1-1)) p2=2*p+1 q2=2*q+1 d2=gmpy2.invert(e,(p2-1)*(q2-1)) #填入他輸出的cipher c1 = 21151742531993710573547425710897641927865431812251870367074974615476947196023818990937531773721159817831540568326430012771017029204594858269615447374733393822719585019585152715616197619193913161508325323839747240362129247645941345454286273602633894772910487947675430526030392912094071192182218560002280246667719201806989032579217004398478404090393023045039212545353542372800473861051345217645271812032186457308143485566373819952733316934166884288561219139097503424061053231093875547232358595532171506731349688703159272518561988896741004483822812740400298954300908353976564035378839236849325436452912994141172684017111 c2 = 62818183008146329276409056323055998354752395300349878829271733651648571584856579955406068012482976250828090842810182898608457729894893815602684355086134126669218213205573891105258191447501061485257311674410706802749496991308792653037584070607980150860459775608776599334891419227439681465071717929183819653616572164900010542536129620906931790306808081402185470322959323706416193282801532918045577387102395289413100245487590409835139147487248899300717713713205000590198945159560687851165611513865142445942256258211044243177734485934949356680940836049836877050416783354434003664343258794638147445260137578779031632214093 m1=pow(c1,d1,2*2*p1*q1) m2=pow(c2,d2,p2*q2) print((long_to_bytes(m1) + long_to_bytes(m2)).decode()) ``` ``` ┃ Now, send us the secret string to get the flag: @:PG;RVp&o4Hm9];Hj;U9cZb'Y'DaU(+io%vn,=I3)Kpl.tj@C'xfK(CJ)Rfdj7c ┃ Congrats, you got the flag: b'CCTF{i_l0v3_5UpeR_S4fE_Pr1m3s!!}' ``` > CCTF{i_l0v3_5UpeR_S4fE_Pr1m3s!!} ## JOE-19 ### source code ```python= #!/usr/bin/env sage from GPT import GPT6 # deep fake from Crypto.Util.number import * from flag import flag P = [GPT6('A 512-bit prime appears in consecutive digits of e') for _ in range(4)] n, m = prod(P), bytes_to_long(flag) c = pow(m, 0x10001, n) print(f'n = {n}') print(f'c = {c}') ``` ### output.txt ``` n = 8098851734937207931222242323719278262039311278408396153102939840336549151541408692581651429325092535316359074019383926520363453725271849258924996783681725111665666420297112252565291898169877088446887149672943461236879128453847442584868198963005276340812322871768679441501282681171263391133217373094824601748838255306528243603493400515452224778867670063040337191204276832576625227337670689681430055765023322478267339944312535862682499007423158988134472889946113994555274385595499503495488202251032898470224056637967019786473820952632846823442509236976892995505554046850101313269847925347047514591030406052185186963433 c = 7109666883988892105091816608945789114105575520302872143453259352879355990908149124303310269223886289484842913063773914475282456079383409262649058768777227206800315566373109284537693635270488429501591721126853086090237488579840160957328710017268493911400151764046320861154478494943928510792105098343926542515526432005970840321142196894715037239909959538873866099850417570975505565638622448664580282210383639403173773002795595142150433695880167315674091756597784809792396452578104130341085213443116999368555639128246707794076354522200892568943534878523445909591352323861659891882091917178199085781803940677425823784662 ``` ### 分析 想法就是直接枚舉,512bits大概是154、155 digits。 ```python= from sage.all import e, is_prime n = 8098851734937207931222242323719278262039311278408396153102939840336549151541408692581651429325092535316359074019383926520363453725271849258924996783681725111665666420297112252565291898169877088446887149672943461236879128453847442584868198963005276340812322871768679441501282681171263391133217373094824601748838255306528243603493400515452224778867670063040337191204276832576625227337670689681430055765023322478267339944312535862682499007423158988134472889946113994555274385595499503495488202251032898470224056637967019786473820952632846823442509236976892995505554046850101313269847925347047514591030406052185186963433 e_str = str(e.n(digits=100100)) def find_prime_in_e(length): for i in range(len(e_str) - length): num_str = e_str[i:i+length] if num_str.isdigit(): num = int(num_str) if is_prime(num) and n % num == 0: print(num) return None find_prime_in_e(154) ``` 輸出了,找到一個,接下來就一直枚舉,拿到四個就解了(上面的腳本要在微調成155,才可以拿到其他的) ``` 7728751393377105569802455757436190501772466214587592374418657530064998056688376964229825501195065837843125232135309371235243969149662310110328243570065781 9688632098638681429535439991332657144752666147923336383829750592576742104399942931057096761773496510622226977570278994077236841491368959008277469453600569 ``` ```python= from Crypto.Util.number import * p=7728751393377105569802455757436190501772466214587592374418657530064998056688376964229825501195065837843125232135309371235243969149662310110328243570065781 q=9688632098638681429535439991332657144752666147923336383829750592576742104399942931057096761773496510622226977570278994077236841491368959008277469453600569 r=10019005372961705640183251650710051163228093250949727357306333102512304273058618645339800283588040423877666492199352609508401454089083503146788384653241593 s=10795109107229646654467923653403055635071360620150038008453082390943756377071343139771120080956310498862485323957447467376538994662280143050510681877597429 d=inverse_mod(65537,(p-1)*(q-1)*(r-1)*(s-1)) long_to_bytes(pow(c,d,n)).decode() ``` ### 非預期解 這題的n在賽中後來可以用factorDB直接分解 > CCTF{ASIS_h1r3_7aL3nT5_t0_cO1La8orAt3_!N_Crypto_CTF!} ## Nazdone ### source code ```python= #!/usr/bin/env python3 from Crypto.Util.number import * from random import * from secret import params, flag def sol(m, a, z): p = m * (a - 1) % 2 + 1 while True: R = list(range(1, a)) shuffle(R) for r in R[:z]: p += getRandomRange(0, 2) * m ** r if isPrime(p): return p else: p = m * (a - 1) % 2 + 1 p, q, r = [sol(*params) for _ in '007'] n = p * q * r m = bytes_to_long(flag) c = pow(m, params[0] ** 3 + params[2] - 2, n) print(f'n = {n}') print(f'c = {c}') ``` ### output.txt ``` n = 301929748923678449872944933611657670834216889867340028357609265175830693931365828840717548752313862343315133541384709574659039910206634528428504034051556622114290811586746168354731258756502196637977942743110508997919976400864419640496894428180120687863921269087080600917900477624095004141559042793509244689248253036809126205146653922738685595903222471152317095497914809983689734189245440774658145462867680027337 c = 104375152140523502741159687674899095271676058870899569351687154311685938980840028326701029233383897490722759532494438442871187152038720886122756131781086198384270569105043114469786514257765392820254951665751573388426239366215033932234329514161827069071792449190823827669673064646681779764841034307000600929149689291216313319444583032339045277433847691961234044840927155960887984372868669401051358701522484473320 ``` ### 分析 未知的三個param -> $m、a、z$ $n=p \times q \times r$ $e=m^3+z-2$ $p、q、r$ 為三個質數 生成方式為: 有一個初始化的陣列 $R=[1、2、3、...、a]$ 並把他打亂 $R=[R_0、R_1、R_2、...、R_{a-1}]$ ```python= R = list(range(1, a)) shuffle(R) ``` 之後以以下方式產生 $p、q、r= \displaystyle\sum_{i=0}^z b_i \times m^i$, $b_i \in (0, 1)$ ```python= for r in R[:z]: p += getRandomRange(0, 2) * m ** r ``` 也就是構造一個多項式 $f(x)=b_0+b_1 \times x+b_2 \times x^2+...+b_z \times x^z$ $p、q、r=f(m)$