Best of show – abuse of libc
ioccc.org
ioccc.org
Oh boy. I'll put that down for my "thing I don't think I wanted to know" of the day.
[0] Mentioned (but not directly linked) by TFA:
https://www.usenix.org/conference/usenixsecurity15/technical...
Oh boy. I'll put that down for my "thing I don't think I wanted to know" of the day.
[0] Mentioned (but not directly linked) by TFA:
https://www.usenix.org/conference/usenixsecurity15/technical...
Edit: ok, I'm guessing it's a joke about Turing completeness. Loops, you know.
> To achieve full Turing-complete computation, we need a way to loop a format string. This is possible by overwriting the pointer inside printf() that tracks which character in the format string is currently being executed. The attacker is unlucky in that at the time the “%n” format specifier is used, this value is saved in a register on our 64-bit system. However, we identify one point in time in which the attacker can always mount the attack. The printf() function makes calls to puts() for the static components of the string. When this function call is made, all registers are saved to the stack. It turns out that an attacker can overwrite this pointer from within the puts() function. By doing this, the format string can be looped.
> An attacker can cause puts() to overwrite the desired pointer. Prior to printf() calling puts(), the attacker uses “%n” format specifiers to overwrite the stdout FILE object so that the temporary buffer is placed directly on top of the stack where the index pointer will be saved. Then, we print the eight bytes corresponding to the new value we want the pointer to have. Finally, we use more “%n” format specifiers to move the buffer back to some other location so that more unintended data will not be overwritten.
[0] https://www.usenix.org/system/files/conference/usenixsecurit..., Appendix B "Printf is Turing-complete".
Perhaps a scanner than I can run against all of github, and then rank results by the number of times that code is exposed on a high value server connected to the internet...?
I don’t think it’s worth the effort to extend that to look for tainted strings, not because it wouldn’t be useful, but because it would be hard to do (as an extreme example: is data read from a file user input? It could be a file containing internationalization info)
The (relatively) few programs that construct format strings on the fly will have to add pragmas to disable these warnings.
https://www.ioccc.org/years.html#1993_dgibson
It implements Conway's Game of Life by creating a DSL using the C preprocessor and printf. The output is a program (several initial boards are supplied to bootstrap) which is the input program to be compiled and run to create the next generation. This is the program for a second generation:
LIFE
L _ _ _ _ _
L _ _ O _ _
L _ _ _ O _
L _ O O O _
L _ _ _ _ _
GEN 2 STAT 328960
END
Each symbol like "LIFE" is a macro, the board is the program.Empty comments can be ok if they're positive. There's nothing wrong with submitting a comment saying just "Thanks." What we especially discourage are comments that are empty and negative—comments that are mere name-calling.
If you think in terms of what's good/bad for community it may make more sense.
(I hope it's clear this applies whether or not the mods were mentioned in either a positive or negative way.)
https://scholar.google.com/citations?user=q4qDvAoAAAAJ&hl=en...
well this is a brainfuck interpreter inside printf. I’m pretty sure there are plenty of c-to-bf transpilers.
Oh, getting to 6 would also be fun: One might replace '[' and ']' with a conditional branch '?'. It just needs two parameters: condition and (signed) number of instructions to jump. Adds the bonus (much like normal asm) to write moch more ~~horribly abusive~~ flexible control flow than a structured "while(*ptr)".
I feel like it did LLVM IR to a bunch of languages or something like that.. but my memory is faulty.
It’s actually intentionally disallowed in some libc implementations.
Looking at old source code, the earliest implementation I found is 4.3BSD Tahoe (1988). See https://www.tuhs.org/cgi-bin/utree.pl?file=4.3BSD-Tahoe/usr/... Second oldest I found was Tenth Edition [Research] Unix (1989). See ocvt_n at https://www.tuhs.org/cgi-bin/utree.pl?file=V10/libc/stdio/vf... I couldn't find support in earlier implementations archived on that site.
You are the HN historian of the day.
> For this reason, a format argument containing %n is assumed to be untrustworthy if located in writable memory (i.e. memory with protection PROT_WRITE; see mprotect(2)) and any attempt to use such an argument is fatal. Practically, this means that %n is permitted in literal format strings but disallowed in format strings located in normal stack- or heap-allocated memory.
The manual page seems correct:
% cat test.c
#include <stdio.h>
int main(void) {
printf((char[]){ "%n" }, &(int){ 0 });
return 0;
}
% cc -o test test.c
% ./test
zsh: abort ./testAnother fun fact: glibc does this too, if you compile with -D_FORTIFY_SOURCE=2. However, since Linux lacks the nice vm_region APIs the code opens up /proc/self/maps :/
[0] should be "printf("%s", string)".
My memory wuftpd was the first big program to suffer from this class of attacks.