{
char buf[8];
sprintf(buf,"AAAA%3s","XXXXXXXX");
printf("%s\n",buf);
}
what will happen?
The buffer have 8 characters space and only 3 free characters left, however, "XXXXXXXX" is 8 characters long.
I take a test with Visual Studion 2008 on Windows 7. As a result, the program printed:AAAXXXXXXX, and a run-time error happened.
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)
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.
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 theXXX...
string contains an address of the attacker's choosing at just the point where the uncontrolledsprintf
function will overwrite the return address on the stack. (NB: Better usesnprintf
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."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.
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
andsprintf
. 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 callsabort()
.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.
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:
Source: ECSP-Secure Programmer.