2023 corCTF - fizzbuzz100
Overview
- 134 solves/121 points
- author: wwm
Description
lsb oracles are pretty overdone… anyway here’s fizzbuzz
nc be.ax 31100
Attached
#!/usr/local/bin/python
from Crypto.Util.number import *
from os import urandom
flag = open("flag.txt", "rb").read()
flag = bytes_to_long(urandom(16) + flag + urandom(16))
p = getPrime(512)
q = getPrime(512)
n = p * q
e = 0x10001
d = pow(e, -1, (p-1)*(q-1))
assert flag < n
ct = pow(flag, e, n)
print(f"{n = }")
print(f"{e = }")
print(f"{ct = }")
while True:
ct = int(input("> "))
pt = pow(ct, d, n)
out = ""
if pt == flag:
exit(-1)
if pt % 3 == 0:
out += "Fizz"
if pt % 5 == 0:
out += "Buzz"
if not out:
out = pt
print(out)
Analyzation
When receiving value x
, the server returns x^d (mod n)
.
So if we send ct * r^e (mod n)
, the server will return (ct * r^e)^d (mod n)
, which equals to flag * r (mod n)
. Just multiply pow(r, -1, n)
and the flag will be yours.
Remember that r
must not be divisible by 3 and 5, and r
is invertible in mod n
.
Solution
from pwn import *
server = remote("be.ax", 31100)
server.recvuntil("n = ")
n = int(server.recvline())
server.recvuntil("e = ")
e = int(server.recvline())
server.recvuntil("ct = ")
ct = int(server.recvline())
r = 2 # make sure r is invertible
to_send = (pow(r, e, n) * (ct % n) ) % n
server.sendline(str(to_send))
server.recvuntil("> ")
flag_r = int(server.recvline())
from Crypto.Util.number import *
flag = flag_r * pow(r, -1, n) % n
print(long_to_bytes(flag)[16:-16])
The flag is
corctf{h4ng_0n_th15_1s_3v3n_34s13r_th4n_4n_LSB_0r4cl3...4nyw4y_1snt_f1zzbuzz_s0_fun}