一键导入
ctf-crypto
Cryptography techniques for CTF challenges. Use when attacking encryption, hashing, ZKP, signatures, or mathematical crypto problems.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Cryptography techniques for CTF challenges. Use when attacking encryption, hashing, ZKP, signatures, or mathematical crypto problems.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
Digital forensics and blockchain analysis for CTF challenges. Use when analyzing disk images, memory dumps, event logs, network captures, or cryptocurrency transactions.
Malware and network analysis techniques for CTF challenges. Use when analyzing obfuscated scripts, malicious packages, custom protocols, or C2 traffic.
Miscellaneous CTF challenge techniques. Use for trivia, automation scripts, encoding puzzles, RF/SDR signal processing, or challenges that don't fit other categories.
Open Source Intelligence techniques for CTF challenges. Use when gathering information from public sources, social media, geolocation, or identifying unknown data.
Binary exploitation (pwn) techniques for CTF challenges. Use when exploiting buffer overflows, format strings, heap vulnerabilities, race conditions, or kernel bugs.
Target reconnaissance and enumeration for CTF challenges. Use when you need to scan ports, discover services, enumerate web directories, or fingerprint technology stacks.
| name | ctf-crypto |
| description | Cryptography techniques for CTF challenges. Use when attacking encryption, hashing, ZKP, signatures, or mathematical crypto problems. |
| user-invocable | false |
| allowed-tools | ["Bash","Read","Write","Edit","Glob","Grep","Task","WebFetch","WebSearch"] |
Quick reference for crypto challenges. For detailed techniques, see supporting files.
commit(i) = sha256(salt(i), color(i)) and have salt, brute all colorsimport networkx as nx
nx.coloring.greedy_color(G, strategy='saturation_largest_first')
new_sig = known_sig XOR block2_of_P1 XOR block2_of_P2
import numpy as np
def solve_gf2(A, b):
"""Solve Ax = b over GF(2)."""
m, n = A.shape
Aug = np.hstack([A, b.reshape(-1, 1)]) % 2
pivot_cols, row = [], 0
for col in range(n):
pivot = next((r for r in range(row, m) if Aug[r, col]), None)
if pivot is None: continue
Aug[[row, pivot]] = Aug[[pivot, row]]
for r in range(m):
if r != row and Aug[r, col]: Aug[r] = (Aug[r] + Aug[row]) % 2
pivot_cols.append((row, col)); row += 1
if any(Aug[r, -1] for r in range(row, m)): return None
x = np.zeros(n, dtype=np.uint8)
for r, c in reversed(pivot_cols):
x[c] = Aug[r, -1] ^ sum(Aug[r, c2] * x[c2] for c2 in range(c+1, n)) % 2
return x
Pattern (Loopy Primes): q = next_prime(p), making p ≈ q ≈ sqrt(N).
Factorization: Find first prime below sqrt(N):
from sympy import nextprime, prevprime, isqrt
root = isqrt(n)
p = prevprime(root + 1)
while n % p != 0:
p = prevprime(p)
q = n // p
Multi-layer variant: 1024 nested RSA encryptions, each with consecutive primes of increasing bit size. Decrypt in reverse order.
When N is product of many small primes (not just p*q):
# Factor N (easier when many primes)
from sympy import factorint
factors = factorint(n) # Returns {p1: e1, p2: e2, ...}
# Compute phi using all factors
phi = 1
for p, e in factors.items():
phi *= (p - 1) * (p ** (e - 1))
d = pow(e, -1, phi)
plaintext = pow(ciphertext, d, n)
Pattern (Cleverly Forging Breaks): AES-CFB with 8-bit feedback and reused IV allows state reconstruction.
Key insight: After encrypting 16 known bytes, the AES internal shift register state is fully determined by those ciphertext bytes. Forge new ciphertexts by continuing encryption from known state.
Known Plaintext Attack (most common in CTFs):
def vigenere_decrypt(ciphertext, key):
result = []
key_index = 0
for c in ciphertext:
if c.isalpha():
shift = ord(key[key_index % len(key)].upper()) - ord('A')
base = ord('A') if c.isupper() else ord('a')
result.append(chr((ord(c) - base - shift) % 26 + base))
key_index += 1
else:
result.append(c)
return ''.join(result)
def derive_key(ciphertext, plaintext):
"""Derive key from known plaintext (e.g., flag format CCOI26{)"""
key = []
for c, p in zip(ciphertext, plaintext):
if c.isalpha() and p.isalpha():
c_val = ord(c.upper()) - ord('A')
p_val = ord(p.upper()) - ord('A')
key.append(chr((c_val - p_val) % 26 + ord('A')))
return ''.join(key)
When standard keys don't work:
Small subgroup attacks:
Invalid curve attacks:
Singular curves:
Smart's attack:
# SageMath ECC basics
E = EllipticCurve(GF(p), [a, b])
G = E.gens()[0] # generator
order = E.order()
Pattern (Faulty Curves): Bit flip during ECC computation reveals private key bits.
Attack: Compare correct vs faulty ciphertext, recover key bit-by-bit:
# For each key bit position:
# If fault at bit i changes output → key bit i affects computation
# Binary distinguisher: faulty_output == correct_output → bit is 0
# Python setup
pip install pycryptodome z3-solver sympy gmpy2
# SageMath for advanced math (required for ECC)
sage -python script.py
from Crypto.Util.number import *
# RSA basics
n = p * q
phi = (p-1) * (q-1)
d = inverse(e, phi)
m = pow(c, d, n)
# XOR
from pwn import xor
xor(ct, key)
Z3 solves constraint satisfaction - useful when crypto reduces to finding values satisfying conditions.
Basic usage:
from z3 import *
# Boolean variables (for bit-level problems)
bits = [Bool(f'b{i}') for i in range(64)]
# Integer/bitvector variables
x = BitVec('x', 32) # 32-bit bitvector
y = Int('y') # arbitrary precision int
solver = Solver()
solver.add(x ^ 0xdeadbeef == 0x12345678)
solver.add(y > 100, y < 200)
if solver.check() == sat:
model = solver.model()
print(model.eval(x))
BPF/SECCOMP filter solving:
When challenges use BPF bytecode for flag validation (e.g., custom syscall handlers):
from z3 import *
# Model flag as array of 4-byte chunks (how BPF sees it)
flag = [BitVec(f'f{i}', 32) for i in range(14)]
s = Solver()
# Constraint: printable ASCII
for f in flag:
for byte in range(4):
b = (f >> (byte * 8)) & 0xff
s.add(b >= 0x20, b < 0x7f)
# Extract constraints from BPF dump (seccomp-tools dump ./binary)
mem = [BitVec(f'm{i}', 32) for i in range(16)]
# Example BPF constraint reconstruction
s.add(mem[0] == flag[0])
s.add(mem[1] == mem[0] ^ flag[1])
s.add(mem[4] == mem[0] + mem[1] + mem[2] + mem[3])
s.add(mem[8] == 4127179254) # From BPF if statement
if s.check() == sat:
m = s.model()
flag_bytes = b''
for f in flag:
val = m[f].as_long()
flag_bytes += val.to_bytes(4, 'little')
print(flag_bytes.decode())
Converting bits to flag:
from Crypto.Util.number import long_to_bytes
if solver.check() == sat:
model = solver.model()
flag_bits = ''.join('1' if model.eval(b) else '0' for b in bits)
print(long_to_bytes(int(flag_bits, 2)))
When to use Z3:
Pattern (Shifty XOR): Each byte XORed with previous ciphertext byte.
# c[i] = p[i] ^ c[i-1] (or similar cascade)
# Brute force first byte, rest follows deterministically
for first_byte in range(256):
flag = [first_byte]
for i in range(1, len(ct)):
flag.append(ct[i] ^ flag[i-1])
if all(32 <= b < 127 for b in flag):
print(bytes(flag))
Pattern (Electronic Christmas Book): AES-ECB on BMP/image data preserves visual patterns.
Exploitation: Identical plaintext blocks produce identical ciphertext blocks, revealing image structure even when encrypted. Rearrange or identify patterns visually.
Pattern (The Seer): Server reveals whether decrypted padding is valid.
Byte-by-byte decryption:
def decrypt_byte(block, prev_block, position, oracle):
for guess in range(256):
modified = bytearray(prev_block)
# Set known bytes to produce valid padding
pad_value = 16 - position
for j in range(position + 1, 16):
modified[j] = known[j] ^ pad_value
modified[position] = guess
if oracle(bytes(modified) + block):
return guess ^ pad_value
Simple substitution: A↔Z, B↔Y, C↔X, etc.
def atbash(text):
return ''.join(
chr(ord('Z') - (ord(c.upper()) - ord('A'))) if c.isalpha() else c
for c in text
)
Identification: Challenge name hints ("Abashed" ≈ Atbash), preserves spaces/punctuation, 1-to-1 substitution.
Pattern (Wheel of Mystery): Physical cipher wheel with inner/outer alphabets.
Brute force all rotations:
outer = "ABCDEFGHIJKLMNOPQRSTUVWXYZ{}"
inner = "QNFUVWLEZYXPTKMR}ABJICOSDHG{" # Given
for rotation in range(len(outer)):
rotated = inner[rotation:] + inner[:rotation]
mapping = {outer[i]: rotated[i] for i in range(len(outer))}
decrypted = ''.join(mapping.get(c, c) for c in ciphertext)
if decrypted.startswith("METACTF{"):
print(decrypted)