0X00前言
AlliN
是一款小巧,便捷,完全无依赖的资产扫描器,主要用于安全项目前的资产收集以及内网横向的部分信息收集的工具。
如何做出一款优秀的小工具或者叫做瑞士军刀,这其实是一个有意思的问题。我们认为,一款优秀的资产扫描器首先应该保证扫描数据的全面,面对各种返回都应该拥有有效的解析等。强大的系统兼容性也是必要的需求,资产收集器也是内网横向渗透的得力助手。一款优秀的资产扫描器应该能运行在各个系统上,包括redhat老版本以及windows 2003之前的系统。
其次,快速的扫描速度、全面的web指纹识别以及端口版本识别、目标 URL的任意搭配等也是优秀资产扫描器加分项。
本文介绍了AlliN
作为一款资产扫描器追求优秀扫描器的过程与其现有的特性和架构,具体使用说明请阅读https://github.com/P1-Team/AlliN
0x01 特性
子域名存活探测
AlliN
子域名探测和扫描是一体化集成的,其主要模块为subscan
与sfscan
,subscan
即为域名扫描,域名来源使用了bing、virustotal、passivetotal和crt.sh,为什么只有四个接口?因为在测了很多接口之后发现继续往上增加接口对域名的数量没有实质性的提升,因此暂时只使用四个接口,如果师傅们有好的查询地址,欢迎推荐呀。
其次,sfscan
即为fofa 扫描与子域名扫描的结合,适合与大型攻防项目中更加细致的扫。可以结合如下fofa语句进行扫描
python AlliN.py --host $host -q '(domain="$host" || cert="$host" || title="$project") && country="CN" && region!="HK" && region!="TW" && region!="MO"' -m sfscan --timeout 6 --project $project -t 100
轻量扫描
AlliN在扫描每一个 URL的时候除去跳转的主动请求之外,其余所有扫描均只扫描一次。指纹的识别全部为被动识别,最小程度地留下流量日志,以防止触发目标机器的流量告警,同时也保证扫描数量的准确性。
AlliN的版本获取有如下几个方式:
-
头部信息从
X-Powered-By
,Server
获取基础信息 -
对头部信息
Set-Cookie
进行分析,指定的指纹的变量进行鉴别。 - 对body进行识别。主要由指纹库进行判定,通过对应的字典获取相应的指纹。
常用的指纹鉴别往往使用通过字典的方式,for循环遍历字典的key,如果匹配,则根据key寻找对应的值。众所周知,python的for in的循环原理是递归的便利,如果字典的key有一定数量,那么遍历每一个key所需要的时间将会非常长,因此AlliN
针对此问题采用AC自动机的算法。
AC自动机的特点就是只需要通过遍历一遍需要查找的字符串既可以匹配多个key值,避免了每一个key值就需要遍历一遍html的内容,极大地提高了cms鉴别的速度。
通过将字典中每一个key构建成Trie树,设置一定范围的数字并构建成数组,将每一个字符的ascii码当成索引在数组中设置指定的值以供后期搜索,具体的教程可以参考https://zhuanlan.zhihu.com/p/80325757。
因为python2与python3编码特性,python2在的中文unicode编码超过一位int位,因此需要将中文根据字典进行编码,则无法中英文混合查询。为了python2与python3良好的版本兼容性,AlliN
将字典识别转换为纯中文字典和纯英文字典,但是出现的问题是如果指纹特征点为中英文混合,例如aa管理系统
的key将会被舍去。后期go版本开发则会将所有key值加入到字典当中。
如何获取有效的title也是AlliN
重点注意的一个方向,title值作为AlliN
唯一一个输出网页原文本的字段,肩并着简短并最大程度描述该网页的重任。
首先,获取网页charset的值,确定输出内容编码方式。其次,正则匹配如下列表title:
-
获取title标签的内的内容
<title[\s\S]*?>([\s\S]*?)</title>
-
获取Description中content的值
Description.*content="(.*)"
-
获取meta名为keywords中content的值
<meta name="keywords" content="(.*?)".*?>
-
获取document.title的值
document.title(.*?);
-
获取Copyright的值
Copyright.*\.?
-
获取h1标签内的值
<h1.*?>(.*?)</h1>
之后,对6个正则匹配的值进行判断,过滤注释符号,编码转译符号等。
对于目标站点出现重定向的情况,希望可以获取重定向后的页面,并且可以解决cookie跟随、多次重定向和无限重定向的问题,但原生urllib并不可以,通过阅读requests源码,发现有设置最大重定向次数。在AlliN
中也效仿requests设置了最大重定向次数,并且根据重定向Location的格式进行判断,以//
开头、以/
开头、abc/login
或完整链接,进而选择对应的拼接方式或直接访问完整链接。
小巧无依赖
即安即用,不需要格外安装python的库,并且所有扫描文件集成到一个文件上,方便后期内网扫描的文件上传,也防止因为流量转发而导致的扫描速度慢以及扫描结果不全。 全文件大小仅为600K,编译成exe文件大小也仅为7MB,并且适配绝大多数WIndows系统和类unix的老版本。
AlliN
适配从python2.7到python3以上全版本,全局使用urllib来发送HTTP请求,使用re进行网页的特征点提取。
输入兼容
针对用户输入的ip格式做了一定的兼容,类似10.1.1.1-10.2.2.2,10.1.1.1/24 , 10.1.1.1-100都是可以解析的,从文件中读取ip也是一样的,还会自动加上http,https,80,443进行探测,避免同一ip的http和https是2个站的情况。
-p
参数用来指定端口,支持80,443,8000-9000,22带有范围的格式或者-p-
指定全端口的格式。
参数灵活
例如在fscan
或sfscan
模块下,接-p 1080 -u /admin
或-p 1080,7000-8000,8080 --uf dir.txt
或-u /.git/index
可以用来特殊情况下的快速漏洞验证。
在扫描时,使用--hiddensize 0
或--hidden 404
可以根据目标环境自定义不显示指定页面大小或者状态码的链接。
除此之外还有--nocert
和--dd
参数可以根据实际情况提高扫描速度。更详细的参数使用指南还请移步github仓库https://github.com/P1-Team/AlliN
模块丰富
根据实战需要,添加了很多模块,抱着力求实战中有AlliN
就足够的理念进行开发,这也是AlliN
的名字由来。
在这里简单说明几个容易被用户忽略但又实际有用的模块。更多的模块说明还请移步github仓库。
bakscan : 根据访问的url生成目标网站备份文件的字典,进行备份扫描。
17scan : 扫描MS17-010
nbscan : netbios扫描,可以通过-p
参数指定445端口
uncd : 用于编码解码的模块,内置powershell encode 、bash encode 、 F5 decode
oxid : 可以探测windows主机的网卡情况,寻找多网卡机器
0x02 脚本结构
容器化服务在目前越来越火爆,每个容器的配置也非常严格。同时因为出现漏洞的机器大多数配置为1核的服务器,因此AlliN
舍弃了多进程的并行扫描,改用多线程并发扫描。我们扫描线程与输出线程拆分,使用queue队列进行传输,同时进行文件保存,其流程图为:
由于AlliN
在扫描的使用了队列的join函数,使得AlliN
能够进行扫描进度的监听,达成扫描和输出完成后自动退出所有函数,但是这里就出现了一个问题使用了join函数之后,此时python2将会无法监听外部中断信号(python3版本中的join能够监听到键盘中断信号),queue.join代码为
def join(self): self.all_tasks_done.acquire() try: while self.unfinished_tasks:
self.all_tasks_done.wait() finally:
self.all_tasks_done.release()
可以看到判断有没有完成任务,否则循环调用wait函数,而wait函数则是acquire获取锁循环等待,此时完全无法监听到外部中断信号。因此为了能够使得AllIN
能够在扫描时监听到键盘中断信号,我们使用了os.fork
,通过销毁父进程保留子进程,将脚本变为孤儿进程使得其进程被收入到pid为1的init进程中,由init监听中断信号进行中断。在解决类unix中断问题之后,我们面临了一个新的问题:Windows没有fork的函数,如何停下来?对此,AlliN
的解决办法是调用线程的threading.Event.set
和threading.Event.clear
两行代码将线程的id全部唤醒并且进行清除。监听中短信号方面,在线程启动的时候while True死循环time.sleep进行暂停,使得程序能够监听到键盘中断信号。但是这存在一个问题。AlliN
在扫描之后无法主动停止,因此AlliN
只能通过计算扫描数量,与扫描总数做对比,如果判断扫描完成,则等待timeout的时间之后主动报错退出。
0x03 使用技巧
通过对域名的指定端口和域名之后进行扫描,输入指令
python AlliN.py --host host -q "(domain=\"host\" || cert=\"host\" || title=\"项目名称\") && country=\"CN\" && region!=\"HK\" && region!=\"TW\" && region!=\"MO\"" -m sfscan --timeout 6 -t 150 -p 80,8080,8888,9000,8000
部分扫描结果如下
如果加入了--project
参数的话,结果就会存放两个文件,一个focuson.txt即需要注意的站点,一个为result.txt,即所有扫描结果
focuson.txt文件部分内容如下
也可以结合fofa来批量扫描判断某个漏洞在全网的情况,使用-u
或者--uf
参数指定 URL路径,如果需要增加POST文件,目前需要自行修改代码为req = urllib2.Request(domain, headers=new_headers)
的所有所在行,增加参数data=post_data
即可,之后可能会增加自由增加POST参数选项。
例如扫描YAPI最新的mock权限引发的RCE,即判断网站是否开启用户注册即可。POST请求/api/user/reg
路径,如果结果包含禁止注册
则修复了该漏洞,如果包含邮箱不能为空
则可能存在RCE漏洞。
0x04 自动化
infoscan
是我们对自动化信息收集的尝试,但最后还是没能做完。我们通过一个域名或者一个IP作为目标,搜索whois上的个人信息和邮箱,一些API上的历史解析的所有IP,通过企查查搜索域名的归属公司以及旗下公司的域名,再通过github的API搜索以域名为关键字的相关代码,甚至使用tg的API接口查询xx库等,最后报告以html的形式展现(这只是一个想法)。先因为资金,时间问题,只实现部分效果,这里也给做一个抛砖引玉,希望和师傅们讨论各种自动化信息收集的渠道。
现存的AlliN
适合于快速打点,缺乏分布式资产扫描。且由于python的GIL锁的限制,多线程的性能达到了以一个瓶颈。为了后期增加AlliN
的扫描速度、稳定、功能,可能会使用go语言进行重构。
同时借此文对AlliN
借鉴的代码作者表示一一感谢