diff --git a/2021/corctf/dividing_secrets/README.md b/2021/corctf/dividing_secrets/README.md new file mode 100644 index 0000000..064b942 --- /dev/null +++ b/2021/corctf/dividing_secrets/README.md @@ -0,0 +1,63 @@ +# dividing\_secrets + +by [haskal](https://awoo.systems) + +crypto / 434 pts / 121 solves + +>I won't give you the secret. But, I'll let you divide it. +> +>`nc crypto.be.ax 6000` + +provided files: [server.py](server.py) + +## solution + +inspecting the server script... it seems to be using a 512 bit prime `p` and taking a random number +`g` to the power of the secret flag message `x` mod `p`. in order to crack this you'd need to come +up with an efficient solution for the [Discrete Log +Problem](https://en.wikipedia.org/wiki/Discrete_logarithm#Algorithms) + +luckily, the server also lets you divide the exponent by an arbitrary input number up to 64 times +(that's `512/8` for those who are paying attention, which suggests taking a character-by-character +approach). the exploit concept is to use the division to shift `x` all the way to 8 bits, then try +to guess what those 8 bits are by trying all 256 possible values. then, once that is known, move on +to the next 8 bits using the known segment and combining it with another round of 256 guesses + +it looks kinda like this + +```python +# start by doing x >> 504 +# (this is the same as x / (2**504)) +position = 504 +top_bits = 0 + +while True: + # send off the next guess + r.recvuntil("number> ") + r.sendline(str(2**position)) + h = int(r.recvline().decode()) + # guess every possible character + for i in range(256): + if pow(g, (top_bits << 8) | i, p) == h: + # once it is found, move on + sys.stdout.write(chr(i)) + top_bits = (top_bits << 8) | i + position -= 8 + break +``` + +running the `exploit.py` script should produce + +``` +[+] Opening connection to crypto.be.ax on port 6000: Done +g 3163314640353309966974084350140065528835797402483351605270276213160985733919488025191658477221550585332241782718778635951464919000972247044376608291073497 +p 9937890065686116796205186685937536971919686769106263396090623316690565375989826956720662974087853527508968612312091794142094431426690835778526649323968253 +enc 5829222177042077791091257368279368382423357539393247444397252396260207162571334610710294330374985463989052071335431112395334343144642068220012344459731980 +corctf{qu4drat1c_r3s1due_0r_n0t_1s_7h3_qu3st1on8852042051e57492}[*] Closed connection to crypto.be.ax port 6000 +Traceback (most recent call last): +..... +... + File "/usr/lib/python3.9/site-packages/pwnlib/tubes/sock.py", line 58, in recv_raw + raise EOFError +EOFError +``` diff --git a/2021/corctf/dividing_secrets/exploit.py b/2021/corctf/dividing_secrets/exploit.py new file mode 100644 index 0000000..8d7c84b --- /dev/null +++ b/2021/corctf/dividing_secrets/exploit.py @@ -0,0 +1,35 @@ +from pwn import * + +from math import ceil, sqrt +import sys + +def run(): + r = remote("crypto.be.ax", 6000) + try: + g = int(r.recvline().decode().split(":")[1]) + print("g", g) + p = int(r.recvline().decode().split(":")[1]) + print("p", p) + enc = int(r.recvline().decode().split(":")[1]) + print("enc", enc) + + position = 504 + top_bits = 0 + + while True: + r.recvuntil("number> ") + r.sendline(str(2**position)) + h = int(r.recvline().decode()) + for i in range(256): + if pow(g, (top_bits << 8) | i, p) == h: + sys.stdout.write(chr(i)) + top_bits = (top_bits << 8) | i + position -= 8 + break + else: + raise Exception('char not found') + finally: + r.close() + +if __name__ == "__main__": + run() diff --git a/2021/corctf/dividing_secrets/server.py b/2021/corctf/dividing_secrets/server.py new file mode 100644 index 0000000..c425ece --- /dev/null +++ b/2021/corctf/dividing_secrets/server.py @@ -0,0 +1,31 @@ +from Crypto.Util.number import bytes_to_long, getStrongPrime +from random import randrange +from secret import flag + +LIMIT = 64 + +def gen(): + p = getStrongPrime(512) + g = randrange(1, p) + return g, p + +def main(): + g, p = gen() + print("g:", str(g)) + print("p:", str(p)) + x = bytes_to_long(flag) + enc = pow(g, x, p) + print("encrypted flag:", str(enc)) + ctr = 0 + while ctr < LIMIT: + try: + div = int(input("give me a number> ")) + print(pow(g, x // div, p)) + ctr += 1 + except: + print("whoops..") + return + print("no more tries left... bye") + +main() +