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).
http://www.hsc.fr/ressources/outils/dns2tcp/index.html.en
Server
$ 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 = 11.22.22.11
port = 53
user = nobody
chroot = /tmp
domain = sub.server.com
resources = ssh:127.0.0.1:22
key = secretpassphrase111
$ sudo server/dns2tcpd -f server/dns2tcpd.conf -d 3 -F
08:48:03 : Debug options.c:97 Add resource ssh:127.0.0.1 port 22
08:48:03 : Debug socket.c:55 Listening on 50.116.4.114:53 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 11.22.22.11 (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
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
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
Hardening:
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:127.0.0.1 port 22
02:02:46 : Debug socket.c:55 Listening on 11.22.22.11:53 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
Client
On your local linux machine download and compile the code.
$ vim /home/laptop/.ssh/config
Host dnstunnel
User user
Port 2828
HostName 127.0.0.1
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 8.8.8.8
$ 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 = 202.180.64.10 (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 8.8.8.8, 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.