平时扫描弱口令一般都用超级弱口令,前段时间做项目,发现在渗透过程中拿到一台Linux服务器或者拿了一台Windows服务器而这台Windows服务器我们又不想开3389的情况下,扫描其内网弱口令只能使用超级弱口令+sock形式。
而这种方式由于多了一层代理,受网络波动比较大,形象点就是小针管上面接了一个高压水枪,扫描出来的准确度就不用说了,而我们渗透时候又常用Webshell而非GUI来执行命令。所以我需要一款Windows/Linux双用爆破工具,第一个想到的当然是Go。
本着不造轮子的思想,先搜索了一下有没有人写过,发现了x-crack
这款工具,读了一遍后发现作者代码写的真的很好,比我自己写代码时东一榔头西一棒槌好多了,想着写篇文章分析一下工具代码,这样以后在看会比较快。
同时也向原作者致敬和学习,感谢作者的付出。
先贴出工具地址:https://github.com/netxfly/x-crack
下面是工程目录:
cmd
目录:存放命令行于程序交互的代码,就是我们常见的-h等
logger
目录:自定义log的输出方式
model
目录:一个文件存放着利用go-cache开源项目对爆破结果进行处理的代码,另一个文件存放着软件涉及到的数据结构
plugin
目录:存放着各种爆破的代码,如ftp、ssh
util
目录:工具类,负责处理任务调度、文件处理等内容
var
目录:存放着项目用到的全局变量,如:字典文件名、爆破协程数等
x-crack.go
:main方法,主要是启动程序
cli
使用了github.com/urfave/cli
的开源项目。
cmd.Scan
的内容如下:
1、全局变量设置:项目把所有的属性类内容(如:目标文件夹,扫描并发数等)统一放到了vars.go
中,在项目运行中各阶段代码需要运用到这些变量的时候就可以直接从vars
的全局变量中取走。
2、扫描模块化:设置了一个关于扫描模块的统一接口ScanFunc
,所有扫描模块都继承该接口,便于后面规范化调用。同时在plugins.go
的init
方法下注册各扫描模块,如果后续需要添加模块,在plugins.go
里面新增即可完成注册。
FTP爆破模块:
3、规范过程中数据结构
Service
:即爆破目标的相关信息
ScanResult
:包含Service数据结构以及该条爆破是否成功
IpAddr
:包含目标的ip、端口、使用协议
task.go
目录下的Scan
方法为程序的起始点,首先是一系列常规的判断命令行中是否指定了属性值,若指定了则赋值给vars.go
中的全局变量:
然后就是对目标、用户名、密码进行读取、目标探活、生成爆破任务列表、执行任务等操作。在下图的代码中都有注释,我们主要看RunTask
是如何操作的:
代码截图:
首先是初始化一个进度条然后声明一个wg
用来防止程序在协程工作时主线程先结束。
之后创建了一个两倍于指定协程数目的channel
。而下面这段代码就是一个golang
实现的生产者-消费者模型:
// 创建vars.ScanNum个协程 for i := 0; i < vars.ScanNum; i++ { go crackPassword(taskChan, wg) } // 生产者,不断地往taskChan channel发送数据,直到channel阻塞 for _, task := range tasks { wg.Add(1) taskChan <- task } close(taskChan)
我之前对于该模型的疑惑在于,如果有某一刻for
循环中的taskChan
不处于阻塞状态了,被close(taskChan)
关闭了,那消费者岂不是取不到taskChan
中残留的数据了?通过看网上大神的解答,大神给出了下面解释。也就是说,直到通道关闭并且通道里面为空,循环才会终止,通带才会被结束。也就是说并不会出现我说的这种情况。
回到正题,接着看crackPassword
方法的实现,直接从我下图中画红线的地方看,前面的主要是一些辅助性工作。
我们看到首先判断了目标协议,如果时redis
、ftp
、snmp
,那么k=ip-port-protocol
,如果不是这些协议,k=ip-port-username
。
然后这个k
值会被hash.MakeTaskHash
做一次hash
,并校验该hash
。如果校验通过则该次循环结束,直接进入下一次循环,如果不通过,则调用爆破模块对此目标进行爆破。
对于这段代码的作用,有心的人会发现这些协议都存在匿名访问,比如redis
协议,如果目标的redis
有未授权,那么你用什么用户名口令都能登录成功,最后输出的结果就是一大堆爆破成功账号密码。
所以这里对于这些有匿名访问的协议,爆破成功一次后会把其k
值得hash
放入一个map
中维护,如果后面有同ip同端口且同协议得目标再来爆破,那就直接略过,不进行再次爆破。
最后产生得最直观得结果就是,一个目标得redis
未授权只能爆破出来一组用户名密码,而一个目标得mysql
如果账号密码都正确可以爆破出来多组用户名密码。
而具体得爆破工作则是由fn(task)
来做,fn
是从plugins.ScanFuncMap
中根据协议取出来得,这也是之前爆破模块那里规范接口得好处,在这里用的时候可以直接用一个fn
表达出所有以注册过得爆破模块(如ScanFtp
、ScanSsh
),然后将爆破结果保存到缓存中:
等所有得协程执行crackPassword
结束后,把缓存中爆破成功得数据进行导出。在这之前作者还设计了一个爆破得时候防止有些协议没有超时选项所以自己设置了一个超时中断方法WaitTimeout
,感兴趣可以自己看看:
主要的思路就是如上所述这样。
这个工具大致符合我对于爆破得需要,支持协议也很全,缺陷有些地方不够符合我的预期,于是我在这个工具上自己迭代了四个小版本。
在原工具基础上又新增了一些符合我们平常渗透得一些输入方式,比如指定一堆ip
、用户名
、密码
,用指定得协议来对这些爆破和指定配置文件进行操作等功能,同时又加了一个oracle
和wmi
爆破得插件。
下面是改变之后工具得部分功能展示:
结尾:再次向原作致敬!