ふるつき

v(*'='*)v かに

watevrCTF writeup

I played wateverCTF as a member of zer0pts. Luckily, my teammates are awesome. We reached 3rd place at the end of the competition!

f:id:Furutsuki:20191216100158p:plain

The scoreboard is pretty cool. And the infrastructure is so good. Moreover, there are very cool challenges. Thanks to all the admins!

[Crypto] Swedish RSA

Also known as Polynomial RSA. This is just some abstract algebra for fun!

We got the following script and its result.

flag = bytearray(raw_input())
flag = list(flag)
length = len(flag)
bits = 16

## Prime for Finite Field.
p = random_prime(2^bits-1, False, 2^(bits-1))

file_out = open("downloads/polynomial_rsa.txt", "w")
file_out.write("Prime: " + str(p) + "\n")

## Univariate Polynomial Ring in y over Finite Field of size p
R.<y> = PolynomialRing(GF(p))

## Analogous to the primes in Z
def gen_irreducable_poly(deg):
    while True:
        out = R.random_element(degree=deg)
        if out.is_irreducible():
            return out


## Polynomial "primes"
P = gen_irreducable_poly(ZZ.random_element(length, 2*length))
Q = gen_irreducable_poly(ZZ.random_element(length, 2*length))

## Public exponent key
e = 65537

## Modulus
N = P*Q
file_out.write("Modulus: " + str(N) + "\n")

## Univariate Quotient Polynomial Ring in x over Finite Field of size 659 with modulus N(x)
S.<x> = R.quotient(N)

## Encrypt
m = S(flag)
c = m^e

file_out.write("Ciphertext: " + str(c))
file_out.close()

Irreducible monic polynomials over the polynomial ring are the same as prime numbers over the integer. So RSA can be constructed on the polynomial ring. Thus same approach is available.

Fortunately (and I don't know why), the given N was factorized easily. Then just do it!

p = 43753
PR.<y> = PolynomialRing(GF(p))

_, N, C = open("polynomial_rsa.txt").read().split("\n")

N = sage_eval(N.split(":")[1], locals=vars())

(P, _), ( Q, _ ) = N.factor()
n, m = P.degree(), Q.degree()
e = 65537
s = (p^n - 1)*(p^m - 1)
d = inverse_mod(e, s)

S.<x> = PR.quotient(N)
C = sage_eval(C.split(":")[1], locals=vars())

M = C^d
print("".join([chr(c) for c in M.list()]))

watevr{RSA_from_ikea_is_fun_but_insecure#k20944uehdjfnjd335uro}

[Reversing] timeout

Stop, wait a minute!

We were given the ELF binary. When I executed it, it seemed to just exit. As I analyzed with IDA, it waits some seconds and calls generate with a can_generate global variable is 0x539 to yield the flag. But alarm prevents it.

So I used gdb to make can_generate 0x539 and call the generate function. I wrote it as a gdb script.

# gdb -n -q -x solve.py ./timeout
import gdb
import re

gdb.execute("set pagination off")
variables = gdb.execute("info var", to_string=True)
for v in variables.split("\n"):
    if not v.startswith("0x"):
        continue
    addr, name = v.split()
    if name == "can_continue":
        break
gdb.execute("break main")
gdb.execute("run")
gdb.execute("set {int}(" + addr + ") = 0x539")
gdb.execute("jump generate")
gdb.execute("quit")

watevr{3ncrytion_is_overrated_youtube.com/watch?v=OPf0YbXqDm0}

[Reversing] Hacking For Vodka

We ran out of soju so you will have to hack for vodka now, smh my head! Anyways, good luck.

I got the ELF binary. It checked the flag is correct. But it branches depend on the result of ptrace system call. If I used a debugger or utilities like a ltrace, it derived to the wrong flag.

I used the angr's hook to return 0 from ptrace.

import angr
import claripy

p = angr.Project("./vodka", load_options={"auto_load_libs": False})


class PHook(angr.SimProcedure):
    def run(self, args):
        return claripy.BVV(0, 64)


p.hook_symbol("ptrace", PHook())

state = p.factory.entry_state()
simgr = p.factory.simulation_manager(state)
simgr.explore(find=0x400000 + 0xC4F)

try:
    print(simgr.found[0].posix.dumps(0))
except:
    print("Not found")

watevr{th4nk5_h4ck1ng_for_s0ju_hackingforsoju.team}