Format String Vulnerability: Reading Memory Without Buffers
Challenge 3: Format String Vulnerability Analysis (3_simple.c
)
Source Code:
#include <stdio.h>
int main() {
char name[32] = {0};
printf("What is your name: \n");
read(0, name, 32);
printf(name); // Format string vulnerability
return 0;
}
// Compiled: gcc -Wall -Wextra -Iinclude -g -fno-stack-protector -no-pie -Wl,-z,norelro -o bin/3_simple src/3_simple.c
Vulnerability Description
The 3_simple.c
program contains a format string vulnerability on line 7:
printf(name);
This is unsafe because the user-controlled input name
is passed directly as the format string to printf()
without a format specifier.
How the Vulnerability Works
- The program reads up to 31 bytes of user input into a 32-byte buffer
name
- The input is then passed directly to
printf()
as the format string - An attacker can include format specifiers like
%x
,%s
,%n
in their input to:- Read memory:
%x
reads values from the stack - Read arbitrary memory:
%s
treats stack values as pointers and dereferences them - Write to memory:
%n
writes the number of characters printed so far to a memory location
- Read memory:
Example Exploit
Input like %x %x %x %x
would leak stack values, potentially revealing:
- Return addresses
- Stack canaries
- Pointer values
- Other sensitive data
Other Vulnerable Functions
The following functions are also vulnerable to format string attacks when user input is passed as the format string:
Standard Library Functions:
printf(user_input)
- prints to stdoutfprintf(file, user_input)
- prints to a filesprintf(buffer, user_input)
- prints to a string buffersnprintf(buffer, size, user_input)
- prints to a string buffer with size limitvprintf(user_input, args)
- variadic version of printfvfprintf(file, user_input, args)
- variadic version of fprintfvsprintf(buffer, user_input, args)
- variadic version of sprintfvsnprintf(buffer, size, user_input, args)
- variadic version of snprintf
System Logging Functions:
syslog(priority, user_input)
- system loggingerr(eval, user_input)
- error reportingerrx(eval, user_input)
- error reporting without errnowarn(user_input)
- warning messageswarnx(user_input)
- warning messages without errno
Mitigation
Always use a format specifier when printing user-controlled data:
// Vulnerable
printf(name);
// Safe
printf("%s", name);
Try it yourself with my Github Repo - Exploit Development Step-by-Step There you are able to check the whole code and also the full exploit script.