Combining chroot and xinetd
Introduction
In this blog we will talk about running network applications securely. A simple program(that takes I/O from the console) can be run as a secure service using a combination of xinetd
and chroot
. I used this technique while developing challenges for Backdoor. The ECHO challenge is a good example.
Key points:
- The program running in the background takes I/O directly from the console.
xinetd
handles all the network related requests.- The program is run in a jail directory using
chroot
with restricted access to directory structure.
I will give a simple walkthrough but first I expect the reader to be familiar with the following:
xinetd
This is what wikipedia says:
xinetd listens for incoming requests over a network and launches the appropriate service for that request. Requests are made using port numbers as identifiers and xinetd usually launches another daemon to handle the request.
Instead of starting each server individually, xinetd
is the only daemon process to be started. It listens for each and every service listed in its configuration and starts the appropriate service whenever a new request comes up.
chroot
Again from wikipedia:
A chroot on Unix operating systems is an operation that changes the apparent root directory for the current running process and its children. A program that is run in such a modified environment cannot name (and therefore normally not access) files outside the designated directory tree. The modified environment is called a "chroot jail".
Setting up a chroot
jail is easy though time consuming.
Walkthrough -
reader
We’ll write a simple service to that takes the name of a file as the input and prints the first 1024 bytes of the file.
1. Write source program for the service
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
int main()
{ char file_name[50];
char buf[1025];
int fd;
printf("Enter filename:\n");
fflush(stdout);
scanf("%s", file_name);
fd = open(file_name, O_RDONLY);
if(fd==-1)
{ printf("Error: %d\n", errno);
return -1;
}
if(read(fd, buf, sizeof(buf))<0)
{ printf("Error: %d\n", errno);
close(fd);
return -1;
}
printf("%s\n", buf);
close(fd);
return 0;
}
Download it here
2. Creating a chroot jail
First of all let’s compile our code and generate the binary.
gcc reader.c -o reader
As it will be jailed, we need to import all the libraries that our binary reader
will require. For finding all the required libraries we will use ldd
.
$ ldd reader
linux-vdso.so.1 => (0x00007ffc79702000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4b13787000)
/lib64/ld-linux-x86-64.so.2 (0x00007f4b13b76000)
This is a sample output on my machine and it may vary for yours. So basically I copy the two libraries (libc.so.6 and ld-linux-x86-64.so.2) maintaining the same directory structure relative to my program. My directory structure now looks like this:
./
|-- lib/
|-- |-- x86_64-linux-gnu/
|-- --- |-- libc.so.6
|-- lib64/
|-- |-- ld-linux-x86-64.so.2
|-- reader.c
|-- reader
To test that you have successfully created a jail try this:
chroot . ./reader
You won’t be able to view any file outside the reader’s directory. If you can then you did something wrong!
3. Adding a configuration file in xinetd for
reader
First of all make sure that /etc/xinetd.conf
contains the following line:
includedir /etc/xinetd.d
After that create a new configuration file /etc/xinetd.d/reader
service reader
{
type = UNLISTED
protocol = tcp
socket_type = stream
port = 8001
wait = no
server = /usr/sbin/chroot
server_args = /home/vampire/reader/ ./reader
user = root
}
You can download the file here.
Explanation:
-
type = UNLISTED: Standard services are listed in
/etc/services
. Our service is not standard so we will also need to specify theprotocol
andport
. -
protocol = tcp: We shall use tcp protocol.
-
socket_type = stream: We will use connection oriented socket
-
port = 8001: The port number our service will listen to
-
wait = no: Our service is multithreaded. There can be more than one client connected to it at a time.
-
server = /usr/sbin/chroot: This is the
chroot
binary in my machine. You can find yours by executingwhich chroot
. -
server_args = /home/vampire/reader/ ./reader: These are the parameters passed to
chroot
command. -
user = root: Only root users can run
chroot
.
For complete list see the man page.
4. Restart the xinetd daemon
The xinetd
daemon can be restarted using the following command:
/etc/init.d/xinetd restart
xinetd
logs in /var/log/syslog
by default.
Hurray! We have successfully run our service securely. To test it run the following command:
nc localhost 8001
Change the IP/port accordingly. You should be able to run the program correctly. Also try giving different source file path names. You won’t be able to access any file other than one in /home/vampire/reader/
. Also keep in mind to flush the buffer so that the text is displayed instantly.
Comments are welcome. If you know of a better way to do this, feel free to tell me!