Description
A simple C program reads user input into a fixed-size buffer on the stack without bounds checking. Overflow the buffer to trigger SIGSEGV - the signal handler for the crash prints the flag.
This is the most introductory buffer overflow challenge in picoCTF 2022, requiring no return-address control - just enough bytes to crash the program.
Setup
Connect to the challenge server via netcat. No local binary is required.
Send more than 32 bytes of input to overflow the stack buffer.
nc saturn.picoctf.net <PORT_FROM_INSTANCE>python3 -c "print('A'*100)" | nc saturn.picoctf.net <PORT_FROM_INSTANCE>Solution
Walk me through it- Step 1Understand the vulnerabilityThe program uses gets() or a similarly unsafe function to fill a fixed-size buffer. No bounds check means any input larger than the buffer overflows adjacent stack space.
Learn more
Buffer overflows are the classic memory-corruption vulnerability. When a program copies user input into a stack-allocated array without checking the length, bytes beyond the array boundary overwrite adjacent memory - saved frame pointers, return addresses, and local variables of calling functions.
The C functions
gets(),strcpy(), andsprintf()are all unsafe because they perform no length validation. Modern C code should usefgets(buf, sizeof(buf), stdin)orstrncpy()instead. Thegets()function was deprecated in C99 and removed entirely in C11 for this reason.When overflowed memory contains critical control-flow data (like a saved return address), the CPU attempts to jump to a garbage address, triggering a SIGSEGV (segmentation fault). In this challenge, the SIGSEGV handler is deliberately set to print the flag - so triggering the crash is sufficient.
- Step 2Send the overflow payloadPipe ~100 bytes of 'A' into the program. The buffer is 32 bytes; anything past it spills into adjacent stack data and eventually corrupts the saved return address.python
python3 -c "print('A'*100)" | nc saturn.picoctf.net <PORT_FROM_INSTANCE>pythonpython3 -c "import sys; sys.stdout.buffer.write(b'A'*100)" | nc saturn.picoctf.net <PORT_FROM_INSTANCE>Learn more
The exact overflow size is layout-dependent: how big the buffer is, what local variables sit between it and the saved frame pointer, whether a stack canary is present, and so on. 100 bytes is a deliberately oversized blunt-force value. Anything >= 32 bytes will overrun this particular buffer; you want enough to clobber the return address regardless of layout.
If the program is whitespace-sensitive,
print()'s trailing newline can become a problem. Two trailing-newline-free alternatives:python3 -c "import sys; sys.stdout.buffer.write(b'A'*100)"orecho -n. Thebuffer.writeform also avoids any encoding surprises.Despite the description hinting at NX, NX (
checksec --filewill confirm) doesn't apply here: you're not executing your input as code. The flag is printed by the SIGSEGV handler, which runs after the crash but before the process exits. NX would only matter if you were trying to jump into your buffer. - Step 3Read the flag from the SIGSEGV handler outputThe challenge process registers a SIGSEGV handler that prints the flag and exits. Triggering the crash is the entire exploit.
Learn more
A signal handler is a function registered with
signal(SIGSEGV, handler)orsigaction. When the kernel raises SIGSEGV (memory access violation), execution jumps into the handler before the process is killed. The challenge author wired the handler to print the flag - so a clean fault is the win.In real exploitation this is the opposite of normal: signal handlers usually fight the exploit by catching the crash, logging it, and restarting the process. The challenge inverts that for didactic effect.
Flag
picoCTF{ov3rfl0ws_ar3_ez_56...}
Send more than 32 bytes to crash the program; the SIGSEGV handler prints the flag automatically.