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:

CODE:
  1. exec 3<>/dev/tcp/www.google.com/80
  2. echo -e "GET / HTTP/1.1\n\n">&3
  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!

17 Responses to “Bash socket programming with /dev/tcp”

  1. Gabriel Gunderson Says:

    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

  2. Dave Says:

    Thanks for the bug report. I think I fixed it with a nice hack. Let me know.

  3. steve Says:

    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?

  4. Tyler Larson Says:

    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

  5. Dave Says:

    Thanks Tyler. Nice to hear from you. Drop me a line some time to catch up!

  6. prosho Says:

    Use

    echo -e “GET / HTTP/1.1\nConnection: close\n” >&3

    so the subsequent call to cat doesn’t hang.

  7. Dave Says:

    Nice one prosho. Thanks.

  8. Eric Windisch Says:

    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.

  9. Dave Says:

    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.

  10. Mark Says:

    Dave, can you give an example if I want to send some data to a server, either via GET or POST?

    TIA

  11. Dave Says:

    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.

  12. Mark Says:

    Thanks, Dave!

  13. Ben Scott Says:

    What exactly is the security exposure of the “/dev/tcp/” feature of Bash? The socket() call will still be available if you disable it.

  14. Anonymous Says:

    can you post the backconnect shellcode?

  15. Dave Says:

    I’m afraid I have no idea what you’re talking about by “backconnect”. Are you talking about the server side?

  16. Connect-back Shell - Defending the Box « Neohapsis Labs Says:

    [...] 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 [...]

  17. Daniel Craig Says:

    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!

Leave a Reply