--- shb-chroot.xml.old 2006-02-19 00:14:38.000000000 +0900 +++ shb-chroot.xml 2006-02-19 02:18:53.000000000 +0900 @@ -18,74 +18,229 @@ Chrooting a service is a way of limiting a service (or user) environment to only accessing what it should and not gaining access (or information) that could lead to root access. By running the service as another user than -root (nobody, apache, named) an attacker can only +root (nobody, apache, named) an attacker can only access files with the permissions of this user. This means that an attacker -cannot gain root access even if the services has a security flaw. +cannot gain root access even if the services has a security flaw.

Some services like pure-ftpd and bind have features for chrooting, and other services do not. If the service supports it, use it, -otherwise you have to figure out how to create your own. Lets see how to create -a chroot, for a basic understanding of how chroots work, we will test it with -bash (easy way of learning). +otherwise you have to figure out how to create your own. In this document, we'll +look at chroot-ing www-servers/monkeyd, a lightweight webserver. First, +the server package needs to be emerged:

+
+# emerge -apv www-servers/monkeyd
+
+ +

+Once it's installed, files must be copied over to the chroot, and the libraries +that monkeyd links against must be checked. First the libraries should +be checked using ldd: +

+ + +You can skip checking the linked libraries if bash was compiled with the +static USE flag. + + +
+# ldd /usr/bin/monkey
+        linux-gate.so.1 =>  (0xffffe000)
+        libpthread.so.0 => /lib/libpthread.so.0 (0xb7eed000)
+        libc.so.6 => /lib/libc.so.6 (0xb7dd9000)
+        /lib/ld-linux.so.2 (0xb7f1e000)
+
+ +

+The files that showup with absolute paths must be copied over for the program to +work. Let's go ahead and copy them over: +

+ +
+# mkdir /chroot/lib
+# cp -p /lib/{libpthread.so.0,libc.so.6,ld-linux.so.2} /chroot/lib/
+
+ +

+Now that the dynamic libraries are copied over, the actual files that the +program uses must be copied over as well. This includes things such as +configuration files and server modules. To help eleviate the stress of going +through and finding every single file a program needs, I've created this simple +script which uses equery to copy over the needed files: +

+ +
+#!/bin/bash
+for files in $(equery -q -C files $1 | grep "^\/" | grep -v "\.d")
+do
+if [ ! -e $2${files} ] ; then
+   if [ -d ${files} ] ; then
+          echo "Creating directory $2${files}..."
+          mkdir -p $2${files}
+   else
+          echo "Copying over file $2${files}..."
+          cp -p ${files} $2${files}
+   fi
+fi
+done
+
+ +

+This script takes 2 arguments. The first is the name of the package, and the +second is the location to the chroot (without the leading slash). Here is an +example output using www-servers/monkeyd: +

+ +
+# chroot_setup.sh www-servers/monkeyd /chroot
+Creating directory /chroot/etc...
+Creating directory /chroot/etc/monkeyd...
+Copying over file /chroot/etc/monkeyd/modules.conf...
+Copying over file /chroot/etc/monkeyd/monkey.conf...
+Copying over file /chroot/etc/monkeyd/monkey.mime...
+Creating directory /chroot/usr...
+Creating directory /chroot/usr/bin...
+Copying over file /chroot/usr/bin/monkey...
+Creating directory /chroot/usr/lib...
+Creating directory /chroot/usr/lib/debug...
+Creating directory /chroot/usr/lib/debug/usr...
+Creating directory /chroot/usr/lib/debug/usr/bin...
+Creating directory /chroot/usr/share...
+Creating directory /chroot/usr/share/doc...
+Creating directory /chroot/usr/share/doc/monkeyd-0.9.1...
+Copying over file /chroot/usr/share/doc/monkeyd-0.9.1/ChangeLog.txt.gz...
+Copying over file /chroot/usr/share/doc/monkeyd-0.9.1/HowItWorks.txt.gz...
+Copying over file /chroot/usr/share/doc/monkeyd-0.9.1/MODULES.gz...
+Copying over file /chroot/usr/share/doc/monkeyd-0.9.1/README.gz...
+Creating directory /chroot/var...
+Creating directory /chroot/var/log...
+Creating directory /chroot/var/log/monkeyd...
+Creating directory /chroot/var/www...
+Creating directory /chroot/var/www/localhost...
+Creating directory /chroot/var/www/localhost/cgi-bin...
+Copying over file /chroot/var/www/localhost/cgi-bin/test.pl...
+Creating directory /chroot/var/www/localhost/htdocs...
+Creating directory /chroot/var/www/localhost/htdocs/docs...
+Copying over file /chroot/var/www/localhost/htdocs/docs/monkey+php.en.html...
+Copying over file /chroot/var/www/localhost/htdocs/docs/monkey+php.es.html...
+Copying over file /chroot/var/www/localhost/htdocs/docs/monkey+php.fr.html...
+Copying over file /chroot/var/www/localhost/htdocs/docs/monkey+php.pt-br.html...
+Copying over file /chroot/var/www/localhost/htdocs/docs/monkey+php.ru.html...
+Copying over file /chroot/var/www/localhost/htdocs/docs/monkey+php.sv.html...
+Creating directory /chroot/var/www/localhost/htdocs/imgs...
+Copying over file /chroot/var/www/localhost/htdocs/imgs/logonooficial.jpg...
+Copying over file /chroot/var/www/localhost/htdocs/imgs/titulo.jpg...
+Copying over file /chroot/var/www/localhost/htdocs/index-monkey.html...
+Creating directory /chroot/var/www/localhost/htdocs/php...
+Copying over file /chroot/var/www/localhost/htdocs/php/index.php...
+
+ +

+Now that the environment is setup, the init.d script must be adjusted to handle +the chroot environment. Here is an example change I made to the monkeyd init.d +file to handle this: +

+ +
+-       /usr/bin/monkey -D &> /dev/null
++       chroot /chroot /usr/bin/monkey -D &> /dev/null
+
+-       start-stop-daemon --stop --quiet --pidfile ${MONKEY_PID}
++       start-stop-daemon --stop --quiet --pidfile /chroot/${MONKEY_PID}
+
+-       rm -f ${MONKEY_PID}
++       rm -f /chroot/${MONKEY_PID}
+
+ + +You can also edit conf.d/monkeyd and prepend /chroot to MONKEY_PID as well. + +

-Create the /chroot directory with mkdir /chroot. And find what -dynamic libraries that bash is compiled with (if it is compiled with --static this step is not necessary): +However, when attempting to start monkeyd, the service fails. In order to find +out why, strace can be used. Here we find the problem is that monkeyd is +unable to create the pid file:

+
+# strace -o strace.log chroot /chroot/ /usr/bin/monkey
+
+(problem file)
+unlink("/var/run/monkey.pid")           = -1 ENOENT (No such file or directory)
+open("/var/run/monkey.pid", O_WRONLY|O_CREAT|O_TRUNC, 0666) = -1 ENOENT (No such file or directory)
+write(1, "Error: I can\'t log pid of monkey"..., 33) = 33
+
+

-The following command will create a list of libraries used by bash. +So in order to fix this, we create the appropriate /var/run directory:

-
-# ldd /bin/bash
-  libncurses.so.5 => /lib/libncurses.so.5 (0x4001b000)
-  libdl.so.2 => /lib/libdl.so.2 (0x40060000)
-  libc.so.6 => /lib/libc.so.6 (0x40063000)
-  /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
+
+# mkdir -p /chroot/var/run
 

-Now lets create the environment for bash. +There were a couple of other files missing, all of them I transfered over as +shown here:

-
-# mkdir /chroot/bash
-# mkdir /chroot/bash/bin
-# mkdir /chroot/bash/lib
+
+# cp -p /etc/nsswitch.conf /chroot/etc/
+# cp -p /etc/passwd /chroot/etc/
+# cp -p /etc/group /chroot/etc/
+# cp -p /lib/libnss_compat.so.2 /chroot/lib/
+# cp -p /usr/lib/libnsl.so /chroot/usr/lib/libnsl.so.1
+# cp -p /usr/lib/libnss_nis.so /chroot/lib/libnss_nis.so.2
+# cp -p /usr/lib/libnss_files.so /chroot/lib/libnss_nis.so.2
+# cp -p /lib/libgcc_s.so.1 /chroot/lib/
 

-Next copy the files used by bash (/lib) to the chrooted -lib and copy the bash command to the chrooted bin -directory. This will create the exact same environment, just with less -functionality. After copying try it out: chroot /chroot/bash /bin/bash. -If you get an prompt saying / it works! Otherwise it will properly -tell you what a file is missing. Some shared libraries depend on each other. +And now that the problematic files are handled, go ahead and start the init.d +script:

+
+# /etc/init.d/monkeyd start
+ * Starting monkeyd ...                       [ ok ]
+
+

-You will notice that inside the chroot nothing works except echo. This -is because we have no other commands in out chroot environment than bash and -echo is a build-in functionality. +And just to make sure:

+
+# ps aux | grep monkey
+nobody   24007  0.0  0.0   1684   572 ?        Ss   01:55   0:00 /usr/bin/monkey -D
+root     24009  0.0  0.1   2664   752 pts/2    R+   01:55   0:00 grep monkey
+#  wget http://localhost:2001/index-monkey.html
+--02:11:29--  http://localhost:2001/index-monkey.html
+           => `index-monkey.html'
+Resolving localhost... 127.0.0.1
+Connecting to localhost|127.0.0.1|:2001... connected.
+HTTP request sent, awaiting response... 200 OK
+Length: 2,610 (2.5K) [text/html]
+
+100%[==========================================================================================================================>] 2,610         --.--K/s
+
+02:11:29 (49.78 MB/s) - `index-monkey.html' saved [2610/2610]
+
+ +

+And to be extra safe, verify that the init.d script can stop the service as +well: +

+ +
+# /etc/init.d/monkeyd stop
+* Stopping monkeyd ...                      [ ok ]
+
+

-This is basically the same way you would create a chrooted service. The only -difference is that services sometimes rely on devices and configuration files -in /etc. Simply copy them (devices can be copied with cp --a) to the chrooted environment, edit the init script to use chroot before -executing. It can be difficult to find what devices and configuration files a -services need. This is where the strace command becomes handy. Start -the service with /usr/bin/strace bash and look for open, read, stat and -maybe connect. This will give you a clue on what files to copy. But in most -cases just copy the passwd file (edit the copy and remove users that has -nothing to do with the service), /dev/zero, /dev/log -and /dev/random. +And that's it! You've now setup your chroot'ed service.