15

According to an article I just read, the functions printf and strcpy are considered security vulnerabilities due to Buffer overflows. I understand how strcpy is vulnerable, but could someone possibly explain how/if printf is really vulnerable, or I am just understanding it wrong.

Here is the article: https://www.digitalbond.com/blog/2012/09/06/100000-vulnerabilities/#more-11658

The specific snippet is :

The vendor had mechanically searched the source code and found some 50,000-odd uses of buffer-overflow-capable C library functions such as “strcpy()” and “printf().”

Thanks!

DarkMantis
  • 746
  • 1
  • 7
  • 19
  • 3
    If you are interested in this topics I suggest you to read [*Hacking: The Art of Exploitation*](http://www.amazon.com/Hacking-The-Art-Exploitation-Edition/dp/1593271441) by Jon Erickson. Chapter three contains a working exploit using the [format string vulnerability](http://en.wikipedia.org/wiki/Uncontrolled_format_string) of `printf`. – Bakuriu Oct 09 '13 at 20:07
  • Sure I understand the format string vulnerabilities, from what I've read at least. However, I was under the impression that the function itself was somehow exploitable (even if it was used as intended). – DarkMantis Oct 09 '13 at 20:58
  • 5
    Seen another way, *C/C++* itself is a buffer overflow vulnerability. All that direct toying with memory... – LateralFractal Oct 10 '13 at 02:05
  • I have faced similar situation for integer buffer where I can't access main() function in C. I am searching for an answer (https://stackoverflow.com/questions/61715941/addresssanitizer-error-while-accessing-value-of-a-memory-address-though-printf) – Tajuddin Khandaker May 10 '20 at 17:28

4 Answers4

23

It is possible to have issues with printf(), by using as format string a user-provided argument, i.e. printf(arg) instead of printf("%s", arg). I have seen it done way too often. Since the caller did not push extra arguments, a string with some spurious % specifiers can be used to read whatever is on the stack, and with %n some values can be written to memory (%n means: "the next argument is an int *; go write there the number of characters emitted so far).

However, I find it more plausible that the article you quote contains a simple typographical mistake, and really means sprintf(), not printf().

(I could also argue that apart from gets(), there is no inherently vulnerable C function; only functions which need to be used with care. The so-called "safe" replacements like snprintf() don't actually solve the problem; they hide it by replacing a buffer overflow with a silent truncation, which is less noisy but not necessarily better.)

Tom Leek
  • 168,808
  • 28
  • 337
  • 475
  • 1
    I've even seen argued (with some merit) that `gets` is not inherently vulnerable either. For example, if a program calls `gets` to read back data that it wrote, it may be guaranteed that the data fits in the buffer. For a file this is not robust but may be correct; for a self-pipe it could even be robust. – Gilles 'SO- stop being evil' Oct 09 '13 at 18:37
  • 3
    Slightly off-topic, but I do not agree at all with your comment regarding `snprintf`: it is difficult to use `sprintf` in a secure manner (and practically impossible if you use a `%s` format specifier), but `snprintf`, when used correctly, is safe: when snprintf truncates the input, because its size exceeds the buffer, it is not silent but tells you by giving a return value equal to the buffer size. – AardvarkSoup Oct 10 '13 at 11:10
6

In addition to the answer by @Tom, I would also like to guide you to the OWASP code review guidelines, where some issues on using printf() are highlighted and this answer to a similar question on cs.stackexchange website.

Jor-el
  • 2,061
  • 17
  • 24
4

Here is an example that shows how this overflow can help you. Imagine you don't have access to the private members (pwd for example) so printf will help you see the content of this variable

#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;

struct SecureLogin{
    SecureLogin(const char * login_)
    {
        strcpy(login,login_);
        strcpy(pwd,"ijk");//the user does not see this part of the source code as it is in a DLL
    }
    char login[8];
private:
    char pwd[8];

};


int main() {
    // your code goes here
    SecureLogin log("abc");
    printf("Pwd = %s\n",(&log.login[0])+8);
    // Pass a string address which is the base address of the login
    // field, but add 8 bytes, which skips onto the pwd field (we know
    // login is 8 bytes)
    return 0;
}

Output:

Pwd = ijk

Gabriel
  • 149
  • 5
2

Some printf directives (ie; %n) have side effects to addresses found on the stack, so print directives can be dangerous, even if the explicit output is implemented correctly.

ddyer
  • 1,974
  • 1
  • 12
  • 20