前言
很久没有写文档了,前段时间身体非常的不舒服,而且也发生了很多事情,讲真有些难受,所以一直就没有对计算机这方面没有关注,但是貌似随着时间的推移,许多事情都已经过去了,也没有感觉多么难受了,可以准备静下心来了。
Wker Test Langue
没有想到更好的名字,暂时先用这个名字吧,写这个脚本语言目的是为了避免类似于python那样,及时poc和exp编写的很多,但是想要统一规范的利用(对某个站点一次性测试很多脚本)还是比较困难的,所以我就写了这个脚本语言,为的是能够更有效率的进行渗透测试。
即可以含有编程语言的灵活性,又不缺失程序框架的规范性,这是高效率的一种体现。
如何体现这两点的请继续看下面的文章(下载地址放在文章末尾)。
程序架构
这个框架语言的组成含有四部分:
- 脚本解析引擎
- 调用脚本引擎的IDE
- 函数功能的支持库
- 大家一起编写的脚本
前三者都由我已经完成了,还有最后一项我也在慢慢的编写,当然大家也可以帮助我编写脚本以及函数功能的支持库(支持库的编写需要关注官方的开发者文档)
程序目录
大家如果进行下载,将会得到的是一个含有脚本引擎以及函数支持库的IDE。
- config:这个目录下面是存放着GitHub配置的相关信息,如果您配置完比GitHub仓库信息之后,会出现一个
github.info
这个文件,这个文件其实是一个java序列化的一个本地持久文件,所以如果这个文件被他人窃取可能会通过反编译我的软件得到相关的类,最终窃取你的token,千万要注意! - ico:这给没啥说的,就是一些图标信息
- jar:这个是函数功能的支持库,里面会有一些按照规则写的jar包,如何编写支持库请移步到开发者官方文档,如果想要更新支持库,一是更新软件,而是在WKer的官方源中下载,切勿随意下载第三方未经授权的支持库,里面啥操作自己不去反编译也不知道,有可能会有反弹的shell,千万注意,但是Wker官方的是不会出现问题的。
- script:这个是保存之前写好的脚本,里面是一类类的文件夹以及.wker的脚本。
- WkerIDE.jar:这个就是主程序了,后面会详细介绍
程序的运行
由于使用的是动态加载支持库(实际上是动态加载jar包),java8前后的操作是不同的,虽然在程序内部做了一些判断URIClassLoader的操作,但是java8之后还是需要提供权限:
-
java8以及8之前的版本运行使用:
java -jar WkerIDE.jar -g
-
java9以及9之之后的版本运行使用:
java --add-opens java.base/jdk.internal.loader=ALL-UNNAMED --add-opens jdk.zipfs/jdk.nio.zipfs=ALL-UNNAMED -jar WkerIDE.jar -g
- -g参数:打开程序的gui界面
目前我也只写了这一个参数,之后程序的更新会增加许多自动化参数
程序启动界面:
程序一启动会弹出一个检查版本信息的加载界面,这个界面不仅会加载各种支持库还有初始化GitHub信息,也会检测更新。
程序启动之后就会出现如下的界面:
可以看到程序界面还算整洁。
程序界面介绍
程序一启动会出现一个实例代码:
function main(args)
{
print(" Wker is handsome !");
}
可以看到代码风格非常类似于js,但也有一些特点是类似于python的,为的就是能够在很短的时间内让大家熟练的使用代码(学起来很简单)。
菜单栏
- 文件:里面包含了打开文件,保存文件,新建文件
- 运行:目前只提供了单独运行当前代码标签页的代码
- 设置:用来设置全局变量数组以及命令行参数和GitHub信息
- 官方源:用来打开官方信息
中间部分
- 支持库:显示当前支持库中提供的函数
- 文件:有本地文件以及配置的GitHub仓库中的文件
- 双击本地文件可以在右侧的代码编辑框中进行展示
- 右侧是一个动态多标签页的代码编辑框
- 这个双机标签页头部是可以进行关闭标签的
底层部分
用来展示各种操作信息的
运行示例代码
点击:运行->开始运行。
会在控制台输出: Wker is handsome !
看到输出说明环境是没有什么问题的。
语法讲解
如果您有js和py的语言基础,那么读起Wker代码是十分简单的。
函数
首先我们要知道Wker语言是一门面向过程的语言,所以程序是由多个函数组成的。
函数又分为三种函数:
- 本地支持库的函数
- main函数
- 自定义函数
- 支持库函数是由Wker官方提供的native本地函数,主要是用来提供功能接口的
- main函数是程序运行的主函数,脚本运行就是从main函数进入的
- 自定义函数是脚本编写者自定义的函数
本地库函数
这里不详细介绍了,因为我们点击支持库的某一个库函数的时候在下方会出现相关的函数介绍,如果想要开发本地库函数可以阅读官方开发文档。
main函数的格式
function main(args)
使用关键字function关键字定义,其中args参数用来接收命令行传递过来的数组,目前命令行传递过来的数组定义暂时只能在:设置->命令函参数中进行设置,之后会推出命令行下运行的时候会直接传递进去的。
可以在main函数中使用args数组,例如:
-
设置args数组
-
打印args[0]
在这里我们也可以看到每一次执行脚本的时候都会用一个------------------------------------------------------
分割线进行分割的。
自定义函数
同样也是使用function进行定义,例如:
function add(a,b)
{
print("add函数已经运行");
return a+b;
}
function main(args)
{
print(add(2,3));
}
我们定义了一个add函数,add函数显示print了一行字,然后返回了a+b的值,我们在主方法中打印了add(2,3)的值,最终程序的运行结果:
可以看到我们输出的结果和想象中的并不是完全一样,哪里不一样呢?我们应该输出5,但我们输出了5.0。这是因为Wker语言没有类别区分,为了兼容性所以全部的数值结算的结果都是小数,那么我们如何得到一个整数的结果呢?我们可以使用库函数:ToInt
进行转换:
print(ToInt(add(2,3)));
最终执行的结果:
这样子们的小数部分就不存在了。
数据类型
Wker语言的数据形式有三种:
- 变量
- 数组
数据类型的话呢:
- 文本
- 小数
- 对象
这里称之为对象其实并不是十分准确,这里称为句柄可能会更加的准确一些,但是为了帮助大家理解还是称之为数组吧。
变量的声明
可以使用var
进行声明,也可以不进行声明直接进行赋值,例如:
可以看到没有进行变量声明也是可以的。
但是有一点注意,如果变量没有被赋值,如果直接使用的话呢,解析引擎会爆出not found的错误!
数组的声明
可以用array
进行声明,当然也可以不声明直接使用,例如:
可以看到我们使用ArrayAddEle函数向数组添加了一个值,最终将数组返回。
对象的使用
暂时来说对于用户无法直接声明一个对象,对象其实在Wker中是一个句柄,通过这个句柄可以操作特定的对象,例如在ObjectLibrary这个支持库中导出的HashMap系列函数,就是典型的例子:
可以看出我们通过hashmap进行键值对的操作,但是有一点注意,我在开发支持库的时候我不小心将hash打成了hasp,哈哈,下次更新支持库的时候再说吧!
返回值
返回值类型:
- 变量
- 数组
- 对象
变量的返回
这个很简单,和常规的返回是一样的:
function add(a,b)
{
print("add函数已经运行");
return a+b;
}
数组的返回
这个在上面的数组的使用中已经用到了数组的返回,其实和变量的返回没有什么区别,只不过是返回了一个数组罢了。
对象的返回
也是同样的,给大家看个例子大家就知道了:
function GetHash()
{
a = GetHaspMap();
SetHaspMapValue(a,"Wker","Good");
print(GetHaspMapValue(a,"Wker"));
return a;
}
function main(args)
{
print(GetHaspMapValue(GetHash(),"Wker"));
}
可以看到,我们定义了GetHash()函数,用来得到一个hashmap对象。
数据控制操作符
Wker语言有五种操作符
+
-
*
/
.
和你看到的一样+-*/没有什么好说的,但是注意的是只能操作变量或者数组元素(是整数的),而.
这个操作符用来连接字符串的。
例如:
function main(args)
{
print("a"."b");
}
可以打印出ab。
条件操作符
>
<
<=
>=
==
!=
如上述所表述,前四种易于理解,无非就是比较大小的操作符。
第五种是表示两个数据相等(可以是数组也可是字符串)
第六种是表示两个数据不相等(可以是数组也可是字符串)
操作符优先级
非常可惜的是,在Wker语言中我并没有提供优先级,也就是说没有优先级,但是如何让Wker拥有优先级呢?很简单,那就是括号,虽然操作符没有优先级,但是括号是有的,任何在()
中的都是优先进行运算的。
语法逻辑
目前Wker语言只提供了两个语法逻辑,因为其他的逻辑语法都是这两个的衍生品。
- if - else
- while
一个用来控制流程走向的,一个用来控制循环操作的。
if - else
基本的流程控制语句,也就是满足情况执行什么,不满足情况的时候执行什么。
这里举个例子大家就清楚了。
function main(args)
{
a = 15;
if(a>10)
{
print("变量a大于10");
}else
{
print("变量a不大于10");
}
}
最终在命令行打印出:变量a大于10
while
循环语句,这个是用来在情况满足时循环执行某一段程序,在情况不满足时跳出。
例如如下代码:
function main(args)
{
a = 15;
while(a >10)
{
print(ToInt(a));
a = a-1;
}
}
上面这段代码打印的结果:
15
14
13
12
11
循环执行了五次就跳出了循环。
continue
这个是在while循环中跳到循环结尾的一个语句,当满足一定的情况可以使用continue
跳到循环的结尾,将上面的while循环稍作顺序调整和改变:
function main(args)
{
a = 15;
while(a >10)
{
a = a-1;
if(a>12)
{
continue;
}
print(ToInt(a));
}
}
最终打印出来的结果:
12
11
10
大家可以自己仔细考虑一下为什么只打印出了这三个。
break
这个是在while循环中跳出循环的一个语句,当满足一定的情况可以使用continue
跳出循环,将上面的while循环稍作顺序调整和改变:
function main(args)
{
a = 15;
while(a >10)
{
a = a-1;
if(a<12)
{
break;
}
print(ToInt(a));
}
}
最终打印的结果:
14
13
12
大家可以自己仔细考虑一下为什么只打印出了这三个。
全局变量与全局数组
全局变量
全局变量分为两种,一种是相对于IDE的全局变量,针对于所有脚本,另一种是针对于当前脚本(这个可以认为是常量会更好)
先讲第二种针对于本脚本的
#define定义
当我们想要使用""
这样子的字符的时候我们会比较麻烦,所以我们最好使用宏定义会比较简单,看如下例子:
#define Wker = "good"
function main(args)
{
print(Wker);
}
最终将会打印出:"good"
,这个比较好理解,并且可以看到#define
定义的常量是不受限于""
的,所以我们可以输入一些相对于复杂的字符,但是\r\n
是不可以的,如果想得到换行的话呢,你可以使用库函数:StrRN
得到一个换行。
IDE全局变量
这个针对于所有脚本的,我们可以通过打开:设置->全局变量进行设置:
让后我们执行下面这段代码:
function main(args)
{
print(test);
}
最终是可以打印出Wker的,并且你再新建一个临时文件也是可以使用test这个变量的。
全局数组
全局数组的定义是只有一种的,我们可以通过打开:设置->全局数组进行设置
然后我们执行下面这段代码:
function main(args)
{
print(ws[0]);
print(ws[1]);
print(Wker[0]);
print(Wker[0]);
}
最终可以得到结果:
000
111
222
222
#request
这个不是赋值,而是一个必须请求。在我们想要得到一个指定变量的时候使用,例如我现在要用户必须提供给我一个名称为url的一个变量,否则不可以运行,我们可以使用#request url = var
,如果我们没有赋值url,然后运行了脚本,那么脚本解析器会提示:
这个在之后的批量运行时是十分重要的!
虽然们可以使用input
库函数从命令行得到输出结果,但是这并不是一个框架性质的做法,所以建议使用#request
来从全局中得到值,当然#request
可以是var
也可以是array
!
注释
单行注释
使用//
在代码的最后,可以随意填写你觉得可以帮助到你的内容
多行注释
使用
/*
*/
可以添加多行注释,里面可以填写可以帮助理解的内容
小例子(SQL注入点检测)
#request url = var
function main(args)
{
source = HttpGet(url,"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:85.0) Gecko/20100101 Firefox/85.0");
right = HttpGet(url."%20and%201=1","User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:85.0) Gecko/20100101 Firefox/85.0");
wrong = HttpGet(url."%20and%201=2","User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:85.0) Gecko/20100101 Firefox/85.0");
if(GetStrLength(source[0]) == GetStrLength(right[0]))
{
if(GetStrLength(wrong[0]) != GetStrLength(right[0]))
{
print(url." have sql");
}else
{
print(url." no have sql");
}
}else
{
print(url." no have sql");
}
}
通过这段代码可以从用户输入的url变量中进行获取连接,然后通过HttpGet得到页面代码,最终通过比较判断是否存在SQL注入漏洞,其实也就是一个简单的if - else逻辑判断。
从这一点也不难看出Wker语言有程序的灵活性也有框架的规范性。
不难想象我们可以通过编写一些获取全局url变量(全局url数组也可以)判断漏洞的脚本然后大批量同时执行。
配置GitHub仓库
写好脚本之后我们通常是存放到本地,但是这样子的方式往往会让我们的脚本丢失,所以将脚本存储到云端是一个更好的选择,那么GitHub将会是我们比较好的免费选择项目,所以Wker也想到了这一点,在程序的内部增加了脚本更新到GitHub的功能,虽然现在还是不是十分只能需要手动提交,但是之后将会推出更加完善的功能。
申请GitHub仓库
首先我们需要有一个GitHub的账号,然后访问https://github.com/new新建一个仓库,选择的时候最好选择public公开的方式,其他的也都就不是那么重要了,申请好之后,我们需要再次申请一个token用来连接我们的GitHub仓库。
创建token
访问:https://github.com/settings/tokens/new
来添加一个token令牌,这个令牌需要注意的是,申请之后他会显示你的token,这个一定要记好,以防之后忘记,因为之后GitHub将不会显示给你这个token了,权限的话呢看着给,要能够上传下载更新删除就可以了,我的话呢一般都是全部勾选,比较懒哈哈。
配置GitHub到Wker
点击设置->GitHub仓库设置
输入您的账号名称,然后点击获取仓库:
我们选择刚才的仓库,我这里选择Demo,然后在下方输入您的Token,然后点击确定:
然后我们就可以看到我们的GitHub仓库的文件了,这个时候我们就可以有点GitHub仓库中的项目进行下载,然后点击本地文件的项目进行上传更新到仓库:
然后我们就可以到仓库中进行查看:
如果下载的话呢就右键点击下载的项目下载就好了,并且因为保存了信息,所以在之后每次打开Wker的时候都是会自动登录GitHub的。
可能出现的问题
因为最近GitHub貌似受到了DNS污染的攻击,所以raw.githubusercontent.com这个域名可能访问不了,我们需要在hosts文件中进行配置:
在C:\Windows\System32\drivers\etc\hosts这个文件中加入:
199.232.96.133 raw.githubusercontent.com
199.232.96.133是你在www.ipaddress.com查询的结果。
Linux和macOS下也是修改host,这里过多赘述。
官方源
可以通过访问https://github.com/Wker666/Demo获取到更多的支持库以及脚本,虽然现在我还没有更新上去,哈哈!
配套工具
在我上传的文件中我们随之上传两个小工具。
-
cmsSearch:用来扫描网站用到的cms
-
java -jar Wker_CMSSearch.jar http://www.xxx.com
不要删除cms文件夹下面的CMS.csv那个是本地的指纹库。工具会联网查找也会本地扫描。
-
-
EXPSearch:用来在exploit-db上面提取漏洞的
-
java -jar WKer_EXPSearch.jar
程序生成的扫描信息结果会放在data目录下,有漏洞信息和poc或exp。
-
后记
程序可能会有一些不完整,有一些方便的功能还是没有完全出来,但是目前来看bug暂时没有发现,至于后面的更新的内容也会在官方源中进行展示。
如果发现了什么bug以及什么可以优化的方面的话呢可以联系Wker:3311736869,当然发送邮件也是一个不错的选择。