Skip to content

Commit b5cae35

Browse files
author
Ekultek
committed
minor tweaks and updates
1 parent a3ff69d commit b5cae35

5 files changed

Lines changed: 310 additions & 121 deletions

File tree

etc/text_files/nmap_opts.lst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@
8989
-oG
9090
-oA
9191
-v
92+
-vv
93+
-vvv
9294
-d
9395
--reason
9496
--open

lib/banner.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import os
22
import random
33

4-
VERSION = "4.0"
4+
VERSION = "4.0.1"
55

66

77
def banner_1(line_sep="#--", space=" " * 30):

lib/scanner/nmap.py

Lines changed: 220 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,12 @@ def do_scan(host, nmap_path, ports=None, arguments=None):
120120
perform the nmap scan
121121
"""
122122
if arguments is None:
123-
arguments = "-sV"
123+
lib.output.misc_info("using default scan arguments")
124+
arguments = [
125+
"-sF", "-Pn", "-sV",
126+
"-O", "-F", "--reason",
127+
"-vvv"
128+
]
124129
launch_arguments = [
125130
nmap_path, '-oX', '-', host,
126131
'-p ' + ports if ports is not None else "",
@@ -150,106 +155,235 @@ def do_scan(host, nmap_path, ports=None, arguments=None):
150155
return output_data, "".join(nmap_warn_tracestack), "".join(nmap_error_tracestack)
151156

152157

158+
# copy pasta :DD
159+
# https://github.com/komand/python-nmap/blob/master/nmap/nmap.py#L273
153160
def parse_xml_output(output, warnings, error):
154161
"""
155-
parse the XML data out of the file into a dict
162+
Analyses NMAP xml scan ouput
163+
May raise PortScannerError exception if nmap output was not xml
164+
Test existance of the following key to know if something went wrong : ['nmap']['scaninfo']['error']
165+
If not present, everything was ok.
166+
:param nmap_xml_output: xml string to analyse
167+
:returns: scan_result as dictionnary
156168
"""
157-
results = {}
169+
# nmap xml output looks like :
170+
# <host starttime="1267974521" endtime="1267974522">
171+
# <status state="up" reason="user-set"/>
172+
# <address addr="192.168.1.1" addrtype="ipv4" />
173+
# <hostnames><hostname name="neufbox" type="PTR" /></hostnames>
174+
# <ports>
175+
# <port protocol="tcp" portid="22">
176+
# <state state="filtered" reason="no-response" reason_ttl="0"/>
177+
# <service name="ssh" method="table" conf="3" />
178+
# </port>
179+
# <port protocol="tcp" portid="25">
180+
# <state state="filtered" reason="no-response" reason_ttl="0"/>
181+
# <service name="smtp" method="table" conf="3" />
182+
# </port>
183+
# </ports>
184+
# <hostscript>
185+
# <script id="nbstat" output="NetBIOS name: GROSTRUC, NetBIOS user: &lt;unknown&gt;, NetBIOS MAC: &lt;unknown&gt;&#xa;" />
186+
# <script id="smb-os-discovery" output=" &#xa; OS: Unix (Samba 3.6.3)&#xa; Name: WORKGROUP\Unknown&#xa; System time: 2013-06-23 15:37:40 UTC+2&#xa;" />
187+
# <script id="smbv2-enabled" output="Server doesn&apos;t support SMBv2 protocol" />
188+
# </hostscript>
189+
# <times srtt="-1" rttvar="-1" to="1000000" />
190+
# </host>
191+
# <port protocol="tcp" portid="25">
192+
# <state state="open" reason="syn-ack" reason_ttl="0"/>
193+
# <service name="smtp" product="Exim smtpd" version="4.76" hostname="grostruc" method="probed" conf="10">
194+
# <cpe>cpe:/a:exim:exim:4.76</cpe>
195+
# </service>
196+
# <script id="smtp-commands" output="grostruc Hello localhost [127.0.0.1], SIZE 52428800, PIPELINING, HELP, &#xa; Commands supported: AUTH HELO EHLO MAIL RCPT DATA NOOP QUIT RSET HELP "/>
197+
# </port>
198+
scan_result = {}
158199
try:
159-
root = ElementTree.fromstring(output)
200+
dom = ElementTree.fromstring(output)
160201
except Exception:
161-
if len(error) != 0:
202+
if len(error) > 0:
162203
raise lib.errors.NmapScannerError(error)
163204
else:
164205
raise lib.errors.NmapScannerError(output)
165-
results['nmap_scan'] = {
166-
'full_command_line': root.get('args'),
167-
'scan_information': {},
168-
'scan_stats': {
169-
'time_string': root.find('runstats/finished').get('timestr'),
170-
'elapsed': root.find('runstats/finished').get('elapsed'),
171-
'hosts_up': root.find('runstats/hosts').get('up'),
172-
'down_hosts': root.find('runstats/hosts').get('down'),
173-
'total_hosts_scanned': root.find('runstats/hosts').get('total')
206+
# nmap command line
207+
scan_result['nmap'] = {
208+
'command_line': dom.get('args'),
209+
'scaninfo': {},
210+
'scanstats': {
211+
'timestr': dom.find("runstats/finished").get('timestr'),
212+
'elapsed': dom.find("runstats/finished").get('elapsed'),
213+
'uphosts': dom.find("runstats/hosts").get('up'),
214+
'downhosts': dom.find("runstats/hosts").get('down'),
215+
'totalhosts': dom.find("runstats/hosts").get('total')}
174216
}
175-
}
176-
if len(error) != 0:
177-
results['nmap_scan']['scan_information']['errors'] = error
178-
if len(warnings) != 0:
179-
results['nmap_scan']['scan_information']['warnings'] = warnings
180-
for info in root.findall('scaninfo'):
181-
results['nmap_scan']['scan_information'][info.get('protocol')] = {
182-
'method': info.get('type'),
183-
'services': info.get('services')
184-
}
185-
for attempted_host in root.findall('host'):
217+
# if there was an error
218+
if len(error) > 0:
219+
scan_result['nmap']['scaninfo']['error'] = error
220+
# if there was a warning
221+
if len(warnings) > 0:
222+
scan_result['nmap']['scaninfo']['warning'] = warnings
223+
# info about scan
224+
for dsci in dom.findall('scaninfo'):
225+
scan_result['nmap']['scaninfo'][dsci.get('protocol')] = {
226+
'method': dsci.get('type'),
227+
'services': dsci.get('services')
228+
}
229+
scan_result['scan'] = {}
230+
for dhost in dom.findall('host'):
231+
# host ip, mac and other addresses
186232
host = None
187-
addresses = {}
188-
vendors = {}
189-
for address in attempted_host.findall("address"):
190-
address_type = address.get('addrtype')
191-
addresses[address_type] = address.get('addr')
192-
if address_type == "ipv4":
193-
host = addresses[address_type]
194-
elif address_type == "mac" and address.get('vendor') is not None:
195-
vendors[addresses[address_type]] = address.get('vendor')
233+
address_block = {}
234+
vendor_block = {}
235+
for address in dhost.findall('address'):
236+
addtype = address.get('addrtype')
237+
address_block[addtype] = address.get('addr')
238+
if addtype == 'ipv4':
239+
host = address_block[addtype]
240+
elif addtype == 'mac' and address.get('vendor') is not None:
241+
vendor_block[address_block[addtype]] = address.get('vendor')
196242
if host is None:
197-
host = attempted_host.find('address').get('addr')
243+
host = dhost.find('address').get('addr')
198244
hostnames = []
199-
if len(attempted_host.findall('hostnames/hostname')) != 0:
200-
for current_hostnames in attempted_host.findall('hostnames/hostname'):
245+
if len(dhost.findall('hostnames/hostname')) > 0:
246+
for dhostname in dhost.findall('hostnames/hostname'):
201247
hostnames.append({
202-
'hostname': current_hostnames.get('name'),
203-
'host_type': current_hostnames.get('type')
248+
'name': dhostname.get('name'),
249+
'type': dhostname.get('type'),
204250
})
205251
else:
206252
hostnames.append({
207-
'hostname': None,
208-
'host_type': None
253+
'name': '',
254+
'type': '',
209255
})
210-
211-
results['nmap_scan'][host] = {}
212-
results['nmap_scan'][host]['hostnames'] = hostnames
213-
results['nmap_scan'][host]['addresses'] = addresses
214-
results['nmap_scan'][host]['vendors'] = vendors
215-
216-
for status in attempted_host.findall('status'):
217-
results['nmap_scan'][host]['status'] = {
218-
'state': status.get('state'),
219-
'reason': status.get('reason')
220-
}
221-
for uptime in attempted_host.findall('uptime'):
222-
results['nmap_scan'][host]['uptime'] = {
223-
'seconds': uptime.get('seconds'),
224-
'lastboot': uptime.get('lastboot')
225-
}
226-
for discovered_port in attempted_host.findall('ports/port'):
227-
protocol = discovered_port.get('protocol')
228-
port_number = discovered_port.get('portid')
229-
port_state = discovered_port.find('state').get('state')
230-
port_reason = discovered_port.find('state').get('reason')
231-
232-
# this is actually a thing!!
233-
name = discovered_config = discovered_version = extra_information = discovered_product = stuff = ""
234-
for discovered_name in discovered_port.findall('service'):
235-
name = discovered_name.get('name')
236-
if discovered_name.get('product'):
237-
discovered_product = discovered_name.get('product')
238-
if discovered_name.get('version'):
239-
discovered_version = discovered_name.get('version')
240-
if discovered_name.get('extrainfo'):
241-
extra_information = discovered_name.get('extrainfo')
242-
if discovered_name.get('conf'):
243-
discovered_config = discovered_name.get('conf')
244-
245-
for other_stuff in discovered_name.findall('cpe'):
246-
stuff = other_stuff.text
247-
if protocol not in results['nmap_scan'][host].keys():
248-
results['nmap_scan'][host][protocol] = list()
249-
results['nmap_scan'][host][protocol].append({
250-
'port': port_number, 'state': port_state, 'reason': port_reason,
251-
'name': name, 'product': discovered_product, 'version': discovered_version,
252-
'extrainfo': extra_information, 'conf': discovered_config, 'cpe': stuff
256+
scan_result['scan'][host] = {'hostnames': hostnames}
257+
scan_result['scan'][host]['addresses'] = address_block
258+
scan_result['scan'][host]['vendor'] = vendor_block
259+
for dstatus in dhost.findall('status'):
260+
# status : up...
261+
scan_result['scan'][host]['status'] = {'state': dstatus.get('state'),
262+
'reason': dstatus.get('reason')}
263+
for dstatus in dhost.findall('uptime'):
264+
# uptime : seconds, lastboot
265+
scan_result['scan'][host]['uptime'] = {'seconds': dstatus.get('seconds'),
266+
'lastboot': dstatus.get('lastboot')}
267+
for dport in dhost.findall('ports/port'):
268+
# protocol
269+
proto = dport.get('protocol')
270+
# port number converted as integer
271+
port = int(dport.get('portid'))
272+
# state of the port
273+
state = dport.find('state').get('state')
274+
# reason
275+
reason = dport.find('state').get('reason')
276+
# name, product, version, extra info and conf if any
277+
name = product = version = extrainfo = conf = cpe = ''
278+
for dname in dport.findall('service'):
279+
name = dname.get('name')
280+
if dname.get('product'):
281+
product = dname.get('product')
282+
if dname.get('version'):
283+
version = dname.get('version')
284+
if dname.get('extrainfo'):
285+
extrainfo = dname.get('extrainfo')
286+
if dname.get('conf'):
287+
conf = dname.get('conf')
288+
for dcpe in dname.findall('cpe'):
289+
cpe = dcpe.text
290+
# store everything
291+
if proto not in list(scan_result['scan'][host].keys()):
292+
scan_result['scan'][host][proto] = list()
293+
# Komand - change proto from dict to list to ease output spec
294+
scan_result['scan'][host][proto].append({
295+
'port': port,
296+
'state': state,
297+
'reason': reason,
298+
'name': name,
299+
'product': product,
300+
'version': version,
301+
'extrainfo': extrainfo,
302+
'conf': conf,
303+
'cpe': cpe
304+
})
305+
script_id = ''
306+
script_out = ''
307+
# get script output if any
308+
for dscript in dport.findall('script'):
309+
script_id = dscript.get('id')
310+
script_out = dscript.get('output')
311+
if 'script' not in list(scan_result['scan'][host][proto][port].keys()):
312+
scan_result['scan'][host][proto][port]['script'] = {}
313+
scan_result['scan'][host][proto][port]['script'][script_id] = script_out
314+
# <hostscript>
315+
# <script id="nbstat" output="NetBIOS name: GROSTRUC, NetBIOS user: &lt;unknown&gt;, NetBIOS MAC: &lt;unknown&gt;&#xa;" />
316+
# <script id="smb-os-discovery" output=" &#xa; OS: Unix (Samba 3.6.3)&#xa; Name: WORKGROUP\Unknown&#xa; System time: 2013-06-23 15:37:40 UTC+2&#xa;" />
317+
# <script id="smbv2-enabled" output="Server doesn&apos;t support SMBv2 protocol" />
318+
# </hostscript>
319+
for dhostscript in dhost.findall('hostscript'):
320+
for dname in dhostscript.findall('script'):
321+
hsid = dname.get('id')
322+
hsoutput = dname.get('output')
323+
if 'hostscript' not in list(scan_result['scan'][host].keys()):
324+
scan_result['scan'][host]['hostscript'] = []
325+
scan_result['scan'][host]['hostscript'].append(
326+
{
327+
'id': hsid,
328+
'output': hsoutput
329+
}
330+
)
331+
# <osmatch name="Juniper SA4000 SSL VPN gateway (IVE OS 7.0)" accuracy="98" line="36241">
332+
# <osclass type="firewall" vendor="Juniper" osfamily="IVE OS" osgen="7.X"
333+
# accuracy="98"><cpe>cpe:/h:juniper:sa4000</cpe><cpe>cpe:/o:juniper:ive_os:7</cpe></osclass>
334+
# </osmatch>
335+
# <osmatch name="Cymphonix EX550 firewall" accuracy="98" line="17929">
336+
# <osclass type="firewall" vendor="Cymphonix" osfamily="embedded"
337+
# accuracy="98"><cpe>cpe:/h:cymphonix:ex550</cpe></osclass>
338+
# </osmatch>
339+
for dos in dhost.findall('os'):
340+
osmatch = []
341+
portused = []
342+
for dportused in dos.findall('portused'):
343+
# <portused state="open" proto="tcp" portid="443"/>
344+
state = dportused.get('state')
345+
proto = dportused.get('proto')
346+
portid = dportused.get('portid')
347+
portused.append({
348+
'state': state,
349+
'proto': proto,
350+
'portid': portid,
253351
})
254-
255-
return results
352+
scan_result['scan'][host]['portused'] = portused
353+
for dosmatch in dos.findall('osmatch'):
354+
# <osmatch name="Linux 3.7 - 3.15" accuracy="100" line="52790">
355+
name = dosmatch.get('name')
356+
accuracy = dosmatch.get('accuracy')
357+
line = dosmatch.get('line')
358+
osclass = []
359+
for dosclass in dosmatch.findall('osclass'):
360+
# <osclass type="general purpose" vendor="Linux" osfamily="Linux" osgen="2.6.X" accuracy="98"/>
361+
ostype = dosclass.get('type')
362+
vendor = dosclass.get('vendor')
363+
osfamily = dosclass.get('osfamily')
364+
osgen = dosclass.get('osgen')
365+
accuracy = dosclass.get('accuracy')
366+
cpe = []
367+
for dcpe in dosclass.findall('cpe'):
368+
cpe.append(dcpe.text)
369+
osclass.append({
370+
'type': ostype,
371+
'vendor': vendor,
372+
'osfamily': osfamily,
373+
'osgen': osgen,
374+
'accuracy': accuracy,
375+
'cpe': cpe,
376+
})
377+
osmatch.append({
378+
'name': name,
379+
'accuracy': accuracy,
380+
'line': line,
381+
'osclass': osclass
382+
})
383+
else:
384+
scan_result['scan'][host]['osmatch'] = osmatch
385+
for dport in dhost.findall('osfingerprint'):
386+
# <osfingerprint fingerprint="OS:SCAN(V=5.50%D=11/[...]S)&#xa;"/>
387+
fingerprint = dport.get('fingerprint')
388+
scan_result['scan'][host]['fingerprint'] = fingerprint
389+
return scan_result

lib/settings.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,9 @@ def complete_text(self, text, state):
5555
personal/custom Load a custom host file
5656
tokens/reset Reset API tokens if needed
5757
external View loaded external commands
58-
ver[sion] View the current version of the program
58+
version View the current version of the program
5959
clean/clear Clean the hosts.txt file of duplicate IP addresses
60+
nmap/mapper/mappy Run an nmap scan on a provided host
6061
help/? Display this help
6162
"""
6263

0 commit comments

Comments
 (0)