codeql测试fastjson

前言

首先要清楚,fastjson的利用链主要集中在getter和setter方法中,如果getter或者setter的方法中存在一些危险操作,比如JNDI查询之类的调用的话,如果参数可控就可以导致JNDI注入,而且fastjson的防御方式为黑名单,所以会层出不穷fastjson的绕过gadgets

鉴于fastjson的漏洞原理较为简单,且source(用户输入的源头)和sink(危险的函数)较为明确,所以可以使用codeql对一些常见的库进行fastjson利用链的挖掘

定义入口点(source)

fastjson的source相对比较好定义,所有fastjson的入口函数都是getter和setter这些函数,所以对应的source就为这些getter和setter,在codeql查询中,其实相当于将所有的函数按照用户所需要的过滤规则拿出来,所以我们只需要定义过滤的规则

对于getter和setter的规则,这里其实并不是一定要有对应的属性,只要前三个字母开头是get,并且第四个字母大写即可

getter的规则

  1. 以get开头
  2. 没有函数参数
  3. 是 code database 中的函数
  4. 为 public方法
  5. 函数名长度要大于3

setter的规则:

  1. 以set开头
  2. 函数参数为一个
  3. 是 code database 中的函数
  4. 为public方法
  5. 函数名长度大于3
  6. 返回值为void

所以我们可以根据这几个规则写出对应的source,转换为ql语句为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class FastjsonSetMethod extends Method{
FastjsonSetMethod(){
this.getName().indexOf("set")=0 and
this.getName().length()>3 and
this.isPublic() and
this.fromSource() and
exists(VoidType vt |vt = this.getReturnType() ) and
this.getNumberOfParameters()=1
}
}

class FastjsonGetMethod extends Method{
FastjsonGetMethod(){
this.getName().indexOf("get")=0 and
this.getName().length() > 3 and
this.isPublic() and
this.fromSource() and
this.hasNoParameters()
}
}

定义危险函数

这里危险函数不仅仅是JNDI注入的函数,也可以是DNS查询之类的函数

JNDI函数的规则:

  1. 这个函数名为lookup
  2. 这个函数所在的类实现了”javax.naming.Context”接口

使用ql语言,描述为

1
2
3
4
5
6
7
class JNDIMethod extends Method{
JNDIMethod(){
this.getDeclaringType().getASupertype *().hasQualifiedName("javax.naming", "Context")
and
this.hasName("lookup")
}
}

确定搜索方法(sink)

因为在fastjson中,有两个输入点,一个是get方法所在类的属性,一个是在fastjson触发的时候所传入的参数,为了方便起见,没有定义确定的source,一般来说能满足get方法最后到lookup的类相对较少,所以可以在查询结束以后再人工进行一次确认

这里没有用fastjson的全局的污点追踪,而是直接通过语法结构查找对应的利用链