wJa(java闭源项目的自动化白盒+黑盒测试工具)
字数 1380 2025-08-24 23:51:23
wJa Java闭源项目自动化白盒+黑盒测试工具教学文档
1. 工具概述
wJa是一款针对Java闭源项目的自动化安全测试工具,主要功能包括:
- 反编译Java生成的jar包文件
- 将代码整理成语法树
- 根据调用链进行污点分析
- 通过cheetah脚本语言编写测试脚本
- 确定可能存在的漏洞调用链
- 生成测试链接进行fuzzer测试
2. 环境准备
2.1 测试环境要求
- Java运行环境
- 待测试的Java靶场/项目(如示例中的shootingRange.jar)
- wJa工具(wJa.jar)
2.2 靶场启动
java -jar shootingRange.jar
2.3 wJa启动
java -jar wJa.jar
3. wJa分析流程
3.1 界面介绍
-
左侧部分:
- Decompile:jar包反编译的Java资源管理器
- cheetahLanguage:脚本管理器(包含支持库介绍和编写好的cheetah脚本)
-
中间部分:
- Decompile:显示反编译的Java代码
- cheetahLanguage:编写和运行cheetah脚本代码
3.2 基本分析步骤
- 使用wJa打开待分析的jar文件
- 从控制层(controller)分析入口点
- 手动或自动跟踪调用链
- 识别危险函数调用
4. 白盒污点分析
4.1 污点分析模型
污点分析可抽象为三元组〈sources, sinks, sanitizers〉:
- source:污点源(如Spring接口入口点参数)
- sink:污点汇聚点(如jdbc的query方法)
- sanitizer:无害处理(如Integer.valueOf()方法)
4.2 关键函数
-
TrackVarIntoFun:跟踪变量流入函数- 参数1: 起始类
- 参数2: 起始方法
- 参数3: 起始方法参数下标
- 参数4: 目标方法的类
- 参数5: 目标方法
- 参数6: 目标方法的参数下标
- 返回值: 执行流node数组
-
GetAllMethodName:获取类中所有方法名- 注意跳过
<init>(构造方法)和<cinit>(静态代码块)
- 注意跳过
-
GetJavaSentence:从node中获取对应的Java代码
4.3 SQL注入检测脚本示例
#define filter1=String.valueOf(.*?)
#define filter2=Integer.valueOf(.*?)
function filter(sentence){
a = StrRe(sentence,filter1);
if(GetArrayNum(a) != 0){return 0;}
a = StrRe(sentence,filter2);
if(GetArrayNum(a) != 0){return 0;}
return 1;
}
function track(className,methodName){
array allNode;
allNode = TrackVarIntoFun(className,methodName,0,"org/springframework/jdbc/core/JdbcTemplate","query",0);
size = GetArrayNum(allNode);
if(StrFindStr(GetJavaSentence(allNode[ToInt(size-1)]),".query(",0) != "-1"){
i = 0;
print(methodName."参数流动:");
cc = 7;
cs = 1;
while(i < size){
sentence = GetJavaSentence(allNode[i]);
if(filter(sentence) == 0){cc = 5;cs = 5;printcolor("想办法绕过此类:",4);}
if(i == ToInt((size-1))){
if(cc != 5){cs = 2;cc = 3;}
}else{}
if(cc == 5){printcolor("[-]",6);}else{printcolor("[+]",1);}
printcolor(GetClassName(GetNodeClassName(allNode[i]))." ",cc);
printcolor(sentence.StrRN(),cs);
i = ToInt(i+1);
}
}
return 0;
}
function main(args){
className = "com/l4yn3/microserviceseclab/controller/IndexController";
methods = GetAllMethodName(className);
size = GetArrayNum(methods);
i = 0;
while(i < size){
if(methods[i] != "<init>"){track(className,methods[i]);}
i = ToInt(i+1);
}
}
5. 黑盒Fuzzer测试
5.1 SQL注入检测函数
function judgeSQLI(api){
res = HttpGet(api,"");
res1 = HttpGet(api."%27%20or%201=1--+","");
if(GetStrLength(res1[0]) != GetStrLength(res[0])){
res2 = HttpGet(api."%27%20or%202=1--+","");
if(GetStrLength(res2[0]) == GetStrLength(res[0])){
return 1;
}
}
return 0;
}
5.2 注解解析函数
wJa提供以下注解解析方法:
GetClassAnnotation:获取类注解GetClassMethodAnnotation:获取方法上的注解GetClassMethodArgAnnotation:获取参数上的注解GetAnnotationArgListValue:获取注解中list数据GetAnnotationArgSingValue:获取注解中的数据
示例注解解析函数:
function getSpringAnnotationValue(an){
anSize = GetArrayNum(an);
i = 0;
while(i < anSize){
if(GetAnnotationName(an[i]) == "org/springframework/web/bind/annotation/RequestMapping"){
allValue = GetAnnotationArgListValue(an[i],"value");
return allValue[0];
}
if(GetAnnotationName(an[i]) == "org/springframework/web/bind/annotation/PostMapping"){
allValue = GetAnnotationArgListValue(an[i],"value");
return allValue[0];
}
if(GetAnnotationName(an[i]) == "org/springframework/web/bind/annotation/RequestParam"){
allValue = GetAnnotationArgSingValue(an[i],"value");
return allValue;
}
i = ToInt(i + 1);
}
return "";
}
6. 白盒+黑盒自动化测试
6.1 完整测试脚本
#define filter1=String.valueOf(.*?)
#define filter2=Integer.valueOf(.*?)
function filter(sentence){
a = StrRe(sentence,filter1);
if(GetArrayNum(a) != 0){return 0;}
a = StrRe(sentence,filter2);
if(GetArrayNum(a) != 0){return 0;}
return 1;
}
function judgeSQLI(api){
res = HttpGet(api,"");
res1 = HttpGet(api."%27%20or%201=1--+","");
if(GetStrLength(res1[0]) != GetStrLength(res[0])){
res2 = HttpGet(api."%27%20or%202=1--+","");
if(GetStrLength(res2[0]) == GetStrLength(res[0])){
return 1;
}
}
return 0;
}
function track(className,methodName,url){
array allNode;
allNode = TrackVarIntoFun(className,methodName,0,"org/springframework/jdbc/core/JdbcTemplate","query",0);
size = GetArrayNum(allNode);
if(StrFindStr(GetJavaSentence(allNode[ToInt(size-1)]),".query(",0) != "-1"){
i = 0;
print(methodName."白盒测试调用链跟踪:");
cc = 7;
cs = 1;
while(i < size){
sentence = GetJavaSentence(allNode[i]);
noSan = filter(sentence);
if(noSan == 0){cc = 5;cs = 5;}
if(i == ToInt((size-1))){
if(cc != 5){cs = 2;cc = 3;}
}else{}
if(noSan == 0){
printcolor("[-]",6);printcolor("想办法绕过此类:",4);
}else{
printcolor("[+]",1);
}
printcolor(GetClassName(GetNodeClassName(allNode[i]))." ",cc);
printcolor(sentence.StrRN(),cs);
i = ToInt(i+1);
}
if(cc != 5){
printcolor("白盒测试发现此调用链可能存在漏洞,生成测试链接进行黑盒测试".StrRN(),7);
an = GetClassMethodAnnotation(className,methodName);
arg_an = GetClassMethodArgAnnotation(className,methodName,0);
argName = getSpringAnnotationValue(arg_an);
if(argName != ""){
api = url.getSpringAnnotationValue(an)."?".argName."=Wker";
if(judgeSQLI(api) == 1){
printcolor("[+]生成测试链接:".api." 测试存在SQL注入漏洞!".StrRN(),3);
}else{
printcolor("[-]生成测试链接:".api." 测试不存在SQL注入漏洞!请自行测试。".StrRN(),5);
}
}else{
printcolor("测试链接生成失败,error:未找到参数入口!".StrRN(),5);
}
}
}
return 0;
}
function getSpringAnnotationValue(an){
anSize = GetArrayNum(an);
i = 0;
while(i < anSize){
if(GetAnnotationName(an[i]) == "org/springframework/web/bind/annotation/RequestMapping"){
allValue = GetAnnotationArgListValue(an[i],"value");
return allValue[0];
}
if(GetAnnotationName(an[i]) == "org/springframework/web/bind/annotation/PostMapping"){
allValue = GetAnnotationArgListValue(an[i],"value");
return allValue[0];
}
if(GetAnnotationName(an[i]) == "org/springframework/web/bind/annotation/RequestParam"){
allValue = GetAnnotationArgSingValue(an[i],"value");
return allValue;
}
i = ToInt(i + 1);
}
return "";
}
function main(args){
className = "com/l4yn3/microserviceseclab/controller/IndexController";
an = GetClassAnnotation(className);
classPath = "http://127.0.0.1:8080".getSpringAnnotationValue(an);
methods = GetAllMethodName(className);
size = GetArrayNum(methods);
i = 0;
while(i < size){
if(methods[i] != "<init>"){track(className,methods[i],classPath);}
i = ToInt(i+1);
}
}
6.2 优化版本(自动扫描所有类)
function SQLTrack(className){
an = GetClassAnnotation(className);
classPath = "http://127.0.0.1:8080".getSpringAnnotationValue(an);
methods = GetAllMethodName(className);
size = GetArrayNum(methods);
i = 0;
while(i < size){
if(methods[i] != "<init>"){track(className,methods[i],classPath);}
i = ToInt(i+1);
}
return 0;
}
function main(args){
allClass = GetAllClassName();
size = GetArrayNum(allClass);
i = 0;
while(i < size){
an = GetClassAnnotation(allClass[i]);
p = getSpringAnnotationValue(an);
if(p != ""){
SQLTrack(allClass[i]);
}
i = ToInt(i + 1);
}
}
7. 复杂调用链分析
wJa能够处理以下复杂情况:
- 接口实现分析:自动分析子类对象和实现类是否进入危险函数
- 变量转换跟踪:自动追加追踪接受追踪变量的变量
- 如从
name变量追踪到sql变量
- 如从
8. SSRF漏洞分析
8.1 危险函数识别
url = new URL(data);
con = url.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("User-Agent","Mozilla/5.0");
in = new BufferedReader(new InputStreamReader(con.getInputStream()));
8.2 SSRF检测函数
function judgeSSRF(api){
res = HttpGet(api."http://www.baidu.com","");
if(StrFindStr(res[0],"//www.baidu.com/",0) != "-1"){
return 1;
}
return 0;
}
9. 学习资源
- cheetah语法学习:https://github.com/Wker666/Demo
- 包含500+渗透测试脚本
- 详细cheetah语法说明