插件分享 | 一键统计 Windows 各版本数量的 Windows Count
Goby社区第16 篇插件分享文章
全文共:4955 字 预计阅读时间:13 分钟
前言:Goby 是一款优秀的漏洞验证和利用的工具,功能十分强大,具有丰富的指纹识别规则,扩展性也非常好,各种丰富的插件极大地简化了日常渗透的工作,初次编写插件的我,选择了一个较为简单的统计插件作为入门之作,编写过程中也学习了很多关于 js 的知识,同时参考了插件市场中许多的插件,也感谢编写期间 @go0p 师傅的指导。
0×01 插件使用
当 Goby 扫描完成后或点击扫描历史结果,然后点击侧边的插件按钮,打开我们的 Windows Count 插件即可看到统计的结果,详情如下所示:
0×02 插件开发
2.1 开发思路
作为一个 js 啥都没有接触过的小白,第一想法肯定是先去看看官方文档和模仿一下别的师傅写的插件。首先,我简单地对插件的需求进行了梳理,主要有以下几个要点:
插件基本配置
从扫描资产中提取信息
Windows 版本信息提取
提取 IP 和数量
展示
2.2 插件基本配置
通过对官方文档进行阅读,主要的是配置好 extension.js 中的注册函数,和 package.json 中的插件位置展示,详情如下:
function activate (content) {
goby.registerCommand('WindowsCount', function () {#WindowsCount以带要和package中的command值对应
let path = __dirname + "/os.html"#实现的代码文件路径
goby.showPage(path,false);#展示以页面方式展示
});
}
exports.activate = activate;
2.3 从扫描资产中提取信息
基本的配置都实现好之后,接下来我们就需要对功能的实现进行编码,首先我们需要将扫描的结果提取出来,这里需要用到的 API 是 goby.getAsset,参考官方文档说明:
我们首先需要编写一个简单的 debug 函数查看获取的信息:
goby.getAsset(goby.getTaskId(), getAssetData);//获取资产数据
function getAssetData(data) {
if (data.statusCode == 200) {
console.log(data);//打印出返回的data数据
}
}
2.4 Windows 版本信息提取
通过将 data 数据进行输出,我们可以很清晰地看到 Windows 的版本信息存储在 dcerpc 协议中的 product 字段中,故此我们可以根据协议为 dcerpc 并且 product 中包含 Windows 关键字作为过滤条件提取 Windows 版本类型,代码如下:
let ostypes = []; //存储系统类型
goby.getAsset(goby.getTaskId(), getAssetData); //获取资产数据
//去重函数
function unique(arr) {
return Array.from(new Set(arr));
}
function getAssetData(data) {
if (data.statusCode == 200) {
let ipinfo = data.data.ips
//获取OS类型
ipinfo.forEach((v, k) = >{
if (v.protocols) {
for (var i in v.protocols) {
if (v.protocols[i].protocol.search("dcerpc") != -1 && v.protocols[i].product.search("Windows") != -1) {
console.log(v.protocols[i].product)
ostypes.push(v.protocols[i].product);//将系统类型存入列表中
}
}
}
});
ostypes = unique(ostypes);//去重
}
}
执行结果
2.5 提取 IP 和数量
将系统版本提取完成后,我们需要将对应的版本的 IP 提取出来,然后将 IP 个数进行统计,这里是一个一对多的关系,我们需要建立一个字典,将系统类型作为 key,将 IP 放入到 list 中去,然后就可以将其关系对应起来,最后对 value 的数量进行统计既可以完成我们的需求,详细代码如下:
//根据OS类型生成dic
for (var i in ostypes) {
osinfo[ostypes[i]] = [];
}
//根据OS类型匹配对应的IP
for (var key in osinfo) {
ipinfo.forEach((v, k) => {
if (v.protocols) {
for (var i in v.protocols) {
if (v.protocols[i].port == 135 && v.protocols[i].product == key) {
osinfo[key].push(v.protocols[i].hostinfo.split(":")[0]);
}
}
}
});
}
console.log(osinfo)
执行结果
2.6 展示
展示就直接抄了 threatbook 插件的 html 代码,直接将源码复制修改一下即可,详细的可以参考如下代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Windows系统统计表</title>
<link rel="stylesheet" href="assets/lib/layui/css/layui.css">
</head>
<body>
<div>
<script>
</script>
</div>
<div>
<table id="os-table" class="layui-table" lay-even lay-skin="nob">
<thead>
<tr>
<th width="40" style="font-size: medium;" data-i18n="System type"></th>
<th width="55" style="font-size: medium;">IP</th>
<th width="55" style="font-size: medium;" data-i18n="Count"></th>
</tr>
</thead>
<tbody>
<tr>
</tr>
</tbody>
</table>
</div>
</div>
<script src="assets/js/jquery-3.3.1.min.js"></script>
<script src="assets/lib/layui/layui.all.js"></script>
<script src="assets/js/jquery.i18next.js"></script>
<script>
let osinfo = new Array();
let fs = parent.require('fs');
let ostypes = [];
let html = "";
goby.getAsset(goby.getTaskId(), getAssetData);
//去重函数
function unique(arr) {
return Array.from(new Set(arr));
}
function lang(){
//获取当前Languzge
let language = goby.getLang();
//判断翻译文件是否存在
let translateState = fs.existsSync(goby.__dirname + '/assets/translate/' + language+'/html.json');
//翻译文件存在则使用翻译文件,否则使用默认EN翻译
let lang = translateState?language:'EN';
let a = $.i18n.init({
lng: language, //指定语言
useCookie:false,
resGetPath: './assets/translate/'+lang+'/html.json',//语言包的路径
}, function(err, t) {
if(!err){
$('[data-i18n]').i18n(); // 通过选择器集体翻译
return;
}
goby.showErrorMessage(err)
});
}
lang();
//当lang改变时更新页面内容
goby.bindEvent('on changeLang',()=>{
lang();
})
function getAssetData(data) {
if (data.statusCode == 200) {
let ipinfo = data.data.ips
//获取OS类型
ipinfo.forEach((v, k) => {
if (v.protocols) {
for (var i in v.protocols) {
if (v.protocols[i].protocol.search("dcerpc") != -1 && v.protocols[i].product.search("Windows") != -1) {
ostypes.push(v.protocols[i].product);
}
}
}
});
ostypes = unique(ostypes);
//根据OS类型生成dic
for (var i in ostypes) {
osinfo[ostypes[i]] = [];
}
//根据OS类型匹配对应的IP
for (var key in osinfo) {
ipinfo.forEach((v, k) => {
if (v.protocols) {
for (var i in v.protocols) {
if (v.protocols[i].protocol.search("dcerpc") != -1 && v.protocols[i].product == key) {
osinfo[key].push(v.protocols[i].hostinfo.split(":")[0]);
}
}
}
});
}
//输出数据
for (var os in osinfo) {
let ips = osinfo[os];
let nums = osinfo[os].length;
let tds = "";
for (var ip in ips) {
tds += ips[ip] + "</br>";
}
html += `<tr>
<td>${os}</td>
<td>${tds}</td>
<td>${nums}</td>
</tr>`;
}
$("#os-table tbody").html(html);
}
}
</script>
</body>
</html>
最后输出结果如下:
0×03 小结
此次通过编写一个简单的插件,对 Goby 的插件编写有了一定了解和认识,并且从中收获了不少 js 的知识,也感谢 @go0p 师傅的指导;在编写过程中也发现 Goby 扫描的结果需要更加完善,目标是在 FOFA 找到的,FOFA 有的能识别出系统是 Windows 2000 或者 Windows 10 等,但是 Goby 好像只能识别出 2008 和 XP,其实 Goby 部分扫描结果是有识别到 Windows 的 NT 版本号的,根据版本号的范围也可以对系统做一个初步的判断,这个只是一个小 bug,可能需要以后版本更新去对一些规则进一步完善,希望 Goby 功能越来越强大,插件越来越丰富,gogo!
插件开发文档及Goby开发版下载:
关于插件开发在B站都有详细的教学,欢迎大家到弹幕区合影~
如果表哥/表姐也想把自己上交给Goby社区(获取红队专版),戳这里领取一份插件任务?
https://github.com/gobysec/GobyExtension/projects
文章来自Goby社区成员:socatos,转载请注明出处。
下载Goby内测版,请关注微信公众号:GobySec
下载Goby正式版,请关注网址:https://gobies.org
最新评论