├── README.md ├── article └── 用codeql分析grafana最新任意文件读取.pdf └── ql ├── Log4j └── ok.ql ├── Sentinel ├── Sentinel.zip └── ok.ql └── grafana ├── 1.ql ├── 2.ql ├── 3.ql ├── 4.ql ├── 5.ql └── ok.ql /README.md: -------------------------------------------------------------------------------- 1 | # CodeqlNote 2 | 记录学习Codeql的笔记,国内资料真的挺少。摘抄各种大佬文章随便记的,比较乱,抽空整理。 3 | 4 | 5 | 6 | **该笔记还在整理中,对codeql感兴趣的师傅推荐直接看文末我收集的一些文章!!!** 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | # codeql 15 | 16 | 1. 这东西本质就是写各种过滤条件、各种数据流跟踪,给我的感觉就是在写面向对象的sql一样,所以在学习之前最好掌握面向对象思想,一门面向对象的编程语言,sql语句编写。 17 | 18 | 2. codeql工作原理主要是,利用分析引擎分析代码之间的关系,生成一个代码数据库。然后我们直接写ql就可以进行各种查询,如找某个方法或者某个类,找方法引用,跟踪某个参数的传递等等用法。 19 | 3. codeql里面的谓词其实就是把各种过滤条件封装成方法。 20 | 4. java里面是万物皆对象,我觉得codeql是万物皆表达式。 21 | 5. lgtm除了用来下数据库还可以用来搜索ql 22 | 6. 这个目录/ql/java/ql/src/Security放着一些官方的规则(java),可直接用。 23 | 7. 这个/ql/java/ql/src/experimental/Security目录下,一些还在实验中的规则(java)。 24 | 25 | 26 | 27 | # 相关下载 28 | 文档: https://codeql.github.com/docs/codeql-cli/ 29 | 二进制:https://github.com/github/codeql-cli-binaries 30 | 现成项目:https://github.com/github/vscode-codeql-starter 31 | 32 | 数据库下载,在线查询,规则搜索:https://lgtm.com/ 33 | 34 | 35 | # 生成数据库 36 | 37 | **ps:生成数据库之前,先保证被分析程序可以正常跑起来。** 38 | 第一步、创建索引代码数据库。得有数据库才能开始查询。 39 | 40 | ``` 41 | codeql database create --language= 42 | ``` 43 | 支持的语言及language对应关系如下 44 | 45 | 46 | | Language | Identity | 47 | | --------------------- | ---------- | 48 | | C/C++ | cpp | 49 | | C# | csharp | 50 | | Go | go | 51 | | Java | java | 52 | | javascript/Typescript | javascript | 53 | | Python | python | 54 | | Ruby | Ruby | 55 | 56 | 57 | 58 | 1、生成代码扫描数据库(java) 59 | 60 | ``` 61 | codeql database create D:\codeqldb/javasec --language=java --command="mvn clean install --file pom.xml -Dmaven.test.skip=true" --source-root=./javasec 62 | ``` 63 | 64 | 注:source-root 为源码路径,默认为当前目录,可不指定 65 | 66 | 一些常用命令 67 | 68 | ``` 69 | 跳过测试,构建 70 | --command="mvn clean install --file pom.xml -Dmaven.test.skip=true" 71 | 无论项目结果如何,构建从不失败 72 | --command="mvn -fn clean install --file pom.xml -Dmaven.test.skip=true" 73 | ``` 74 | 75 | 76 | 77 | 包含xml文件https://github.com/github/codeql/issues/3887 78 | 79 | 80 | 81 | ``` 82 | codeql database init --source-root= --language java 83 | codeql database trace-command --working-dir= 84 | codeql database index-files --language xml --include-extension .xml --working-dir= 85 | codeql database finalize 86 | ``` 87 | 88 | 将上面的命令拆分为如下4条命令,在index-files中将xml文件添加到CodeQL的数据库中CodeQL将XML文件包含到CodeQL数据库 89 | 90 | 第二种方案是在codeql-cli/java/tools/pre-finalize.cmd文件中插入--include "**/resources/**/*.xml" 91 | 92 | 93 | 94 | 2、更新数据库 95 | 96 | ``` 97 | codeql database upgrade database/javasec 98 | ``` 99 | 100 | 101 | 102 | 参考:https://help.semmle.com/lgtm-enterprise/admin/help/prepare-database-upload.html 103 | 104 | 105 | 106 | ### 编译与非编译 107 | 108 | 对于编译型语言来说,需要在创建索引数据库的时候增加编译的功能,主要是针对java,对于非编译性的语言来说,直接扫描吧 109 | 110 | 对于go来说,可编译也可不编译 111 | 112 | 113 | 114 | # 基础查询 115 | 116 | 117 | 118 | ### 过滤 Method 119 | 120 | #### 根据Method name查询 121 | 122 | ```java 123 | import java 124 | 125 | from Method method 126 | where method.hasName("toObject") 127 | select method 128 | ``` 129 | 130 | 把这个方法的`class` `name`也查出来 131 | 132 | ```java 133 | import java 134 | 135 | from Method method 136 | where method.hasName("toObject") 137 | select method, method.getDeclaringType() 138 | ``` 139 | 140 | #### 根据Method name 和 interface name 查询 141 | 142 | 比如我想查询`ContentTypeHandler` 的所有子类`toObject`方法 143 | 144 | ```java 145 | import java 146 | 147 | from Method method 148 | where method.hasName("toObject") and method.getDeclaringType().getASupertype().hasQualifiedName("org.apache.struts2.rest.handler", "ContentTypeHandler") 149 | select method 150 | ``` 151 | 152 | #### Call和Callable 153 | Callable表示可调用的方法或构造器的集合。 154 | 155 | Call表示调用Callable的这个过程(方法调用,构造器调用等等) 156 | 157 | 158 | 159 | 160 | ### MethodAccess 161 | 过滤 方法调用 162 | 163 | 一般是先查`method`,与`MethodAccess.getMethod()` 进行比较。 164 | 165 | 比如查`ContentTypeHandler` 的 `toObject()` 方法的调用。 166 | 167 | ```java 168 | import java 169 | 170 | from MethodAccess call, Method method 171 | where method.hasName("toObject") and method.getDeclaringType().getASupertype().hasQualifiedName("org.apache.struts2.rest.handler", "ContentTypeHandler") and call.getMethod() = method 172 | select call 173 | ``` 174 | 175 | 上面这种查询方式不行,只能查到`JsonLibHandler` 这样显式定义的。 176 | 177 | 怎么改进呢? 178 | 179 | 也可以使用`getAnAncestor()` 或者`getASupertype()*` 180 | 181 | ```java 182 | import java 183 | 184 | from MethodAccess call, Method method 185 | where method.hasName("toObject") and method.getDeclaringType().getAnAncestor().hasQualifiedName("org.apache.struts2.rest.handler", "ContentTypeHandler") and call.getMethod() = method 186 | select call 187 | ``` 188 | ### 过滤构造方法 189 | new File的参数为我们的sink点,所以构造ql 190 | ``` 191 | class FileContruct extends ClassInstanceExpr{ 192 | FileContruct(){ 193 | this.getConstructor().getDeclaringType*().hasQualifiedName("java.io", "File") 194 | } 195 | } 196 | ``` 197 | 198 | 199 | # codeql java规则目录 200 | 201 | 202 | 一些官方规则,可直接用。 203 | ``` 204 | -java 205 | 206 | --ql 207 | 208 | ---src 209 | 210 | ----Security(正式运行的规则) 211 | 212 | ----experimental(还在实验中的规则) 213 | 214 | ---lib 215 | 216 | ----semmle 217 | 218 | -----code 219 | 220 | ------java(这个下面都是框架相关的内容) 221 | ``` 222 | 223 | 224 | 225 | # 数据流跟踪 226 | 227 | Local Data Flow分析SPEL 228 | 229 | 本地数据流 230 | 本地数据流是单个方法(一旦变量跳出该方法即为数据流断开)或可调用对象中的数据流。本地数据流通常比全局数据流更容易、更快、更精确。 231 | 232 | ``` 233 | import java 234 | import semmle.code.java.frameworks.spring.SpringController 235 | import semmle.code.java.dataflow.TaintTracking 236 | from Call call,Callable parseExpression,SpringRequestMappingMethod route 237 | where 238 | call.getCallee() = parseExpression and 239 | parseExpression.getDeclaringType().hasQualifiedName("org.springframework.expression", "ExpressionParser") and 240 | parseExpression.hasName("parseExpression") and 241 | TaintTracking::localTaint(DataFlow::parameterNode(route.getARequestParameter()),DataFlow::exprNode(call.getArgument(0))) 242 | select route.getARequestParameter(),call 243 | ``` 244 | 245 | 246 | 247 | 全局数据流分析要继承`DataFlow::Configuration` 这个类,然后重载`isSource` 和`isSink` 方法 248 | 249 | ``` 250 | class MyConfig extends DataFlow::Configuration { 251 | MyConfig() { this = "Myconfig" } 252 | override predicate isSource(DataFlow::Node source) { 253 | .... 254 | 255 | } 256 | 257 | override predicate isSink(DataFlow::Node sink) { 258 | .... 259 | 260 | } 261 | } 262 | ``` 263 | 264 | # 数据流断的原因 265 | - 外部的方法,因为没有编译到数据库中,这个是最常见的,基本上市面上的扫描器都存在这个问题,说起来复杂,原因大概是因为构建数据流会随着扫描AST的复杂程度递增导致数据库过大,最后大家在时间和易用性上做了平衡,选择了编译直接依赖的内容进行查询,从而导致这个问题的存在。 266 | 267 | - 复杂的字符串拼接,例如append,一些其他的字符串赋值,这个一般出场都是空的,要自己去搞,当然会有一些类似fortify的自带了部分场景的连接,不过有的时候要自己去排查 268 | 269 | - 强制类型转换 270 | 271 | - 动态特性,例如class.ForName。codeQL有很好的反射类支持这个,对比fortify,你就知道什么是好,什么是不好。Fortify的类太简单了,你去看看codeQL官方手册里的类,简直对比下来就是指数级的,哪怕你看一眼 soot,都比fortify好。 272 | 273 | 274 | ## isAddtionalStep技巧 275 | isAddtionalStep使用就用最简单的二分法来定位,先前移sink,然后检测出来的话就移动到后面,直到找到哪个断开的地方。 276 | 冷知识:数据流是可以混用的,例如我们的sink又可以是一个hasFlow表达式 277 | 278 | 上面两点来自xsser师傅文章 279 | 280 | 281 | # 污点跟踪 282 | 283 | 284 | 285 | 全局污点跟踪分析要继承`TaintTracking::Configuration` 这个类,然后重载`isSource` 和`isSink` 方法 286 | 287 | ``` 288 | class VulConfig extends TaintTracking::Configuration { 289 | VulConfig() { this = "myConfig" } 290 | 291 | override predicate isSource(DataFlow::Node source) { 292 | 293 | } 294 | 295 | override predicate isSink(DataFlow::Node sink) { 296 | 297 | } 298 | } 299 | 300 | from VulConfig config, DataFlow::PathNode source, DataFlow::PathNode sink 301 | where config.hasFlowPath(source, sink) 302 | select sink.getNode(), source, sink, "source are" 303 | ``` 304 | 305 | 306 | 307 | # 白盒扫描 308 | 309 | ql库集成了许多常见的安全漏洞,可以直接拿来扫描项目源码 310 | 311 | https://codeql.github.com/codeql-query-help/java/ 312 | 313 | 314 | 315 | 下面是写好的 316 | 317 | java 318 | 1、zip slip(zip解压覆盖任意文件) 319 | 320 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-022/ZipSlip.ql 321 | 322 | 2、命令注入 323 | 324 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-078/ExecUnescaped.ql 325 | 326 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-078/ExecTainted.ql 327 | 328 | 3、cookie安全 329 | 330 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-312/CleartextStorageCookie.ql 331 | 332 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-614/InsecureCookie.ql 333 | 334 | 4、XSS 335 | 336 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-079/XSS.ql 337 | 338 | 5、依赖漏洞 339 | 340 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-1104/MavenPomDependsOnBintray.ql 341 | 342 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-829/InsecureDependencyResolution.ql 343 | 344 | 6、反序列化 345 | 346 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.ql 347 | 348 | 7、http头注入 349 | 350 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-113/NettyResponseSplitting.ql 351 | 352 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-113/ResponseSplitting.ql 353 | 354 | 8、url跳转 355 | 356 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-601/UrlRedirect.ql 357 | 358 | 9、ldap注入 359 | 360 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-090/LdapInjection.ql 361 | 362 | 10、sql注入 363 | 364 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-089/SqlTainted.ql 365 | 366 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-089/SqlUnescaped.ql 367 | 368 | 11、file权限&目录注入 369 | 370 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-732/ReadingFromWorldWritableFile.ql 371 | 372 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-022/TaintedPath.ql 373 | 374 | 12、xml注入 375 | 376 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-611/XXE.ql 377 | 378 | 13、SSL校验 379 | 380 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-297/UnsafeHostnameVerification.ql 381 | 382 | 14、弱加密 383 | 384 | https://github.com/github/codeql/java/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql 385 | 386 | 15、随机数种子可预测 387 | 388 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-335/PredictableSeed.ql 389 | 390 | 391 | codeql analyze命令可以执行单个ql文件,目录下所有ql文件,和查询suite(.qls) 392 | 393 | 394 | 395 | 白盒扫描使用如下命令(执行所有漏洞类查询) 396 | 397 | ``` 398 | codeql database analyze source_database_name qllib/java/ql/src/codeql-suites/java-security-extended.qls --format=csv --output=java-results.csv 399 | ``` 400 | 401 | 如果是自己写可用于analyze的必须按规范写,包含元数据@kind,如下这种 402 | 403 | ``` 404 | /** 405 | * @name Incomplete regular expression for hostnames 406 | * @description Matching a URL or hostname against a regular expression that contains an unescaped 407 | * dot as part of the hostname might match more hostnames than expected. 408 | * @kind path-problem 409 | * @problem.severity warning 410 | * @security-severity 7.8 411 | * @precision high 412 | * @id go/incomplete-hostname-regexp 413 | * @tags correctness 414 | * security 415 | * external/cwe/cwe-20 416 | */ 417 | ``` 418 | 419 | 420 | 421 | 422 | 423 | 424 | # Chrome书签 425 | 自己学习codeql 看过的一些文章 426 | 427 | - [CodeQL从入门到放弃 - FreeBuf网络安全行业门户](https://www.freebuf.com/articles/web/283795.html) 428 | - [使用codeql挖掘fastjson利用链 - 先知社区](https://xz.aliyun.com/t/7482) 429 | - [CodeQL documentation](https://codeql.github.com/docs/) 430 | - https://www.4hou.com/search-post?page=4&keywords=codeql 431 | - [代码分析平台CodeQL学习手记(十七) - 嘶吼 RoarTalk – 回归最本质的信息安全,互联网安全新媒体,4hou.com](https://www.4hou.com/posts/o6wX) 432 | - [Query console - LGTM](https://lgtm.com/query/lang:java/) 433 | - [使用codeql 挖掘 ofcms - 安全客,安全资讯平台](https://www.anquanke.com/post/id/203674) 434 | - [haby0/mark: notes](https://github.com/haby0/mark) 435 | - [codeql学习——污点分析 - 先知社区](https://xz.aliyun.com/t/7789) 436 | - [codeql学习笔记 - 知乎](https://zhuanlan.zhihu.com/p/354275826) 437 | - [github/vscode-codeql-starter: Starter workspace to use with the CodeQL extension for Visual Studio Code.](https://github.com/github/vscode-codeql-starter) 438 | - [codeql学习——污点分析 - 先知社区](https://xz.aliyun.com/t/7789#toc-0) 439 | - [CodeQL for Golang Practise(3)](http://f4bb1t.com/post/2020/12/16/codeql-for-golang-practise3/) 440 | - [CodeQL静态代码扫描之实现关联接口、入参、和危险方法并自动化构造payload及抽象类探究](https://mp.weixin.qq.com/s/Rqo12z9mapwlj6wGHZ1zZA) 441 | - [Codeql分析Vulnerability-GoApp - FreeBuf网络安全行业门户](https://www.freebuf.com/articles/web/253491.html) 442 | - [codeql反序列化分析](https://github.com/githubsatelliteworkshops/codeql) 443 | - [[原创\]58集团白盒代码审计系统建设实践2:深入理解SAST-业务安全-看雪论坛-安全社区|安全招聘|bbs.pediy.com](https://bbs.pediy.com/thread-266995.htm#msg_header_h1_4) 444 | - [楼兰#CodeQL](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=Mzg4ODU4ODYzOQ==&action=getalbum&album_id=1970201600723910658&scene=173&from_msgid=2247484983&from_itemidx=1&count=3&nolastread=1#wechat_redirect) 445 | - [CodeQL学习笔记 | Gamous'Site](http://blog.gamous.cn/post/codeql/) 446 | - [language:go - Search - LGTM](https://lgtm.com/search?q=language%3Ago&t=rules) 447 | - [CodeQL 和代码扫描简介 - GeekMasher 的博客](https://geekmasher.dev/posts/sast/codeql-introduction) 448 | - [CVE-2018-11776: 如何使用CodeQL发现5个 Apache Struts RCEs](https://mp.weixin.qq.com/s/LmOFGAhqAKiO8VDQW4vvLg) 449 | - [CodeQL静态代码扫描规则编写之RemoteFlowSource](https://mp.weixin.qq.com/s/jVZ3Op8FYBmiFAV3p0li3w) 450 | - [CodeQL静态代码扫描之抽象类探究](https://mp.weixin.qq.com/s/KQso2nvWx737smunUHwXag) 451 | - [Codeql规则编写入门](https://mp.weixin.qq.com/s/sAUSgRAohFlmzwSkkWjp9Q) 452 | - [About LGTM - Help - LGTM](https://lgtm.com/help/lgtm/about-lgtm) 453 | - [LGTM help & documentation](https://help.semmle.com/home/help/home.html) 454 | - [Capture the flag | GitHub Security Lab](https://securitylab.github.com/ctf/) 455 | - [CodeQL笔记 | LFYSec](https://lfysec.top/2020/06/03/CodeQL笔记/) 456 | - [CodeQL学习——CodeQl数据流分析 - bamb00 - 博客园](https://www.cnblogs.com/goodhacker/p/13583650.html) 457 | - [分类: codeql - 食兔人的博客](https://blog.ycdxsb.cn/categories/research/codeql/) 458 | - [CodeQL - butter-fly](https://yourbutterfly.github.io/note-site/module/semmle-ql/codeql/) 459 | - [表达式](https://www.4hou.com/posts/lM11) 460 | - [mark/CodeQL-数据流在Java中的使用.md at master · haby0/mark](https://github.com/haby0/mark/blob/master/articles/2021/CodeQL-数据流在Java中的使用.md) 461 | - [github/securitylab: Resources related to GitHub Security Lab](https://github.com/github/securitylab) 462 | - [CodeQL从0到1(内附Shiro检测demo) - 安全客,安全资讯平台](https://www.anquanke.com/post/id/255721) 463 | - [codeql挖掘React应用的XSS实践 | Image's blog](https://hexo.imagemlt.xyz/post/javascript-codeql-learning/) 464 | - [SummerSec/learning-codeql: CodeQL Java 全网最全的中文学习资料](https://github.com/SummerSec/learning-codeql) 465 | - [CodeQL query help for Go — CodeQL query help documentation](https://codeql.github.com/codeql-query-help/go/#) 466 | - [codeql使用指南_zzzzfeng的博客-CSDN博客_codeql使用](https://blog.csdn.net/haoren_xhf/article/details/115064677) 467 | - [Apache Dubbo:条条大路通RCE | GitHub 安全实验室](https://securitylab.github.com/research/apache-dubbo/) 468 | - [如何用CodeQL数据流复现 apache kylin命令执行漏洞 - 先知社区](https://xz.aliyun.com/t/8240) 469 | - [如何利用CodeQL挖掘CVE-2020-10199 - 安全客,安全资讯平台](https://www.anquanke.com/post/id/202987) 470 | - [南大软件分析课程](https://space.bilibili.com/2919428?share_medium=iphone&share_plat=ios&share_session_id=6851D997-0AC6-4C67-B858-BD1E6258C548&share_source=COPY&share_tag=s_i×tamp=1639480132&unique_k=8wQBAkV) 471 | - [各种语言危险sink](https://github.com/haby0/sec-note) 472 | - [利用CodeQL分析并挖掘Log4j漏洞](https://mp.weixin.qq.com/s/JYco8DysQNszMohH6zJEGw) 473 | - [几张图结构看懂CodeQL数据流](https://mp.weixin.qq.com/s/3mlRedFwPz31Rwe7VDBAuA) 474 | - [Firebasky师傅的笔记](https://github.com/Firebasky/CodeqlLearn) 475 | - [凡人老哥codeql学习资料](https://github.com/SummerSec/learning-codeql) 476 | - [fynch3r师傅的笔记](https://fynch3r.github.io/tags/CodeQL/) 477 | - [CodeQL 目录、框架和一些有趣的东西](https://mp.weixin.qq.com/s/zSI157qJXYivSvyxHzXALQ) 478 | - [CodeQL 提升篇](https://tttang.com/archive/1415/) 479 | - [CodeQL与OpenJDK的联动](https://fynch3r.github.io/%E8%AE%B0%E4%B8%80%E6%AC%A1CodeQL%E4%B8%8EOpenJDK%E7%9A%84%E8%81%94%E5%8A%A8/) 480 | - [深入理解CodeQL](https://github.com/ASTTeam/CodeQL) 481 | - [CodeQL 踩坑指南 - Java](https://tttang.com/archive/1497/) 482 | - [楼兰师傅codeql学习笔记](https://www.yuque.com/loulan-b47wt/rc30f7) 483 | - [CodeQL能找到log4shell(CVE-2021-44228)漏洞吗](https://mp.weixin.qq.com/s/CkCnAAc0OafEcLiBV17wdg) 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | -------------------------------------------------------------------------------- /article/用codeql分析grafana最新任意文件读取.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/safe6Sec/CodeqlNote/fdd1435c473ea5abecf584b7e7425fb9f92cbf9b/article/用codeql分析grafana最新任意文件读取.pdf -------------------------------------------------------------------------------- /ql/Log4j/ok.ql: -------------------------------------------------------------------------------- 1 | /** 2 | * @name Tainttrack Context lookup 3 | * @description from https://mp.weixin.qq.com/s/JYco8DysQNszMohH6zJEGw 4 | * @kind path-problem 5 | * 6 | */ 7 | 8 | import java 9 | import semmle.code.java.dataflow.FlowSources 10 | import DataFlow::PathGraph 11 | 12 | class Context extends RefType { 13 | Context() { 14 | this.hasQualifiedName("javax.naming", "Context") 15 | or 16 | this.hasQualifiedName("javax.naming", "InitialContext") 17 | or 18 | this.hasQualifiedName("org.springframework.jndi", "JndiCallback") 19 | or 20 | this.hasQualifiedName("org.springframework.jndi", "JndiTemplate") 21 | or 22 | this.hasQualifiedName("org.springframework.jndi", "JndiLocatorDelegate") 23 | or 24 | this.hasQualifiedName("org.apache.shiro.jndi", "JndiCallback") 25 | or 26 | this.getQualifiedName().matches("%JndiCallback") 27 | or 28 | this.getQualifiedName().matches("%JndiLocatorDelegate") 29 | or 30 | this.getQualifiedName().matches("%JndiTemplate") 31 | } 32 | } 33 | 34 | class Logger extends RefType { 35 | Logger() { this.hasQualifiedName("org.apache.logging.log4j.spi", "AbstractLogger") } 36 | } 37 | 38 | class LoggerInput extends Method { 39 | LoggerInput() { 40 | this.getDeclaringType() instanceof Logger and 41 | this.hasName("error") and 42 | this.getNumberOfParameters() = 1 43 | } 44 | 45 | Parameter getAnUntrustedParameter() { result = this.getParameter(0) } 46 | } 47 | 48 | predicate isLookup(Expr arg) { 49 | exists(MethodAccess ma | 50 | ma.getMethod().getName() = "lookup" and 51 | ma.getMethod().getDeclaringType() instanceof Context and 52 | arg = ma.getArgument(0) 53 | ) 54 | } 55 | 56 | class TainttrackLookup extends TaintTracking::Configuration { 57 | TainttrackLookup() { this = "TainttrackLookup" } 58 | 59 | override predicate isSource(DataFlow::Node source) { 60 | exists(LoggerInput LoggerMethod | source.asParameter() = LoggerMethod.getAnUntrustedParameter()) 61 | } 62 | 63 | override predicate isAdditionalTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) { 64 | exists(MethodAccess ma, MethodAccess ma2 | 65 | ma.getMethod() 66 | .getDeclaringType() 67 | .hasQualifiedName("org.apache.logging.log4j.core.impl", "ReusableLogEventFactory") and 68 | ma.getMethod().hasName("createEvent") and 69 | fromNode.asExpr() = ma.getArgument(5) and 70 | ma2.getMethod() 71 | .getDeclaringType() 72 | .hasQualifiedName("org.apache.logging.log4j.core.config", "LoggerConfig") and 73 | ma2.getMethod().hasName("log") and 74 | ma2.getMethod().getNumberOfParameters() = 2 and 75 | toNode.asExpr() = ma2.getArgument(0) 76 | ) 77 | } 78 | 79 | override predicate isSink(DataFlow::Node sink) { 80 | exists(Expr arg | 81 | isLookup(arg) and 82 | sink.asExpr() = arg 83 | ) 84 | } 85 | } 86 | 87 | from TainttrackLookup config, DataFlow::PathNode source, DataFlow::PathNode sink 88 | where config.hasFlowPath(source, sink) 89 | select sink.getNode(), source, sink, "unsafe lookup", source.getNode(), "this is user input" 90 | -------------------------------------------------------------------------------- /ql/Sentinel/Sentinel.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/safe6Sec/CodeqlNote/fdd1435c473ea5abecf584b7e7425fb9f92cbf9b/ql/Sentinel/Sentinel.zip -------------------------------------------------------------------------------- /ql/Sentinel/ok.ql: -------------------------------------------------------------------------------- 1 | /** 2 | * @kind path-problem 3 | */ 4 | 5 | import java 6 | import semmle.code.java.dataflow.TaintTracking 7 | import semmle.code.java.dataflow.FlowSources 8 | import DataFlow::PathGraph 9 | 10 | 11 | /** 12 | * 把添加machine到定时任务执行连起来 13 | * 14 | */ 15 | predicate machine(DataFlow::Node expSrc, DataFlow::Node expDest) { 16 | exists(MethodAccess ma, Method me, MethodAccess ma1,Method me1 | 17 | me.getName() = "addMachine" and 18 | me = ma.getMethod() and 19 | expSrc.asExpr() = ma.getAnArgument() and 20 | me1.getName()="fetchOnce" and 21 | ma1.getMethod() = me1 and 22 | ma1.getAnArgument() = expDest.asExpr() 23 | ) 24 | } 25 | 26 | 27 | /** 28 | * 把添加machine到每个MachineInfo调用自身方法连起来 29 | */ 30 | predicate machine1(DataFlow::Node expSrc, DataFlow::Node expDest) { 31 | exists(MethodAccess ma, Method me, MethodAccess ma1,Method me1 | 32 | me.getName() = "addMachine" and 33 | me = ma.getMethod() and 34 | expSrc.asExpr() = ma.getAnArgument() and 35 | me1.getQualifiedName().matches("%MachineInfo%") and 36 | me1.getName().matches("%get%") and 37 | ma1.getMethod() = me1 and 38 | expDest.asExpr() = ma1 39 | ) 40 | } 41 | 42 | 43 | predicate machine2(DataFlow::Node expSrc, DataFlow::Node expDest) { 44 | exists(MethodAccess ma, Method me, MethodAccess ma1,Method me1 | 45 | me.getName() = "getMachines" and 46 | me = ma.getMethod() and 47 | expSrc.asExpr() = ma and 48 | me1.getQualifiedName().matches("%MachineInfo%") and 49 | me1.getName().matches("%get%") and 50 | ma1.getMethod() = me1 and 51 | expDest.asExpr() = ma1 52 | ) 53 | } 54 | 55 | // predicate machine2(DataFlow::Node expSrc, DataFlow::Node expDest) { 56 | // exists(MethodAccess ma, Method me | 57 | // me.getName() = "addMachine" and 58 | // me = ma.getMethod() and 59 | // expSrc.asExpr() = ma.getAnArgument() and 60 | // expDest.asExpr() = ma.getAnArgument() 61 | // ) 62 | // } 63 | 64 | 65 | class SsrfConfig extends TaintTracking::Configuration { 66 | SsrfConfig() { this = "SsrfConfig" } 67 | 68 | override predicate isSource(DataFlow::Node src) { 69 | src instanceof RemoteFlowSource 70 | } 71 | 72 | 73 | // override predicate isSink(DataFlow::Node sink) { 74 | // exists(Method me, MethodAccess ma| me.getName() = "execute" and ma.getMethod() = me and 75 | // ma.getAnArgument() = sink.asExpr()) 76 | // } 77 | 78 | override predicate isSink(DataFlow::Node sink) { 79 | exists(ConstructorCall call,Class clz| 80 | call.getAnArgument() = sink.asExpr() and call.getConstructedType()=clz and clz.getName()="HttpGet") 81 | } 82 | 83 | 84 | // override predicate isSink(DataFlow::Node sink) { 85 | // exists(Method method, MethodAccess call | 86 | // method.hasName("execute") and method.getDeclaringType().getAnAncestor().hasQualifiedName("org.apache.http.impl.nio.client", "CloseableHttpAsyncClient") and call.getMethod() = method 87 | // and 88 | // sink.asExpr() = call.getArgument(0) 89 | // ) 90 | // } 91 | 92 | override predicate isAdditionalTaintStep(DataFlow::Node expSrc, DataFlow::Node expDest) { 93 | exists(MethodAccess ma, Method me, MethodAccess maa,Method mee | 94 | // me.getQualifiedName().matches("%MachineInfo%") and 95 | me.getName()="setIp" and 96 | ma.getMethod() = me and 97 | expSrc.asExpr() = ma.getAnArgument() and 98 | // mee.getQualifiedName().matches("%MachineInfo%") and 99 | mee.getName().matches("getIp") and 100 | maa.getMethod() = mee and 101 | expDest.asExpr() = maa 102 | ) 103 | } 104 | } 105 | 106 | from SsrfConfig config, DataFlow::PathNode source, DataFlow::PathNode sink 107 | where config.hasFlowPath(source, sink) 108 | select source.getNode(), source, sink, "source" 109 | -------------------------------------------------------------------------------- /ql/grafana/1.ql: -------------------------------------------------------------------------------- 1 | import go 2 | 3 | from Function fun 4 | where fun.hasQualifiedName("os", "Open") 5 | select fun,fun.getAReference() -------------------------------------------------------------------------------- /ql/grafana/2.ql: -------------------------------------------------------------------------------- 1 | import go 2 | 3 | 4 | from Function fun,CallExpr call 5 | where fun.hasQualifiedName("github.com/grafana/grafana/pkg/api/routing.RouteRegister", 6 | ["Get","Post","Delete","Put","Patch","Any"]) and call.getTarget() = fun 7 | 8 | select fun.getAReference(),call.getAnArgument().toString() -------------------------------------------------------------------------------- /ql/grafana/3.ql: -------------------------------------------------------------------------------- 1 | /** 2 | * @kind path-problem 3 | */ 4 | 5 | import go 6 | import DataFlow::PathGraph 7 | 8 | 9 | class GfSource extends DataFlow::Node { 10 | GfSource(){ 11 | exists( Function fun| 12 | fun.hasQualifiedName("github.com/grafana/grafana/pkg/api/routing.RouteRegister", 13 | ["Get","Post","Delete","Put","Patch","Any"]) and 14 | //["Get","Post"]) and 15 | fun.getAReference()=this.asExpr() 16 | ) 17 | } 18 | } 19 | 20 | 21 | class Gfconfig extends TaintTracking::Configuration{ 22 | 23 | Gfconfig() { this = "Gfconfig" } 24 | 25 | override predicate isSource(DataFlow::Node source) { 26 | source instanceof GfSource 27 | } 28 | 29 | override predicate isSink(DataFlow::Node sink) { 30 | exists(Function fun ,CallExpr call| 31 | fun.hasQualifiedName("os", "Open") and 32 | call.getTarget() = fun and 33 | call.getAnArgument()= sink.asExpr() 34 | ) 35 | } 36 | 37 | /** 38 | * sink参数只能是两个,第二个参数才是真正的sink 39 | */ 40 | override predicate isAdditionalTaintStep(DataFlow::Node expSrc, DataFlow::Node expDest) { 41 | exists(CallExpr call| 42 | call=expSrc.asExpr() and 43 | call.getArgument(0).getType().toString()="string" and 44 | call.getNumArgument()=2 and 45 | call.getArgument(1).(CallExpr).getTarget().getAParameter()=expDest.asParameter() 46 | ) 47 | } 48 | } 49 | 50 | from Gfconfig gf,DataFlow::PathNode source,DataFlow::PathNode sink 51 | where gf.hasFlowPath(source, sink) 52 | select source.getNode(), source, sink, "test" -------------------------------------------------------------------------------- /ql/grafana/4.ql: -------------------------------------------------------------------------------- 1 | /** 2 | * @kind path-problem 3 | */ 4 | 5 | import go 6 | import DataFlow::PathGraph 7 | 8 | 9 | // class GfSource extends DataFlow::Node { 10 | // GfSource(){ 11 | // exists( Function fun, CallExpr call| 12 | // fun.hasQualifiedName("github.com/grafana/grafana/pkg/api/routing.RouteRegister", 13 | // ["Get","Post","Delete","Put","Patch","Any"]) and 14 | // //["Get","Post"]) and 15 | // call.getTarget() = fun and 16 | // call.getCalleeExpr()= this.asExpr() 17 | // ) 18 | // } 19 | // } 20 | 21 | class GfSource1 extends DataFlow::Node { 22 | GfSource1(){ 23 | exists( Function fun, CallExpr call,SelectorExpr se| 24 | call.getTarget().hasQualifiedName("github.com/grafana/grafana/pkg/api/routing.RouteRegister", 25 | ["Get","Post","Delete","Put","Patch","Any"]) and 26 | //["Get","Post"]) and 27 | (call.getAnArgument() =se or call.getAnArgument().getAChildExpr()=se) and 28 | fun.getAReference() = se.getSelector() and 29 | fun.getAParameter()= this.asParameter() 30 | ) 31 | } 32 | } 33 | 34 | // class GfSource1 extends DataFlow::Node { 35 | // GfSource1(){ 36 | // exists(Type tp, Function fun,TypeEntity ent | 37 | // tp.hasQualifiedName("github.com/grafana/grafana/pkg/api", "HTTPServer")and 38 | // ent = tp.getEntity() and 39 | // ent.getAReference().getEnclosingFunction() = fun.getFuncDecl()) 40 | // } 41 | // } 42 | 43 | // predicate isApi(DataFlow::Node expSrc, DataFlow::Node expDest) { 44 | // exists(CallExpr call| 45 | // call=expSrc.asExpr() and 46 | // call.getArgument(0).getType().toString()="string" and 47 | // call.getNumArgument()=2 and 48 | // call.getArgument(1).(CallExpr).getTarget().getAParameter()=expDest.asParameter() 49 | // ) 50 | // } 51 | 52 | // predicate isApi1(DataFlow::Node expSrc, DataFlow::Node expDest) { 53 | // exists(CallExpr call| 54 | // call=expSrc.asExpr() and 55 | // call.getArgument(0).getType().toString()="string" and 56 | // call.getNumArgument()=2 and 57 | // call.getArgument(1).(CallExpr).getTarget().getAParameter()=expDest.asParameter() 58 | // ) 59 | // } 60 | 61 | 62 | predicate isOther(DataFlow::Node expSrc, DataFlow::Node expDest) { 63 | exists(CallExpr call, SimpleAssignStmt sas| 64 | call.getTarget().getName().toString()="Params" and 65 | call.getArgument(0)=expSrc.asExpr() and 66 | sas.getRhs().getAChild()=call.getParent*().getAChild() and 67 | sas.getRhs()=expDest.asExpr() 68 | ) 69 | } 70 | 71 | // predicate isWrap(DataFlow::Node expSrc, DataFlow::Node expDest) { 72 | // exists(CallExpr call,Function fun| 73 | // fun.hasQualifiedName("github.com/grafana/grafana/pkg/api/routing", "Wrap") and 74 | // fun.getAReference() = expSrc.asExpr() and 75 | // call.getTarget() = fun and 76 | // call.getArgument(0).(CallExpr).getTarget().getAParameter()=expDest.asParameter() 77 | // ) 78 | // } 79 | 80 | class Gfconfig extends TaintTracking::Configuration{ 81 | 82 | Gfconfig() { this = "Gfconfig" } 83 | 84 | override predicate isSource(DataFlow::Node source) { 85 | source instanceof GfSource1 86 | } 87 | 88 | override predicate isSink(DataFlow::Node sink) { 89 | exists(Function fun ,CallExpr call| 90 | fun.hasQualifiedName("os", "Open") and 91 | call.getTarget() = fun and 92 | call.getAnArgument()= sink.asExpr() 93 | ) 94 | } 95 | 96 | /** 97 | * sink参数只能是两个,第二个参数才是真正的sink 98 | */ 99 | override predicate isAdditionalTaintStep(DataFlow::Node expSrc, DataFlow::Node expDest) { 100 | isOther(expSrc, expDest) 101 | } 102 | } 103 | 104 | from Gfconfig gf,DataFlow::PathNode source,DataFlow::PathNode sink 105 | where gf.hasFlowPath(source, sink) 106 | select source.getNode(), source, sink, "test" -------------------------------------------------------------------------------- /ql/grafana/5.ql: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * 赋值表达式 4 | */ 5 | import go 6 | 7 | 8 | from SimpleAssignStmt sas 9 | select sas,sas.getRhs().getAChildExpr() -------------------------------------------------------------------------------- /ql/grafana/ok.ql: -------------------------------------------------------------------------------- 1 | /** 2 | * @kind path-problem 3 | */ 4 | 5 | import go 6 | import DataFlow::PathGraph 7 | 8 | 9 | 10 | 11 | class GfSource1 extends DataFlow::Node { 12 | GfSource1(){ 13 | exists( Function fun, CallExpr call,SelectorExpr se| 14 | call.getTarget().hasQualifiedName("github.com/grafana/grafana/pkg/api/routing.RouteRegister", 15 | ["Get","Post","Delete","Put","Patch","Any"]) and 16 | //["Get","Post"]) and 17 | (call.getAnArgument() =se or call.getAnArgument().getAChildExpr()=se) and 18 | fun.getAReference() = se.getSelector() and 19 | fun.getAParameter()= this.asParameter() 20 | ) 21 | } 22 | } 23 | 24 | 25 | 26 | predicate isOther(DataFlow::Node expSrc, DataFlow::Node expDest) { 27 | exists(CallExpr call, SimpleAssignStmt sas| 28 | call.getTarget().getName().toString()="Params" and 29 | call.getArgument(0)=expSrc.asExpr() and 30 | sas.getRhs().getAChild()=call.getParent*().getAChild() and 31 | sas.getRhs()=expDest.asExpr() 32 | ) 33 | } 34 | 35 | 36 | 37 | class Gfconfig extends TaintTracking::Configuration{ 38 | 39 | Gfconfig() { this = "Gfconfig" } 40 | 41 | override predicate isSource(DataFlow::Node source) { 42 | source instanceof GfSource1 43 | } 44 | 45 | override predicate isSink(DataFlow::Node sink) { 46 | exists(Function fun ,CallExpr call| 47 | fun.hasQualifiedName("os", "Open") and 48 | call.getTarget() = fun and 49 | call.getAnArgument()= sink.asExpr() 50 | ) 51 | } 52 | 53 | /** 54 | * sink参数只能是两个,第二个参数才是真正的sink 55 | */ 56 | override predicate isAdditionalTaintStep(DataFlow::Node expSrc, DataFlow::Node expDest) { 57 | isOther(expSrc, expDest) 58 | } 59 | } 60 | 61 | from Gfconfig gf,DataFlow::PathNode source,DataFlow::PathNode sink 62 | where gf.hasFlowPath(source, sink) 63 | select source.getNode(), source, sink, "test" --------------------------------------------------------------------------------