#!/usr/bin/env python
#-*- coding:utf-8 -*-
import os, sys, re
from socket import *
PORT = 7777 or int(sys.argv[1])
KEY = open("_flag.txt").read()
SBOX = list(range(128))
SALTED_SBOX = list(range(128))
# ----------------------------------------------------------------
# SERVICE
# ----------------------------------------------------------------
def main():
    add_key(SALTED_SBOX, KEY)
    serve()
def serve():
    f = socket(AF_INET, SOCK_DGRAM)
    f.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
    f.bind(("0.0.0.0", PORT))
    print "[*] Server started on %d" % PORT
    while True:
        data, addr = f.recvfrom(4096)
        client(data, addr, f)
    return
def client(data, addr, f):
    print "[.] GOT", repr(data), "FROM", addr
    if len(data) % 2 or len(data) > 64:
        return
    for ch in data:
        if ord(ch) >= 128:
            return
    mid = len(data) >> 1
    k = data[:mid].rstrip("\x00")
    m = data[mid:].rstrip("\x00")
    c = encrypt(SALTED_SBOX, k, m)
    f.sendto(c.encode("hex"), addr)
    print "[+] RESULT SENT", addr, "\n"
    return
# ----------------------------------------------------------------
# CRYPTO
# ----------------------------------------------------------------
def encrypt(sbox, k, m):
    sbox = sbox[::]
    add_key(sbox, k)
    c = ""
    for ch in m:
        c += chr(sbox[ord(ch)])
        sbox = combine(sbox, sbox)
    return c
def add_key(sbox, k):
    for i, c in enumerate(k):
 print i, sbox[ord(c)], ord(c)
        sbox[i], sbox[ord(c)] = sbox[ord(c)], sbox[i]
        for i in xrange(len(sbox)):
            sbox[i] = (sbox[i] + 1) % 128
    return
def combine(a, b):
    ret = [-1] * len(b)
    for i in range(len(b)):
        ret[i] = a[b[i]]
    return tuple(ret)
if __name__ == "__main__":
    main()
The big weakness in this crypto was the fact that we can steal the SALTED_SBOX by sending special packets to the server. My script to steal the sbox is shown below. 
from socket import *
import binascii
 # Create a list of numbers so I can figure out which one I didn't download
nums = list(range(128))
SALT = list()
# This iterates through all possible spots of the SBOX
for i in range(1,128):
 print i
 # Create a string that looks like \x00\x01
 send = '\x00' + binascii.unhexlify(hex(i)[2:].zfill(2))
 s = socket(AF_INET, SOCK_DGRAM)
 # You actually run this against their server intially
 s.connect(('localhost', 7777))
 s.sendall(send)
 sbox = int(s.recv(1024), 16)
 SALT.append(sbox)
 s.close()
 nums.remove(sbox)
SALT.insert(0, nums[0])
length = SALT[-1]
flag = ''
for i in range(0, length):
 val = (SALT[i]-(length+1))%128
 flag += chr(val)
print flag
for i in range(128):
 SALT[i] = (SALT[i] - (length+1))%128
hexSALT = []
for i in SALT:
 hexSALT.append(hex(i)[2:].zfill(2))
print hexSALT
### Everything below this line was added merely so I could easily see the
### Salted SBOX of the server after I had downloaded it.
print
print ['3c', '69', '73', '60', '74', '68', '31', '02', '03', '6b', '33', '79', '08', '6c', '30', '6e', '39', '0c', '65', '0f', '0e', '75', '67', '05', '3f', '3e', '1a', '1b', '1c', '1d', '1e', '1f', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '2a', '2b', '2c', '2d', '2e', '2f', '14', '06', '32', '0a', '34', '35', '36', '37', '38', '10', '3a', '3b', '00', '3d', '19', '18', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '4a', '4b', '4c', '4d', '4e', '4f', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59', '5a', '5b', '5c', '5d', '5e', '5f', '11', '61', '62', '63', '64', '12', '66', '16', '17', '01', '6a', '09', '0d', '6d', '13', '6f', '70', '71', '72', '07', '04', '15', '76', '77', '78', '0b', '7a', '7b', '7c', '7d', '7e', '7f']
The server's stolen sbox is at the bottom of the script and (if there are no duplicate chars) then the key used to salt the sbox is at the beginning of the array where each value subtracts the final value in the array mod 128 (ie. 3c-7f % 128). So now, instead of running against their server, I ran a local one with the key that I knew up to that point (the first few characters were legible) and slowly changed the _flag.txt until the sboxs matched. So all I did was download there sbox and then create a string that resulted in their sbox, which was the flag - -- suntzu_II
 
No comments:
Post a Comment