python::ctf

scripting python one-liners · snippets
Encode/DecodeBytesCrypto math NetworkingFilesStruct Misc
01Encode / Decode
All encodings in one place
# base64
import base64
base64.b64encode(b'data').decode()
base64.b64decode('ZGF0YQ==')
base64.b64decode('ZGF0YQ==' + '==')   # fix padding
base64.urlsafe_b64decode(s.replace('-','+').replace('_','/'))

# hex
bytes.fromhex('7069636f')
b'pico'.hex()
int('ff', 16)
f'{255:02x}'

# binary
int('01000001', 2)
f'{65:08b}'
bytes(int(s[i:i+8],2) for i in range(0,len(s),8))

# URL
from urllib.parse import quote, unquote
quote('hello world')
unquote('hello%20world')

# rot13
s.translate(str.maketrans(
    'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
    'NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm'))
Decode unknown input
# Try all common decodings
import base64, binascii

def try_decode(s):
    attempts = []
    try: attempts.append(('b64', base64.b64decode(s + '==')))
    except: pass
    try: attempts.append(('hex', bytes.fromhex(s)))
    except: pass
    try: attempts.append(('b32', base64.b32decode(s)))
    except: pass
    for name, val in attempts:
        printable = all(32 <= b < 127 for b in val)
        print(f['{name}'] {val}{' ← printable' if printable else ''})

try_decode('cGljb0NURg==')
02Bytes & Binary
Byte manipulation
# XOR bytes
bytes(a ^ b for a, b in zip(ct, key))
bytes(b ^ 0x42 for b in data)         # single byte key
bytes(b ^ key[i % len(key)] for i, b in enumerate(data))

# Brute XOR — find printable result
for k in range(256):
    result = bytes(b ^ k for b in data)
    if all(32 <= x < 127 for x in result):
        print(k, result)

# Reverse bytes
data[::-1]

# Swap endianness of 4-byte chunks
import struct
[struct.unpack(', data[i:i+4])[0] for i in range(0, len(data), 4)]

# Pack list of ints as bytes
bytes([0x70, 0x69, 0x63, 0x6f])

# Null-terminate string
s.split(b'\x00')[0].decode()
Hexdump
# Pretty hexdump (like xxd)
def hexdump(data, width=16):
    for i in range(0, len(data), width):
        chunk = data[i:i+width]
        hex_part = ' '.join(f'{b:02x}' for b in chunk)
        asc_part = ''.join(chr(b) if 32 <= b < 127 else '.' for b in chunk)
        print(f'{i:08x}  {hex_part:<{width*3}}  |{asc_part}|')

hexdump(b'hello world\x00\x01\x02')

# Find byte pattern
data.find(b'\x89PNG')
[i for i in range(len(data)) if data[i:i+4] == b'\xde\xad\xbe\xef']

# Count occurrences
data.count(b'\x90')
03Crypto Math
Number theory
# Modular inverse
pow(e, -1, phi)                  # Python 3.8+ built-in
from Crypto.Util.number import inverse
inverse(e, phi)

# RSA decrypt
from Crypto.Util.number import long_to_bytes, bytes_to_long
p, q, e, c = ...
phi = (p-1)*(q-1)
d = pow(e, -1, phi)
m = pow(c, d, p*q)
print(long_to_bytes(m))

# GCD / extended GCD
from math import gcd
gcd(a, b)

# Integer square root
import gmpy2
root, exact = gmpy2.iroot(n, 3)   # cube root
root, exact = gmpy2.iroot(n, 2)   # square root

# CRT (Chinese Remainder Theorem)
from sympy.ntheory.modular import crt
n_list = [3, 5, 7]
r_list = [2, 3, 2]
x = crt(n_list, r_list)[1]        # → 23
Hashing & AES
# Hashes
import hashlib
hashlib.md5(b'data').hexdigest()
hashlib.sha256(b'data').hexdigest()
hashlib.sha1(b'data').digest()

# HMAC
import hmac
hmac.new(b'key', b'msg', hashlib.sha256).hexdigest()

# AES CBC decrypt
from Crypto.Cipher import AES
cipher = AES.new(key, AES.MODE_CBC, iv)
pt = cipher.decrypt(ct)

# AES ECB detect (repeating blocks)
ct = bytes.fromhex('...')
blocks = [ct[i:i+16] for i in range(0, len(ct), 16)]
print(len(blocks) != len(set(blocks)))  # True = ECB

# XOR two ciphertexts (CTR/OFB nonce reuse)
keystream = bytes(a^b for a,b in zip(ct1, ct2))
04Networking
Socket patterns
# Read until prompt, send answer
import socket
s = socket.socket()
s.connect(('host', 1337))

# Read challenge line
line = s.recv(1024).decode().strip()
n = int(line.split(': ')[1])
s.sendall((str(n * 2) + '\n').encode())
print(s.recv(1024).decode())    # flag

# Read until specific string
def recv_until(s, marker):
    buf = b''
    while marker not in buf:
        buf += s.recv(1)
    return buf

# pwntools is better for interactive
from pwn import *
p = remote('host', 1337)
p.recvuntil(b'Enter n: ')
p.sendline(b'42')
print(p.recvline())
HTTP requests
# requests — web challenges
import requests
s = requests.Session()

# GET with cookies
r = s.get('http://target/flag', cookies={'session': '...'})

# POST form
r = s.post('http://target/login', data={'user':'admin','pass':"' OR 1=1--"})

# POST JSON
r = s.post('http://target/api', json={'cmd':'cat /flag'})

# Custom headers
r = s.get('http://target/', headers={'X-Admin':'true', 'User-Agent':'admin'})

# Check response
print(r.status_code, r.text[:200])
import re
print(re.findall(r'picoCTF\{[^}]+\}', r.text))
05File & String Operations
File I/O
# Read binary
data = open('file.bin', 'rb').read()

# Write binary
open('out.bin', 'wb').write(payload)

# Patch bytes at offset
data = bytearray(open('file', 'rb').read())
data[0x100] = 0x90
data[0x101:0x103] = b'\x90\x90'
open('patched', 'wb').write(data)

# Find all flag patterns in file
import re
flags = re.findall(rb'picoCTF\{[^\}]+\}', data)

# Read lines, strip whitespace
lines = open('data.txt').read().splitlines()

# Frequency count
from collections import Counter
Counter(data.decode(errors='replace')).most_common(10)
String tricks
# Check printable
all(32 <= b < 127 for b in data)
data.decode(errors='replace').isprintable()

# Caesar brute force
for shift in range(26):
    print(shift, ''.join(
        chr((ord(c) - 65 - shift) % 26 + 65) if c.isupper() else
        chr((ord(c) - 97 - shift) % 26 + 97) if c.islower() else c
        for c in ciphertext))

# Frequency analysis
from collections import Counter
Counter(c for c in text if c.isalpha()).most_common()

# All combinations
from itertools import product
for combo in product('abcdef', repeat=4):
    print(''.join(combo))
06struct — Binary Parsing
struct format reference
import struct

# Format: [endian][count][type]
# Endian: < little  > big  ! network  = native
# B=uint8  H=uint16  I=uint32  Q=uint64
# b=int8   h=int16   i=int32   q=int64
# f=float  d=double  s=bytes   x=pad byte

struct.pack(', 0xdeadbeef, 0x1234, 0x5678)   # → 8 bytes LE
struct.unpack(', data[:8])                     # → (val1, val2, val3)
struct.unpack_from(', data, offset=4)            # unpack at offset
struct.calcsize(')                             # → 8 (size in bytes)

# Parse stream of records
record_fmt = '
size = struct.calcsize(record_fmt)
for i in range(0, len(data), size):
    a, b, c = struct.unpack(record_fmt, data[i:i+size])
    print(a, b, c)

# int.to_bytes / from_bytes (simpler for single values)
(0xdeadbeef).to_bytes(4, 'little')
int.from_bytes(b'\xef\xbe\xad\xde', 'little')
07Misc Utilities
subprocess & os
# Run command, get output
import subprocess
out = subprocess.check_output(['strings', 'binary']).decode()
out = subprocess.check_output('strings binary | grep flag', shell=True).decode()

# Run and get stdout+stderr
r = subprocess.run(['./challenge'], input=b'payload\n',
                   capture_output=True, timeout=5)
print(r.stdout, r.stderr)

# Environment variable
import os
os.environ['FLAG']
Regex & parsing
# Find flag pattern
import re
re.findall(r'picoCTF\{[^}]+\}', text)
re.search(r'picoCTF\{.*?\}', text).group()

# Extract numbers from string
re.findall(r'\d+', text)
re.findall(r'0x[0-9a-fA-F]+', text)    # hex values

# JSON parsing
import json
data = json.loads(response_text)
json.dumps(data, indent=2)

# Bit operations
n = 0b11010110
bin(n)              # '0b11010110'
n.bit_length()      # 8
bin(n).count('1')   # popcount = 5
n & (n - 1) == 0    # True if power of 2
COPY-PASTE ESSENTIALS →  bytes(b^k for b in data) XOR  · base64.b64decode(s+'==') safe b64  · bytes.fromhex(s) hex→bytes  · re.findall(r'picoCTF\{[^}]+\}', text) find flag  · struct.unpack('<I', data[:4])[0] parse int  · Counter(data).most_common() frequency  · pow(e,-1,phi) modular inverse  · long_to_bytes(pow(c,d,n)) RSA decrypt