Skip to content

Commit 593e019

Browse files
committed
Fixing Cl
1 parent bfbc159 commit 593e019

3 files changed

Lines changed: 135 additions & 0 deletions

File tree

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44
self-assessment/
55
temp/
66
tmp/
7+
!temp/
8+
temp/*
9+
!temp/nmap/
10+
temp/nmap/*
11+
!temp/nmap/nmap-services
12+
!temp/nmap/nmap-service-probes
713
#===========================================================
814

915

@@ -42,6 +48,7 @@ install/test-root/
4248

4349
#===========================================================
4450
# Others...
51+
#===========================================================
4552
tree.txt
4653
releases/
4754
#===========================================================

lib/asrfacet_rb/scanner/probe_db.rb

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,46 @@ def to_h
4444
ROOT = File.expand_path("../../../temp/nmap", __dir__)
4545
SERVICES_PATH = File.join(ROOT, "nmap-services")
4646
PROBES_PATH = File.join(ROOT, "nmap-service-probes")
47+
FALLBACK_SERVICE_NAMES = {
48+
1 => "tcpmux",
49+
7 => "echo",
50+
20 => "ftp-data",
51+
21 => "ftp",
52+
22 => "ssh",
53+
23 => "telnet",
54+
25 => "smtp",
55+
53 => "domain",
56+
80 => "http",
57+
110 => "pop3",
58+
111 => "rpcbind",
59+
135 => "msrpc",
60+
139 => "netbios-ssn",
61+
143 => "imap",
62+
389 => "ldap",
63+
443 => "https",
64+
445 => "microsoft-ds",
65+
465 => "smtps",
66+
587 => "submission",
67+
993 => "imaps",
68+
995 => "pop3s"
69+
}.freeze
70+
FALLBACK_SERVICE_LOOKUP_EXTRAS = {
71+
[53, :udp] => "domain",
72+
[67, :udp] => "bootps",
73+
[68, :udp] => "bootpc",
74+
[69, :udp] => "tftp",
75+
[123, :udp] => "ntp",
76+
[161, :udp] => "snmp",
77+
[443, :tcp] => "https",
78+
[1433, :tcp] => "ms-sql-s",
79+
[1434, :udp] => "ms-sql-m",
80+
[3306, :tcp] => "mysql",
81+
[5060, :udp] => "sip",
82+
[5432, :tcp] => "postgresql",
83+
[6379, :tcp] => "redis",
84+
[8443, :tcp] => "https-alt",
85+
[27017, :tcp] => "mongodb"
86+
}.freeze
4787
SERVICE_FAMILY_ALIASES = {
4888
"null" => { probe_names: ["NULL"], services: [] },
4989
"genericlines" => { probe_names: ["GenericLines"], services: [] },
@@ -66,6 +106,8 @@ class << self
66106
private
67107

68108
def load_services
109+
return fallback_services unless File.file?(SERVICES_PATH)
110+
69111
top_ports = []
70112
lookup = {}
71113

@@ -95,6 +137,8 @@ def load_services
95137
end
96138

97139
def load_probes
140+
return fallback_probes unless File.file?(PROBES_PATH)
141+
98142
probes = []
99143
current = nil
100144

@@ -237,6 +281,76 @@ def expand_ports(spec)
237281
end
238282
end.uniq
239283
end
284+
285+
def fallback_services
286+
top_ports = (1..1000).map do |port|
287+
{
288+
port: port,
289+
proto: :tcp,
290+
service: FALLBACK_SERVICE_NAMES.fetch(port, "unknown"),
291+
frequency: (1001 - port).to_f
292+
}
293+
end
294+
lookup = top_ports.each_with_object({}) do |entry, memo|
295+
memo[[entry[:port], entry[:proto]]] = entry[:service]
296+
end
297+
FALLBACK_SERVICE_LOOKUP_EXTRAS.each do |key, value|
298+
lookup[key] = value
299+
end
300+
[top_ports.freeze, lookup.freeze]
301+
end
302+
303+
def fallback_probes
304+
[
305+
fallback_probe("NULL", :tcp, "", matches: [], softmatches: []),
306+
fallback_probe("GenericLines", :tcp, "\r\n", ports: [21, 22, 23, 25, 80, 110, 143], matches: [], softmatches: []),
307+
fallback_probe("HTTPOptions", :tcp, "OPTIONS / HTTP/1.0\r\n\r\n", ports: [80, 8080, 8000], ssl_ports: [443, 8443], matches: [match_entry("http", "^HTTP/1\\.[01] 200", metadata: { product: "Generic HTTP", version: nil, extra: nil, cpes: [] })]),
308+
fallback_probe("RTSPRequest", :tcp, "OPTIONS * RTSP/1.0\r\n\r\n", ports: [554], matches: [match_entry("rtsp", "^RTSP/", metadata: { product: "Generic RTSP", version: nil, extra: nil, cpes: [] })]),
309+
fallback_probe("SSLSessionReq", :tcp, "", ports: [], ssl_ports: [443, 8443], matches: [], softmatches: [match_entry("ssl", "a^", metadata: { product: nil, version: nil, extra: nil, cpes: [] })]),
310+
fallback_probe("SSHSessionReq", :tcp, "SSH-2.0-ASRFacet-Rb\r\n", ports: [22], matches: [match_entry("ssh", "^SSH-", metadata: { product: "Generic SSH", version: nil, extra: nil, cpes: [] })]),
311+
fallback_probe("SMTPRequest", :tcp, "EHLO asrfacet-rb.local\r\n", ports: [25, 465, 587], matches: [match_entry("smtp", "^220", metadata: { product: "Generic SMTP", version: nil, extra: nil, cpes: [] })]),
312+
fallback_probe("FTPRequest", :tcp, "QUIT\r\n", ports: [21], matches: [match_entry("ftp", "^220", metadata: { product: "Generic FTP", version: nil, extra: nil, cpes: [] })]),
313+
fallback_probe("Sqlping", :udp, "\x02".b, ports: [1434], matches: [match_entry("ms-sql-s", ".", flags: "s", metadata: { product: "Microsoft SQL Server", version: nil, extra: nil, cpes: [] })]),
314+
fallback_probe("MySQLRequest", :tcp, "\n".b, ports: [3306], matches: [match_entry("mysql", ".", flags: "s", metadata: { product: "MySQL", version: nil, extra: nil, cpes: [] })]),
315+
fallback_probe("PostgresRequest", :tcp, "\x00\x00\x00\x08\x04\xd2\x16/".b, ports: [5432], matches: [match_entry("postgresql", ".", flags: "s", metadata: { product: "PostgreSQL", version: nil, extra: nil, cpes: [] })]),
316+
fallback_probe("redis-server", :tcp, "INFO\r\n", ports: [6379], matches: [match_entry("redis", ".", flags: "s", metadata: { product: "Redis", version: nil, extra: nil, cpes: [] })]),
317+
fallback_probe("mongodb", :tcp, "\x3a\x00\x00\x00".b, ports: [27_017], matches: [match_entry("mongodb", ".", flags: "s", metadata: { product: "MongoDB", version: nil, extra: nil, cpes: [] })]),
318+
fallback_probe("DNSVersionBindReq", :udp, "\x00\x00\x10\x00\x00\x01\x00\x00\x00\x00\x00\x00\x07version\x04bind\x00\x00\x10\x00\x03".b, ports: [53], matches: [match_entry("domain", ".", flags: "s", metadata: { product: "DNS", version: nil, extra: nil, cpes: [] })]),
319+
fallback_probe("SIPOptions", :udp, "OPTIONS sip:asrfacet-rb SIP/2.0\r\n\r\n", ports: [5060], matches: [match_entry("sip", "SIP/", metadata: { product: "SIP", version: nil, extra: nil, cpes: [] })])
320+
].freeze
321+
end
322+
323+
def fallback_probe(name, proto, probe_str, ports: [], ssl_ports: [], matches: nil, softmatches: nil, rarity: 5, wait_ms: 5000)
324+
Probe.new(
325+
name: name,
326+
proto: proto,
327+
probe_str: probe_str,
328+
rarity: rarity,
329+
wait_ms: wait_ms,
330+
ports: ports,
331+
ssl_ports: ssl_ports,
332+
matches: matches || [],
333+
softmatches: softmatches || []
334+
)
335+
end
336+
337+
def match_entry(service, pattern_source, flags: "", metadata: {})
338+
{
339+
soft: false,
340+
service: service,
341+
pattern_source: pattern_source,
342+
pattern_flags: flags,
343+
metadata: {
344+
product: metadata[:product],
345+
version: metadata[:version],
346+
extra: metadata[:extra],
347+
hostname: metadata[:hostname],
348+
os: metadata[:os],
349+
device: metadata[:device],
350+
cpes: Array(metadata[:cpes])
351+
}
352+
}
353+
end
240354
end
241355

242356
TOP_PORTS, SERVICE_LOOKUP = send(:load_services)

spec/scanner/probe_db_spec.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,18 @@
4747
expect(probe_db.supports_service?("DNSQuery")).to be(true)
4848
expect(probe_db.supports_service?("SIPOptions")).to be(true)
4949
end
50+
51+
it "falls back to bundled defaults when the Nmap data files are unavailable" do
52+
allow(File).to receive(:file?).and_call_original
53+
allow(File).to receive(:file?).with(described_class::SERVICES_PATH).and_return(false)
54+
allow(File).to receive(:file?).with(described_class::PROBES_PATH).and_return(false)
55+
56+
top_ports, lookup = described_class.send(:load_services)
57+
probes = described_class.send(:load_probes)
58+
59+
expect(top_ports.length).to eq(1000)
60+
expect(lookup[[22, :tcp]]).to eq("ssh")
61+
expect(lookup[[53, :udp]]).to eq("domain")
62+
expect(probes.map(&:name)).to include("NULL", "HTTPOptions", "SSLSessionReq", "SIPOptions")
63+
end
5064
end

0 commit comments

Comments
 (0)