CodeQL 学习使用杂记(一)

admin 2022年10月29日14:57:54安全开发评论29 views5314字阅读17分42秒阅读模式

我的学习习惯是上去就是干,看看基本语法就行遇到不会的再去查,文章可能有疏漏错误之处,请见谅,欢迎一起学习交流,自己学太累了,codeql 太难了。

CodeQL

CodeQL 是开发人员用来自动化安全检查的分析引擎,安全研究人员用来执行变体分析。

在 CodeQL 中,代码被视为数据。安全漏洞、错误和其他错误被建模为可以针对从代码中提取的数据库执行的查询。您可以运行由 GitHub 研究人员和社区贡献者编写的标准 CodeQL 查询,也可以编写自己的查询以用于自定义分析。查找潜在错误的查询直接在源文件中突出显示结果。

CodeQL 分析包括三个步骤:

  1. 通过创建 CodeQL 数据库准备代码
  2. 针对数据库运行 CodeQL 查询
  3. 解释查询结果

安装

codeql-cli

在命令行(cli)的环境下运行codeql

项目地址 : github/codeql-cli-binaries ,打开项目地址之后进入Releases库,下载对应操作系统的压缩包解压到任意一个文件夹。最好配置到环境变量中,方便使用。

codeql

开源的codeql标准库和查询库

项目地址: github/codeql, 进入到上面解压codeql-cli的文件夹,并把该仓库clone下来,保证codeql-cli和codeql在同一个目录下

vscode-codeql

vscode的codeql插件,直接在插件市场安装

CodeQL 学习使用杂记(一)

image-20221012113347985

基本语法

查询(Query)

查询是CodeQL的输出。查询有两种类型,分别是

  • 选择子句
  • 查询谓词,这意味着我们可以在当前模块中定义或者从其他模块中导入

选择子句

在编写查询模块时,select语句通常位于文件的末尾,其一般格式如下所示:

from  /* ... 变量声明... */
where /* ... 逻辑公式 ... */
select /* ... 表达式 ... */

其中,from和where子句是可选的

from int x, int y
where x = 6 and y = 7
select x + y

在select语句中我们还可以使用一些关键字:

  • as关键字,后面跟随一个名字。作用相当于sql中的as,为结果列提供了一个"标签",并允许在后续的select表达式中使用它们。
  • order by关键字,后面跟随一个一个结果列名。作用相当于sql中的order by,用于排序结果,并且在结果列名后可选asc(升序)或desc(降序)关键字。

全局数据流

全局数据流跟踪整个程序的数据流,因此比本地数据流更强大。但是,全局数据流不如本地数据流精确,并且分析通常需要更多的时间和内存来执行。

DataFlow::Configuration

class Configuration extends DataFlow::Configuration {    
Configuration() { this = "OpenUrlRedirect" }

override predicate isSource(DataFlow::Node source) { source instanceof Source }

override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }

override predicate isBarrier(DataFlow::Node node) { node instanceof Barrier }

override predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
...
}

override predicate isBarrierOut(DataFlow::Node node) {
......
}

deprecated override predicate isBarrierGuard(DataFlow::BarrierGuard guard) {
guard instanceof BarrierGuard
}
}

配置中定义了以下谓词:

  • isSource——定义数据可能从哪里流出
  • isSink- 定义数据可能流向的位置
  • isBarrier--可选,限制数据流
  • isBarrierGuard--可选,限制数据流
  • isAdditionalFlowStep— 可选,添加额外的流程步骤

特征谓词Configuration()定义了配置的名称

使用谓词执行数据流分析:hasFlow(DataFlow::Node source, DataFlow::Node sink)

from Configuration dataflow, DataFlow::Node source, DataFlow::Node sink
where dataflow.hasFlow(source, sink)
select source, "Data flow to [email protected]", sink, sink.toString()

全局污点跟踪

全局污点跟踪针对全局数据流,就像本地污点跟踪针对本地数据流一样。也就是说,全局污点跟踪通过额外的非保值步骤扩展了全局数据流。通过扩展类使用全局污点跟踪库TaintTracking::Configuration,如下所示:

import semmle.code.cpp.dataflow.TaintTracking

class MyTaintTrackingConfiguration extends TaintTracking::Configuration {
MyTaintTrackingConfiguration() { this = "MyTaintTrackingConfiguration" }

override predicate isSource(DataFlow::Node source) {
...
}

override predicate isSink(DataFlow::Node sink) {
...
}
}

配置中定义了以下谓词:

  • isSource- 定义污点可能从哪里流出
  • isSink- 定义污点可能流向的位置
  • isSanitizer— 可选,限制污点流
  • isSanitizerGuard— 可选,限制污点流
  • isAdditionalTaintStep— 可选,添加额外的污点步骤

与全局数据流类似,特征谓词MyTaintTrackingConfiguration()定义了配置的唯一名称,因此"MyTaintTrackingConfiguration"应替换为自己的类的名称。

污点跟踪分析是使用谓词执行的。hasFlow(DataFlow::Node source, DataFlow::Node sink)

污点分析定义

污点分析可以抽象成一个三元组<sources,sinks,processor>的形式,其中:

  • source 即污点源,代表直接引入不受信任的数据或者机密数据到系统中
  • sink 即污点汇聚点,代表直接产生安全敏感操作(违反数据完整性)或者泄露隐私数据到外界(违反数据保密性)
  • sanitizer 即无害处理,代表通过数据加密或者移除危害操作等手段使数据传播不再对软件系统的信息安全产生危害

另类 Debug - Partial flow

Partial Data Flow允许寻找从一个给定的source到任何可能的sink的流动,让sink不受限制,同时限制从sourcesink的搜索步骤的数量。因此,可以使用这个来跟踪污点数据从源头到所有可能的汇的流动,并查看流动在哪里停止被进一步track

数据流中断时,使用 Partial flow 进行跟踪

导入import DataFlow::PartialPathGraph ,注意:不能同时与 import DataFlow::PathGraph使用

import go
import semmle.go.security.SqlInjection
import DataFlow::PartialPathGraph

from SqlInjection::Configuration cfg,DataFlow::PartialPathNode source, DataFlow::PartialPathNode sink
where cfg.hasPartialFlow(source, sink,_)
select sink, source, sink, "Partial flow from unsanitized user data"

同时qlInjection::Configuration 要实现

....
Configuration() { this = "SqlInjection" }

override int explorationLimit() { result = 50 } // 实现该谓词,表示探索深度

.....

感觉不太好用,也有可能是我不会使用

Go ...隐式数组的问题

func TT(query ...*QuotaQuery) string {
return query[0].Sort
}

func TT1(query *QuotaQuery) string {
return query.Sort
}

数据经过TT函数后,当前数据流就会中断,而TT1不会中断, 这是因为 codeql 本身就无法对调用含有可变参数的函数起作用,是本身的一个缺陷。

官方给的解决方案(我不会写,求助的官方,哈哈):

/*
* @Auth Chris Smowton
*/


private predicate isVarargsParam(Parameter p) {
exists(ParameterDecl pd, FuncTypeExpr tp | pd = tp.getAParameterDecl() |
p.getDeclaration() = pd.getANameExpr() and
pd.getTypeExpr() instanceof Ellipsis
)
}

class TaintConfig extends TaintTracking::Configuration {
TaintConfig() { this = "taint-configuration" }

override predicate isAdditionalTaintStep(DataFlow::Node source, DataFlow::Node sink) {
exists(Parameter p, DataFlow::ArgumentNode an, int idx |
an = source and
p = an.getCall().getACallee().getAParameter() and
isVarargsParam(p) and
not an.getCall().hasEllipsis() and
an.argumentOf(_, idx) and
idx >= p.getIndex() and
sink.asParameter() = p
)
}
}

This will do what you want so long as query itself is tainted on calling TT -- it won't work if just the Sort field of TT is tainted, because additional steps only apply to "top level" taint.

To use this with a DataFlow::Configuration instead of a TaintTracking::Configuration we'd need to target not the varargs parameter itself, but an array-read from it, like sink.(Read).readsElement(p.getARead(), _). This would also only work if query is the value we're tracking, not a value stored in one of its members.

So these workarounds are not great, but perhaps they will help with your case -- otherwise please bear with us while we implement a higher quality solution!

期待更好吧

参考

保姆级安装教程 https://longlone.top/%E5%AE%89%E5%85%A8/%E5%AE%89%E5%85%A8%E7%A0%94%E7%A9%B6/CodeQL%E4%B8%8Egolang%20sql%E6%B3%A8%E5%85%A5%E6%A3%80%E6%B5%8B/#%E4%BF%9D%E5%A7%86%E7%BA%A7%E5%AE%89%E8%A3%85%E6%95%99%E7%A8%8B

代码分析平台CodeQL学习手记(一)https://www.4hou.com/posts/yJOW

GitHub Java CodeQL CTF https://sumsec.me/2022/GitHub%20Java%20CodeQL%20CTF.html

CodeQL 提升篇 https://tttang.com/archive/1415/#toc_0x03-partial-flow


原文始发于微信公众号(谁不想当剑仙):CodeQL 学习使用杂记(一)

特别标注: 本站(CN-SEC.COM)所有文章仅供技术研究,若将其信息做其他用途,由用户承担全部法律及连带责任,本站不承担任何法律及连带责任,请遵守中华人民共和国安全法.
  • 我的微信
  • 微信扫一扫
  • weinxin
  • 我的微信公众号
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年10月29日14:57:54
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                  CodeQL 学习使用杂记(一) https://cn-sec.com/archives/1373617.html

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: