ecology相关的挖掘思路

前段时间 ecology 密集发布了一系列补丁,修复几个笔者之前储备的 0day,本文就来介绍其中一个列比较有意思的,以及分享一下相关的挖掘思路。
背景 最近几个月笔者都在研究 java web 方向,一方面是工作职责的调整,另一方面也想挑战一下新的领域。对于漏洞挖掘而言,选择一个具体目标是非常重要的,经过一段时间供应链和生态的学习以及同事建议,兼顾漏洞挖掘难度和实战效果选择了 ecology oa作为第一个漏洞挖掘的目标。
代码审计 虽然本文介绍的是 fuzzing,但之前也说过很多次,自动化漏洞挖掘只能作为一种辅助手段,是基于自身对代码结构的理解基础上的提效方式。
在真正开始挖漏洞之前,笔者花了好几周的时间去熟悉目标的代码,并且对一些不清晰的动态调用去进行运行时分析,最终才能在 20g 代码之中梳理出大致的鉴权和路由流程。
通过分析 javaee 应用注册的路由,注意到其中一个映射:
servletmapping[url-pattern=/services/*, name=xfireservlet] ^/services(?=/)|^/servicesz] 其对应的类为 org.codehaus.xfire.transport.http.xfireconfigurableservlet:
    xfireservlet    xfire servlet    org.codehaus.xfire.transport.http.xfireconfigurableservlet    xfireservlet    /services/* xfire 考古 xfire[1] 并不是 ecology 自己的业务代码,而是一个 soap web 服务框架,它是作为 apache axis 的有效替代方案而开发的。除了通过使用 stax 实现良好性能的目标外,xfire 的目标还包括通过各种插件机制实现灵活性,api 的直观操作以及与通用标准的兼容性。此外 xfire 非常适合集成到基于 spring framework 的项目中。
值得一提的是,xfire 目前已经不再进行开发,其官方继任者是 apache cxf[2]。
xfire 的用法比较简单,首先在 meta-inf/xfire/services.xml 中定义需要导出的服务,比如:
            workflowservice        webservices.services.weaver.com.cn        weaver.workflow.webservices.workflowservice        weaver.workflow.webservices.workflowserviceimpl        org.codehaus.xfire.annotations.annotationservicefactory     这样 weaver.workflow.webservices.workflowservice 就被认为是导出服务。
可以直接被客户端进行调用。调用方式主要是通过 soap 请求到 xfireservlet,例如调用上述服务可以发送 post 请求到 /services/workflowservice:
    evilpan
   2333
  表示以指定参数调用服务的 getuserid 方法。
sql 注入 接下来回到漏洞本身,workflowservice 服务的具体实现为 workflowserviceimpl,例如其中的 getuserid 就是服务导出的一个方法,其具体实现为:
@overridepublic string getuserid(string var1, string var2) {    if (util.null2string(var2).equals()) {        return -1;    } else if (util.null2string(var1).equals()) {        return -2;    } else {        recordset var3 = new recordset();        var3.executequery(select id from hrmresource where  + var1 + =? and status= 16 && b1 <= 31) {        return true;      }    case -64:      switch (b1) {        case -88:          return true;      }    default:      return false;    case 10:      return true;  }} 其逻辑是对 getremoteaddrproxy 取出来的 ip,如果路径匹配 webservicelist 且 ip 匹配 webserviceiplist 前缀,就认为是内网地址的请求从而进行放过:
webservicelist = [   /online/synconlinedata.jsp,   /services/,   /system/mobilelicenseoperation.jsp,   /system/pluginlicenseoperation.jsp,   /system/inpluginlicense.jsp,   /system/inmobilelicense.jsp];webserviceiplist = [   localhost,   127.0.0.1,   192.168.,   10.,   172.16.,   172.17.,   172.18.,   172.19.,   172.20.,   172.21.,   172.22.,   172.23.,   172.24.,   172.25.,   172.26.,   172.27.,   172.28.,   172.29.,   172.30.,   172.31.] 根据上面的代码,你能发现鉴权绕过的漏洞吗?
fuzzing 也许对代码比较敏感的审计人员可以通过上述鉴权代码很快发现问题,但说实话我一开始并没有找到漏洞。于是我想到这个鉴权逻辑是否能单独抽离出来使用 fuzzing 的思路去进行自动化测试。
之前发现 java 也有一个基于 libfuzzer 的模糊测试框架 jazzer[3],但是试用之后发现比较鸡肋,因为和二进制程序会自动 crash 不同,java 的 fuzz 需要自己指定 sink,令其在触达的时候抛出异常来构造崩溃。
虽然说没法发现通用的漏洞,但是对于现在这个场景来说正好是绝配,我们可以将目标原始的鉴权代码抠出来,然后在未授权通过的时候抛出一个异常即可。构建的 test harness 代码如下:
public static void fuzzertestoneinput(fuzzeddataprovider data) {    string poc = data.consumeremainingasstring();    fuzzip(poc);}public static void fuzzip(string poc) {    if (containsnonprintable(poc)) return;    xssrequestweblogic x = new xssrequestweblogic();    string out = x.getremoteaddr(poc);    boolean check2 = check2(out);    if (check2) {        throw new fuzzersecurityissuehigh(found ip [ + poc + ]);    }}public static boolean check2(string ipstr) {    for (string ip: webserviceiplist) {        if (ipstr.startswith(ip)) {            return true;        }    }    return false;} 其中精简了一些 ecology 代码中读取配置相关的依赖,将无关的逻辑进行手动剔除。
编译好代码后,使用以下命令开始进行 fuzz:
$ ./jazzer --cp=target/test-1.0-snapshot.jar --target_class=org.example.app 不多一会儿,就已经有了一个成功的结果!
fuzz.png 可以看到图中给出了 127.0.0.10 这个 payload,可以触发 ip 鉴权的绕过!反过来分析这个 poc,可以发现之所以能绕过是因为 webserviceiplist 只检查了前缀,而 127.0.0.10 可以在 internalip 返回 false,即认为不是内部 ip,但实际上 webserviceiplist 却认为是内部 ip,从而导致了绕过。
如果只是从代码上去分析的话,可能一时半会并不一定能发现这个问题,可是通过 fuzzing 在覆盖率反馈的加持下,却可以在几秒钟之内找到正解,这也是人工审计无法比拟的。
漏洞补丁 通过 ip 的鉴权绕过和 xfire 组件的 sql 注入,笔者实现了多套前台的攻击路径,并且在 hw 中成功打入多个目标。因为当时提交的报告中带了漏洞细节,因此这个漏洞自然也就被官方修补了。如果没有公开的话这个洞短期也不太会被撞到。
漏洞修复的关键补丁如下:
diff --git a/src/weaver/security/webcontainer/iputils.java b/src/weaver/security/webcontainer/iputils.javaindex 6b3d8efc..e7482511 100644--- a/src/weaver/security/webcontainer/iputils.java+++ b/src/weaver/security/webcontainer/iputils.java@@ -48,12 +48,16 @@ public class iputils {    }    public static boolean internalip(string ip) {-      if (ip != null && !ip.equals(127.0.0.1) && !ip.equals(::1) && !ip.equals(0000:1)) {+      if (ip == null || ip.equals(127.0.0.1) || ip.equals(::1) || ip.equals(0000:1)) {+         return true;+      } else if (ip.startswith(127.0.0.)) {+         return true;+      } else {          if (ip.indexof(:) != -1 && ip.indexof(:) == ip.lastindexof(:)) {             ip = ip.substring(0, ip.indexof(:));          } 其中把 equals 换成了 startswith,并且还过滤了我们之前使用的 workflowservice 组件。当然还是沿袭 ecology 一贯的漏洞修复原则,不改业务代码,只增加安全校验,这也是对历史遗留问题的一种妥协吧。
总结 • 对于 java 这样的内存安全编程语言也是可以 fuzz 的,只不过目的是找出逻辑漏洞而不是内存破坏;
• 漏洞挖掘初期花时间投入到代码审计中是有必要的,有助于理解项目整体结构并在后期进行针对性覆盖;
• 漏洞挖掘的时候重点关注边界的系统和服务,处于信任边界之外的组件更有可能过于信任外部输入导致安全问题;
• 对于看起来很复杂的数据处理模块,可以充分利用 fuzzing 的优势,帮助我们快速找出畸形的 payload;
• 模块化 fuzzing 的难点在于抽离代码并构建可编译或者可以独立运行的程序,即构建 test harness,跑起来测试用例你就已经成功了 90%;
• 软件开发和漏洞挖掘正好相反。开发者会出于厌恶情绪刻意避开复杂的历史遗留代码,而这些代码却是更可能出现问题的地方。因此安全研究员要学会克服自己的厌恶情绪,做到 —— “明知山有屎,偏向屎山行”。

产业链消息人士:三星电子最快一季末下调NAND闪存价格
USB、UART、TTL、RS232串口通信知识点
行业 | 基于物联网的智能照明系统
效率可达97%的可驱动高输出电压电源模块
动态断裂研究的福音—变阶力学新理论
ecology相关的挖掘思路
库克发微博悼念乔布斯:他让我懂得了人文关怀的意义
最好的智能手表正式上市:三星Gear S3智能手表
收了哈曼又接管量子点公司 三星的大动作覆盖面广得很
OPPO发布了少量的芯片工程师职位,或许是全新战略布局
荣耀8A正式发布 具备高性价比珍珠全面屏和震撼大音量两个特点
2019年全球十大IT企业公布 华为与京东入围
CD4511应用电路
共享充电宝悄悄涨价,又来割韭菜?
如何使用4节AA电池制作智能锁的方案设计
陆地火箭!特斯拉P100D加速性能超越法拉利旗舰!
荣耀V9和荣耀8青春版谁更值得入手?荣耀V9和荣耀8青春版区别对比
莱特波特无线终端测试解决方案
一文分析美国与华为的竞争关系
混合动力系统代表动力总成系统电气化的第一步