RedRoom Recon Category : Portscan


What is the Portscan?
The Portscan tool is designed to identify open ports on a target system, detect the services running on those ports, and perform banner grabbing to collect additional details. It primarily uses TCP packets to gather this information but UDP and ICMP packets are an option too
Where does it help?
Knowing which ports are open and what services they host is critical for planning your next move—whether for defense or offense. For example, identifying a specific service can lead you to check for known vulnerabilities that need patching or, in the case of red team operations, could be exploited.
Methods Portscan Uses
Portscan builds upon the TCP scanning logic introduced in the Hostscan tool but with a broader range of scan types for more thorough results. In addition to traditional stealth and full TCP scans, it also supports:
FIN Scan – Sends a TCP packet with only the FIN flag set. Closed ports typically respond with a RST packet, while open ports ignore it, helping identify live services without completing a full handshake.
XMAS Scan – Sends a TCP packet with FIN, URG, and PSH flags set, creating a “lit up” packet. Like FIN scans, open ports often stay silent, while closed ports send back a RST.
ACK Scan – Sends an ACK packet to check firewall rules and filtering. It doesn’t identify open ports directly but can reveal whether a port is filtered or unfiltered.
Additionally, Portscan uses a built-in dictionary mapping common ports to their default services, allowing it to quickly match discovered ports with the most likely running applications.
Structure of the Portscan
Portscan can operate either as a standalone tool or as a method within other tools.
Here, we’ll look at both cases—starting with its standalone operation.
Running Portscan as a Standalone Tool
When run independently, Portscan accepts its own set of flags, with two being essential:
-r
– Specifies the target range or a single IP.-m
– Defines the scan method (available options:TCP
,UDP
,ICMP
).
Once executed, the tool’s main handler begins processing the request.
Inside portscan.py
from .methods_recon.digital_fingerprinting.find_ports import PortScan
from Essentials.utils import print_portscan_results
def run(args):
try:
tcp_flags = PortScan.parse_tcp_flags(args.extra)
if tcp_flags is None:
class DummyFlags:
stealth = False
fin = False
ack = False
xmas = False
aggressive = False
tcp_flags = DummyFlags()
results = PortScan.Scan_method_handler(args.range, tcp_flags, args.timeout, args.retries)
except Exception as e:
print(f"Error during port scanning: {e}")
print_portscan_results(results)
Here’s what’s happening :
Importing dependencies –
PortScan
is imported from themethods_
recon.digital
_fingerprinting.find_ports
module.print_portscan_results
is imported fromEssentials.utils
to format and display the scan results.(we will talk about utilites on another article)
Parsing TCP flags –
The script attempts to parsetcp_flags
from the command-line arguments. These flags define the type of TCP scan (e.g., stealth, FIN, ACK, XMAS).Fallback to default scan –
If no TCP flags are provided, the script creates aDummyFlags
class where all scan types are set toFalse
.
This effectively means: run a standard full TCP scan.Executing the scan –
TheScan_method_handler
method is called with the target range, chosen TCP flags, and timeout/retry settings.Outputting results –
The results are passed toprint_portscan_results
for a clean, readable output.
Inside find_ports.py
:
@staticmethod
def Scan_method_handler(ip_range, tcp_flags=None, timeout=1, retries=1, max_workers=200):
try:
network = ipaddress.ip_network(ip_range, strict=False)
except ValueError:
print(colored(f"[!] Invalid IP range: {ip_range}", "red"))
return []
ports = getattr(tcp_flags, "port", None) or list(COMMON_PORTS.keys())
if tcp_flags:
if tcp_flags.aggressive:
scan_funcs = [SCAN_METHODS["stealth"], SCAN_METHODS["ACK"], SCAN_METHODS["FIN"]]
elif tcp_flags.stealth:
scan_funcs = [SCAN_METHODS["stealth"]]
elif tcp_flags.fin:
scan_funcs = [SCAN_METHODS["FIN"]]
elif tcp_flags.xmas:
scan_funcs = [SCAN_METHODS["XMAS"]]
elif tcp_flags.ack:
scan_funcs = [SCAN_METHODS["ACK"]]
else:
scan_funcs = [SCAN_METHODS["connect"]]
else:
scan_funcs = [SCAN_METHODS["connect"]]
all_results = {}
scanned_pairs = set()
for scan_func in scan_funcs:
scan_name = scan_func.__name__
targets = [
(ip, port) for ip, port in product(network.hosts(), ports)
if (str(ip), port) not in scanned_pairs
]
with ThreadPoolExecutor(max_workers=max_workers) as executor:
results = list(executor.map(lambda ip_port: scan_func(ip_port[0], [ip_port[1]], timeout, retries), targets))
for ip, port_list in results:
for port in port_list:
scanned_pairs.add((ip, port))
formatted_results = {}
for ip, port_list in results:
if ip not in formatted_results:
formatted_results[ip] = set()
formatted_results[ip].update(port_list)
final_results = []
for ip, port_set in formatted_results.items():
open_ports = []
filtered_ports = []
services = []
if scan_name in ['ACK', 'stealth', 'FIN']:
filtered_ports = sorted(port_set)
else:
open_ports = sorted(port_set)
for port in open_ports:
banner = PortScan.grab_banner(ip, port, timeout)
services.append({
"port": port,
"banner": banner or COMMON_PORTS.get(port, "Unknown")
})
final_results.append({
"ip": ip,
"open_ports": open_ports,
"filtered_ports": filtered_ports,
"services": services,
"scan_type": scan_name
})
all_results[scan_name] = final_results
return all_results
I’ve structured the find_
ports.py
file so that each scan method is its own function, with the PortScan
class acting as the main controller.
Inside this class, the handler function is responsible for:
Parsing the target IP and ports to scan.
Determining which scan methods should run (based on the provided flags).
Using parallel threading to speed up the scanning process.
Appending the results into a final dictionary, where each key represents a specific data type and each value stores the corresponding scan result.
@staticmethod
def grab_banner(ip, port, timeout=2):
try:
with socket.create_connection((ip, port), timeout=timeout) as s:
s.settimeout(timeout)
return s.recv(1024).decode(errors="ignore").strip()
except Exception:
return None
Portscan also includes a straightforward, standard banner grabbing implementation.
This step queries the target service on an open port and retrieves its initial response (the “banner”), which often contains useful details like service type, version, or even system information.
Running Portscan as a Method
When running Portscan as a method—as we did in the Hostprofile tool—you simply provide the required inputs and call the find_
ports.py
module directly.
This allows Portscan to perform only the specific scanning logic needed, without going through the standalone handler or additional CLI parsing.
Conclusion
Portscan is one of the “hybrid” tools in RedRoom, meaning it can operate both as a standalone tool and as an internal method for other modules.
Because of this dual role, the design prioritizes simplicity and speed over maximum scanning efficiency.
The goal is to get reliable, actionable results as quickly as possible, whether it’s run on its own or embedded in a larger reconnaissance workflow.
Next up: RedRoom – Recon Category: TraceRoute
Subscribe to my newsletter
Read articles from Ektoras Kalantzis directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
