Sitemap

Format String Vulnerabilities

2 min readMay 8, 2025

--

Format string vulnerabilities are a classic yet relevant category of software bugs in C programs. These vulnerabilities arise when user-controlled input is unsafely passed to formatted output functions such as printf, fprintf, sprintf, or their variants. When exploited, they can lead to information disclosure, memory corruption, and in some cases, arbitrary memory write.

Below is a sample vulnerable source code.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(){

int secret = 0xdeadbeef;

char name[256];
memset(name, 0, sizeof(name)); //initialize the name char array

printf("What is your name: ");
if(!fgets(name, sizeof(name), stdin)){
exit(1);
}

printf("Hi, ");
printf(name);

return 0;
}

On a typical x86–64 architecture, the first six non-floating-point arguments to a function are passed through the following registers:

  • RDI – first argument
  • RSI – second argument
  • RDX – third argument
  • RCX – fourth argument
  • R8 – fifth argument
  • R9 – sixth argument

Therefore, when the user supplies%x, the value is taken from the second argument (RSI), not from RDI. Why? Because RDI is used to pass the format string itself, which, in this case, is user-controlled. The actual parameters that %x, %s, or %n refer to will be fetched from RSI and onward.

Get Can Özkan’s stories in your inbox

Join Medium for free to get updates from this writer.

Moreover, anything beyond the sixth argument is pulled from the stack, meaning an adversary can leak stack contents by supplying enough format specifiers (e.g., %x %x %x ...). This allows the attacker to effectively "walk the stack" and read its contents, which may reveal valuable information or enable memory write.

Press enter or click to view image in full size
Figure 1: RDI, RSI, and other registers
Press enter or click to view image in full size
Figure 2: Fetching register values thorugh format specifiers
Press enter or click to view image in full size
Figure 3: Leaking out the valuable information from the stack.
Press enter or click to view image in full size
Figure 4: a more efficient leaking input

Mitigation

To avoid format string vulnerabilities:

  • Never use user input as the format string directly.
  • Always use constant format strings, such as: printf(“%s”, user_input); // Safe
  • Use compiler flags like -Wformat with GCC or Clang to catch format string issues.
  • Consider safer alternatives likesnprintf, with proper bounds checking and format specifiers.

Thanks for reading.

Acknowledgment

The sample vulnerable code is taken from the hexdump YouTube channel.

Can Ozkan

--

--

Can Özkan
Can Özkan

Written by Can Özkan

Security Researcher, Penetration Tester, and Reverse Engineer