Bash socket programming with /dev/tcp
Today I discovered a nifty way to do socket programming in bash without the need for netcat (nc) or telnet: /dev/tcp. Say you want to connect to Google and fetch their front page. Just do this:
-
exec 3<>/dev/tcp/www.google.com/80
-
echo -e "GET / HTTP/1.1\n\n">&3
-
cat <&3
I found this very handy when trying to connect to a host and read some info from a socket, but I wanted to do it all in a few lines of bash. This is great, because you don't have to worry about what version of Python or Perl your users will have. If they've got bash, you're set. There is one caveat: some systems (Debian included) don't enable /dev/tcp. I don't know why, but they don't. So make sure your target system has it before coding this up. Oh, and you can use /dev/udp too if you really want to spice things up!
Where does this come from? It turns out it's a pure bashism, which has to be enabled when you compile bash. Bash actually intercepts "/dev/tcp" and provides special behavior, so you're not actually opening a device node called /dev/tcp. Pretty cool, eh?!
Happy bashing!
May 23rd, 2006 at 1:20 pm
I could have used this two weeks ago. I ended up using nc. It works pretty well anyway.
PS. I get this error on page load:
Warning: in_array() [function.in-array]: Wrong datatype for second argument in /home/vhosts/thesmithfam.org/wordpress/wp-content/plugins/BAStats/BAStats_logger.php on line 114
May 23rd, 2006 at 1:35 pm
Thanks for the bug report. I think I fixed it with a nice hack. Let me know.
June 2nd, 2006 at 8:26 am
Dave, you’ve got your mug up. Now you’ll have to start mixing up your daily routine to avoid the papparazzi.
How’s the baby?
You hacked your airhog to drop “bombs” yet?
August 5th, 2006 at 7:22 pm
Your example code is invalid for HTTP 1.1: a ‘host’ header is always required (to aid in virtual hosting). Instead, do the following:
echo -e “GET / HTTP/1.1\nhost: http://www.google.com\n\n” >&3
Or
echo -e ‘GET / HTTP/0.9\n\n’ > &3
Hope you’re doing well.
-Tyler
August 5th, 2006 at 11:25 pm
Thanks Tyler. Nice to hear from you. Drop me a line some time to catch up!
October 17th, 2006 at 11:57 am
Use
echo -e “GET / HTTP/1.1\nConnection: close\n” >&3
so the subsequent call to cat doesn’t hang.
October 17th, 2006 at 12:03 pm
Nice one prosho. Thanks.
January 27th, 2007 at 3:36 am
Just in case anyone still comes across this blog post…
Don’t use this hack. Use netcat or socat. There is a reason that Debian has this disabled.
This is a security risk on a multi-user system. It is easy to restrict access to socat, netcat, wget, and curl. It is impossible to disable this feature of the shell without changing the shell. This is a feature transparent enough that many administrators could overlook, allowing into their otherwise-secure chroots.
While I admit that on a single-user system, this is less of an issue than on a multi-user system, the fact that the security issue exists requires the expectation (and subsequent reality) that many systems have this disabled.
On the other hand, it is true that netcat also doesn’t exist everywhere, if you must make the choice between programming for netcat or bash sockets — choose netcat. It isn’t that difficult to install and it doesn’t necessitate the creation of unnecessary security concerns.
I would be very upset if a vendor told me that I needed to have a bash enabled with sockets; while I wouldn’t at all mind a vendor telling me to install netcat. At least I can restrict netcat.
January 27th, 2007 at 3:38 pm
Eric,
A customer of mine had an immediate need for a small fix to some existing commercial software and hardware on a Red Hat system, to which I had no access. The only thing I knew about the system a priori was that it was Red Hat Enterprise 3. I didn’t even know if they had netcat installed or not. I did know, however, that they were running a vanilla install of Red Hat Enterprise. Armed with that knowledge, I was able to solve their problem reliably with a nice, dirty bash hack using /dev/tcp.
Had I relied on netcat, it could have come back to me. /dev/tcp did the job for them nicely.
May 23rd, 2007 at 11:36 am
Dave, can you give an example if I want to send some data to a server, either via GET or POST?
TIA
May 23rd, 2007 at 11:55 am
Sending a POST with data would be the same, but you would add extra text like this:
echo -e “POST / HTTP/1.1\n\nThis is the body of my POST”>&3
You can also add headers right after the first \n, but be sure to use \n\n before the HTTP body.
May 23rd, 2007 at 6:14 pm
Thanks, Dave!
June 9th, 2007 at 8:43 pm
What exactly is the security exposure of the “/dev/tcp/” feature of Bash? The socket() call will still be available if you disable it.
July 22nd, 2007 at 1:47 am
can you post the backconnect shellcode?
July 22nd, 2007 at 7:26 am
I’m afraid I have no idea what you’re talking about by “backconnect”. Are you talking about the server side?
April 18th, 2008 at 1:40 pm
[...] known for quite some time - it’s easily discovered on the blogosphere in articles here and here for example. Since this is built-in to bash by default in most instances, the main method of [...]
June 25th, 2008 at 9:00 am
Hey, I was looking around for a while searching for vendor security and I happened upon this site and your post regarding cket programming with /dev/tcp, I will definitely this to my vendor security bookmarks!