Playing with Sandbox: An analysis of Capsicum

Introduction

In this post, we will talk about sandbox. Researchers who work and study software exploitation probably know the concept. When properly implemented on a system, this kind of feature makes it harder to compromise the system. On Wikipedia, we have a good description of the concept:

“In computer security, a sandbox is a security mechanism for separating running programs. It is often used to execute untested code, or untrusted programs from unverified third parties, suppliers, untrusted users and untrusted websites. A sandbox typically provides a tightly controlled set of resources for guest programs to run in, such as scratch space on disk and memory. Network access, the ability to inspect the host system or read from input devices are usually disallowed or heavily restricted.”

The sandbox is a security mechanism that separates processes. Basically, we have a process with least privileges (target) and another process with greater privileges (broker). If the process with least privileges needs to execute an operation that is not allowed, a request is sent to the broker. Then, the broker checks whether the operation is allowed to be executed. If so, it executes, acknowledges the execution and returns a value to the target when needed. Sandboxes is used to protect the application and can also be used to provide a restricted and safe environment for execution and testing of malicious binaries. As an example, the Cuckoo Sandbox that is used for malware analysis.

In this post, we will talk about Capsicum [1]. It is a sandbox technology developed by the University of Cambridge. Capsicum support has already being implemented for several popular commands in the FreeBSD operating system, such as tcpdump [2], hastd, dhclient, kdump and sshd [3]. The experimental version was developed for FreeBSD [5] and was available since version 9.0. This sandbox adds two new features to the system, capability mode and capabilities.

Capability mode is a feature that enables the developers to isolate processes, allowing only specific system calls, reducing the permissions of the isolated process. Capabilities enables a more refined control over the files and devices. This post will talk only about the capability mode.

Building the kernel with Capsicum

In FreeBSD 10.0, Capsicum is enabled by default, but in FreeBSD 9.0, it needs to be build in the kernel.

Edit your GENERIC kernel file at /usr/src/sys/amd64/conf/GENERIC and add this option:

options CAPABILITY_MODE

Then, rebuild the kernel. There are many possible ways to do this, but I recommend to use the options available at [6]. If Capsicum is available in the kernel, there is a new sysctl option and two new syscalls. They are cap_getmode() and cap_enter().

The code below is a simple example that we can use to confirm if Capsicum is working as expected. If the syscall execve() fails, it shows Capsicum is working correctly and denying the syscall execution.

File: example01.c
---
1     #include 
2     #include 
3     #include 
4     #include 
5     #include <sys/capability.h>
6
7     int main(void){
8
9          bool sandbox_status;
10
11         char *const command[] = {"/bin/sh", NULL};
12
13         cap_enter();
14
15         sandbox_status = cap_sandboxed();
16         if(sandbox_status == true){
17            fprintf(stdout,"Sandbox enabled\n");
18         }
19         else{
20            fprintf(stdout,"Capsicum disabled\n");
21         }
22
23         if(execve("/bin/sh",command,NULL) == -1){
24            perror("execve");
25            exit(EXIT_FAILURE);
26         }
27
28    return 0;
29    }
---

A closer look at Capsicum

In the output from example01, we can see that the execve() syscall execution has failed and the error message has returned that execve() syscall is not allowed to be executed on capability mode. The syscalls are the main ways of communication with the kernel, and restricting some of them reduces the attack vectors.

File: /usr/src/sys/kern/sys_capability.c
---
90    /*
91     * System call to enter capability mode for the process.
92    */
93    int
94    sys_cap_enter(struct thread *td, struct cap_enter_args *uap)
95    {
96         struct ucred *newcred, *oldcred;
97         struct proc *p;
98
99         if (IN_CAPABILITY_MODE(td))
100           return (0);
101
102       newcred = crget();
103       p = td->td_proc;
104       PROC_LOCK(p);
105       oldcred = p->p_ucred;
106       crcopy(newcred, oldcred);
107       newcred->cr_flags |= CRED_FLAG_CAPMODE;
108       p->p_ucred = newcred;
109       PROC_UNLOCK(p);
110       crfree(oldcred);
111  return (0);
112  }
---
File: /usr/src/sys/sys/capability.h
---
343 #define IN_CAPABILITY_MODE(td)((td->td_ucred->cr_flags & CRED_FLAG_CAPMODE) != 0)
---
File: /usr/src/sys/sys/ucred.h
---
49    struct ucred {
50     u_int cr_ref; /* reference count */
51    #define cr_startcopy cr_uid
52     uid_t cr_uid; /* effective user id */
53     uid_t cr_ruid; /* real user id */
54     uid_t cr_svuid; /* saved user id */
55     int cr_ngroups; /* number of groups */
56     gid_t cr_rgid; /* real group id */
57     gid_t cr_svgid; /* saved group id */
58     struct uidinfo *cr_uidinfo; /* per euid resource consumption */
59     struct uidinfo *cr_ruidinfo; /* per ruid resource consumption */
60     struct prison *cr_prison; /* jail(2) */
61     struct loginclass *cr_loginclass; /* login class */
62     u_int cr_flags; /* credential flags */
63     void *cr_pspare2[2]; /* general use 2 */
64    #define cr_endcopy cr_label
65     struct label *cr_label; /* MAC label */
66     struct auditinfo_addr cr_audit; /* Audit properties. */
67     gid_t *cr_groups; /* groups */
68     int cr_agroups; /* Available groups */
69     gid_t cr_smallgroups[XU_NGROUPS]; /* storage for small groups */
70    };
---

The cap_getmode() syscall and the function cap_sandboxed() is used to check if the capability mode is enabled in the running process. The cap_sandboxed() is a function that calls cap_getmode() syscall. This function was designed to help developers, because cap_getmode() is always executed successfully. There’s no need to check its return value. The function cap_sandboxed() returns true or false, depending on the Capsicum state in the process.

File: /usr/src/sys/kern/sys_capability.c
---
114   /*
115   * System call to query whether the process is in capability mode.
116   */
117   int
118   sys_cap_getmode(struct thread *td, struct cap_getmode_args *uap)
119   {
120        u_int i;
...
122        i = IN_CAPABILITY_MODE(td) ? 1 : 0;
123        return (copyout(&i, uap->modep, sizeof(i)));
124   }
---

There’s a file called capabilities.conf in the directory /usr/src/sys/kern/ which contains syscalls allowed to be executed by a process within the Capsicum sandbox. Another way to know what syscalls are permitted is to look at the file /usr/src/sys/kern/init_sysent.c that contains the syscalls definitions. The syscalls containing the SYF_CAPENABLED parameter are allowed for execution. The validation is made by the function syscallenter(). It manages all syscalls executed by the kernel, running right after the interrupt handler.

File: /usr/src/sys/kern/subr_syscall.c
---
55    static inline int
56    syscallenter(struct thread *td, struct syscall_args *sa)
57    {
...
106   #ifdef CAPABILITY_MODE
107        /*
108         * In capability mode, we only allow access to system calls
109         * flagged with SYF_CAPENABLED.
110        */
111        if (IN_CAPABILITY_MODE(td) &&
112        !(sa->callp->sy_flags & SYF_CAPENABLED)) {
113           error = ECAPMODE;
114           goto retval;
115        }
116   #endif
...
165 }
---

At the moment of this post, on 64-bit systems, Capsicum does not have support for 32-bit binaries. FreeBSD has a layer (compat32) that allows 32-bit binaries to run on FreeBSD 64-bit systems.

Conclusion

Using a sandbox drastically reduces the possibilities that an attacker has to execute code after exploiting a vulnerability. If a vulnerability in the FreeBSD kernel is exploited for privilege escalation within an application protected by Capsicum, an additional step is needed to escape the sandbox for the attacker to achieve broader system impact. If the sandbox is not disabled, an attacker might have control over the application, but not much could be done over the system in general.

Nowadays, many popular software programs use this technology, such as Adobe Reader X, Flash Player, and Google Chrome. Using this technology also results in more attention to kernel vulnerabilities because they may help circumvent the restrictions imposed by the sandbox. For example, exploitation Google Chrome at Pwn2Own 2013 edition [7], a researcher needs to escape the sandbox to execute arbitrary code. Another example is the famous malware Duqu that contains an exploit for a vulnerability in the Windows kernel that, when exploited, gives full access to the machine, escaping from the Microsoft Word sandbox. Although there are ways to circumvent the sandbox in some situations, this technology is highly recommended to protect your application.

References

[1] – https://www.cl.cam.ac.uk/research/security/capsicum/

[2] – http://svnweb.freebsd.org/changeset/base/253004

[3] – https://www.cl.cam.ac.uk/research/security/capsicum/freebsd.html

[4] – https://www.cl.cam.ac.uk/research/security/capsicum/linux.html

[5] – https://www.freebsd.org/releases/9.0R/announce

[6] – https://docs.freebsd.org/en/books/handbook/kernelconfig/#kernelconfig-building

[7] – https://labs.withsecure.com/publications/mwr-labs-pwn2own-2013-write-up-kernel-exploit

Author: Anderson Nascimento

A computer security researcher focused on understanding, discovering and exploiting computer security vulnerabilities. - Um pesquisador em segurança da informação com o foco em entender, descobrir e explorar vulnerabilidades em computadores.

Leave a Reply

Discover more from Anderson Nascimento

Subscribe now to keep reading and get access to the full archive.

Continue reading