author:SpringKill
概述
Tai-e是针对java的静态程序分析框架,支持包括指针分析、数据流分析、污点分析在内的诸多静态程序分析。由于Tai-e并非专门用来做静态代码安全分析,所以并非开箱即用,在实际安全分析中使用有许多问题。准备通过大致如下多篇文章,逐渐将Tai-e改造为开箱即用的静态代码安全分析框架。
-
Tomcat
中Servlet API
调用适配web应用。 -
Filters
、Listeners
等处理。 - 不同
Java Servlet
容器的适配 - ……
本文是在看到了larck和Keanu两位大佬的文章之后发现同样有对Tai-e
感兴趣的人所以写出,其实还有一些问题没有解决本文也不算是第一篇的完整版就叫第零篇了。
Tomcat
原理部分前面两篇文章讲得很详细,我就不过多赘述了,有兴趣的可以参阅:
https://xz.aliyun.com/t/13775
https://xz.aliyun.com/t/14058
入口点
tai-e
默认是以main
方法作为入口点的,所以要对Java Web
程序进行分析需要手工添加入口。
首先要支持的就是最直接的部署方式,Tomcat的servlet
编程。
在使用servlet
编程的时候,后端对每个路径都要有对应的servlet
类,在servlet
类中以注解@WebServlet()
来表示访问的路径名,并根据传入的http请求类型决定调用其中的doGet()
、doPost()
等方法。
那么根据这一点我们就可以直接使用Tai-e
提供的方法,扫描所有的类并尝试获取@WebServlet()
注解,对于获取到注解的类我们扫描其全部方法,提取出全部的服务方法,将其作为入口点进行分析。
当然也有使用web.xml
形式配置的方法,只需要扫描web.xml
文件获取即可,以后也会提到。
具体做法是,拓展一个插件,然后重写onstart
方法,在程序开始的时候对程序中扫描到的所有class
进行扫描,然后找到包含javax.servlet.ServletRequest
注解的类,这些类就是入口点。
但是要注意的是,由于Tai-e
的堆模拟无法直接模拟接口类,所以我们要手工添加一个模拟类,这个类要实现当前的被模拟的接口(javax.servlet.http.HttpServletRequest
接口)。
在tomcat
中,请求实际拿到的是org.apache.catalina.connector.RequestFacade
和org.apache.catalina.connector.ResponseFacade
,所以在设置入口点的时候我们将其作为mockobj
放进去。
具体实现如下:
final JClass requestFacade = World.get().getClassHierarchy().getClass("org.apache.catalina.connector.RequestFacade");
final JClass responseFacade = World.get().getClassHierarchy().getClass("org.apache.catalina.connector.ResponseFacade");
@Override
public void onStart() {
List<JClass> list = solver.getHierarchy().applicationClasses().toList();
for (JClass jClass : list) {
String a = jClass.getName();
if (a.matches("^(javax\\.servlet\\.ServletRequest).+$")) {
System.out.println("found: " + a);
}
HeapModel heapModel = solver.getHeapModel();
jClass.getAnnotations().forEach(annotation -> {
if (annotation.getType().matches("javax.servlet.annotation.WebServlet")) {
jClass.getDeclaredMethods().forEach(jMethod -> {
if (jMethod.getName().matches("\\b(doGet|doPost|doPut|doDelete)\\b")) {
Type requestFacadeType = jMethod.getParamType(0);
Type responseFacadeType = jMethod.getParamType(1);
String requestFacadeAlloc = "<" + requestFacadeType.toString() + ">";
String responseFacadeAlloc = "<" + responseFacadeType.toString() + ">";
Obj mockRequest = heapModel.getMockObj(ENTRY_DESC, requestFacadeAlloc, requestFacade.getType(), jMethod);
Obj mockResponse = heapModel.getMockObj(ENTRY_DESC, responseFacadeAlloc, responseFacade.getType(), jMethod);
Obj mockServlet = heapModel.getMockObj(ENTRY_DESC, "<http-controller>", jClass.getType());
SpecifiedParamProvider paramProvider = new SpecifiedParamProvider.Builder(jMethod)
.addThisObj(mockServlet)
.addParamObj(0, mockRequest)
.addParamObj(1, mockResponse)
.build();
solver.addEntryPoint(new EntryPoint(jMethod, paramProvider));
}
});
}
}
);
}
}
source
添加了入口点,我们还需要添加source
让初始数据携带污点,这个时候就需要重写onNewCSMethod
方法,具体原理可以参考Springboot篇(一)和(二)。
使用如下代码:
@Override
public void onNewCSMethod(CSMethod csMethod) {
JMethod method = csMethod.getMethod();
Context context = csMethod.getContext();
boolean isDoMethod = method.getName().matches("\\b(doGet|doPost|doPut|doDelete)\\b");
if (isDoMethod) {
IR ir = method.getIR();
Var param = ir.getParam(0);
SourcePoint sourcePoint = new ParamSourcePoint(method, new IndexRef(IndexRef.Kind.VAR, 0, null));
Obj taint = manager.makeTaint(sourcePoint, param.getType());
solver.addVarPointsTo(context, param, taint);
}
这里的代码和上面很类似,不过上面是为了添加入口,这里是为了添加source
,扫描方法名,并将request
对象(也就是do方法的第0个参数)添加为source
。
然后就可以配置transfer
了,transfer
的配置直接通过配置文件就可以实现,这里举个例子,以getParameter
方法为例子:
- { method: "<org.apache.catalina.connector.RequestFacade: java.lang.String getParameter(java.lang.String)>", from: base, to: result }
getParameter
方法最为简单,添加最为方便,实际还有getParameterValues
、getParameterMap
、hearders
、cookies
等等,对于这些点的transfer
添加略微复杂,打算放在下一篇文章来说。
sink
点配置因为是检测命令执行,所以直接对exec
添加sink
就可以:
- { vuln: "Remote Code Execution", level: 1, method: "<java.lang.Runtime: java.lang.Process exec(java.lang.String)>", index: 0 }
可以看到污点的流图了:
仍然存在的问题
对于Map
中的数据,在上下文不敏感的分析中是可行的,但是在进一步的上下文敏感分析中,Tai-e
的指针分析或者说污点分析不能精确的识别,导致污点中断(也可能是我使用的问题),不过目前问题已经初步解决但还不完善,水平有限,希望以后的学习能带来更多有意思有质量的东西,如本文存在错误,请大佬们指正。