Skip to content

Commit

Permalink
Merge pull request #138 from rackerlabs/nmap_port_range_carver
Browse files Browse the repository at this point in the history
Added nmap_port_range_carver files
  • Loading branch information
derpadoo committed Jan 3, 2020
2 parents 6bee67d + 19e1c95 commit 16b1098
Show file tree
Hide file tree
Showing 4 changed files with 27,521 additions and 0 deletions.
90 changes: 90 additions & 0 deletions nmap_port_range_carver/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Carve out top TCP/UDP ranked ports from nmap according to the nmap-services file

A standalone script to carve out a range of the top TCP/UDP ports according to the `nmap-services` file. This is useful
when:

1. You want to scan a subset of the ports specified in `--top-ports`, say the 10th through 20th top TCP ports, but not
the 1st or 9th ports.

2. You want the 1337th ranked TCP port.

3. You want to utilize nmap to scan **both** TCP and UDP, but not scan the same number of top ports.

This works and will scan the top 10 ports for BOTH TCP and UDP

```bash
nmap --top-ports 10 -sU -sT <TARGET>
```

but you can't only scan the top 20 TCP and top 10 UDP ports using `--top-ports`.

## Installation

```bash
git clone https://github.com/rackerlabs/scantron.git
cd scantron/nmap_port_range_carver
virtualenv -p python3 .venv # If using a virtual environment.
source .venv/bin/activate # If using a virtual environment.
```

## Command Line Usage

Script switches

```bash
python nmap_port_range_carver.py -h
```

Retrieve TCP ports ranked 10 through 20:

```bash
$ python nmap_port_range_carver.py -s 10 -e 20
port_rank_list: [139, 143, 53, 135, 3306, 8080, 1723, 111, 995, 993, 5900]
port_rank_csv: 139,143,53,135,3306,8080,1723,111,995,993,5900
```

Retrieve 1,337th ranked TCP port:

```bash
$ python nmap_port_range_carver.py -s 1337 -e 1337
port_rank_list: [7010]
port_rank_csv: 7010
```

Retrieve UDP ports ranked 50 through 60:

```bash
$ python nmap_port_range_carver.py -s 50 -e 60 -p udp
port_rank_list: [1027, 177, 1719, 427, 497, 4444, 1023, 65024, 19, 9, 49193]
port_rank_csv: 1027,177,1719,427,497,4444,1023,65024,19,9,49193
```

## Python Import Usage

If used as a Python module, it returns a dictionary with a keys for a Python list and CSV string:

```python
import nmap_port_range_carver
tcp_ports_range_10_20 = nmap_port_range_carver.main(start_rank=10, end_rank=20, protocol="tcp")
print(tcp_ports_range_10_20)
```

```json
{
"port_rank_list": [139, 143, 53, 135, 3306, 8080, 1723, 111, 995, 993, 5900],
"port_rank_csv": "139,143,53,135,3306,8080,1723,111,995,993,5900"
}
```

## Generate top ports files from nmap's nmap-services

> Note: The `nmap-services` file only contains the top 8309 ports.
These files are already provided, but here are the commands to generate them.

```bash
egrep /tcp /usr/share/nmap/nmap-services | sort -r -k3 | sed 's/[\t ]/,/g' \
| cut -d "," -f 2 | cut -f 1 -d "/" > nmap_top_ports_tcp.txt
egrep /udp /usr/share/nmap/nmap-services | sort -r -k3 | sed 's/[\t ]/,/g' \
| cut -d "," -f 2 | cut -f 1 -d "/" > nmap_top_ports_udp.txt
```
100 changes: 100 additions & 0 deletions nmap_port_range_carver/nmap_port_range_carver.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#!/usr/bin/env python

# Standard Python libraries.
import argparse

# Third party Python libraries.


# Custom Python libraries.


# BASH command to generate nmap_top_ports_PROTOCOL.txt files.
r"""
egrep /tcp /usr/share/nmap/nmap-services | sort -r -k3 | sed 's/[\t ]/,/g' \
| cut -d "," -f 2 | cut -f 1 -d "/" > nmap_top_ports_tcp.txt
egrep /udp /usr/share/nmap/nmap-services | sort -r -k3 | sed 's/[\t ]/,/g' \
| cut -d "," -f 2 | cut -f 1 -d "/" > nmap_top_ports_udp.txt
"""


def main(start_rank, end_rank, protocol="tcp"):

if protocol == "tcp":
port_file = "nmap_top_ports_tcp.txt"

elif protocol == "udp":
port_file = "nmap_top_ports_udp.txt"

else:
print("This should never be reached.")
exit()

# Build list of port ranks.
port_list = []

with open(port_file, "r") as fh:
for index, port in enumerate(fh):
port_list.append(port.strip())

# Don't subtract one from end_rank to include actual rank.
# Creates a list of strings, will covert to list of ints later.
port_rank_list_temp = port_list[(start_rank - 1) : end_rank] # noqa
port_rank_csv = ",".join(port_rank_list_temp)

port_rank_list = []
for rank in port_rank_list_temp:
port_rank_list.append(int(rank))

print(f"port_rank_list: {port_rank_list}")
print(f"port_rank_csv: {port_rank_csv}")

# fmt: off
port_rank_dict = {
"port_rank_list": port_rank_list,
"port_rank_csv": port_rank_csv,
}
# fmt: on

return port_rank_dict


if __name__ == "__main__":

parser = argparse.ArgumentParser(description="")
parser.add_argument(
"-s", dest="start_rank", action="store", type=int, required=True, help="Port rank to start at. Minimum: 1"
)
parser.add_argument(
"-e", dest="end_rank", action="store", type=int, required=True, help="Port rank to end at. Maximum: 8309"
)
parser.add_argument(
"-p",
dest="protocol",
action="store",
required=False,
default="tcp",
help="Specify tcp or udp protocol. Default: tcp",
)

args = parser.parse_args()

args.protocol = args.protocol.lower()

if args.protocol not in ["tcp", "udp"]:
print("Protocol must be 'tcp' or 'udp'")
exit()

if args.end_rank < args.start_rank:
print("Start rank must be less than (<) end rank.")
exit()

if args.start_rank not in range(1, 8310):
print("Port start rank must be 1-8309 inclusive")
exit()

if args.end_rank not in range(1, 8310):
print("Port end rank must be 1-8309 inclusive")
exit()

main(**vars(args))
Loading

0 comments on commit 16b1098

Please sign in to comment.