Skip to content

Flagr

An automation framework for solving CTF challenges automatically.

Find at https://github.com/imattas/Flagr

Terminal window
curl -fsSL https://raw.githubusercontent.com/imattas/Flagr/main/install.sh | sudo bash

This installs system dependencies (python3, binwalk, steghide, foremost, tesseract, exiftool, etc.), Python packages, optional stego tools (zsteg, jsteg, stegsnow), clones the repo to /opt/flagr, installs the package via pip, and puts flagr on your PATH.

Supports apt (Debian/Ubuntu/Kali), dnf (Fedora), pacman (Arch), and yum (RHEL/CentOS).

Terminal window
cd docker
docker build -t flagr .
docker run -v "$(pwd)/ctf:/data" -it flagr
Terminal window
flagr # interactive REPL shell
flagr -f "FLAG{.*?}" target.txt # solve a file
flagr -f "picoCTF{.*?}" challenge.png # solve an image
flagr -f "FLAG{.*?}" "http://ctf.com/chall" # solve a URL
flagr -f "FLAG{.*?}" "RkxBR3tiYXNlNjR9" # solve raw data
flagr -u steghide challenge.jpg # run only one unit
flagr --force -f "FLAG{.*?}" target.bin # force re-run
flagr --remote host.ctf.com 1337 ./binary # exploit remote target

Without arguments, Flagr drops into an interactive REPL. With arguments, it queues targets immediately and enters the REPL for monitoring.


FlagDescription
-f, --flag <regex>Flag format regex. Use FLAG{.*?} or picoCTF{.*?}. Shorthand FLAG{*} is expanded automatically.
-c, --config <file>Path to .ini configuration file
-u, --unit <name>Run only specific unit(s). Can be repeated: -u steghide -u binwalk
-e, --exclude <name>Exclude unit(s). Can be repeated: -e brainfuck -e cow
-a, --autoAuto-select units for recursive targets
-t, --timeout <secs>Global timeout for all unit evaluations
--forceRemove previous results directory before running
--remote <host> <port>Remote target for exploit delivery (pwn units)
-i, --imageguiDisplay images as Flagr finds them
-m, --manager <opts>Comma-separated manager options (e.g. flag-format=FLAG{*},threads=8)
--<unit-name> <opts>Unit-specific configuration (e.g. --steghide passphrase=secret)

The interactive shell is the primary interface. It runs a cmd2-based REPL with tab completion, history, and scripting support.

Manage solve targets.

> target add ./challenge.bin # queue a file
> target add http://ctf.com/download # queue a URL
> target add "RkxBR3tiYXNlNjR9" # queue raw data
> target add 10.0.0.1:1337 # queue a network target
> target list # show all targets + status
> target solution <hash> # show the solution chain for a target
> target stop <hash> # stop processing a target

When a target completes, Flagr shows the solution chain — every unit that ran, what data it produced, and which one found the flag.

Queue multiple targets at once.

> batch file1.txt file2.png http://ctf.com/chall3

Watch a directory and auto-queue new files as they appear.

> monitor add ./downloads # watch a directory
> monitor list # show active monitors
> monitor remove ./downloads # stop watching

Uses filesystem events (inotify/FSEvents) — no polling.

Show current thread activity, queue depth, and evaluation progress.

> status
running - 14 units queued - 42 cases evaluated - 3 threads active

View or modify runtime configuration.

> set # show all settings
> set flag-format FLAG{.*?} # change flag format
> set threads 8 # change thread count
> set auto yes # enable auto mode
> set recurse yes # enable recursion
> set timeout 30 # evaluation timeout

Load a .ini configuration file at runtime.

> config ctf.ini

Attach notes to challenges for tracking.

> notes add chall1 "Tried caesar, didn't work"
> notes list
> notes show chall1

Export all solutions.

> export results.md # markdown format
> export results.json # JSON format
> export results.txt # plain text

Connect to a CTFd instance and queue challenges directly.

> ctf list # list challenges
> ctf queue 1 # queue challenge #1
> ctf submit 1 "FLAG{answer}" # submit a flag
> ctf scoreboard # show scoreboard

Configure in .ini:

[ctf]
provider=ctfd
url=http://ctf.example.com
username=youruser
password=yourpass
auto-submit=yes

API token authentication: set password=token:<your-api-token>.

Exit cleanly, stopping all threads.

> quit

Flagr ships with 96 units across 17 categories. Units are Python classes that inherit from flagr.unit.Unit. Each unit implements:

  • validate() — decide if the unit applies to a given target (file type, content, etc.)
  • evaluate() — perform the actual solving, yielding results

Units run in parallel threads. Results are checked against the flag regex and optionally fed back as new targets for recursive solving.

UnitDescription
caesarCaesar cipher (all 26 shifts)
caesar255Extended Caesar (all 256 byte shifts)
keyed_caesarKeyed Caesar cipher
vigenereVigenere cipher (with key cracking)
vigenere_autoAuto-key Vigenere
xorXOR with common keys
affineAffine cipher
atbashAtbash cipher
baconBacon’s cipher
hillHill cipher
polybiusPolybius square
railfenceRail fence cipher
rot47ROT47
reverseReversed string
substitutionFrequency-analysis substitution
quipqiupOnline substitution cipher solver
rsaRSA with small keys
rsa_attackRSA common attacks (Fermat, Pollard, etc.)
rsa_wienerRSA Wiener’s attack
rsa_common_modulusRSA common modulus attack
jwtJWT decode and verify
hashesHash lookup (MD5, SHA1, etc.)
phoneticNATO phonetic alphabet
dnaDNA codon encoding
t9T9 phone keypad encoding
UnitDescription
base64Base64 decode
base32Base32 decode
base58Base58 decode
base85Base85 decode
ascii85ASCII85 decode
unhexlifyHex string decode
unbinaryBinary string decode
undecimalDecimal string decode
morsecodeMorse code decode
urldecodeURL percent-encoding decode
unicode_decodeUnicode escape decode
qrcodeQR code decode
UnitDescription
basic_sqliSQL injection (' OR 1=1 #)
basic_nosqliNoSQL injection
sstiServer-Side Template Injection
ssrfServer-Side Request Forgery
xxeXML External Entity
robotsrobots.txt / sitemap parsing
cookiesCookie analysis and manipulation
logon_cookiesCookie-based auth bypass
source_leakSource code leak detection (.git, .svn, backup files)
spiderWeb crawler for hidden pages
dirbusterDirectory brute-forcing
form_submitAutomated form submission
jwt_forgeJWT token forging (none alg, weak secret)
deserializeInsecure deserialization
gitGit repository extraction
basic_img_shellImage upload web shell
UnitDescription
checksecBinary security check (NX, PIE, RELRO, canary)
overflowStack buffer overflow detection
ret2winAutomatic ret2win exploitation
ret2libcReturn-to-libc chain building
shellcodeShellcode injection
formatstringFormat string vulnerability exploitation
remote_exploitRemote binary exploitation via pwntools

PWN units use pwntools under the hood. The --remote <host> <port> flag enables sending exploits to remote targets.

UnitDescription
steghideSteghide extraction (with passphrase brute-forcing)
stegsnowSnow whitespace steganography
stegsolveBit-plane analysis
jstegJPEG steganography (jsteg)
lsbLeast Significant Bit extraction
png_chunksPNG chunk analysis (tEXt, zTXt, iTXt)
zstegPNG/BMP steganography (zsteg)
whitespaceWhitespace encoding
snowSNOW steganography
audio_spectrogramAudio spectrogram analysis
dtmf_decodeDTMF tone decoding
UnitDescription
brainfuckBrainfuck interpreter
malbolgeMalbolge interpreter
ookOok! interpreter
cowCOW interpreter
jsfuckJSFuck decoder (via Node.js)
pikalangPikalang interpreter
UnitDescription
binwalkBinwalk file extraction
file_carveGeneric file carving
foremostForemost file recovery
pcap_credsPCAP credential extraction
UnitDescription
blockchainBlockchain transaction analysis
xor_bruteforceXOR brute-force (single-byte keys)
substitutionFrequency-based substitution solver
pickle_deserializePython pickle deserialization
UnitDescription
stringsExtract printable strings
grepRegex search through data
exiftoolEXIF metadata extraction
gunzipGzip decompression
unzipZip extraction
extract (tar)Tar extraction
pdf2textPDF text extraction
pdfinfoPDF metadata
pdfimagesPDF embedded image extraction
pdfcrackPDF password cracking
apktoolAPK decompilation
tesseractOCR text extraction
tcpflowTCP stream reassembly
ltraceLibrary call tracing
netcatBanner grabbing / basic interaction
pwntools_ncpwntools-based network interaction
template_solverTemplated challenge solver (math, trivia)
md5 (crack)MD5 hash cracking

Target (file, URL, raw data, host:port)
Manager (thread pool, configurable thread count)
├──▶ Unit 1 (base64 decode) → found data → recurse as new target
├──▶ Unit 2 (strings + grep) → found flag! → report + stop
├──▶ Unit 3 (binwalk) → extracted files → recurse each file
├──▶ Unit 4 (steghide) → extracted data → check for flag
├──▶ Unit 5 (caesar, 26 shifts) → plaintext → check for flag
└──▶ ...96 units total
  1. Target wrapping — Input (file path, URL, raw bytes, or host:port) is wrapped into a Target object that provides uniform access to raw data, file path, and metadata.

  2. Unit matching — The Finder scans all registered units and calls each unit’s constructor. Units that raise NotApplicable are skipped. Applicable units are queued with their priority.

  3. Threaded evaluation — A configurable thread pool (default 4 threads) pulls work items from a priority queue. Each unit’s evaluate() method runs in a thread and yields results.

  4. Flag checking — Every piece of output from every unit is checked against the flag format regex. If it matches, the flag is reported and the target is marked solved.

  5. Recursion — Data or files produced by units are fed back as new targets (up to a configurable depth). This handles layered challenges (e.g., base64-encoded zip containing a steganographic image).

  6. Solution chain — Flagr tracks the parent-child relationship between units, so you can see exactly which sequence of operations solved the challenge.

Units have a PRIORITY value from 0 (highest) to 100 (lowest). Default is 50. Fast, high-success-rate units (base64, strings) run first. Slow or low-probability units (brute-force, web attacks) run later. Child units inherit scaled priority from their parent to ensure recursive results are processed promptly.

PropertyDescription
PRIORITY0-100, lower = runs first
GROUPSTags for filtering (e.g. ["crypto", "caesar"])
BLOCKED_GROUPSGroups this unit won’t recurse into
DEPENDENCIESRequired system binaries (e.g. ["steghide"])
RECURSE_SELFWhether the unit can recurse into itself
NO_RECURSEDisable all recursion from this unit
STRICT_FLAGSFlag must match the entire output, not a substring

Create a .ini file for persistent settings:

[manager]
flag-format = FLAG{.*?}
auto = yes
threads = 8
outdir = ./results
recurse = yes
timeout = 30
force = no
min-data = 5
[ctf]
provider = ctfd
url = http://ctf.example.com
username = player1
password = supersecret
auto-submit = yes
[steghide]
passphrase = password123
[DEFAULT]
remote = host.ctf.com:1337

Load with flagr -c ctf.ini or config ctf.ini in the REPL.

KeyDefaultDescription
flag-format(none)Regex for flag detection
threads4Worker thread count
outdir./resultsOutput directory for artifacts
autonoAuto-select units for recursive targets
recurseyesEnable recursive target processing
forcenoRemove previous results before running
timeout0.1Per-unit evaluation timeout (seconds)
min-data5Minimum data length to process
units(all)Comma-separated list of units to run
exclude(none)Comma-separated list of units to skip
downloadyesAuto-download URL targets
imageguinoDisplay images in GUI

For pwn challenges hosted on a remote server:

Terminal window
# From the command line
flagr --remote host.ctf.com 1337 ./challenge_binary
# Or in the REPL
> set remote host.ctf.com:1337
> target add ./challenge_binary

The --remote flag:

  1. Stores the remote address in the config so all pwn units can access it
  2. Enables auto mode
  3. Queues both the binary (for local analysis) and the remote address (for network units)

PWN units (ret2win, ret2libc, overflow, formatstring, shellcode, remote_exploit) will:

  • Analyze the local binary for vulnerabilities
  • Build the exploit payload
  • Deliver it to the remote target
  • Capture and check the response for flags

Create a Python file in flagr/units/<category>/:

from typing import Generator, Any
from flagr.unit import Unit as BaseUnit, NotApplicable
class Unit(BaseUnit):
GROUPS = ["misc", "my_unit"]
PRIORITY = 50
DEPENDENCIES = [] # e.g. ["my_tool"]
RECURSE_SELF = False
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Raise NotApplicable if this unit shouldn't run on this target
if not self.target.is_printable:
raise NotApplicable("not printable data")
def evaluate(self, case: Any) -> Generator[Any, None, None]:
"""
Perform the actual work. Yield results (strings, bytes, file paths).
Each yielded result is checked for flags and optionally recursed.
"""
data = self.target.raw
result = self._do_something(data)
if result:
yield result
def _do_something(self, data):
# Your solving logic here
return data.decode("rot13") # example

The unit is auto-discovered on next run. No registration needed.

ClassUse For
UnitGeneric unit
FileUnitUnits that only work on files
PrintableDataUnitUnits that expect printable input
NotEnglishAndPrintableUnitPrintable but not already English (for ciphers)
NotEnglishUnitNot English text
PwnUnitBinary exploitation (auto-checks for ELF)
WebUnitWeb challenges (auto-checks for URL targets)
CryptoUnitCrypto challenges

/opt/flagr/ ← install directory
├── install.sh ← curl installer
├── setup.py ← pip package
├── requirements.txt ← Python dependencies
├── flagr/
│ ├── __init__.py ← exports Manager, Target, Unit, Finder
│ ├── __main__.py ← CLI entry point + arg parsing
│ ├── manager.py ← thread pool, work queue, recursion
│ ├── monitor.py ← result reporting (logging, JSON)
│ ├── target.py ← target abstraction (file, URL, raw, network)
│ ├── unit.py ← base Unit class + Finder (auto-discovery)
│ ├── util.py ← shared utilities
│ ├── repl/
│ │ ├── __init__.py ← cmd2-based interactive shell
│ │ ├── ctf.py ← CTF platform base class
│ │ ├── ctfd.py ← CTFd provider
│ │ └── pico.py ← picoCTF provider
│ └── units/ ← 96 solving units
│ ├── raw/ ← encoding (base64, hex, morse, etc.)
│ ├── crypto/ ← ciphers (caesar, vigenere, rsa, etc.)
│ ├── web/ ← web attacks (sqli, ssti, ssrf, etc.)
│ ├── pwn/ ← binary exploitation
│ ├── stego/ ← steganography
│ ├── esoteric/ ← esoteric languages
│ ├── forensics/ ← file carving, pcap
│ ├── misc/ ← blockchain, xor brute, pickle
│ ├── network/ ← netcat, pwntools
│ ├── ocr/ ← tesseract
│ ├── pcap/ ← tcpflow
│ ├── pdf/ ← pdf tools
│ ├── rev/ ← reverse engineering
│ ├── apk/ ← Android APK
│ ├── gzip/ ← decompression
│ ├── tar/ ← extraction
│ └── zip/ ← extraction
├── tests/ ← unit tests
├── examples/ ← usage examples
│ ├── quick.py ← programmatic usage
│ └── everything.py ← full example
└── docker/ ← Docker support

Flagr can be used as a Python library:

from flagr.manager import Manager
from flagr.monitor import LoggingMonitor
monitor = LoggingMonitor()
manager = Manager(monitor=monitor)
manager["manager"]["flag-format"] = "FLAG{.*?}"
manager.start()
manager.queue_target("./challenge.bin")
if manager.join(timeout=30):
for flag in monitor.flags:
print(f"Found: {flag}")

Flagr automatically runs code and performs potentially intrusive actions against targets. This includes SQL injection, local file inclusion, web shell uploads, and remote code execution attempts.

Only run Flagr against systems you have explicit permission to test.