freeBuf
主站

分类

云安全 AI安全 开发安全 终端安全 数据安全 Web安全 基础安全 企业安全 关基安全 移动安全 系统安全 其他安全

特色

热点 工具 漏洞 人物志 活动 安全招聘 攻防演练 政策法规

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

CodeQL(3)
2022-12-13 23:12:01
所属地 陕西省

前言

上一篇通过官方文档给出的4个小故事,我们学习了QL语言的大概的使用,这篇来学习关于CodeQL queries的相关知识,这部分是对Java语言进行介绍。也就是在CodeQL平台上对实际的项目进行分析的查询编写。

Basic query

看以下Java代码:

public class TestJava {
    void myJavaFun(String s) {
        boolean b = s.equals("");
    }
}

或者Kotlin代码:

void myKotlinFun(s: String) {
    var b = s.equals("")
}

上面两种代码,站在安全编码的角度,我们应该将s.equals("")替换为s.isEmpty()

所以我们需要查找处项目中的此类代码,查询如下:

from MethodAccess ma
where
    ma.getMethod().hasName("equals") and
    ma.getArgument(0).(StringLiteral).getValue() = ""
select ma, "This comparison to empty string is inefficient, use isEmpty() instead."

MethodAccess:方法调用类,获取的就是所有的方法调用

ma.getMethod().hasName("equals")限制调用方法名必须为equals

ma.getArgument(0).(StringLiteral).getValue() = "",限制调用方法的第一个参数字面量为”“

image.png
image.png

CodeQL library for Java

CodeQL提供了一个专门针对Java项目做分析的库,这个库中的类以面向对象的形式呈现数据库中的数据,并提供大量谓词帮助分析。

该库作为一组QL模块实现,模块即具有.qll扩展名的文件,java.qll模块导入了所有的核心Java库模块。

import java

接下来简要写一下此库中较为重要的类和谓词。

Summary of the library classes

标准 Java 库中最重要的类可以分为五个主要类别:

  1. 用于表示程序元素(如类和方法)的类

  2. 用于表示 AST 节点(如语句和表达式)的类

  3. 用于表示元数据(如批注和注释)的类

  4. 用于计算指标(如复杂度和耦合)的类

  5. 用于对调用图进行操作的类

其中第一种最多也是最复杂,第四种不做讲解,有兴趣的自行学习

Program elements

程序元素类包括程序中进行命名的元素:包(Package), 编译单元 (CompilationUnit), 类型(Type), 方法 (Method),构造器 (Constructor), 变量(Variable)。

上述几种的共同超类是Element,提供了一般成员谓词,来确定程序元素的名称并检查两个元素是否嵌套。

Types类有大量的子类来表示不同类型的类:

  • PrimitiveType表示基本类型,例如boolean,byte,char,double,float,int,long,short,QL还将void<nulltype>也作为基本类型

  • RefType表示引用类型(非基本类型),它有几个子类:

    • Class表示Java类

    • Interface表示Java接口

    • EnumType表示Java枚举类型.

    • Array表示Java数组类型

例如,下面的语句查找所有的int类型的变量

import java

from Variable v, PrimitiveType pt
where pt = v.getType() and
    pt.hasName("int")
select v

此查询会得到很多结果,因为大多数项目都包含许多int类型的变量

引用类型也可以根据其声明范围进行分类:

  • TopLevelType表示在编译单元的顶层声明的引用类型。

  • NestedType是在另一个类型中声明的类型。

例如,此查询查找名称与其编译单元名称不同的所有顶级类型:

import java

from TopLevelType tl
where tl.getName() != tl.getCompilationUnit().getName()
select tl

更多的专业类也很有用:

  • TopLevelClass:表示在编译单元的顶层声明的类。

  • NestedClass:表示在另一个类型中声明的类,

该库还具有许多单例类,它们包装了常用的Java标准类库:TypeObject,TypeCloneable,TypeRuntime,TypeSerializable,TypeString,TypeSystemTypeClass。很明显,TypeObject包装了Object

例如,我们可以编写一个查询来查找所有直接继承自Object的嵌套类:

import java

from NestedClass nc
where nc.getASupertype() instanceof TypeObject
select nc

image.png

Variables

·Variables类表示Java中的变量,分为3种情况,一是类的成员字段(无论是否静态),二是局部变量,三是一个参数,因此Variables有三个子类来满足上面的三种情况。

  • Field代表一个java字段

  • LocalVariableDecl代表一个本地变量

  • Parameter代表方法或构造器的参数

Abstract syntax tree(AST)

这个类别中的类主要是为了表示抽象语法树上(AST)的节点(nodes),较为重要的是语句类 (classStmt) 和表达式类 (classExpr),后面会详细介绍AST这个类别。

ExprStmt两个类都提供了大量的谓词来帮助我们对程序的抽象语法树进行研究:

  • Expr.getAChildExpr:返回给定表达式的子表达式

  • Stmt.getAChild:返回给定语句中嵌套的语句或表达式

  • Expr.getParentStmt.getParent返回给定AST节点的父节点

例如,下面的查询查找父语句为return语句的所有表达式

import java

from Expr e
where e.getParent() instanceof ReturnStmt
select e

image.png

image.png

在AST中return后边语句是其子节点,这样就能理解了,如果程序包含一个语句return x + y,查询将会返回子表达式x + y

再举一个例子,下面这个查询查找父语句为if语句的所有表达式。

import java

from Stmt s
where s.getParent() instanceof IfStmt
select s

image.png

这个和上边的例子还是有所不同的,这个查询将返回ifelse分支下的所有语句

接下来介绍一个语句用于发现方法体:

import java

from Stmt s
where s.getParent() instanceof Method
select s

image.png

当然上面只是较为简单的语句,我们需要结合自定义谓词以及类,来查询符合要求的表达式或语句,站在挖掘漏洞的角度,同时也需要我们需要很强的抽象能力,将已知的漏洞模式进行抽象形成查询,进而应用再实际的项目中。

上面的例子也说明了:表达式的父节点不总是表达式,也有可能是一个语句,同样的,语句的父节点不总是语句,也有可能是方法或构造函数,为了应对这一点,QL库提供了两个抽象类,ExprParentandStmtParent,前者表示可能是表达式父节点的任何节点,后者表示可能是语句父节点的任何节点。

Metadata(元数据)

除了程序代码,Java中还有许多种元数据,特别是注释和Javadoc,Java底层的类其中存在大量的注释,CodeQL官方认为元数据,无论是帮助代码分析还是作为一个独立的分析主题,都是很有趣的,所以QL库定义了访问元数据的类

对于注释,Annotatable类是所有可以被注释的程序元素的超类(superclass),子类对应Java程序中的元素,包括packages,reference types, fields,methods,constructors和

本地变量声明,对应上述每个元素对应的类的getAnAnnotation,可以访问此元素的任何可能存在的注释,例如,下面的查询,查找构造器的所有注释:

import java

from Constructor c
select c.getAnAnnotation()

image.png

这样会查询结果包含许多例子,这些注释是被用来禁止显示警告或标记代码被弃用。

注释是被Annotation类表示的,一个annotation是一个简单的表达式,其类型是AnnotationType例如我们可以修改此查询,使其仅报告已弃用的构造函数:

import java

from Constructor c, Annotation ann, AnnotationType anntp
where ann = c.getAnAnnotation() and
    anntp = ann.getType() and
    anntp.hasQualifiedName("java.lang", "Deprecated")
select ann

只有被@Deprecated标注的构造器被查询出来。

Javadoc 是 Sun 公司提供的一种工具,它可以从程序源代码中抽取类、方法、成员等注释,然后形成一个和源代码配套的 API 帮助文档。也就是说,只要在编写程序时以一套特定的标签注释,在程序编写完成后,通过 Javadoc 就形成了程序的 API 帮助文档。

对于javadocElement类使用成员谓词getDoc来返回一个代理的Documentable对象,

接下来,我们可以查询此委托对象来获取Javadoc下面这个查询获取私有字段上的Javadoc注释:

import java

from Field f, Javadoc jdoc
where f.isPrivate() and
    jdoc = f.getDoc().getJavadoc()
select jdoc

image.png

Javadoc类使用JavadocElement节点树来表示完整的javadoc文档,我们可以通过成员谓词``getAChildand getParent来对节点树进行遍历。例如,可以使用以下查询来查找私有字段的所有带有@author`标签的Javadoc注释。

import java

from Field f, Javadoc jdoc, AuthorTag at
where f.isPrivate() and
    jdoc = f.getDoc().getJavadoc() and
    at.getParent+() = jdoc
select at

第5行可能比较难理解:使用了递归来查找嵌套在Javadoc注释中的任意深度的标签

Call graph

Java代码库生成的CodeQL数据库包括关于程序调用图的一些预处理信息。

Call graph是整个程序中方法(函数)之间调用关系的图,图中的节点是方法,边表示调用关系。例如方法foo()调用了方法bar(),则CG中应有一条从foo()到bar()的有向边,

CodeQL对应的类为Callable包括了CG中的方法或构造器,调用表达式可以抽象为Call类,此类包括方法调用,new表达式,或使用this或super显式的构造函数。

我们可以使用谓词Call.getCallee来查找特定调用特定方法或构造函数的表达式,例如,下面这个查询查找所有调用println方法的所有方法。

import java

from Call c, Method m
where m = c.getCallee() and
    m.hasName("println")
select c

相反的,谓词Callable.getAReference可以用来查找从未调用过指定方法或构造器的语句:

import java

from Callable c
where not exists(c.getAReference())
select c

小结

这部分只是简单的了解了一下Java QL库的一些较为重要的基础知识点。下一篇会介绍一些实际安全场景中的运用。

# web安全 # 漏洞分析 # 网络安全技术
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录