User: Password:
|
|
Subscribe / Log in / New account

Spengler: False Boundaries and Arbitrary Code Execution

Spengler: False Boundaries and Arbitrary Code Execution

Posted Jan 5, 2011 14:07 UTC (Wed) by jchaxby (subscriber, #63942)
Parent article: Spengler: False Boundaries and Arbitrary Code Execution

Years ago, longer than I like to think, about 6 of the 32 VMS capabilities would allow you to acquire all of them: change-mode-to-kernel and set-privileges are the two I can remember now. There's nothing new under the sun is there?

This potential privilege escalation isn't there so much as to prevent programs from getting real-uid == 0 as to prevent them doing something unintended, somewhat akin to accidentally rebooting the machine.


(Log in to post comments)

Spengler: False Boundaries and Arbitrary Code Execution

Posted Jan 5, 2011 15:51 UTC (Wed) by cesarb (subscriber, #6266) [Link]

He is also assuming that the attacker has full control under whatever privileges the daemon has.

If, for instance, the daemon has a bug which allows you to write to an arbitrary path, and it does not have DAC_OVERRIDE and is not running as root, you cannot use that directly to for instance overwrite /etc/shadow. Instead, you have to first find another bug in the daemon (perhaps first writing to some file it will read and misinterpret) to be able to execute arbitrary code under the daemon's privileges. Only then you can exploit the capabilities as he described.

To explain in another way: you have a barrier (the daemon itself) which should pass nothing but accidentally lets pass B and D. The capabilities the daemon has allow it to do A and C. Unless you can own the daemon (thus being able to do anything it can do), you cannot pass the combined barrier, unless the holes happened to align (both the daemon and its capabilities allowed you to do E, for instance).

Spengler: False Boundaries and Arbitrary Code Execution

Posted Jan 5, 2011 16:09 UTC (Wed) by drag (subscriber, #31333) [Link]

> He is also assuming that the attacker has full control under whatever privileges the daemon has.

Yes.

That is the point.

The idea behind capabilities is that you can reduce the exploit potential of bugs in otherwise setuid programs. Both Fedora and Ubuntu are expressing interest in eliminating their set of 'setuid by default' programs and replacing it with capabilities system for that expressed purpose.

The theory is that if you get rid of setuid privileges and use capabilities instead then if programs end up having a bug then you won't be handing over full root access.

Spender was pointing out that out of 20 of 35 capabilities offered by the Linux kernel provide little security benefit over just making the binaries 'setuid root' since those capabilities alone are enough to gain full root access. (remember that probably 15 capabilities are relatively safe to delegate and provide advantages over just using setuid root permissions)

The idea is that there remains quite a lot of work to hardening those capabilities to make them safe for their expressed purpose, if that is even possible. (apparently capabilities with PAX can solve most of the issues)

It is important that as administrators that everybody has a good understanding of what is a 'safe' capability versus potential vulnerabilities you may be opening yourself up to if you use them.

Spengler: False Boundaries and Arbitrary Code Execution

Posted Jan 5, 2011 17:17 UTC (Wed) by farnz (subscriber, #17727) [Link]

It depends; even the 20 capabilities that Spender points out are still an improvement on suid root binaries. As cesarb correctly points out, while a daemon running with one of those 20 capabilities is still potentially as dangerous as a suid root binary, there are cases where a bug would allow a daemon running as root unlimited ability to do harm, yet merely permit the capabilities variant to DoS the daemon in question.

As with so much in security, capabilities are not a silver bullet; 15 of them genuinely appear to limit an attacker's options, while the 20 capabilities that can be converted to root are still marginally better than suid root, as they convert a limited set of bugs from exploit to DoS. This doesn't mean that there's no room for improvement, merely that we've taken one more step towards real security.

Remember, too, that in the wider world, security is not a boolean. Even though capabilities as implemented in Linux today are incomplete, they're still a little bit better than suid root (aka full access by default) - after all, if capabilities mean that 1% of the bugs that previously got an attacker root are no longer exploitable, that's a small number of bugs converted from security-critical, will be exploited if not fixed, to fix ASAP, just in case the analysis is incomplete. Further, thinking about caps results in people beginning to think about better routes than all-or-nothing root. It's possible that a side effect of Spender's analysis and distros moving towards caps will be better caps that don't suffer the same problem.

Spengler: False Boundaries and Arbitrary Code Execution

Posted Jan 5, 2011 17:35 UTC (Wed) by iabervon (subscriber, #722) [Link]

They're equivalent to being root in the case of an arbitrary code execution bug. In the case of a bug that only allows the attacker to cause the daemon to perform a particular unintended operation, they are not all the same as root. There are plenty of potential bugs that can only cause the program to write to an unintended file, and if these programs only have special capabilities that don't directly affect permissions, the use of capabilities has prevented an attack. If, for example, there is a process running as nobody with CAP_SETUID which is secure except for insecure temporary file handling (of the sort where the attacker causes the program to open and write to the attacker's choice of path), the attacker won't be able to use this particular bug to get root. He does mention this, saying that a particular bug may have constraints that prohibit using the bug to execute the transitions that the capabilities allow. (In particular, if cron on his system had an insecure temporary file handling bug, having it not run as root and not with capabilities it doesn't actually have would prevent exploitation.)

Of course, arbitrary code execution is probably the most common end result of security hole, simply because once the program is doing something unintended, this starts violating assumptions and causing more unintended behavior.

Spengler: False Boundaries and Arbitrary Code Execution

Posted Jan 5, 2011 21:26 UTC (Wed) by epa (subscriber, #39769) [Link]

If the kernel makes sure that the text segment of a program (its executable code) is read-only, while the data segment is no-execute, does that not eliminate most arbitrary code execution exploits?

Spengler: False Boundaries and Arbitrary Code Execution

Posted Jan 5, 2011 21:47 UTC (Wed) by cesarb (subscriber, #6266) [Link]

Not as much as one might think, thanks to return-to-libc attacks.

Spengler: False Boundaries and Arbitrary Code Execution

Posted Jan 6, 2011 11:02 UTC (Thu) by epa (subscriber, #39769) [Link]

I see... by overwriting the return address on the stack you can execute pretty much any code you want. I suppose some kind of 'stack guard' checking added by the compiler would mostly stop these attacks? I believe RHEL 5 now has that by default.

Spengler: False Boundaries and Arbitrary Code Execution

Posted Jan 6, 2011 13:54 UTC (Thu) by spender (subscriber, #23067) [Link]

SSP by no means prevents the ret2libc exploitation technique. It is of some use in preventing exploitation of linear stack overflows, but beyond that, it's none the wiser to exploitation. Consider this simple example:

stackbuf[attacker_controlled_index] = maybe_attacker_controlled_value;

SSP doesn't actually protect any function pointers or saved instruction pointers. It places a cookie it expects to be overwritten in the case of a linear stack overflow that it can check in function epilogues.

A proper ASLR implementation is a more useful mitigation (it helps even in the example above), though it too is of limited use in the presence of an additional info-leak vulnerability. It should be mentioned that SSP is also of limited use in the presence of the same vulnerability (leaking of the random cookie).

No one has real, deterministic protection against ret2libc (yet). Lest I be accused of FUD again by someone in an effort to drive up PaX usage, I won't mention who will be the first to implement this technology.

-Brad

Spengler: False Boundaries and Arbitrary Code Execution

Posted Jan 6, 2011 16:29 UTC (Thu) by cesarb (subscriber, #6266) [Link]

Wouldn't a separate return address stack, which is accessible only to call and return instructions, completely avoid return-to-libc and related attacks?

For instance, if a processor has a separate hardware return address stack, pushes/pops from it on call/return, and needs a special instruction (not the normal memory load/store instructions) to manipulate it directly, it becomes much harder to manipulate the return address of normal code (you would only be able to manipulate the return address of code which does nasty control flow manipulations, and only if such code reads from somewhere which you can write to).

I can even see how to implement this idea in userspace on common hardware (but in a way no one would do since it would be too slow):

* The kernel makes available a stack in its memory which is not accessible to userspace, and provides system calls to read and write it
* The compiler, in each function's prologue, tells the kernel to push the return address (read from the stack or the return address register, depending on the architecture)
* The compiler, in each function's epilogue, just before the return instruction, asks the kernel for the return address and writes it to where the hardware expects it to be (so the return instruction will read it)

This could even be done within the kernel (and be even slower), by having the special return address stack be on a page which is mapped just before reading/writing and unmapping it from the page tables afterwards.

Spengler: False Boundaries and Arbitrary Code Execution

Posted Jan 6, 2011 16:41 UTC (Thu) by cesarb (subscriber, #6266) [Link]

In fact, I just thought of a way which, while not as secure, should be less slow.

Simply xor the return address in the prologue with a random number, and xor it back just before the return instruction. Two loads, a xor, and a store in the prologue, and again two loads, a xor, and a store in the epilogue. You can save one load if the random value is in a register (but then you add register pressure on x86-32). Should convert a return-to-libc into a jump to a random address, which should be quite effective on 64-bit architectures with lots of unmapped land. As long as the attacker cannot *read* the random number, of course, but it is yet another speed bump. It would be even more secure if the random value was always on a register and never saved to memory.

Spengler: False Boundaries and Arbitrary Code Execution

Posted Jan 6, 2011 19:19 UTC (Thu) by spender (subscriber, #23067) [Link]

See d.1 of http://pax.grsecurity.net/docs/pax-future.txt
You're only 8 years late ;)

-Brad

Spengler: False Boundaries and Arbitrary Code Execution

Posted Jan 6, 2011 22:21 UTC (Thu) by cesarb (subscriber, #6266) [Link]

Cool. Has it ever been implemented?

My idea was a bit different; instead of XOR with an ASLR-randomized stack pointer, it would XOR with a cookie read from a global variable (initialized to a random number on a global constructor). So leaking the stack pointer would not be enough, you would need a leak of either the cookie or an obfuscated pointer (which you would then XOR with the expected unobfuscated pointer to recover the cookie). And, as a bonus, it does something useful even without ASLR enabled.

But what to XOR with is only a small detail (and a local decision even, since it is completely contained within each function, so different parts of the same program can XOR with values obtained in different ways even); the main idea, which is to XOR the return address in the stack, is the same both in my comment above and in your link ;-) . I completely forgot about the frame pointer, however (your link didn't).

The main problem with this idea is that it could break GDB badly (as mentioned in the link PaXTeam posted), unless an extension to the debugging format was developed to tell GDB where to find the cookie and which functions need it. Of course, the user can simply zero the cookie within gdb before debugging the program, to prevent the values from being obfuscated.

Spengler: False Boundaries and Arbitrary Code Execution

Posted Jan 7, 2011 21:02 UTC (Fri) by PaXTeam (guest, #24616) [Link]

> Cool. Has it ever been implemented?

search google for the following titles/keywords:

"Embedded Firmware Diversity for Smart Electric Meters"
"Hardware and Binary Modification Support for Code Pointer Protection From Buffer Overflow"
"G-Free: Defeating Return-Oriented Programming through Gadget-less Binaries"
"HyperSafe: A Lightweight Approach to Provide Lifetime Hypervisor Control-Flow Integrity"
"Preventing memory error exploits with WIT"
"Control-Flow Integrity Principles, Implementations, and Applications" (in general, MSR's gleipnir project and the related papers)
"Automated Detection of Persistent Kernel Control-Flow Attacks"

of course this is just a small selection, this area of research goes back to decades (no, it didn't start in security ;-).

Spengler: False Boundaries and Arbitrary Code Execution

Posted Jan 9, 2011 19:12 UTC (Sun) by nix (subscriber, #2304) [Link]

More examples to add to those PaXTeam suggested: glibc already does this with addresses inside jmp_bufs. This is not the only libc to do that. It is *widely* implemented.

Spengler: False Boundaries and Arbitrary Code Execution

Posted Jan 6, 2011 20:00 UTC (Thu) by PaXTeam (guest, #24616) [Link]

you might be interested in StackGhost then ;).

Spengler: False Boundaries and Arbitrary Code Execution

Posted Jan 5, 2011 17:41 UTC (Wed) by tialaramex (subscriber, #21167) [Link]

... and quite a few of his examples rely on stealing interactive password entry, which is no kind of substitute for production line instant remote root attacks we're still seeing occasionally today.

I can't tell if this is because there isn't (or Brad couldn't think of) a more practical (which is to say, automatic) root elevation from these privileges, or if he's just being nice by ensuring that POCs inspired by his posting will do something relatively harmless.

Spengler: False Boundaries and Arbitrary Code Execution

Posted Jan 5, 2011 17:38 UTC (Wed) by martinfick (subscriber, #4455) [Link]

> This potential privilege escalation isn't there so much as to prevent programs from getting real-uid == 0 as to prevent them doing something unintended, somewhat akin to accidentally rebooting the machine.

While this may be true in some cases, it is not in others. For example, in the case of linux vservers, capabilities are used to restrict the capabilities of the entire vserver. They are used as a mechanism to isolate vservers from the host. There is a mechanism for a host sysadmin to grant limited capabilities to a vserver when it needs to perform certain privileged operations. Therefor, it should be of concern if granting certain capabilities to a vserver means that users in that vserver can effectively gain more capabilities than the host sysadmin intended them to receive.

Spengler: False Boundaries and Arbitrary Code Execution

Posted Jan 5, 2011 18:03 UTC (Wed) by SEJeff (subscriber, #51588) [Link]

It seems like Information Assurance in the form of MAC (hello SELinux) is a cleaner option than capabilities where possible. I know that Fedora / RHEL taught libvirtd about SELinux and called it sVirt[1]. This seems like the best possible way forward over simple capabilities.

[1] http://selinuxproject.org/page/SVirt


Copyright © 2017, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds