- A+
所属分类:业界关注
python-nmap是一个python的库,python2.x使用的是python-nmap-0.1.4,使用过程中遇到一点问题。记录如下:
错误信息:
Traceback (most recent call last): File "<string>", line 1, in <module> File "D:\opt\Python27\lib\multiprocessing\forking.py", line 373, in main prepare(preparation_data) File "D:\opt\Python27\lib\multiprocessing\forking.py", line 488, in prepare '__parents_main__', file, path_name, etc File "E:\Workspace\scanner_01.py", line 13, in <module> nma.scan(hosts='192.168.18.0/24', arguments='-sP') File "D:\opt\Python27\lib\site-packages\nmap\nmap.py", line 417, in scan self._process.start() File "D:\opt\Python27\lib\multiprocessing\process.py", line 130, in start self._popen = Popen(self) File "D:\opt\Python27\lib\multiprocessing\forking.py", line 271, in __init__ dump(process_obj, to_child, HIGHEST_PROTOCOL) File "D:\opt\Python27\lib\multiprocessing\forking.py", line 193, in dump ForkingPickler(file, protocol).dump(obj) File "D:\opt\Python27\lib\pickle.py", line 224, in dump self.save(obj) File "D:\opt\Python27\lib\pickle.py", line 331, in save self.save_reduce(obj=obj, *rv) File "D:\opt\Python27\lib\pickle.py", line 419, in save_reduce save(state) File "D:\opt\Python27\lib\pickle.py", line 286, in save f(self, obj) # Call unbound method with explicit self File "D:\opt\Python27\lib\pickle.py", line 649, in save_dict self._batch_setitems(obj.iteritems()) File "D:\opt\Python27\lib\pickle.py", line 681, in _batch_setitems save(v) File "D:\opt\Python27\lib\pickle.py", line 286, in save f(self, obj) # Call unbound method with explicit self File "D:\opt\Python27\lib\pickle.py", line 747, in save_global (obj, module, name)) pickle.PicklingError: Can't pickle <function scan_progressive at 0x01C255B0>: it 's not found as nmap.nmap.scan_progressive
仔细追查,在pickle.py文件745行抛出了错误:
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "D:\opt\Python27\lib\site-packages\nmap\nmap.py", line 413, in scan target=self.scan_progressive, AttributeError: 'PortScannerAsync' object has no attribute 'scan_progressive'
然后又阅读nmap的源码nmap.py,终于发现在402行,方法scan_progressive被定义在scan方法内部,导致pickle失败。
解决方法:
将方法Scan_progressive定义到外面,并将nmap.py 413行从
target=scan_progressive,
改为
target=self.progressive,
修改后完整代码
#!/usr/bin/env python # -*- coding: latin-1 -*- """ nmap.py - v0.1.4 - 2010.06.20 Author : Alexandre Norman - [email protected] Contributor: Steve 'Ashcrow' Milner - [email protected] Licence : GPL v3 or any later version This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. Test strings : ^^^^^^^^^^^^ >>> import nmap >>> nm = nmap.PortScanner() >>> r=nm.scan('127.0.0.1', '22-443') >>> nm.command_line() u'nmap -oX - -p 22-443 -sV 127.0.0.1' >>> nm.scaninfo() {u'tcp': {'services': u'22-443', 'method': u'connect'}} >>> nm.all_hosts() [u'127.0.0.1'] >>> nm['127.0.0.1'].hostname() u'localhost' >>> nm['127.0.0.1'].state() u'up' >>> nm['127.0.0.1'].all_protocols() [u'tcp'] >>> nm['127.0.0.1']['tcp'].keys() [80, 25, 443, 22, 111] >>> nm['127.0.0.1'].has_tcp(22) True >>> nm['127.0.0.1'].has_tcp(23) False >>> nm['127.0.0.1']['tcp'][22] {'state': u'open', 'reason': u'syn-ack', 'name': u'ssh'} >>> nm['127.0.0.1'].tcp(22) {'state': u'open', 'reason': u'syn-ack', 'name': u'ssh'} >>> nm['127.0.0.1']['tcp'][22]['state'] u'open' >>> nm.scanstats()['uphosts'] u'1' >>> nm.scanstats()['downhosts'] u'0' >>> nm.scanstats()['totalhosts'] u'1' >>> 'timestr' in nm.scanstats().keys() True >>> 'elapsed' in nm.scanstats().keys() True >>> nm.listscan('192.168.1.0/30') [u'192.168.1.0', u'192.168.1.1', u'192.168.1.2', u'192.168.1.3'] >>> nm.listscan('localhost/30') [u'127.0.0.0', u'127.0.0.1', u'127.0.0.2', u'127.0.0.3'] """ __author__ = 'Alexandre Norman ([email protected])' __version__ = '0.1.4' import os import re import string import subprocess import sys import types import xml.dom.minidom import shlex try: from multiprocessing import Process except ImportError: # For pre 2.6 releases from threading import Thread as Process ############################################################################ class PortScanner(object): """ PortScanner allows to use nmap from python """ def __init__(self): """ Initialize the module detects nmap on the system and nmap version may raise PortScannerError exception if nmap is not found in the path """ self._scan_result = {} self._nmap_version_number = 0 # nmap version number self._nmap_subversion_number = 0 # nmap subversion number self._nmap_last_output = '' # last full ascii nmap output is_nmap_found = False # true if we have found nmap self.__process = None # regex used to detect nmap regex = re.compile('Nmap version [0-9]*\.[0-9]*[^ ]* \( http://nmap\.org \)') # launch 'nmap -V', we wait after 'Nmap version 5.0 ( http://nmap.org )' p = subprocess.Popen(['nmap', '-V'], bufsize=10000, stdout=subprocess.PIPE) self._nmap_last_output = p.communicate()[0] # store stdout for line in self._nmap_last_output.split('\n'): if regex.match(line) is not None: is_nmap_found = True # Search for version number regex_version = re.compile('[0-9]+') regex_subversion = re.compile('\.[0-9]+') rv = regex_version.search(line) rsv = regex_subversion.search(line) if rv is not None and rsv is not None: # extract version/subversion self._nmap_version_number = int(line[rv.start():rv.end()]) self._nmap_subversion_number = int(line[rsv.start()+1:rsv.end()]) break if is_nmap_found == False: raise PortScannerError('nmap program was not found in path') return def get_nmap_last_output(self): """ returns the last text output of nmap in raw text this may be used for debugging purpose """ return self._nmap_last_output def nmap_version(self): """ returns nmap version if detected (int version, int subversion) or (0, 0) if unknown """ return (self._nmap_version_number, self._nmap_subversion_number) def listscan(self, hosts='127.0.0.1'): """ do not scan but interpret target hosts and return a list a hosts """ assert type(hosts) in types.StringTypes, 'Wrong type for [hosts], should be a string [was {0}]'.format(type(hosts)) self.scan(hosts, arguments='-sL') return self.all_hosts() def scan(self, hosts='127.0.0.1', ports=None, arguments='-sV'): """ Scan given hosts May raise PortScannerError exception if nmap output something on stderr hosts = string for hosts as nmap use it 'scanme.nmap.org' or '198.116.0-255.1-127' or '216.163.128.20/20' ports = string for ports as nmap use it '22,53,110,143-4564' arguments = string of arguments for nmap '-sU -sX -sC' """ assert type(hosts) in types.StringTypes, 'Wrong type for [hosts], should be a string [was {0}]'.format(type(hosts)) assert type(ports) in types.StringTypes+(types.NoneType,), 'Wrong type for [ports], should be a string [was {0}]'.format(type(ports)) assert type(arguments) in types.StringTypes, 'Wrong type for [arguments], should be a string [was {0}]'.format(type(arguments)) f_args = shlex.split(arguments) # Launch scan args = ['nmap', '-oX', '-', hosts] + ['-p', ports]*(ports!=None) + f_args p = subprocess.Popen(args, bufsize=100000, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # wait until finished # get output (self._nmap_last_output, nmap_err) = p.communicate() # If there was something on stderr, there was a problem so abort... if len(nmap_err) > 0: regex_warning = re.compile('^Warning: .*') for line in nmap_err.split('\n'): if len(line) > 0: rgw = regex_warning.search(line) if rgw is not None: sys.stderr.write(line+'\n') pass else: raise PortScannerError(nmap_err) # nmap xml output looks like : # <host starttime="1267974521" endtime="1267974522"> # <status state="up" reason="user-set"/> # <address addr="192.168.1.1" addrtype="ipv4" /> # <hostnames><hostname name="neufbox" type="PTR" /></hostnames> # <ports> # <port protocol="tcp" portid="22"> # <state state="filtered" reason="no-response" reason_ttl="0"/> # <service name="ssh" method="table" conf="3" /> # </port> # <port protocol="tcp" portid="25"> # <state state="filtered" reason="no-response" reason_ttl="0"/> # <service name="smtp" method="table" conf="3" /> # </port> # </ports> # <times srtt="-1" rttvar="-1" to="1000000" /> # </host> scan_result = {} dom = xml.dom.minidom.parseString(self._nmap_last_output) # nmap command line scan_result['nmap'] = { 'command_line': dom.getElementsByTagName('nmaprun')[0].getAttributeNode('args').value, 'scaninfo': {}, 'scanstats':{'timestr':dom.getElementsByTagName("finished")[0].getAttributeNode('timestr').value, 'elapsed':dom.getElementsByTagName("finished")[0].getAttributeNode('elapsed').value, 'uphosts':dom.getElementsByTagName("hosts")[0].getAttributeNode('up').value, 'downhosts':dom.getElementsByTagName("hosts")[0].getAttributeNode('down').value, 'totalhosts':dom.getElementsByTagName("hosts")[0].getAttributeNode('total').value} } # info about scan for dsci in dom.getElementsByTagName('scaninfo'): scan_result['nmap']['scaninfo'][dsci.getAttributeNode('protocol').value] = { 'method': dsci.getAttributeNode('type').value, 'services': dsci.getAttributeNode('services').value } scan_result['scan'] = {} for dhost in dom.getElementsByTagName('host'): # host ip host = dhost.getElementsByTagName('address')[0].getAttributeNode('addr').value hostname = '' for dhostname in dhost.getElementsByTagName('hostname'): hostname = dhostname.getAttributeNode('name').value scan_result['scan'][host] = PortScannerHostDict({'hostname': hostname}) for dstatus in dhost.getElementsByTagName('status'): # status : up... scan_result['scan'][host]['status'] = {'state': dstatus.getAttributeNode('state').value, 'reason': dstatus.getAttributeNode('reason').value} for dport in dhost.getElementsByTagName('port'): # protocol proto = dport.getAttributeNode('protocol').value # port number converted as integer port = int(dport.getAttributeNode('portid').value) # state of the port state = dport.getElementsByTagName('state')[0].getAttributeNode('state').value # reason reason = dport.getElementsByTagName('state')[0].getAttributeNode('reason').value # name if any name = '' for dname in dport.getElementsByTagName('service'): name = dname.getAttributeNode('name').value # store everything if not proto in scan_result['scan'][host].keys(): scan_result['scan'][host][proto] = {} scan_result['scan'][host][proto][port] = {'state': state, 'reason': reason, 'name': name} script_id = '' script_out = '' # get script output if any for dscript in dport.getElementsByTagName('script'): script_id = dscript.getAttributeNode('id').value script_out = dscript.getAttributeNode('output').value if not 'script' in scan_result['scan'][host][proto][port].keys(): scan_result['scan'][host][proto][port]['script'] = {} scan_result['scan'][host][proto][port]['script'][script_id] = script_out self._scan_result = scan_result # store for later use return scan_result def __getitem__(self, host): """ returns a host detail """ assert type(host) in types.StringTypes, 'Wrong type for [host], should be a string [was {0}]'.format(type(host)) return self._scan_result['scan'][host] def all_hosts(self): """ returns a sorted list of all hosts """ if not 'scan' in self._scan_result.keys(): return [] listh = self._scan_result['scan'].keys() listh.sort() return listh def command_line(self): """ returns command line used for the scan """ return self._scan_result['nmap']['command_line'] def scaninfo(self): """ returns scaninfo structure {u'tcp': {'services': u'22', 'method': u'connect'}} """ return self._scan_result['nmap']['scaninfo'] def scanstats(self): """ returns scanstats structure {'uphosts': u'3', 'timestr': u'Thu Jun 3 21:45:07 2010', 'downhosts': u'253', 'totalhosts': u'256', 'elapsed': u'5.79'} """ return self._scan_result['nmap']['scanstats'] def has_host(self, host): """ returns True if host has result, False otherwise """ assert type(host) is types.StringTypes, 'Wrong type for [host], should be a string [was {0}]'.format(type(host)) if host in self._scan_result['scan'].keys(): return True return False ############################################################################ class PortScannerAsync(object): """ PortScannerAsync allows to use nmap from python asynchronously for each host scanned, callback is called with scan result for the host """ def __init__(self): """ Initialize the module detects nmap on the system and nmap version may raise PortScannerError exception if nmap is not found in the path """ self._process = None self._nm = PortScanner() return def __del__(self): """ Cleanup when deleted """ if self._process is not None and self._process.is_alive(): self._process.terminate() return def scan(self, hosts='127.0.0.1', ports=None, arguments='-sV', callback=None): """ Scan given hosts in a separate process and return host by host result using callback function PortScannerError exception from standard nmap is catched and you won't know about it hosts = string for hosts as nmap use it 'scanme.nmap.org' or '198.116.0-255.1-127' or '216.163.128.20/20' ports = string for ports as nmap use it '22,53,110,143-4564' arguments = string of arguments for nmap '-sU -sX -sC' callback = callback function which takes (host, scan_data) as arguments """ assert type(hosts) in types.StringTypes, 'Wrong type for [hosts], should be a string [was {0}]'.format(type(hosts)) assert type(ports) in types.StringTypes+(types.NoneType,), 'Wrong type for [ports], should be a string [was {0}]'.format(type(ports)) assert type(arguments) in types.StringTypes, 'Wrong type for [arguments], should be a string [was {0}]'.format(type(arguments)) assert type(callback) in (types.FunctionType, types.NoneType), 'Wrong type for [callback], should be a function or None [was {0}]'.format(type(callback)) def scan_progressive(self, hosts, ports, arguments, callback): for host in self._nm.listscan(hosts): try: scan_data = self._nm.scan(host, ports, arguments) except PortScannerError: pass if callback is not None and callable(callback): callback(host, scan_data) return self._process = Process( target=self.progressive, args=(self, hosts, ports, arguments, callback) ) self._process.daemon = True self._process.start() return def stop(self): """ Stop the current scan process """ if self._process is not None: self._process.terminate() return def wait(self, timeout=None): """ Wait for the current scan process to finish, or timeout """ assert type(timeout) in (types.IntType, types.NoneType), 'Wrong type for [timeout], should be an int or None [was {0}]'.format(type(timeout)) self._process.join(timeout) return def still_scanning(self): """ Return True if a scan is currently running, False otherwise """ try: return self._process.is_alive() except: return False ############################################################################ class PortScannerHostDict(dict): """ Special dictionnary class for storing and accessing host scan result """ def hostname(self): """ returns hostname """ return self['hostname'] def state(self): """ returns host state """ return self['status']['state'] def all_protocols(self): """ returns a list of all scanned protocols """ lp = self.keys() lp.remove('status') lp.remove('hostname') lp.sort() return lp def all_tcp(self): """ returns list of tcp ports """ if 'tcp' in self.keys(): ltcp = self['tcp'].keys() ltcp.sort() return ltcp return [] def has_tcp(self, port): """ returns True if tcp port has info, False otherwise """ assert type(port) is types.IntType, 'Wrong type for [port], should be an int [was {0}]'.format(type(port)) if ('tcp' in self.keys() and port in self['tcp'].keys()): return True return False def tcp(self, port): """ returns info for tpc port """ assert type(port) is types.IntType, 'Wrong type for [port], should be an int [was {0}]'.format(type(port)) return self['tcp'][port] def all_udp(self): """ returns list of udp ports """ if 'udp' in self.keys(): ludp = self['udp'].keys() ludp.sort() return ludp return [] def has_udp(self, port): """ returns True if udp port has info, False otherwise """ assert type(port) is types.IntType, 'Wrong type for [port], should be an int [was {0}]'.format(type(port)) if ('udp' in self.keys() and 'port' in self['udp'].keys()): return True return False def udp(self, port): """ returns info for udp port """ assert type(port) is types.IntType, 'Wrong type for [port], should be an int [was {0}]'.format(type(port)) return self['udp'][port] def all_ip(self): """ returns list of ip ports """ if 'ip' in self.keys(): lip = self['ip'].keys() lip.sort() return lip return [] def has_ip(self, port): """ returns True if ip port has info, False otherwise """ assert type(port) is types.IntType, 'Wrong type for [port], should be an int [was {0}]'.format(type(port)) if ('ip' in self.keys() and port in self['ip'].keys()): return True return False def ip(self, port): """ returns info for ip port """ assert type(port) is types.IntType, 'Wrong type for [port], should be an int [was {0}]'.format(type(port)) return self['ip'][port] def all_sctp(self): """ returns list of sctp ports """ if 'sctp' in self.keys(): lsctp = self['sctp'].keys() lsctp.sort() return lsctp return [] def has_sctp(self, port): """ returns True if sctp port has info, False otherwise """ assert type(port) is types.IntType, 'Wrong type for [port], should be an int [was {0}]'.format(type(port)) if ('sctp' in self.keys() and port in self['sctp'].keys()): return True return False def sctp(self, port): """ returns info for sctp port """ assert type(port) is types.IntType, 'Wrong type for [port], should be an int [was {0}]'.format(type(port)) return self['sctp'][port] ############################################################################ class PortScannerError(Exception): """ Exception error class for PortScanner class """ def __init__(self, value): self.value = value def __str__(self): return repr(self.value) ############################################################################ # MAIN ------------------- if __name__ == '__main__': import doctest # non regression test doctest.testmod() #<EOF>######################################################################
- 我的微信
- 这是我的微信扫一扫
- 我的微信公众号
- 我的微信公众号扫一扫