AD
 > 健康 > 正文

W9S90后歌手 can

[2019-09-14 20:09:32] 来源: 编辑: 点击量:
评论 点击收藏
导读:原标题问题:安全启迪之扫描器迭代记:W9Scan *本文原创作者:w8ay,本文属FreeBuf原创奖励计划,未经容许禁止转载 w9scan是一款万能型的web裂痕扫描器,警惕了列位儿女的优

原标题问题:安全启迪之扫描器迭代记:W9Scan

*本文原创作者:w8ay,本文属FreeBuf原创奖励计划,未经容许禁止转载

w9scan是一款万能型的web裂痕扫描器,警惕了列位儿女的优质代码。内置1200 插件可对网站进行一次范畴的检测,功能包罗但不限于web指纹检测、端口指纹检测、站点组织综合、各种盛行的裂缝检测、爬虫以及SQL注入检测、XSS检测等等,w9scan会主动生成优美HTML花式终究报告。

在开发w9scan早年笔者曾经启迪过了w8scan,体味的朋友大概知道,w8scan的扫描功能实际上不强,所以,笔者想通过开荒w9scan,这款在外埠运行的扫描器来为w8scan的扫描器代码探路~。

俗语说工欲善其事必先利其器,笔者用过得多扫描器,无不为他们壮大的扫描功能所折服。而笔者作为一名脚本小子,本想开车驶向远方却造起了轮子乐此不疲。仅以此文追悼w9scan的开发历程,记念那逝去的青春…

额,,, 将视线拉回到本渣作。w9scan的初期代码是模仿bugscan而写的,由于w9scan在编写的初期等于为了兼容bugscan的插件,是以做了多量兼容任务来兼容w9scan的代码。而做兼容工作必不可少要熟悉下bugscan的工作事理,以是笔者用本身的渣渣理解力简述下bugscan的功能流程:

首先加载效能类型为www的插件,www插件扫描的过程中同时解析做事,得到ip,加载效能类型为ip的插件继续扫描,失去端口动态加载各类端口插件对指标剖析,失去CMS静态,加载对应cms的插件等等…

不得不说,这是一个很棒的构造。

于是笔者在代码布局层次模仿w9scan,功能组织条理模仿bugscan,凭着脑中若干的想像!@#¥@# 制造了w9scan初版本..

关于bugscan插件的兼容:可以在

lib/code/exploit.py

Exploit_run类中找到,首要通过下面几个阶段完成。

1. 获取plugins目录下所有的py文件,(__init__.py除外),将内容掏出一个字典中

2. 插件代码加载函数,通过调用imp模块将字典存储的代码加载出去,返回模块对象

def_load_module(self,chunk,name=): try: pluginObj = imp.new_module(str(name)) exec chunk in pluginObj.__dict__ except Exception as err_info: raise LoadModuleException return pluginObj

3.为前去的模块类加上内置的API(就是一些bugscan经常使用的内置API,如curlhackhttp之类)

4.一切就绪,今后遵循bugscan API阐明,bugscan插件需界说两个函数 assign为考据 audit为实行函数。所有接下来来调用这两个函数了。

pluginObj_tuple = pluginObj.assign(service,url) if notisinstance(pluginObj_tuple, tuple): # 果决可否是元组 continue bool_value, agrs =pluginObj_tuple[0], pluginObj_tuple[1] if bool_value: pluginObj.audit(agrs) CMS辨认

今朝CMS大多数但凡依赖指纹,看了良多交付机械辨认来考据webshell的列子,笔者也在进修如何用机器深造来识别CMS。

W9scan的CMS辨认的指纹库以及代码但凡bugscan的,内里有一些乏味的才智,分享一下。CMS指纹文件在 lib/utils/cmsdata.py

可以看到主要是遵照MD5以及关头字来辨认的。笔者从前写的CMS辨认都会用个字段来表现识别方式,这个犹如不有,来看看有甚么玄妙?

脱离 plugins/www/whatcms.py

import re,urlparse from lib.utils.cmsdata import cms_dict import hashlib def getMD5(password): m= hashlib.md5() m.update(password) return m.hexdigest() def makeurl(url): prox = http:// if(url.startswith(https://)): prox = https:// url_info = urlparse.urlparse(url) url = prox url_info.netloc / return url def isMatching(f_path, cms_name, sign, res,code, host, head): isMatch = False if f_path.endswith(.gif): if sign: isMatch = getMD5(res) == sign else: isMatch = res.startswith(GIF89a) elif f_path.endswith(.png): if sign: isMatch = getMD5(res) == sign else: isMatch = res.startswith(\x89PNG\x0d\x0a\x1a\x0a) elif f_path.endswith(.jpg): if sign: isMatch = getMD5(res) == sign else: isMatch = res.startswith(\xff\xd8\xff\xe0\x00\x10JFIF) elif f_path.endswith(.ico): if sign: isMatch = getMD5(res) == sign else: isMatch = res.startswith(\x00\x00\x00) elif code == 200: if sign and res.find(sign) != -1 or head.find(sign) != -1: isMatch = True elif sign and head.find(sign) != -1: isMatch = True if isMatch: task_push(cms_name, host, target=util.get_url_host(host)) security_note(cms_name,whatcms) #print %s %s % (cms_name, host) return True return False def assign(service, arg): if service == www: return True,makeurl(arg) def audit(arg): cms_cache = {} cache = {} def _cache(url): if url in cache: return cache[url] else: status_code, header, html_body, error, error = curl.curl2(url) if status_code != 200 or not html_body: html_body = cache[url] = (status_code, header, html_body) return status_code, header, html_body for cmsname in cms_dict: cms_hash_list = cms_dict[cmsname] for cms_hash in cms_hash_list: if isinstance(cms_hash, tuple): f_path, sign = cms_hash else: f_path, sign = cms_hash, None if not isinstance(f_path, list): f_path = [f_path] for file_path in f_path: if file_path not in cms_cache: cms_cache[file_path] = [] cms_cache[file_path].append((cmsname, sign)) cms_key = cms_cache.keys() cms_key.sort(key=len) isMatch = False for f_path in cms_key: if isMatch: break for cms_name, sign in cms_cache[f_path]: code, head, res = _cache(arg f_path) isMatch =isMatching(f_path, cms_name, sign, res, code, arg, head) if isMatch: break

从 audit函数看起,第一个for循环是给指纹排序

for cmsname in cms_dict: cms_hash_list = cms_dict[cmsname] for cms_hash in cms_hash_list: if isinstance(cms_hash, tuple): f_path, sign = cms_hash else: f_path, sign = cms_hash, None if not isinstance(f_path, list): f_path = [f_path] for file_path in f_path: if file_path not in cms_cache: cms_cache[file_path] = [] cms_cache[file_path].append((cmsname, sign))

为了削减接见会面网页的次数,cms辨认即最佳造访一次蹊径后,同时找出类似阶梯下的cms的特征,例如接见一次 robots.txt 会有许多cms的指纹路子是这个。

收尾在isMatch() 函数下找到我们问题的谜底~

def isMatching(f_path, 90后歌手 cms_name, sign, res,code, host, head): isMatch = False if f_path.endswith(.gif): if sign: isMatch = getMD5(res) == sign else: isMatch = res.startswith(GIF89a) elif f_path.endswith(.png): if sign: isMatch = getMD5(res) == sign else: isMatch = res.startswith(\x89PNG\x0d\x0a\x1a\x0a) elif f_path.endswith(.jpg): if sign: isMatch = getMD5(res) == sign else: isMatch = res.startswith(\xff\xd8\xff\xe0\x00\x10JFIF) elif f_path.endswith(.ico): if sign: isMatch = getMD5(res) == sign else: isMatch = res.startswith(\x00\x00\x00) elif code == 200: if sign and res.find(sign) != -1 or head.find(sign) != -1: isMatch = True elif sign and head.find(sign) != -1: isMatch = True if isMatch: task_push(cms_name, host, target=util.get_url_host(host)) security_note(cms_name,whatcms) #print %s %s % (cms_name, host) return True return 90后歌手 False

可以看到,是通过对会面蹊径的后缀做果断,而且对读取的图片前几位做校验。这种武断内容比一些暴力用指纹罗列的果决形式在服从方面应当是更好的。

末了,若是成婚成功,会像我们下面说到的同样,调用响应CMS的相应插件

if isMatch: task_push(cms_name, host, target=util.get_url_host(host)) security_note(cms_name,whatcms) #print %s %s % (cms_name, host) return True

在咱们exploit_run 类的内部实现task_push 的功能就好啦~

整理插件目次

刚初阶笔者征战到的插件是多么的

这类对查找插件和增长都不太利便,于是笔者一个一个的将它们收拾整顿到了目录,变成为了这个边幅。这内中的吃力。。!

的确整理也不辛劳拉,像笔者这么懒的人怎样会一个个手动干呢,一个正则一个移动文件 一个自动设立文件夹就把这些搞定了

为甚么要放出来说呢?由于笔者认为这是笔者用递次干过的最省力的事项了!QAQ

.子域名盘考

子域名盘查是相比头疼的工具,因为对付w9scan,不想太依赖第三方巨大的库支持,重写DNS协议一个感应麻烦而且一再造轮子不成心义,参考github上别人的子域名工具都太巨大了,短小精悍的不知道有木有。末了…用下面这十行的代码OK了。

try: l =socket.gethostbyname_ex(hostnames) security_info(str(l),subdomain) except socket.error: pass

O(∩_∩)O哈哈~,实在通过socket.gethostname即可以完成子域名爆破的工作,为甚么要用自己重写dns协定呢。

集成Buildwith

这是一个辨认网站框架,网站静态的剧本,目下当今认识它是在一本爬虫的书上,厥后缔造原先挪用的是Wappalyzer的脚本,可是Buildwith更短小精悍,一个py文件就写好了悉数的功能,简直深得我意。于是集成之~

人人可以自行 pipinstall buildwith 安设这个库试试,非常壮大!

固然要是各人下载w9scan是不须要安装这个的,由于我已经将他集成上去了!!

道理确实也非常简单,便是这么多的指纹!!!

切实,一款好用的扫描器无外乎需求在速度和精准度之间掂量,精准度需要大批的插件做撑持,而这些插件,也但凡一些特定的指纹会面特定的门路,但此时速度方面就得不到前进。恍如陷进一个二者不可得兼的环境。

线程问题

对付像扫描器这样的IO麋集型功课,用线程似乎可以大大提升速率。虽然,用多进程联动的方式也行,这理应是w9scan后背钻研的对象,现在说下w9scan怎样管束线程的。

起初,用了网上常用的ThreadPool模块,然则不知怎的,屡屡会泛起python运转已终了的提示(Windows上)。。,而且混合一大堆不知道有什么用的模块。上回说到,笔者并不洗用那种一大堆文件的模块,不利于集成就算了,还ctrl c停息的时候卡住了!是可忍孰不成忍,于是笔者立马操起菜刀,胆大妄为的在Google上征采答案。

以笔者的渣渣水平,十个答案内里只能看懂3个,转而想想看代码好了。以前笔者用POC-T这款软件的时候感应挺稳,于是乎拉它开刀,还真开对了!

笔者模仿[POC-T](https://github.com/Xyntax/POC-T/blob/2.0/lib/controller/engine.py)的线程引擎不只图谋了措施无比,也管理了ctrl c壅塞的问题。请听我冉冉道来。

顺序运行异常可在于ThreadPool模块中有不少积极调理线程的程序,经由进程笔者多次的测试,每次泛起异常时加载的插件并不相通,可以翦灭是笔者插件代码问题导致。实践上笔者的顺序不必要这么高真个线程池,模仿POC-T,笔者写了一个粗陋,然而好用的线程池。

# coding:utf-8 # 模拟一个 线程池,可以向内里增长任务, import threading import time import traceback import Queue import random class w8_threadpool: def__init__(self,threadnum,func_scan): self.thread_count = self.thread_nums = threadnum self.scan_count_lock = threading.Lock() self.thread_count_lock = threading.Lock() self.load_lock = threading.Lock() self.scan_count = 0 self.isContinue = True self.func_scan = func_scan self.queue = Queue.Queue() def push(self,payload): self.queue.put(payload) defchangeScanCount(self,num): self.scan_count_lock.acquire() self.scan_count = num self.scan_count_lock.release() defchangeThreadCount(self,num): self.thread_count_lock.acquire() self.thread_count = num self.thread_count_lock.release() defrun(self): for iin range(self.thread_nums): t= threading.Thread(target=self.scan, name=str(i)) t.setDaemon(True) t.start() #It can quit with Ctrl-C while1: ifself.thread_count 0 and self.isContinue: time.sleep(0.01) else: break defstop(self): self.load_lock.acquire() self.isContinue = False self.load_lock.release() defscan(self): while1: self.load_lock.acquire() ifself.queue.qsize() 0 and self.isContinue: payload = self.queue.get() self.load_lock.release() else: self.load_lock.release() break try: # POC在实行时报错假定不被措置,线程框架会中止并参与 self.func_scan(payload) except KeyboardInterrupt: self.isContinue = False raise KeyboardInterrupt except Exception: errmsg = traceback.format_exc() self.isContinue = False self.changeScanCount(-1) self.changeThreadCount(-1) if __name__ == __main__: defcalucator(num): i =random.randint(1, 100) u =num a = i* u if (a% 6 == 0): for x in range(5): print new thread p.push(x) p =w8_threadpool(3, calucator) for i inrange(100000): p.push(i) p.run()

这么一个粗陋的线程池对于笔者的w9scan来说充盈了(切实笔者的申请也不高是否是)

Ctrl c梗阻主线程多是join()这个方法壅闭了,意图方法等于不用这个方法,用while轮回和time.sleep功能到达一个模拟join()的浸染。

后记

我觉得,一些成熟的扫描器在一些惯例扫描方式达到无以复加的境地,甚至于在想用这些惯例方法扫描破绽,功效能够不太好。想要有用挖掘一个站点的缝隙,应该从那些不起眼的中央着力,譬喻w9scan扫描器中有git svm走露门路探求,会基于域名的字典来查找备份文件,以及按照爬虫寻觅出的文件逐一进行一句话密码破解等等……

为什么写此文呢?由于笔者感到斥地过程很无聊,每次公布的版本都是更新了什么修复了什么,假定能加些佐料,加以纪录相武侠小说一样,又能分享经验,何乐而不为呀!

*本文原创作者:w8ay,本文属FreeBuf原创表彰计划,未经核准制止转载

为您推荐