Skip to main content
Be Bitwise

Moving from CTF challenges to real targets

CTF binaries are puzzles with one bug; real software is a city with many. The mindset, scoping, and patience the transition takes — without the hype.

#vulnerability-research#ctf#fuzzing#career

A CTF binary is a haiku. Seventeen functions, three of which matter, exactly one bug, exactly one path to it. The challenge author has done the hard work of pruning the search space; your job is to walk down the only branch that leads anywhere and find the trick at the end.

Real software is a city. Tens of thousands of functions, most irrelevant to security, an unknown number of bugs scattered across them, and no helpful "exploit me" sign. Nobody has done the pruning. The trick at the end might not exist; even if it does, the cost of confirming that it doesn't (so you can move on) is itself substantial.

The transition between the two is more than a step up in difficulty. It's a different game. Mistaking it for a harder version of the same game is the first mistake people make.

What CTFs taught you that you'll keep

Plenty, to be fair. The mechanics transfer. If you can write a ROP chain on a pwn.college challenge you can write one against a real binary; the assembly hasn't changed and the calling conventions don't care that the target has more code around the bug. Heap exploitation primitives (tcache poisoning, fastbin attacks, large bin manipulation, house-of-this-or-that) are the same techniques in both worlds. Knowing them makes you faster at recognising what's possible once you've located a candidate bug.

Debugger fluency carries over. Reading assembly carries over. Understanding mitigations and how they interact carries over. None of this disappears.

What changes is everything that happens before you reach the point of "now apply a known primitive to a known bug". The earlier stages, which CTFs hand you for free, become the bulk of the work.

How real targets differ, in concrete terms

Each box in the right column is a job. Some are jobs that take days. R2 ("build target understanding") is the one most CTF graduates underestimate; real research often spends weeks doing nothing more than reading patches, tracing code paths, and forming a mental model of how the target's developers think.

A few specific differences:

One bug versus many. A CTF gives you the bug. A real target may have hundreds, of which most are irrelevant (DoS, info leak with no useful data, crashes that don't reach corruption), some are useful but already known and patched in the version you eventually need to support, and a small minority are exploitable, novel, and worth the time to weaponise. Filtering is most of the work.

Simplified versus realistic mitigations. A CTF disables PIE on the binary that needs it disabled. A real target has full PIE, full RELRO, ASLR, CFI on some functions, stack canaries, fortify_source on the libc calls, and a SELinux policy that may quietly close half the post-exploitation paths you were planning. Each mitigation is straightforward in isolation. Stacked, they require you to find primitives that work in their combined presence, and the combinatorics are harsh.

Known-bug versus unknown-bug mindset. The CTF mindset is "I know there's a bug here, where is it?". The real-target mindset is "I have no idea if there's a bug here, and most days I should expect to find none". The emotional load is different. CTF challenges reward decisive action; real targets reward willingness to sit in uncertainty.

Patches that aren't documented. Modern projects (browsers, kernels, hypervisors) silent-fix bugs all the time. A patch that looks like a refactor might be quietly fixing a use-after-free. Reading commit history for security implications is its own skill, and it's the foundation of variant analysis, which is one of the more reliable VR techniques.

Choosing a target

Probably the single most important decision you make. Pick badly and you spend six months on something with no bugs, no audience, and no path to publication. Pick well and the work itself trains you faster than any course.

The honest selection criteria, in rough order of importance:

  1. You can build it from source. This is non-negotiable for serious work. You want symbols, you want sanitisers, you want to be able to insert your own logging.
  2. It has been audited recently, but not heavily. Targets that have never been audited often have shallow bugs that aren't representative; targets that have been audited to death have a high floor for novel discovery. The middle is where the interesting work lives.
  3. The codebase is intelligible. A 200kloc parser written in idiomatic C is a better starting target than a 5Mloc browser engine with custom build infrastructure and seven layers of abstraction.
  4. You care about it. This sounds soft. It isn't. You'll spend months on this thing. If you don't have some genuine curiosity about the target, motivation runs out before the bug arrives.
  5. It has a reasonable disclosure path. Whether bug bounty, vendor disclosure, or coordinated publication, knowing in advance how you'll dispose of a finding is part of the planning.

The very common mistake is to pick the most prestigious target you can think of (Chrome, Linux kernel, iOS). These are real targets and real research happens on them, but they are also the worst possible starting point. Pick something smaller. A specific Linux kernel subsystem. A particular Wireshark dissector. An open-source FTP server. A binary in the SUID set on Ubuntu's default install. The bugs are less prestigious, the work is more legible, and the lessons travel.

Scoping

CTFs scope themselves. You're given a single binary; the scope is its complete attack surface. Real targets give you nothing.

The skill is to take a target you've chosen and carve a scope of work that's defensible. "I'm going to look for memory corruption in the parser of file format X handled by component Y of project Z, in version range V." That sentence should fit on a sticky note. If you can't write that sentence, you're not scoped. The first month of research is often nothing but resisting the urge to expand scope while building understanding within it.

A rough rule: scope so the surface fits in your head. If you can hold a complete map of the parsing logic mentally, you can spot anomalies. If you can't, you're pattern-matching against a fragment, and the bugs hide in the bits you don't see.

The role of fuzzing

In CTFs, fuzzing rarely appears. The bugs are findable by reading. In real-world VR, fuzzing is one of the dominant discovery methods, partly because the codebases are too large to read and partly because the human brain misses the boring half of bugs (the off-by-one in the seventh branch of a switch you skimmed past).

Fuzzing is mostly preparation. Writing the harness, getting coverage instrumentation working, picking a corpus, deciding what to mutate. The actual fuzzer run is something you start before bed. Triaging the output, removing duplicates, separating the bugs you care about from the noise — that's the morning's work, and the day after, and the day after.

The CTF version of you may be allergic to fuzzing because pwn challenges are built to be solved by reasoning, not throwing inputs at the wall. That allergy is a handicap in real work. Treat the harness-writing skill as core, not as something other people do.

Patience matters more than skill

The deepest lesson, and the one nobody wants to hear: in real-world VR, patience does most of the work. The researchers who find bugs are usually the ones who kept reading code at week ten when their intuition said "give up, there's nothing here". Cleverness shows up briefly at the moment of recognition. The hours that produced the surfacing are the bulk of the work.

CTFs select for cleverness in compressed time. Real targets select for endurance over months. The change in tempo is the most under-discussed part of the transition, and the part that surprises most CTF veterans.

Where this fits in

The VR Foundations track is the bridge between the CTF muscle you've built and the real-world workflow described here. It covers target selection, scoping, harness design, variant analysis, and the slow craft of building target understanding before you start hunting. Treat it as the unwritten manual for the years between "good at pwn" and "found a real CVE".