├── README.md └── example ├── Datagear └── 任意文件读取.md ├── Hystrix └── ssrf.md └── Sentinel └── ssrf.md /README.md: -------------------------------------------------------------------------------- 1 | # CodeqlLearn 2 | 3 | >在safe6sec师傅的基础上修改的,更加适合自己 4 | 5 | # AST 6 | 7 | https://www.jianshu.com/p/ff8ec920f5b9 8 | 9 | https://www.jianshu.com/p/4bd5dc13f35a 10 | 11 | https://www.jianshu.com/p/68fcbc154c2f 12 | 13 | # 学习过程 14 | 15 | 自己学习codeql 看过的一些文章 16 | 17 | - [CodeQL从入门到放弃](https://www.freebuf.com/articles/web/283795.html) :heavy_check_mark: 18 | - [codeQL入门](https://me.xxf.world/post/codeql-huan-jing-da-jian/) :heavy_check_mark: 19 | - [Codeql 入门2](https://mp.weixin.qq.com/s?__biz=Mzg5OTQ3NzA2MQ==&mid=2247485016&idx=1&sn=983c23cd5cff4310ee233b21444815f4&chksm=c053fd72f72474647ba9d70e23ba81196f01055550d6b8ead0eebb67df7dc7aac15cda6ae05b&mpshare=1&scene=23&srcid=1229z6KsvgKYZRrPzIwGONPb&sharer_sharetime=1640768952290&sharer_shareid=33a823b10ae99f33a60db621d83241cb#rd) :heavy_check_mark: 20 | - [CodeQL笔记](https://lfysec.top/2020/06/03/CodeQL%E7%AC%94%E8%AE%B0/) :heavy_check_mark: 21 | - [代码分析引擎 CodeQL 初体验](https://paper.seebug.org/1078) :heavy_check_mark: 22 | - [codeql学习笔记](https://zhuanlan.zhihu.com/p/354275826) :heavy_check_mark: 23 | - [CodeQL学习——CodeQl数据流分析 - bamb00 - 博客园](https://www.cnblogs.com/goodhacker/p/13583650.html) :heavy_check_mark: 24 | - [CodeQL for Golang Practise(3)](http://f4bb1t.com/post/2020/12/16/codeql-for-golang-practise3/) 25 | - [CodeQL静态代码扫描之实现关联接口、入参、和危险方法并自动化构造payload及抽象类探究](https://mp.weixin.qq.com/s/Rqo12z9mapwlj6wGHZ1zZA) 26 | - [Codeql分析Vulnerability-GoApp - FreeBuf网络安全行业门户](https://www.freebuf.com/articles/web/253491.html) 27 | - [codeql反序列化分析](https://github.com/githubsatelliteworkshops/codeql) 28 | - [[原创\]58集团白盒代码审计系统建设实践2:深入理解SAST-业务安全-看雪论坛-安全社区|安全招聘|bbs.pediy.com](https://bbs.pediy.com/thread-266995.htm#msg_header_h1_4) 29 | - [楼兰#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) 30 | - [CodeQL学习笔记 | Gamous'Site](http://blog.gamous.cn/post/codeql/) 31 | - [language:go - Search - LGTM](https://lgtm.com/search?q=language%3Ago&t=rules) 32 | - [CodeQL 和代码扫描简介 - GeekMasher 的博客](https://geekmasher.dev/posts/sast/codeql-introduction) 33 | - [CVE-2018-11776: 如何使用CodeQL发现5个 Apache Struts RCEs](https://mp.weixin.qq.com/s/LmOFGAhqAKiO8VDQW4vvLg) 34 | - [CodeQL静态代码扫描规则编写之RemoteFlowSource](https://mp.weixin.qq.com/s/jVZ3Op8FYBmiFAV3p0li3w) 35 | - [CodeQL静态代码扫描之抽象类探究](https://mp.weixin.qq.com/s/KQso2nvWx737smunUHwXag) 36 | - [Codeql规则编写入门](https://mp.weixin.qq.com/s/sAUSgRAohFlmzwSkkWjp9Q) 37 | - [About LGTM - Help - LGTM](https://lgtm.com/help/lgtm/about-lgtm) 38 | - [LGTM help & documentation](https://help.semmle.com/home/help/home.html) 39 | - [Capture the flag | GitHub Security Lab](https://securitylab.github.com/ctf/) 40 | - [分类: codeql - 食兔人的博客](https://blog.ycdxsb.cn/categories/research/codeql/) 41 | - [CodeQL - butter-fly](https://yourbutterfly.github.io/note-site/module/semmle-ql/codeql/) 42 | - [表达式](https://www.4hou.com/posts/lM11) 43 | - [mark/CodeQL-数据流在Java中的使用.md at master · haby0/mark](https://github.com/haby0/mark/blob/master/articles/2021/CodeQL-数据流在Java中的使用.md) 44 | - [github/securitylab: Resources related to GitHub Security Lab](https://github.com/github/securitylab) 45 | - [codeql挖掘React应用的XSS实践 | Image's blog](https://hexo.imagemlt.xyz/post/javascript-codeql-learning/) 46 | - [SummerSec/learning-codeql: CodeQL Java 全网最全的中文学习资料](https://github.com/SummerSec/learning-codeql) 47 | - [CodeQL query help for Go — CodeQL query help documentation](https://codeql.github.com/codeql-query-help/go/#) 48 | - [codeql使用指南_zzzzfeng的博客-CSDN博客_codeql使用](https://blog.csdn.net/haoren_xhf/article/details/115064677) 49 | - [Apache Dubbo:条条大路通RCE | GitHub 安全实验室](https://securitylab.github.com/research/apache-dubbo/) 50 | - [南大软件分析课程](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) 51 | - [各种语言危险sink](https://github.com/haby0/sec-note) 52 | 53 | # 环境搭建 54 | - [编译OpenJDK8并生成CodeQL数据库](https://blog.csdn.net/mole_exp/article/details/122330521) :heavy_check_mark: **对jdk进行ql用处多多。。** 55 | 56 | # 真实例子 57 | 58 | - [如何利用CodeQL挖掘CVE-2020-10199](https://www.anquanke.com/post/id/202987) :heavy_check_mark: **可以使用污点跟踪TaintTracking::Configuration 并且添加isAdditionalTaintStep** 59 | - [利用CodeQL分析并挖掘Log4j漏洞](https://mp.weixin.qq.com/s/JYco8DysQNszMohH6zJEGw) 60 | - [使用codeql 挖掘 ofcms](https://www.anquanke.com/post/id/203674) :heavy_check_mark: 61 | - [使用codeql挖掘fastjson利用链](https://xz.aliyun.com/t/7482) :heavy_check_mark: 62 | - [用codeql分析grafana最新任意文件读取]() :heavy_check_mark: 63 | - [codeql学习——污点分析](https://xz.aliyun.com/t/7789) :heavy_check_mark: 64 | - [CodeQL从0到1(内附Shiro检测demo)](https://www.anquanke.com/post/id/255721) :heavy_check_mark: 65 | - [Codeql分析Vulnerability-GoApp](https://www.freebuf.com/articles/web/253491.html) :heavy_check_mark: (go语言) 66 | - [如何用CodeQL数据流复现 apache kylin命令执行漏洞 - 先知社区](https://xz.aliyun.com/t/8240) :heavy_check_mark: 67 | - [从Java反序列化漏洞题看CodeQL数据流](https://www.anquanke.com/post/id/256967) :heavy_check_mark: 68 | - [CodeQL 学习小记](https://www.buaq.net/go-98696.html) :heavy_check_mark: 69 | - [使用codeql挖掘fastjson利用链](https://xz.aliyun.com/t/7482) :heavy_check_mark: 70 | 71 | 72 | # 下载 73 | 74 | 文档: https://codeql.github.com/docs/codeql-cli/ 75 | 二进制:https://github.com/github/codeql-cli-binaries 76 | 现成项目:https://github.com/github/vscode-codeql-starter 77 | 78 | 数据库下载,在线查询,规则搜索:https://lgtm.com/ 79 | 80 | 81 | # 生成数据库 82 | 83 | 第一步、创建索引代码数据库。得有数据库才能开始查询。 84 | 85 | ``` 86 | codeql database create --language= 87 | ``` 88 | 89 | 支持的语言及language对应关系如下 90 | 91 | 92 | | Language | Identity | 93 | | --------------------- | ---------- | 94 | | C/C++ | cpp | 95 | | C# | csharp | 96 | | Go | go | 97 | | Java | java | 98 | | javascript/Typescript | javascript | 99 | | Python | python | 100 | | Ruby | Ruby | 101 | 102 | 103 | 104 | 1、生成代码扫描数据库(java) 105 | 106 | ``` 107 | codeql database create D:\codeqldb/javasec --language=java --command="mvn clean install --file pom.xml -Dmaven.test.skip=true" --source-root=./javasec 108 | ``` 109 | 110 | 注:source-root 为源码路径,默认为当前目录,可不指定 111 | 112 | 一些常用命令 113 | 114 | ``` 115 | 跳过测试,构建 116 | --command="mvn clean install --file pom.xml -Dmaven.test.skip=true" 117 | 无论项目结果如何,构建从不失败 118 | --command="mvn -fn clean install --file pom.xml -Dmaven.test.skip=true" 119 | ``` 120 | 121 | 122 | 123 | 包含xml文件https://github.com/github/codeql/issues/3887 124 | 125 | 126 | 127 | ``` 128 | codeql database init --source-root= --language java 129 | codeql database trace-command --working-dir= 130 | codeql database index-files --language xml --include-extension .xml --working-dir= 131 | codeql database finalize 132 | ``` 133 | 134 | 将上面的命令拆分为如下4条命令,在index-files中将xml文件添加到CodeQL的数据库中CodeQL将XML文件包含到CodeQL数据库 135 | 136 | 第二种方案是在codeql-cli/java/tools/pre-finalize.cmd文件中插入--include "**/resources/**/*.xml" 137 | 138 | 139 | 140 | 2、更新数据库 141 | 142 | ``` 143 | codeql database upgrade database/javasec 144 | ``` 145 | 146 | 147 | 148 | 参考:https://help.semmle.com/lgtm-enterprise/admin/help/prepare-database-upload.html 149 | 150 | 151 | 152 | ### 编译与非编译 153 | 154 | 对于编译型语言来说,需要在创建索引数据库的时候增加编译的功能,主要是针对java,对于非编译性的语言来说,直接扫描吧 155 | 156 | 对于go来说,可编译也可不编译 157 | 158 | 159 | 160 | ## 基础查询 161 | 162 | ### 过滤 Method 163 | 164 | #### 根据Method name查询 165 | 166 | ```java 167 | import java 168 | 169 | from Method method 170 | where method.hasName("toObject") 171 | select method 172 | ``` 173 | 174 | 把这个方法的`class` `name`也查出来 175 | 176 | ```java 177 | import java 178 | 179 | from Method method 180 | where method.hasName("toObject") 181 | select method, method.getDeclaringType() 182 | ``` 183 | 184 | #### 根据Method name 和 interface name 查询 185 | 186 | 比如我想查询`ContentTypeHandler` 的所有子类`toObject`方法 187 | 188 | ```java 189 | import java 190 | 191 | from Method method 192 | where method.hasName("toObject") and method.getDeclaringType().getASupertype().hasQualifiedName("org.apache.struts2.rest.handler", "ContentTypeHandler") 193 | select method 194 | ``` 195 | 196 | #### Call和Callable 197 | 198 | Callable表示可调用的方法或构造器的集合。 199 | 200 | Call表示调用Callable的这个过程(方法调用,构造器调用等等) 201 | 202 | 203 | 过滤 方法调用 204 | 205 | ### MethodAccess 206 | 207 | 一般是先查`method`,与`MethodAccess.getMethod()` 进行比较。 208 | 209 | 比如查`ContentTypeHandler` 的 `toObject()` 方法的调用。 210 | 211 | ```java 212 | import java 213 | 214 | from MethodAccess call, Method method 215 | where method.hasName("toObject") and method.getDeclaringType().getASupertype().hasQualifiedName("org.apache.struts2.rest.handler", "ContentTypeHandler") and call.getMethod() = method 216 | select call 217 | ``` 218 | 219 | 上面这种查询方式不行,只能查到`JsonLibHandler` 这样显式定义的。 220 | 221 | 怎么改进呢? 222 | 223 | 也可以使用`getAnAncestor()` 或者`getASupertype()*` 224 | 225 | ```java 226 | import java 227 | 228 | from MethodAccess call, Method method 229 | where method.hasName("toObject") and method.getDeclaringType().getAnAncestor().hasQualifiedName("org.apache.struts2.rest.handler", "ContentTypeHandler") and call.getMethod() = method 230 | select call 231 | ``` 232 | 233 | 234 | 235 | 236 | 237 | # 数据流跟踪 238 | 239 | Local Data Flow分析SPEL 240 | 241 | 本地数据流 242 | 本地数据流是单个方法(一旦变量跳出该方法即为数据流断开)或可调用对象中的数据流。本地数据流通常比全局数据流更容易、更快、更精确。 243 | 244 | ``` 245 | import java 246 | import semmle.code.java.frameworks.spring.SpringController 247 | import semmle.code.java.dataflow.TaintTracking 248 | from Call call,Callable parseExpression,SpringRequestMappingMethod route 249 | where 250 | call.getCallee() = parseExpression and 251 | parseExpression.getDeclaringType().hasQualifiedName("org.springframework.expression", "ExpressionParser") and 252 | parseExpression.hasName("parseExpression") and 253 | TaintTracking::localTaint(DataFlow::parameterNode(route.getARequestParameter()),DataFlow::exprNode(call.getArgument(0))) 254 | select route.getARequestParameter(),call 255 | ``` 256 | 257 | 258 | 259 | 全局数据流分析要继承`DataFlow::Configuration` 这个类,然后重载`isSource` 和`isSink` 方法 260 | 261 | ``` 262 | class MyConfig extends DataFlow::Configuration { 263 | MyConfig() { this = "Myconfig" } 264 | override predicate isSource(DataFlow::Node source) { 265 | .... 266 | 267 | } 268 | 269 | override predicate isSink(DataFlow::Node sink) { 270 | .... 271 | 272 | } 273 | } 274 | ``` 275 | 276 | 277 | 278 | # 污点跟踪 279 | 280 | 281 | 282 | 全局污点跟踪分析要继承`TaintTracking::Configuration` 这个类,然后重载`isSource` 和`isSink` 方法 283 | 284 | ``` 285 | import semmle.code.java.dataflow.TaintTracking 286 | import java 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 | java 316 | 1、zip slip(zip解压覆盖任意文件) 317 | 318 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-022/ZipSlip.ql 319 | 320 | 2、命令注入 321 | 322 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-078/ExecUnescaped.ql 323 | 324 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-078/ExecTainted.ql 325 | 326 | 3、cookie安全 327 | 328 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-312/CleartextStorageCookie.ql 329 | 330 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-614/InsecureCookie.ql 331 | 332 | 4、XSS 333 | 334 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-079/XSS.ql 335 | 336 | 5、依赖漏洞 337 | 338 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-1104/MavenPomDependsOnBintray.ql 339 | 340 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-829/InsecureDependencyResolution.ql 341 | 342 | 6、反序列化 343 | 344 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.ql 345 | 346 | 7、http头注入 347 | 348 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-113/NettyResponseSplitting.ql 349 | 350 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-113/ResponseSplitting.ql 351 | 352 | 8、url跳转 353 | 354 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-601/UrlRedirect.ql 355 | 356 | 9、ldap注入 357 | 358 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-090/LdapInjection.ql 359 | 360 | 10、sql注入 361 | 362 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-089/SqlTainted.ql 363 | 364 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-089/SqlUnescaped.ql 365 | 366 | 11、file权限&目录注入 367 | 368 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-732/ReadingFromWorldWritableFile.ql 369 | 370 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-022/TaintedPath.ql 371 | 372 | 12、xml注入 373 | 374 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-611/XXE.ql 375 | 376 | 13、SSL校验 377 | 378 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-297/UnsafeHostnameVerification.ql 379 | 380 | 14、弱加密 381 | 382 | https://github.com/github/codeql/java/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql 383 | 384 | 15、随机数种子可预测 385 | 386 | https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-335/PredictableSeed.ql 387 | 388 | 389 | codeql analyze命令可以执行单个ql文件,目录下所有ql文件,和查询suite(.qls) 390 | 391 | 392 | 393 | 白盒扫描使用如下命令(执行所有漏洞类查询) 394 | 395 | ``` 396 | codeql database analyze source_database_name qllib/java/ql/src/codeql-suites/java-security-extended.qls --format=csv --output=java-results.csv 397 | ``` 398 | 399 | 如果是自己写可用于analyze的必须按规范写,包含元数据@kind,如下这种 400 | 401 | ``` 402 | /** 403 | * @name Incomplete regular expression for hostnames 404 | * @description Matching a URL or hostname against a regular expression that contains an unescaped 405 | * dot as part of the hostname might match more hostnames than expected. 406 | * @kind path-problem 407 | * @problem.severity warning 408 | * @security-severity 7.8 409 | * @precision high 410 | * @id go/incomplete-hostname-regexp 411 | * @tags correctness 412 | * security 413 | * external/cwe/cwe-20 414 | */ 415 | ``` 416 | 417 | # 文章推荐 418 | 419 | - https://github.com/SummerSec/learning-codeql 420 | - https://www.anquanke.com/post/id/203674 421 | - https://fynch3r.github.io/tags/CodeQL/ 422 | - https://www.freebuf.com/articles/web/283795.html 423 | -------------------------------------------------------------------------------- /example/Datagear/任意文件读取.md: -------------------------------------------------------------------------------- 1 | # Datagear漏洞与ql实现 2 | 3 | >学习ql的过程无意间发现了一个项目https://github.com/datageartech/datagear 感觉可能存在比较简单的漏洞,于是想挖掘一下并且使用ql去实现。之前是[safe6sec](https://github.com/safe6Sec)师傅带着完成了一个非常感谢。https://github.com/Firebasky/CodeqlLearn/blob/main/example/Sentinel/ssrf.md 4 | 5 | ## 任意文件读取 6 | 7 | ![image-20220107210234891](https://user-images.githubusercontent.com/63966847/148550868-25b09ed1-a3f9-4cd9-b473-bdd014450bd0.png) 8 | 9 | 10 | 演示 11 | 12 | ![image-20220107210250612](https://user-images.githubusercontent.com/63966847/148550881-98915067-f875-44a3-92fd-3f31450045d5.png) 13 | 14 | 15 | 16 | ## CodeQL实现 17 | 18 | 简单的看完了项目,让我们通过ql来实现吧(其实ql才是主角. 19 | 20 | 21 | 22 | 我们的source点可以先使用默认的(**RemoteFlowSource**)里面包含了springboot框架的一些source点 23 | 24 | ```java 25 | override predicate isSource(DataFlow::Node src) { 26 | src instanceof RemoteFlowSource//默认的 27 | } 28 | ``` 29 | 30 | 而sink点就是 31 | 32 | ![image-20220107210441904](https://user-images.githubusercontent.com/63966847/148550895-f8bc4a82-7693-4a44-b53c-7b1b8be27bbb.png) 33 | 34 | 35 | 就是write方法污染点是第一个参数,也就是说只要污染点能够传递到write方法就是完整的漏洞。 36 | 37 | ```java 38 | //sink IOUtil.write(tempFile, out); 39 | override predicate isSink(DataFlow::Node sink) { 40 | exists(Method method, MethodAccess call | 41 | method.hasName("write") 42 | and 43 | call.getMethod() = method 44 | and 45 | sink.asExpr() = call.getArgument(0) 46 | ) 47 | } 48 | ``` 49 | 50 | 完整的 51 | 52 | ```java 53 | /** 54 | * @id datagear 55 | * @name Readfile 56 | * @description Arbitrary file read 57 | * @kind path-problem 58 | * @precision high 59 | */ 60 | import java 61 | import semmle.code.java.dataflow.TaintTracking 62 | import semmle.code.java.dataflow.FlowSources 63 | import DataFlow::PathGraph 64 | 65 | class ReadfileConfig extends TaintTracking::Configuration { 66 | ReadfileConfig() { this = "ReadfileConfig" } 67 | 68 | override predicate isSource(DataFlow::Node src) { 69 | src instanceof RemoteFlowSource//默认的 70 | } 71 | 72 | //sink IOUtil.write(tempFile, out); 73 | override predicate isSink(DataFlow::Node sink) { 74 | exists(Method method, MethodAccess call | 75 | method.hasName("write") 76 | and 77 | call.getMethod() = method 78 | and 79 | sink.asExpr() = call.getArgument(0) 80 | ) 81 | } 82 | } 83 | 84 | from ReadfileConfig config, DataFlow::PathNode source, DataFlow::PathNode sink 85 | where config.hasFlowPath(source, sink) 86 | select source.getNode(), source, sink, "source" 87 | ``` 88 | 89 | 可以看到确实跑出了漏洞,不过163个结果太多,肯定有误报的。 90 | 91 | ![image-20220107210551312](https://user-images.githubusercontent.com/63966847/148550908-e1fe29c8-e42d-45b3-93f7-924b6b1cfb2c.png) 92 | 93 | 94 | 95 | 我们来完善一下,简单的看了一下sink点有时候并没有调用org.datagear.util.IOUtil#write所以我们加上他。 96 | 97 | ```java 98 | override predicate isSink(DataFlow::Node sink) { 99 | exists(Method method, MethodAccess call | 100 | method.hasName("write") 101 | and 102 | call.getMethod() = method 103 | and 104 | method.getDeclaringType().getAnAncestor().hasQualifiedName("org.datagear.util", "IOUtil") 105 | and 106 | sink.asExpr() = call.getArgument(0) 107 | ) 108 | } 109 | ``` 110 | 111 | 这下子跑出来54个结果还可以。不过里面的误报还是比较多。类似于 **getOriginalFilename()**方法是防止了目录穿越的所以我们需要给他clear。 112 | 113 | 就使用 **isSanitizer**方法 114 | 115 | ```java 116 | //解决误报,调用getOriginalFilename方法的给他clear 117 | override predicate isSanitizer(DataFlow::Node node) { 118 | exists(MethodAccess call ,Method method| 119 | method.hasName("getOriginalFilename") 120 | and 121 | call.getMethod() = method 122 | and 123 | call.getAChildExpr()=node.asExpr() 124 | ) 125 | } 126 | ``` 127 | 128 | 现在看看结果是38个,我们继续。简单的看看结果发现有些不是路由传递过来的也当成看source导致误报又添加了,使用我们自己写一个source点。 129 | 130 | ```java 131 | class ControllerAnno extends Annotation { 132 | ControllerAnno() { 133 | this.getType().hasQualifiedName("org.springframework.web.bind.annotation", "RequestMapping") or 134 | this.getType().hasQualifiedName("org.springframework.web.bind.annotation", "GetMapping") 135 | } 136 | } 137 | private class SpringBootSource extends RemoteFlowSource { 138 | SpringBootSource(){ 139 | this.asParameter().getCallable().getAnAnnotation() instanceof ControllerAnno 140 | } 141 | override string getSourceType() { result = "SpringBoot input parameter" } 142 | } 143 | ``` 144 | 145 | nice,又过滤了一些,现在有27个结果。在继续看结果发现有的结果是触发了 **IOUtil.write(in, Out);**因为不同的write方法,我们需要的是 146 | 147 | ```javascript 148 | public static void write(File file, OutputStream out) 149 | ``` 150 | 151 | ![image-20220107210821582](https://user-images.githubusercontent.com/63966847/148550928-72b4ec8c-7f20-4d44-bb18-9248143489d5.png) 152 | 153 | 154 | 而其他的基本上是写文件操作,现在我们讨论的是任意读文件所以我们先过滤他。在一次修改**isSink** 155 | 156 | ```java 157 | //sink IOUtil.write(tempFile, out); 158 | override predicate isSink(DataFlow::Node sink) { 159 | exists(Method method, MethodAccess call | 160 | method.hasName("write") 161 | and 162 | call.getMethod() = method 163 | and 164 | method.getDeclaringType().getAnAncestor().hasQualifiedName("org.datagear.util", "IOUtil") 165 | and 166 | call.getArgument(0).getType().hasName("File")//选择唯一的write方法 167 | and 168 | sink.asExpr() = call.getArgument(0) 169 | ) 170 | } 171 | ``` 172 | 173 | 现在跑一下结果有9个,并且存在漏洞. 174 | 175 | ![image-20220107210935493](https://user-images.githubusercontent.com/63966847/148550942-f916780f-24c8-4015-b12c-eaf6494e7d36.png) 176 | 177 | 178 | 完整ql 179 | 180 | ```java 181 | /** 182 | * @id datagear 183 | * @name Readfile 184 | * @description Arbitrary file read 185 | * @kind path-problem 186 | * @precision high 187 | */ 188 | import java 189 | import semmle.code.java.dataflow.TaintTracking 190 | import semmle.code.java.dataflow.FlowSources 191 | import DataFlow::PathGraph 192 | 193 | class ControllerAnno extends Annotation { 194 | ControllerAnno() { 195 | this.getType().hasQualifiedName("org.springframework.web.bind.annotation", "RequestMapping") or 196 | this.getType().hasQualifiedName("org.springframework.web.bind.annotation", "GetMapping") 197 | } 198 | } 199 | private class SpringBootSource extends RemoteFlowSource { 200 | SpringBootSource(){ 201 | this.asParameter().getCallable().getAnAnnotation() instanceof ControllerAnno 202 | } 203 | override string getSourceType() { result = "SpringBoot input parameter" } 204 | } 205 | 206 | 207 | class ReadfileConfig extends TaintTracking::Configuration { 208 | ReadfileConfig() { this = "ReadfileConfig" } 209 | 210 | override predicate isSource(DataFlow::Node src) { 211 | src instanceof SpringBootSource//自己实现的 212 | } 213 | 214 | //sink IOUtil.write(tempFile, out); 215 | override predicate isSink(DataFlow::Node sink) { 216 | exists(Method method, MethodAccess call | 217 | method.hasName("write") 218 | and 219 | call.getMethod() = method 220 | and 221 | method.getDeclaringType().getAnAncestor().hasQualifiedName("org.datagear.util", "IOUtil") 222 | and 223 | call.getArgument(0).getType().hasName("File")//选择唯一的write方法 224 | and 225 | sink.asExpr() = call.getArgument(0) 226 | ) 227 | } 228 | 229 | //解决误报,调用getOriginalFilename方法的给他clear 230 | override predicate isSanitizer(DataFlow::Node node) { 231 | exists(MethodAccess call ,Method method| 232 | method.hasName("getOriginalFilename") 233 | and 234 | call.getMethod() = method 235 | and 236 | call.getAChildExpr()=node.asExpr() 237 | ) 238 | } 239 | } 240 | 241 | from ReadfileConfig config, DataFlow::PathNode source, DataFlow::PathNode sink 242 | where config.hasFlowPath(source, sink) 243 | select source.getNode(), source, sink, "source" 244 | ``` 245 | 246 | -------------------------------------------------------------------------------- /example/Hystrix/ssrf.md: -------------------------------------------------------------------------------- 1 | # Hystrix 2 | 3 | CVE-2020-5412 4 | 5 | 漏洞点比较简单。 6 | 7 | ![image](https://user-images.githubusercontent.com/63966847/148392353-328f1ef3-b55c-46e1-96c7-3ba94b82b38b.png) 8 | 9 | ql实现应该和Sentinel的ssrf差不多,而且还简单不需要add操作 10 | 11 | ```ql 12 | /** 13 | * @kind path-problem 14 | */ 15 | 16 | import java 17 | import semmle.code.java.dataflow.TaintTracking 18 | import semmle.code.java.dataflow.FlowSources 19 | import DataFlow::PathGraph 20 | 21 | class SsrfConfig extends TaintTracking::Configuration { 22 | SsrfConfig() { this = "SsrfConfig" } 23 | 24 | override predicate isSource(DataFlow::Node src) { 25 | src instanceof RemoteFlowSource//默认的 26 | } 27 | 28 | //sink HttpGet构造方法 29 | override predicate isSink(DataFlow::Node sink) { 30 | exists(ConstructorCall call, Class clz| 31 | call.getAnArgument() = sink.asExpr() 32 | and call.getConstructedType()=clz 33 | and clz.getName()="HttpGet" 34 | ) 35 | } 36 | 37 | } 38 | 39 | from SsrfConfig config, DataFlow::PathNode source, DataFlow::PathNode sink 40 | where config.hasFlowPath(source, sink) 41 | select source.getNode(), source, sink, "source" 42 | ``` 43 | -------------------------------------------------------------------------------- /example/Sentinel/ssrf.md: -------------------------------------------------------------------------------- 1 | # Sentinel 2 | 3 | 随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式服务架构的**轻量级**流量控制产品,主要以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度来帮助您保护服务的稳定性。 4 | 5 | [介绍](https://blog.csdn.net/u012190514/article/details/81383698) 6 | 7 | ## SSRF 8 | 9 | https://github.com/alibaba/Sentinel/issues/2451 10 | 11 | ## source 12 | 13 | ![image-20220102190441213](https://user-images.githubusercontent.com/63966847/147877579-bc3f1a6c-e274-409e-98e3-401259ca6815.png) 14 | 15 | 16 | ![image-20220102190456538](https://user-images.githubusercontent.com/63966847/147877583-77e3152f-c4d8-4fd1-bd4f-8e1775df54bf.png) 17 | 18 | 19 | ## sink 20 | 21 | ![image-20220102190519809](https://user-images.githubusercontent.com/63966847/147877588-ff6b13b7-d192-4913-a419-e3044634df93.png) 22 | 23 | exp 24 | 25 | ``` 26 | http://127.0.0.1:8080/registry/machine?app=SSRF-TEST&appType=0&version=0&hostname=TEST&ip=localhost:12345%23&port=0 27 | ``` 28 | 29 | ## codeql 30 | 31 | 使用污点分析 32 | 33 | 其他ssrf不过需要登录。 34 | 35 | ``` 36 | http://127.0.0.1:8080/cluster/state_single?ip=1.116.136.120&port=3333&app=test 37 | 38 | http://127.0.0.1:8080/authority/rules?ip=1.116.136.120&port=3333&app=test 39 | 40 | http://127.0.0.1:8080/v1/flow/rules?ip=1.116.136.120&port=3333&app=test 41 | 42 | http://127.0.0.1:8080/paramFlow/rules?ip=1.116.136.120&port=3333&app=test 43 | 44 | http://127.0.0.1:8080/resource/machineResource.json?ip=1.116.136.120&port=3333&app=test 45 | 46 | http://127.0.0.1:8080/system/rules.json?ip=1.116.136.120&port=3333&app=test 47 | 48 | http://127.0.0.1:8080/gateway/api//list.json?ip=1.116.136.120&port=3333&app=test 49 | ``` 50 | 51 | 因为能力有限只能分开弄 52 | 53 | ```java 54 | /** 55 | * @id Sentinel 56 | * @name Ssrf 57 | * @description Ssrf 58 | * @kind path-problem 59 | * @problem.severity warning 60 | */ 61 | 62 | import java 63 | import semmle.code.java.dataflow.TaintTracking 64 | import semmle.code.java.dataflow.FlowSources 65 | import semmle.code.java.security.QueryInjection 66 | import DataFlow::PathGraph 67 | 68 | 69 | 70 | class SsrfConfig extends TaintTracking::Configuration { 71 | SsrfConfig() { this = "SsrfConfig" } 72 | 73 | override predicate isSource(DataFlow::Node src) { 74 | src instanceof RemoteFlowSource 75 | }//默认参数 76 | 77 | override predicate isSink(DataFlow::Node sink) { 78 | exists(//触发set ip操作 79 | Parameter p | p = sink.asParameter() and p.getCallable().getName() = "setIp" and p.getName() = "ip" 80 | ) 81 | } 82 | } 83 | 84 | from SsrfConfig config, DataFlow::PathNode source, DataFlow::PathNode sink 85 | where config.hasFlowPath(source, sink) 86 | select source.getNode(), source, sink, "source" 87 | ``` 88 | 89 | ```java 90 | import java 91 | 92 | from MethodAccess call, Method method, DataFlow::Node src 93 | where method.hasName("setIp") and method.getDeclaringType().getAnAncestor().hasQualifiedName("com.alibaba.csp.sentinel.dashboard.discovery", "MachineInfo") and call.getMethod() = method and src instanceof RemoteFlowSource 94 | select call 95 | ``` 96 | --------------------------------------------------------------------------------- 97 | 更新 2021/1/3 98 | 99 | 让safe6sec师傅看了看,师傅说sink点需要是危险的地方,之前的setip不能这样。 100 | 101 | 和师傅讨论弄了一下午加一晚上终于弄出来了(主要是safe6sec师傅在弄 hhhh 102 | 103 | 感谢safe6sec师傅 104 | 105 | ```ql 106 | /** 107 | * @id Sentinel 108 | * @name Ssrf 109 | * @description Ssrf 110 | * @kind path-problem 111 | * @problem.severity warning 112 | */ 113 | 114 | import java 115 | import semmle.code.java.dataflow.TaintTracking 116 | import semmle.code.java.dataflow.FlowSources 117 | import DataFlow::PathGraph 118 | 119 | //连接setip到getip 120 | predicate isTaintedString(Expr expSrc, Expr expDest) { 121 | exists(Method method1,Method method2, MethodAccess call1,MethodAccess call2| 122 | method1.getName()="setIp" and call1.getMethod() = method1 and expSrc = call1.getAnArgument()//获得setip方法的参数 123 | and 124 | method2.getName()="getIp" and call2.getMethod() = method2 and expDest = call2 125 | ) 126 | } 127 | 128 | class SsrfConfig extends TaintTracking::Configuration { 129 | SsrfConfig() { this = "SsrfConfig" } 130 | 131 | override predicate isSource(DataFlow::Node src) { 132 | src instanceof RemoteFlowSource//默认的 133 | } 134 | 135 | //sink 136 | override predicate isSink(DataFlow::Node sink) { 137 | exists(ConstructorCall call, Class clz| 138 | call.getAnArgument() = sink.asExpr() 139 | and call.getConstructedType()=clz 140 | and clz.getName()="HttpGet" 141 | ) 142 | } 143 | 144 | override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { 145 | isTaintedString(node1.asExpr(), node2.asExpr()) 146 | } 147 | 148 | } 149 | 150 | from SsrfConfig config, DataFlow::PathNode source, DataFlow::PathNode sink 151 | where config.hasFlowPath(source, sink) 152 | select source.getNode(), source, sink, "source" 153 | 154 | // from Method method1,MethodAccess call1,DataFlow::Node expSrc 155 | // where method1.getName()="setIp" and call1.getMethod() = method1 and expSrc.asExpr() = call1.getAnArgument() 156 | // select call1,expSrc,call1.getAnArgument(),1 157 | ``` 158 | 159 | ![image](https://user-images.githubusercontent.com/63966847/147954723-35bcda60-b9d3-403a-8178-8998bd79049f.png) 160 | 161 | --------------------------------------------------------------------------------