diff --git a/2021/corctf/4096/README.md b/2021/corctf/4096/README.md new file mode 100644 index 0000000..bfe5daf --- /dev/null +++ b/2021/corctf/4096/README.md @@ -0,0 +1,88 @@ +# 4096 + +by [haskal](https://awoo.systems) + +crypto / 360 pts / 219 solves + +>I heard 4096 bit RSA is secure, so I encrypted the flag with it. + +provided files: [source.py](source.py) [output.txt](output.txt) + +## solution + +inspecting the source you can see the provided source implements RSA. the weakness is it uses many +small primes instead of 2 large primes. this makes it extremely easy to factor the number +(factoring the public key in RSA leads to recovery of the private key)[^1] + +```python +m = bytes_to_long(flag) +primes = [getPrime(32) for _ in range(128)] +n = prod(primes) +e = 65537 +print(n) +print(pow(m, e, n)) +``` + +i turned to my trusted factoring tool, [yafu](https://sourceforge.net/projects/yafu/) and _quickly_ +discovered that in 2021 yafu is very crashy (at least on my system... i assume this is some glibc or +gmp ABI incompatibility)[^2] + +yafu provides a shell in which you can invoke the `factor` operation +``` +factor(50630448182626893495....) +``` + +this should complete in a few seconds even on old machines. it produces a list like +``` +... +P10 = 3991834969 +P38 = 66683226414537879762507759703783429499 +C20 = 15613277632742914627 +P10 = 3959814431 +P10 = 3943871257 +P10 = 2602521199 +P10 = 3177943303 +P10 = 3625437121 +P10 = 2707095227 +P10 = 3346647649 +P10 = 2572542211 +P10 = 2753147143 +P10 = 3488338697 +P10 = 2525697263 +P10 = 3291377941 +P10 = 4141964923 +... +``` + +some of the output was not factored enough, there are still some composite numbers and incorrectly +identified primes -- we know from the source that all the primes are 32 bit so we're looking for all +`P10` lines. the solution is simple just run `factor(...)` again on any non-P10 outputs... and this +is where i wrote a quick script to do this automatically except for some reason yafu consistently +crashed when run under python (;___;) so i ended up doing it by hand (time wasted that could be +spent pwning but whatever) + +anyway once you have all the primes you just need to calculate the private key and do decryption. +the private key is computed by `65537^{-1} mod phi`, where `phi` (the easier one to calculate) is +the product of all the primes minus 1. then do `{encrypted message}^d mod n` and you have the flag + +```python +[ins] In [1]: import math + +[nav] In [2]: factors = [int(x) for x in open("factors")] + +[nav] In [3]: phi = math.prod([x - 1 for x in factors]) + +[nav] In [4]: [n, enc] = [int(x) for x in open("output.txt")] + +[ins] In [5]: d = pow(65537, -1, phi) + +[ins] In [6]: dec = pow(enc, d, n) + +[ins] In [7]: dec.to_bytes(dec.bit_length()//8+1,"big") +Out[8]: b'corctf{to0_m4ny_pr1m3s55_63aeea37a6b3b22f}' +``` + +[^1]: i assume we are familiar with RSA but if not, wikipedia is a good reference: + + +[^2]: time to get a new factoring tool of choice probably diff --git a/2021/corctf/4096/output.txt b/2021/corctf/4096/output.txt new file mode 100644 index 0000000..62c7888 --- /dev/null +++ b/2021/corctf/4096/output.txt @@ -0,0 +1,2 @@ +50630448182626893495464810670525602771527685838257974610483435332349728792396826591558947027657819590790590829841808151825744184405725893984330719835572507419517069974612006826542638447886105625739026433810851259760829112944769101557865474935245672310638931107468523492780934936765177674292815155262435831801499197874311121773797041186075024766460977392150443756520782067581277504082923534736776769428755807994035936082391356053079235986552374148782993815118221184577434597115748782910244569004818550079464590913826457003648367784164127206743005342001738754989548942975587267990706541155643222851974488533666334645686774107285018775831028090338485586011974337654011592698463713316522811656340001557779270632991105803230612916547576906583473846558419296181503108603192226769399675726201078322763163049259981181392937623116600712403297821389573627700886912737873588300406211047759637045071918185425658854059386338495534747471846997768166929630988406668430381834420429162324755162023168406793544828390933856260762963763336528787421503582319435368755435181752783296341241853932276334886271511786779019664786845658323166852266264286516275919963650402345264649287569303300048733672208950281055894539145902913252578285197293 +15640629897212089539145769625632189125456455778939633021487666539864477884226491831177051620671080345905237001384943044362508550274499601386018436774667054082051013986880044122234840762034425906802733285008515019104201964058459074727958015931524254616901569333808897189148422139163755426336008738228206905929505993240834181441728434782721945966055987934053102520300610949003828413057299830995512963516437591775582556040505553674525293788223483574494286570201177694289787659662521910225641898762643794474678297891552856073420478752076393386273627970575228665003851968484998550564390747988844710818619836079384152470450659391941581654509659766292902961171668168368723759124230712832393447719252348647172524453163783833358048230752476923663730556409340711188698221222770394308685941050292404627088273158846156984693358388590950279445736394513497524120008211955634017212917792675498853686681402944487402749561864649175474956913910853930952329280207751998559039169086898605565528308806524495500398924972480453453358088625940892246551961178561037313833306804342494449584581485895266308393917067830433039476096285467849735814999851855709235986958845331235439845410800486470278105793922000390078444089105955677711315740050638 diff --git a/2021/corctf/4096/source.py b/2021/corctf/4096/source.py new file mode 100644 index 0000000..996dc27 --- /dev/null +++ b/2021/corctf/4096/source.py @@ -0,0 +1,15 @@ +from Crypto.Util.number import getPrime, bytes_to_long +from private import flag + +def prod(lst): + ret = 1 + for num in lst: + ret *= num + return ret + +m = bytes_to_long(flag) +primes = [getPrime(32) for _ in range(128)] +n = prod(primes) +e = 65537 +print(n) +print(pow(m, e, n)) \ No newline at end of file