5 ms·
displayln is a _Generic. All of these are valid: displayln("Hello, World!"); displayln(100); displayln(1.8); The point is, for simple things, to
by shakna 7y ago
displayln is a _Generic.
All of these are valid:
displayln("Hello, World!");
displayln(100);
displayln(1.8);
The point is, for simple things, to not have to specify how they appear.
> Well... Because it should have been
> printf("Hello, World!\n");
No. You don't really want to do that. If you're doing that, use puts [0] . All this requires is a modification to one string in memory and you have an injection vulnerability.
[0] http://www.cplusplus.com/reference/cstdio/puts/ http://www.cplusplus.com/reference/cstdio/puts/
- temac 7y agoIf the string was in a variable, yes, but in this case most implementations will put it in a RO section.
- shakna 7y agoThat'll be depending on undefined behaviour, though, correct?
- simias 7y agoThat's not UB, that's implementation dependent, AFAIK the C standard says nothing about read-only memory. Attempting to modify a string literal is indeed UB but that would only happen if an attacker managed to attempt to modify the string, not when the program is used normally.
- shakna 7y ago> That's not UB, that's implementation dependent, AFAIK the C standard says nothing about read-only memory. If we're being pedantic, it's _unspecified behaviour_. The implementation isn't required to document how it would behave.
- shawnz 7y agoOther important security features like N^X are also not specified in the C standard either, so what's the point of worrying about just printf format strings?
- ryandrake 7y agoTBH it’s not pedantic to understand the difference between undefined, implementation-defined, and unspecified behavior. It’s part of knowing the language. One of my standard interview questions for C candidates is to ask them to describe and provide an example of each.
- Dylan16807 7y agoIs there really a meaningful difference between implementation-defined and unspecified? I'd say they're shades of gray based on how pedantic the compiler documentation is.
- temac 7y agoIs it really not UB to attempt to modify RO things? Typically (on major implementations, e.g. GNU/Linux or MSVC/Windows) it will crash, and I don't think it is allowed to crash on non-UB things?
- ddalex 7y agoCan you please exemplify how you exploit a printf("Hello, World!\n") ?
- shakna 7y agoThat's a format string attack [0]. By modifying the start of that string, you can begin reading and writing to various parts of the stack. Whilst implementations may inline that string into a RO memory region - that's not defined behaviour, so you shouldn't depend on it. [0] https://owasp.org/www-community/attacks/Format_string_attack https://owasp.org/www-community/attacks/Format_string_attack
- dezgeg 7y agoBy that same logic, puts("Hello, world!"); is also vulnerable to DoS attack and information leak since someone could have removed the NUL terminator at the end of the string and have puts() read uninitialized/unmapped memory. Which is absurd logic.
- shakna 7y agoFormat string attacks have occurred in the wild. [0] > Originally thought harmless, format string exploits can be used to crash a program or to execute harmful code. They are not the same as puts. Puts can allow you to potentially read memory. A format string attack can allow you to write to memory. [0] https://en.wikipedia.org/wiki/Uncontrolled_format_string https://en.wikipedia.org/wiki/Uncontrolled_format_string
- scatters 7y agoSo an attacker able to write to memory would be able to elevate into the ability to... write to memory. That doesn't sound particularly worrisome.
- nocturnial 7y agoIn a lot of cases the attacker can only write to a limited range of memory addresses. If that string happens to fall in that range, they can use it to write to other addresses and/or find out where in memory certain things are stored. So their ability to write to a limited range of addresses can be extended to a larger range.
- senozhatsky 7y ago> No. You don't really want to do that. If you're doing that, use puts This is not the case for RO strings, is it?
- shakna 7y agoYou're not guaranteed to have a RO string by the standard are you?
- senozhatsky 7y agoGood point. I suppose that you are talking about overwriting terminating NUL, do I get it right? puts() is vulnurable in exactly same way.
- shakna 7y agoNo, a format string attack. If you replace the start of the string with various specifiers, you can lift out pointer addresses and write to them. You can't do that with puts. Worst you can do with puts is read.
- senozhatsky 7y agoOK, understood. So what you meant was more like puts()'s attack surface is smaller than printf()'s. This is not how your message appeared to me - "printf() is vulnerable to injections, use puts() instead". Both are vulnerable to "unintended read()-s".
- shakna 7y agoNot really. printf is vulnerable to both read and _write_ attacks when you misuse it by only supplying the single argument. It's vulnerable to injections that can lead to remote execution and all sorts of CVEs. puts is sometimes vulnerable to read attacks, but not often.
- simias 7y agoGCC automatically replaces printf("foo\n") with puts("foo") even with -O0. Clang does it too, albeit I have to enable optimizations: https://godbolt.org/z/drw4xP https://godbolt.org/z/drw4xP . As a result I never use puts for literal strings, this way if I want to add dynamic parameters later I don't have to change the function call. I'm pathologically lazy. Also as others point out typically the literal string will be in a ro segment so tampering with it won't be easy unless the code runs in a rather exotic environment.
- juped 7y agoThe good practice that you seem to have read about and badly misunderstood is that the format string argument to a printf family function should always be a string literal right there in the code calling it. The concept of changing printf("foo") to printf("%s", "foo") for 'security' against your own hardcoded string literal is more bizarre than any of the intentionally bizarre convolutions in your posted project.