CodeQL JS/TS Journey
关于
之前做过的一些使用CodeQL对JS/TS项目做扫描的笔记。
关于构建数据库过程
对于JS/TS的项目来说,CodeQL统一都是 --language=javascript
的参数处理的,而且它主要是扫描,解析,然后构建数据库,对于小项目直接默认参数应该是ok的:
1 | codeql database create --language=javascript <your_prj> |
但是对于比较大型的项目来说,因为CodeQL是Java写的,所以可能会存在内存不足导致构建数据库失败的情况:
1 | FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - |
默认给的内存是2400MB
,大项目必然不够啊,文件太多了。
找了一圈没有解决方案,索性直接掏出JD_GUI把它的jar包给反编译了,发现是通过环境变量控制的:
1 | export SEMMLE_TYPESCRIPT_RAM=8000 |
这个不是给JAVA的那个内存设置(-J-Xmx1234M
)
Query
接口函数
1 | interface FooInterface{ |
拿这个Demo为例,很多接口函数统一导出,需要借助InterfaceDeclaration
来找,不过我的方法有点“笨”。
1 | import javascript |
我这里实现很粗暴,就是限制函数名(字符串值)和Interface里成员名字(字符串值)一致,就认为这个函数是导出接口中的函数。
特定参数的处理
在我的需求中,我需要重点关注,参数中带有路径的函数,换言之就是需要识别出这么多接口函数中,参数带有path
的情况,那么很直接的思路就是利用正则,但是在实际的场景下,你会发现代码真的写出了“花”,不是常规的query能覆盖的。
1 | foo: (params: WTFParams) => Promise<....>; |
参数是一个interface,你需要对这个interface再限制,即这个interface的成员是不是path
参数直接就是 {arg : string} 这类情况
奇怪的函数写法,函数体在return里
1 | class PathParamInterfaceType extends InterfaceType{ |
必须依赖TaintTracking吗
最后一个问题比较简单了,就是有了source,然后再找合适的sink,看有没有路径就行了;但是其实还有一种办法会来得更直接,就是利用传递闭包,但是会带来比较多的误报,好处是实现起来简单,想要排除误报,只需要增加限制即可,看具体需求吧,哪个方法合适用哪个。
CodeQL的JS/TS部分实现不如cpp多,所以有些predicate需要自己手动实现,比如用cpp做query可以:
1 | FunctionCall getFunctionToACall(FunctionCall fc){ |
但是JS/TS部分没有getACallToThisFunction
,根据原理,手动实现一个即可:
1 | CallExpr getACallToThisFunction(Function f){ |
所以,如果想要查询foo函数的传递闭包,就可以:
1 | from CallExpr call |
参考
https://ctftime.org/writeup/22177
https://kernelshaman.blogspot.com/2021/01/building-xnu-for-macos-big-sur-1101.html
https://github.com/D4rkD0g/boringforever/blob/main/xnu/boringanalysis/codeql_xnu.md