10 ms·
#include </etc/shadow>
- lelf 7y ago> you can include /dev/stdin in C code compiled with gcc. This is, to say the very least, surprising. Why?
- kbumsik 7y agoVirtually all Linux distributions sandbox their package build system using something like fakeroot. Before the security reason the OP mentions, they don't want to screw the build tasks because of the host environment they are running on, or they don't want to screw the host directories when they make mistakes with installation paths.
- cesarb 7y agofakeroot is not a sandbox, it's just a way to have tasks which normally expect to run as root (like setting file permissions during "make install", or creating a .tar.gz with the correct permissions) work without root. IIRC, it works through LD_PRELOAD, and it's very easy to bypass (just unset that environment variable).
- judge2020 7y agoMaybe these services run the compilation in a docker container? shadow and lsb-release exist in many images.
- stevekemp 7y agoI found a lot of online services which would do LaTeX to PDF conversion, which were running in docker containers. They would almost universally allow you to include files, and run commands on the host.
- jcrawfordor 7y agoUntrusted code execution in a Docker container is not exactly safe. Even if the runtime and container are optimally configured for security purposes (uncommon), container runtimes are not designed or particularly thoroughly evaluated for use as a security solution.
- deleted 7y ago[deleted]
- deleted 7y ago[deleted]
- Someone1234 7y agoThis seems contrived. So you need to send someone "evil" code that they won't read, have them compile it as root, and then ship you the resulting binary. I wouldn't read too much into it "working" with some kind of compile/show service, as they could have been using non-persistent containers. Ultimately this seems like social engineering i.e. "Tricking privileged users into doing <bad thing> as root." Might have well ask them to cat /etc/shadow and email you the "nonsense" it prints. https://devblogs.microsoft.com/oldnewthing/20180227-00/?p=98115 https://devblogs.microsoft.com/oldnewthing/20180227-00/?p=98...
- dvt 7y agoNot only is it contrived, it's also compiler dependent[1]. I'd wager most compilers will simply copy the contents of the included file like gcc does, but all kinds of other stuff can happen. [1] https://gcc.gnu.org/onlinedocs/cpp/Include-Syntax.html https://gcc.gnu.org/onlinedocs/cpp/Include-Syntax.html
- jessaustin 7y agoThey're talking about reading compiler errors, so there won't be a binary to ship. If we could arrange for the code to compile correctly and then be executed, we wouldn't need the binary because the program itself could just upload all the password hashes.
- jdsully 7y agoPeople compile unread code all the time. Having them send the binary back is a little unusual though. But nothing says the resulting binary can’t open its own socket when its first run. There are lots of exfiltration options. Getting them to run make as root would be pretty easy. People are already conditioned to run “sudo make install”. A good mitigation is to install software by user so root privileges aren’t needed at any step of the process.
- dTal 7y agoRestricted user accounts don't keep us secure - if you run malicious software even as a regular desktop user, there's tons of ways for it to get root, or do damage/get valuable data without it. What keeps us safe, usually, is a web of trust that involves package managers and websites. A vulnerability like this is only a problem if there is a threat model that sidesteps the usual web-of-trust mechanisms we use. In your specific variant, someone gets a source tarball from a weird place and runs 'make' as root on its Makefile - at that point, #include shenanigans are entirely redundant. Basically, what this is is a very strained local privilege escalation exploit for a workstation machine. I don't think those are very interesting because are a bazillion of them - notably you can simply drop an alias to sudo in .profile.
- slimsag 7y ago> is it equally obvious that the compiler also needs to be sandboxed? I would NEVER expect that one can run a C or C++ compiler on arbitrary input safely. There are so many potential attack vectors and, unless the authors have gone out of their way extensively to prevent them, it seems very likely they would suffer from buffer overflows, leaking memory to callers, and in the worst case arbitrary code execution. I doubt any one of these websites is safe unless using very strict validation or disposable VMs/hardware in some way.
- nneonneo 7y agoCompiling untrusted code is already a dangerous affair. Compilers are not audited for security vulnerabilities, and many versions of popular compilers have contained memory corruption bugs or similar issues that could be leveraged to gain code execution. Many services that compile untrusted code will run the resulting binaries too, which definitely requires a sandbox or disposable VM - at which point you may as well throw your whole compiler in the sandbox/VM too. I find it more likely that the "root" user mentioned in this post is the root user of some disposable Docker container, which would be the right way to run a compiler-as-a-service.
- unilynx 7y agoWell, if he saw an actual hash... there’s generally no reason a docker container should have any password hashes in /etc/shadow. Of course how a specific container is built is anyone’s guess
- mehrdadn 7y ago> I find it more likely that the "root" user mentioned in this post is the root user of some disposable Docker container, which would be the right way to run a compiler-as-a-service. My understanding is that Docker isn't something you use if you really want security.
- dharmab 7y agoYou're being downvoted but you're right- Docker really isn't a good choice for running untrusted and potentially hostile code, since a container breakout zero-day pretty much immediately compromises the host OS. (Even with user namespace remapping a breakout still gives enough access to get up to shenanigans.) At the minimum a disposable VM using something like KVM/QEMU/Firecracker would be a start. That way you have kernel isolation down to the hardware which is much less likely to be exploitable.
- anonymousDan 7y agoCan you elaborate? Doesn't a KVM bug result in pretty much the same thing? Or is the argument that this is less likely?
- jakeogh 7y agoGentoo's build system is sandboxed by default: https://wiki.gentoo.org/wiki/Project:Sandbox https://wiki.gentoo.org/wiki/Project:Sandbox
- asveikau 7y agoThis reminds me that in say, a *BSD ports tree, you end up pulling tarballs from the internet, extracting them and running make. (Granted there can be a hash on them so that's some verification) But an exploit using that would likely sooner just write something malicious in the Makefile if it wants to compromise the build machine. Targeting the compiler for such a goal seems like it would be harder.
- trasz 7y agoThere’s the mandatory hash, but generally speaking: that’s how you build software on Unix/Linux; there’s no way around it. You can do what Poudriere automatically does on FreeBSD, which is doing the whole thing in a dedicated jail.
- yori 7y ago> Recently I saw a tweet where someone mentioned that you can include /dev/stdin in C code compiled with gcc. This is, to say the very least, surprising. Why is this surprising? Do programmers not read books anymore? Almost, any decent C programming book explains that #include reads the specified file and substitutes itself with the content of that file. Any Unix/Linux book explains that /dev/stdin is a special device file that represents the standard input.
- adwn 7y ago> Why is this surprising? Do programmers not read books anymore? [...] No need to be condescending. Three reasons: 1) A sophisticated compiler might read the length of a file before loading it, so that it can allocate a buffer of the right size. Doesn't work with /dev/stdin. 2) Alternatively, it might read the file via mmap(). Doesn't work with /dev/stdin. 3) Furthermore, it might check whether the file is a regular file. If not, it is almost certainly not what the programmer had in mind.
- zonidjan 7y ago> 1) A sophisticated compiler might read the length of a file before loading it, so that it can allocate a buffer of the right size. Doesn't work with /dev/stdin. gcc does this. It appears to be why /proc files don't work. gcc sees that stat calls it a 'regular file' and 0 bytes long, and actually performs a read() syscall with a length of 0. > 3) Furthermore, it might check whether the file is a regular file. If not, it is almost certainly not what the programmer had in mind. gcc probably does this. (It would explain why /dev/stdin works)
- puzzledobserver 7y agoNeither of the individual facts is surprising. It is the juxtaposition that is. In 20 years of writing C/C++ code, I had never thought of #including files such as /dev/stdin. Of course, I know how the #include mechanism works, and what the special device files do, so I can anticipate the results of #include </dev/stdin>, but it is unusual enough that I had to write a small test program to see for myself.
- Ericson2314 7y agoNo surprise, coming from Nix!
- soraminazuki 7y agoNix won't help you secure your system from untrusted code written by internet script kiddies. It's a build tool and simply isn't designed for such things.
- Ericson2314 7y agoUm, yes it will? Linux namespeaces are linux namespaces; if you don't trust them we have bigger problems than Nix. It will certainly make sure the skids cannot do `#include </etc/password>` and get useful information, for example.
- soraminazuki 7y agoThat only works if you can turn your entire web application into a Nix build process, which is unrealistic at best. Nix is wonderful as a build tool, but it's quite a stretch to assume it's adequate for securing running applications. Plain containers, or even better, VMs are more suited for that purpose.
- Ericson2314 7y agoYour unsandboxed web application can perform a sandboxed nix build based on user input used in a very specific way. This contains the dangerous bit.
- willvarfar 7y agoIts interesting tangent that the "confused deputy" security problem was first identified in a compiler, back in the days when people paid to have their code compiled. This led towards "capabilities" and lots of operating system design that is now in vogue again. https://en.wikipedia.org/wiki/Confused_deputy_problem https://en.wikipedia.org/wiki/Confused_deputy_problem (this #include problem can be thought of as a confused deputy vulnerability. The compiler shouldn't have the capability to read the password file, and if it did, it is a confused deputy to be wielding that cap on behalf of its user, instead of wielding the caps it gets from the user). Its sad that the links to Norm Hardy's original write-up all seem broken. https://web.archive.org/web/20031205034929/http://www.cis.upenn.edu/~KeyKOS/ConfusedDeputy.html https://web.archive.org/web/20031205034929/http://www.cis.up... Norm was a brilliant mind. He was talking and thinking about capabilities right up until the end.
- chmaynard 7y agoHenry Levy's 1984 book "Capability-Based Computer Systems" -- a survey and description of early object-based and capability-based processors and operating systems -- is available here: https://homes.cs.washington.edu/~levy/capabook/index.html https://homes.cs.washington.edu/~levy/capabook/index.html
- julien_p 7y agoThis talk https://talks.golang.org/2019/playground-v3/playground-v3.slide#1 https://talks.golang.org/2019/playground-v3/playground-v3.sl... on the golang playground has some details on its security considerations.
- pvtmert 7y ago- most of them (actually) containers - one can easily do: ``` char buf[8192]; fread(buf, sizeof(buf), 1, fopen("/etc/shadow", "rb")); printf(buf); ``` also reading 'shadow' is not do that much since its salted and hashed. strong password (10 chars) will take many months and years. you can do more harm with actual 'code' which you may compile on the service
- jdoerfert 7y agoThe godbolt compiler explorer, which is awesome btw, had to tackle all sorts of problems like this. I think there is a talk on YouTube that goes into some detail.
- zonidjan 7y ago> Recently I saw a tweet where someone mentioned that you can include /dev/stdin in C code compiled with gcc. This is, to say the very least, surprising. You can also call something to read from stdin in your Makefile, or read from stdin in your executable. > But is it equally obvious that the compiler also needs to be sandboxed? Yes. Why wouldn't it be sandboxed?! > I even found one service that ... showed me the hash of the root password. Wow. That's bad. Of course, that's not a compiler issue, but rather a system administration issue. /etc/shadow should not be world-readable. > This effectively means this service is running compile tasks as root. That's quite a leap from 'I can read /etc/shadow' to 'I am root'. > Interestingly, including pseudo-files from /proc does not work. It seems gcc treats them like empty files. More accurately, it seems the system treats them like empty files. gcc does a stat on the file, which returns 'regular file' and 'size=0'. gcc therefore calls read() with a length of 0 bytes.
- simias 7y ago>That's quite a leap from 'I can read /etc/shadow' to 'I am root'. Is it? There are alternatives of course but I would say that without further clues that seems the most likely explanation. I agree with the rest of your points though. In general it seems fairly obvious that build systems should be sandboxed if they're building "foreign" code, after all if you can mess with the source code you can probably affect the build system as well, and from there you can basically do anything you want.
- softwarelimits 7y agoIf that was my server I would of course put a joke in /etc/shadow - did you try to brute force the hashes? It would not be a great surprise to find some obvious funny content if you try?
- boop-the-snoot 7y agoThat'd be pretty funny :D Like for example, if the entry for root in the joke /etc/shadow was the hash of "Thank you Mario! But our princess is in another castle!"
- softwarelimits 7y agoDid you try this on an up2date Linux OS, like eg Debian or Ubuntu? What was your result? Certainly as a real hacker you are not only re-posting "things from the news" but validate everything before posting any comments? Are you? I did not see any relevant content on the websites you mention in your HN profile, I expected some in-depth security publications - maybe update it with some real code that shows us how you are using the mentioned CVE-2019-14378 to perform escapes on any KVM host? Thanks!
- mulle_nat 7y agoWhy would '/' ever be in the searchpath of the compiler ? This looks like a preprocessor bug to me.
- penagwin 7y agoCounter point, why should '/' be invalid? I'm not saying it's good practice or that the compiler shouldn't warn you, but "/home/me/path_to_thing/file" is a perfectly valid path.
- mulle_nat 7y agoAn absolute path is a valid path on the filesystem. But the compiler should be searching according to its implementation dependent search paths, when doing <>. Not prepending the searchpath (and not rejecting) for absolute paths is an implementation choice I personally think is wrong for a C compiler. But it may be able to do so I guess as you can also do "..".
- eb0la 7y agoI was wondering if it there is a _practical_ attack that stores the content of a file into a string, char array, etc.. Looks that it's not that easy unless the file is formatted in a special way: https://stackoverflow.com/questions/410980/include-a-text-file-in-a-c-program-as-a-char https://stackoverflow.com/questions/410980/include-a-text-fi... (sorry for the stack overflow link - my C/C+ is rusty to say politely)
- cesarb 7y agoIf the output from the compiler is a binary object (.o) instead of the assembly (.s), I'd use gcc's inline assembly extension to call the GNU assembly ".incbin" directive (plus the necessary directives to put it in the correct section with an exported symbol).
- didymospl 7y agoOn a related note, the XML standard defines a way to include external files in the document. If you come across a service which replies with a part of your request(e.g. validation errors) and uses XML parser with this feature turned on, which is true by default in many cases, this can be used to read arbitrary files. I wonder how many poorly maintained enterprise systems systems are vulnerable to that. https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Processing https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Pr...
- amlozano 7y agoAbout a year and a half ago it was a very common vulnerability to find when doing web application assessments. Especially if uploading Excel spreadsheets was somehow involved. Its less common now that most major parsers are turning this feature off by default though.
- Sohcahtoa82 7y agoXXE is a feature that never should have happened. Whoever decided that not only should it be a thing, but that it should be enabled by default, needs to have their keyboard taken away.
- fwsgonzo 7y agoYou can compile and execute C/C++ code in my little hobby project: https://droplet.fwsnet.net/ https://droplet.fwsnet.net/ It's something I use to measure certain things, like how many instructions does a C++ exception add etc. It's run in a docker container, and I think I strip out any slashes from includes. I'm pretty sure the container is not executing stuff as root as well. Still, probably not bulletproof.
- hag 7y ago`#include </etc/lsb-release>` gave some interesting errors. Looks like it's running Ubuntu.
- shawabawa3 7y agoYou aren't stripping slashes. I tried `#include </dev/urandom>` and it eventually crashes the container failing to allocate memory (looks like they have a 4GB limit?)
- fwsgonzo 7y agoHaha, that's clever. Yes, it's a 4GB limit. Guess I'll try to fix that again. EDIT: fixed
- ajor 7y agoStill some workarounds to the slash-stripping: #include "\ /etc/passwd" program221/code.cpp:1:11: warning: backslash-newline at end of file 1 | #include "\ | In file included from program221/code.cpp:2: /etc/passwd:1:5: error: found ':' in nested-name-specifier, expected '::' 1 | root:x:0:0:root:/root:/bin/bash | ^ | :: /etc/passwd:1:1: error: 'root' does not name a type 1 | root:x:0:0:root:/root:/bin/bash | ^~~~ Is it possible to restrict the compiler's access to only files in "/usr/include" instead? Seems like it'd be hard to cover every case with just pattern matching.
- fwsgonzo 7y ago
- shrimpx 7y agoThe author thinks they stumbled onto a discovery: > There are plenty of webpages that offer online services where you can type in C code and run it. It is obvious that such systems are insecure if the code running is not sandboxed in some way. But is it equally obvious that the compiler also needs to be sandboxed? Yes it's equally and painfully obvious.
- deleted 7y ago[deleted]
- softwarelimits 7y agoYou wrote something interesting, unfortunately you accidentally hit the "reply" button before you could insert some URLs that would add some substance to your words. I am sure you know that words without evidence are of no value on the internet and it will kill your reputation, so I am waiting until you get online again and send some examples. Please post some currently working code for escaping XEN, KVM, also VMWare and Virtualbox may be of interest, thanks! I could not find any relevant content on the website you publish in your profile - btw it seems to be a bit broken, maybe go into webdev a little bit after you finished the code for the VM exploits?
- jedisct1 7y agoAnd in Rust you can use the `include_str!()` macro to include any file. Works well on the Rust playground and pretty much everywhere else: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=856359950728b28e9e7ea98a81d15b0b https://play.rust-lang.org/?version=stable&mode=debug&editio... If procedural macros are available, they can also be abused to run arbitrary code.
- fnord77 7y agoand if you look at this file "/proc/1/cgroup" you'll see that it is isolated in a docker container
- fnord77 7y ago> and showed me the hash of the root password. This effectively means this service is running compile tasks as root. Or in a docker container.
- danmg 7y agoIf you can include /etc/shadow you can also just cat it. curl|sh software installations are far more of a threat than potentially a malicious c per-processor statement.
- dylan-m 7y agoSandboxing your build is good practice anyway, for this and many other reasons :) For bonus points, build each major component in its own sandbox and integrate them later. That allows you to tightly control your dependencies (which makes your project tidier and makes incremental builds faster), and it paves the way to reproducible builds.
- dward 7y agoSee also std::embed.
- notaplumber 7y agoThis isn't limited to C. If you run compiles as root, game over. fn main() { let shadow = include_str!("/etc/shadow"); println!("{}", shadow); } That's why OpenBSD ports clusters uses unprivileged users for fetching and building (with no network access/chroot).
- m463 7y agoYou used to be able to click on a link like file:///etc/passwd and it would show up in the browser.