# -*- coding: utf-8 -*-"""@author:随时静听@file: shodanForIp.py@time: 2019/01/28@email:d1314ziting@163.com"""try: from libnmap.parser import NmapParser import shodan import os import glob import simplejson #用于loding import json #用于 dumping import argparse from functools import wraps import xlsxwriter import sysexcept : exit(u''' Python package dependency:(请检查包依赖)\n pip install xlsxwriter\n pip install simplejson\n pip install python-libnmap\n pip install argparse\n ''')# shodan访问API keyAPI_KEY=""CACHE_ON = TrueCACHE_FILES=[]CACHE_DIR = "./cache"LOG_ON = True# Excel格式配置EXCEL_TILTE=[u"序号","IP","Shodan_PORTS"]# 列宽设置COL_WIDTH=[7,20,30]# 行高设置ROW_HIGHT=[(0,17),("other",15)]#第一行和其他行高度title_style={ 'bold':True,#字体加粗 'align':'center',#水平位置设置:居中 'valign':'vcenter',#垂直位置设置,居中 'font_size':12,#'字体大小设置' 'font_name':'Courier New', 'border':1,#边框设置样式1 'border_color':'black',#边框颜色 'bg_color':'#009ad6',#背景颜色设置}body_style={ 'align': 'left', 'valign': 'vcenter', 'font_size': 10, 'font_name':'Courier New',#字体设置 'border': 2, 'border_color': '#808080', 'font_name': 'Courier New',}FAILED_LST=[]#DATA_DIC={}def env_init(): ''' 程序运行环境初始化: 1. 缓存路径检查,不存在就创建 2. 缓存文件见检查,如果存在将获取缓存文件名字,从现有文件中获取,加快获取数据 :return: ''' if not os.path.exists(CACHE_DIR): os.makedirs(CACHE_DIR) CACHE_FILES.extend([os.path.join(CACHE_DIR,json_file) for json_file in glob.glob1(CACHE_DIR,"*.json")]) if CACHE_ON :#开启缓存加速 for filename in CACHE_FILES: try: with open(filename,'r') as fr: data = simplejson.load(fr) DATA_DIC.update(data) except Exception as e: print '[!] Error: loding data from file failed! '+filename print '[!] Error: '+ e.messagedef parseArgs(): global API_KEY, CACHE_ON, LOG_ON , CACHE_DIR parser = argparse.ArgumentParser( usage=''' python shellFilename -l ip_lst.txt -o outfile.xlsx \n\n Python package dependency:\n \tpip install xlsxwriter\n \tpip install python-libnmap\n \tpip install argparse\n 程序说明:\n \t1. 默认不开启开启缓存 ,请使用 --make-cache开启缓存\n \t2. 如果需要实时查看信息获取,请使用 -v 参数\n \t3. 使用 --api-key shodan-key 来初始化 shodan api \n''', epilog=".." * 50) parser.add_argument('-l', "--file", help="A File Output scan in normal using nmap", required=True) parser.add_argument('-o', "--output", help="Report xlsx filename", required=True) parser.add_argument('-v', "--verbosity", help=u"Print data in real time (默认关闭)", action="store_true") parser.add_argument('-c', "--make-cache", help=u"Create cached data (默认关闭)", action="store_true") parser.add_argument("--cache-path", help="Cache file path", default="./cache") parser.add_argument("--api-key", help="A key for Shodan API") args = parser.parse_args() if args.api_key: API_KEY = args.api_key if args.cache_path: CACHE_DIR = args.cache_path CACHE_ON = args.make_cache LOG_ON = args.verbosity if args.output: if os.path.exists(args.output): print u"[!] Error: 文件已经存在 ! (" + args.output + ")." exit(u"[!] 程序退出") return (args.file, args.output)def ReportExcel(data_lst,outfile,title_style=title_style,body_style=body_style,title=EXCEL_TILTE,c_w=COL_WIDTH,r_h=ROW_HIGHT): if not outfile: exit("[!] Error in Function : ReportExcel.") book=xlsxwriter.Workbook(outfile) sheet=book.add_worksheet("Result") title_style=book.add_format(title_style) body_style=book.add_format(body_style) # 设置 列宽 for c, w in enumerate(c_w): # print c, w sheet.set_column(c, c + 1, w) # 设置 行高 exculde_r=[] other_h=0 for r,h in r_h: if r!="other": sheet.set_row(r,h) exculde_r.append(r) if r=="other": other_h=h for i in list(set(range(1000))-set(exculde_r)): sheet.set_row(i,other_h) #写入标题 for i,data in enumerate(title): sheet.write(0,i,data,title_style) # 数据写入 index=1 for r,data in enumerate(data_lst): # host,nmap_ports_lst,shodan_ports_lst sheet.write(r+1,0,index,body_style) #写入 IP sheet.write(r+1,1,data[0],body_style) if not data[1]: sheet.write(r+1,2,"/",body_style) else: sheet.write(r+1,2,",".join([ str(p[0]) for p in data[1] ]),body_style) index+=1 book.close()# 处理缓存数据def cache_processing(func): @wraps(func) def inner(*args,**kwargs): if len(args)==2: #如果开启缓存 if CACHE_ON: ret=DATA_DIC.get(args[0],None) #如果从缓存文件中获取不到数据就直接请求加入缓存数据中 if not ret: ret = func(*args, **kwargs) if ret: DATA_DIC.update({args[0]:ret})#讲数据加入缓存字典 else: ret=func(*args,**kwargs) try: if LOG_ON: print "[-] INFO: " + args[0] +" : " +json.dumps(ret,sort_keys=True, indent=2) except Exception as e: print "[!] Failed: " + args[0] return ret else: print "[!] Error: Too few function parameters! In function "+func.__name__ return None return inner@cache_processingdef load_data_from_shodan(ip,shodan_api): try: data_dic=shodan_api.host(ip,history=False) return data_dic except Exception as e: pass return Nonedef writeCache(): ''' 缓存数据回写 :return: ''' import time cache_filename=time.strftime("%Y%m%d_%H%M%S",time.localtime())+".json" if CACHE_ON: with open(os.path.join(CACHE_DIR,cache_filename),"w") as f: try: json.dump(DATA_DIC,f) except: print "WARNING: CACHE DATA WRITE FAILED!"#打印进度条,这个进度条打印思路很不错def printProgress(cnt, tot, target='', previouslen=0): percent = 100 * float(cnt) / float(tot) if target and previouslen > len(target): target = target + ' ' * (previouslen - len(target)) sys.stdout.write('[%-40s] %d%% %s\r' % ('='*int(float(percent)/100*40), percent, target)) sys.stdout.flush() return ''def get_ip_lst(filename): if os.path.exists(filename): with open(filename,'r') as f: return map(lambda x : x.strip(),f.readlines()) else: exit("[!] INFO: IP file is zero IP! ("+filename+")")def runMain(): env_init() #统计信息 num=0 # 获取解析的xml和导出的文件名 ip_lst_file, outfile = parseArgs() print "[-] INFO: Processing IP file: "+ip_lst_file print "[-] INFO: Set output Excel file name : "+outfile # 获取file 中的主机信息 host_lst=get_ip_lst(ip_lst_file) print "[-] INFO: Parser Nmap XML file completed! GET HOST NUM: "+ str(len(host_lst)) # 初始化shodan API try: api = shodan.Shodan(API_KEY) except Exception as e: print "[!] Error: Shodan API initialization failed! " exit(u"[!] 程序异常退出:"+e.message) result_lst = [] if not host_lst : exit("[!] Parse IP file ("+ip_lst_file+") 0 host!") for i,host in enumerate(host_lst) : host_dic = load_data_from_shodan(host,api) # print DATA_DIC if host_dic: num+=1 shodan_ports = host_dic.get('ports', []) result_lst.append( (host,shodan_ports) ) printProgress(i + 1, len(host_lst), host) ReportExcel(result_lst,outfile) writeCache() print "[-] INFO: All has Finished processing ! Total:" + str(num) print "[-] INFO: Excel File save path: " + outfileif __name__ == '__main__': import datetime t_start=datetime.datetime.now() runMain() t_end=datetime.datetime.now() print u"[!] INFO: 用时 [ "+str((t_end-t_start).total_seconds())+" S ]" # api=shodan.Shodan(API_KEY) # print api.host("211.147.146.74",history=False) pass