Description
Picker IV is now compiled. It prompts for an address and jumps there directly, so feeding it the address of win() immediately prints the flag.
Setup
Fetch both picker-IV and picker-IV.c so you can review the logic or compile locally.
Use objdump or Ghidra to locate the address of win().
wget https://artifacts.picoctf.net/c/529/picker-IV.cwget https://artifacts.picoctf.net/c/529/picker-IVobjdump -D picker-IV | lessSolution
- Step 1Resolve win()Disassembling the binary shows win at 0x40129e. Because the service naively jumps to any address you supply, that value is all you need.
Learn more
objdump is a standard GNU binutils tool that displays information about object files and binaries. The
-Dflag disassembles all sections, converting the raw machine code back into assembly instructions. Looking for thewinsymbol in the output reveals its address in the binary's virtual address space - the address where execution must jump to trigger the flag-printing code.Function addresses in a compiled binary are fixed when the binary is not position-independent (no PIE). A PIE (Position-Independent Executable) binary uses randomized base addresses (ASLR) each time it runs. When PIE is disabled, every function always loads at the same virtual address, making exploitation predictable and straightforward. You can check with:
file picker-IV- a PIE binary will say "shared object" while a non-PIE will say "executable."Alternative tools for finding win():
nm picker-IV | grep win- list symbols and filter for winreadelf -s picker-IV | grep win- inspect ELF symbol tablegdb picker-IVthenp win- GDB prints the address- Ghidra - full GUI decompiler with cross-reference analysis
- Step 2Send the address remotelyConnect to the provided host and type 40129e when prompted. The binary adds the 0x prefix internally and jumps straight into win().
printf "40129e\n" | nc saturn.picoctf.net 56193Learn more
The vulnerability here is arbitrary code execution via user-controlled function pointer. The program reads an address from the user and calls it as a function pointer with no validation. This is a fundamental category of memory-safety bug. In more realistic exploits, this kind of control over the instruction pointer is achieved through buffer overflows, use-after-free, or format string vulnerabilities - but the core concept is the same: redirect execution to code you want to run.
printf "40129e\n" | ncuses a pipeline to pipe the input directly into netcat, automating what would otherwise be a manual copy-paste. The\nsimulates pressing Enter. This pattern - scripting interactive program input - is the foundation of exploit development with pwntools:io.sendline(b"40129e")does the same thing in Python.ASLR and PIE are the main defenses against this type of attack in real systems. ASLR (Address Space Layout Randomization) randomizes where the stack, heap, and libraries are loaded. PIE randomizes the base address of the executable itself. Together, they prevent an attacker from knowing the address of
win()without a separate memory leak vulnerability. This challenge deliberately disables both, making the address static. - Step 3Copy the flagwin() prints the picoCTF flag directly, so no extra decoding steps are required.
Learn more
win() functions are a classic CTF pattern - a function that prints the flag exists in the binary but is never called in normal execution flow. The challenge is to redirect execution to it. This mimics real-world scenarios where privileged code paths exist (admin panels, debug functions, backdoors) that an attacker wants to reach by subverting normal control flow.
In the Picker series (I through IV), the challenge progressively restricts how you can invoke win(): Picker-I allows calling it by name through eval, Picker-II adds a filter on the function name, Picker-III encodes the name, and Picker-IV compiles the binary so you must work with raw addresses. This progression teaches a core binary exploitation concept: control flow hijacking - the art of making a program execute code at an address of your choosing.
Beyond CTFs, this concept underlies real exploits. Return-oriented programming (ROP) chains together "gadgets" (short instruction sequences ending in
ret) to build arbitrary computation entirely from code that already exists in the binary and its libraries - a sophisticated evolution of the simple "jump to win()" technique demonstrated here.
Flag
picoCTF{n3v3r_jump_t0_u53r_5uppl13d_4ddr355...1af4}
Because there is no validation on the destination address, pointing execution at win() is trivial.