Java静态分析&gadgetinspector改造扫描sb

看了大哥写的java字节码静态分析审计工具,有点想法,做一个直接分析字节码的静态审计工具,而不需要像codeql那样需要编译。

文中这个思路完全仿照cobra,从sink到source,根据callee或者assign来回溯,没有用到cfg,完全的数据流分析。
我感觉他这么做有两个问题:

  1. 比如https://xz.aliyun.com/t/7979,用了@Valid,他的控制流是跳来跳去的,如果只是看callee或者assign stmt,跟到一半必然断,造成漏报。
  2. 这种很简陋的污点分析最大的问题应该是误报严重。

整体思路

因此我的想法是使用soot或者其他java的静态分析框架,能够从字节码解析出cfg。接下来分析过程是:先从source开始,找source所在的函数,然后找到这个函数在的block,分析cfg,看这个block能通到哪个sink所在的block,这个过程主要是控制流。如果找到了的话,再污点分析source到sink能不能传播过去,这个过程主要是数据流。

前期调研

java目前比较好的有gadgetinspector、soot、FlowDroid。

soot好处是能拿到cfg,感觉如果手工实现污点分析会方便一点,缺点是文档很恶心,要研究的话得花很多时间。

FlowDroid描述本身就有污点分析,准备看一下能不能用来分析java web。需要的可能是复杂的规则。

默安写了个Hades,看了一下,自己维护的cfg,感觉可用性不大。

gadgetinspector是直接使用的asm分析字节码实现的污点分析。他整体逻辑是从source到sink找到一条调用路径。首先通过MethodDiscovery收集方法、类的调用关系,然后生成PassthroughDiscovery数据流,这个过程主要判断每个方法的返回结果是否可以被其参数所影响,主要通过逆拓扑排序来实现。然后通过CallGraphDiscovery生成方法调用关系,这个过程主要记录子方法的参数是否可以被父方法的参数所影响,主要依赖visitMethodInsn中对passthroughDataflow的处理。
目前还是没太看懂passthroughDataflow和callgraph的调用逻辑上的具体关系,有机会需要再动态调几遍。

gadgetinspector改造计划

为了让gadgetinspector能扫springboot,对其做了两处改动。

  1. source
1
2
3
4
5
6
7
8
if(
classReference != null
&&
(classReference.getAnnotations().contains("Lorg/springframework/web/bind/annotation/RestController;") || classReference.getAnnotations().contains("Lorg/springframework/stereotype/Controller;"))
&& !(method.getName().equals("<init>"))
&& !(method.getDesc().equals("()V"))
&& (classReference.getName().contains("com/ruoyi"))
)

参考3dream师傅改的sqli的,其实只要定义好springboot的几个controller注解、几个getParameter方法就可以了。还有就是要跳过这些controller的构造方法,然后限定一下包名。
TODO1:对于扫描springboot、springmvc的项目,source是关键。因此这里需要添加springmvc的几个source,并且需要对springboot source的参数进行修改。
TODO2:还有就是@Valid这种注解,参考https://xz.aliyun.com/t/7979,需要解决一下,还没想好怎么办。

  1. 类加载
    因为我们要扫某些controller->sink的漏洞,不是像扫gadget那样复杂,因此污点分析还是挺好用的,也不需要加载JDK的类,只需要加载指定包下边的类即可。因此把ClassResourceEnumerator中的getAllClasses改一下:
1
2
3
4
5
6
7
public Collection<ClassResource> getAllClasses() throws IOException {
Collection<ClassResource> result = new ArrayList<>();
for (ClassPath.ClassInfo classInfo : ClassPath.from(classLoader).getTopLevelClassesRecursive("com.ruoyi")) {
result.add(new ClassLoaderClassResource(classLoader, classInfo.getResourceName()));
}
return result;
}

参考:

1
2
java字节码
https://mp.weixin.qq.com/s?__biz=MjM5NjQ5MTI5OA==&mid=2651750626&idx=1&sn=3e1ac6c41d6e1803abb32285daf0244a&chksm=bd1259af8a65d0b97809a6a8ff5afaff1be4a4232bd8527ef9d95bb7a2e768bd7d9fdc768211&scene=27#wechat_redirect

Proudly powered by Hexo and Theme by Hacker
© 2021 LFY