sprintf function's buffer overflow?

拥有回忆 提交于 2019-11-30 18:13:16

It makes a lot of sense to consider what happens in your and, more importantly, similar, cases. As other posters have noted, it invokes UB. That's probably true. However, the world does not stop simply because someone did not define what exactly should happen next. And what physically happens next, may well be a major security hole.

If your string XXX... comes from uncontrolled sources, you are very close to generating a buffer overflow vulnerability.

(1) Your stack typically "grows" backwards, i.e. the smaller the addresses, the more the stack is filled.

(2) Strings expect the characters belonging to that string to be stored so that character n+1 is stored after character n.

(3) When you call a function, the return address, i.e. the address of the instruction that is to be executed after the function returns, is pushed to the stack (among other things, typically).

Now consider a stack frame of your function.

|----------------|
| buf [size 8]   |
|----------------|
| (func args)    |
|----------------|
| (other stuff)  |
|----------------|
| return address |
|----------------|

By finding out what exactly the offset between buf and the return address on the stack is, a malicious user may manipulate input to your application in a way that the XXX... string contains an address of the attacker's choosing at just the point where the uncontrolled sprintf function will overwrite the return address on the stack. (NB: Better use snprintf if it's available to you). Thereby the attacker mounted a buffer overflow attack. He might use something like the NOP sled technique to have your application start a shell for him. If you were writing an application that ran under a privileged user account, you'd just have provided an attacker with a first-grade entry to your costumer's system, an ACE hole, if you will.

Update

The run-time error you experience may well be due to an overwritten return address. Since you filled it with, basically, gargabe, the address the CPU jumped to did probably contain byte sequences that, interpreted as program text, cause an invalid memory access (or the address itself was already bad).

It should be noted that some compilers can help against these kinds of errors. GCC, for example, has the -fstack-protector. I'm not familiar with how good those features are.

The function sprintf() will write past the array as it writes in the string, and therefore invokes undefined behavior. Looking at your code, it'll probably write over the first few bytes of whatever happens to be next on the stack, or cause a runtime error, but that behavior is not guaranteed.

Undefined behavior quite literally means anything can happen. That means your code may do nothing wrong, cause a runtime error, or cause your computer to explode, win the lottery, make unicorns appear in your backyard, raise Hitler from the dead or assassinate the President of the United States. Please don't do this.

Always ensure that your character buffer has enough space to hold whatever you are sprintf()-ing into it plus an extra character for the null terminator. In general, don't try to mess around with memory spaces that are not yours.

Instead of using this method you should try using the snprintf() method as described here. This method performs essentially the same function but it allows you to control the number of characters explictly, preventing undefined behaviour (this is a good thing)

snprintf is guaranteed not to write more than size bytes into str, so use of it can help avoid the risk of a buffer overflow Wiki

You have a bug/typo in your format string. Instead of "AAAA%3s" it should be "AAAA%.3s". Field [minimum] width and field precision are very different. The former sets the minimum number of bytes the field will expand to fill. The latter (for strings) sets the maximum number of bytes that will be output; additional bytes of the string are neither inspected nor copied to the output.

"In silico" is quite right, but likely because computer kernels are much smarter then they used to be, it won't let you write into what comes after char buf[4]; and will kill your program and issue a segmentation fault signal.

This is nice because if the next piece of memory is something really important, it will be kept safe instead of crashing your computer.

And also as he said NEVER do this.

The sprintf() function facilitates unbounded copying of text, in turn leaving the buffer susceptible to overflow attack. A buffer overflow occurs when a process attemps to store more data than the boundaries allow in the fixe-length buffer.

After discovering overflow vulnerability, attackers will observe how the call obtains its user input and it is routed through the function call. Attackers can then write an exploit, which makes the software do things it would not do normally. This can range from simply crashing the machine to injecting code so that the attacker can gain remote access to the machine.

Many functins in C lead to erros if not properly used. Some functions provide alternative solutions:

Avoid      prefer
sprintf    snprintf
vsprintf   vsnprintf
strcat     strlcat
strcpy     strlcpy
strncat    strlcat
strncpy    strlcpy

Source: ECSP-Secure Programmer.

what will happen? ...

{     
    char buf[8];
    sprintf(buf,"AAAA%3s","XXXXXXXX");
    printf("%s\n",buf);
}

On Windows, you are supposed to use sprintf_s. The code should fail an audit, so it should not make it into production. For reference, see Microsoft's Writing Secure Code (Developer Best Practices). In particular, see Chapter 5.


On Linux, if the compiler and platform provides FORTIFY_SOURCE, then the code above should result in a call to abort(). Many modern Linux platforms support it, so I would expect it.

FORTIFY_SOURCE uses "safer" variants of high risk functions like memcpy, strcpy and sprintf. The compiler uses the safer variants when it can deduce the destination buffer size. If the copy would exceed the destination buffer size, then the program calls abort().

To disable FORTIFY_SOURCE for testing, you should compile the program with -U_FORTIFY_SOURCE or -D_FORTIFY_SOURCE=0.


To address @prng's comment regarding portability, strcpy_s, printf_s, sprintf_s and friends are standard C. See ISO/IEC TR 24731-1.

If the missing functionality on Linux and glibc is a problem, then you can abstract away the differences due to a crippled glibc with preprocessor macros. Regardless of what Linux and glibc does, the code does not meet minimum standards on the Windows platform.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!