├── README.md ├── JarFileReader.java └── SearchClassInJar.java /README.md: -------------------------------------------------------------------------------- 1 | # JavaSearchTools 辅助人工审计,寻找java反序列化危险类的工具。 2 | 3 | ## Usage:java -jar SearchClassInJar.jar Path 4 | 5 | 第一步:首先用jd-gui反编译jar包还原代码,存储路径:C:\\Users\\afanti\\Desktop\\ctf-tools\\jd-gui\\weblogic\\ 6 | 7 | 第二步:java -jar SearchClassInJar.jar C:\\Users\\afanti\\Desktop\\ctf-tools\\jd-gui\\weblogic\\ 8 | 9 | ![](http://img2020.cnblogs.com/blog/1298490/202003/1298490-20200319105834907-1284701098.png) 10 | 11 | > Demo是寻找xml库和实现序列化接口的正则,可在SearchReadObject,SearchEvilPackage函数修改正则。 12 | 13 | 文章发表在安全客:https://www.anquanke.com/post/id/199703 14 | -------------------------------------------------------------------------------- /JarFileReader.java: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | import java.net.URL; 3 | import java.util.regex.Pattern; 4 | 5 | public class JarFileReader { 6 | public static void Test(String jarName,String classname) throws IOException { 7 | URL url1 = new URL("jar:file:"+jarName.replaceAll("\\","/")+"!"+classname); 8 | URL url2 = new URL("jar:file:"+jarName.replaceAll("\\","/")+"!"+classname); 9 | // 标准输入流 10 | try { 11 | InputStream is1 = url1.openStream(); 12 | InputStream is2 = url2.openStream(); 13 | if (processEvilPackage(is1)&&processReadObject(is2)) { 14 | System.out.println(classname + " this class maybe have XXE!!!!!!!!!"); 15 | } 16 | }catch (Exception e) 17 | { 18 | System.out.println(classname + " java.io.FileNotFoundException"); 19 | } 20 | } 21 | 22 | private static boolean processEvilPackage(InputStream input) throws IOException { 23 | InputStreamReader isr = new InputStreamReader(input); 24 | BufferedReader reader = new BufferedReader(isr); 25 | String line; 26 | //遍历查找库 27 | while ((line = reader.readLine()) != null) { 28 | // System.out.println(line); 29 | if (SearchEvilPackage(line)) 30 | { 31 | return true; 32 | } 33 | } 34 | reader.close(); 35 | return false; 36 | } 37 | private static boolean processReadObject(InputStream input) throws IOException { 38 | InputStreamReader isr = new InputStreamReader(input); 39 | BufferedReader reader = new BufferedReader(isr); 40 | String line; 41 | //遍历查找库 42 | while ((line = reader.readLine()) != null) { 43 | // System.out.println(line); 44 | if (SearchReadObject(line)) 45 | { 46 | return true; 47 | } 48 | } 49 | reader.close(); 50 | return false; 51 | } 52 | private static boolean SearchEvilPackage(String line) 53 | { 54 | //表达式 55 | String XXE_Regex = ".*javax.xml.parsers.DocumentBuilderFactory.*|.*javax.xml.parsers.SAXParser.*|.*javax.xml.transform.TransformerFactory.*|.*javax.xml.validation.Validator.*|.*javax.xml.validation.SchemaFactory.*|.*javax.xml.transform.sax.SAXValidator.*|.*javax.xml.transform.sax.SAXSource.*|.*org.xml.sax.XMLReader.*|.*org.xml.sax.helpers.XMLReaderFactory.*|.*org.dom4j.io.SAXReader.*|.*org.jdom.input.SAXBuilder.*|.*org.jdom2.input.SAXBuilder.*|.*javax.xml.bind.Unmarshaller.*|.*javax.xml.xpath.XpathExpression.*|.*javax.xml.stream.XMLStreamReader.*|.*org.apache.commons.digester3.Digester.*|.*javax.xml.transform.stream.StreamSource.*|.*javax.xml.parsers.SAXParserFactory.*|.*javax.xml.ws.EndpointReference.*"; 56 | boolean b = Pattern.matches(XXE_Regex, line); 57 | if(b){ 58 | return true; 59 | }else 60 | { 61 | return false; 62 | } 63 | } 64 | private static boolean SearchReadObject(String line) 65 | { 66 | //表达式 67 | String Ser_Regex = ".*Externalizable.*|.*Serializable.*|.*readObject.*|.*readExternal.*"; 68 | boolean b = Pattern.matches(Ser_Regex, line); 69 | if(b){ 70 | return true; 71 | }else 72 | { 73 | return false; 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /SearchClassInJar.java: -------------------------------------------------------------------------------- 1 | import java.io.File; 2 | import java.util.Enumeration; 3 | import java.util.zip.ZipEntry; 4 | import java.util.zip.ZipFile; 5 | import java.util.regex.Pattern; 6 | 7 | public class SearchClassInJar { 8 | private String className; 9 | private String className_temp; 10 | private String className_final; 11 | private String jarDir; 12 | private Integer totalNum = 0; 13 | public SearchClassInJar(String className,String jarDir) { 14 | this.className = className; 15 | this.jarDir = jarDir; 16 | } 17 | //将jar中的类文件路径形式改为包路径形式 18 | protected String getClassName(ZipEntry entry) { 19 | StringBuffer className = new StringBuffer(entry.getName().replace('/','.')); 20 | return className.toString(); 21 | } 22 | // 从jar从搜索目标类 23 | public void searchClass(boolean recurse) { 24 | searchDir(this.jarDir, recurse); 25 | System.out.println(String.format("[!] Find %s classes",this.totalNum)); 26 | System.out.println(); 27 | } 28 | //递归搜索目录和子目录下所有jar和zip文件 29 | protected void searchDir(String dir, boolean recurse) { 30 | try { 31 | File d = new File(dir); 32 | if (!d.isDirectory()) { 33 | return; 34 | } 35 | File[] files = d.listFiles(); 36 | for (int i = 0; i < files.length; i++) { 37 | if (recurse && files[i].isDirectory()) { 38 | searchDir(files[i].getAbsolutePath(), true); 39 | } else { 40 | String filename = files[i].getAbsolutePath(); 41 | if (filename.endsWith(".jar")||filename.endsWith(".zip")) { 42 | System.out.println("---------------------扫描"+filename+"中----------------------------"); 43 | ZipFile zip = new ZipFile(filename); 44 | Enumeration entries = zip.entries(); 45 | while (entries.hasMoreElements()) { 46 | ZipEntry entry = (ZipEntry) entries.nextElement(); 47 | String thisClassName = getClassName(entry); 48 | if (wildcardEquals(this.className.toLowerCase(),thisClassName.toLowerCase()) || wildcardEquals(this.className.toLowerCase() + ".class",thisClassName.toLowerCase())) { 49 | JarFileReader jarFileReader = new JarFileReader(); 50 | className_temp = "/"+thisClassName.replaceAll("\.","/"); 51 | className_final = className_temp.substring(0,className_temp.length()-5)+".java"; 52 | jarFileReader.Test(filename,className_final); 53 | totalNum++; 54 | } 55 | } 56 | } 57 | } 58 | } 59 | } catch (Exception e) { 60 | e.printStackTrace(); 61 | } 62 | } 63 | //通配符匹配 64 | private boolean wildcardEquals(String wildcard, String str) { 65 | String regRule = WildcardToReg(wildcard); 66 | return Pattern.compile(regRule).matcher(str).matches(); 67 | } 68 | //将通配符转换为正则表达式 69 | private static String WildcardToReg(String path) { 70 | char[] chars = path.toCharArray(); 71 | int len = chars.length; 72 | StringBuilder sb = new StringBuilder(); 73 | boolean preX = false; 74 | for(int i=0;i"); 102 | System.out.println("Example:java -jar SearchClassInJar.jar C:\\\\Users\\\\afanti\\\\Desktop\\\\ctf-tools\\\\jd-gui\\\\weblogic\\\\"); 103 | return; 104 | } 105 | SearchClassInJar scij = new SearchClassInJar("*.java",args[0]); 106 | scij.searchClass(true); 107 | } 108 | } --------------------------------------------------------------------------------