Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add section about printf exploits #241

Open
Flakebi opened this issue May 3, 2024 · 4 comments
Open

Add section about printf exploits #241

Flakebi opened this issue May 3, 2024 · 4 comments

Comments

@Flakebi
Copy link

Flakebi commented May 3, 2024

printf can be used for exploits if an attacker controls the format string:

char *input = ; // attacker controlled
print(input);

There are three main format options that can be used for exploitation, the first two are well-known, the third one is rather esoteric, but essential for exploiting:

  1. "%p" leaks argument registers and stack memory.
  2. "%s" dereferences a pointer (in argument registers or on the stack) and leaks the memory until the first zero-byte in memory.
  3. "%n" writes to a pointer (from argument registers or on the stack).

Different registers or memory can be leaked by repeating format options, e.g. "%p %p %p %p %p %p %s".
POSIX (and therefore glibc) supports argument reordering, allowing to replace the repetition by "%5$p" to print the 5th argument and jumping back and forth between arguments.

Now to the most important format option, "%n". When %n is found in a format string, printf interprets the argument as a pointer and writes the number of printed characters so far to this pointer.
This makes a nice write gadget, as the written number can be controlled by prepending garbage output of the needed length, e.g. with "%100p%n" to write a 100. The size of the written value can be controlled by specifying a precision for "%n".

With this much, we still need a pointer on the stack that points to something useful which we want to overwrite. Luckily, one possibility that is always there are frame pointers, which conveniently point directly to another address that is also located on the stack.
A possible pattern is, use a frame pointer to overwrite the few least-significant bytes of the next frame pointer with a controlled value, making this second frame pointer point to a controlled location. A second "%n" in the string makes use of the second frame pointer to overwrite a more interesting memory location.

If there are two or more attacker controlled printfs in a row (or a loop of them), the first one can be used to leak information about stack layout, existing pointers and so on (leaking a return address breaks ASLR). The second printf can then be used to change the memory content based on the leaked information.

@kbeyls
Copy link
Member

kbeyls commented May 6, 2024

@all-contributors please add @Flakebi for bug, ideas

Copy link
Contributor

@kbeyls

I've put up a pull request to add @Flakebi! 🎉

@kbeyls
Copy link
Member

kbeyls commented May 6, 2024

Thank you for sharing this idea to also write about printf-based vulnerabilities!
Would you happen to also have any pointers to how compilers help mitigate against exploits using these vulnerabilities?

@Flakebi
Copy link
Author

Flakebi commented May 6, 2024

clang has a warning for this (-Wformat-security, seems to be on by default; gcc didn’t complain on this code):

<source>:31:12: warning: format string is not a string literal (potentially insecure) [-Wformat-security]
   31 |     printf(argv[0]);
      |            ^~~~~~~
<source>:31:12: note: treat the string as an argument to avoid this
   31 |     printf(argv[0]);
      |            ^
      |            "%s", 

Relatedly, I just found the owasp site for format string attacks, but it doesn’t have that much information: https://owasp.org/www-community/attacks/Format_string_attack

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants