The netcat utility is a relatively simple but extremely useful tool to read and write data to/from sockets. There is the old incarnation called nc that was released in 1995 and the newer version called ncat with a few more options.
As we have done before, let’s explain the usefulness of netcat with a series of examples.
Netcat can work in client or server mode. In client mode it opens a socket through which to send data whereas in server mode it opens a socket in listening mode. Let’s throw in a few examples to see what ncat‘s uses can be.
Chat
server> ncat -l 192.168.8.105 -p 6789
In the example above we are opening a listening socket (“-l”) on port 6789 (“-p 6789“) of the local IP address 192.168.8.105. Now we shall open a connection to this same address and port from a remote client.
client> ncat 192.168.8.105 -p 6789
The connection is now established and we can send data on both directions. We can type “sending data from the server” on the server side and we should see the same line shown in the client soon after we press Enter. We can also type “sending data from client” and we will see it shown in the server side. So 2 users can chat back and forth. What if we need more than 2 concurrent users chatting? Then we can use the “–chat” option:
server> ncat -l –chat 192.168.8.105
With the command above we are opening a chat line with no users yet. Let’s have the first chat user…
user1> ncat 192.168.8.105
<announce> 192.168.8.107 is connected as <user4>.
<announce> already connected: nobody.
… and now the second …
user2> ncat 192.168.8.105
<announce> 192.168.8.108 is connected as <user5>.
<announce> already connected: 192.168.8.107 as <user4>.
We can see that this layout is far more convenient as we can have several users all of which have a userID and its source IP displayed for identification. If now user4 types something and presses Enter, its message will be shown in the other chat members terminals with the “<user4>” prefix. So everybody knows who is saying what.
Banner grabbing
Netcat is a obvious choice to perform banner grabbing and check what service is listening on the server side. It can be as simple as…
# # ncat 192.168.122.1 22
SSH-2.0-OpenSSH_7.4
… or this …
# ncat 124.111.100.100 25 -v
Ncat: Version 7.40 ( https://nmap.org/ncat )
Ncat: Connected to 124.111.100.100:25.
220 ps659864.dreamteam.com ESMTP
… or a bit more elaborate that requires interacting with the service …
# ncat www.google.com 80
GET / HTTP/1.1
.
HTTP/1.1 302 Found
Cache-Control: private
Content-Type: text/html; charset=UTF-8
Location: http://www.google.ch/?gfe_rd=cr&ei=2oLlWM3ZK-6A8QfH1pSoCA
Content-Length: 258
Date: Wed, 05 Apr 2017 23:50:50 GMT
.
<HTML><HEAD><meta http-equiv=”content-type” content=”text/html;charset=utf-8″>
<TITLE>302 Moved</TITLE></HEAD><BODY>
<H1>302 Moved</H1>
The document has moved
<A HREF=”http://www.google.ch/?gfe_rd=cr&ei=2oLlWM3ZK-6A8QfH1pSoCA”>here</A>.
</BODY></HTML>
File transfer
Imagine you want to transfer a file from one server to another where ftp is disabled and ssh cannot be used for whatever reason (e.g. SSH bans your username logins). There is often a workaround but in this case using ncat might be the easiest shortcut…
file-destination> ncat 192.168.8.105 -p 6789 -l > /tmp/boot.log
file-source> ncat 192.168.8.105 -p 6789 < /var/log/boot.log
We have opened a listening socket in the destination and forwarded the input to the intended file. Then we opened a connection from the source and piped the file to it. Voila! If we now check it, we will see that the file and its contents were sent over the network and written to the specified file.
If we leave out the port (it’s not mandatory) the default port 31337 will be used. But what should always happen is that the listening socket is open before the sending socket is (or there will be no socket to connect to!).
The receiving side is usually the one listening, but it need not be the case as in…
file-source> ncat 192.168.8.105 -p 6789 -l < /var/log/boot.log
file-destination> ncat 192.168.8.105 -p 6789 > /tmp/boot.log
Whoever listens… should listen first!
Are we limited to sending one file at a time? Nope. We can tar files…
destination> ncat -l –recv-only | tar xvz
source> tar cvfz file1 file2 file3 | ncat –send-only 192.168.8.105
We just opened a listening socket on 0.0.0.0 (all local IPs) and port 31337, piping the input so that it is decompressed and untar’ed. Then we compressed, tar’ed and sent a bunch of files to the listening socket. The “–send-only” option is meant for sockets that only send data and ignore anything received. The opposite is “–recv-only” meant for receiving sockets.
We can send not only files but also partitions or whole disks:
destination> ncat -l > /backup/server1-sda.img
source> ncat –send-only 192.168.8.105 < /dev/sda
And we can compress and decompress them on-the-fly…
destination> ncat -l | bzip2 -d > /backup/server1-sda.img
source> cat /dev/sda | bzip2 | ncat –send-only 192.168.8.105
We need to transfer a file from host-A to host-C jumping through host-B because A and C cannot connect directly. If we had SSH, we could do it easily with the “-3″ flag. But we cannot use it so ncat comes again to the rescue:
host-B> ncat -l –broker
host-C> ncat host-B > file-to-transfer
host-A> ncat –send-only host-B < file-to-transfer
First we opened a listening socket on the intermediary server in “–broker” mode. In this mode, all data received is broadcasted to all connected sockets.
Then we established a connection from the intermediary to the destination server, piping the incoming data to the intended filename. At this point, there is no data to pipe yet.
Finally, we connect from the source to the intermediary and send the file to the listening socket on host-B. What happens then? Host-B broadcasts the incoming data to all connected sockets (host-A & host-C), but the sending node (host-A) ignores it as the “–send-only” flag compels it to discard any incoming data. So only host-C receives it and writes it to the destination file.
We could have opened a bunch of connections from servers D, E, F, … in the same fashion as we did with the destination server host-C. What would be the point? To write the source file to several destinations in one go!
One problem with file transfers with netcat is that they are insecure by default (unencrypted). But overcoming that problem is as easy as using the “–ssl” flag on both sides of the connection as in:
file-source> ncat 192.168.8.105 -l –ssl < /var/log/boot.log
file-destination> ncat 192.168.8.105 –ssl > /tmp/boot.log
Port scanner
If you do not have nmap available (likely in many environments!), you might use telnet to check whether or not a certain service is listening on a given ip:port. But that is not telnet’s intended use and it has many shortcomings. Netcat is far more suitable for port scanning:
# ncat 192.168.1.45 22
SSH-2.0-OpenSSH_7.4
The command above is simply opening a tcp socket on the SSH port to see if the service is available and it happens to be. If we tried the same on the FTP port …
# ncat 192.168.1.45 21
Ncat: Connection refused
… we would see that either the service is not running on this port or there’s a firewall blocking the way. We can scan several ports in one go …
# ncat 192.168.8.105 78-82 -v -n -z -w3
nc: connect to 192.168.8.105 port 78 (tcp) failed: Connection refused
nc: connect to 192.168.8.105 port 79 (tcp) failed: Connection refused
Connection to 192.168.8.105 80 port [tcp/*] succeeded!
nc: connect to 192.168.8.105 port 81 (tcp) failed: Connection refused
nc: connect to 192.168.8.105 port 82 (tcp) failed: Connection refused
The “-v” flag means verbose, “-n” means no DNS resolution (faster), “-z” means zero I/O (it just attempts to open a socket without sending any data so it’s faster and a bit more subtle) and “-w3” implies a 3 second wait before timeout at each connection attempt.
Some versions of netcat do not allow port ranges and will only accept one port. If that’s your case, you can achieve the same as above with:
# for i in {78..82}
> do
> ncat 192.168.8.105 $i -vnz -w3
> sleep 1
> done
Remote shell or backdoor
We can use the “-e <command>” option to execute commands remotely. If we need to do that we first establish a listening socket on the target server…
server> ncat -l 192.168.122.1 –ssl -e /bin/bash
… and then we can connect remotely and execute any command we could run as the logged in user:
client> ncat 192.168.122.1
ls -l
total 3444
-rw-rw-r–. 1 marc marc 2975492 Mar 21 23:05 903-linux-x64.zip
-rw-r–r–. 1 root root 391 Mar 22 13:11 allow-ssh.xml
-rw-r–r–. 1 root root 18214 Apr 4 16:23 boot.log
-rw-r–r–. 1 root root 241 Mar 21 23:26 home-net.xml
drwxr-xr-x. 2 marc marc 4096 Mar 8 20:24 hsperfdata_marc
drwxr-xr-x. 2 root root 4096 Apr 3 01:10 hsperfdata_root
-rw-r–r–. 1 root root 0 Mar 31 00:08 logs.txt
drwx——. 2 root root 16384 Nov 29 15:03 lost+found
Opening a listening socket like the one above is a blatantly obvious risk as it gives the remote connection freedom to do as they like. But we can execute any command we want so we could give it something a bit more harmless such as …
server> ncat -l 192.168.122.1 –ssl -c “/bin/echo The time here is `date`” -k -m1
… so a connecting socket would only get something like …
client> ncat 192.168.122.1 –ssl
The time here is Wed Apr 5 01:52:57 CEST 2017
… and would not be able to do anything else. Basically, we should use common sense if the listening socket is meant to be permanent to limit the risk.
The “-k” flag used in the listening socket stands for keep-alive. Without it, the listening socket will be closed as soon as the first remote connection is closed. With it, it will remain open and ready to serve subsequent connections.
The “-m1” limits the number of concurrent connections to 1. The default value for max concurrent connections is 100 in UNIX/Linux but it can be set to any other reasonable value.
Security
Obviously we should make sure that listening ncat sockets are only available to the intended IPs via firewall filtering. But for added security, we can specify what servers are allowed/denied connection to netcat listening sockets:
server> ncat -l 192.168.122.1 –ssl -c “/bin/echo The time here is `date`” -k -m1 –allow 192.168.122.0/24
In the example above we are using SSL and allowing only the given network access to the socket. Much safer! We can list the IPs and networks we grant access in a file and then pass the file to netcat with the “–allowfile” option:
server> cat allow-file.ncat
192.168.122.0/24
192.168.123.0/24
192.168.124.0/24
.
server>
ncat -l 192.168.122.1 –ssl -c “/bin/echo The time here is `date`” -k -m1 –allowfile=allow-file.ncat
We can do the exact opposite with the options “–deny” and “–denyfile“.
As we have seen before, SSL can be used to establish an encrypted connection. But we can do more than that:
# ncat -l –ssl –-ssl-cert /etc/pki/tls/cert.pem –ssl-key /var/key/server-key.pem
With the command above we have stated the certificate and private key to use. We can verify the certificate and matching of the domain name with:
# ncat –ssl-verify 192.168.122.1 443
Verification is performed using the ca-cert.crt file bunded with netcat plus any certificates provided by the OS. But if we want to use a certificate not signed by a certification authority, then we must use the –ssl-trustfile option:
# ncat –ssl-verify –ssl-trustfile private-certificates.pem 192.168.122.1 443
Other options
There are a few more options we can use with netcat:
• -4: used to force IPv4 only
• -6: used to force IPv6 only
• -U: when we want to use UNIX sockets (e.g. ncat -l -U /var/tmp/netcat.sock)
• -u: when we want to use UDP instead of the default TCP
• –sctp: when we want to use SCTP instead of the default TCP
• -d: used to force a delay in seconds, minutes or hours between successive reads/writes. For instance “-d 1s” will add a delay of 1 second after each read/write to the socket.
• -i: used to specify a maximum idle time before timeout
• -p: used to specify a binding source port
• -s: used to specify a binding source IP address
• -proxy <ip:port>: used to specify a proxy through which the connection is established
• -proxy-type <type>: can be set to http, socks4 or socks5
• -proxy-auth <username:password>