MeePwn CTF 2017: |\/|/-\T|-| (100)

We are given a file, hack.py, which looks as follows.

from Crypto.Util.number import *
from hashlib import md5

flag = "XXX"
assert len(flag) == 4
pad = bytes_to_long(md5(flag).digest())

hack = 0

for char in flag:
    hack+= pad
    hack*= ord(char)

print hack
print pad
print hack % pad
#hack = 64364485357060434848865708402537097493512746702748009007197338675
#flag_to_submit = "MeePwnCTF{" + flag + "}"

Looking at the loop, hack will be like \(abcdx + bcdx + cdx + dx\), with \(x\) is the value of pad. The value of hack is not quite long. Factoring hack leads to 13 prime factors (11 distincts prime factors). We can search which one is \(x\) by brute-force, and then try to solve the remaining equation.

After dividing hack with \(x\), the remaining value will be in a form like \(abcd + bcd + cd + d\). We can find a proper factor of the remaining equation, and then substract it with 1, and the remaining value will in a form like \(abc + bc + c\). This means we can recursively do this and it will be the correct sequence if we can make it 0 and MD5(flag) is the same as our candidate padding. We will use DFS to recursively find the candidate.

Here is the Python script to find the value of flag:

import string
from Crypto.Util.number import *
from hashlib import md5

primes = [3,3,5,5,7,107,487,607,28429,29287,420577267963,3680317203978923,1002528655290265069]
hack = 64364485357060434848865708402537097493512746702748009007197338675
flen = 14
total = 1

for p in primes:
    total = total * p
assert(hack == total)

mask = 2 ** len(primes)
cand = []
for i in range(mask):
    q = 1
    for j in range(len(primes)):
    if ((i & (1<<j)) != 0):
        q = q * primes[j]

    if (2 ** 120 <= q and q <= 2 ** 128):
    cand.append(q)

def check(d, t, a, h):
    if d == 0 and t == 0:
    flag = "".join([chr(c) for c in a])
    if (bytes_to_long(md5(flag).digest()) == h):
        print(flag)
    return
    if t == 0:
    return

    if (d,t) in vis:
    return

    vis.add((d,t))


    for c in string.printable:
    x = ord(c)
    if t % x == 0:
        check(d-1, (t // x) - 1, [x] + a, h)

for pad in cand:
    t = hack // pad
    vis = set()
    check(flen, t, [], pad)

Flag is: MeePwnCTF{d0y0ul1keM@TH?}

Related Posts

MeePwn CTF 2017: Simpler RSA (100)
Cyber Sea Game 2017: addcrypto (50)
Cyber Sea Game 2017: rsa-8192 (200)
TUCTF 2017: Crypto Clock (300)