beginnercat/misc~2 min read

Scripting for CTF

Write Python one-liners and short scripts to automate repetitive tasks — iteration, bruteforcing, and service interaction.

// prerequisite reading

Why script?

CTF challenges regularly demand:

  • Brute-forcing 256 XOR keys.
  • Interacting with a service 1000 times to collect oracle results.
  • Automating a timing side-channel with sub-millisecond precision.

A one-liner or 20-line script beats doing it by hand every time.

Essential Python CTF imports

from pwn import *           # network, encoding, crypto helpers
import hashlib               # MD5, SHA1, SHA256
import itertools             # product, permutations, combinations
import base64                # b64decode, b64encode
import struct                # pack, unpack bytes
import socket                # raw TCP if pwntools is overkill
from Crypto.Util.number import bytes_to_long, long_to_bytes  # PyCryptodome

Connecting to a service

from pwn import *

io = remote("challenge.ctf", 1337)
io.recvuntil(b"Enter: ")     # read until the prompt
io.sendline(b"my_answer")    # send a line
data = io.recvline()         # read one line back
io.interactive()             # hand off to your terminal

Brute-force template

from pwn import *

io = remote("challenge.ctf", 1337)
for guess in range(256):
    io.sendline(str(guess).encode())
    response = io.recvline()
    if b"flag" in response:
        print(response)
        break
    io.close()
    io = remote("challenge.ctf", 1337)

Hash brute-force

import hashlib

target = "5f4dcc3b5aa765d61d8327deb882cf99"
wordlist = open("/usr/share/wordlists/rockyou.txt", "rb")
for word in wordlist:
    word = word.strip()
    if hashlib.md5(word).hexdigest() == target:
        print(word.decode())
        break

Padding oracle automation

# pwntools handles the connection, you handle the logic
# For real padding oracle, use padbuster or the bleichenbacher tool
# Manual version skeleton:
def oracle(ct: bytes) -> bool:
    io = remote("challenge.ctf", 1337)
    io.sendline(ct.hex().encode())
    result = io.recvline()
    io.close()
    return b"error" not in result.lower()

Writing output to a file

with open("output.bin", "wb") as f:
    f.write(decrypted_bytes)

# Or pipe directly to xxd:
import subprocess
subprocess.run(["xxd"], input=decrypted_bytes)

One-liner style

# Decode hex flag from a service
python3 -c "
from pwn import *; io = remote('ctf', 1337); io.recvuntil(b': '); print(bytes.fromhex(io.recvline().strip().decode()))
"