巡风的扫描与漏斗检测脚本分析
启动并在配置好之后,巡风就i在后端开始的资产探测的扫描,先来看一下需要启动的三个脚本:aider.py、nasscan.py和vulscan.py
0x01:aider.py
这个脚本主要作用有两个,一是用作dns,建立socket连接,一个简单的DNS log平台,启动两个线程,一个线程执行udp服务,一个执行http服务;二是用来判断无返回类型的服务
import socket,thread,datetime,time query_history = [] url_history = [] def web_server(): # 创建http服务 web = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 监听8088(http)端口 web.bind(('0.0.0.0',8088)) # 监听端口 web.listen(10) while True: try: # 被动接受TCP客户端连接,(阻塞式)等待连接的到来 # 连接成功返回非负值,失败时返回-1 conn,addr = web.accept() # recv接受tcpp数据,最大为4096字节 data = conn.recv(4096) req_line = data.split("\r\n")[0] path = req_line.split()[1] route_list = path.split('/') html = "NO" if len(route_list) == 3: if route_list[1] == 'add': if route_list[2] not in url_history: url_history.append(route_list[2]) elif route_list[1] == 'check': if route_list[2] in url_history: url_history.remove(route_list[2]) html = 'YES' else: query_str = route_list[1] for query_raw in query_history: if query_str in query_raw: query_history.remove(query_raw) html = "YES" print datetime.datetime.now().strftime('%m-%d %H:%M:%S') + " " + str(addr[0]) +' web query: ' + path raw = "HTTP/1.0 200 OK\r\nContent-Type: application/json; charset=utf-8\r\nContent-Length: %d\r\nConnection: close\r\n\r\n%s" %(len(html),html) conn.send(raw) conn.close() except: pass if __name__=="__main__": # 创建一个socket对象,规定套接字家族和类型(非面向连接) dns = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # 监听53(udp)端口 dns.bind(('0.0.0.0', 53)) # start_new_thread创建一个新线程,返回线程标识符 thread.start_new_thread(web_server,()) while True: try: # 接受udp数据,但返回值是(data,address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址。 recv,addr = dns.recvfrom(1024) # 将请求添加到query_history数组中。 if recv not in query_history:query_history.append(recv) print datetime.datetime.now().strftime('%m-%d %H:%M:%S') + " " +str(addr[0]) +' Dns Query: ' + recv except Exception,e: print e
0x02:nasscan.py
大致的顺一下这个脚本的功能顺序:获取前端配置-进行日志记录-读取统计信息-判断是否应该扫描(包括两种情况)-删除失效记录-开始扫描
这个脚本主要是用来进行网络资产的扫描,包括探测存活主机、开放端口、服务等。
if __name__ == "__main__": try: # 读取配置 CONFIG_INI = get_config() # 日志记录,传入参数scan_type, host, port, info log.write('info', None, 0, u'获取配置成功') # 读取统计信息 STATISTICS = get_statistics() print STATISTICS MASSCAN_AC = [0] # 标识符 masscan是否在使用 NACHANGE = [0] # 标识符 扫描列表是否被改变 thread.start_new_thread(monitor, (CONFIG_INI, STATISTICS, NACHANGE)) # 心跳线程,主要用于判断扫描配置是否发生了变化 thread.start_new_thread(cruise, (STATISTICS, MASSCAN_AC)) # 失效记录删除线程 socket.setdefaulttimeout(int(CONFIG_INI['Timeout']) / 2) # 设置连接超时 ac_data = [] # 扫描循环 while True: # 获取当前具体时间信息 now_time = time.localtime() # 获取当前小时 now_hour = now_time.tm_hour # 获取当前星期几 now_day = now_time.tm_mday # 获取年月日 now_date = str(now_time.tm_year) + str(now_time.tm_mon) + str(now_day) # 获取资产探测周期 cy_day, ac_hour = CONFIG_INI['Cycle'].split('|') log.write('info', None, 0, u'扫描规则: ' + str(CONFIG_INI['Cycle'])) # 判断是否进入扫描时段 # 判断是否达到了一个扫描的周期,或者心跳线程是否检测到扫描列表更新 # 在心跳线程中可以看到base64不同时会将NACHANGE[0]置于1 if (now_hour == int(ac_hour) and now_day % int(cy_day) == 0 and now_date not in ac_data) or NACHANGE[0]: # 判断是否扫描过列表 ac_data.append(now_date) NACHANGE[0] = 0 log.write('info', None, 0, u'开始扫描') # 声明一个start对象,并传入配置参数 s = start(CONFIG_INI) # 标识masscan是否在使用,标识扫描列表是否被改变 s.masscan_ac = MASSCAN_AC s.statistics = STATISTICS # 开始扫描 s.run() time.sleep(60) except Exception, e: print e
这个方法用来获取配置页面中的各项配置
def get_config(): config = {} # 从mongodb中读取`nascan`的配置,可以看到Config集合中有`vulscan`和`nascan`的扫描配置 config_info = mongo.na_db.Config.find_one({"type": "nascan"}) for name in config_info['config']: # 对于cms识别、组件容器、动态语言、服务 的配置存储是使用`|`进行分割存储的 # 所以在取出之前要进行简单的格式化然后放到配置中 if name in ['Discern_cms', 'Discern_con', 'Discern_lang', 'Discern_server']: config[name] = format_config(name, config_info['config'][name]['value']) else: config[name] = config_info['config'][name]['value'] return config
用来进行日志记录
import threading import time import sys reload(sys) sys.setdefaultencoding('utf8') # 线程互斥锁 mutex = threading.Lock() def write(scan_type, host, port, info): # 上锁,避免多个进程输出,导致格式混乱 mutex.acquire() port = int(port) try: time_str = time.strftime('%X', time.localtime(time.time())) # 根据传入的scan_type,判断输出内容 if scan_type == 'portscan': print "[%s] %s:%d open" % (time_str, host, port) elif scan_type == 'server': print "[%s] %s:%d is %s" % (time_str, host, port, str(info)) elif scan_type == 'web': print "[%s] %s:%d is web" % (time_str, host, port) print "[%s] %s:%d web info %s" % (time_str, host, port, info) elif scan_type == 'active': print "[%s] %s active" % (time_str, host) elif scan_type == 'info': print "[%s] %s" % (time_str, info) except Exception, e: print 'logerror',e pass # 释放锁 mutex.release()
读取统计信息
def get_statistics(): # 获取当日的统计信息 date_ = datetime.datetime.now().strftime('%Y-%m-%d') now_stati = mongo.na_db.Statistics.find_one({"date": date_}) if not now_stati: # 没有当日的信息则返回一个初始统计信息 now_stati = {date_: {"add": 0, "update": 0, "delete": 0}} return now_stati else: # 有则返回 return {date_: now_stati['info']}
心跳线程,判断是否到达扫描周期或资产探测列表已改变
# 心跳线程,主要用于判断扫描配置是否发生了变化,如果改变,则立即触发扫描 def monitor(CONFIG_INI, STATISTICS, NACHANGE): while True: try: time_ = datetime.datetime.now() # 记录心跳 date_ = time_.strftime('%Y-%m-%d') mongo.na_db.Heartbeat.update({"name": "heartbeat"}, {"$set": {"up_time": time_}}) if date_ not in STATISTICS: STATISTICS[date_] = {"add": 0, "update": 0, "delete": 0} # 更新统计信息 mongo.na_db.Statistics.update({"date": date_}, {"$set": {"info": STATISTICS[date_]}}, upsert=True) new_config = get_config() # 获取最新配置 # 比较配置扫描列表的base64是否相同,不同则置NACHANGE[0]为1,说明配置发生改名,立即出发扫描 if base64.b64encode(CONFIG_INI["Scan_list"]) != base64.b64encode(new_config["Scan_list"]):NACHANGE[0] = 1 CONFIG_INI.clear() # 更新新配置 CONFIG_INI.update(new_config) except Exception, e: print e # 每30秒检测一次 time.sleep(30)
失效记录删除线程
# 失效记录,删除线程,STATISTICS统计信息,MASSCAN_AC判断是否启用masscan def cruise(STATISTICS,MASSCAN_AC): while True: # 获取当前日期(年 月 日 时 分 秒) now_str = datetime.datetime.now() # 获取当天是星期几0-6 week = int(now_str.weekday()) # 获取当前时间的整点数 hour = int(now_str.hour) if week >= 1 and week <= 5 and hour >= 9 and hour <= 18: # 非工作时间不删除 try: # 获取扫描信息记录,根据time字段进行升序排列 data = mongo.NA_INFO.find().sort("time", 1) for history_info in data: while True: # 如果masscan正在扫描即不进行清理,在用masscan进行扫描的时候会置1 if MASSCAN_AC[0]: # 如果masscan正在扫描即不进行清理 time.sleep(10) else: break ip = history_info['ip'] port = history_info['port'] try: # 检测端口是否存活 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((ip, int(port))) sock.close() except Exception, e: time_ = datetime.datetime.now() date_ = time_.strftime('%Y-%m-%d') # 不存活则删除改记录 mongo.NA_INFO.remove({"ip": ip, "port": port}) # 日志记录 log.write('info', None, 0, '%s:%s delete' % (ip, port)) STATISTICS[date_]['delete'] += 1 del history_info["_id"] history_info['del_time'] = time_ history_info['type'] = 'delete' # 添加一条操作历史 mongo.NA_HISTORY.insert(history_info) except: pass # 每小时检测一次 time.sleep(3600)
start类,扫描的主要方法,包括IP地址段的解析,端口的扫描,白名单的绕过等
class start: def __init__(self, config): # 默认配置 # 传入CONFIG_INI 配置,然后设置类的属性 self.config_ini = config self.queue = Queue.Queue() # 队列对象 self.thread = int(self.config_ini['Thread']) # 最大线程数 self.scan_list = self.config_ini['Scan_list'].split('\n') # 扫描列表 self.mode = int(self.config_ini['Masscan'].split('|')[0]) # MASSCAN配置 self.icmp = int(self.config_ini['Port_list'].split('|')[0]) # 端口列表 self.white_list = self.config_ini.get('White_list', '').split('\n') # 白名单 # 启动函数 def run(self): # 在start.py中定义的全局变量,端口列表 global AC_PORT_LIST all_ip_list = [] for ip in self.scan_list: # 处理CIDR格式的ip, eg:192.168.0.1/24 # 就不具体跟进看了,大约40行左右,涉及一些位运算格式转换啥的 if "/" in ip: # 把CIDR格式的地址转换成地址段 ip = cidr.CIDR(ip) if not ip: continue # 获取IP列表 ip_list = self.get_ip_list(ip) # 对于白名单ip进行移除 for white_ip in self.white_list: if white_ip in ip_list: ip_list.remove(white_ip) # 是否开始了masscan扫描,开启了mode置为1,否则为0 if self.mode == 1: # 获取文件路径 masscan_path = self.config_ini['Masscan'].split('|')[2] # 获取扫描速率 masscan_rate = self.config_ini['Masscan'].split('|')[1] # 如果用户在前台关闭了ICMP存活探测则进行全IP段扫描 # 获取存活IP if self.icmp: ip_list = self.get_ac_ip(ip_list) self.masscan_ac[0] = 1 # 如果安装了Masscan即使用Masscan进行全端口扫描 AC_PORT_LIST = self.masscan( ip_list, masscan_path, masscan_rate) if not AC_PORT_LIST: continue # 将self.masscan_ac[0]置0,表示结束使用 self.masscan_ac[0] = 0 for ip_str in AC_PORT_LIST.keys(): self.queue.put(ip_str) # 加入队列 self.scan_start() # 开始扫描 else: all_ip_list.extend(ip_list) # 不使用masscan扫描 if self.mode == 0: if self.icmp: all_ip_list = self.get_ac_ip(all_ip_list) for ip_str in all_ip_list: self.queue.put(ip_str) # 加入队列 self.scan_start() # TCP探测模式开始扫描 # 开始扫描 def scan_start(self): for i in range(self.thread): # 开始扫描 t = ThreadNum(self.queue) t.setDaemon(True) t.mode = self.mode t.config_ini = self.config_ini t.statistics = self.statistics t.start() self.queue.join() def masscan(self, ip, masscan_path, masscan_rate): try: if len(ip) == 0: return sys.path.append(sys.path[0] + "/plugin") # 导入masscan.py,并在下面调用它的run方法 m_scan = __import__("masscan") result = m_scan.run(ip, masscan_path, masscan_rate) return result except Exception, e: print e print 'No masscan plugin detected' # 接受cidr格式的ip,返回IP列表 def get_ip_list(self, ip): ip_list_tmp = [] def iptonum(x): return sum([256 ** j * int(i) for j, i in enumerate(x.split('.')[::-1])]) def numtoip(x): return '.'.join( [str(x / (256 ** i) % 256) for i in range(3, -1, -1)]) if '-' in ip: ip_range = ip.split('-') ip_start = long(iptonum(ip_range[0])) ip_end = long(iptonum(ip_range[1])) ip_count = ip_end - ip_start if ip_count >= 0 and ip_count <= 655360: for ip_num in range(ip_start, ip_end + 1): ip_list_tmp.append(numtoip(ip_num)) else: print 'IP format error' else: ip_split = ip.split('.') net = len(ip_split) if net == 2: for b in range(1, 255): for c in range(1, 255): ip = "%s.%s.%d.%d" % (ip_split[0], ip_split[1], b, c) ip_list_tmp.append(ip) elif net == 3: for c in range(1, 255): ip = "%s.%s.%s.%d" % ( ip_split[0], ip_split[1], ip_split[2], c) ip_list_tmp.append(ip) elif net == 4: ip_list_tmp.append(ip) else: print "IP format error" return ip_list_tmp # 通过ping请求来探测主机存活,后期只对存活主机进行扫描 def get_ac_ip(self, ip_list): try: s = icmp.Nscan() ipPool = set(ip_list) return s.mPing(ipPool) except Exception, e: print 'The current user permissions unable to send icmp packets' return ip_list
动态引入masscan.py脚本(m_scan = __import__("masscan"))
def run(ip_list,path,rate): try: ip_file = open('target.log','w') # 将存活的ip列表写到target.log中 ip_file.write("\n".join(ip_list)) ip_file.close() # 进行过滤一些危险字符,translate用来转换字符串字符 path = str(path).translate(None, ';|&`\n') rate = str(rate).translate(None, ';|&`\n') if not os.path.exists(path):return # 用系统命令进行masscan全端口扫描 os.system("%s -p1-65535 -iL target.log -oL tmp.log --randomize-hosts --rate=%s"%(path,rate)) # 读取扫描结果 result_file = open('tmp.log', 'r') result_json = result_file.readlines() result_file.close() del result_json[0] del result_json[-1] open_list = {} # 对扫描结果进行格式化处理 for res in result_json: try: ip = res.split()[3] port = res.split()[2] if ip in open_list: open_list[ip].append(port) else: open_list[ip] = [port] except:pass os.remove('target.log') os.remove('tmp.log') # 返回扫描结果 return open_list except: pass
0x03:vulscan.py
用于对扫出的资产进行漏洞扫描,具体的扫描过程依赖于vuldb
中的插件形式进行扫描,
main函数:脚本运行的开始函数,主要是启动心跳线程、漏斗检查线程、更新kunpeng插件线程、获取任务、清理插件缓存等。
if __name__ == '__main__': init() # 密码字典、线程数量、超时时间、白名单 PASSWORD_DIC, THREAD_COUNT, TIMEOUT, WHITE_LIST = get_config() # 开启心跳线程 thread.start_new_thread(monitor, ()) # 开启漏斗检查线程 thread.start_new_thread(kp_check, ()) # 开启更新kunpeng线程 thread.start_new_thread(kp_update, ()) while True: try: # 获取未执行任务的任务id,、任务周期、任务目标、任务插件 task_id, task_plan, task_target, task_plugin = queue_get() if task_id == '': time.sleep(10) continue # 清理插件缓存 if PLUGIN_DB: del sys.modules[PLUGIN_DB.keys()[0]] PLUGIN_DB.clear() for task_netloc in task_target: while True: # thread._count返回正在运行的线程数量,包括主线程 if int(thread._count()) < THREAD_COUNT: # 绕过白名单 if task_netloc[0] in WHITE_LIST: break # 进行漏斗检测 try: thread.start_new_thread( vulscan, (task_id, task_netloc, task_plugin)) except Exception as e: print e break else: time.sleep(2) # 更新status文档 if task_plan == 0: na_task.update({"_id": task_id}, {"$set": {"status": 2}}) except Exception as e: print e
init函数:用来初始化,获取插件列表,安装kunpeng等。
def init(): time_ = datetime.datetime.now() if na_plugin.find().count() >= 1: return script_plugin = [] json_plugin = [] print 'init plugins' # 获取插件列表 file_list = os.listdir(sys.path[0] + '/vuldb') # 把插件添加到对应的列表中 for filename in file_list: try: if filename.split('.')[1] == 'py': script_plugin.append(filename.split('.')[0]) if filename.split('.')[1] == 'json': json_plugin.append(filename) except: pass for plugin_name in script_plugin: try: # 动态加载 res_tmp = __import__(plugin_name) # 获取插件信息 plugin_info = res_tmp.get_plugin_info() plugin_info['add_time'] = time_ plugin_info['filename'] = plugin_name plugin_info['count'] = 0 na_plugin.insert(plugin_info) except: pass for plugin_name in json_plugin: try: json_text = open(sys.path[0] + '/vuldb/' + plugin_name, 'r').read() plugin_info = json.loads(json_text) plugin_info['add_time'] = time_ plugin_info['filename'] = plugin_name plugin_info['count'] = 0 del plugin_info['plugin'] na_plugin.insert(plugin_info) except: pass # 安装kunpeng install_kunpeng_plugin()
get_config:从数据库里查找配置,白名单、线程数、超时时间等
def get_config(): try: # 在Config集合中,找到type=vulscan的文档 config_info = na_config.find_one({"type": "vulscan"}) # 下面都是获取这个文档中的一些值,都是字典类型的 pass_row = config_info['config']['Password_dic'] thread_row = config_info['config']['Thread'] timeout_row = config_info['config']['Timeout'] white_row = config_info['config']['White_list'] password_dic = pass_row['value'].split('\n') thread_count = int(thread_row['value']) timeout = int(timeout_row['value']) white_list = white_row['value'].split('\n') return password_dic, thread_count, timeout, white_list except Exception, e: print e
monitor:心跳线程函数,看的不是很明白,希望大佬们可以支教
def monitor(): global PASSWORD_DIC, THREAD_COUNT, TIMEOUT, WHITE_LIST while True: # 从数据库里找到相应的值 queue_count = na_task.find({"status": 0, "plan": 0}).count() if queue_count: load = 1 else: ac_count = thread._count() load = float(ac_count - 6) / THREAD_COUNT if load > 1: load = 1 if load < 0: load = 0 na_heart.update({"name": "load"}, { "$set": {"value": load, "up_time": datetime.datetime.now()}}) PASSWORD_DIC, THREAD_COUNT, TIMEOUT, WHITE_LIST = get_config() if load > 0: time.sleep(8) else: time.sleep(60)
kp_check:调用kunpeng,进行检查
def kp_check(): while True: try: new_release = kp.check_version() print new_release if new_release: info = new_release['body'] if '###' in new_release['body']: info = new_release['body'].split('###')[1] row = { 'info': info, 'isInstall': 0, 'name': new_release['name'], 'author': new_release['author']['login'], 'pushtime': new_release['published_at'], 'location': "", 'unicode': new_release['tag_name'], 'coverage': 0, 'source': 'kunpeng' } na_update.insert(row) time.sleep(60 * 60 * 48) except Exception as e: print e time.sleep(60 * 30)
kp_update:更新kunpeng插件
def kp_update(): while True: try: # 找到相应的文档删除,并返回删除的数量 row = na_update.find_one_and_delete( {'source': 'kunpeng', 'isInstall': 1}) if row: kp.update_version(row['unicode']) na_plugin.delete_many({'_id':re.compile('^KP')}) install_kunpeng_plugin() except Exception as e: print e time.sleep(10)
queue_get:获取任务信息,id、周期、插件等
def queue_get(): # 全局字典 global TASK_DATE_DIC # 在Task这个集合中提取并更新数据,找到所有status等于0,plan等于0的文档,返回后更新status=1,然后根据时间升序排列 # find_and_modify task_req = na_task.find_and_modify(query={"status": 0, "plan": 0}, update={ "$set": {"status": 1}}, sort={'time': 1}) # 返回未执行任务 if task_req: TASK_DATE_DIC[str(task_req['_id'])] = datetime.datetime.now() return task_req['_id'], task_req['plan'], task_req['target'], task_req['plugin'] # 不存在还未执行任务,返回空或返回定期执行任务 else: # $ne表示不等于 task_req_row = na_task.find({"plan": {"$ne": 0}}) if task_req_row: # 执行定期任务 for task_req in task_req_row: if (datetime.datetime.now() - task_req['time']).days / int(task_req['plan']) >= int(task_req['status']): if task_req['isupdate'] == 1: task_req['target'] = update_target( json.loads(task_req['query'])) na_task.update({"_id": task_req['_id']}, { "$set": {"target": task_req['target']}}) na_task.update({"_id": task_req['_id']}, { "$inc": {"status": 1}}) TASK_DATE_DIC[str(task_req['_id']) ] = datetime.datetime.now() return task_req['_id'], task_req['plan'], task_req['target'], task_req['plugin'] return '', '', '', ''
vulscan类:这是主要的,漏斗的检测主要在这里面进行。
class vulscan(): def __init__(self, task_id, task_netloc, task_plugin): self.task_id = task_id # 任务id self.task_netloc = task_netloc # 任务目标 self.task_plugin = task_plugin # 任务插件 self.result_info = '' self.start() # 线程启动函数,与run不同,会在一个新线程里开启 def start(self): self.get_plugin_info() # 获取插件信息 if '.json' in self.plugin_info['filename']: # 标示符检测模式 self.load_json_plugin() # 读取漏洞标示 self.set_request() # 标示符转换为请求 self.poc_check() # 检测 elif 'KP-' in self.plugin_info['filename']: self.log(str(self.task_netloc) + 'call kunpeng - ' + self.plugin_info['filename']) kp.set_config(TIMEOUT, PASSWORD_DIC) if self.task_netloc[1] != 80: self.result_info = kp.check('service', '{}:{}'.format( self.task_netloc[0], self.task_netloc[1]), self.plugin_info['filename']) if not self.result_info: scheme = 'http' if self.task_netloc[1] == 443: scheme = 'https' self.result_info = kp.check('web', '{}://{}:{}'.format( scheme, self.task_netloc[0], self.task_netloc[1]), self.plugin_info['filename']) else: # 脚本检测模式 plugin_filename = self.plugin_info['filename'] self.log(str(self.task_netloc) + 'call ' + self.task_plugin) if task_plugin not in PLUGIN_DB: # 字典 plugin_res = __import__(plugin_filename) setattr(plugin_res, "PASSWORD_DIC", PASSWORD_DIC) # 给插件声明密码字典 PLUGIN_DB[plugin_filename] = plugin_res self.result_info = PLUGIN_DB[plugin_filename].check( str(self.task_netloc[0]), int(self.task_netloc[1]), TIMEOUT) self.save_request() # 保存结果 # 获取插件信息 def get_plugin_info(self): # 从插件库中找到插件 info = na_plugin.find_one({"name": self.task_plugin}) self.plugin_info = info def load_json_plugin(self): json_plugin = open(sys.path[0] + '/vuldb/' + self.plugin_info['filename']).read() self.plugin_info['plugin'] = json.loads(json_plugin)['plugin'] # 构造请求 def set_request(self): url = 'http://' + \ self.task_netloc[0] + ":" + \ str(self.task_netloc[1]) + self.plugin_info['plugin']['url'] if self.plugin_info['plugin']['method'] == 'GET': request = urllib2.Request(url) else: request = urllib2.Request(url, self.plugin_info['plugin']['data']) self.poc_request = request # 获取代码语言,主要是通过正则匹配 def get_code(self, header, html): try: m = re.search(r'<meta.*?charset=(.*?)"(>| |/)', html, flags=re.I) if m: return m.group(1).replace('"', '') except: pass try: if 'Content-Type' in header: Content_Type = header['Content-Type'] m = re.search(r'.*?charset=(.*?)(;|$)', Content_Type, flags=re.I) if m: return m.group(1) except: pass def poc_check(self): try: # 发送请求 res = urllib2.urlopen(self.poc_request, timeout=30) res_html = res.read(204800) # 获取i请求头 header = res.headers # res_code = res.code except urllib2.HTTPError, e: # res_code = e.code header = e.headers res_html = e.read(204800) except Exception, e: return try: # 获取编码语言 html_code = self.get_code(header, res_html).strip() if html_code and len(html_code) < 12: res_html = res_html.decode(html_code).encode('utf-8') except: pass an_type = self.plugin_info['plugin']['analyzing'] vul_tag = self.plugin_info['plugin']['tag'] analyzingdata = self.plugin_info['plugin']['analyzingdata'] if an_type == 'keyword': # print poc['analyzingdata'].encode("utf-8") if analyzingdata.encode("utf-8") in res_html: self.result_info = vul_tag elif an_type == 'regex': if re.search(analyzingdata, res_html, re.I): self.result_info = vul_tag elif an_type == 'md5': md5 = hashlib.md5() md5.update(res_html) if md5.hexdigest() == analyzingdata: self.result_info = vul_tag # def save_request(self): if self.result_info: time_ = datetime.datetime.now() self.log(str(self.task_netloc) + " " + self.result_info) v_count = na_result.find( {"ip": self.task_netloc[0], "port": self.task_netloc[1], "info": self.result_info}).count() if not v_count: na_plugin.update({"name": self.task_plugin}, {"$inc": {'count': 1}}) vulinfo = {"vul_name": self.plugin_info['name'], "vul_level": self.plugin_info['level'], "vul_type": self.plugin_info['type']} w_vul = {"task_id": self.task_id, "ip": self.task_netloc[0], "port": self.task_netloc[1], "vul_info": vulinfo, "info": self.result_info, "time": time_, "task_date": TASK_DATE_DIC[str(self.task_id)]} na_result.insert(w_vul) # self.wx_send(w_vul) # 自行定义漏洞提醒 def log(self, info): lock.acquire() try: time_str = time.strftime('%X', time.localtime(time.time())) print "[%s] %s" % (time_str, info) except: pass lock.release()
参考文章:https://xz.aliyun.com/t/4104#toc-9
*************不积跬步无以至千里*************