百度OpenRasp實現原理


1、基礎知識

1.1、java插樁技術 :javaagent

  • 允許在jvm啟動時優先執行agent代碼,通常agent代碼用來添加Transformer,提供了對class在加載時進行字節碼修改的機會。

  • java啟動時增加參數java -javaagent:/Users/didi/Downloads/openrasp-javaagent/boot/target/rasp.jar -jar myapplication.jar

  • jar包構建時設置入口 <Premain-Class>com.baidu.openrasp.Agent</Premain-Class> ,啟動時會進入此類的premain方法執行

    public static void premain(String agentArg, Instrumentation inst) {
    inst.addTransformer(new CustomClassTransformer());
    }

1.2、java字節碼修改:javaassist

  • 其他類似的庫:
    • javaassist:openrasp用的這個,學習門檻低,源碼級別,不需要掌握字節碼相關技術。
    • asm:字節碼級別,學習門檻高,需要掌握字節碼技術。性能好
    • cglib:spring aop用的這個進行字節碼增強
    • bcel:apache

2、OpenRasp原理

2.1、openrasp介紹

  • 百度開源rasp,提供了完整的rasp + iast的功能,包括以下模塊:
    • java + php 的探針,對應用插樁,收集應用運行時數據; (java)
    • v8引擎 + rasp檢測插件,根據hook信息判斷是否為攻擊;(javascript)
    • 管理控制台,用於接收及查看rasp攻擊事件、iast漏洞信息、配置下發、應用管理等功能;(golang)
    • iast fuzz功能,用戶對探針采集的流量增加poc並進行重放 (python);
  • rasp支持的攻擊類型:
  • iast支持的漏洞類型:
    • 命令注入
    • 目錄遍歷
    • PHP eval代碼執行
    • 文件上傳
    • 文件包含
    • 任意文件讀取
    • 任意文件寫入
    • SQL注入
    • SSRF
    • Java XXE

2.2、啟動過程

  • a、通過插樁技術,進入openrasp入口com.baidu.openrasp.Agent.premain方法
  • b、premain方法執行初始化,並加載引擎模塊,引擎模塊執行后續動作
  • c、加載配置:本地yml文件 + 雲端定期拉取,配置比如:每個攻擊類型是否攔截還是只記錄、agent身份認證、郵件&釘釘報警、控制台密碼
    loadConfigFromFile(new File(configFilePath), true);
  • e、CheckerManager初始化,為不同的攻擊類型,設置不同的檢測checker,大部分攻擊使用V8AttackChecker檢測
    public synchronized static void init() throws Exception {
    for (Type type : Type.values()) {
    checkers.put(type, type.checker);
    }
    }
     
    <!-- // js測-->
    <!--SQL("sql", new V8AttackChecker(), 1),-->
    <!--COMMAND("command", new V8AttackChecker(), 1 << 1),-->
    <!--DIRECTORY("directory", new V8AttackChecker(), 1 << 2),-->
    <!--REQUEST("request", new V8AttackChecker(), 1 << 3),-->
    <!--READFILE("readFile", new V8AttackChecker(), 1 << 5),-->
    <!--WRITEFILE("writeFile", new V8AttackChecker(), 1 << 6),-->
    <!--FILEUPLOAD("fileUpload", new V8AttackChecker(), 1 << 7),-->
    <!--RENAME("rename", new V8AttackChecker(), 1 << 8),-->
    <!--XXE("xxe", new V8AttackChecker(), 1 << 9),-->
    <!--OGNL("ognl", new V8AttackChecker(), 1 << 10),-->
    <!--DESERIALIZATION("deserialization", new V8AttackChecker(), 1 << 11),-->
    <!--WEBDAV("webdav", new V8AttackChecker(), 1 << 12),-->
    <!--INCLUDE("include", new V8AttackChecker(), 1 << 13),-->
    <!--SSRF("ssrf", new V8AttackChecker(), 1 << 14),-->
    <!--SQL_EXCEPTION("sql_exception", new V8AttackChecker(), 1 << 15),-->
    <!--REQUESTEND("requestEnd", new V8AttackChecker(), 1 << 17),-->
    <!--DELETEFILE("deleteFile", new V8AttackChecker(), 1 << 18),-->
    <!--MONGO("mongodb", new V8AttackChecker(), 1 << 19),-->
    <!--LOADLIBRARY("loadLibrary", new V8AttackChecker(), 1 << 20),-->
    <!--SSRF_REDIRECT("ssrfRedirect", new V8AttackChecker(), 1 << 21),-->
    <!--RESPONSE("response", new V8AttackChecker(false), 1 << 23),-->
    <!--LINK("link", new V8AttackChecker(), 1 << 24),-->
     
    <!--// java測-->
    <!--XSS_USERINPUT("xss_userinput", new XssChecker(), 1 << 16),-->
    <!--SQL_SLOW_QUERY("sqlSlowQuery", new SqlResultChecker(false), 0),-->
     
    <!--// 測-->
    <!--POLICY_LOG("log", new LogChecker(false), 1 << 22),-->
    <!--POLICY_MONGO_CONNECTION("mongoConnection", new MongoConnectionChecker(false), 0),-->
    <!--POLICY_SQL_CONNECTION("sqlConnection", new SqlConnectionChecker(false), 0),-->
    <!--POLICY_SERVER_TOMCAT("tomcatServer", new TomcatSecurityChecker(false), 0),-->
    <!--POLICY_SERVER_JBOSS("jbossServer", new JBossSecurityChecker(false), 0),-->
    <!--POLICY_SERVER_JBOSSEAP("jbossEAPServer", new JBossEAPSecurityChecker(false), 0),-->
    <!--POLICY_SERVER_JETTY("jettyServer", new JettySecurityChecker(false), 0),-->
    <!--POLICY_SERVER_RESIN("resinServer", new ResinSecurityChecker(false), 0),-->
    <!--POLICY_SERVER_WEBSPHERE("websphereServer", new WebsphereSecurityChecker(false), 0),-->
    <!--POLICY_SERVER_WEBLOGIC("weblogicServer", new WeblogicSecurityChecker(false), 0),-->
    <!--POLICY_SERVER_WILDFLY("wildflyServer", new WildflySecurityChecker(false), 0),-->
    <!--POLICY_SERVER_TONGWEB("tongwebServer", new TongwebSecurityChecker(false), 0),-->
    <!--POLICY_SERVER_BES("bes", new BESSecurityChecker(false), 0);-->
     
  • f、構造CustomClassTransformer,設置到Instrumentation:關鍵動作如下:
    transformer = new CustomClassTransformer(inst);
    public CustomClassTransformer(Instrumentation inst) {
    this.inst = inst;
    inst.addTransformer(this, true);
    addAnnotationHook();
    }
    • ServerDetectorManager構造,並創建所有服務器檢測類,比如tomcat、springboot、webloigc、jboss、jetty、resin、dubbo、bes、ubdertow等
      private ServerDetectorManager serverDetector = ServerDetectorManager.getInstance();
    • 對所有com.baidu.openrasp.hook包里的class進行掃描,判斷每個class是否設置了注解HookAnnotation,如果設置了則加入CustomClassTransformer的hooks集合
      Set<Class> classesSet = AnnotationScanner.getClassWithAnnotation(SCAN_ANNOTATION_PACKAGE, HookAnnotation.class);
  • g、對已經加載和后續加載的class進行transform,transform包括以下處理:
    • 判斷class所在的文件路徑是否為jar包,如果是則加入 loadedJarPaths ,這樣可以獲取所有加載的jar包,可用於三方組件檢測

    • 調用hooks集合每個hook的isClassMatched與每個class進行匹配,判斷是否需要hook,如果需要則進行hook處理

      • 主要是利用字節碼技術 javaassist 對相應的字節碼進行修改,插入hook邏輯
        // 類hook測ssrf個hook的sink
        @HookAnnotation
        public class URLConnectionHook extends AbstractSSRFHook {
         
        @Override
        public boolean isClassMatched(String className) { //前class要hook
        return "sun/net/www/protocol/http/HttpURLConnection".equals(className) ||
        "weblogic/net/http/HttpURLConnection".equals(className);
        }
         
        @Override //的hook對class
        protected void hookMethod(CtClass ctClass) throws IOException, CannotCompileException, NotFoundException {
        String src = getInvokeStaticSrc(URLConnectionHook.class, "checkHttpConnection",
        "$0", URLConnection.class);
        // 通過javaassit修改class,插入一段源碼src
         
        insertBefore(ctClass, "getInputStream", "()Ljava/io/InputStream;", src);
        src = getInvokeStaticSrc(URLConnectionHook.class, "onExit", "$0", Object.class);
        insertAfter(ctClass, "getInputStream", "()Ljava/io/InputStream;", src, true);
        }
         
        public static void onExit(Object urlConnection) {
        try {
        if (isChecking.get() && !isExit.get() && URLConnectionRedirectHook.urlCache.get() != null) {
        // 調用 getinpustream isExit
        isExit.set(true);
        HashMap<String, Object> cache = originCache.get();
        HashMap<String, Object> redirectCache = getSsrfParamWithURL(URLConnectionRedirectHook.urlCache.get());
        if (cache != null && redirectCache != null) {
        AbstractRedirectHook.checkRedirect(cache, redirectCache,
        ((HttpURLConnection) urlConnection).getResponseMessage(), ((HttpURLConnection) urlConnection).getResponseCode());
        }
        }
        } catch (Exception e) {
        // ignore
        } finally {
        isChecking.set(false);
        originCache.set(null);
        isExit.set(false);
        URLConnectionRedirectHook.urlCache.set(null);
        }
        }
         
        private static HashMap<String, Object> getSsrfParamWithURL(URL url) {
        try {
        String host = null;
        String port = "";
        if (url != null) {
        host = url.getHost();
        int temp = url.getPort();
        if (temp > 0) {
        port = temp + "";
        }
        }
        if (url != null && host != null) {
        return getSsrfParam(url.toString(), host, port, "url_open_connection");
        }
        } catch (Exception e) {
        // ignore
        }
        return null;
        }
         
        public static void checkHttpConnection(URLConnection urlConnection) {
        if (!isChecking.get()) {
        isChecking.set(true);
        if (urlConnection != null) {
        URL url = urlConnection.getURL();
        HashMap<String, Object> param = getSsrfParamWithURL(url);
        checkHttpUrl(param);
        originCache.set(param);
        }
        }
        }
        }
         
    • 調用serverDetector.detectServer,檢測服務器類型,比如是否為springboot、tomcat、weblogic

      // springboot ,class為 org/apache/catalina/startup/Bootstrap
      public boolean isClassMatched(String className) {
      return "org/apache/catalina/startup/Bootstrap".equals(className);
      }
       
  • h、注冊應用,向控制台注冊應用,並且定期發送心跳、上報漏洞、異常、組件依賴信息等。

2.3、攻擊檢測:

  • hook點拿到對應的參數信息后,交給hook指定攻擊類型的checker處理(在啟動時為每個攻擊類型設置過對應的checker),大部分攻擊使用V8AttackChecker檢測
  • V8AttackChecker調用v8引擎,通過js插件來進行判斷是否為攻擊、是否進行攔截
    • V8AttackChecker -> jni方式調用chrome v8 -> js plugin
    function check_ssrf(params, context, is_redirect) {
    var hostname = params.hostname
    var url = params.url
    var ip = params.ip
    var reason = false
     
    // 法1 - 網IP為SSRF
    if (algorithmConfig.ssrf_userinput.action != 'ignore')
    {
    var ret
    ret = check_internal(params, context, is_redirect)
    // 非HTTP(dubbo)
    var header = context.header || {}
    if (ret && Object.keys(header).length != 0) {
    return ret
    }
    }
     
    // 法2 -
    if (algorithmConfig.ssrf_common.action != 'ignore')
    {
    if (is_hostname_dnslog(hostname))
    {
    return {
    action: algorithmConfig.ssrf_common.action,
    message: _("SSRF - Requesting known DNSLOG address: %1%", [hostname]),
    confidence: 100,
    algorithm: 'ssrf_common'
    }
    }
    }
     
    <!-- domains: [-->
    <!-- '.vuleye.pw',-->
    <!-- '.ceye.io',-->
    <!-- '.exeye.io',-->
    <!-- '.vcap.me',-->
    <!-- '.xip.name',-->
    <!-- '.xip.io',-->
    <!-- '.sslip.io',-->
    <!-- '.nip.io',-->
    <!-- '.burpcollaborator.net',-->
    <!-- '.tu4.org',-->
    <!-- '.2xss.cc',-->
    <!-- '.bxss.me',-->
    <!-- '.godns.vip',-->
    <!-- '.pipedream.net' // requestbin 址-->
    <!--]-->
     
     
     
    // 法3 - 測 AWS/Aliyun/GoogleCloud 址: 截IP
    if (algorithmConfig.ssrf_aws.action != 'ignore')
    {
    if (ip == '169.254.169.254' || ip == '100.100.100.200'
    || hostname == '169.254.169.254' || hostname == '100.100.100.200' || hostname == 'metadata.google.internal')
    {
    return {
    action: algorithmConfig.ssrf_aws.action,
    message: _("SSRF - Requesting AWS metadata address"),
    confidence: 100,
    algorithm: 'ssrf_aws'
    }
    }
    }
     
    // 法4 - ssrf_obfuscate
    //
    // 淆:
    // http://2130706433
    // http://0x7f001
    //
    //
    // http://0x7f.0x0.0x0.0x1
    // http://0x7f.0.0.0
    if (algorithmConfig.ssrf_obfuscate.action != 'ignore')
    {
    var reason = false
     
    if (!isNaN(hostname) && hostname.length != 0)
    {
    reason = _("SSRF - Requesting numeric IP address: %1%", [hostname])
    }
    // else if (hostname.startsWith('0x') && hostname.indexOf('.') === -1)
    // {
    // reason = _("SSRF - Requesting hexadecimal IP address: %1%", [hostname])
    // }
     
    if (reason)
    {
    return {
    action: algorithmConfig.ssrf_obfuscate.action,
    message: reason,
    confidence: 100,
    algorithm: 'ssrf_obfuscate'
    }
    }
    }
     
    // 法5 -
    if (algorithmConfig.ssrf_protocol.action != 'ignore')
    {
    //
    var proto = url.split(':')[0].toLowerCase()
     
    if (algorithmConfig.ssrf_protocol.protocols.indexOf(proto) != -1)
    {
    return {
    action: algorithmConfig.ssrf_protocol.action,
    message: _("SSRF - Using dangerous protocol: %1%://", [proto]),
    confidence: 100,
    algorithm: 'ssrf_protocol'
    }
    }
    }
    return false
    }

2.4、iast漏洞檢測:

  • 非重放
    • 對rasp的攻擊事件數據按照stack合並去重后作為漏洞
  • 重放
    • 利用javaagent抓取請求信息,然后參數加上poc后重放(fuzz)
  • 業界情況
    • 大部分公司已經在開發
      • 京東、阿里、華為、攜程、58、美團、百度、騰訊、華泰、快手、字節
    • 優點:
      • java開源的比較成熟,可以快速拿來用,其他語言較少;
      • 檢測准確率高、覆蓋率也不錯(如果是測試環境取決於QA的測試覆蓋度);
      • 可以拿到完整的調用鏈,類似白盒的數據流但也不太一樣;
      • 可以很方便的支持dubbo之類的框架;
      • 可以比較方便的拿到所有三方組件依賴信息;
      • 不存在白盒那種路徑爆炸、spring依賴注入之類的問題;
      • 完整的獲取API接口信息、請求和響應數據,檢測敏感數據的流向、收集、輸出很方便;
      • 可以更精准的檢測日志打印敏感數據、數據庫存儲敏感數據等目前黑白盒檢測不了的風險。
      • 可以檢測web弱口令;中間件配置類安全問題;
    • 缺點:
      • 部署成本較高,生產環境對穩定性、性能要求較高
      • 每種語言的實現方式不一樣,需要適配多種開發語言,目前開源的方案java相對來說比較成熟,其他語言實踐較少。
      • 對業務應用有侵入性、如果存在bug可能導致應用出問題,比如crash;
      • 跨線程促發的漏洞檢測調用鏈不完整;

3、參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM