CodeQL
之前上课做过的实验,脚本记录找不到了,只找到实验报告~
本人用的codeql-win64
0 安装
解析引擎安装
SDK安装
VScode插件安装
生成并导入database,测试
1.1 源码分析
漏洞代码
程序接受用户输入的数学表达式,检查表达式两项运算数据是否都为整数,通过检查的计算表达式结果并输出,没有通过检查的输出“hacker!”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import reclass Base : def __init__ (self,expr ) -> None : self .expr = expr class calc (Base ): def __init__ (self, expr ) -> None : super ().__init__(expr) def checkExpr (self ): a = re.split(pattern=r"[+|-|x|/]" , string = self .expr) print (a) try : int (a[0 ]) int (a[1 ]) except : return 0 return 1 def getResult (self ): if (self .checkExpr()): full_expr = "print(%s)" %(self .expr) print (full_expr) eval (full_expr) return 1 else : print ("hacker!" ) return 0 expr = input ("expr> " ) a = calc(expr) a.getResult()
计算结果时,程序使用了危险函数eval()
人为朴素分析数据流:expr 是通过 input 函数获取的用户输入,并通过 getResult() 方法传递给 eval() 函数执行,这里 eval()存在任意代码执行漏洞。
通过分析,将source定义为input()返回值,sink定义为eval()参数
1.2 ql查询
1.为目标代码生成数据库
1 2 cd ./targetcodeql database create ./codeql-test1 --language=python
并在vscode DATABASE中选择目标文件夹codeql-test1
2.编写查询代码
但本人代码拼拼凑凑,一直报错,最后求助大佬同桌~
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 //导入库 import python import semmle.python.dataflow.new.TaintTracking import semmle.python.dataflow.new.DataFlow import semmle.python.ApiGraphs //定义source和sink module TestTaintTrackingConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { exists(CallNode call | call.getFunction().(NameNode).getId() = "input" and source.(DataFlow::CfgNode).getNode() = call.getASuccessor() ) } predicate isSink(DataFlow::Node sink) { exists(CallNode call | call.getFunction().(NameNode).getId() = "eval" and sink.(DataFlow::CfgNode).getNode() = call.getAnArg() ) } } //路径查询 module TestTaintTrackingFlow = TaintTracking::Global<TestTaintTrackingConfig>; from TestTaintTrackingFlow::PathNode source, TestTaintTrackingFlow::PathNode sink where TestTaintTrackingFlow::flowPath(source, sink) select source, sink
3.右击ql程序,点击Run against local database
查询结果,路径连通,与预期一致
PS:同桌的代码可以跑出两个路径
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import python import semmle.python.dataflow.new.TaintTracking import semmle.python.ApiGraphs module InputToEvalConfiguration implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source = API::builtin("input").getACall() } predicate isSink(DataFlow::Node sink) { exists(DataFlow::CallCfgNode call | call = API::builtin("eval").getACall() and sink = call.getArg(0) ) } } module InputToEvalFlow = TaintTracking::Global<InputToEvalConfiguration>; import InputToEvalFlow::PathGraph from InputToEvalFlow::PathNode input, InputToEvalFlow::PathNode eval where InputToEvalFlow::flowPath(input, eval) select input, eval
T2 muchmorecomplicated
2.1 程序分析
有四个Go语言文件,是Grafana的一部分,构成了Grafana的插件管理和API服务器的核心逻辑。
manager.go 插件管理器
plugins.go 处理插件相关API请求
api.go Grafana API的路由和相关的处理函数
http_server.go 定义HTTP服务器的结构和行为
上网搜索发现,可能存在任意文件读取漏洞 CVE-2021-43798
漏洞存在于plugins.go中,当输入的 pluginId存在时,会匹配*内容,使用filepath.Clean清理路径中的多余字符后,直接拼接到pluginFilePath,然后使用os.open(pluginFilePath)打开该文件,最终回显到页面。
filepath.Clean()尽管进行了处理,但仍然可以利用。
并且plugins api权限为public,是未授权的,任何人都可以查看。
2.2 ql查询
1.生成数据库记得生成language=go
2.查询代码
Sink定义为os.open()
Source开始设置为api.go中的get(),但无法联通,后来将 source 定为 Params 函数, 可以成功连通
之前有师傅通过添加isAdditionalTaintStep 连接数据流
参考这位师傅的分析过程
safe6Sec/codeql-grafana: 用codeql分析grafana最新任意文件读取
总代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 import go import semmle.go.security.TaintedPathCustomizations::TaintedPath import codeql.dataflow.DataFlow class Source extends DataFlow::Node{ Source(){ exists( DataFlow::CallExpr call | call.getCalleeName().toString() = "Params"| call =this.asExpr() ) } } class Sink extends DataFlow::Node{ Sink(){ exists( Function f,CallExpr call | f.hasQualifiedName("os", "Open") and call.getTarget() = f and call.getAnArgument()=this.asExpr() ) } } class Configuration extends TaintTracking::Configuration{ Configuration(){ this = "xxx"} override predicate isSource(DataFlow::Node source) { source instanceof Source } override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } } from Configuration cfg, DataFlow::PathNode sink, DataFlow::PathNode source where cfg.hasFlowPath(source, sink) select source,sink