前言 之前工作的时候发现一款很不错的开源工具 osmedeus,这个工具可以通过 yaml 编排各种安全工具的工作流。
比如子域名收集模块,就很好编写,很简单的就实现了 subfinder 和 amass 的集成:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 kind: module name: subdomain-enum params: - name: target required: true steps: - name: subfinder type: bash command: subfinder -d {{target }} -o {{Output }}/subs.txt - name: amass type: bash command: amass enum -passive -d {{target }} >> {{Output }}/subs.txt - name: dedupe type: bash command: sort -u {{Output }}/subs.txt -o {{Output }}/subdomains.txt
然后模块构成工作流:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 kind: flow name: full-recon params: - name: target required: true modules: - name: subdomain-enum path: modules/subdomain-enum.yaml - name: http-probe path: modules/http-probe.yaml depends_on: [subdomain-enum ] - name: screenshot path: modules/screenshot.yaml depends_on: [http-probe ] condition: 'fileLength("{{Output}}/live.txt") > 0'
在 yaml 中还可以使用其本身提供的各种函数和代码比如这里的 'fileLength("{{Output}}/live.txt") > 0' ,由 Golang 完成功能,然后在 yaml 中使用 ‘’ 中包含 JavaScript 代码进行调用( github.com/dop251/goja )。
比如直接把 nmap 端口扫描解析的函数写在 Golang,然后直接在 yaml 通过 JS 运行,这就实现了很好的动态加载。
简单工具的结果,直接通过 yaml 运行 bash 执行,比如 subfinder/amass 这样的,运行后就直接处理好了
复杂工具的结果,比如 nmap 的 xml,那么就在 Go 中完成解析,提供对应的函数,可以让用户在 yaml 中直接处理
感觉是 Go 做工作流一个很完善的方案了,工具、工作流都可以直接通过 yaml 实现,复杂的东西就使用 Go 写好 —— 但是大部分不需要
看源码感觉是大部分的情况都考虑到了,可以一定程度上自由添加新的工具,新的工作流。
相较于很多平台,osmedeus 要更加轻量,测试过一些平台,同样可以直接后台添加新的工具插件,问题就是太大了,我正常就 2核2G 的 VPS,不想要各种后端的架构 Redis 啊什么的,可能快速扫描完成就关闭了。
总之还是比较好用的。
至于为什么要编写 Goauto,是当时微信公众号有个文章说转子女神很厉害,但是它只有 windows 版本的,就感觉 osm 并没有那么的好,后续我又想加上 oneforall,但是 osm 的安装是通过一个 sh 文件的,添加起来感觉很乱,oneforall 的结果是 csv ,虽然通过 linux 命令可以完成提取,但是还是感觉到了 osm 的局限性。
它只能执行 linux 或者是写好的函数,那么可扩展性好像对我来说,并没有那么有用,因为我正常使用的其实也就那几个工具和流程,添加新的工具其实并不频繁。
所以就写了 Goauto,完全没有任何的扩展性,想加工具就得写代码重新打包,至少我自己很熟悉要怎么添加和使用。
因为即使把一个工具源码来来回回阅读,理解清,但是隔一段时间想做修改,还是很麻烦。
AI 看到 freefub 发布了一些要钱的 AI 工具,看了下描述,大部分就是写了 MCP 服务里面提供各种工具,然后 AI 能自己调用工具执行把结果分析展示给人。
那么感觉对于安全从业者,只是把执行工具命令变成了用汉字指挥,况且前段时间在写测绘 MCP Demo 的时候就发现 AI 调用 MCP 的超时和数据大小影响是很大的。有的工具调用时间很长就会导致超时问题,有的工具返回的结果实在是太多了,AI 不会全部读出来,只能多次。
目前对于 AI 在安全工具的看法还是,AI 更适合做不机械化的事情,机械化的事情完全可以用代码实现,固定的工具执行工作流根本不需要,多此一举,MCP 针对批量目标、多个工具就会乏力了。用代码把每个模块要执行的多个工具执行好,出结果后,再给 AI。
对于 Goauto 扫描完的结果就完全可以交给 AI 进行分析( 这是人需要看的东西 ),比如:
端口扫描结果:AI 分析是否有特殊端口,如 redis、es …
网站扫描结果:AI 分析标题、子域名、指纹是否是特殊需要重点关注的业务,比如未授权的 ES、各种 OA…
目录扫描结果:AI 分析是否有特殊目录,如备份文件、swagger ….
漏洞扫描结果:AI 分析是否有高危漏洞,误报验证、或者是一些没用的什么 HTTPS 不安全什么的 ….
信息泄露扫描结果:AI 分析提取是否有真正的敏感信息
爬虫结果:如果把所以流量保持然后 AI 分析,测试是否能寻找更多的需要人工测试的漏洞 ? 这种情况不考虑,个人使用 API 费钱又没有意义
所以目前 Goauto 不打算接入 AI,先用代码完成机械化的事情吧。
Goauto 我的期待是可以很方便的完成各种工具的安装和更新,然后加工具和写工作流的时候也可以有一个规范。
断断续续的完成了,还有的没搞,但是大框架是没啥问题了。
放 Github 上面了 https://github.com/liancccc/goauto
工具安装 使用 go install 可以直接安装 goauto,然后使用 goauto install 就可以一键安装各种工具!
对于文件的去除和排序都直接使用 powershell 和 linux 的工具,效率更高
类型
工具
子域名
subfinder
oneforall
ksubdomain
alterx
cdn 识别
cdncheck ( 添加国内和并发 )
域名解析
dnsx
端口扫描
naabu + nmap
验活去重 | WEB信息 | 截图
httpx
测绘资产
uncover ( 默认工作流的是 quake ,因为我没有其他的会员 )
目录扫描
feroxbuster
爬虫
gospider
katana
urlfinder
gau
crawlergo
爬虫去重
uro
敏感信息
wih
漏洞扫描
xscan
xray
nuclei
afrog
添加工具 定义了一个工具接口和工具运行参数接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 type Module interface { Name () string Install () error CheckInstalled () bool Run (funcParams any) }type BaseParams struct { Target string Output string Proxy string Dict string Timeout string CustomizeParams string }
还是比较简单的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 package oneforall import ( "fmt" "path/filepath" "strings" "github.com/liancccc/goauto/pkg/executil" "github.com/liancccc/goauto/pkg/fileutil" "github.com/liancccc/goauto/pkg/modules" "github.com/liancccc/goauto/pkg/paths" "github.com/liancccc/goauto/pkg/venv/python" "github.com/projectdiscovery/gologger" )var ( pythonBin = python.New ().PythonBin pipBin = python.New ().PipBin oenforallDir = filepath.Join (paths.ToolsDir , "OneForAll" ) oneforallBin = filepath.Join (oenforallDir, "oneforall.py" ) oneforallRequirements = filepath.Join (oenforallDir, "requirements.txt" ) oneforallExec = fmt.Sprintf ("%s %s" , pythonBin, oneforallBin) installRequireCommands = [] string{ fmt.Sprintf ("%s -m pip install -U pip setuptools wheel" , pythonBin), fmt.Sprintf ("%s install -r %s" , pipBin, oneforallRequirements), fmt.Sprintf ("%s install fire" , pipBin), } cloneCommand = fmt.Sprintf ("git clone https://github.com/liancccc/OneForAll.git %s" , oenforallDir) ) func init () { modules.RegisterModule (&ModuleStruct{}) } type ModuleStruct struct { } func (m *ModuleStruct) Name () string { return "oneforall" } func (m *ModuleStruct) Install () error { fileutil.MakeDir (filepath.Dir (oneforallBin)) if !fileutil.IsFile (oneforallBin) { executil.RunCommandSteamOutput (cloneCommand) } for _, cmd := range installRequireCommands { executil.RunCommandSteamOutput (cmd) } return nil } func (m *ModuleStruct) CheckInstalled () bool { commandSteamOutput, _ := executil.RunCommandSteamOutput (oneforallExec) return strings.Contains (commandSteamOutput, "python3 oneforall.py" ) } func (m *ModuleStruct) Run (funcParams any) { params, ok := funcParams.(modules.BaseParams) if !ok { gologger.Error ().Str ("module" , m.Name ()).Msg ("invalid params" ) return } _ = params.MkOutDir () var csvFilePath = filepath.Join (filepath.Dir (params.Output), "oneforall.csv" ) fileutil.Remove (csvFilePath) var command string if params.IsFileTarget () { command = fmt.Sprintf ("%s --targets %s --dns False --brute False --req False --path %s run" , oneforallExec, params.Target , csvFilePath) } else { command = fmt.Sprintf ("%s --target %s --dns False --brute False --req False --path %s run" , oneforallExec, params.Target , csvFilePath) } _, err := executil.RunCommandSteamOutput (command, params.Timeout) if err != nil { gologger.Error ().Str ("module" , m.Name ()).Msg (err.Error ()) return } if !params.IsFileTarget () && fileutil.IsFile (csvFilePath) { subdomains := fileutil.GetCsvColumn (csvFilePath, 6 ) fileutil.WriteSliceToFile (params.Output , subdomains) fileutil.Remove (csvFilePath) } var msg = fmt.Sprintf ("Output: %s, Count: %d" , params.Output , fileutil.CountLines (params.Output)) gologger.Info ().Str ("module" , m.Name ()).Msg (msg) }
实战测试 用 Goauto 扫了大半个月,补天扫了个 XSS 50块钱,hackerone nba 扫了一个 XSS 但是不在范围,hackerone wih 扫了什么前端 KEY 泄露,后面就暂停了。感觉好像没啥作用,VPS 也到期了,不想再充钱。
Todo