A format string attack, at its simplest, is this:
char buffer[128];
gets(buffer);
printf(buffer);
There's a buffer overflow vulnerability in there as well, but the point is this: you're passing untrusted data (from the user) to printf (or one of its cousins) that uses that argument as a format string.
That is: if the user types in "%s", you've got an information-disclosure vulnerability, because printf will treat the user input as a format string, and will attempt to print the next thing on the stack as a string. It's as if your code said printf("%s");. Since you didn't pass any other arguments to printf, it'll display something arbitrary.
If the user types in "%n", you've got a potential elevation of privilege attack (at least a denial of service attack), because the %n format string causes printf to write the number of characters printed so far to the next location on the stack. Since you didn't give it a place to put this value, it'll write to somewhere arbitrary.
This is all bad, and is one reason why you should be extremely careful when using printf and cousins.
What you should do is this:
printf("%s", buffer);
This means that the user's input is never treated as a format string, so you're safe from that particular attack vector.
In Visual C++, you can use the __Format_string annotation to tell it to validate the arguments to printf. %n is disallowed by default. In GCC, you can use __attribute__(__printf__) for the same thing.
Protection from Format String Vulnerability - Stack Overflow
c++ - Is `std::format` vulnerable to format string attack? How to mitigate it? - Stack Overflow
How exactly do format string vulnerabilities works [C]?
Format string attack
As you found, %x will pop bytes off the call stack. %08x will print 4 bytes and you can enter multiples of these to walk up the stack.
You now have addresses on the stack and you can print the contents of that memory with %s.
By chance have you tried %n? It should cause a write.
Check this paper for more info https://cs155.stanford.edu/papers/formatstring-1.2.pdf
More on reddit.comVideos
A format string attack, at its simplest, is this:
char buffer[128];
gets(buffer);
printf(buffer);
There's a buffer overflow vulnerability in there as well, but the point is this: you're passing untrusted data (from the user) to printf (or one of its cousins) that uses that argument as a format string.
That is: if the user types in "%s", you've got an information-disclosure vulnerability, because printf will treat the user input as a format string, and will attempt to print the next thing on the stack as a string. It's as if your code said printf("%s");. Since you didn't pass any other arguments to printf, it'll display something arbitrary.
If the user types in "%n", you've got a potential elevation of privilege attack (at least a denial of service attack), because the %n format string causes printf to write the number of characters printed so far to the next location on the stack. Since you didn't give it a place to put this value, it'll write to somewhere arbitrary.
This is all bad, and is one reason why you should be extremely careful when using printf and cousins.
What you should do is this:
printf("%s", buffer);
This means that the user's input is never treated as a format string, so you're safe from that particular attack vector.
In Visual C++, you can use the __Format_string annotation to tell it to validate the arguments to printf. %n is disallowed by default. In GCC, you can use __attribute__(__printf__) for the same thing.
In this pseudo code the user enters some characters to be printed, like "hello"
string s=getUserInput();
write(s)
That works as intended. But since the write can format strings, for example
int i=getUnits();
write("%02d units",i);
outputs: "03 units". What about if the user in the first place wrote "%02d"... since there is no parameters on the stack, something else will be fetched. What that is, and if that is a problem or not depends on the program.
An easy fix is to tell the program to output a string:
write("%s",s);
or use another method that don't try to format the string:
output(s);
a link to wikipedia with more info.
I would like to know more about if
std::formatis vulnerable, and how to mitigate it, even if I have to format user provided strings.
Even if you use std::vformat (which accepts a run-time string), the input is verified against the types of the other arguments and std::format_error is raised upon mismatch (while std::format verifies this at the call site during compile time).
So a malicious user cannot sneak in a format specifier for an argument you did not provide. And since the formatter that is used for an argument must be based on its static type (and so also provided by you), an attacker cannot try punning.
All in all, that vector of attack seems blocked.
std::format, like printf/etc., assumes that the format string is from a trusted source. A malicious format string for std::format can't usually cause the same specific problems as one for printf/etc. (implicit type punning, buffer overruns, etc.), though std::format has some customization support which potentially enables such problems (and others).
If you want to use std::format, then you need to make sure that the format string is OK, either by writing it yourself or by validating that it has the specific form you expect.