I’ve finished yet another learning course, this time about nmap
, and I just have to share my excitement with somebody. Like, probably everyone has heard at least once that “nmap
– is a tool for detecting open ports”, and that’s it. At least that’s how I first heard about it. But, apparently, “detecting open ports” doesn’t tell the full story. It’s not just about the ports – one can get a full picture of what’s going on inside a local network. Even if that network is “home Wi-Fi”!
Detecting network hosts
For instance, let’s talk about my own home network. It’s pretty regular one – one gateway/router, two Wi-Fi hotspots and lots of junk connected to them. Address space belongs to a class C of private IP addresses, and it’s probably identical to millions of other home networks – 192.168.1.0/24
.
But who is actually connected to my network? Address space allows connection of 251 devices (256 – 3 (router/access points) – 2 reserved), so who is there now? Forgotten server? Sneaky neighbour leaching on free internet for years?
nmap
is exactly the tool to answer these questions. We just need to type some spells in the terminal and voilà:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
nmap -sn 192.168.1.0/24 | grep "Nmap scan report" # Nmap scan report for 192.168.1.1 # Nmap scan report for 192.168.1.38 # Nmap scan report for 192.168.1.39 # Nmap scan report for 192.168.1.41 # Nmap scan report for 192.168.1.46 # Nmap scan report for 192.168.1.53 # Nmap scan report for 192.168.1.61 # Nmap scan report for 192.168.1.64 # Nmap scan report for 192.168.1.78 # Nmap scan report for git.dotsandbrackets.com (192.168.1.88) # Nmap scan report for 192.168.1.114 # Nmap scan report for 192.168.1.121 # Nmap scan report for 192.168.1.122 # Nmap scan report for 192.168.1.190 # Nmap scan report for 192.168.1.200 |
-sn
parameter stands for ping scan
. No ports examination, no OS detection, no nothing. We just checking who is out there. 192.168.1.0/24
defines target address range and could be either single IP, like 192.168.1.1
, or enumeration of IPs, like – 192.168.1.1-200
, or a whole CIDR – 192.168.1.0/24
.
Now I know that as of today there are 15 hosts in my network. That’s actually a bit less than I thought.
Detecting host type
Host IP on its own doesn’t tell much. It’s way more interesting to understand what this host is about. At least, what operating system is runs. The latter is done via -O
parameter, producing results similar to these:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
sudo nmap -O 192.168.1.0/24 #.... #Nmap scan report for 192.168.1.46 #Host is up (0.011s latency). #Not shown: 995 closed tcp ports (reset) #PORT STATE SERVICE #80/tcp open http #443/tcp open https #515/tcp open printer #631/tcp open ipp #9100/tcp open jetdirect #Device type: general purpose #Running: Wind River VxWorks #OS CPE: cpe:/o:windriver:vxworks #OS details: VxWorks #Network Distance: 1 hop #..... |
“Wind River VxWorks” – I didn’t even know that it’s a thing. But apparently yes, it’s a popular Real-Time OS for embedded systems. It seems like I’ve found my printer! The cool part is I had no idea that it has a web interface, which according to nmap
it does at port 80. I owned this device for years!
However, -O
parameter performs only basic OS detection. After all, OS detection is a non-trivial thing, and doing it right takes time and possibly an unwanted attention of a network admin. However, in some scenarios this is justified, so here are a few tweaks.
First, --osscan-guess
will tell nmap
to guess harder (which still might give you results like “I’m 90% certain it’s Windows. And I’m also 91% certain it’s Linux”). Second, -sC
argument will turn on the set of standard Lua scripts, that smart people wrote to perform some extra guesses. Since -sC
works in other queries too, I like it the most.
Finally, there is -A
– aggressive. -A
is basically everything we’ve mentioned so far + a few minor tweaks. Results will probably be the best, but if your network had some sort of IDS (Intrusion Detection System) which didn’t wake up before, it probably will now.
Detecting host services
We can figure out what services are exposed by the host with yet another command line parameter – -sV
. However, not unlike OS detection, detecting services is also not 100% precise science. We still can enhance the results by enabling Lua scripts (-sC
), but here and there will be services which leave nmap
puzzled.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
sudo nmap -sV -sC -p- 192.168.1.88 #... #139/tcp open netbios-ssn Samba smbd 3.X - 4.X (workgroup: WORKGROUP) #445/tcp open netbios-ssn Samba smbd 4.7.6-Ubuntu (workgroup: WORKGROUP) #... #8080/tcp open http nginx 1.15.9 #| http-title: Grafana #|_Requested resource was /login #|_http-trane-info: Problem with XML parsing of /evox/about #| http-robots.txt: 1 disallowed entry #... #8200/tcp open trivnet1? #| fingerprint-strings: #| GetRequest: #| HTTP/1.0 307 Temporary Redirect #| Cache-Control: no-store #| Content-Type: text/html; charset=utf-8 #| Location: /ui/ #| Date: Sat, 26 Mar 2022 23:06:46 GMT #| Content-Length: 40 #| href="/ui/">Temporary Redirect</a>. |
Here it found the bunch of services, including someone truly unexpected – a web service at port 8200. Since the service itself suggested redirecting to /ui
(HTTP/1.0 307 Temporary Redirect
), I went there and discovered… HashiCorp Vault! How did it get there? Was it sitting there since the time I wrote a blog post about it? Wasn’t it like 4 years or so ago?
But things like this happen all the time. Last time I found a forgotten WordPress instance.
Looking for open ports
That’s what nmap
was supposed to do all along. Well, it was actually checking for open ports during OS and services detection, but when we just need the ports, there’s an option for that. Moreover, the whole experience will be much faster:
1 2 3 4 5 6 7 8 9 10 11 12 |
sudo nmap -sS 192.168.1.88 #... #PORT STATE SERVICE #22/tcp open ssh #80/tcp open http #111/tcp open rpcbind #139/tcp open netbios-ssn #445/tcp open microsoft-ds #5000/tcp open upnp #8080/tcp open http-proxy #8200/tcp open trivnet1 #9090/tcp open zeus-admin |
-sS
looks for open TCP ports. "S"
itself stands for SYN
– the first of three network packets that establishes TCP connection. Since nmap
just needs to check if someone’s listening, it’ll abort the handshake after receiving SYN/ACK package. Nice and quick. As a side effect, working on a network packet level usually requires admin credentials, so you’ll probably be asked to use sudo
. If sudo
is not an option, there’s always -sT
switch, which also detects TCP ports, but relies on OS functions to establish a full-blown TCP connection. It will be slower, but less admin’y.
-sU
looks for UDP ports. I’ve found three of those on my basement server. Not sure what to do with that information now.
Formatting the output
I had no idea that output formatting could be something I might be interested in, but here we are. Apparently, nmap
can output results in multiple formats. There are boring ones, like -oN
– default, or -oG
– greppable, but there’s also an ancient one – oX
– XML. Among those three, XML is the funniest.
Not only XML is much easier to process programmatically, there’s also such thing as XSLT. Extensible Stylesheet Language Transformation. Modern hipsters probably haven’t heard of it, but somewhere between the discovery of America and WWI I used it to generate perfectly valid T-SQL from an XML document, which in its turn was generated from a .NET class library. Good ol’ days.
Anyhow, nmap
ships with XSL-transformation document that is capable of converting nmap
‘s XML into pretty decent looking HTML. Here’s how it works:
- Running ports detection and outputting the result into XML
sudo nmap -sS 192.168.1.88 -oX server-ports.xml
- applying built-in XSLT:
xsltproc server-ports.xml -o server-ports.html
- checking out generated HTML
open server-ports.html
- enjoying the view:
Beautiful witchcraft.
Conclusion
Aren’t you excited? Ancient mantra – “nmap
is a tool for scanning the ports” – is actually pretty cool utility which can build a picture of who exactly lives in your (or maybe not only yours) network. Without it, I’d have no idea that my printer has a web interface, and that a certain someone should’ve shut down HashiCorp Vault service years ago.
Moreover, if you are bored and accidentally decided to open nmap
‘s manual – man nmap
– inside a very decent documentation about the tool, there’s a section called “Port Scanning Techniques”, which is a pure gold. That’s a nicely written article about how to use the tool in a wild professionally.
PS
OK, so I couldn’t stop thinking why there’s a Vault on my server’s port 8200. Since I wouldn’t install it on a bare metal, it’s probably running in a container, so: docker ps
, and yes, here is the guy:
1 2 |
docker ps # 4aff35fec2db vault "docker-entrypoint.s…" 14 months ago Up 3 months 0.0.0.0:8200->8200/tcp |
It’s been there for 14 months. Unbelievable.
Since it’s restarted 3 months ago, it’s most likely maintained by docker-compose, so there should be some mounts or something that could lead to container origins:
1 2 3 4 |
docker inspect 4aff35fec2db # "HostConfig": { # "Binds": [ # "/home/pav/Projects/rbc-scrapper/vault:/vault/config:rw" |
Ok, I think I remember now. I used to have a small pet project called rbc-scrapper
. It was supposed to periodically go to my bank account and scrape some info that I’d want to use elsewhere. NodeJS, Selenium, and yes, Vault. Oh, well. The project is long dead, so docker-compose down
and the mystery is over.