Friday, September 7, 2012

Chroot dns2tcp for dns tunnelling

I wanted a lightweight DNS tunnelling daemon that would deploy easily. I found that Dns2tcp was just that and I've had good results with this program when testing.

Dns2tcp is a network tool designed to relay TCP connections through DNS traffic. Encapsulation is done on the TCP level, thus no specific driver is needed (i.e: TUN/TAP).


$ curl http://www.hsc.fr/ressources/outils/dns2tcp/download/dns2tcp-0.5.2.tar.gz | tar xzv
$ cd dns2tcp-0.5.2 
$ ./configure &&  make
$ vim server/dns2tcpd/dns2tcpd.conf
listen =
port = 53
user = nobody
chroot = /tmp
domain = sub.server.com
resources = ssh:
key = secretpassphrase111

$ sudo server/dns2tcpd -f server/dns2tcpd.conf -d 3 -F
08:48:03 : Debug options.c:97   Add resource ssh: port 22
08:48:03 : Debug socket.c:55    Listening on for domain sub.server.com
Starting Server v0.5.2...
08:48:03 : Debug main.c:132     Chroot to /tmp
08:48:03 : Debug main.c:142     Change to user nobody

I've downloaded and compiled dns2tcpd on my Debian server, see the README file that comes with the code for more details. After creating a configuration file the server starts fine, listening on the public ip (nothing can connect to it yet because you run a firewall of course).

chrooting the server

Even though the process drops privileges I'm going to build a chroot jail for it [as something to do because why not? grsecurity has chroot hardenig]. Now to see what libraries the process is using. On another console (because the program above is running in the foreground):

$ sudo su
$ ps aux | grep dns2tcp -m1
nobody   21520  0.0  0.1  41864   824 pts/8    S+   02:01   0:00 server/dns2tcpd -f server/dns2tcpd.conf -d 3 -F

$ lsof -p 21520
dns2tcpd 21520 nobody  cwd    DIR      202,0     4096     12 /tmp
dns2tcpd 21520 nobody  rtd    DIR      202,0     4096     12 /tmp
dns2tcpd 21520 nobody  txt    REG      202,0   138934 165243 /home/user/source/dns2tcp-0.5.2/server/dns2tcpd
dns2tcpd 21520 nobody  mem    REG      202,0    71432  92053 /lib/libresolv-2.11.3.so
dns2tcpd 21520 nobody  mem    REG      202,0    22036  92068 /lib/libnss_dns-2.11.3.so
dns2tcpd 21520 nobody  mem    REG      202,0    42580  92054 /lib/libnss_files-2.11.3.so
dns2tcpd 21520 nobody  mem    REG      202,0    38504  92047 /lib/libnss_nis-2.11.3.so
dns2tcpd 21520 nobody  mem    REG      202,0    79676  92051 /lib/libnsl-2.11.3.so
dns2tcpd 21520 nobody  mem    REG      202,0    30496  92069 /lib/libnss_compat-2.11.3.so
dns2tcpd 21520 nobody  mem    REG      202,0  1319176  92067 /lib/libc-2.11.3.so
dns2tcpd 21520 nobody  mem    REG      202,0   118060  92060 /lib/ld-2.11.3.so
dns2tcpd 21520 nobody    0u   CHR      136,8      0t0     11 /dev/pts/8
dns2tcpd 21520 nobody    1u   CHR      136,8      0t0     11 /dev/pts/8
dns2tcpd 21520 nobody    2u   CHR      136,8      0t0     11 /dev/pts/8
$ kill -9 21520

Building the chroot:

$ mkdir -p /opt/chroot_dns2tcp/dns2tcpd/{etc,tmp,dev,usr,lib}
$ mkdir  /opt/chroot_dns2tcp/dns2tcpd/usr/dns2tcpd/
$ mknod /opt/chroot_dns2tcpd/dns2tcpd/dev/null c 1 3
$ cp /lib/ld-linux.so.2 /lib/libc.so.6 /lib/libnss_dns.so.2 /lib/libnss_files.so.2 /lib/libnss_nis.so.2 /lib/libresolv.so.2 /opt/chroot_dns2tcp/dns2tcpd/lib/
$ cp /home/user/source/dns2tcp-0.5.2/server/dns2tcpd /home/user/source/dns2tcp-0.5.2/server/dns2tcpd.conf /opt/chroot_dns2tcp/dns2tcpd/usr/dns2tcpd/ -v
$ cp /etc/hosts /etc/localtime /opt/chroot_dns2tcp/dns2tcpd/etc/ -v

$ touch /opt/chroot_dns2tcp/dns2tcpd/etc/group

$ echo "nobody:x:65534:65534:nobody:/dev/null:/bin/false" >> /opt/chroot_dns2tcp/dns2tcpd/etc/group

$ touch /opt/chroot_dns2tcp/dns2tcpd/etc/passwd

$ echo "nobody:x:65534:65534:nobody:/dev/null:/bin/false" >> /opt/chroot_dns2tcp/dns2tcpd/etc/passwd

$ touch /opt/chroot_dns2tcpd/daemon.log

$ touch /opt/chroot_dns2tcpd/screen.rc

$ vim /opt/chroot_dns2tcp/dns2tcpd/etc/nsswitch.conf 

passwd:         files
group:          files
shadow:         files
hosts:          files dns
networks:       files
protocols:      db files
services:       db files
ethers:         db files
rpc:            db files
netgroup:       nis


If you use the PaX patch on your Linux kernel you have more hardening options:

$ pax -MRXSPE /opt/chroot_dns2tcp/dns2tcpd/usr/dns2tcpd/dns2tcpd
$ paxctl -v /opt/chroot_dns2tcpd/dns2tcpd/usr/local/dns2tcpd/dns2tcpd
PaX control v0.5
Copyright 2004,2005,2006,2007 PaX Team

- PaX flags: P-S-M-X-E-R- [/opt/chroot_dns2tcpd/dns2tcpd/usr/local/dns2tcpd/dns2tcpd]
        PAGEEXEC is enabled
        SEGMEXEC is enabled
        MPROTECT is enabled
        RANDEXEC is enabled
        EMUTRAMP is enabled
        RANDMMAP is enabled

Using checksec.sh I found that further hardening can still be implemented (listed below). There has been a remote buffer overflow vulnerability in dns2tcp before - CVE-2008-03910.

$ ./checksec.sh --file /opt/chroot_dns2tcpd/dns2tcpd/usr/local/dns2tcpd/dns2tcpd
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE
No RELRO        No canary found   NX enabled    No PIE          No RPATH   No RUNPATH   /opt/chroot_dns2tcpd/dns2tcpd/usr/local/dns2tcpd/dns2tcpd
File permissions:

$ chmod o-rwx /opt/chroot_dns2tcpd/ -R -v
$ chmod -w /opt/chroot_dns2tcpd/dns2tcpd/ -R -v
$ chattr +i /opt/chroot_dns2tcpd/dns2tcpd/* -R -v
$ chattr +a /opt/chroot_dns2tcpd/daemon.log

Starting the server

This command will start the server and log the output. I start the server from inside of screen so I can logout from ssh and leave the process running. Here the screen config set by -c is blank because I can't yet figure out how to stop screen from loading my regular .screenrc on startup.

screen -S dns2tcp -c /opt/chroot_dns2tcpd/screen.rc sh -c "/usr/sbin/chroot /opt/chroot_dns2tcpd/dns2tcpd /usr/local/dns2tcpd/dns2tcpd -f /usr/local/dns2tcpd/dns2tcpd.conf -d1 -F 2>&1 | tee -a  /opt/chroot_dns2tcpd/daemon.log"
02:02:46 : Debug options.c:97   Add resource ssh: port 22
02:02:46 : Debug socket.c:55    Listening on for domain  sub.server.com
Starting Server v0.5.2...
02:02:46 : Debug main.c:132     Chroot to /tmp
09:02:46 : Debug main.c:142     Change to user nobody

When the server starts I get an message in my syslog from grsecurity because I have enabled logging of exec's within chroots. I've also utilised the socket restrictions feature and blocked client sockets for the user nobody.

$ dmesg | grep -m1 dns2tcpd
grsec: From 100.XX.XXX.XXX: exec of /opt/chroot_dns2tcpd/dns2tcpd/usr/local/dns2tcpd/dns2tcpd within chroot by process /opt/chroot_dns2tcpd/dns2tcpd/usr/local/dns2tcpd/dns2tcpd[chroot:18125] uid/euid:0/0 gid/egid:0/0, parent /bin/bash[bash:6016] uid/euid:0/0 gid/egid:0/0


On your local linux machine download and compile the code.

$ vim /home/laptop/.ssh/config
Host dnstunnel
User user
Port 2828
IdentityFile /home/laptop/.ssh/private-key-file
LogLevel  QUIET
DynamicForward localhost:8080

$ dns2tcpc -d 3 -z  sub.server.com -k secretpassphrase111 -r ssh -l 2828
$ ssh dnstunnel

Have now connected to the ssh daemon listening on localhost of the remote server, with all of the traffic being sent/received over dns queries. 

Creating session id: 0x8gd7 address = (compression NOT wanted)
delete_client 0x8gd7 

The dns2tcp daemon will show clients connecting and disconnecting. The IP address shown here belongs to google because as you see above out client is using, one of googles DNS servers. If you are using this behind a captive portal and don't specify a DNS server the client will look in resolv.conf.