5

Can a non-sanitized user input result in a vulnerability if passed to System.out.printf (Or any equivalent function that takes a format)?

Example:

public class Demo {
    public static void main(String[] args) {
        String userInput = "%n";
        System.out.printf(userInput);
    }
}

If this was C for example, that would be a huge security issue, however in Java, the only thing that can be done here is injecting a new line using "%n" ? Is there something I'm missing here?

1
  • Generally, no. The JVM (the ones that interprets and translate code to bycote) provides at least 3 layers of security.
    – Full Array
    Jan 13 at 1:24

2 Answers 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.

1
  • Good analysis. Still, while the risk of a user-controlled format string is low, I see no benefit. So just as a general precaution, I think user-controlled format strings should still be avoided.
    – sleske
    Dec 1, 2023 at 12:09
1

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:

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .