Format string
- C course
- Expert
- Lesson 22/47
- 5 min
Learn the format string vulnerability.
What is the format string vulnerability?
A format string vulnerability arises when user input is passed directly as printf's first argument. Writing printf(input) lets an attacker control the format string.
With %x they can read stack values; with %n they can write to memory. The correct form is printf("%s", input), where the format string is constant. fprintf, sprintf, snprintf and syslog share the same flaw. The compiler's -Wformat-security warning catches risky uses. This bug looks simple but has been exploited many times in the wild.
Writing to memory with %n
The %n specifier writes the number of characters printed so far into a pointer. This gives an attacker a way to write to memory through printf.
For example printf("%n", &target) writes 0 into target. An attacker can use this behavior to change the return address. That is why modern systems often disable %n. In safe code the format string is always constant; user input comes only as an argument. puts or fputs is safer when no formatting is needed. The same care applies to syslog calls.
Practice Print with safe formatting
Define void safe_print(const char *fmt, const char *arg) with body printf(fmt, arg);. In main call it three times: ("%s\n", "hello"), ("%s\n", "world"), ("%s\n", "safe").
Starter code
#include <stdio.h>
// Define safe_print function
// Print three strings with "%s\n" format
int main(void) {
return 0;
}Sample solution
#include <stdio.h>
void safe_print(const char *fmt, const char *arg) {
printf(fmt, arg);
}
int main(void) {
safe_print("%s\n", "hello");
safe_print("%s\n", "world");
safe_print("%s\n", "safe");
return 0;
}Expected output
hello world safe
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 Which is a safe printf call?
- printf(input)
- printf("%s", input) Correct answer
- printf(input, &x)
- printf(input, x)
Explanation: The format string must be constant; user input comes as an argument.
2 Match format specifiers
| Term | Meaning |
|---|---|
%s |
String |
%d |
Integer |
%x |
Hexadecimal |
%n |
Count written |
3 Complete the safe printf call
printf("%s", ____);
printf("%s", name);
Explanation: name is passed as an argument; the format string is constant.