├── test └── CVE-2022-33980-1.0-SNAPSHOT.jar ├── src └── main │ └── java │ ├── Main.java │ ├── rules │ ├── ZipSlipConstant.java │ ├── XSSconstant.java │ ├── JenkinsConstant.java │ ├── FileReadConstant.java │ ├── RCEConstant.java │ ├── LDAPinjectionConstant.java │ ├── SQLinjectionConstant.java │ ├── SSRFconstant.java │ ├── JNDIConstant.java │ ├── XXEconstant.java │ ├── Ruleservice.java │ └── UnserializeConstan.java │ ├── Util │ ├── IOUtil.java │ ├── DirUtil.java │ ├── ClassUtil.java │ ├── StackUtil.java │ ├── JarUtil.java │ └── WriteUtil.java │ ├── jvm │ ├── GotoState.java │ ├── LocalVariables.java │ └── OperandStack.java │ ├── Service │ ├── MethodCallService.java │ ├── CallGraphService.java │ ├── LoadSink.java │ ├── LoadSource.java │ ├── DiscoverService.java │ ├── DarwService.java │ ├── PassthroughService.java │ ├── InheritanceService.java │ ├── onlySinkParseServerice2.java │ ├── SinkParseService.java │ ├── NoTaintChainDiscoverService.java │ ├── onlySinkParseServerice.java │ └── ChainDiscoverService.java │ ├── model │ ├── ClassFile.java │ ├── Sink.java │ ├── InheritanceMap.java │ ├── CallGraph.java │ ├── MethodReference.java │ └── ClassReference.java │ ├── framework │ ├── JenkinsSourceVisitor.java │ ├── SinkClassVisitor.java │ └── JenkinsAdapter.java │ ├── asm │ ├── MethodCallAdapter.java │ ├── MethodCallClassVisitor.java │ ├── VulnMethodAdapter.java │ ├── VulnClassVisitor.java │ ├── CallGraphClassVisitor.java │ ├── SourceClassVisitor.java │ ├── PassthroughClassVisitor.java │ ├── DiscoveryClassVisitor.java │ ├── CallGraphMethodAdapter.java │ └── PassthroughMethodAdapter.java │ └── app │ ├── Command.java │ └── Application.java ├── html ├── graph.html ├── data.js └── vis.min.css ├── pom.xml └── README.md /test/CVE-2022-33980-1.0-SNAPSHOT.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LaNyer640/java_asm_parse/HEAD/test/CVE-2022-33980-1.0-SNAPSHOT.jar -------------------------------------------------------------------------------- /src/main/java/Main.java: -------------------------------------------------------------------------------- 1 | import app.Application; 2 | 3 | import java.io.IOException; 4 | 5 | public class Main { 6 | public static void main(String[] args) throws IOException { 7 | Application.run(args); 8 | } 9 | } -------------------------------------------------------------------------------- /src/main/java/rules/ZipSlipConstant.java: -------------------------------------------------------------------------------- 1 | package rules; 2 | 3 | public class ZipSlipConstant { 4 | private static final String[][] rules = new String[][]{ 5 | {"INVOKEVIRTUAL","java/util/zip/ZipEntry","getName","*","ZipSlip","ZipSlip","-1","1"}, 6 | {"INVOKEVIRTUAL","org/apache/commons/compress/archivers/ArchiveEntry","getName","*","ZipSlip","ZipSlip","-1","1"}, 7 | }; 8 | 9 | public static String[][] getRules(){ 10 | return rules; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/Util/IOUtil.java: -------------------------------------------------------------------------------- 1 | package Util; 2 | 3 | import java.io.InputStream; 4 | import java.io.OutputStream; 5 | 6 | public class IOUtil { 7 | public static void copy(InputStream inputStream, OutputStream outputStream) { 8 | try { 9 | final byte[] buffer = new byte[4096]; 10 | int n; 11 | while ((n = inputStream.read(buffer)) > 0) { 12 | outputStream.write(buffer, 0, n); 13 | } 14 | } catch (Exception e) { 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/rules/XSSconstant.java: -------------------------------------------------------------------------------- 1 | package rules; 2 | 3 | public class XSSconstant { 4 | private static final String[][] rules = new String[][]{ 5 | {"INVOKEVIRTUAL","hudson/util/FormValidation","errorWithMarkup","*","XSS","JENKINS-PLUGIN-XSS","-1","1"}, 6 | {"INVOKEVIRTUAL","hudson/util/FormValidation","okWithMarkup","*","XSS","JENKINS-PLUGIN-XSS","-1","1"}, 7 | {"INVOKEVIRTUAL","hudson/util/FormValidation","addMarkup","*","XSS","JENKINS-PLUGIN-XSS","-1","1"}, 8 | }; 9 | 10 | public static String[][] getRules(){ 11 | return rules; 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/jvm/GotoState.java: -------------------------------------------------------------------------------- 1 | package jvm; 2 | 3 | public class GotoState { 4 | private LocalVariables localVariables; 5 | private OperandStack operandStack; 6 | 7 | public LocalVariables getLocalVariables() { 8 | return localVariables; 9 | } 10 | 11 | public void setLocalVariables(LocalVariables localVariables) { 12 | this.localVariables = localVariables; 13 | } 14 | 15 | public OperandStack getOperandStack() { 16 | return operandStack; 17 | } 18 | 19 | public void setOperandStack(OperandStack operandStack) { 20 | this.operandStack = operandStack; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/rules/JenkinsConstant.java: -------------------------------------------------------------------------------- 1 | package rules; 2 | 3 | 4 | public class JenkinsConstant { 5 | public static String JenkinsAnno1 = "Lorg/kohsuke/stapler/verb/POST;"; 6 | public static String JenkinsAnno2 = "Ljenkins/security/stapler/WebMethod;"; 7 | public static String JenkinsAnno3 = "Lorg/kohsuke/stapler/interceptor/InterceptorAnnotation;"; 8 | public static String JenkinsAnno4 = "Lorg/kohsuke/stapler/interceptor/RequirePOST;"; 9 | public static String JenkinsAnno5 = "Lorg/kohsuke/stapler/DataBoundConstructor;"; 10 | public static String JenkinsAnno6 = "Lorg.kohsuke/stapler/DataBoundSetter;"; 11 | 12 | 13 | public static String ParamAnn1 = "StaplerRequest"; 14 | public static String ParamAnn2 = "StaplerRequest"; 15 | public static String ParamAnn3 = "StaplerRequest"; 16 | public static String ParamAnn4 = "org/kohsuke/stapler/QueryParameter"; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/Service/MethodCallService.java: -------------------------------------------------------------------------------- 1 | package Service; 2 | 3 | import asm.MethodCallClassVisitor; 4 | import model.ClassFile; 5 | import model.MethodReference; 6 | import org.objectweb.asm.ClassReader; 7 | import org.objectweb.asm.Opcodes; 8 | 9 | import java.util.List; 10 | import java.util.Map; 11 | import java.util.Set; 12 | 13 | public class MethodCallService { 14 | public static void start(List classFileList, Map> methodCall){ 15 | for (ClassFile file : classFileList) { 16 | try { 17 | MethodCallClassVisitor dcv = new MethodCallClassVisitor(Opcodes.ASM7,methodCall); 18 | ClassReader cr = new ClassReader(file.getFile()); 19 | cr.accept(dcv, ClassReader.EXPAND_FRAMES); 20 | } catch (Exception e) { 21 | e.printStackTrace(); 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/rules/FileReadConstant.java: -------------------------------------------------------------------------------- 1 | package rules; 2 | 3 | public class FileReadConstant { 4 | 5 | private static final String[][] rules = new String[][]{ 6 | {"INVOKEVIRTUAL","java/nio/file/Files","readAllBytes","*","FileRead","FileRead","-1","1"}, 7 | {"INVOKEVIRTUAL","java/nio/file/Files","readAllLines","*","FileRead","FileRead","-1","1"}, 8 | {"INVOKEVIRTUAL","java/nio/file/Files","readString","*","FileRead","FileRead","-1","1"}, 9 | {"INVOKEVIRTUAL","java/nio/file/Files","lines","*","FileRead","FileRead","-1","1"}, 10 | {"INVOKEVIRTUAL","java/nio/file/Files","newBufferedReader","*","FileRead","FileRead","-1","1"}, 11 | //{"INVOKEVIRTUAL","java/nio/file/Files","newInputStream","*","FileRead","FileRead","1","1"}, 12 | {"INVOKEVIRTUAL","java/nio/file/Files","newByteChannel","*","FileRead","FileRead","-1","1"}, 13 | }; 14 | public static String[][] getRules(){ 15 | return rules; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/rules/RCEConstant.java: -------------------------------------------------------------------------------- 1 | package rules; 2 | 3 | public class RCEConstant { 4 | //xmldecode和ELProcessor规则需要添加 5 | private static final String[][] rules = new String[][]{ 6 | {"INVOKEVIRTUAL","java/lang/Runtime","exec","*","RCE","Runtime-RCE","-1","1"}, 7 | {"INVOKEVIRTUAL","java/lang/ProcessBuilder","exec","*","RCE","ProcessBuilder-RCE","-1","1"}, 8 | {"INVOKEVIRTUAL","java/lang/ProcessBuilder","start","*","RCE","ProcessBuilder-RCE","-1","1"}, 9 | {"INVOKEVIRTUAL","groovy/lang/GroovyShell","evaluate","*","RCE","GroovyShell-RCE","-1","1"}, 10 | {"INVOKEVIRTUAL","javax/script/ScriptEngineManager","getEngineByName","(Ljava/lang/String;)Ljavax/script/ScriptEngine;","RCE","Script-RCE","1","2"}, 11 | {"INVOKEVIRTUAL","javax/script/ScriptEngine","eval","*","RCE","Script-RCE","1","2"}, 12 | {"INVOKEVIRTUAL","bsh/Interpreter","eval","*","RCE","BeanShell-RCE","-1","1"} 13 | }; 14 | 15 | public static String[][] getRules(){ 16 | return rules; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/Service/CallGraphService.java: -------------------------------------------------------------------------------- 1 | package Service; 2 | 3 | import asm.CallGraphClassVisitor; 4 | import model.*; 5 | import org.objectweb.asm.ClassReader; 6 | 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.Set; 10 | 11 | public class CallGraphService { 12 | public static void start(Map classMap, 13 | InheritanceMap inheritanceMap, 14 | Map> passthroughDataflow, 15 | Set discoveredCalls, List classFileList){ 16 | for (ClassFile file : classFileList) { 17 | try { 18 | CallGraphClassVisitor cv = new CallGraphClassVisitor(classMap, inheritanceMap, passthroughDataflow,discoveredCalls); 19 | ClassReader cr = new ClassReader(file.getFile()); 20 | cr.accept(cv, ClassReader.EXPAND_FRAMES); 21 | } catch (Exception e) { 22 | e.printStackTrace(); 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/jvm/LocalVariables.java: -------------------------------------------------------------------------------- 1 | package jvm; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashSet; 5 | import java.util.List; 6 | import java.util.Set; 7 | 8 | public class LocalVariables { 9 | private final ArrayList> array; 10 | 11 | public LocalVariables() { 12 | this.array = new ArrayList<>(); 13 | } 14 | 15 | public void clear() { 16 | this.array.clear(); 17 | } 18 | 19 | public void add(Set t) { 20 | this.array.add(t); 21 | } 22 | 23 | public void set(int index, Set t) { 24 | array.set(index, t); 25 | } 26 | 27 | public void set(int index, T t) { 28 | Set set = new HashSet<>(); 29 | set.add(t); 30 | array.set(index, set); 31 | } 32 | 33 | public Set get(int index) { 34 | return array.get(index); 35 | } 36 | 37 | public int size() { 38 | return this.array.size(); 39 | } 40 | 41 | public void remove(int index) { 42 | this.array.remove(index); 43 | } 44 | 45 | public List> getList() { 46 | return this.array; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/Service/LoadSink.java: -------------------------------------------------------------------------------- 1 | package Service; 2 | 3 | import model.Sink; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | public class LoadSink { 9 | public static void load(List> Sinks, String[][] SinkRule){ 10 | for(int i=0;i SourceMethod; 14 | 15 | public JenkinsSourceVisitor(List SourceMethod){ 16 | super(Opcodes.ASM6); 17 | this.SourceMethod = SourceMethod; 18 | } 19 | 20 | @Override 21 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { 22 | this.ClassName = name; 23 | super.visit(version,access,name,signature,superName,interfaces); 24 | } 25 | 26 | @Override 27 | public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions){ 28 | boolean isStatic = (access & Opcodes.ACC_STATIC) != 0; 29 | MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); 30 | this.MethodName = name; 31 | return new JenkinsAdapter(MethodName, desc, this.ClassName, Opcodes.ASM6, mv,SourceMethod,isStatic); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/Service/LoadSource.java: -------------------------------------------------------------------------------- 1 | package Service; 2 | 3 | import asm.SourceClassVisitor; 4 | import model.ClassFile; 5 | import model.MethodReference; 6 | import org.objectweb.asm.ClassReader; 7 | 8 | import java.util.List; 9 | 10 | public class LoadSource { 11 | public static void loadsource(List Sources, List classFileList,String sourcePattern) { 12 | for (ClassFile file : classFileList) { 13 | try { 14 | ClassReader cr = new ClassReader(file.getFile()); 15 | SourceClassVisitor cv = new SourceClassVisitor(Sources,sourcePattern); 16 | cr.accept(cv, ClassReader.EXPAND_FRAMES); 17 | } catch (Exception e) { 18 | throw new RuntimeException(e); 19 | } 20 | } 21 | } 22 | 23 | 24 | public static void loadsource(List Sources, List classFileList) { 25 | for (ClassFile file : classFileList) { 26 | try { 27 | ClassReader cr = new ClassReader(file.getFile()); 28 | SourceClassVisitor cv = new SourceClassVisitor(Sources); 29 | cr.accept(cv, ClassReader.EXPAND_FRAMES); 30 | } catch (Exception e) { 31 | throw new RuntimeException(e); 32 | } 33 | } 34 | } 35 | 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/asm/MethodCallAdapter.java: -------------------------------------------------------------------------------- 1 | package asm; 2 | 3 | import model.ClassReference; 4 | import model.MethodReference; 5 | import org.objectweb.asm.MethodVisitor; 6 | import org.objectweb.asm.Type; 7 | 8 | import java.util.HashSet; 9 | import java.util.Map; 10 | import java.util.Set; 11 | 12 | public class MethodCallAdapter extends MethodVisitor { 13 | private String ClassName; 14 | private String MethodName; 15 | private String descriptor; 16 | 17 | private final Map> methodCall; 18 | private final Set calledMethods; 19 | public MethodCallAdapter(int api, MethodVisitor mv,Map> methodCall, String className, String name, String descriptor) { 20 | super(api,mv); 21 | this.methodCall = methodCall; 22 | this.calledMethods = new HashSet<>(); 23 | this.methodCall.put(new MethodReference.Handle(new ClassReference.Handle(className), name, descriptor), calledMethods); 24 | } 25 | 26 | 27 | @Override 28 | public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { 29 | calledMethods.add(new MethodReference.Handle(new ClassReference.Handle(owner), name, desc)); 30 | super.visitMethodInsn(opcode, owner, name, desc, itf); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/Util/DirUtil.java: -------------------------------------------------------------------------------- 1 | package Util; 2 | 3 | import java.io.File; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | public class DirUtil { 8 | 9 | public static boolean removeDir(File dir){ 10 | if(dir.isDirectory()){ 11 | String[] children = dir.list(); 12 | if(children != null){ 13 | for (String child : children){ 14 | boolean success = removeDir(new File(dir,child)); 15 | if(!success){ 16 | return false; 17 | } 18 | } 19 | } 20 | } 21 | return dir.delete(); 22 | } 23 | 24 | public static List getAllFile(String directoryPath) { 25 | List list = new ArrayList(); 26 | File baseFile = new File(directoryPath);; 27 | if (baseFile.isFile() || !baseFile.exists()) { 28 | return list; 29 | } 30 | File[] files = baseFile.listFiles(); 31 | for (File file : files) { 32 | if (file.isDirectory()) { 33 | list.add(file.getAbsolutePath()); 34 | list.addAll(getAllFile(file.getAbsolutePath())); 35 | } else { 36 | list.add(file.getAbsolutePath()); 37 | } 38 | } 39 | return list; 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/model/Sink.java: -------------------------------------------------------------------------------- 1 | package model; 2 | 3 | public class Sink { 4 | private final String ClassName; 5 | private final String name; 6 | private final String desc; 7 | private int targetIndex; 8 | private String sinkName; 9 | private int flag; 10 | 11 | public Sink(String ClassName, String name, String desc,String sinkName,int targetIndex,int flag) { 12 | this.ClassName = ClassName; 13 | this.name = name; 14 | this.desc = desc; 15 | this.sinkName = sinkName; 16 | this.targetIndex = targetIndex; 17 | this.flag = flag; 18 | } 19 | 20 | public String getClassName(){ 21 | return this.ClassName; 22 | } 23 | public String getDesc(){ 24 | return this.desc; 25 | } 26 | public String getName(){ 27 | return this.name; 28 | } 29 | public int getTargetIndex(){ 30 | return this.targetIndex; 31 | } 32 | public String getSinkName(){ 33 | return this.sinkName; 34 | } 35 | public int getFlag(){ 36 | return this.flag; 37 | } 38 | 39 | @Override 40 | public int hashCode() { 41 | int result = ClassName != null ? ClassName.hashCode() : 0; 42 | result = 31 * result + (name != null ? name.hashCode() : 0); 43 | result = 31 * result + (desc != null ? desc.hashCode() : 0); 44 | return result; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/app/Command.java: -------------------------------------------------------------------------------- 1 | package app; 2 | 3 | import com.beust.jcommander.Parameter; 4 | 5 | import java.util.List; 6 | 7 | public class Command { 8 | @Parameter(names = {"-h", "--help"}, description = "Help Info", help = true) 9 | public boolean help; 10 | 11 | @Parameter(names = {"-l","--lib"},description = "【+】需要扫描的jar包") 12 | public List jar = null; 13 | 14 | @Parameter(names = {"-ld","--libs"},description = "【+】需要扫描的jar包所在文件夹") 15 | public String libs= null; 16 | 17 | @Parameter(names = {"--jdk"}, description = "【+】使用jdk中的rt.jar") 18 | public boolean jdk; 19 | 20 | @Parameter(names = {"--all"}, description = "【+】加载所有lib") 21 | public boolean lib; 22 | 23 | @Parameter(names = {"-m","--moudles"}, description = "【+】选择sink规则") 24 | public String module; 25 | 26 | @Parameter(names = {"-r","--rule"}, description = "【+】加载sink自定义规则") 27 | public String rule=null; 28 | 29 | @Parameter(names = {"--source"}, description = "【+】source选择") 30 | public String source=null; 31 | 32 | @Parameter(names = {"-t", "--Taint"}, description = "【+】选择模式 模式一:使用污点分析 模式二:不使用污点分析 模式三:从sink逆推调用链 模式四:只分析源码中是否存在sink点") 33 | public int taint; 34 | 35 | @Parameter(names = {"--draw"}, description = "【+】画出调用图") 36 | public boolean draw; 37 | @Parameter(names = {"--Save"}, description = "【+】保存sink规则") 38 | public Boolean Save=false; 39 | @Parameter(names = {"--methodName"}, description = "【+】想要搜寻方法") 40 | public String methodName=null; 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/rules/LDAPinjectionConstant.java: -------------------------------------------------------------------------------- 1 | package rules; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class LDAPinjectionConstant { 7 | private static final String[][] rules = new String[][]{ 8 | {"INVOKEVIRTUAL","javax/naming/directory/DirContext","search","*;","LDAP","JDK-LDAP","-1","1"}, 9 | {"INVOKEVIRTUAL","com/unboundid/ldap/sdk/LDAPConnection","search","*;","LDAP","UnboundID-LDAP","-1","1"}, 10 | {"INVOKEVIRTUAL","com/unboundid/ldap/sdk/LDAPConnection","searchForEntry","*;","LDAP","UnboundID-LDAP","-1","1"}, 11 | {"INVOKEVIRTUAL","com/unboundid/ldap/sdk/LDAPConnection","asyncSearch","*;","LDAP","UnboundID-LDAP","-1","1"}, 12 | {"INVOKEVIRTUAL","org/springframework/ldap/core/LdapTemplate","find","*;","LDAP","SPRING-LDAP","-1","1"}, 13 | {"INVOKEVIRTUAL","org/springframework/ldap/core/LdapTemplate","findOne","*;","LDAP","SPRING-LDAP","-1","1"}, 14 | {"INVOKEVIRTUAL","org/springframework/ldap/core/LdapTemplate","search","*;","LDAP","SPRING-LDAP","-1","1"}, 15 | {"INVOKEVIRTUAL","org/springframework/ldap/core/LdapTemplate","searchForContext","*;","LDAP","SPRING-LDAP","-1","1"}, 16 | {"INVOKEVIRTUAL","org/springframework/ldap/core/LdapTemplate","searchForObject","*;","LDAP","SPRING-LDAP","-1","1"}, 17 | {"INVOKEVIRTUAL","org/springframework/ldap/core/LdapTemplate","authenticate","*;","LDAP","SPRING-LDAP","-1","1"}, 18 | }; 19 | public static String[][] getRules(){ 20 | return rules; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/asm/MethodCallClassVisitor.java: -------------------------------------------------------------------------------- 1 | package asm; 2 | 3 | import model.MethodReference; 4 | import org.objectweb.asm.ClassVisitor; 5 | import org.objectweb.asm.MethodVisitor; 6 | import org.objectweb.asm.commons.JSRInlinerAdapter; 7 | 8 | import java.util.Map; 9 | import java.util.Set; 10 | 11 | public class MethodCallClassVisitor extends ClassVisitor { 12 | private String ClassName; 13 | private final Map> methodCall; 14 | 15 | public MethodCallClassVisitor(int api, Map> methodCall) { 16 | super(api); 17 | this.methodCall = methodCall; 18 | } 19 | 20 | @Override 21 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { 22 | if (this.ClassName != null) { 23 | throw new IllegalStateException("ClassVisitor already visited a class!"); 24 | } 25 | this.ClassName = name; 26 | } 27 | 28 | @Override 29 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { 30 | MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); 31 | //在visit每个method的时候,创建MethodVisitor对method进行观察 32 | MethodCallAdapter MethodCallAdapter = new MethodCallAdapter( 33 | api, mv, methodCall,ClassName,name,descriptor); 34 | return new JSRInlinerAdapter(MethodCallAdapter, access, name, descriptor, signature, exceptions); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/asm/VulnMethodAdapter.java: -------------------------------------------------------------------------------- 1 | package asm; 2 | 3 | import asm.jvmasm.JvmMethodAdapter; 4 | import model.InheritanceMap; 5 | import model.MethodReference; 6 | import model.Sink; 7 | import org.objectweb.asm.MethodVisitor; 8 | import org.objectweb.asm.Opcodes; 9 | import org.objectweb.asm.Type; 10 | 11 | import java.util.HashSet; 12 | import java.util.List; 13 | import java.util.Map; 14 | import java.util.Set; 15 | 16 | public class VulnMethodAdapter extends MethodVisitor { 17 | private final List sinks; 18 | private int flag=0;//这个flag主要是为了多个sink的时候记录是否有污点时候弄的 19 | private int need; 20 | public VulnMethodAdapter(List sinks, int api) { 21 | super(api); 22 | this.sinks = sinks; 23 | this.need = sinks.size(); 24 | } 25 | 26 | @Override 27 | public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { 28 | if(flag!=need&&isSink(sinks,owner,name,desc,flag)){ 29 | this.flag = flag+1; 30 | } 31 | super.visitMethodInsn(opcode, owner, name, desc, itf); 32 | } 33 | 34 | 35 | public int getVulnFlag() { 36 | return flag; 37 | } 38 | 39 | public boolean isSink(List sinks,String owner, String name, String desc,int flag){ 40 | if(sinks.get(flag).getName().equals(name)&&sinks.get(flag).getClassName().equals(owner)&& 41 | (sinks.get(flag).getDesc().equals(desc)||sinks.get(flag).getDesc().equals("*"))) 42 | { 43 | return true; 44 | } 45 | return false; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/jvm/OperandStack.java: -------------------------------------------------------------------------------- 1 | package jvm; 2 | 3 | import java.util.HashSet; 4 | import java.util.LinkedList; 5 | import java.util.List; 6 | import java.util.Set; 7 | 8 | public class OperandStack { 9 | private final LinkedList> stack; 10 | 11 | public OperandStack() { 12 | this.stack = new LinkedList<>(); 13 | } 14 | public Set pop() { 15 | return stack.remove(stack.size() - 1); 16 | } 17 | 18 | public void push(T t) { 19 | Set set = new HashSet<>(); 20 | set.add(t); 21 | stack.add(set); 22 | } 23 | 24 | public void push() { 25 | stack.add(new HashSet<>()); 26 | } 27 | 28 | public void push(Set t) { 29 | stack.add(t); 30 | } 31 | 32 | public void clear() { 33 | stack.clear(); 34 | } 35 | 36 | public Set get(int index) { 37 | return stack.get(stack.size() - index - 1); 38 | } 39 | 40 | public void set(int index, Set t) { 41 | stack.set(stack.size() - index - 1, t); 42 | } 43 | 44 | public void set(int index, T t) { 45 | Set set = new HashSet<>(); 46 | set.add(t); 47 | stack.set(stack.size() - index - 1, set); 48 | } 49 | 50 | public void add(Set t) { 51 | this.stack.add(t); 52 | } 53 | 54 | public int size() { 55 | return this.stack.size(); 56 | } 57 | 58 | public void remove(int index) { 59 | this.stack.remove(index); 60 | } 61 | 62 | public List> getList() { 63 | return this.stack; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/rules/SQLinjectionConstant.java: -------------------------------------------------------------------------------- 1 | package rules; 2 | 3 | public class SQLinjectionConstant { 4 | private static final String[][] rules = new String[][]{ 5 | {"INVOKEVIRTUAL","org/springframework/jdbc/core/JdbcTemplate","update","*","sqlinjection","JdbcTemplate-SQL","-1","1"}, 6 | {"INVOKEVIRTUAL","org/springframework/jdbc/core/JdbcTemplate","execute","*","sqlinjection","JdbcTemplate-SQL","-1","1"}, 7 | {"INVOKEVIRTUAL","org/springframework/jdbc/core/JdbcTemplate","query","*","sqlinjection","JdbcTemplate-SQL","-1","1"}, 8 | {"INVOKEVIRTUAL","org/springframework/jdbc/core/JdbcTemplate","queryForStream","*","sqlinjection","JdbcTemplate-SQL","-1","1"}, 9 | {"INVOKEVIRTUAL","org/springframework/jdbc/core/JdbcTemplate","queryForList","*","sqlinjection","JdbcTemplate-SQL","-1","1"}, 10 | {"INVOKEVIRTUAL","org/springframework/jdbc/core/JdbcTemplate","queryForMap","*","sqlinjection","JdbcTemplate-SQL","-1","1"}, 11 | {"INVOKEVIRTUAL","org/springframework/jdbc/core/JdbcTemplate","queryForObject","*","sqlinjection","JdbcTemplate-SQL","-1","1"}, 12 | 13 | {"INVOKEVIRTUAL","java/sql/Statement","executeQuery","*","sqlinjection","Statement-SQL","-1","1"}, 14 | {"INVOKEVIRTUAL","java/sql/Statement","execute","*","sqlinjection","Statement-SQL","-1","1"}, 15 | {"INVOKEVIRTUAL","java/sql/Statement","executeUpdate","*","sqlinjection","Statement-SQL","-1","1"}, 16 | 17 | {"INVOKEVIRTUAL","com/mongodb/BasicDBObject","parse","*","sqlinjection","Statement-SQL","-1","1"}, 18 | }; 19 | public static String[][] getRules(){ 20 | return rules; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/Util/ClassUtil.java: -------------------------------------------------------------------------------- 1 | package Util; 2 | 3 | import javassist.bytecode.stackmap.TypeData; 4 | import model.ClassFile; 5 | 6 | import java.io.File; 7 | import java.nio.file.Files; 8 | import java.nio.file.Path; 9 | import java.nio.file.Paths; 10 | import java.util.*; 11 | 12 | public class ClassUtil { 13 | public static List getAllClassesFromBoots(List bootPathList, 14 | boolean runtime, 15 | boolean useAllLib, Map jarByClass) { 16 | Set classFileSet = new HashSet<>(); 17 | if (runtime) { 18 | getRuntime(classFileSet); 19 | } 20 | for (String jarPath : bootPathList) { 21 | JarUtil JarUtil = new JarUtil(); 22 | List jarclassist = JarUtil.resolveSpringBootJarFile(jarPath, useAllLib); 23 | String jarName = jarPath; 24 | for(ClassFile classFile:jarclassist){ 25 | jarByClass.put(classFile.getClassName().split("\\.")[0],jarName); 26 | } 27 | classFileSet.addAll(jarclassist); 28 | } 29 | return new ArrayList<>(classFileSet); 30 | } 31 | private static void getRuntime(Set classFileSet) { 32 | String rtJarPath = System.getenv("JAVA_HOME") + 33 | File.separator + "jre" + 34 | File.separator + "lib" + 35 | File.separator + "rt.jar"; 36 | Path rtPath = Paths.get(rtJarPath); 37 | if (!Files.exists(rtPath)) { 38 | throw new RuntimeException("rt.jar not exists"); 39 | } 40 | JarUtil JarUtil = new JarUtil(); 41 | classFileSet.addAll(JarUtil.resolveNormalJarFile(rtJarPath)); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/Service/DiscoverService.java: -------------------------------------------------------------------------------- 1 | package Service; 2 | 3 | import asm.DiscoveryClassVisitor; 4 | import model.ClassFile; 5 | import model.ClassReference; 6 | import model.MethodReference; 7 | import org.objectweb.asm.ClassReader; 8 | 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | public class DiscoverService { 13 | public static void start(List classFileList, List discoveredClasses, 14 | List discoveredMethods, Map classMap, 15 | Map methodMap, Map classFileByName) { 16 | for (ClassFile file : classFileList) { 17 | try { 18 | DiscoveryClassVisitor dcv = new DiscoveryClassVisitor(discoveredClasses, discoveredMethods); 19 | ClassReader cr = new ClassReader(file.getFile()); 20 | cr.accept(dcv, ClassReader.EXPAND_FRAMES); 21 | classFileByName.put(dcv.getName(), file); 22 | } catch (Exception e) { 23 | e.printStackTrace(); 24 | } 25 | } 26 | for (ClassReference clazz : discoveredClasses) { 27 | classMap.put(clazz.getHandle(), clazz); 28 | } 29 | for (MethodReference method : discoveredMethods) { 30 | methodMap.put(method.getHandle(), method); 31 | } 32 | } 33 | 34 | 35 | public static void start(List classFileList,String methodName) { 36 | for (ClassFile file : classFileList) { 37 | try { 38 | DiscoveryClassVisitor dcv = new DiscoveryClassVisitor(methodName); 39 | ClassReader cr = new ClassReader(file.getFile()); 40 | cr.accept(dcv, ClassReader.EXPAND_FRAMES); 41 | } catch (Exception e) { 42 | e.printStackTrace(); 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/framework/SinkClassVisitor.java: -------------------------------------------------------------------------------- 1 | package framework; 2 | 3 | import model.ClassReference; 4 | import model.MethodReference; 5 | import org.objectweb.asm.ClassVisitor; 6 | import org.objectweb.asm.MethodVisitor; 7 | import org.objectweb.asm.Opcodes; 8 | 9 | import java.util.List; 10 | import java.util.regex.Pattern; 11 | 12 | public class SinkClassVisitor extends ClassVisitor { 13 | private String ClassName; 14 | private ClassReference.Handle classHandle; 15 | private List Sources; 16 | 17 | public SinkClassVisitor(List Sources) { 18 | super(Opcodes.ASM6); 19 | this.Sources = Sources; 20 | } 21 | 22 | @Override 23 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { 24 | if (this.ClassName != null) { 25 | throw new IllegalStateException("ClassVisitor already visited a class!"); 26 | } 27 | this.classHandle = new ClassReference.Handle(name); 28 | } 29 | 30 | @Override 31 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { 32 | if(MethodNameIsMatch(name)){ 33 | System.out.println(name); 34 | boolean isStatic = (access & Opcodes.ACC_STATIC) != 0; 35 | boolean isAbstract = (access & Opcodes.ACC_ABSTRACT) !=0; 36 | Sources.add(new MethodReference( 37 | classHandle, 38 | name, 39 | descriptor, 40 | isStatic, 41 | isAbstract)); 42 | } 43 | return super.visitMethod(access, name, descriptor, signature, exceptions); 44 | } 45 | 46 | public boolean MethodNameIsMatch(String MethodName){ 47 | //String pattern = "^do[A-Z].*"; 48 | String pattern = "doInterpolate"; 49 | boolean isMatch = Pattern.matches(pattern, MethodName); 50 | return isMatch; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/model/InheritanceMap.java: -------------------------------------------------------------------------------- 1 | package model; 2 | 3 | import java.util.*; 4 | 5 | import model.ClassReference; 6 | 7 | public class InheritanceMap { 8 | //子-父关系集合 9 | private final Map> inheritanceMap; 10 | //父-子关系集合 11 | private final Map> subClassMap; 12 | 13 | public InheritanceMap(Map> inheritanceMap){ 14 | this.inheritanceMap = inheritanceMap; 15 | subClassMap = new HashMap<>(); 16 | for(Map.Entry> entry : inheritanceMap.entrySet()){ 17 | ClassReference.Handle child = entry.getKey(); 18 | for (ClassReference.Handle parent : entry.getValue()) { 19 | subClassMap.computeIfAbsent(parent, k -> new HashSet<>()).add(child); //computeIfAbsent 如果不存在key就将值添加进去 20 | } 21 | } 22 | } 23 | 24 | public Set>> entrySet() { 25 | return inheritanceMap.entrySet(); 26 | } 27 | 28 | public Set getSuperClasses(ClassReference.Handle clazz) { 29 | Set parents = inheritanceMap.get(clazz); 30 | if (parents == null) { 31 | return null; 32 | } 33 | return Collections.unmodifiableSet(parents); //unmodifiableSet() 用于获取指定集合的不可修改视图。 34 | } 35 | 36 | public boolean isSubclassOf(ClassReference.Handle clazz, ClassReference.Handle superClass) { 37 | Set parents = inheritanceMap.get(clazz); 38 | if (parents == null) { 39 | return false; 40 | } 41 | return parents.contains(superClass); 42 | } 43 | 44 | public Set getSubClasses(ClassReference.Handle clazz) { 45 | Set subClasses = subClassMap.get(clazz); 46 | if (subClasses == null) { 47 | return null; 48 | } 49 | return Collections.unmodifiableSet(subClasses); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/asm/VulnClassVisitor.java: -------------------------------------------------------------------------------- 1 | package asm; 2 | 3 | import model.InheritanceMap; 4 | import model.MethodReference; 5 | import model.Sink; 6 | import org.objectweb.asm.ClassVisitor; 7 | import org.objectweb.asm.MethodVisitor; 8 | import org.objectweb.asm.Opcodes; 9 | import org.objectweb.asm.commons.JSRInlinerAdapter; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import java.util.Map; 14 | import java.util.Set; 15 | 16 | public class VulnClassVisitor extends ClassVisitor { 17 | 18 | private String name; 19 | private MethodReference.Handle methodHandle; 20 | private final List sinks; 21 | 22 | 23 | private VulnMethodAdapter vulnMethodAdapter; 24 | 25 | public VulnClassVisitor(MethodReference.Handle callerMethod,List sinks) { 26 | super(Opcodes.ASM7); 27 | this.methodHandle = callerMethod; 28 | this.sinks = sinks; 29 | } 30 | 31 | @Override 32 | public void visit(int version, int access, String name, String signature, 33 | String superName, String[] interfaces) { 34 | super.visit(version, access, name, signature, superName, interfaces); 35 | this.name = name; 36 | } 37 | 38 | @Override 39 | public MethodVisitor visitMethod(int access, String name, String descriptor, 40 | String signature, String[] exceptions) { 41 | MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); 42 | if (name.equals(this.methodHandle.getName())) { 43 | VulnMethodAdapter vulnMethodAdapter = new VulnMethodAdapter( 44 | this.sinks,Opcodes.ASM6 45 | ); 46 | this.vulnMethodAdapter = vulnMethodAdapter; 47 | return new JSRInlinerAdapter(vulnMethodAdapter, 48 | access, name, descriptor, signature, exceptions); 49 | } 50 | return mv; 51 | } 52 | 53 | public Integer getVulnFlag() { 54 | if (vulnMethodAdapter == null) { 55 | return null; 56 | } 57 | return vulnMethodAdapter.getVulnFlag(); 58 | } 59 | } -------------------------------------------------------------------------------- /src/main/java/rules/SSRFconstant.java: -------------------------------------------------------------------------------- 1 | package rules; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | import java.util.Set; 7 | 8 | public class SSRFconstant{ 9 | private static final String[][] rules = new String[][]{ 10 | //{"INVOKEVIRTUAL","java/net/URL","","(Ljava/lang/String;)V","SSRF","JDKSSRF"}, 11 | {"INVOKEVIRTUAL","java/net/URL","openConnection","()Ljava/net/URLConnection;","SSRF","JDKSSRF","-1","1"}, 12 | //{"INVOKEVIRTUAL","java/net/HttpURLConnection","getInputStream","()Ljava/io/InputStream;","SSRF","JDKSSRF"}, 13 | 14 | //{"INVOKEVIRTUAL","org/apache/http/client/methods/HttpGet","","(Ljava/lang/String;)V","SSRF","APACHE-SSRF"}, 15 | {"INVOKEVIRTUAL","org/apache/http/impl/client/CloseableHttpClient","execute","(Lorg/apache/http/client/methods/HttpUriRequest;)Lorg/apache/http/client/methods/CloseableHttpResponse;","SSRF","APACHE-SSRF","-1","1"}, 16 | {"INVOKEVIRTUAL","org/apache/http/impl/nio/client/CloseableHttpAsyncClient","execute","(Lorg/apache/http/client/methods/HttpUriRequest;)Lorg/apache/http/client/methods/CloseableHttpResponse;","SSRF","APACHE-SSRF","-1","1"}, 17 | 18 | //{"INVOKEVIRTUAL","java/net/Socket","","(Ljava/lang/String;I)V","SSRF","SOCKETSSRF"}, 19 | //{"INVOKEVIRTUAL","java/net/Socket","getInputStream","*","SSRF","SOCKETSSRF"}, 20 | //{"INVOKEVIRTUAL","java/net/Socket","getOutputStream","*","SSRF","SOCKETSSRF"}, 21 | 22 | {"INVOKEVIRTUAL","okhttp3/Request$Builder","build","()Lokhttp3/Request;","SSRF","OKHHTPSSRF","-1","2"}, 23 | {"INVOKEVIRTUAL","okhttp3/Call","execute","()Lokhttp3/Response;","SSRF","OKHHTPSSRF","-1","2"}, 24 | {"INVOKEVIRTUAL","okhttp/Request$Builder","build","()Lokhttp/Request;","SSRF","OKHHTPSSRF","-1","2"}, 25 | {"INVOKEVIRTUAL","okhttp/Call","execute","()Lokhttp/Response;","SSRF","OKHHTPSSRF","-1","2"} 26 | //{"INVOKEVIRTUAL","okhttp3/OkHttpClient","newCall","(Lokhttp3/Request;)Lokhttp3/Call;","SSRF","OKHHTPSSRF","-1","1"}, 27 | //{"INVOKEVIRTUAL","okhttp/OkHttpClient","newCall","(Lokhttp/Request;)Lokhttp/Call;","SSRF","OKHHTPSSRF","-1","1"}, 28 | }; 29 | public static String[][] getRules(){ 30 | return rules; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /html/graph.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Network | Hierarchical layout difference 5 | 6 | 7 | 8 | 9 | 10 | 52 | 53 | 54 | 55 | Layout method: 56 |
60 |
61 |

62 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /src/main/java/asm/CallGraphClassVisitor.java: -------------------------------------------------------------------------------- 1 | package asm; 2 | 3 | import model.CallGraph; 4 | import model.ClassReference; 5 | import model.InheritanceMap; 6 | import model.MethodReference; 7 | import org.objectweb.asm.ClassVisitor; 8 | import org.objectweb.asm.MethodVisitor; 9 | import org.objectweb.asm.Opcodes; 10 | import org.objectweb.asm.commons.JSRInlinerAdapter; 11 | 12 | import java.util.Map; 13 | import java.util.Set; 14 | 15 | public class CallGraphClassVisitor extends ClassVisitor { 16 | private final Set discoveredCalls; 17 | private final Map classMap; 18 | private final InheritanceMap inheritanceMap; 19 | private final Map> passthroughDataflow; 20 | private String name; 21 | 22 | public CallGraphClassVisitor(Map classMap, 23 | InheritanceMap inheritanceMap, 24 | Map> passthroughDataflow, 25 | Set discoveredCalls) { 26 | super(Opcodes.ASM7); 27 | this.classMap = classMap; 28 | this.inheritanceMap = inheritanceMap; 29 | this.passthroughDataflow = passthroughDataflow; 30 | this.discoveredCalls = discoveredCalls; 31 | } 32 | 33 | @Override 34 | public void visit(int version, int access, String name, String signature, 35 | String superName, String[] interfaces) { 36 | super.visit(version, access, name, signature, superName, interfaces); 37 | this.name = name; 38 | } 39 | 40 | @Override 41 | public MethodVisitor visitMethod(int access, String name, String desc, 42 | String signature, String[] exceptions) { 43 | MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); 44 | CallGraphMethodAdapter callGraphMethodVisitor = new CallGraphMethodAdapter(classMap, 45 | inheritanceMap, passthroughDataflow,api, discoveredCalls, 46 | mv, this.name, access, name, desc); 47 | return new JSRInlinerAdapter(callGraphMethodVisitor, access, name, desc, signature, exceptions); 48 | } 49 | 50 | @Override 51 | public void visitEnd() { 52 | super.visitEnd(); 53 | } 54 | } 55 | 56 | -------------------------------------------------------------------------------- /src/main/java/Service/DarwService.java: -------------------------------------------------------------------------------- 1 | package Service; 2 | 3 | import model.MethodReference; 4 | 5 | import java.io.BufferedWriter; 6 | import java.io.File; 7 | import java.io.FileWriter; 8 | import java.io.IOException; 9 | import java.util.*; 10 | 11 | public class DarwService { 12 | 13 | private int flag =0; 14 | 15 | private MethodReference.Handle qianji; 16 | 17 | public static void start(List> stacks) throws IOException { 18 | File file = new File("html/data.js"); 19 | DarwService DarwService = new DarwService(); 20 | DarwService.display(file,stacks); 21 | } 22 | 23 | public void display(File file, List> stacks) throws IOException { 24 | 25 | String path = file.getAbsolutePath(); 26 | file.delete(); 27 | BufferedWriter nfile = new BufferedWriter(new FileWriter(path, true)); 28 | nfile.write("var nodes = [];\n"); 29 | nfile.write("var edges = [];\n"); 30 | 31 | // 2 loops because all nodes must declared before be used in edges 32 | ArrayList idList = new ArrayList(); 33 | for ( Deque stack: stacks){ 34 | for(MethodReference.Handle method : stack){ 35 | if(!idList.contains(method.hashCode())){ 36 | idList.add(method.hashCode()); 37 | nfile.write("nodes.push({ id: " + method.hashCode()+ ", label: String(\"" + method.getName() + "\"), title: String(\"" + method.getClassReference().getName() + "\") });\n"); 38 | } 39 | } 40 | } 41 | 42 | ArrayList idList2 = new ArrayList(); 43 | for ( Deque stack: stacks){ 44 | this.flag =0; 45 | for(MethodReference.Handle method : stack){ 46 | if(this.flag ==0){ 47 | this.qianji = method; 48 | this.flag = 1; 49 | } else if(!idList2.contains(qianji.hashCode()+method.hashCode())){ 50 | idList2.add(qianji.hashCode()+method.hashCode()); 51 | nfile.write("edges.push({ from: " + method.hashCode()+ ", to: " + this.qianji.hashCode()+ " });\n"); 52 | this.qianji =method; 53 | } 54 | } 55 | } 56 | nfile.close(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/model/CallGraph.java: -------------------------------------------------------------------------------- 1 | package model; 2 | 3 | import java.io.Serializable; 4 | import java.util.Objects; 5 | 6 | public class CallGraph implements Serializable { 7 | private final MethodReference.Handle callerMethod; 8 | private final MethodReference.Handle targetMethod; 9 | private final int callerArgIndex; 10 | private final int targetArgIndex; 11 | 12 | public CallGraph(MethodReference.Handle callerMethod, MethodReference.Handle targetMethod, 13 | int callerArgIndex, int targetArgIndex) { 14 | this.callerMethod = callerMethod; 15 | this.targetMethod = targetMethod; 16 | this.callerArgIndex = callerArgIndex; 17 | this.targetArgIndex = targetArgIndex; 18 | } 19 | 20 | public CallGraph(MethodReference.Handle callerMethod, MethodReference.Handle targetMethod) { 21 | this.callerMethod = callerMethod; 22 | this.targetMethod = targetMethod; 23 | this.callerArgIndex = -1; 24 | this.targetArgIndex = -1; 25 | } 26 | 27 | public MethodReference.Handle getCallerMethod() { 28 | return callerMethod; 29 | } 30 | 31 | public MethodReference.Handle getTargetMethod() { 32 | return targetMethod; 33 | } 34 | 35 | public int getCallerArgIndex() { 36 | return callerArgIndex; 37 | } 38 | 39 | public int getTargetArgIndex() { 40 | return targetArgIndex; 41 | } 42 | 43 | @Override 44 | public boolean equals(Object o) { 45 | if (this == o) return true; 46 | if (o == null || getClass() != o.getClass()) return false; 47 | 48 | CallGraph CallGraph = (CallGraph) o; 49 | 50 | if (callerArgIndex != CallGraph.callerArgIndex) return false; 51 | if (targetArgIndex != CallGraph.targetArgIndex) return false; 52 | if (!Objects.equals(callerMethod, CallGraph.callerMethod)) 53 | return false; 54 | if (!Objects.equals(targetMethod, CallGraph.targetMethod)){ 55 | return false; 56 | }else{ 57 | return true; 58 | } 59 | } 60 | 61 | @Override 62 | public int hashCode() { 63 | int result = callerMethod != null ? callerMethod.hashCode() : 0; 64 | result = 31 * result + (targetMethod != null ? targetMethod.hashCode() : 0); 65 | result = 31 * result + callerArgIndex; 66 | result = 31 * result + targetArgIndex; 67 | return result; 68 | } 69 | } -------------------------------------------------------------------------------- /src/main/java/rules/JNDIConstant.java: -------------------------------------------------------------------------------- 1 | package rules; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class JNDIConstant { 7 | private static final String[][] rules = new String[][]{ 8 | {"INVOKEVIRTUAL","javax/naming/Context","lookup","(Ljava/lang/String;)Ljava/lang/Object;","JNDI","JAVAX-JNDI","-1","1"}, 9 | //{"INVOKEVIRTUAL","javax/naming/Context","lookupLink","*","JNDI","JAVAX-JNDI","-1","1"}, 10 | //{"INVOKEVIRTUAL","javax/naming/Context","list","*","JNDI","JAVAX-JNDI","-1","1"}, 11 | //{"INVOKEVIRTUAL","javax/naming/Context","listBindings","*","JNDI","JAVAX-JNDI","-1","1"}, 12 | {"INVOKEVIRTUAL","javax/naming/InitialContext","doLookup","*","JNDI","JAVAX-JNDI","-1","1"}, 13 | {"INVOKEVIRTUAL","javax/naming/InitialContext","lookup","*","JNDI","JAVAX-JNDI","1","1"}, 14 | {"INVOKEVIRTUAL","javax/naming/InitialContext","","*","JNDI","JAVAX-JNDI","1","1"}, 15 | {"INVOKEVIRTUAL","javax/management/remote/JMXConnector","connect","*","JNDI","JAVAX-JNDI","-1","1"}, 16 | {"INVOKEVIRTUAL","javax/management/remote/JMXConnectorFactory","connect","*","JNDI","JAVAX-JNDI","-1","1"}, 17 | //{"INVOKEVIRTUAL","javax/naming/Context","list","*","JNDI","JAVAX-JNDI","-1","1"}, 18 | {"INVOKEVIRTUAL","org/springframework/jndi/JndiTemplate","lookup","*","JNDI","SPRING-JNDI","-1","1"}, 19 | {"INVOKEVIRTUAL","org/springframework/ldap/core/LdapOperations","lookup","*","JNDI","SPRING-JNDI","-1","1"}, 20 | {"INVOKEVIRTUAL","org/springframework/ldap/core/LdapOperations","findByDn","*","JNDI","SPRING-JNDI","-1","1"}, 21 | {"INVOKEVIRTUAL","org/springframework/ldap/core/LdapOperations","rename","*","JNDI","SPRING-JNDI","-1","1"}, 22 | //{"INVOKEVIRTUAL","org/springframework/ldap/core/LdapOperations","list","*","JNDI","SPRING-JNDI","-1","1"}, 23 | //{"INVOKEVIRTUAL","org/springframework/ldap/core/LdapOperations","listBindings","*","JNDI","SPRING-JNDI","-1","1"}, 24 | {"INVOKEVIRTUAL","org/springframework/ldap/core/LdapOperations","search","*","JNDI","SPRING-JNDI","-1","1"}, 25 | {"INVOKEVIRTUAL","org/springframework/ldap/core/LdapOperations","searchForObject","*","JNDI","SPRING-JNDI","-1","1"}, 26 | {"INVOKEVIRTUAL","org/apache/shiro/jndi/JndiTemplate","lookup","*","JNDI","JAVAX-RCE","-1","1"} 27 | }; 28 | public static String[][] getRules(){ 29 | return rules; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/rules/XXEconstant.java: -------------------------------------------------------------------------------- 1 | package rules; 2 | 3 | public class XXEconstant { 4 | 5 | private static final String[][] rules = new String[][]{ 6 | {"INVOKEVIRTUAL","javax/xml/parsers/SAXParser","parse","*","XXE","SAX-PARSER-XXE","-1","1"}, 7 | {"INVOKEVIRTUAL","org/xml/sax/XMLReader","parse","*","XXE","XML-READER-XXE","-1","1"}, 8 | {"INVOKEVIRTUAL","org/dom4j/io/SAXReader","read","*","XXE","SAX-READER-XXE","-1","1"}, 9 | {"INVOKEVIRTUAL","javax/xml/parsers/DocumentBuilder","parse","*","XXE","Document-Builder-XXE","-1","1"}, 10 | {"INVOKEVIRTUAL","javax/xml/bind/Unmarshaller","unmarshal","*","XXE","UNMARSHALLER","-1","1"}, 11 | {"INVOKEVIRTUAL","javax/xml/stream/XMLInputFactory","createXMLStreamReader","*","XXE","XMLInput-XXE","-1","1"}, 12 | {"INVOKEVIRTUAL","javax/xml/xpath/XPathExpression","evaluate","*","XXE","XPathExpression","-1","1"}, 13 | {"INVOKEVIRTUAL","org/simpleframework/xml/core/Persister","read","*","XXE","SIMPLE-XXE","-1","1"}, 14 | {"INVOKEVIRTUAL","org/simpleframework/xml/stream/Formatter","format","*","XXE","SIMPLE-XXE","-1","1"}, 15 | {"INVOKEVIRTUAL","org/simpleframework/xml/core/Persister","validate","*","XXE","SIMPLE-XXE","-1","1"}, 16 | {"INVOKEVIRTUAL","org/simpleframework/xml/stream/StreamProvider","provide","*","XXE","SIMPLE-XXE","-1","1"}, 17 | {"INVOKEVIRTUAL","org/simpleframework/xml/stream/DocumentProvider","provide","*","XXE","SIMPLE-XXE","-1","1"}, 18 | {"INVOKEVIRTUAL","javax/xml/stream/XMLInputFactory","createXMLEventReader","*","XXE","XMLInput-XXE","-1","1"}, 19 | {"INVOKEVIRTUAL","org/jdom/input/SAXBuilder","build","*","XXE","SAXBuilder-XXE","-1","1"}, 20 | {"INVOKEVIRTUAL","org/jdom2/input/SAXBuilder","build","*","XXE","SAXBuilder-XXE","-1","1"}, 21 | 22 | {"INVOKEVIRTUAL","javax/xml/transform/TransformerFactory","newTransformer","*","XXE","Transform-XXE","-1","1"}, 23 | {"INVOKEVIRTUAL","javax/xml/transform/Transformer","transform","*","XXE","SAXBuilder-XXE","-1","1"}, 24 | {"INVOKEVIRTUAL","javax/xml/transform/sax/SAXTransformerFactory","newXMLFilter","*","XXE","SAX-PARSER-XXE","-1","1"}, 25 | {"INVOKEVIRTUAL","javax/xml/transform/sax/SAXTransformerFactory","newTransformer","*","XXE","SAX-PARSER-XXE","-1","1"}, 26 | {"INVOKEVIRTUAL","javax/xml/validation/SchemaFactory","newSchema","*","XXE","Schema-XXE","-1","1"} 27 | }; 28 | 29 | public static String[][] getRules(){ 30 | return rules; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /html/data.js: -------------------------------------------------------------------------------- 1 | var nodes = []; 2 | var edges = []; 3 | nodes.push({ id: -1592429837, label: String("getEngineByName"), title: String("-1592429837") }); 4 | nodes.push({ id: 668052877, label: String("lookup"), title: String("668052877") }); 5 | nodes.push({ id: -1145887774, label: String("lookup"), title: String("-1145887774") }); 6 | nodes.push({ id: -2112549658, label: String("resolveVariable"), title: String("-2112549658") }); 7 | nodes.push({ id: -1760632522, label: String("substitute"), title: String("-1760632522") }); 8 | nodes.push({ id: -1169671082, label: String("substitute"), title: String("-1169671082") }); 9 | nodes.push({ id: -1888320187, label: String("replace"), title: String("-1888320187") }); 10 | nodes.push({ id: -307768002, label: String("lookup"), title: String("-307768002") }); 11 | nodes.push({ id: -85657648, label: String("lookup"), title: String("-85657648") }); 12 | nodes.push({ id: 112939707, label: String("lookup"), title: String("112939707") }); 13 | nodes.push({ id: -112346020, label: String("resolve"), title: String("-112346020") }); 14 | nodes.push({ id: 1096944344, label: String("resolveSingleVariable"), title: String("1096944344") }); 15 | nodes.push({ id: 184559637, label: String("interpolate"), title: String("184559637") }); 16 | nodes.push({ id: 1609648354, label: String("doInterpolate"), title: String("1609648354") }); 17 | nodes.push({ id: 1516056989, label: String("lookup"), title: String("1516056989") }); 18 | nodes.push({ id: 2057800149, label: String("lookup"), title: String("2057800149") }); 19 | edges.push({ from: 668052877, to: -1592429837 }); 20 | edges.push({ from: -1145887774, to: 668052877 }); 21 | edges.push({ from: -2112549658, to: -1145887774 }); 22 | edges.push({ from: -1760632522, to: -2112549658 }); 23 | edges.push({ from: -1169671082, to: -1760632522 }); 24 | edges.push({ from: -1888320187, to: -1169671082 }); 25 | edges.push({ from: -307768002, to: -1888320187 }); 26 | edges.push({ from: -85657648, to: -307768002 }); 27 | edges.push({ from: 112939707, to: -85657648 }); 28 | edges.push({ from: -112346020, to: 112939707 }); 29 | edges.push({ from: 1096944344, to: -112346020 }); 30 | edges.push({ from: 184559637, to: 1096944344 }); 31 | edges.push({ from: 1609648354, to: 184559637 }); 32 | edges.push({ from: -1145887774, to: -1592429837 }); 33 | edges.push({ from: 1516056989, to: -1145887774 }); 34 | edges.push({ from: 112939707, to: 1516056989 }); 35 | edges.push({ from: 1096944344, to: 112939707 }); 36 | edges.push({ from: 1609648354, to: 1096944344 }); 37 | edges.push({ from: 2057800149, to: -1592429837 }); 38 | edges.push({ from: 112939707, to: 2057800149 }); 39 | edges.push({ from: 184559637, to: 112939707 }); 40 | edges.push({ from: -2112549658, to: -1592429837 }); 41 | edges.push({ from: -1169671082, to: -2112549658 }); 42 | edges.push({ from: 184559637, to: -1169671082 }); 43 | -------------------------------------------------------------------------------- /src/main/java/asm/SourceClassVisitor.java: -------------------------------------------------------------------------------- 1 | package asm; 2 | 3 | import model.ClassReference; 4 | import model.MethodReference; 5 | import org.objectweb.asm.ClassVisitor; 6 | import org.objectweb.asm.MethodVisitor; 7 | import org.objectweb.asm.Opcodes; 8 | 9 | import java.util.List; 10 | import java.util.regex.Pattern; 11 | 12 | public class SourceClassVisitor extends ClassVisitor { 13 | private ClassReference.Handle classHandle; 14 | private List Sources; 15 | private String sourcePattern; 16 | 17 | 18 | public SourceClassVisitor(List Sources,String sourcePattern) { 19 | super(Opcodes.ASM7); 20 | this.Sources = Sources; 21 | this.sourcePattern = sourcePattern; 22 | } 23 | public SourceClassVisitor(List Sources) { 24 | super(Opcodes.ASM7); 25 | this.Sources = Sources; 26 | } 27 | @Override 28 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { 29 | this.classHandle = new ClassReference.Handle(name); 30 | } 31 | 32 | @Override 33 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { 34 | if(sourcePattern==null){ 35 | if (MethodNameIsMatch(name)) { 36 | boolean isStatic = (access & Opcodes.ACC_STATIC) != 0; 37 | boolean isAbstract = (access & Opcodes.ACC_ABSTRACT) != 0; 38 | Sources.add(new MethodReference( 39 | classHandle, 40 | name, 41 | descriptor, 42 | isStatic, 43 | isAbstract)); 44 | } 45 | }else { 46 | if (MethodNameIsMatch(this.sourcePattern,name)) { 47 | boolean isStatic = (access & Opcodes.ACC_STATIC) != 0; 48 | boolean isAbstract = (access & Opcodes.ACC_ABSTRACT) != 0; 49 | Sources.add(new MethodReference( 50 | classHandle, 51 | name, 52 | descriptor, 53 | isStatic, 54 | isAbstract)); 55 | } 56 | } 57 | 58 | return super.visitMethod(access, name, descriptor, signature, exceptions); 59 | } 60 | 61 | public boolean MethodNameIsMatch(String MethodName) { 62 | String pattern = "^do[A-Z].*"; 63 | boolean isMatch = Pattern.matches(pattern, MethodName); 64 | return isMatch; 65 | } 66 | 67 | public boolean MethodNameIsMatch(String sourcePattern,String MethodName) { 68 | boolean isMatch = Pattern.matches(sourcePattern, MethodName); 69 | return isMatch; 70 | } 71 | } -------------------------------------------------------------------------------- /src/main/java/asm/PassthroughClassVisitor.java: -------------------------------------------------------------------------------- 1 | package asm; 2 | 3 | import model.ClassReference; 4 | import model.InheritanceMap; 5 | import model.MethodReference; 6 | import org.objectweb.asm.ClassVisitor; 7 | import org.objectweb.asm.MethodVisitor; 8 | import org.objectweb.asm.commons.JSRInlinerAdapter; 9 | 10 | import java.util.Map; 11 | import java.util.Set; 12 | 13 | public class PassthroughClassVisitor extends ClassVisitor { 14 | private final Map classMap; 15 | private final InheritanceMap inheritanceMap; 16 | private final MethodReference.Handle methodToVisit; 17 | private final Map> passthroughDataflow; 18 | private String name; 19 | private PassthroughMethodAdapter PassthroughMethodAdapter; 20 | 21 | public PassthroughClassVisitor(Map classMap, InheritanceMap inheritanceMap, 22 | Map> passthroughDataflow, 23 | int api, MethodReference.Handle methodToVisit) { 24 | super(api); 25 | this.classMap = classMap; 26 | this.inheritanceMap = inheritanceMap; 27 | this.methodToVisit = methodToVisit; 28 | this.passthroughDataflow = passthroughDataflow; 29 | } 30 | 31 | @Override 32 | public void visit(int version, int access, String name, String signature, 33 | String superName, String[] interfaces) { 34 | super.visit(version, access, name, signature, superName, interfaces); 35 | this.name = name; 36 | //不是目标观察的class跳过 37 | if (!this.name.equals(methodToVisit.getClassReference().getName())) { 38 | return; 39 | } 40 | } 41 | 42 | @Override 43 | public MethodVisitor visitMethod(int access, String name, String desc, 44 | String signature, String[] exceptions) { 45 | //不是目标观察的method需要跳过,上一步得到的method都是有调用关系的method才需要数据流分析 46 | if (!name.equals(methodToVisit.getName()) || !desc.equals(methodToVisit.getDesc())) { 47 | return null; 48 | } 49 | if (PassthroughMethodAdapter != null) { 50 | return null; 51 | } 52 | 53 | //对method进行观察 54 | MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); 55 | PassthroughMethodAdapter = new PassthroughMethodAdapter( 56 | classMap, inheritanceMap, this.passthroughDataflow, 57 | api, mv, this.name, access, name, desc, signature, exceptions); 58 | return new JSRInlinerAdapter(PassthroughMethodAdapter, access, name, desc, signature, exceptions); 59 | } 60 | 61 | public Set getReturnTaint() { 62 | if (PassthroughMethodAdapter == null) { 63 | return null; 64 | } 65 | return PassthroughMethodAdapter.getReturnTaint(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/model/MethodReference.java: -------------------------------------------------------------------------------- 1 | package model; 2 | 3 | import java.util.Objects; 4 | import java.io.Serializable; 5 | 6 | public class MethodReference implements Serializable { 7 | private final ClassReference.Handle classReference; 8 | private final String name; 9 | private final String desc; 10 | private final boolean isStatic; 11 | private final boolean isAbstract; 12 | 13 | public MethodReference(ClassReference.Handle classReference, 14 | String name, String desc, boolean isStatic,boolean isAbstract) { 15 | this.classReference = classReference; 16 | this.name = name; 17 | this.desc = desc; 18 | this.isStatic = isStatic; 19 | this.isAbstract = isAbstract; 20 | } 21 | 22 | public ClassReference.Handle getClassReference() { 23 | return classReference; 24 | } 25 | 26 | public String getName() { 27 | return name; 28 | } 29 | 30 | public String getDesc() { 31 | return desc; 32 | } 33 | 34 | public boolean isStatic() { 35 | return isStatic; 36 | } 37 | 38 | public Handle getHandle() { 39 | return new Handle(classReference, name, desc); 40 | } 41 | 42 | public boolean isAbstract(){return isAbstract;} 43 | 44 | public static class Handle implements Serializable { 45 | private final ClassReference.Handle classReference; 46 | private final String name; 47 | private final String desc; 48 | 49 | public Handle(ClassReference.Handle classReference, String name, String desc) { 50 | this.classReference = classReference; 51 | this.name = name; 52 | this.desc = desc; 53 | } 54 | 55 | public ClassReference.Handle getClassReference() { 56 | return classReference; 57 | } 58 | 59 | public String getName() { 60 | return name; 61 | } 62 | 63 | public String getDesc() { 64 | return desc; 65 | } 66 | 67 | @Override 68 | public boolean equals(Object o) { 69 | if (this == o) return true; 70 | if (o == null || getClass() != o.getClass()) return false; 71 | Handle handle = (Handle) o; 72 | if (!Objects.equals(classReference, handle.classReference)) { 73 | return false; 74 | } 75 | if (!Objects.equals(name, handle.name)) { 76 | return false; 77 | } 78 | return Objects.equals(desc, handle.desc); 79 | } 80 | 81 | @Override 82 | public int hashCode() { 83 | int result = classReference != null ? classReference.getName().hashCode() : 0; 84 | result = 31 * result + (name != null ? name.hashCode() : 0); 85 | result = 31 * result + (desc != null ? desc.hashCode() : 0); 86 | return result; 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/rules/Ruleservice.java: -------------------------------------------------------------------------------- 1 | package rules; 2 | 3 | import app.Command; 4 | import model.Sink; 5 | 6 | import java.io.*; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | public class Ruleservice { 11 | private String owner; 12 | private String methodname; 13 | private String desc; 14 | private int targetIndex; 15 | private String sinkName; 16 | private int flag; 17 | private int flag2; 18 | private int flag3; 19 | 20 | 21 | public void start(List> Sinks,Command command){ 22 | flag2=Sinks.size()-1; 23 | if(command.rule!=null){ 24 | loadRules(Sinks,command.rule); 25 | } 26 | //print(Sinks); 27 | } 28 | 29 | private void loadRules(List> Sinks,String rules){ 30 | try{ 31 | FileInputStream rulefile = new FileInputStream(rules); 32 | BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(rulefile)); 33 | String rule = null; 34 | while((rule = bufferedReader.readLine() )!= null){ 35 | List tempList = new ArrayList(); 36 | String[] temp = rule.split("\\s+"); 37 | if(temp.length==6){ 38 | owner = temp[0]; 39 | methodname = temp[1]; 40 | desc = temp[2]; 41 | sinkName = temp[3]; 42 | targetIndex = Integer.parseInt(temp[4]); 43 | flag = Integer.parseInt(temp[5]); 44 | Sink sink = new Sink(owner,methodname,desc,sinkName,targetIndex,flag); 45 | tempList.add(sink); 46 | if(flag3 ==0){ 47 | flag3 = Integer.parseInt(temp[5]); 48 | } 49 | if(flag==1){ 50 | Sinks.add(tempList); 51 | flag2++; 52 | flag3--; 53 | } else if(flag!=1&&flag3==flag){ 54 | Sinks.add(tempList); 55 | flag2++; 56 | flag3--; 57 | } else if(flag!=1&& flag3!=flag && flag3 !=0){ 58 | Sinks.get(flag2).add(sink); 59 | flag3--; 60 | } else if(flag!=1&& flag3==0){ 61 | Sinks.get(flag2).add(sink); 62 | flag2++; 63 | } 64 | } 65 | } 66 | } catch (FileNotFoundException e) { 67 | throw new RuntimeException(e); 68 | } catch (IOException e) { 69 | throw new RuntimeException(e); 70 | } 71 | } 72 | 73 | /*private void print(List> Sinks){ 74 | for(List Sink:Sinks){ 75 | for(Sink sink:Sink){ 76 | System.out.println(sink.getName()); 77 | } 78 | System.out.println("---------------------------------------------"); 79 | } 80 | }*/ 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/model/ClassReference.java: -------------------------------------------------------------------------------- 1 | package model; 2 | 3 | import org.objectweb.asm.Handle; 4 | 5 | import java.io.Serializable; 6 | import java.util.List; 7 | import java.util.Objects; 8 | 9 | public class ClassReference implements Serializable { 10 | private final String name; //类名 11 | private final String superClass; //父类 12 | private final List interfaces; //接口 13 | private final boolean isInterface; //判断是否为接口 14 | private final List Variables; //这里一直用中文不知道好不好 15 | private final boolean isAbstract; 16 | public static class Variable implements Serializable{ 17 | private final String name; 18 | 19 | private final int modifiers; 20 | 21 | private final Handle Types; 22 | 23 | public Variable(String name, int modifiers, Handle type) { 24 | this.name = name; 25 | this.modifiers = modifiers; 26 | this.Types = type; 27 | } 28 | 29 | public String getName() { 30 | return name; 31 | } 32 | 33 | public int getModifiers() { 34 | return modifiers; 35 | } 36 | 37 | public Handle getType() { 38 | return Types; 39 | } 40 | } 41 | 42 | 43 | public ClassReference(String name, String superClass, List interfaces, 44 | boolean isInterface, List Variables,boolean isAbstract) { 45 | this.name = name; 46 | this.superClass = superClass; 47 | this.interfaces = interfaces; 48 | this.isInterface = isInterface; 49 | this.Variables = Variables; 50 | this.isAbstract = isAbstract; 51 | } 52 | 53 | public String getName() { 54 | return name; 55 | } 56 | 57 | public String getSuperClass() { 58 | return superClass; 59 | } 60 | 61 | public List getInterfaces() { 62 | return interfaces; 63 | } 64 | 65 | public boolean isInterface() { 66 | return isInterface; 67 | } 68 | 69 | public List getZiDuan() { 70 | return Variables; 71 | } 72 | 73 | public Handle getHandle() { 74 | return new Handle(name); 75 | } 76 | 77 | public boolean isAbstract(){ 78 | return isAbstract; 79 | } 80 | 81 | public static class Handle implements Serializable{ 82 | private final String name; 83 | 84 | public Handle(String name) { 85 | this.name = name; 86 | } 87 | 88 | public String getName() { 89 | return name; 90 | } 91 | 92 | @Override 93 | public boolean equals(Object o) { 94 | if (this == o) { 95 | return true; 96 | } 97 | if (o == null || getClass() != o.getClass()) { 98 | return false; 99 | } 100 | Handle handle = (Handle) o; 101 | return Objects.equals(name, handle.name); 102 | } 103 | 104 | @Override 105 | public int hashCode() { 106 | return name != null ? name.hashCode() : 0; 107 | } 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.example 8 | java_asm_parse 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | com.beust 14 | jcommander 15 | 1.82 16 | 17 | 18 | org.ow2.asm 19 | asm 20 | 9.3 21 | 22 | 23 | org.ow2.asm 24 | asm-commons 25 | 9.3 26 | 27 | 28 | com.google.guava 29 | guava 30 | 31.1-jre 31 | 32 | 33 | org.projectlombok 34 | lombok 35 | 1.18.24 36 | 37 | 38 | 39 | org.slf4j 40 | slf4j-api 41 | 2.0.0 42 | 43 | 44 | 45 | org.slf4j 46 | slf4j-simple 47 | 2.0.0 48 | 49 | 50 | 51 | 52 | org.reflections 53 | reflections 54 | 0.10.2 55 | 56 | 57 | 58 | 59 | 8 60 | 8 61 | UTF-8 62 | 63 | 64 | 65 | 66 | 67 | maven-assembly-plugin 68 | 69 | false 70 | 71 | jar-with-dependencies 72 | 73 | 74 | 75 | Main 76 | 77 | 78 | 79 | 80 | 81 | make-assembly 82 | package 83 | 84 | assembly 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /src/main/java/framework/JenkinsAdapter.java: -------------------------------------------------------------------------------- 1 | package framework; 2 | 3 | import model.ClassReference; 4 | import model.MethodReference; 5 | import org.objectweb.asm.AnnotationVisitor; 6 | import org.objectweb.asm.ClassVisitor; 7 | import org.objectweb.asm.MethodVisitor; 8 | import rules.JenkinsConstant; 9 | 10 | import java.util.List; 11 | import java.util.regex.Pattern; 12 | 13 | public class JenkinsAdapter extends MethodVisitor { 14 | private String MethodName; 15 | private String desc; 16 | private String ClassName; 17 | private List SourceMethod; 18 | boolean isStatic; 19 | private int flag=0; 20 | 21 | public JenkinsAdapter(String name, String desc, String className, int api, MethodVisitor mv, List sourceMethod,boolean isStatic) { 22 | super(api, mv); 23 | this.MethodName = name; 24 | this.desc = desc; 25 | this.ClassName = className; 26 | this.SourceMethod = sourceMethod; 27 | this.isStatic = isStatic; 28 | if((MethodNameIsMatch(this.MethodName)&&isneed(ClassName))|(MethodName.contains("search")&&isneed(ClassName))){ 29 | this.flag=1; 30 | this.SourceMethod.add(new MethodReference(new ClassReference.Handle(ClassName),MethodName,desc,isStatic)); 31 | System.out.println("入口点source在"+ClassName+"-->"+MethodName); 32 | } 33 | } 34 | 35 | @Override 36 | public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) { 37 | AnnotationVisitor av = super.visitAnnotation(descriptor, visible); 38 | if((descriptor.equals(JenkinsConstant.JenkinsAnno1) | descriptor.equals(JenkinsConstant.JenkinsAnno2) 39 | |descriptor.equals(JenkinsConstant.JenkinsAnno3)| descriptor.equals(JenkinsConstant.JenkinsAnno4)|descriptor.equals(JenkinsConstant.JenkinsAnno5) 40 | |descriptor.equals(JenkinsConstant.JenkinsAnno6))&&(this.flag==0)){ 41 | this.flag=1; 42 | this.SourceMethod.add(new MethodReference(new ClassReference.Handle(ClassName),MethodName,desc,isStatic)); 43 | System.out.println("入口点source在"+ClassName+"-->"+MethodName); 44 | } 45 | return av; 46 | } 47 | 48 | 49 | @Override 50 | public AnnotationVisitor visitParameterAnnotation(int parameter, String descriptor, boolean visible) { 51 | AnnotationVisitor av = super.visitParameterAnnotation(parameter, descriptor, visible); 52 | if((descriptor.contains(JenkinsConstant.ParamAnn1)|descriptor.contains(JenkinsConstant.ParamAnn2) 53 | |descriptor.contains(JenkinsConstant.ParamAnn3)|descriptor.contains(JenkinsConstant.ParamAnn4))&&(this.flag==0)&&isneed(ClassName)) 54 | { 55 | this.flag=1; 56 | this.SourceMethod.add(new MethodReference(new ClassReference.Handle(ClassName),MethodName,desc,isStatic)); 57 | System.out.println("入口点source在"+ClassName+"-->"+MethodName); 58 | } 59 | return av; 60 | } 61 | 62 | public boolean isneed(String ClassName){ 63 | for(String black:blacklist){ 64 | if(ClassName.contains(black)){ 65 | return false; 66 | } 67 | } 68 | return true; 69 | } 70 | 71 | public String[] blacklist = new String[]{ 72 | "org/apache","okhttp","javax/xml/","org/json","org/","fasterxml/","javassist/","groovy/","sun/","google/" 73 | }; 74 | 75 | public boolean MethodNameIsMatch(String MethodName){ 76 | String pattern = "^do[A-Z].*"; 77 | boolean isMatch = Pattern.matches(pattern, MethodName); 78 | return isMatch; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/asm/DiscoveryClassVisitor.java: -------------------------------------------------------------------------------- 1 | package asm; 2 | 3 | import model.ClassReference; 4 | import model.MethodReference; 5 | import org.objectweb.asm.*; 6 | 7 | import java.util.*; 8 | 9 | public class DiscoveryClassVisitor extends ClassVisitor { 10 | private String name; 11 | private String superName; 12 | private String[] interfaces; 13 | private boolean isInterface; 14 | private boolean isAbstract; 15 | private List Variables; 16 | private ClassReference.Handle classHandle; 17 | private List discoveredClasses; 18 | private List discoveredMethods; 19 | 20 | private String methodName; 21 | 22 | 23 | 24 | public DiscoveryClassVisitor(List discoveredClasses, 25 | List discoveredMethods) { 26 | super(Opcodes.ASM7); 27 | this.discoveredClasses = discoveredClasses; 28 | this.discoveredMethods = discoveredMethods; 29 | } 30 | 31 | public DiscoveryClassVisitor(String methodName) { 32 | super(Opcodes.ASM7); 33 | this.methodName = methodName; 34 | } 35 | 36 | @Override 37 | public void visit(int version, int access, String name, 38 | String signature, String superName, String[] interfaces) { 39 | this.name = name; 40 | this.superName = superName; 41 | this.interfaces = interfaces; 42 | this.isInterface = (access & Opcodes.ACC_INTERFACE) != 0; 43 | this.isAbstract = (access & Opcodes.ACC_ABSTRACT) != 0; 44 | this.Variables = new ArrayList<>(); 45 | this.classHandle = new ClassReference.Handle(name); 46 | super.visit(version, access, name, signature, superName, interfaces); 47 | } 48 | 49 | public String getName(){ 50 | return this.name; 51 | } 52 | 53 | @Override 54 | public FieldVisitor visitField(int access, String name, String desc, 55 | String signature, Object value) { 56 | if ((access & Opcodes.ACC_STATIC) == 0) { 57 | Type type = Type.getType(desc); 58 | String typeName; 59 | if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) { 60 | typeName = type.getInternalName(); 61 | } else { 62 | typeName = type.getDescriptor(); 63 | } 64 | Variables.add(new ClassReference.Variable(name, access, new ClassReference.Handle(typeName))); 65 | } 66 | return super.visitField(access, name, desc, signature, value); 67 | } 68 | 69 | @Override 70 | public MethodVisitor visitMethod(int access, String name, String desc, 71 | String signature, String[] exceptions) { 72 | if(methodName!=null){ 73 | if(methodName.equals(name)){ 74 | System.out.println(this.name); 75 | System.out.println(desc); 76 | } 77 | } else { 78 | boolean isStatic = (access & Opcodes.ACC_STATIC) != 0; 79 | discoveredMethods.add(new MethodReference( 80 | classHandle, 81 | name, 82 | desc, 83 | isStatic,isAbstract)); 84 | } 85 | return super.visitMethod(access, name, desc, signature, exceptions); 86 | 87 | } 88 | 89 | @Override 90 | public void visitEnd() { 91 | if(methodName==null){ 92 | ClassReference classReference = new ClassReference( 93 | name, 94 | superName, 95 | Arrays.asList(interfaces), 96 | isInterface, 97 | Variables, 98 | isAbstract); 99 | discoveredClasses.add(classReference); 100 | } 101 | super.visitEnd(); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/Util/StackUtil.java: -------------------------------------------------------------------------------- 1 | package Util; 2 | 3 | import com.google.common.io.Files; 4 | import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream; 5 | import model.MethodReference; 6 | 7 | import java.io.*; 8 | import java.nio.charset.StandardCharsets; 9 | import java.nio.file.Path; 10 | import java.util.*; 11 | 12 | public class StackUtil { 13 | public static T clone(Map obj) { 14 | T cloneObj = null; 15 | try { 16 | ByteOutputStream bos = new ByteOutputStream(); 17 | ObjectOutputStream oos = new ObjectOutputStream(bos); 18 | oos.writeObject(obj); 19 | oos.close(); 20 | ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); 21 | ObjectInputStream ois = new ObjectInputStream(bis); 22 | cloneObj = (T) ois.readObject(); 23 | ois.close(); 24 | } catch (Exception e) { 25 | e.printStackTrace(); 26 | } 27 | return cloneObj; 28 | } 29 | 30 | public static void printStackTrace(Deque stack) { 31 | Deque copyStack = new LinkedList<>(stack); 32 | StringBuilder prefix=new StringBuilder("\t"); 33 | for (MethodReference.Handle handle : copyStack) { 34 | System.out.println(prefix+handle.getClassReference().getName()+"."+handle.getName()); 35 | prefix.append("\t"); 36 | } 37 | System.out.println(""); 38 | System.out.println(""); 39 | } 40 | 41 | public static void SaveStack(Path filePath, List> StackList) throws IOException { 42 | try { 43 | File file = new File(filePath.toString()); 44 | if(file.exists()){ 45 | file.delete(); 46 | } 47 | BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filePath.toString(), true))); 48 | for (Deque Stack: StackList) { 49 | StringBuilder sb = new StringBuilder(); 50 | Deque copyStack = new LinkedList<>(Stack); 51 | StringBuilder prefix=new StringBuilder("\t"); 52 | for (MethodReference.Handle handle : copyStack) { 53 | sb.append(prefix).append(handle.getClassReference().getName()).append(".").append(handle.getName()).append("\n"); 54 | prefix.append("\t"); 55 | } 56 | sb.append("\n"); 57 | writer.write(String.valueOf(sb)); 58 | } 59 | } catch (IOException e) { 60 | throw new RuntimeException(e); 61 | } 62 | } 63 | 64 | public static List>> paixu(List> stacks){ 65 | List>> fenleiList = new ArrayList<>(); 66 | List>> fenleiList2 = new ArrayList<>(); 67 | fenleiList2.add(new ArrayList<>()); 68 | fenleiList2.add(new ArrayList<>()); 69 | List storeList = new ArrayList<>(); 70 | for(Deque stack:stacks){ 71 | MethodReference.Handle First = stack.getFirst(); 72 | if(storeList.contains(First)){ 73 | int i = storeList.indexOf(First); 74 | fenleiList.get(i).add(stack); 75 | }else { 76 | storeList.add(First); 77 | List> newList = new ArrayList<>(); 78 | newList.add(stack); 79 | fenleiList.add(newList); 80 | } 81 | } 82 | for(List> a:fenleiList){ 83 | Deque b = a.stream().min(Comparator.comparing(Deque::size)).get(); 84 | fenleiList2.get(0).add(b); 85 | fenleiList2.get(1).addAll(a); 86 | } 87 | return fenleiList2; 88 | } 89 | 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/Service/PassthroughService.java: -------------------------------------------------------------------------------- 1 | package Service; 2 | 3 | import Util.WriteUtil; 4 | import asm.PassthroughClassVisitor; 5 | import javassist.bytecode.stackmap.TypeData; 6 | import model.ClassFile; 7 | import model.ClassReference; 8 | import model.InheritanceMap; 9 | import model.MethodReference; 10 | import org.objectweb.asm.ClassReader; 11 | import org.objectweb.asm.Opcodes; 12 | 13 | import java.nio.file.Paths; 14 | import java.util.*; 15 | 16 | public class PassthroughService { 17 | public static void start(Map ClassFileByName, Map classMap, InheritanceMap InheritanceMap, 18 | Map> methodCall, Map> passthroughDataflow){ 19 | List sortedMethods = BaseDfsSortMethod(methodCall); 20 | WriteUtil.SaveSortedMethods(Paths.get("sortedMethods.dat"),sortedMethods); 21 | calculatePassthroughDataflow(ClassFileByName, classMap, InheritanceMap, sortedMethods,passthroughDataflow); 22 | } 23 | 24 | 25 | 26 | public static List BaseDfsSortMethod(Map> methodCall){ 27 | Map> outgoingReferences = new HashMap<>(); 28 | for (Map.Entry> entry : methodCall.entrySet()) { 29 | MethodReference.Handle method = entry.getKey(); 30 | outgoingReferences.put(method, new HashSet<>(entry.getValue())); 31 | } 32 | Set dfsStack = new HashSet<>(); 33 | Set visitedNodes = new HashSet<>(); 34 | List sortedMethods = new ArrayList<>(outgoingReferences.size()); 35 | for (MethodReference.Handle root : outgoingReferences.keySet()) { 36 | dfsSort(outgoingReferences, sortedMethods, visitedNodes, dfsStack, root); 37 | } 38 | return sortedMethods; 39 | } 40 | 41 | //使用dfs排序将所有方法进行排序,这样做的目的是让前面0出度的方法先被分析,那么后面进行分析的时候,前面的方法必定被分析过 42 | private static void dfsSort(Map> outgoingReferences, List sortedMethods, 43 | Set visitedNodes, Set dfsStack, MethodReference.Handle root) { 44 | if (dfsStack.contains(root)) { 45 | return; 46 | } 47 | if (visitedNodes.contains(root)) { 48 | return; 49 | } 50 | Set outgoingRefs = outgoingReferences.get(root); 51 | if (outgoingRefs == null) { 52 | return; 53 | } 54 | dfsStack.add(root); 55 | for (MethodReference.Handle child : outgoingRefs) { 56 | dfsSort(outgoingReferences, sortedMethods, visitedNodes, dfsStack, child); 57 | } 58 | dfsStack.remove(root); 59 | visitedNodes.add(root); 60 | sortedMethods.add(root); 61 | } 62 | 63 | 64 | private static Map> calculatePassthroughDataflow(Map ClassFileByName, Map classMap, InheritanceMap inheritanceMap, List sortedMethods,Map> passthroughDataflow) { 65 | //遍历所有方法,然后asm观察所属类,经过前面DFS的排序,调用链最末端的方法在最前面 66 | for (MethodReference.Handle method : sortedMethods) { 67 | //跳过static静态初始化代码 68 | if (method.getName().equals("")) { 69 | continue; 70 | } 71 | //获取所属类进行观察 72 | ClassFile file = ClassFileByName.get(method.getClassReference().getName()); 73 | try { 74 | PassthroughClassVisitor dcv = new PassthroughClassVisitor(classMap,inheritanceMap,passthroughDataflow,Opcodes.ASM7,method); 75 | ClassReader cr = new ClassReader(file.getFile()); 76 | cr.accept(dcv, ClassReader.EXPAND_FRAMES); 77 | passthroughDataflow.put(method, dcv.getReturnTaint()); 78 | } catch (Exception e) { 79 | e.printStackTrace(); 80 | } 81 | } 82 | return passthroughDataflow; 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/rules/UnserializeConstan.java: -------------------------------------------------------------------------------- 1 | package rules; 2 | 3 | 4 | public class UnserializeConstan { 5 | private static final String[][] rules = new String[][]{ 6 | {"INVOKEVIRTUAL","java/io/ObjectInputStream","readObject","*","unserialize","JAVAX-unserialize","-1","1"}, 7 | {"INVOKEVIRTUAL", "org/yaml/snakeyaml/Yaml", "load", "*", "unserialize", "SNAKEYAML-unserialize","-1","1"}, 8 | {"INVOKEVIRTUAL", "org/yaml/snakeyaml/Yaml", "compose", "*", "unserialize", "SNAKEYAML-unserialize","-1","1"}, 9 | {"INVOKEVIRTUAL", "org/yaml/snakeyaml/Yaml", "composeAll", "*", "unserialize", "SNAKEYAML-unserialize","-1","1"}, 10 | {"INVOKEVIRTUAL", "org/yaml/snakeyaml/Yaml", "loadAll", "*", "unserialize", "SNAKEYAML-unserialize","-1","1"}, 11 | {"INVOKEVIRTUAL", "org/yaml/snakeyaml/Yaml", "loadAs", "*", "unserialize", "SNAKEYAML-unserialize","-1","1"}, 12 | {"INVOKEVIRTUAL", "org/yaml/snakeyaml/Yaml", "parse", "*", "unserialize", "SNAKEYAML-unserialize","-1","1"}, 13 | 14 | {"INVOKEVIRTUAL", "com/fasterxml/jackson/databind/ObjectMapper", "readValue", "*", "unserialize", "JACKSON-unserialize","-1","1"}, 15 | {"INVOKEVIRTUAL", "com/fasterxml/jackson/databind/ObjectMapper", "readValues", "*", "unserialize", "JACKSON-unserialize","-1","1"}, 16 | {"INVOKEVIRTUAL", "com/fasterxml/jackson/databind/ObjectMapper", "treeToValue", "*", "unserialize", "JACKSON-unserialize","-1","1"}, 17 | 18 | {"INVOKEVIRTUAL", "com/thoughtworks/xstream/XStream", "fromXML", "*", "unserialize", "XStream-unserialize","-1","1"}, 19 | {"INVOKEVIRTUAL", "com/thoughtworks/xstream/XStream", "unmarshal", "*", "unserialize", "XStream-unserialize","-1","1"}, 20 | 21 | {"INVOKEVIRTUAL", "java/beans/XMLDecoder", "readObject", "*", "unserialize", "XMLDecoder-unserialize","-1","1"}, 22 | 23 | {"INVOKEVIRTUAL", "com/alibaba/fastjson/JSON", "parse", "*", "unserialize", "FASTJSON-unserialize","-1","1"}, 24 | {"INVOKEVIRTUAL", "com/alibaba/fastjson/JSON", "parseObject", "*", "unserialize", "FASTJSON-unserialize","-1","1"}, 25 | 26 | {"INVOKEVIRTUAL", "com/cedarsoftware/util/io/JsonReader", "jsonToJava", "*", "unserialize", "JsonReader-unserialize","-1","1"}, 27 | {"INVOKEVIRTUAL", "com/cedarsoftware/util/io/JsonReader", "readObject", "*", "unserialize", "JsonReader-unserialize","-1","1"}, 28 | 29 | {"INVOKEVIRTUAL", "com/esotericsoftware/yamlbeans/YamlReader", "read", "*", "unserialize", "YamlReader-unserialize","-1","1"}, 30 | 31 | {"INVOKEVIRTUAL", "com/caucho/hessian/io.AbstractHessianInput", "readObject", "*", "unserialize", "HESSIAN-unserialize","-1","1"}, 32 | {"INVOKEVIRTUAL", "com/alibaba/com/caucho/hessian/io/AbstractHessianInput", "readObject", "*", "unserialize", "HESSIAN-unserialize","-1","1"}, 33 | {"INVOKEVIRTUAL", "com/caucho/hessian/io/Hessian2StreamingInput", "readObject", "*", "unserialize", "HESSIAN-unserialize","-1","1"}, 34 | {"INVOKEVIRTUAL", "com/alibaba/com/caucho/hessian/io/Hessian2StreamingInput", "readObject", "*", "unserialize", "HESSIAN-unserialize","-1","1"}, 35 | {"INVOKEVIRTUAL", "com/caucho/hessian/io/Hessian2Input", "readObject", "*", "unserialize", "HESSIAN-unserialize","-1","1"}, 36 | {"INVOKEVIRTUAL", "com/alibaba/com/caucho/hessian/io/Hessian2Input", "readObject", "*", "unserialize", "HESSIAN-unserialize","-1","1"}, 37 | 38 | {"INVOKEVIRTUAL", "org/exolab/castor/xml/Unmarshaller", "unmarshal", "*", "unserialize", "exolab-unserialize","-1","1"}, 39 | 40 | {"INVOKEVIRTUAL", "org/jabsorb/JSONSerializer", "unmarshall", "*", "unserialize", "jabsorb-unserialize","-1","1"}, 41 | {"INVOKEVIRTUAL", "org/jabsorb/JSONSerializer", "fromJSON", "*", "unserialize", "jabsorb-unserialize","-1","1"}, 42 | 43 | {"INVOKEVIRTUAL", "com/google/gson/Gson", "fromJson", "*", "unserialize", "Gson-unserialize","-1","1"}, 44 | 45 | {"INVOKEVIRTUAL", "org/apache/commons/lang/RandomStringUtils", "deserialize", "*", "unserialize", "lang-unserialize","-1","1"}, 46 | {"INVOKEVIRTUAL", "org/apache/commons/lang3/RandomStringUtils", "deserialize", "*", "unserialize", "lang-unserialize","-1","1"}, 47 | 48 | {"INVOKEVIRTUAL", "com/esotericsoftware/kryo", "readClassAndObject", "*", "unserialize", "kryo-unserialize","1","1"} 49 | 50 | }; 51 | 52 | public static String[][] getRules(){ 53 | return rules; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/asm/CallGraphMethodAdapter.java: -------------------------------------------------------------------------------- 1 | package asm; 2 | 3 | import asm.jvmasm.JvmMethodAdapter; 4 | import model.CallGraph; 5 | import model.ClassReference; 6 | import model.InheritanceMap; 7 | import model.MethodReference; 8 | import org.objectweb.asm.MethodVisitor; 9 | import org.objectweb.asm.Opcodes; 10 | import org.objectweb.asm.Type; 11 | 12 | import java.util.Map; 13 | import java.util.Set; 14 | 15 | public class CallGraphMethodAdapter extends JvmMethodAdapter { 16 | private final Map classMap; 17 | private final Set discoveredCalls; 18 | private final String owner; 19 | private final int access; 20 | private final String name; 21 | private final String desc; 22 | 23 | public CallGraphMethodAdapter(Map classMap, 24 | InheritanceMap inheritanceMap, 25 | Map> passthroughDataflow, final int api, Set discoveredCalls, 26 | final MethodVisitor mv, final String owner, 27 | int access, String name, String desc) { 28 | super(inheritanceMap, passthroughDataflow,api, mv, owner, access, name, desc); 29 | this.classMap = classMap; 30 | this.owner = owner; 31 | this.access = access; 32 | this.name = name; 33 | this.desc = desc; 34 | this.discoveredCalls = discoveredCalls; 35 | } 36 | 37 | @Override 38 | public void visitCode() { 39 | super.visitCode(); 40 | int localIndex = 0; 41 | int argIndex = 0; 42 | if ((this.access & Opcodes.ACC_STATIC) == 0) { 43 | localVariables.set(localIndex, "arg" + argIndex); 44 | localIndex += 1; 45 | argIndex += 1; 46 | } 47 | for (Type argType : Type.getArgumentTypes(desc)) { 48 | localVariables.set(localIndex, "arg" + argIndex); 49 | localIndex += argType.getSize(); 50 | argIndex += 1; 51 | } 52 | } 53 | 54 | @Override 55 | @SuppressWarnings("all") 56 | public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { 57 | Type[] argTypes = Type.getArgumentTypes(desc); 58 | if (opcode != Opcodes.INVOKESTATIC) { 59 | Type[] extendedArgTypes = new Type[argTypes.length + 1]; 60 | System.arraycopy(argTypes, 0, extendedArgTypes, 1, argTypes.length); 61 | extendedArgTypes[0] = Type.getObjectType(owner); 62 | argTypes = extendedArgTypes; 63 | } 64 | switch (opcode) { 65 | case Opcodes.INVOKESTATIC: 66 | case Opcodes.INVOKEVIRTUAL: 67 | case Opcodes.INVOKESPECIAL: 68 | case Opcodes.INVOKEINTERFACE: 69 | int stackIndex = 0; 70 | for (int i = 0; i < argTypes.length; i++) { 71 | int argIndex = argTypes.length - 1 - i; 72 | Type type = argTypes[argIndex]; 73 | Set taint = operandStack.get(stackIndex); 74 | if (taint.size() > 0) { 75 | for (String argSrc : taint) { 76 | if (!argSrc.startsWith("arg")) { 77 | throw new IllegalStateException("invalid taint arg: " + argSrc); 78 | } 79 | int dotIndex = argSrc.indexOf('.'); 80 | int srcArgIndex; 81 | if (dotIndex == -1) { 82 | srcArgIndex = Integer.parseInt(argSrc.substring(3)); 83 | } else { 84 | srcArgIndex = Integer.parseInt(argSrc.substring(3, dotIndex)); 85 | } 86 | discoveredCalls.add(new CallGraph( 87 | new MethodReference.Handle( 88 | new ClassReference.Handle(this.owner), this.name, this.desc), 89 | new MethodReference.Handle( 90 | new ClassReference.Handle(owner), name, desc), 91 | srcArgIndex, 92 | argIndex)); 93 | } 94 | } 95 | stackIndex += type.getSize(); 96 | } 97 | break; 98 | default: 99 | throw new IllegalStateException("unsupported opcode: " + opcode); 100 | } 101 | super.visitMethodInsn(opcode, owner, name, desc, itf); 102 | } 103 | } -------------------------------------------------------------------------------- /src/main/java/Util/JarUtil.java: -------------------------------------------------------------------------------- 1 | package Util; 2 | 3 | 4 | import model.ClassFile; 5 | 6 | import java.io.*; 7 | import java.nio.file.Files; 8 | import java.nio.file.Path; 9 | import java.nio.file.Paths; 10 | import java.util.*; 11 | import java.util.jar.JarEntry; 12 | import java.util.jar.JarInputStream; 13 | import java.util.zip.ZipEntry; 14 | import java.util.zip.ZipInputStream; 15 | 16 | public class JarUtil { 17 | 18 | private Set classFileSet = new HashSet<>(); 19 | 20 | public void resolveJarFile(String jarPath) { 21 | try { 22 | final Path tmpDir = Files.createTempDirectory( 23 | Paths.get(jarPath).getFileName().toString() + "_"); 24 | Runtime.getRuntime().addShutdownHook(new Thread(() -> { 25 | DirUtil.removeDir(tmpDir.toFile()); 26 | })); 27 | resolve(jarPath, tmpDir); 28 | } catch (Exception e) { 29 | System.out.println(e); 30 | } 31 | } 32 | public List resolveNormalJarFile(String jarPath) { 33 | try { 34 | final Path tmpDir = Files.createTempDirectory( 35 | Paths.get(jarPath).getFileName().toString() + "_"); 36 | Runtime.getRuntime().addShutdownHook(new Thread(() -> { 37 | DirUtil.removeDir(tmpDir.toFile()); 38 | })); 39 | resolve(jarPath, tmpDir); 40 | return new ArrayList<>(classFileSet); 41 | } catch (Exception e) { 42 | System.out.println(e); 43 | } 44 | return new ArrayList<>(); 45 | } 46 | 47 | private void resolve(String jarPath, Path tmpDir) { 48 | try { 49 | InputStream is = new FileInputStream(jarPath); 50 | JarInputStream jarInputStream = new JarInputStream(is); 51 | JarEntry jarEntry; 52 | while ((jarEntry = jarInputStream.getNextJarEntry()) != null) { 53 | Path fullPath = tmpDir.resolve(jarEntry.getName()); 54 | if (!jarEntry.isDirectory()) { 55 | if (!jarEntry.getName().endsWith(".class")) { 56 | continue; 57 | } 58 | Path dirName = fullPath.getParent(); 59 | if (!Files.exists(dirName)) { 60 | Files.createDirectories(dirName); 61 | } 62 | OutputStream outputStream = Files.newOutputStream(fullPath); 63 | IOUtil.copy(jarInputStream, outputStream); 64 | ClassFile classFile = new ClassFile(jarEntry.getName(), fullPath); 65 | classFileSet.add(classFile); 66 | } 67 | } 68 | } catch (Exception e) { 69 | } 70 | } 71 | 72 | 73 | public List resolveSpringBootJarFile(String jarPath, boolean useAllLib) { 74 | try { 75 | final Path tmpDir = Files.createTempDirectory( 76 | Paths.get(jarPath).getFileName().toString() + "_"); 77 | Runtime.getRuntime().addShutdownHook(new Thread(() -> { 78 | DirUtil.removeDir(tmpDir.toFile()); 79 | })); 80 | resolve(jarPath, tmpDir); 81 | if (useAllLib) { 82 | resolveBoot(jarPath, tmpDir); 83 | if(Files.exists(tmpDir)){ 84 | allfile(tmpDir.toFile()); 85 | } 86 | } 87 | return new ArrayList<>(classFileSet); 88 | } catch (Exception e) { 89 | System.out.println(e); 90 | } 91 | return new ArrayList<>(); 92 | } 93 | 94 | private void resolveBoot(String jarPath, Path tmpDir) { 95 | try { 96 | InputStream is = new FileInputStream(jarPath); 97 | JarInputStream jarInputStream = new JarInputStream(is); 98 | JarEntry jarEntry; 99 | while ((jarEntry = jarInputStream.getNextJarEntry()) != null) { 100 | Path fullPath = tmpDir.resolve(jarEntry.getName()); 101 | if (!jarEntry.isDirectory()) { 102 | if (!jarEntry.getName().endsWith(".jar")) { 103 | continue; 104 | } 105 | Path dirName = fullPath.getParent(); 106 | if (!Files.exists(dirName)) { 107 | Files.createDirectories(dirName); 108 | } 109 | OutputStream outputStream = Files.newOutputStream(fullPath); 110 | IOUtil.copy(jarInputStream, outputStream); 111 | } 112 | } 113 | } catch (Exception e) { 114 | System.out.println(e); 115 | } 116 | } 117 | 118 | 119 | public void allfile(File file) { 120 | File[] files = file.listFiles(); 121 | if(files!=null && files.length>0) { 122 | for(File temp:files) { 123 | //如果文件是一个目录时则递归 124 | if(temp.isDirectory()) { 125 | allfile(temp); 126 | }else if(temp.getAbsoluteFile().getName().endsWith(".jar")){ 127 | resolveJarFile(temp.getAbsolutePath()); 128 | } 129 | } 130 | } 131 | } 132 | } 133 | 134 | -------------------------------------------------------------------------------- /src/main/java/asm/PassthroughMethodAdapter.java: -------------------------------------------------------------------------------- 1 | package asm; 2 | 3 | import asm.jvmasm.JvmMethodAdapter; 4 | import model.ClassReference; 5 | import model.InheritanceMap; 6 | import model.MethodReference; 7 | import org.objectweb.asm.MethodVisitor; 8 | import org.objectweb.asm.Opcodes; 9 | import org.objectweb.asm.Type; 10 | 11 | import java.util.*; 12 | 13 | public class PassthroughMethodAdapter extends JvmMethodAdapter { 14 | private final Map classMap; 15 | private final InheritanceMap inheritanceMap; 16 | private final Map> passthroughDataflow; 17 | private final int access; 18 | private final String desc; 19 | private final Set returnTaint; 20 | public PassthroughMethodAdapter(Map classMap, InheritanceMap inheritanceMap, Map> passthroughDataflow, int api, MethodVisitor mv, String owner, int access, String name, String desc, String signature, String[] exceptions) { 21 | super(inheritanceMap,passthroughDataflow,api,mv,owner,access,name,desc); 22 | this.classMap = classMap; 23 | this.inheritanceMap = inheritanceMap; 24 | this.passthroughDataflow = passthroughDataflow; 25 | this.access = access; 26 | this.desc = desc; 27 | returnTaint = new HashSet<>(); 28 | } 29 | 30 | @Override 31 | public void visitCode() { 32 | super.visitCode(); 33 | int localIndex = 0; 34 | int argIndex = 0; 35 | if ((this.access & Opcodes.ACC_STATIC) == 0) { 36 | localVariables.set(localIndex, argIndex); 37 | localIndex += 1; 38 | argIndex += 1; 39 | } 40 | for (Type argType : Type.getArgumentTypes(desc)) { 41 | localVariables.set(localIndex, argIndex); 42 | localIndex += argType.getSize(); 43 | argIndex += 1; 44 | } 45 | } 46 | 47 | @Override 48 | public void visitInsn(int opcode) { 49 | switch (opcode) { 50 | case Opcodes.IRETURN: 51 | case Opcodes.FRETURN: 52 | case Opcodes.ARETURN: 53 | returnTaint.addAll(operandStack.get(0)); 54 | break; 55 | case Opcodes.LRETURN: 56 | case Opcodes.DRETURN: 57 | returnTaint.addAll(operandStack.get(1)); 58 | break; 59 | case Opcodes.RETURN: 60 | break; 61 | default: 62 | break; 63 | } 64 | super.visitInsn(opcode); 65 | } 66 | 67 | @Override 68 | public void visitFieldInsn(int opcode, String owner, String name, String desc) { 69 | super.visitFieldInsn(opcode,owner,name,desc); 70 | } 71 | 72 | 73 | @Override 74 | public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { 75 | Type[] argTypes = Type.getArgumentTypes(desc); 76 | if (opcode != Opcodes.INVOKESTATIC) { 77 | Type[] extendedArgTypes = new Type[argTypes.length+1]; 78 | System.arraycopy(argTypes, 0, extendedArgTypes, 1, argTypes.length); 79 | extendedArgTypes[0] = Type.getObjectType(owner); 80 | argTypes = extendedArgTypes; 81 | } 82 | int retSize = Type.getReturnType(desc).getSize(); 83 | Set resultTaint; 84 | switch (opcode) { 85 | case Opcodes.INVOKESTATIC: 86 | case Opcodes.INVOKEVIRTUAL: 87 | case Opcodes.INVOKESPECIAL: 88 | case Opcodes.INVOKEINTERFACE: 89 | final List> argTaint = new ArrayList<>(argTypes.length); 90 | for (int i = 0; i < argTypes.length; i++) { 91 | argTaint.add(null); 92 | } 93 | int stackIndex = 0; 94 | for (int i = 0; i < argTypes.length; i++) { 95 | Type argType = argTypes[i]; 96 | if (argType.getSize() > 0) { 97 | argTaint.set(argTypes.length - 1 - i, 98 | operandStack.get(stackIndex+argType.getSize()-1)); 99 | } 100 | stackIndex += argType.getSize(); 101 | } 102 | if (name.equals("")) { 103 | resultTaint = argTaint.get(0); 104 | } else { 105 | resultTaint = new HashSet<>(); 106 | } 107 | Set passthrough = passthroughDataflow.get( 108 | new MethodReference.Handle(new ClassReference.Handle(owner), name, desc)); 109 | if (passthrough != null) { 110 | for (Integer passthroughDataflowArg : passthrough) { 111 | resultTaint.addAll(argTaint.get(passthroughDataflowArg)); 112 | } 113 | } 114 | break; 115 | default: 116 | throw new IllegalStateException("unsupported opcode: " + opcode); 117 | } 118 | super.visitMethodInsn(opcode, owner, name, desc, itf); 119 | if (retSize > 0) { 120 | operandStack.get(retSize-1).addAll(resultTaint); 121 | } 122 | } 123 | 124 | public Set getReturnTaint() { 125 | return returnTaint; 126 | } 127 | 128 | } 129 | -------------------------------------------------------------------------------- /src/main/java/Service/InheritanceService.java: -------------------------------------------------------------------------------- 1 | package Service; 2 | 3 | import model.ClassReference; 4 | import model.InheritanceMap; 5 | import model.MethodReference; 6 | 7 | import java.util.HashMap; 8 | import java.util.HashSet; 9 | import java.util.Map; 10 | import java.util.Set; 11 | 12 | public class InheritanceService { 13 | public static InheritanceMap start(Map classMap){ 14 | Map> implicitInheritance = new HashMap<>(); 15 | 16 | for(ClassReference classReference : classMap.values()){ 17 | if(implicitInheritance.containsKey(classReference.getHandle())){ 18 | throw new IllegalStateException("Already derived implicit classes for " + classReference.getName()); 19 | } 20 | Set allParents = new HashSet<>(); 21 | getAllParents(classReference,classMap,allParents); 22 | //添加缓存:类名 -> 所有的父类、超类、接口类 23 | implicitInheritance.put(classReference.getHandle(), allParents); 24 | } 25 | //InheritanceMap翻转集合,转换为{class:[subclass]} 26 | return new InheritanceMap(implicitInheritance); 27 | } 28 | 29 | 30 | public static void getAllParents(ClassReference classReference,Map classMap, Set allParents){ 31 | Set parents = new HashSet<>(); 32 | //把当前classReference类的父类添加到parents 33 | if (classReference.getSuperClass() != null) { 34 | parents.add(new ClassReference.Handle(classReference.getSuperClass())); 35 | } 36 | //把当前classReference类实现的所有接口添加到parents 37 | for (String iface : classReference.getInterfaces()) { 38 | parents.add(new ClassReference.Handle(iface)); 39 | } 40 | 41 | for (ClassReference.Handle immediateParent : parents) { 42 | //从所有类数据集合中,遍历找出classReference的父类、接口 43 | ClassReference parentClassReference = classMap.get(immediateParent); 44 | if (parentClassReference == null) { 45 | continue; 46 | } 47 | //继续添加到集合中 48 | allParents.add(parentClassReference.getHandle()); 49 | //继续递归查找,直到把classReference类的所有父类、超类、接口类都添加到allParents 50 | getAllParents(parentClassReference, classMap, allParents); 51 | } 52 | } 53 | 54 | public static Map> getAllMethodImplementations( 55 | InheritanceMap inheritanceMap, Map methodMap) { 56 | 57 | //遍历整合,得到每个类的所有方法实现,形成 类->实现的方法集 的映射 58 | Map> methodsByClass = getMethodsByClass(methodMap); 59 | 60 | //遍历继承关系数据,形成 父类->子孙类集 的映射 61 | Map> subClassMap = new HashMap<>(); 62 | for (Map.Entry> entry : inheritanceMap.entrySet()) { 63 | for (ClassReference.Handle parent : entry.getValue()) { 64 | if (!subClassMap.containsKey(parent)) { 65 | Set subClasses = new HashSet<>(); 66 | subClasses.add(entry.getKey()); 67 | subClassMap.put(parent, subClasses); 68 | } else { 69 | subClassMap.get(parent).add(entry.getKey()); 70 | } 71 | } 72 | } 73 | 74 | //遍历所有方法,根据父类->子孙类集合,找到所有的override的方法,记录下来(某个类的方法->所有的override方法) 75 | Map> methodImplMap = new HashMap<>(); 76 | for (MethodReference method : methodMap.values()) { 77 | // Static methods cannot be overriden 78 | if (method.isStatic()) { 79 | continue; 80 | } 81 | 82 | Set overridingMethods = new HashSet<>(); 83 | Set subClasses = subClassMap.get(method.getClassReference()); 84 | if (subClasses != null) { 85 | for (ClassReference.Handle subClass : subClasses) { 86 | // This class extends ours; see if it has a matching method 87 | Set subClassMethods = methodsByClass.get(subClass); 88 | if (subClassMethods != null) { 89 | for (MethodReference.Handle subClassMethod : subClassMethods) { 90 | if (subClassMethod.getName().equals(method.getName()) && subClassMethod.getDesc().equals(method.getDesc())) { 91 | overridingMethods.add(subClassMethod); 92 | } 93 | } 94 | } 95 | } 96 | } 97 | 98 | if (overridingMethods.size() > 0) { 99 | methodImplMap.put(method.getHandle(), overridingMethods); 100 | } 101 | } 102 | 103 | return methodImplMap; 104 | } 105 | 106 | public static Map> getMethodsByClass( 107 | Map methodMap) { 108 | Map> methodsByClass = new HashMap<>(); 109 | for (MethodReference.Handle method : methodMap.keySet()) { 110 | ClassReference.Handle classReference = method.getClassReference(); 111 | if (!methodsByClass.containsKey(classReference)) { 112 | Set methods = new HashSet<>(); 113 | methods.add(method); 114 | methodsByClass.put(classReference, methods); 115 | } else { 116 | methodsByClass.get(classReference).add(method); 117 | } 118 | } 119 | return methodsByClass; 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/main/java/Service/onlySinkParseServerice2.java: -------------------------------------------------------------------------------- 1 | package Service; 2 | 3 | import Util.WriteUtil; 4 | import asm.VulnClassVisitor; 5 | import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream; 6 | import model.*; 7 | import org.objectweb.asm.ClassReader; 8 | 9 | import java.io.ByteArrayInputStream; 10 | import java.io.ObjectInputStream; 11 | import java.io.ObjectOutputStream; 12 | import java.io.Serializable; 13 | import java.nio.file.Paths; 14 | import java.util.*; 15 | 16 | public class onlySinkParseServerice2 { 17 | private final Map classFileByName; 18 | private final model.InheritanceMap InheritanceMap; 19 | private final Map> methodCall; 20 | private final Map methodMap; 21 | private final Map classMap; 22 | 23 | private Map> methodImplCall = new HashMap<>(); 24 | 25 | private final List> Sinks; 26 | 27 | private List SaveSinkList = new ArrayList<>(); 28 | 29 | private int VulnNumber = 1; 30 | private boolean Save; 31 | 32 | 33 | public onlySinkParseServerice2(Map classFileByName, InheritanceMap InheritanceMap, Map> methodCall, 34 | Map methodMap, Map classMap, List> Sinks,Boolean Save){ 35 | this.classFileByName = classFileByName; 36 | this.InheritanceMap = InheritanceMap; 37 | this.methodCall = methodCall; 38 | this.methodMap = methodMap; 39 | this.classMap =classMap; 40 | this.Sinks = Sinks; 41 | this.Save = Save; 42 | } 43 | 44 | public void start(){ 45 | preparemethodCall(methodMap); 46 | doDiscover(Sinks); 47 | } 48 | 49 | 50 | 51 | private void preparemethodCall(Map methodMap){ 52 | Map> methodImplMap = InheritanceService.getAllMethodImplementations(InheritanceMap, methodMap); 53 | methodImplCall = clone(methodCall); 54 | for (Map.Entry> entry: methodCall.entrySet()){ 55 | for(MethodReference.Handle TargetMethod: entry.getValue()){ 56 | ClassReference.Handle handle = TargetMethod.getClassReference(); 57 | ClassReference classReference = classMap.get(handle); 58 | if (classReference != null && (classReference.isInterface()||classReference.isAbstract())){ 59 | Set methodImp = methodImplMap.get(TargetMethod); 60 | if(methodImp!=null){ 61 | for ( MethodReference.Handle a : methodImp ){ 62 | methodImplCall.get(TargetMethod).add(a); 63 | } 64 | } 65 | } 66 | } 67 | } 68 | } 69 | 70 | 71 | 72 | public void doDiscover(List> Sinks){ 73 | for(List sink : Sinks){ 74 | for(Map.Entry> entry:methodImplCall.entrySet()) { 75 | for (MethodReference.Handle method : entry.getValue()) { 76 | if (sink.size() == 1 && isFirstSink(sink, method) && !entry.getKey().getClassReference().getName().equals(sink.get(0).getClassName())) { 77 | System.out.println(); 78 | System.out.println("[" + VulnNumber + "] detect vuln: " + sink.get(0).getSinkName() + " Name: " + sink.get(0).getName()); 79 | System.out.println("location is:" + entry.getKey().getClassReference().getName() + ":" + entry.getKey().getName()); 80 | VulnNumber++; 81 | SaveSinkList.add(entry.getKey()); 82 | } 83 | if (sink.size() != 1 && isFirstSink(sink, method)) { 84 | ClassFile file = classFileByName.get(entry.getKey().getClassReference().getName()); 85 | VulnClassVisitor dcv = new VulnClassVisitor(entry.getKey(), sink); 86 | ClassReader cr = new ClassReader(file.getFile()); 87 | cr.accept(dcv, ClassReader.EXPAND_FRAMES); 88 | if (dcv.getVulnFlag() == sink.size() && !entry.getKey().getClassReference().getName().equals(sink.get(0).getClassName())) { 89 | System.out.println(); 90 | System.out.println("[" + VulnNumber + "] detect vuln: " + sink.get(0).getSinkName() + " Name: " + sink.get(0).getName()); 91 | System.out.println("location is:" + entry.getKey().getClassReference().getName() + ":" + entry.getKey().getName()); 92 | VulnNumber++; 93 | SaveSinkList.add(entry.getKey()); 94 | } 95 | } 96 | } 97 | } 98 | } 99 | if(Save==true){ 100 | WriteUtil.SaveSinkRule(Paths.get("SinkRule.dat"),SaveSinkList); 101 | } 102 | } 103 | 104 | 105 | 106 | public boolean isFirstSink(List sinks,MethodReference.Handle targetMethod){ 107 | /*System.out.println("SinkName:"+sinks.get(0).getName()+" targetMethodName:"+targetMethod.getName()+ 108 | " SinkClass:"+sinks.get(0).getClassName()+"targetMethodClass:"+targetMethod.getClassReference().getName()+ "sinkDec:"+sinks.get(0).getDesc() 109 | +" sinkTarget:Index:"+ sinks.get(0).getTargetIndex());*/ 110 | if(sinks.get(0).getName().equals(targetMethod.getName())&&sinks.get(0).getClassName().equals(targetMethod.getClassReference().getName())&& 111 | (sinks.get(0).getDesc().equals(targetMethod.getDesc())||sinks.get(0).getDesc().equals("*"))){ 112 | return true; 113 | } 114 | return false; 115 | } 116 | 117 | 118 | private T clone(Map obj) { 119 | T cloneObj = null; 120 | try { 121 | ByteOutputStream bos = new ByteOutputStream(); 122 | ObjectOutputStream oos = new ObjectOutputStream(bos); 123 | oos.writeObject(obj); 124 | oos.close(); 125 | ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); 126 | ObjectInputStream ois = new ObjectInputStream(bis); 127 | cloneObj = (T) ois.readObject(); 128 | ois.close(); 129 | } catch (Exception e) { 130 | e.printStackTrace(); 131 | } 132 | return cloneObj; 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/main/java/Service/SinkParseService.java: -------------------------------------------------------------------------------- 1 | package Service; 2 | 3 | import Util.StackUtil; 4 | import Util.WriteUtil; 5 | import model.*; 6 | 7 | import java.nio.file.Paths; 8 | import java.util.*; 9 | 10 | public class SinkParseService { 11 | private final model.InheritanceMap InheritanceMap; 12 | private final Map> methodCall; 13 | private final Map methodMap; 14 | private final Map MethodByNameMap = new HashMap<>(); 15 | private final Map classMap; 16 | 17 | private Map> methodImplCall = new HashMap<>(); 18 | private Map> submethodImplCallMap = new HashMap<>(); 19 | private final List> Sinks; 20 | private List> stacks; 21 | private HashMap hashcodeMap = new HashMap<>(); 22 | private int hashCode; 23 | 24 | public SinkParseService(InheritanceMap InheritanceMap, Map> methodCall, 25 | Map methodMap, Map classMap, List> Sinks,List> stacks){ 26 | this.InheritanceMap = InheritanceMap; 27 | this.methodCall = methodCall; 28 | this.methodMap = methodMap; 29 | this.classMap = classMap; 30 | this.Sinks = Sinks; 31 | this.stacks = stacks; 32 | } 33 | 34 | public void start(){ 35 | preparemethodCall(methodMap); 36 | doDiscover(Sinks); 37 | } 38 | private void preparemethodCall(Map methodMap){ 39 | Map> methodImplMap = InheritanceService.getAllMethodImplementations(InheritanceMap, methodMap); 40 | methodImplCall = StackUtil.clone(methodCall); 41 | for (Map.Entry> entry: methodCall.entrySet()){ 42 | for(MethodReference.Handle TargetMethod: entry.getValue()){ 43 | ClassReference.Handle handle = TargetMethod.getClassReference(); 44 | ClassReference classReference = classMap.get(handle); 45 | if (classReference != null && (classReference.isInterface()||classReference.isAbstract())){ 46 | Set methodImp = methodImplMap.get(TargetMethod); 47 | if(methodImp!=null){ 48 | for ( MethodReference.Handle a : methodImp ){ 49 | methodImplCall.get(TargetMethod).add(a); 50 | } 51 | } 52 | } 53 | } 54 | } 55 | for (Map.Entry> entry: methodImplCall.entrySet()) { 56 | for (MethodReference.Handle TargetMethod : entry.getValue()) { 57 | CallGraph callGraph = new CallGraph(TargetMethod,entry.getKey()); 58 | if (!this.submethodImplCallMap.containsKey(TargetMethod)) { 59 | Set graphCalls = new HashSet<>(); 60 | graphCalls.add(callGraph); 61 | this.submethodImplCallMap.put(TargetMethod, graphCalls); 62 | } else{ 63 | this.submethodImplCallMap.get(TargetMethod).add(callGraph); 64 | } 65 | } 66 | } 67 | 68 | WriteUtil.SavecallGraphMap(Paths.get("submethodImplCallMap.dat"),submethodImplCallMap); 69 | for(Map.Entry> entry:methodImplCall.entrySet()){ 70 | if (!MethodByNameMap.containsKey(entry.getKey().hashCode())) { 71 | hashcodeMap.put(entry.getKey().hashCode()-entry.getKey().getDesc().hashCode(),entry.getKey().hashCode()); 72 | MethodByNameMap.put(entry.getKey().hashCode(), entry.getKey()); 73 | for(MethodReference.Handle method: entry.getValue() ){ 74 | if(!MethodByNameMap.containsKey(method.hashCode())){ 75 | MethodByNameMap.put(method.hashCode(),method); 76 | hashcodeMap.put(method.hashCode()-method.getDesc().hashCode(),method.hashCode()); 77 | } 78 | } 79 | }else { 80 | for(MethodReference.Handle method: entry.getValue() ){ 81 | if(!MethodByNameMap.containsKey(method.hashCode())){ 82 | MethodByNameMap.put(method.hashCode(),method); 83 | hashcodeMap.put(method.hashCode()-method.getDesc().hashCode(),method.hashCode()); 84 | } 85 | } 86 | } 87 | } 88 | } 89 | 90 | 91 | 92 | 93 | public void doDiscover(List> Sinks){ 94 | for(List sink : Sinks){ 95 | if(sink.get(0).getDesc().equals("*")&&hashcodeMap.containsKey(sink.get(0).hashCode()-sink.get(0).getDesc().hashCode())){ 96 | int hashCode = this.hashcodeMap.get(sink.get(0).hashCode()-sink.get(0).getDesc().hashCode()); 97 | Set calls = submethodImplCallMap.get(MethodByNameMap.get(hashCode)); 98 | if(calls!=null){ 99 | for(CallGraph callGraph : calls){ 100 | LinkedList stack = new LinkedList<>(); 101 | stack.push(callGraph.getCallerMethod()); 102 | doTask(callGraph.getTargetMethod(), stack); 103 | stack.pop(); 104 | } 105 | } 106 | }else if(!sink.get(0).getDesc().equals("*")){ 107 | int hashCode = sink.get(0).hashCode(); 108 | Set calls = submethodImplCallMap.get(MethodByNameMap.get(hashCode)); 109 | if(calls!=null){ 110 | for(CallGraph callGraph : calls){ 111 | LinkedList stack = new LinkedList<>(); 112 | stack.push(callGraph.getCallerMethod()); 113 | doTask(callGraph.getTargetMethod(), stack); 114 | stack.pop(); 115 | } 116 | } 117 | } 118 | } 119 | } 120 | 121 | private void doTask(MethodReference.Handle targetMethod, 122 | Deque stack) { 123 | if (stack.contains(targetMethod)) { 124 | stack.push(targetMethod); 125 | return; 126 | } 127 | stack.push(targetMethod); 128 | Set calls = submethodImplCallMap.get(targetMethod); 129 | if (calls == null || calls.size() == 0) { 130 | Deque copyStack = new LinkedList<>(stack); 131 | this.stacks.add(copyStack); 132 | return; 133 | } 134 | for (CallGraph callGraph : calls) { 135 | doTask(callGraph.getTargetMethod(), stack); 136 | stack.pop(); 137 | } 138 | } 139 | 140 | 141 | } 142 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # java_asm_parse: 2 | 3 | ## 引言: 4 | 5 | 因为之前看了4ra1n师傅和r2的文章,所以对自动化代码审计很感兴趣。所以自己也跟着两位师傅的文章学习了一下。当学习到污点分析这些内容的时候感觉还是很吃力,所以就自己一边看代码一边自己上手写了一下。感觉单纯只是看的话,还是不能了解整个过程。 6 | 7 | 具体学习的话,还是主要参考看的是两位师傅的文章: 8 | 9 | https://xz.aliyun.com/t/10433 10 | 11 | https://xz.aliyun.com/t/10756?page=5#toc-0 12 | 13 | 核心代码依旧是参考的两位师傅和gadget-inspector的核心代码: 14 | 15 | https://github.com/Er1cccc/ACAF 16 | 17 | https://github.com/JackOfMostTrades/gadgetinspector 18 | 19 | 但在实际使用这些工具去分析已经有的cve的时候,感觉使用效果并不是特别好,尤其是分析的时候,经常出现污点中断导致分析失效。而且感觉这种分析不是特别适合实际操作使用,比如分析一个spring web的时候就是我不使用污点分析,而是直接匹配sink点也很少出现匹配得到的情况。 20 | 21 | crilwa给我说java程序很复杂,soot或许比asm更适合一些抽象的分析。后续考虑去学习一下soot框架这些。 22 | 23 | 因为这是一个工具的介绍也就不多说学习上的讲解了,如果想学习还是多看看上面两个大佬的文章吧。这个工具只是我自己修复了点小bug和多增加了一点我想要的小功能吧。 24 | 25 | 26 | 27 | ## 工具使用 28 | 29 | ``` 30 | Options: 31 | -t, --Taint 32 | 【+】选择模式 模式一:使用污点分析 模式二:不使用污点分析 模式三:从sink逆推调用链 模式四:只分析源码中是否存在sink点 33 | Default: 0 34 | --all 35 | 【+】加载所有lib 36 | Default: false 37 | --draw 38 | 【+】画出调用图 39 | Default: false 40 | -h, --help 41 | Help Info 42 | --jdk 43 | 【+】使用jdk中的rt.jar 44 | Default: false 45 | -l, --lib 46 | 【+】需要扫描的jar包 47 | -ld, --libs 48 | 【+】需要扫描的jar包所在文件夹 49 | -m, --moudles 50 | 【+】选择sink规则 51 | -r, --rule 52 | 【+】加载sink自定义规则 53 | --source 54 | 【+】source选择 55 | --methodName 56 | --methodName 57 | 【+】想要搜寻方法 58 | --Save 59 | 【+】保存sink规则 60 | ``` 61 | 62 | 上面一一解释用法 63 | 64 | 1. **-t, --Taint** 65 | 66 | 【+】选择模式 模式一:使用污点分析 模式二:不使用污点分析 模式三:从sink逆推调用链 模式四 只分析源码中是否存在sink点 67 | 68 | -t 1 代表使用模式一,依此类推 69 | 70 | 2. **--all** 71 | 【+】加载所有lib 72 | 填上这个选项后会加载jar中的所有依赖的jar包 73 | 74 | 3. **-l, --lib** 75 | 【+】需要扫描的jar包 76 | 这里可以填上需要扫描的jar包,列如 -l 1.jar 2.jar 但是需要值得注意的是如果遇到1.jar中有com.test.Main这个类,并且2.jar中也有的时候会出现一些问题。 77 | 78 | 4. **-ld, --libs** 79 | 【+】需要扫描的jar包 80 | 这里可以填上需要扫描的jar包,列如 -l 1.jar 2.jar 但是需要值得注意的是如果遇到1.jar中有com.test.Main这个类,并且2.jar中也有的时候会出现一些问题。 81 | 82 | 5. **--jdk** 83 | 【+】使用jdk中的rt.jar 84 | 85 | 6. **-m, --moudles** 86 | 【+】选择sink规则 87 | 现在已经有 11 种规则 88 | 使用 -m all 是加载所有规则 89 | -m SSRF ssrf的规则 90 | -m XXE xxe的规则 91 | -m SQLI sql注入的规则 //这里有个尴尬的点,如果熟悉java中的sql注入的朋友应该不难发现,现在其实注入mybits的sql注入 应该更多的关注的是xml文件中的#参数。所以后续可能会去研究一下这里如何进行审计。不过好像 看到过有工具已经实现了。 92 | 93 | -m RCE 命令执行的规则 94 | 95 | -m FileRead 文件读取的规则 96 | 97 | -m JNDI JNDI注入的规则 98 | 99 | -m XSS XSS 的规则 //其实xss这个规则是之前想要看看jenkins插件的漏洞弄得,不适用于其他。而且感觉xss这类应该和 codeql自带规则一样,写成正则匹配方法名的形式。 100 | 101 | -m LDAP LDAP注入的规则 102 | 103 | -m ZIPSLIP zipslip的规则 104 | 105 | -m UNSERIALIZE 反序列化漏洞的规则 106 | 107 | ​ 以上漏洞的规则大部分都是从codeql中找到的,因为知识储备有限+对于codeql代码的不熟悉,所以有些规则可能我也弄错了,如果想看一下可以再下面这里找一下。而且相对于来说,诸如FileRead和SSRF或者ZIPSLIP这一类的规则误报率会非常搞。 108 | 109 | ![image-20220918202020590.png](https://img1.imgtp.com/2022/09/18/B3a5KoTD.png) 110 | 111 | ​ 当然也可以去codeql找自带的cwe规则 112 | 113 | 7. **-r, --rule** 114 | 115 | 【+】加载sink自定义规则 116 | 117 | 举个例子 118 | 119 | ``` 120 | java/lang/Runtime exec * Runtime-RCE -1 1 121 | javax/script/ScriptEngineManager getEngineByName * Script-RCE -1 2 122 | javax/script/ScriptEngine eval * Script-RCE -1 2 123 | ``` 124 | 125 | 第一项是classname,第二项是方法名,第三项是方法的入参描述,如果不了解可以直接填`*`,第四项是规则的名字,第五项是规则中期望的危险入参是第几个,比如exec(String a)我们的危险入参是a,就填1,如果不知道是几就填-1,第六项是多规则选项。比如我们拿上面的列子,需要上面第2和第3规则都存在才能说是漏洞存在,那么我们后面都填2。如果需要三个规则,那么我们就要准备三个规则的同时后面最后一项都填3,再举例子,比如这之后我再有一个规则,只要规则存在就定义为漏洞,那么后面填1。如果需要五个规则同时存在,那么后面就填5。 126 | 127 | 储存在txt文件中,使用-r 1.txt 128 | 129 | 7. **--source** 130 | 131 | 【+】source选择 132 | 因为这里还没有设置一些source,我这里设置source因为不像前面几个师傅们一样专注于spring-web,所以我这里直接使用了正则匹配方法名来设置,这里设置了专门匹配do开头后面接一个大写字母,然后任意字母这样的规则,比如doMain这样的方法来收集source。~~这样确实很简陋,但是可以一步步改进,后面弄个,从外部接受规则~~ 133 | 134 | ~~现在如果想要使用的话,还是需要自己去源码中的`SourceClassVisitor` 自行更改正则规则~~ 135 | 136 | - ![image-20220918205554347.png](https://img1.imgtp.com/2022/09/18/UNXNG5RE.png) 137 | 138 | 使用 139 | 140 | ``` 141 | --source "这里填正则来匹配方法名" 142 | ``` 143 | 144 | 或许后面还可以用添加一些其他的方法来使用,比如有个函数在其内部有接收数据的方法就给其添加上。 145 | 146 | 9. --methodName 147 | 【+】想要搜寻方法 148 | 这个方法是有些时候在工具的使用中需要知道方法的入参描述。就可以单独使用 149 | 150 | ``` 151 | java -jar java_asm_parse-1.0-SNAPSHOT.jar -l 1.jar --methodName "RCEtest" 152 | ``` 153 | 154 | 那么就会把所有名字叫RCEtest的函数入参描述输出。 155 | 156 | 10. --Save 157 | 【+】保存sink规则 158 | 这个选项主要是为了在模式四中,根据已有的规则来得到的调用了该规则的方法。这样做是实际在做的时候,可以先筛选一遍减少无用链子。 159 | 160 | 161 | 162 | 163 | 164 | ## 使用例子 165 | 166 | 因为之前师傅们都是自己搭建的一个漏洞比较明显的环境来测试,我这里就不这样弄了,因为想试试在复杂环境中asm的污点分析这些还能不能用。 167 | 168 | 我这里找了一个调用链比较少的漏洞来做漏洞 169 | 170 | 这里使用CVE-2022-33980来做例子, 171 | 172 | ![image-20220918205053447.png](https://img1.imgtp.com/2022/09/18/TYoKPN7i.png) 173 | 174 | 环境我也会放在test文件夹中,可以自己下载测试。 175 | 176 | ``` 177 | java -jar java_asm_parse-1.0-SNAPSHOT.jar -l CVE-2022-33980-1.0-SNAPSHOT.jar --all -m RCE -t 1 178 | ``` 179 | 180 | 使用污点分析 181 | 182 | - ![image-20221004141902126.png](https://img1.imgtp.com/2022/10/04/evsER6XP.png) 183 | 184 | 得到四条链子,但是只有第一条链子有用,其余三条链子出现误报。为什么会出现这种误报?之所以会产生这种误报,主要是调用实现类无法在静态分析中直接得出,所以会在中途将该抽象类的所有实现类都遍历一遍。 185 | 186 | 187 | 188 | 在之前版本中,使用模式一是得不到结果的。 189 | 190 | 跟踪分析了一下 191 | 192 | 发现数据流在,数组这里断掉了。 193 | 194 | ![1.png](https://s2.loli.net/2022/09/29/n1rftaxs4pgHho2.png) 195 | 196 | 197 | 198 | 写了一个如下列子来测试 199 | 200 | - ![1111.png](https://img1.imgtp.com/2022/10/04/9wh5aOUe.png) 201 | 202 | ![222.png](https://img1.imgtp.com/2022/10/04/JGWjMy9z.png) 203 | 204 | 205 | 206 | 后来改了一下模拟帧栈的核心类,AALLOAD这里,发现污点能继续传递下去了。 207 | 208 | - ![3333.png](https://img1.imgtp.com/2022/10/04/CA4eaUlO.png) 209 | 210 | 211 | 212 | 213 | 214 | 模式2 不使用污点分析 215 | 216 | ``` 217 | java -jar java_asm_parse.jar --jar CVE-2022-33980-1.0-SNAPSHOT.jar --all -m RCE -t 2 218 | ``` 219 | 220 | - ![image-20221004143920726.png](https://img1.imgtp.com/2022/10/04/VXn9iMbd.png) 221 | 222 | 这样也能找到,但是呢还是会出现一些问题,相比较于模式一,首先链子普遍要长很多,很多也不准确相差比较大。但是会提供更多的路径。同样的,与模式1一样,还是会出现,关于抽象类与实现类遍历的问题。 223 | 224 | 225 | 226 | 模式三 从sink逆推调用链 227 | 228 | ``` 229 | java -jar java_asm_parse.jar -l CVE-2022-33980-1.0-SNAPSHOT.jar --all -m RCE -t 3 230 | ``` 231 | 232 | 这个功能实在是一言难尽,太多了一弄就是几十个结果,根本没法看。如果真的想要使用的话,可能后期得配合neo4j数据库得到cha调用图或者使用别的优化方法才能够使用。 233 | 这里找了个老项目拿来改了一下,https://github.com/masters-info-nantes/bytecode-to-cfg 234 | 能生成调用图了,后面命令的最后需要加一个--draw,但是生成的调用图并不好看。使用的时候需要将生成的jar文件与html文件夹放在一个目录下。 235 | [![xEx7y6.png](https://s1.ax1x.com/2022/09/26/xEx7y6.png)](https://imgse.com/i/xEx7y6) 236 | 237 | 模式三这种将所有方法都定义为sourc。逆推链子得到的数据会变得极为庞大且不适用。所以做了个小优化,将链子最后的方法进行分类,然后将这个分类中最短的链子输出。其余链子放在了Stack.dat文件中,若想比对也可以使用。 238 | 239 | 这里拿最近的CVE-2022-41852做个例子 240 | 241 | - ![image-20221013092920050.png](https://img1.imgtp.com/2022/10/13/WKNFnjZo.png) 242 | 243 | - ![image-20221013093112464.png](https://img1.imgtp.com/2022/10/13/60k2SzDF.png) 244 | 245 | 246 | 247 | 又或者拿昨天有师傅看到得 248 | 249 | apache.commons.text 250 | 251 | - ![image-20221013093640368.png](https://img1.imgtp.com/2022/10/13/eIGlMvGO.png) 252 | 253 | 虽然这个是在看CVE-2022-33980也发现了得,但是当时也没注意。 254 | 255 | 以上给出得例子,链子都不是特别复杂,在更多得分析当中,模式三可能并不适用 256 | 257 | 258 | 259 | 260 | 261 | 模式四 只分析源码中是否存在sink点 262 | 263 | 这里用使用log4j2存在漏洞的版本来做个例子,我将jar包全部储存在一个文件夹中。 264 | 265 | 使用 266 | 267 | ``` 268 | java -jar java_asm_parse-1.0-SNAPSHOT.jar -ld SSS --all -m JNDI -t 42 269 | ``` 270 | 271 | - ![image-20221004144527968.png](https://img1.imgtp.com/2022/10/04/pNOwKBOJ.png) 272 | 273 | 可以看到找到了漏洞sink点 274 | 275 | -------------------------------------------------------------------------------- /src/main/java/Util/WriteUtil.java: -------------------------------------------------------------------------------- 1 | package Util; 2 | 3 | import com.google.common.io.Files; 4 | import model.CallGraph; 5 | import model.ClassReference; 6 | import model.MethodReference; 7 | 8 | import java.io.BufferedWriter; 9 | import java.io.IOException; 10 | import java.nio.charset.StandardCharsets; 11 | import java.nio.file.Path; 12 | import java.util.Deque; 13 | import java.util.List; 14 | import java.util.Map; 15 | import java.util.Set; 16 | 17 | public class WriteUtil { 18 | public static void SaveSortedMethods(Path filePath,List sortedMethods){ 19 | try (BufferedWriter writer = Files.newWriter(filePath.toFile(), StandardCharsets.UTF_8)) { 20 | StringBuilder sb = new StringBuilder(); 21 | for (MethodReference.Handle method : sortedMethods) { 22 | String MethodName =method.getName(); 23 | String ClassName =method.getClassReference().getName(); 24 | if (method == null) { 25 | sb.append("\n"); 26 | } else { 27 | sb.append("\n").append(ClassName).append("#").append(MethodName); 28 | } 29 | } 30 | writer.write(sb.substring(1)); 31 | writer.write("\n"); 32 | } catch (IOException e) { 33 | throw new RuntimeException(e); 34 | } 35 | }; 36 | 37 | public static void SaveAllClass(Path filePath, Map classMap) { 38 | try (BufferedWriter writer = Files.newWriter(filePath.toFile(), StandardCharsets.UTF_8)) { 39 | StringBuilder sb = new StringBuilder(); 40 | for (Map.Entry entry: classMap.entrySet()) { 41 | String ClassName = entry.getKey().getName(); 42 | if (ClassName == null) { 43 | sb.append("\n"); 44 | } else { 45 | sb.append("\n").append(ClassName); 46 | } 47 | } 48 | writer.write(sb.substring(1)); 49 | writer.write("\n"); 50 | } catch (IOException e) { 51 | throw new RuntimeException(e); 52 | } 53 | }; 54 | 55 | public static void SaveMethodCall(Path filePath, Map> methodCall) { 56 | try (BufferedWriter writer = Files.newWriter(filePath.toFile(), StandardCharsets.UTF_8)) { 57 | StringBuilder sb = new StringBuilder(); 58 | for (Map.Entry> entry: methodCall.entrySet()) { 59 | String MethodName = entry.getKey().getName(); 60 | sb.append("\n").append(entry.getKey().getClassReference().getName()).append("#").append(MethodName).append("(").append(entry.getKey().getDesc()).append(")"); 61 | for(MethodReference.Handle TargetMethod: entry.getValue()){ 62 | String TargetMethodName = TargetMethod.getName(); 63 | if (TargetMethodName == null) { 64 | sb.append("\n"); 65 | } else { 66 | sb.append("\n\t").append(TargetMethod.getClassReference().getName()).append("#").append(TargetMethodName).append("(").append(TargetMethod.getDesc()).append(")"); 67 | } 68 | } 69 | } 70 | writer.write(String.valueOf(sb)); 71 | writer.write("\n"); 72 | } catch (IOException e) { 73 | throw new RuntimeException(e); 74 | } 75 | } 76 | 77 | public static void SavePassthroughs(Path filePath, Map> passthroughDataflow) { 78 | try (BufferedWriter writer = Files.newWriter(filePath.toFile(), StandardCharsets.UTF_8)) { 79 | StringBuilder sb = new StringBuilder(); 80 | for (Map.Entry> entry: passthroughDataflow.entrySet()) { 81 | String MethodName = entry.getKey().getName(); 82 | String ClassName = entry.getKey().getClassReference().getName(); 83 | sb.append("\n").append(ClassName).append("\t").append(MethodName).append("\t"); 84 | if (entry.getValue() != null) { 85 | sb.append("\n"); 86 | }else { 87 | sb.append(entry.getValue()); 88 | } 89 | } 90 | writer.write(String.valueOf(sb)); 91 | writer.write("\n"); 92 | } catch (IOException e) { 93 | throw new RuntimeException(e); 94 | } 95 | } 96 | 97 | public static void SavecallGraphMap(Path filePath, Map> callGraphMap) { 98 | try (BufferedWriter writer = Files.newWriter(filePath.toFile(), StandardCharsets.UTF_8)) { 99 | StringBuilder sb = new StringBuilder(); 100 | for (Map.Entry> entry: callGraphMap.entrySet()) { 101 | String MethodName = entry.getKey().getName(); 102 | String ClassName = entry.getKey().getClassReference().getName(); 103 | sb.append(ClassName).append("#").append(MethodName).append(":").append("\n"); 104 | for(CallGraph CallGraph : entry.getValue()) { 105 | sb.append("\t").append(CallGraph.getCallerMethod().getName()).append("==>") 106 | .append(CallGraph.getTargetMethod().getClassReference().getName()).append("#").append(CallGraph.getTargetMethod().getName()).append("\t") 107 | .append(CallGraph.getCallerArgIndex()).append("\t").append(CallGraph.getTargetArgIndex()).append("\n"); 108 | } 109 | } 110 | writer.write(String.valueOf(sb)); 111 | writer.write("\n"); 112 | } catch (IOException e) { 113 | throw new RuntimeException(e); 114 | } 115 | } 116 | 117 | public static void SavemethodImplMap(Path filePath, Map> methodImplMap) { 118 | try (BufferedWriter writer = Files.newWriter(filePath.toFile(), StandardCharsets.UTF_8)) { 119 | StringBuilder sb = new StringBuilder(); 120 | for (Map.Entry> entry: methodImplMap.entrySet()) { 121 | String MethodName = entry.getKey().getName(); 122 | String ClassName = entry.getKey().getClassReference().getName(); 123 | 124 | sb.append(ClassName).append("#").append(MethodName).append(":").append("\n"); 125 | for(MethodReference.Handle Method : entry.getValue()) { 126 | sb.append("\t").append(Method.getClassReference().getName()).append("#").append(Method.getName()).append("\n"); 127 | } 128 | } 129 | writer.write(String.valueOf(sb)); 130 | writer.write("\n"); 131 | } catch (IOException e) { 132 | throw new RuntimeException(e); 133 | } 134 | } 135 | 136 | public static void SaveSinkRule(Path filePath, List SinkList){ 137 | try (BufferedWriter writer = Files.newWriter(filePath.toFile(), StandardCharsets.UTF_8)) { 138 | StringBuilder sb = new StringBuilder(); 139 | for (MethodReference.Handle Sink: SinkList) { 140 | String MethodName = Sink.getName(); 141 | String ClassName = Sink.getClassReference().getName(); 142 | String desc = Sink.getDesc(); 143 | sb.append(ClassName).append(" ").append(MethodName).append(" ").append(desc).append(" sinkName 1 1").append("\n"); 144 | } 145 | writer.write(String.valueOf(sb)); 146 | } catch (IOException e) { 147 | throw new RuntimeException(e); 148 | } 149 | } 150 | 151 | } 152 | -------------------------------------------------------------------------------- /src/main/java/Service/NoTaintChainDiscoverService.java: -------------------------------------------------------------------------------- 1 | package Service; 2 | 3 | import Util.WriteUtil; 4 | import asm.VulnClassVisitor; 5 | import model.*; 6 | import org.objectweb.asm.ClassReader; 7 | 8 | import java.nio.file.Paths; 9 | import java.util.*; 10 | 11 | public class NoTaintChainDiscoverService { 12 | private final Map classFileByName; 13 | private final InheritanceMap InheritanceMap; 14 | private final Map> methodCall; 15 | private final Map methodMap; 16 | private final Map classMap; 17 | 18 | private final Map> methodImplCall = new HashMap<>(); 19 | private Map> methodImplCallMap; 20 | private final List Sources; 21 | 22 | private final List> Sinks; 23 | private final List> stacks; 24 | 25 | public NoTaintChainDiscoverService(Map classFileByName, InheritanceMap InheritanceMap, Map> methodCall, 26 | Map methodMap, Map classMap, List Sources, List> Sinks,List> stacks){ 27 | this.classFileByName = classFileByName; 28 | this.InheritanceMap = InheritanceMap; 29 | this.methodCall = methodCall; 30 | this.methodMap = methodMap; 31 | this.classMap =classMap; 32 | this.Sources = Sources; 33 | this.Sinks = Sinks; 34 | this.stacks = stacks; 35 | } 36 | 37 | public void start(){ 38 | methodImplCallMap = preparemethodCall(methodMap); 39 | doDiscover(Sources,Sinks); 40 | } 41 | 42 | 43 | 44 | private Map> preparemethodCall(Map methodMap){ 45 | Map> methodImplCallMap = new HashMap<>(); 46 | Map> methodImplMap = InheritanceService.getAllMethodImplementations(InheritanceMap, methodMap); 47 | methodImplCall.putAll(methodCall); 48 | for (Map.Entry> entry: methodCall.entrySet()){ 49 | for(MethodReference.Handle TargetMethod: entry.getValue()){ 50 | ClassReference.Handle handle = TargetMethod.getClassReference(); 51 | ClassReference classReference = classMap.get(handle); 52 | if (classReference != null && (classReference.isInterface()||classReference.isAbstract())) { 53 | Set methodImp = methodImplMap.get(TargetMethod); 54 | if(methodImp!=null){ 55 | for ( MethodReference.Handle a :methodImp){ 56 | methodImplCall.get(TargetMethod).add(a); 57 | } 58 | } 59 | } 60 | } 61 | } 62 | 63 | WriteUtil.SaveMethodCall(Paths.get("methodCall.dat"),methodImplCall); 64 | for (Map.Entry> entry: methodImplCall.entrySet()) { 65 | for (MethodReference.Handle TargetMethod : entry.getValue()) { 66 | CallGraph callGraph = new CallGraph(entry.getKey(),TargetMethod); 67 | if (!methodImplCallMap.containsKey(entry.getKey())) { 68 | Set graphCalls = new HashSet<>(); 69 | graphCalls.add(callGraph); 70 | methodImplCallMap.put(entry.getKey(), graphCalls); 71 | } else { 72 | methodImplCallMap.get(entry.getKey()).add(callGraph); 73 | } 74 | } 75 | } 76 | 77 | 78 | return methodImplCallMap; 79 | } 80 | 81 | public void doDiscover(List Sources , List> Sinks){ 82 | for(MethodReference Source : Sources){ 83 | System.out.println(Source.getName()); 84 | Set calls = methodImplCallMap.get(Source.getHandle()); 85 | if(calls!=null){ 86 | for(CallGraph callGraph : calls){ 87 | for(List sink : Sinks){ 88 | LinkedList stack = new LinkedList<>(); 89 | stack.push(callGraph.getCallerMethod()); 90 | doTask(callGraph.getCallerMethod(),callGraph.getTargetMethod(), stack,sink); 91 | stack.pop(); 92 | } 93 | } 94 | } 95 | } 96 | } 97 | 98 | 99 | private void doTask(MethodReference.Handle callerMethod,MethodReference.Handle targetMethod, 100 | Deque stack,List sinks) { 101 | if (stack.contains(targetMethod)) { 102 | stack.push(targetMethod); 103 | return; 104 | } 105 | if (sinks.size() == 1 && isFirstSink(sinks, targetMethod)) { 106 | System.out.println("[+] detect vuln: " + sinks.get(0).getName()); 107 | Deque copyStack = new LinkedList<>(stack); 108 | stacks.add(copyStack); 109 | printStackTrace(stack); 110 | } 111 | if (sinks.size() != 1 && isFirstSink(sinks, targetMethod)) { 112 | ClassFile file = classFileByName.get(callerMethod.getClassReference().getName()); 113 | VulnClassVisitor dcv = new VulnClassVisitor(callerMethod, sinks); 114 | ClassReader cr = new ClassReader(file.getFile()); 115 | cr.accept(dcv, ClassReader.EXPAND_FRAMES); 116 | if (dcv.getVulnFlag() == sinks.size()) { 117 | /*Set stackpushmethod = methodImplCall.get(callerMethod); 118 | for (int s = 1; s < sinks.size(); s++) { 119 | for (MethodReference.Handle a : stackpushmethod) { 120 | if ((a.getClassReference().getName() + a.getName()).equals(sinks.get(s).getClassName() + sinks.get(s).getName())) { 121 | stack.push(a); 122 | } 123 | } 124 | }*/ 125 | System.out.println("[+] detect vuln: " + sinks.get(0).getName()); 126 | Deque copyStack = new LinkedList<>(stack); 127 | stacks.add(copyStack); 128 | printStackTrace(stack); 129 | /*for (int s = 1; s == sinks.size(); s++) { 130 | stack.pop(); 131 | }*/ 132 | return; 133 | } 134 | } 135 | Set calls = methodImplCallMap.get(targetMethod); 136 | if (calls == null || calls.size() == 0) { 137 | return; 138 | } 139 | for (CallGraph callGraph : calls) { 140 | doTask(callGraph.getCallerMethod(), callGraph.getTargetMethod(), stack, sinks); 141 | stack.pop(); 142 | } 143 | } 144 | private void printStackTrace(Deque stack) { 145 | Deque copyStack = new LinkedList<>(stack); 146 | StringBuilder prefix=new StringBuilder("\t"); 147 | for (MethodReference.Handle handle : copyStack) { 148 | System.out.println(prefix+handle.getClassReference().getName()+"."+handle.getName()); 149 | prefix.append("\t"); 150 | } 151 | } 152 | 153 | public boolean isFirstSink(List sinks,MethodReference.Handle targetMethod){ 154 | /*System.out.println("SinkName:"+sinks.get(0).getName()+" targetMethodName:"+targetMethod.getName()+ 155 | " SinkClass:"+sinks.get(0).getClassName()+"targetMethodClass:"+targetMethod.getClassReference().getName()+ "sinkDec:"+sinks.get(0).getDesc() 156 | +" sinkTarget:Index:"+ sinks.get(0).getTargetIndex());*/ 157 | if(sinks.get(0).getName().equals(targetMethod.getName())&&sinks.get(0).getClassName().equals(targetMethod.getClassReference().getName())&& 158 | (sinks.get(0).getDesc().equals(targetMethod.getDesc())||sinks.get(0).getDesc().equals("*"))){ 159 | return true; 160 | } 161 | return false; 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /src/main/java/Service/onlySinkParseServerice.java: -------------------------------------------------------------------------------- 1 | package Service; 2 | 3 | import Util.WriteUtil; 4 | import app.Command; 5 | import asm.VulnClassVisitor; 6 | import model.*; 7 | import org.objectweb.asm.ClassReader; 8 | 9 | import java.nio.file.Paths; 10 | import java.util.*; 11 | 12 | public class onlySinkParseServerice { 13 | private final Map classFileByName; 14 | private final model.InheritanceMap InheritanceMap; 15 | private final Map methodMap; 16 | private Set discoveredCalls; 17 | private final Map classMap; 18 | private final List> Sinks; 19 | private final Map jarByClass; 20 | private List SaveSinkList = new ArrayList<>(); 21 | private int VulnNumber = 1; 22 | private boolean Save; 23 | 24 | 25 | public onlySinkParseServerice(Map classFileByName, InheritanceMap InheritanceMap, Set discoveredCalls, 26 | Map methodMap, Map classMap, List> Sinks, Map jarByClass, boolean Save){ 28 | this.classFileByName = classFileByName; 29 | this.InheritanceMap = InheritanceMap; 30 | this.methodMap = methodMap; 31 | this.discoveredCalls = discoveredCalls; 32 | this.classMap =classMap; 33 | this.Sinks = Sinks; 34 | this.jarByClass = jarByClass; 35 | this.Save = Save; 36 | } 37 | 38 | public void start(){ 39 | prepareCallGraphMap(methodMap); 40 | doDiscover(Sinks); 41 | } 42 | 43 | 44 | /* 45 | private void preparemethodCall(Map methodMap){ 46 | Map> methodImplMap = InheritanceService.getAllMethodImplementations(InheritanceMap, methodMap); 47 | WriteUtil.SavemethodImplMap(Paths.get("methodImplMap.dat"),methodImplMap); 48 | methodImplCall.putAll(methodCall); 49 | for (Map.Entry> entry: methodCall.entrySet()){ 50 | for(MethodReference.Handle TargetMethod: entry.getValue()){ 51 | ClassReference.Handle handle = TargetMethod.getClassReference(); 52 | ClassReference classReference = classMap.get(handle); 53 | if (classReference != null && classReference.isInterface()) { 54 | Set methodImp = methodImplMap.get(TargetMethod); 55 | if(methodImp!=null){ 56 | for ( MethodReference.Handle a :methodImp){ 57 | methodImplCall.get(TargetMethod).add(a); 58 | } 59 | } 60 | } 61 | } 62 | } 63 | WriteUtil.SaveMethodCall(Paths.get("methodImpCall.dat"),methodImplCall); 64 | } 65 | */ 66 | 67 | private void prepareCallGraphMap(Map methodMap) { 68 | 69 | Map> methodImplMap = InheritanceService.getAllMethodImplementations(InheritanceMap, methodMap); 70 | WriteUtil.SavemethodImplMap(Paths.get("methodImplMap.dat"), methodImplMap); 71 | 72 | List tempList = new ArrayList<>(discoveredCalls); 73 | for (int i = 0; i < discoveredCalls.size(); i++) { 74 | CallGraph edge = tempList.get(i); 75 | ClassReference.Handle handle = edge.getTargetMethod().getClassReference(); 76 | ClassReference classReference = classMap.get(handle); 77 | if (classReference != null && (classReference.isInterface()||classReference.isAbstract())) { 78 | Set implSet = methodImplMap.get(edge.getTargetMethod()); 79 | if (implSet == null || implSet.size() == 0) { 80 | continue; 81 | } 82 | for (MethodReference.Handle methodHandle : implSet) { 83 | String callerDesc = methodMap.get(methodHandle).getDesc(); 84 | if (edge.getTargetMethod().getDesc().equals(callerDesc)) { 85 | tempList.add(new CallGraph( 86 | edge.getCallerMethod(), 87 | methodHandle, 88 | edge.getCallerArgIndex(), 89 | edge.getTargetArgIndex() 90 | )); 91 | } 92 | } 93 | } 94 | } 95 | discoveredCalls.clear(); 96 | discoveredCalls.addAll(tempList); 97 | } 98 | 99 | public void doDiscover(List> Sinks){ 100 | for(List sink : Sinks){ 101 | List VistedMethod = new ArrayList<>(); 102 | for(CallGraph CallGraph:discoveredCalls) { 103 | if (!VistedMethod.contains(CallGraph.getCallerMethod().hashCode()+CallGraph.getTargetMethod().hashCode())) { 104 | if (sink.size() == 1 && isFirstSink(sink, CallGraph.getTargetMethod()) && isblacklist(CallGraph.getCallerMethod().getClassReference().getName(), sink.get(0).getClassName())) { 105 | System.out.println(); 106 | System.out.println("[" + VulnNumber + "] detect vuln: " + sink.get(0).getSinkName() + " Name: " + sink.get(0).getName()); 107 | System.out.println("jar is: " + jarByClass.get(CallGraph.getCallerMethod().getClassReference().getName())); 108 | System.out.println("location is: " + CallGraph.getCallerMethod().getClassReference().getName() + ":" + CallGraph.getCallerMethod().getName()); 109 | VulnNumber++; 110 | SaveSinkList.add(CallGraph.getCallerMethod()); 111 | } 112 | if (sink.size() != 1 && isFirstSink(sink, CallGraph.getTargetMethod()) && isblacklist(CallGraph.getCallerMethod().getClassReference().getName(), sink.get(0).getClassName())) { 113 | ClassFile file = classFileByName.get(CallGraph.getCallerMethod().getClassReference().getName()); 114 | VulnClassVisitor dcv = new VulnClassVisitor(CallGraph.getCallerMethod(), sink); 115 | ClassReader cr = new ClassReader(file.getFile()); 116 | cr.accept(dcv, ClassReader.EXPAND_FRAMES); 117 | if (dcv.getVulnFlag() == sink.size() && !CallGraph.getCallerMethod().getClassReference().getName().equals(sink.get(0).getClassName())) { 118 | System.out.println(); 119 | System.out.println("[" + VulnNumber + "] detect vuln: " + sink.get(0).getSinkName() + " Name: " + sink.get(0).getName()); 120 | System.out.println("jar is: " + jarByClass.get(CallGraph.getCallerMethod().getClassReference().getName())); 121 | System.out.println("location is:" + CallGraph.getCallerMethod().getClassReference().getName() + ":" + CallGraph.getCallerMethod().getName()); 122 | VulnNumber++; 123 | SaveSinkList.add(CallGraph.getCallerMethod()); 124 | } 125 | } 126 | } 127 | VistedMethod.add(CallGraph.getCallerMethod().hashCode()+CallGraph.getTargetMethod().hashCode()); 128 | } 129 | } 130 | if(Save==true){ 131 | WriteUtil.SaveSinkRule(Paths.get("SinkRule.dat"),SaveSinkList); 132 | } 133 | } 134 | 135 | 136 | 137 | public boolean isFirstSink(List sinks,MethodReference.Handle targetMethod){ 138 | /*System.out.println("SinkName:"+sinks.get(0).getName()+" targetMethodName:"+targetMethod.getName()+ 139 | " SinkClass:"+sinks.get(0).getClassName()+"targetMethodClass:"+targetMethod.getClassReference().getName()+ "sinkDec:"+sinks.get(0).getDesc() 140 | +" sinkTarget:Index:"+ sinks.get(0).getTargetIndex());*/ 141 | if(sinks.get(0).getName().equals(targetMethod.getName())&&sinks.get(0).getClassName().equals(targetMethod.getClassReference().getName())&& 142 | (sinks.get(0).getDesc().equals(targetMethod.getDesc())||sinks.get(0).getDesc().equals("*"))){ 143 | return true; 144 | } 145 | return false; 146 | } 147 | 148 | public boolean isblacklist(String ClassName,String sinkClassName){ 149 | int flag = 0; 150 | if(ClassName.equals(sinkClassName)){ 151 | flag++; 152 | } 153 | if(flag==0){ 154 | for(String black : blacklist){ 155 | if(ClassName.contains(black)){ 156 | flag++; 157 | break; 158 | } 159 | } 160 | } 161 | if(flag!=0){ 162 | return false; 163 | } else { 164 | return true; 165 | } 166 | } 167 | 168 | private final String[] blacklist = { 169 | "org/apache/naming/", 170 | "org/springframework/jmx/", 171 | "org/springframework/jndi/", 172 | "org/apache/catalina/" 173 | }; 174 | } 175 | -------------------------------------------------------------------------------- /src/main/java/Service/ChainDiscoverService.java: -------------------------------------------------------------------------------- 1 | package Service; 2 | 3 | import Util.WriteUtil; 4 | import asm.VulnClassVisitor; 5 | import model.*; 6 | import org.objectweb.asm.ClassReader; 7 | import org.objectweb.asm.Type; 8 | 9 | import java.nio.file.Paths; 10 | import java.util.*; 11 | 12 | public class ChainDiscoverService { 13 | private final Map classFileByName; 14 | private final InheritanceMap InheritanceMap; 15 | private final Set discoveredCalls; 16 | private final Map methodMap; 17 | private final Map classMap; 18 | private Map> callGraphMap; 19 | 20 | List Sources; 21 | 22 | List> Sinks; 23 | 24 | public ChainDiscoverService(Map classFileByName, InheritanceMap InheritanceMap,Set discoveredCalls, 25 | Map methodMap, Map classMap,List Sources,List> Sinks){ 26 | this.classFileByName = classFileByName; 27 | this.InheritanceMap = InheritanceMap; 28 | this.discoveredCalls = discoveredCalls; 29 | this.methodMap = methodMap; 30 | this.classMap =classMap; 31 | this.Sources = Sources; 32 | this.Sinks = Sinks; 33 | } 34 | 35 | 36 | public void start(){ 37 | callGraphMap = prepareCallGraphMap(methodMap); 38 | WriteUtil.SavecallGraphMap(Paths.get("callGraphMap.dat"),callGraphMap); 39 | doDiscover(Sources,Sinks); 40 | } 41 | 42 | 43 | private Map> prepareCallGraphMap(Map methodMap){ 44 | Map> graphCallMap=new HashMap<>(); 45 | 46 | Map> methodImplMap = InheritanceService.getAllMethodImplementations(InheritanceMap, methodMap); 47 | WriteUtil.SavemethodImplMap(Paths.get("methodImplMap.dat"),methodImplMap); 48 | 49 | List tempList = new ArrayList<>(discoveredCalls); 50 | for (int i = 0; i < discoveredCalls.size(); i++) { 51 | CallGraph edge = tempList.get(i); 52 | ClassReference.Handle handle = edge.getTargetMethod().getClassReference(); 53 | ClassReference classReference = classMap.get(handle); 54 | if (classReference != null && (classReference.isInterface()||classReference.isAbstract())) { 55 | Set implSet = methodImplMap.get(edge.getTargetMethod()); 56 | if (implSet == null || implSet.size() == 0) { 57 | continue; 58 | } 59 | for (MethodReference.Handle methodHandle : implSet) { 60 | String callerDesc = methodMap.get(methodHandle).getDesc(); 61 | if (edge.getTargetMethod().getDesc().equals(callerDesc)) { 62 | tempList.add(new CallGraph( 63 | edge.getCallerMethod(), 64 | methodHandle, 65 | edge.getCallerArgIndex(), 66 | edge.getTargetArgIndex() 67 | )); 68 | } 69 | } 70 | } 71 | } 72 | 73 | discoveredCalls.clear(); 74 | discoveredCalls.addAll(tempList); 75 | for (CallGraph graphCall : discoveredCalls) { 76 | MethodReference.Handle caller = graphCall.getCallerMethod(); 77 | if (!graphCallMap.containsKey(caller)) { 78 | Set graphCalls = new HashSet<>(); 79 | graphCalls.add(graphCall); 80 | graphCallMap.put(caller, graphCalls); 81 | } else { 82 | graphCallMap.get(caller).add(graphCall); 83 | } 84 | } 85 | return graphCallMap; 86 | } 87 | 88 | public void doDiscover(List Sources , List> Sinks){ 89 | for(MethodReference Source : Sources){ 90 | Type[] argTypes = Type.getArgumentTypes(Source.getDesc()); 91 | Type[] extendedArgTypes = new Type[argTypes.length + 1]; 92 | System.arraycopy(argTypes, 0, extendedArgTypes, 1, argTypes.length); 93 | argTypes = extendedArgTypes; 94 | boolean[] vulnerableIndex = new boolean[argTypes.length]; 95 | for (int i = 1; i < argTypes.length; i++) { 96 | if (!isPrimitive(argTypes[i])) { 97 | vulnerableIndex[i] = true; 98 | } 99 | } 100 | Set calls = callGraphMap.get(Source.getHandle()); 101 | if(calls == null || calls.size() ==0){ 102 | continue; 103 | } 104 | 105 | for (CallGraph callGraph : calls){ 106 | int callerIndex = callGraph.getCallerArgIndex(); 107 | if(callerIndex == -1){ 108 | continue; 109 | } 110 | if(vulnerableIndex[callerIndex]){ 111 | for(List sink : Sinks){ 112 | LinkedList stack = new LinkedList<>(); 113 | stack.push(callGraph.getCallerMethod()); 114 | doTask(callGraph.getCallerMethod(),callGraph.getTargetMethod(), callGraph.getTargetArgIndex(), stack,sink); 115 | } 116 | } 117 | } 118 | } 119 | } 120 | 121 | private boolean isPrimitive(Type argType) { 122 | int sort = argType.getSort(); 123 | return sort==Type.BYTE|| 124 | sort==Type.INT|| 125 | sort==Type.SHORT|| 126 | sort==Type.LONG|| 127 | sort==Type.FLOAT|| 128 | sort==Type.DOUBLE|| 129 | sort==Type.BOOLEAN|| 130 | sort==Type.CHAR; 131 | } 132 | 133 | 134 | private void doTask(MethodReference.Handle callerMethod,MethodReference.Handle targetMethod, int targetIndex, 135 | Deque stack,List sinks) { 136 | if (stack.contains(targetMethod)) { 137 | stack.push(targetMethod); 138 | return; 139 | } 140 | stack.push(targetMethod); 141 | if (sinks.size() == 1 && isFirstSink(sinks, targetMethod,targetIndex)) { 142 | System.out.println("[+] detect vuln: " + sinks.get(0).getName()); 143 | printStackTrace(stack); 144 | } 145 | if (sinks.size() != 1 && isFirstSink(sinks, targetMethod,targetIndex)) { 146 | ClassFile file = classFileByName.get(callerMethod.getClassReference().getName()); 147 | VulnClassVisitor dcv = new VulnClassVisitor(callerMethod, sinks); 148 | ClassReader cr = new ClassReader(file.getFile()); 149 | cr.accept(dcv, ClassReader.EXPAND_FRAMES); 150 | if (dcv.getVulnFlag() == sinks.size()) { 151 | /*Set stackpushmethod = methodImplCall.get(callerMethod); 152 | for (int s = 1; s < sinks.size(); s++) { 153 | for (MethodReference.Handle a : stackpushmethod) { 154 | if ((a.getClassReference().getName() + a.getName()).equals(sinks.get(s).getClassName() + sinks.get(s).getName())) { 155 | stack.push(a); 156 | } 157 | } 158 | }*/ 159 | System.out.println("[+] detect vuln: " + sinks.get(0).getName()); 160 | printStackTrace(stack); 161 | /*for (int s = 1; s == sinks.size(); s++) { 162 | stack.pop(); 163 | }*/ 164 | return; 165 | } 166 | } 167 | 168 | Set calls = callGraphMap.get(targetMethod); 169 | if (calls == null || calls.size() == 0) { 170 | return; 171 | } 172 | for (CallGraph callGraph : calls) { 173 | if (callGraph.getCallerArgIndex() == targetIndex && targetIndex != -1) { 174 | doTask(callGraph.getCallerMethod(),callGraph.getTargetMethod(), callGraph.getTargetArgIndex(), stack, sinks); 175 | stack.pop(); 176 | } 177 | } 178 | } 179 | 180 | private void printStackTrace(Deque stack) { 181 | Deque copyStack = new LinkedList<>(stack); 182 | StringBuilder prefix=new StringBuilder("\t"); 183 | for (MethodReference.Handle handle : copyStack) { 184 | System.out.println(prefix+handle.getClassReference().getName()+"."+handle.getName()); 185 | prefix.append("\t"); 186 | } 187 | System.out.println(); 188 | System.out.println(); 189 | } 190 | 191 | public boolean isFirstSink(List sinks,MethodReference.Handle targetMethod,int targetIndex){ 192 | /*System.out.println("SinkName:"+sinks.get(0).getName()+" targetMethodName:"+targetMethod.getName()+ 193 | " SinkClass:"+sinks.get(0).getClassName()+"targetMethodClass:"+targetMethod.getClassReference().getName()+ "sinkDec:"+sinks.get(0).getDesc() 194 | +" sinkTarget:Index:"+ sinks.get(0).getTargetIndex());*/ 195 | if(sinks.get(0).getName().equals(targetMethod.getName())&&sinks.get(0).getClassName().equals(targetMethod.getClassReference().getName())&& 196 | (sinks.get(0).getDesc().equals(targetMethod.getDesc())||sinks.get(0).getDesc().equals("*"))&& 197 | (sinks.get(0).getTargetIndex()==-1||targetIndex==sinks.get(0).getTargetIndex())){ 198 | return true; 199 | } 200 | return false; 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /html/vis.min.css: -------------------------------------------------------------------------------- 1 | .vis .overlay{position:absolute;top:0;left:0;width:100%;height:100%;z-index:10}.vis-active{box-shadow:0 0 10px #86d5f8}.vis.timeline.root{position:relative;border:1px solid #bfbfbf;overflow:hidden;padding:0;margin:0;box-sizing:border-box}.vis.timeline .vispanel{position:absolute;padding:0;margin:0;box-sizing:border-box}.vis.timeline .vispanel.bottom,.vis.timeline .vispanel.center,.vis.timeline .vispanel.left,.vis.timeline .vispanel.right,.vis.timeline .vispanel.top{border:1px #bfbfbf}.vis.timeline .vispanel.center,.vis.timeline .vispanel.left,.vis.timeline .vispanel.right{border-top-style:solid;border-bottom-style:solid;overflow:hidden}.vis.timeline .vispanel.bottom,.vis.timeline .vispanel.center,.vis.timeline .vispanel.top{border-left-style:solid;border-right-style:solid}.vis.timeline .background{overflow:hidden}.vis.timeline .vispanel>.content{position:relative}.vis.timeline .vispanel .shadow{position:absolute;width:100%;height:1px;box-shadow:0 0 10px rgba(0,0,0,.8)}.vis.timeline .vispanel .shadow.top{top:-1px;left:0}.vis.timeline .vispanel .shadow.bottom{bottom:-1px;left:0}.vis.timeline .labelset{position:relative;overflow:hidden;box-sizing:border-box}.vis.timeline .labelset .vlabel{position:relative;left:0;top:0;width:100%;color:#4d4d4d;box-sizing:border-box;border-bottom:1px solid #bfbfbf}.vis.timeline .labelset .vlabel:last-child{border-bottom:none}.vis.timeline .labelset .vlabel .inner{display:inline-block;padding:5px}.vis.timeline .labelset .vlabel .inner.hidden{padding:0}.vis.timeline .itemset{position:relative;padding:0;margin:0;box-sizing:border-box}.vis.timeline .itemset .background,.vis.timeline .itemset .foreground{position:absolute;width:100%;height:100%;overflow:visible}.vis.timeline .axis{position:absolute;width:100%;height:0;left:0;z-index:1}.vis.timeline .foreground .group{position:relative;box-sizing:border-box;border-bottom:1px solid #bfbfbf}.vis.timeline .foreground .group:last-child{border-bottom:none}.vis.timeline .item{position:absolute;color:#1A1A1A;border-color:#97B0F8;border-width:1px;background-color:#D5DDF6;display:inline-block;padding:5px}.vis.timeline .item.selected{border-color:#FFC200;background-color:#FFF785;z-index:2}.vis.timeline .editable .item.selected{cursor:move}.vis.timeline .item.point.selected{background-color:#FFF785}.vis.timeline .item.box{text-align:center;border-style:solid;border-radius:2px}.vis.timeline .item.point{background:0 0}.vis.timeline .item.dot{position:absolute;padding:0;border-width:4px;border-style:solid;border-radius:4px}.vis.timeline .item.range{border-style:solid;border-radius:2px;box-sizing:border-box}.vis.timeline .item.background{overflow:hidden;border:none;background-color:rgba(213,221,246,.4);box-sizing:border-box;padding:0;margin:0}.vis.timeline .item.range .content{position:relative;display:inline-block;overflow:hidden;max-width:100%}.vis.timeline .item.background .content{position:absolute;display:inline-block;overflow:hidden;max-width:100%;margin:5px}.vis.timeline .item.line{padding:0;position:absolute;width:0;border-left-width:1px;border-left-style:solid}.vis.timeline .item .content{white-space:nowrap;overflow:hidden}.vis.timeline .item .delete{background:url(img/timeline/delete.png) top center no-repeat;position:absolute;width:24px;height:24px;top:0;right:-24px;cursor:pointer}.vis.timeline .item.range .drag-left{position:absolute;width:24px;height:100%;top:0;left:-4px;cursor:w-resize}.vis.timeline .item.range .drag-right{position:absolute;width:24px;height:100%;top:0;right:-4px;cursor:e-resize}.vis.timeline .timeaxis{position:relative;overflow:hidden}.vis.timeline .timeaxis.foreground{top:0;left:0;width:100%}.vis.timeline .timeaxis.background{position:absolute;top:0;left:0;width:100%;height:100%}.vis.timeline .timeaxis .text{position:absolute;color:#4d4d4d;padding:3px;white-space:nowrap}.vis.timeline .timeaxis .text.measure{position:absolute;padding-left:0;padding-right:0;margin-left:0;margin-right:0;visibility:hidden}.vis.timeline .timeaxis .grid.vertical{position:absolute;width:0;border-right:1px solid}.vis.timeline .timeaxis .grid.minor{border-color:#e5e5e5}.vis.timeline .timeaxis .grid.major{border-color:#bfbfbf}.vis.timeline .currenttime{background-color:#FF7F6E;width:2px;z-index:1}.vis.timeline .customtime{background-color:#6E94FF;width:2px;cursor:move;z-index:1}.vis.timeline .vispanel.background.horizontal .grid.horizontal{position:absolute;width:100%;height:0;border-bottom:1px solid}.vis.timeline .vispanel.background.horizontal .grid.minor{border-color:#e5e5e5}.vis.timeline .vispanel.background.horizontal .grid.major{border-color:#bfbfbf}.vis.timeline .dataaxis .yAxis.major{width:100%;position:absolute;color:#4d4d4d;white-space:nowrap}.vis.timeline .dataaxis .yAxis.major.measure{padding:0;margin:0;visibility:hidden;width:auto}.vis.timeline .dataaxis .yAxis.minor{position:absolute;width:100%;color:#bebebe;white-space:nowrap}.vis.timeline .dataaxis .yAxis.minor.measure{padding:0;margin:0;visibility:hidden;width:auto}.vis.timeline .dataaxis .yAxis.title{position:absolute;color:#4d4d4d;white-space:nowrap;bottom:20px;text-align:center}.vis.timeline .dataaxis .yAxis.title.measure{padding:0;margin:0;visibility:hidden;width:auto}.vis.timeline .dataaxis .yAxis.title.left{bottom:0;-webkit-transform-origin:left top;-moz-transform-origin:left top;-ms-transform-origin:left top;-o-transform-origin:left top;transform-origin:left bottom;-webkit-transform:rotate(-90deg);-moz-transform:rotate(-90deg);-ms-transform:rotate(-90deg);-o-transform:rotate(-90deg);transform:rotate(-90deg)}.vis.timeline .dataaxis .yAxis.title.right{bottom:0;-webkit-transform-origin:right bottom;-moz-transform-origin:right bottom;-ms-transform-origin:right bottom;-o-transform-origin:right bottom;transform-origin:right bottom;-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.vis.timeline .legend{background-color:rgba(247,252,255,.65);padding:5px;border-color:#b3b3b3;border-style:solid;border-width:1px;box-shadow:2px 2px 10px rgba(154,154,154,.55)}.vis.timeline .legendText{white-space:nowrap;display:inline-block}.vis.timeline .graphGroup0{fill:#4f81bd;fill-opacity:0;stroke-width:2px;stroke:#4f81bd}.vis.timeline .graphGroup1{fill:#f79646;fill-opacity:0;stroke-width:2px;stroke:#f79646}.vis.timeline .graphGroup2{fill:#8c51cf;fill-opacity:0;stroke-width:2px;stroke:#8c51cf}.vis.timeline .graphGroup3{fill:#75c841;fill-opacity:0;stroke-width:2px;stroke:#75c841}.vis.timeline .graphGroup4{fill:#ff0100;fill-opacity:0;stroke-width:2px;stroke:#ff0100}.vis.timeline .graphGroup5{fill:#37d8e6;fill-opacity:0;stroke-width:2px;stroke:#37d8e6}.vis.timeline .graphGroup6{fill:#042662;fill-opacity:0;stroke-width:2px;stroke:#042662}.vis.timeline .graphGroup7{fill:#00ff26;fill-opacity:0;stroke-width:2px;stroke:#00ff26}.vis.timeline .graphGroup8{fill:#f0f;fill-opacity:0;stroke-width:2px;stroke:#f0f}.vis.timeline .graphGroup9{fill:#8f3938;fill-opacity:0;stroke-width:2px;stroke:#8f3938}.vis.timeline .fill{fill-opacity:.1;stroke:none}.vis.timeline .bar{fill-opacity:.5;stroke-width:1px}.vis.timeline .point{stroke-width:2px;fill-opacity:1}.vis.timeline .legendBackground{stroke-width:1px;fill-opacity:.9;fill:#fff;stroke:#c2c2c2}.vis.timeline .outline{stroke-width:1px;fill-opacity:1;fill:#fff;stroke:#e5e5e5}.vis.timeline .iconFill{fill-opacity:.3;stroke:none}div.network-manipulationDiv{border-width:0;border-bottom:1px;border-style:solid;border-color:#d6d9d8;background:#fff;background:-moz-linear-gradient(top,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#fff),color-stop(48%,#fcfcfc),color-stop(50%,#fafafa),color-stop(100%,#fcfcfc));background:-webkit-linear-gradient(top,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);background:-o-linear-gradient(top,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);background:-ms-linear-gradient(top,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);background:linear-gradient(to bottom,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#fcfcfc', GradientType=0);position:absolute;left:0;top:0;width:100%;height:30px}div.network-manipulation-editMode{position:absolute;left:0;top:0;height:30px;margin-top:20px}div.network-manipulation-closeDiv{position:absolute;right:0;top:0;width:30px;height:30px;background-position:20px 3px;background-repeat:no-repeat;background-image:url(img/network/cross.png);cursor:pointer;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}div.network-manipulation-closeDiv:hover{opacity:.6}span.network-manipulationUI{font-family:verdana;font-size:12px;-moz-border-radius:15px;border-radius:15px;display:inline-block;background-position:0 0;background-repeat:no-repeat;height:24px;margin:-14px 0 0 10px;vertical-align:middle;cursor:pointer;padding:0 8px;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}span.network-manipulationUI:hover{box-shadow:1px 1px 8px rgba(0,0,0,.2)}span.network-manipulationUI:active{box-shadow:1px 1px 8px rgba(0,0,0,.5)}span.network-manipulationUI.back{background-image:url(img/network/backIcon.png)}span.network-manipulationUI.none:hover{box-shadow:1px 1px 8px transparent;cursor:default}span.network-manipulationUI.none:active{box-shadow:1px 1px 8px transparent}span.network-manipulationUI.none{padding:0}span.network-manipulationUI.notification{margin:2px;font-weight:700}span.network-manipulationUI.add{background-image:url(img/network/addNodeIcon.png)}span.network-manipulationUI.edit{background-image:url(img/network/editIcon.png)}span.network-manipulationUI.edit.editmode{background-color:#fcfcfc;border-style:solid;border-width:1px;border-color:#ccc}span.network-manipulationUI.connect{background-image:url(img/network/connectIcon.png)}span.network-manipulationUI.delete{background-image:url(img/network/deleteIcon.png)}span.network-manipulationLabel{margin:0 0 0 23px;line-height:25px}div.network-seperatorLine{display:inline-block;width:1px;height:20px;background-color:#bdbdbd;margin:5px 7px 0 15px}div.network-navigation_wrapper{position:absolute;left:0;top:0;width:100%;height:100%}div.network-navigation{width:34px;height:34px;-moz-border-radius:17px;border-radius:17px;position:absolute;display:inline-block;background-position:2px 2px;background-repeat:no-repeat;cursor:pointer;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}div.network-navigation:hover{box-shadow:0 0 3px 3px rgba(56,207,21,.3)}div.network-navigation:active{box-shadow:0 0 1px 3px rgba(56,207,21,.95)}div.network-navigation.up{background-image:url(img/network/upArrow.png);bottom:50px;left:55px}div.network-navigation.down{background-image:url(img/network/downArrow.png);bottom:10px;left:55px}div.network-navigation.left{background-image:url(img/network/leftArrow.png);bottom:10px;left:15px}div.network-navigation.right{background-image:url(img/network/rightArrow.png);bottom:10px;left:95px}div.network-navigation.zoomIn{background-image:url(img/network/plus.png);bottom:10px;right:15px}div.network-navigation.zoomOut{background-image:url(img/network/minus.png);bottom:10px;right:55px}div.network-navigation.zoomExtends{background-image:url(img/network/zoomExtends.png);bottom:50px;right:15px} -------------------------------------------------------------------------------- /src/main/java/app/Application.java: -------------------------------------------------------------------------------- 1 | package app; 2 | 3 | import Service.*; 4 | import Util.ClassUtil; 5 | import Util.DirUtil; 6 | import Util.StackUtil; 7 | import com.beust.jcommander.JCommander; 8 | import model.*; 9 | import rules.*; 10 | 11 | import java.io.IOException; 12 | import java.nio.file.Paths; 13 | import java.util.*; 14 | 15 | import org.slf4j.Logger; 16 | import org.slf4j.LoggerFactory; 17 | 18 | public class Application { 19 | private static final Logger logger = LoggerFactory.getLogger(Application.class); 20 | private static final Map classFileByName = new HashMap<>(); 21 | private static final List classFileList = new ArrayList<>(); 22 | private static final List discoveredClasses = new ArrayList<>(); 23 | private static final List discoveredMethods = new ArrayList<>(); 24 | private static final Map classMap = new HashMap<>(); 25 | private static final Map methodMap = new HashMap<>(); 26 | 27 | private static final Map> methodCall = new HashMap<>(); 28 | private static final Map> passthroughDataflow = new HashMap<>(); 29 | private static final Set discoveredCalls = new HashSet<>(); 30 | private static InheritanceMap InheritanceMap; 31 | 32 | private static final List Sources = new ArrayList<>(); 33 | 34 | private static final List> Sinks = new ArrayList<>(); 35 | 36 | private static final List> stacks = new ArrayList<>(); 37 | 38 | private static final Map jarByClass = new HashMap<>(); 39 | 40 | public static void run(String[] args) throws IOException { 41 | Command command = new Command(); 42 | JCommander jc = JCommander.newBuilder().addObject(command).build(); 43 | jc.parse(args); 44 | if (command.help) { 45 | jc.usage(); 46 | return; 47 | } 48 | if((command.jar != null && command.jar.size() != 0)||(command.libs!=null)){ 49 | printConfig(command); 50 | if(command.methodName!=null){ 51 | getClassFileList(command,jarByClass); 52 | getClassinfo(command.methodName); 53 | }else { 54 | start(command); 55 | } 56 | }else if (command.jar == null && command.libs ==null){ 57 | logger.error("[-] no zips or jar input"); 58 | } 59 | } 60 | 61 | private static void printConfig(Command command) { 62 | if(command.jar != null){ 63 | System.out.print("[+] jar File: "); 64 | for (String jar : command.jar) { 65 | System.out.print(jar + " "); 66 | } 67 | System.out.println(); 68 | if (command.lib) { 69 | System.out.println("[+] Use All Libs In jar"); 70 | } 71 | } 72 | if(command.libs != null){ 73 | System.out.print("[+] libs director: "); 74 | System.out.print(command.libs + " "); 75 | System.out.println(); 76 | if (command.lib) { 77 | System.out.println("[+] Use All Libs In jar"); 78 | } 79 | } 80 | } 81 | 82 | private static void start(Command command) throws IOException { 83 | getClassFileList(command,jarByClass); 84 | loadSinks(command); 85 | getClassinfo(); 86 | builfInheritance(); 87 | getMethodCall(); 88 | if (command.taint==1){ 89 | loadSource(command); 90 | buildPassthrough(); 91 | buildCallGraph(); 92 | startTaintParse(); 93 | } 94 | if(command.taint==2) { 95 | loadSource(command); 96 | startNoTaintParse(); 97 | } 98 | if(command.taint==3){ 99 | parseSink(); 100 | } 101 | if(command.taint==41){ 102 | buildPassthrough(); 103 | buildCallGraph(); 104 | parseOnlySink(command); 105 | } 106 | if(command.taint==42){ 107 | parseOnlySink2(command); 108 | } 109 | if(command.draw == true){ 110 | startdraw(); 111 | } 112 | } 113 | 114 | public static void loadSinks(Command command){ 115 | if ((command.module == null || command.module.equals(""))&&command.rule==null) { 116 | System.out.println("[-] no module selected"); 117 | } else { 118 | if(command.module != null){ 119 | String module = command.module.toUpperCase(Locale.ROOT); 120 | if (module.contains("ALL")) { 121 | module = "SSRF|SQLI|XXE|RCE|DOS|FileRead|JNDI|XSS|ZIPSLIP|UNSERIALIZE"; 122 | System.out.println("[+] 加载所有规则"); 123 | } 124 | if (module.contains("SSRF")) { 125 | LoadSink.load(Sinks,SSRFconstant.getRules()); 126 | System.out.println("[+] 加载SSRF规则"); 127 | } 128 | if (module.contains("XXE")) { 129 | LoadSink.load(Sinks,XXEconstant.getRules()); 130 | System.out.println("[+] 加载XXE规则"); 131 | } 132 | if (module.contains("SQLI")) { 133 | LoadSink.load(Sinks,SQLinjectionConstant.getRules()); 134 | System.out.println("[+] 加载SQLI规则"); 135 | } 136 | if (module.contains("RCE")) { 137 | LoadSink.load(Sinks,RCEConstant.getRules()); 138 | System.out.println("[+] 加载RCE规则"); 139 | } 140 | if (module.contains("FileRead")) { 141 | LoadSink.load(Sinks,FileReadConstant.getRules()); 142 | System.out.println("[+] 加载FileRead规则"); 143 | } 144 | if (module.contains("LDAP")) { 145 | LoadSink.load(Sinks,LDAPinjectionConstant.getRules()); 146 | System.out.println("[+] 加载LDAP规则"); 147 | } 148 | if (module.contains("JNDI")) { 149 | LoadSink.load(Sinks,JNDIConstant.getRules()); 150 | System.out.println("[+] 加载JNDI规则"); 151 | } 152 | if (module.contains("XSS")) { 153 | LoadSink.load(Sinks,XSSconstant.getRules()); 154 | System.out.println("[+] 加载XSS规则"); 155 | } 156 | if (module.contains("ZIPSLIP")) { 157 | LoadSink.load(Sinks,ZipSlipConstant.getRules()); 158 | System.out.println("[+] 加载ZipSlip规则"); 159 | } 160 | if (module.contains("UNSERIALIZE")) { 161 | LoadSink.load(Sinks,UnserializeConstan.getRules()); 162 | System.out.println("[+] 加载Unserialize规则"); 163 | } 164 | } 165 | if(command.rule!=null){ 166 | System.out.println("[+] 使用自定义rule"); 167 | load_rules(Sinks,command); 168 | } 169 | } 170 | } 171 | 172 | private static void loadSource(Command command) { 173 | if (command.source != null) { 174 | LoadSource.loadsource(Sources, classFileList,command.source); 175 | } else { 176 | LoadSource.loadsource(Sources, classFileList); 177 | } 178 | } 179 | private static void getClassFileList(Command command,Map jarByClass) { 180 | if(command.jar!=null){ 181 | classFileList.addAll(ClassUtil.getAllClassesFromBoots(command.jar, command.jdk, command.lib,jarByClass)); 182 | } 183 | if(command.libs!=null){ 184 | List libs =DirUtil.getAllFile(command.libs); 185 | classFileList.addAll(ClassUtil.getAllClassesFromBoots(libs, command.jdk, command.lib,jarByClass)); 186 | } 187 | } 188 | 189 | 190 | private static void getClassinfo(){ 191 | DiscoverService.start(classFileList,discoveredClasses,discoveredMethods,classMap,methodMap,classFileByName); 192 | System.out.println("[+] 一共分析了" +discoveredClasses.size()+"个类"); 193 | System.out.println("[+] 一共分析了" +discoveredMethods.size()+"个方法"); 194 | } 195 | 196 | private static void getClassinfo(String methodName){ 197 | DiscoverService.start(classFileList,methodName); 198 | } 199 | public static void load_rules(List> Sinks,Command command){ 200 | Ruleservice Ruleservice = new Ruleservice(); 201 | Ruleservice.start(Sinks,command); 202 | } 203 | 204 | private static void builfInheritance(){ 205 | InheritanceMap = InheritanceService.start(classMap); 206 | } 207 | 208 | private static void getMethodCall(){ 209 | MethodCallService.start(classFileList,methodCall); 210 | } 211 | 212 | private static void buildPassthrough(){ 213 | PassthroughService.start(classFileByName,classMap,InheritanceMap,methodCall,passthroughDataflow); 214 | } 215 | 216 | private static void buildCallGraph(){ 217 | CallGraphService.start(classMap,InheritanceMap,passthroughDataflow,discoveredCalls,classFileList); 218 | } 219 | 220 | private static void startTaintParse(){ 221 | ChainDiscoverService ChainDiscoverService = new ChainDiscoverService(classFileByName,InheritanceMap,discoveredCalls,methodMap,classMap,Sources,Sinks); 222 | ChainDiscoverService.start(); 223 | } 224 | 225 | private static void startNoTaintParse(){ 226 | NoTaintChainDiscoverService NoTaintChainDiscoverService = new NoTaintChainDiscoverService(classFileByName,InheritanceMap,methodCall,methodMap,classMap,Sources,Sinks,stacks); 227 | NoTaintChainDiscoverService.start(); 228 | } 229 | 230 | private static void parseSink() throws IOException { 231 | SinkParseService SinkParseService = new SinkParseService(InheritanceMap,methodCall,methodMap,classMap,Sinks,stacks); 232 | SinkParseService.start(); 233 | List>> paixuStack = StackUtil.paixu(stacks); 234 | System.out.println("【+】 一共回溯出了"+paixuStack.get(0).size()+"条链子"); 235 | for(Deque i : paixuStack.get(0)){ 236 | StackUtil.printStackTrace(i); 237 | } 238 | StackUtil.SaveStack(Paths.get("Stack.dat"),paixuStack.get(1)); 239 | } 240 | private static void parseOnlySink(Command command){ 241 | onlySinkParseServerice onlySinkParseServerice = new onlySinkParseServerice(classFileByName,InheritanceMap,discoveredCalls,methodMap,classMap,Sinks,jarByClass,command.Save); 242 | onlySinkParseServerice.start(); 243 | } 244 | 245 | private static void parseOnlySink2(Command command){ 246 | onlySinkParseServerice2 onlySinkParseServerice = new onlySinkParseServerice2(classFileByName,InheritanceMap,methodCall,methodMap,classMap,Sinks,command.Save); 247 | onlySinkParseServerice.start(); 248 | } 249 | 250 | private static void startdraw() throws IOException { 251 | DarwService.start(stacks); 252 | } 253 | } 254 | --------------------------------------------------------------------------------