codeql使用指南

目录

简介

hello world

1、安装codeql-cli 和 ql库

2、创建源码数据库

3、编写hello world

4、执行查询

进阶

1、扫描结果快速定位到源码

2、用作白盒扫描器

3、开发自己的查询代码

4、分析GitHub上的开源项目

​5、语法规则学习

codeql安全能力

java

实战

宽泛的跨域配置


简介

codeql是一门类似SQL的查询语言,通过对项目源码(C/C++、C#、golang、java、JavaScript、typescript、python)进行完整编译,并在此过程中把项目源码文件的所有相关信息(调用关系、语法语义、语法树)存在数据库中,然后编写代码查询该数据库来发现安全漏洞(硬编码/XSS等)

 

hello world

1、安装codeql-cli 和 ql库

codeql-cli是执行文件,ql库是已经写好的可以查询安全漏洞的代码

下载地址:

codeql-cli:https://github.com/github/codeql-cli-binaries/releases

ql库:https://github.com/github/codeql/releases

 

两个下载的zip文件务必解压在同一目录(codeql-home)下(因为codeql-cli把同层目录作为查找路径),并将codeql-cli放在系统目录中(Linux添加export PATH=$PATH:/home/f/.local/bin:/mnt/c/Users/xx/codeql-home/codeql-cli到.bashrc文件末尾)

 

2、创建源码数据库

首先clone项目源码:git clone https://github.com/XiaoMi/galaxy-sdk-java.git

然后创建源码数据库:codeql database create source_database_name  --language=java

 

3、编写hello world

下载的ql库是codeql代码,有包结构/目录结构要求(qlpack.yml定义一个package),才能正常编译、执行。

 

java语言的漏洞查询代码目录在qllib/java/ql/src/Security/CWE,这里新建test.ql(qllib/java/ql/src/Security/test/test.ql)查询源码,内容:

/**

 * @name sectest2

 * @description Writing sectest33

 * @kind problem

 * @problem.severity error

 * @precision high

 * @id java/sectest

 * @tags security

 *       external/cwe/cwe-113

 */

import java

from Parameter p

where not exists(p.getAnAccess())

select p, "no used param"

test.ql用来查询函数参数未使用的函数

 

4、执行查询

执行了查询代码之后,输出的内容即有漏洞的项目源代码

 

命令行执行:codeql database analyze source_database_name qllib/java/ql/src/Security/test/test.ql --format=csv --output=java-results.csv

 

查询发现的漏洞会输出到java-results.csv文件

 

 

进阶

1、扫描结果快速定位到源码

命令行方式执行查询,多少有些不便,使用vscode codeql插件则方便的多

安装完插件,需要在插件中指定待查询的源码库(第2步产生的文件夹),

然后在vscode中打开test.ql,右键运行查询,结果会自动打开

2、用作白盒扫描器

ql库集成了许多常见的安全漏洞(参考:https://codeql.github.com/codeql-query-help/java/),可以拿来扫描项目源码

 

codeql analyze命令可以执行单个ql文件,目录下所有ql文件,和查询suite(.qls)

 

白盒扫描使用如下命令(执行所有漏洞类查询)

codeql database analyze source_database_name qllib/java/ql/src/codeql-suites/java-security-extended.qls --format=csv --output=java-results.csv

 

3、开发自己的查询代码

ql入门:https://codeql.github.com/docs/writing-codeql-queries/introduction-to-ql/

各语言文档:https://codeql.github.com/docs/codeql-language-guides/abstract-syntax-tree-classes-for-working-with-java-programs/

 

目前codeql文档较少,只能照已有的规则进行模仿

qll文件是库文件,有很多函数可以直接import使用;qhelp是帮助说明文件;

 

ql文件(qllib/java/ql/src/Security/CWE/CWE-614/InsecureCookie.ql)如下:

注释部分是meta信息(都有重要作用,比如tags可以用来归属规则suites),

import同其他编程语言类似,可以导入现成的函数使用(qllib/java/ql/src/semmle/code/java)

from用来定义变量,where是判断规则,select是输出

/**

 * @name Failure to use secure cookies

 * @description Insecure cookies may be sent in cleartext, which makes them vulnerable to

 *              interception.

 * @kind problem

 * @problem.severity error

 * @precision high

 * @id java/insecure-cookie

 * @tags security

 *       external/cwe/cwe-614

 */

import java

import semmle.code.java.frameworks.Servlets



from MethodAccess add

where

  add.getMethod() instanceof ResponseAddCookieMethod and

  not exists(Variable cookie, MethodAccess m |

    add.getArgument(0) = cookie.getAnAccess() and

    m.getMethod().getName() = "setSecure" and

    m.getArgument(0).(BooleanLiteral).getBooleanValue() = true and

    m.getQualifier() = cookie.getAnAccess()

  )

select add, "Cookie is added to response without the 'secure' flag being set."

 

有两类查询alert和path,从ql文件中的@kind problem/path-problem分辨,alert查询select返回两个字段(qllib/java/ql/src/Security/CWE/CWE-614/InsecureCookie.ql,select element, string),path查询(污点查找)select返回4个字段(qllib/java/ql/src/Security/CWE/CWE-079/XSS.ql,select element, source, sink, string),path查询带有调用链

 

4、分析GitHub上的开源项目

直接搜索即可

https://lgtm.com/search?q=xiaomi

 

https://lgtm.com/projects/g/XiaoMi/minos/?mode=list&result_filter=0e00f5fa7b93849767c1677dc71d9400f85c6a54

该开源项目存在xss漏洞:https://github.com/XiaoMi/minos/issues/43

 

 

​5、语法规则学习

①定义类/方法

/**
 * A class that has `javax.servlet.Servlet` as an ancestor.
 */
class ServletClass extends Class {
  ServletClass() { getAnAncestor().hasQualifiedName("javax.servlet", "Servlet") }
}

方法

/**
 * The interface `javax.servlet.http.HttpServletResponse`.
 */
class HttpServletResponse extends RefType {
  HttpServletResponse() { hasQualifiedName("javax.servlet.http", "HttpServletResponse") }
}

/**
 * The method `addCookie(Cookie)` declared in `javax.servlet.http.HttpServletResponse`.
 */
class ResponseAddCookieMethod extends Method {
  ResponseAddCookieMethod() {
    getDeclaringType() instanceof HttpServletResponse and
    hasName("addCookie")
  }
}

//========================

/** The class `java.lang.String`. */
class TypeString extends Class {
  TypeString() { this.hasQualifiedName("java.lang", "String") }
}
/**
 * The method `getHeader(String)` declared in `javax.servlet.http.HttpServletRequest`.
 */
library class HttpServletRequestGetHeaderMethod extends Method {
  HttpServletRequestGetHeaderMethod() {
    getDeclaringType() instanceof HttpServletRequest and
    hasName("getHeader") and
    getNumberOfParameters() = 1 and
    getParameter(0).getType() instanceof TypeString
  }
}

②查询所有外部输入

import java

import semmle.code.java.dataflow.FlowSources



from RemoteFlowSource rls

select rls, "t:"+rls.getSourceType()

③获取所有外部依赖

/**

 * @name dependency version

 * @description version with vulnerabilities

 * @kind problem

 * @problem.severity error

 * @precision high

 * @id java/dependency-version

 * @tags security

 *       external/cwe/cwe-113

 */

import java

import semmle.code.xml.MavenPom

predicate getCompileDependency(PomDependency dependency) {

  dependency.getScope() = "compile" or dependency.getScope() = "runtime"

  }

  

  from PomDependency dependency

  where  getCompileDependency(dependency)

  select dependency,

    "dependency: " +

    dependency.getShortCoordinate()+":"+dependency.getVersionString()

④获取某方法的所有调用

/**

 * The class `com.xiaomi.miui.lockServer.utils. HttpUtils `.

 */

class TypeAbstractRequestMatcherRegistry extends Class {

    TypeAbstractRequestMatcherRegistry() {

      this.hasQualifiedName("com.xiaomi.miui.lockServer.utils",

        "HttpUtils")

    }

  }

/** A call to `HttpUtils. getRemoteUserIP ` method. */

class AnyRequestCall extends MethodAccess {

    AnyRequestCall() {

      getMethod().hasName("getRemoteUserIP") and

      getMethod().getDeclaringType() instanceof TypeAbstractRequestMatcherRegistry

    }

  }



from Call c, Callable callee

where callee = c.getCallee() and callee.getAReference() instanceof AnyRequestCall

select c, "t:"+c.getQualifier()+" "+c.getCallee()



//另外一种简便方式

from Call c

where c.getQualifier().toString() = "httpUtils" and c.getCallee().toString() = "getRemoteUserIP"

select c, "t:"+c.getQualifier()+c.getCallee()

⑤获取某方法的调用链

/**

 * @name sectest2

 * @description Writing sectest33

 * @kind path-problem

 * @problem.severity error

 * @precision high

 * @id java/sectest

 * @tags security

 *       external/cwe/cwe-113

 */

import java

import semmle.code.java.dataflow.FlowSources

import DataFlow::PathGraph



class GetOrderIdByIMEIMethod extends Method {

  GetOrderIdByIMEIMethod() {

    getDeclaringType().hasQualifiedName("com.xiaomi.miui.lockServer.utils", "HttpUtils") and

    hasName("getRemoteUserIP")

  }

}

//ql自动调用实现类中的方法

abstract class HeaderSplittingSink extends DataFlow::Node { }

//sink为目标函数的参数

class OrderHeaderSplittingSink extends HeaderSplittingSink{

  OrderHeaderSplittingSink(){

    exists(GetOrderIdByIMEIMethod m, MethodAccess ma |

      ma.getMethod() = m and

      this.asExpr() = ma.getArgument(0)

    )

  }

}

class ResponseSplittingConfig extends TaintTracking::Configuration {

  ResponseSplittingConfig() { this = "ResponseSplittingConfig" }

  override predicate isSource(DataFlow::Node source) {

    //source instanceof RemoteFlowSource

    exists(source.asExpr())

  }

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

}

from DataFlow::PathNode source, DataFlow::PathNode sink, ResponseSplittingConfig conf

where conf.hasFlowPath(source, sink)

select sink.getNode(), source, sink, "vulnerability due to this $@.",

  source.getNode(), "user-provided value"

⑥判断参数值

MethodAccess ma | ma.getArgument(1).(StringLiteral).getValue() = "Nonex"

⑦嵌套类定义

class JaxRsResponseBuilder2 extends Class {

  JaxRsResponseBuilder2() { this.hasQualifiedName("javax.ws.rs.core", "Response$ResponseBuilder") }

}

codeql安全能力

java

1、zip slip(zip解压覆盖任意文件)

https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-022/ZipSlip.ql

2、命令注入

https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-078/ExecUnescaped.ql

https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-078/ExecTainted.ql

3、cookie安全

https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-312/CleartextStorageCookie.ql

https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-614/InsecureCookie.ql

4、XSS

https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-079/XSS.ql

5、依赖漏洞

https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-1104/MavenPomDependsOnBintray.ql

https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-829/InsecureDependencyResolution.ql

6、反序列化

https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.ql

7、http头注入

https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-113/NettyResponseSplitting.ql

https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-113/ResponseSplitting.ql

8、url跳转

https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-601/UrlRedirect.ql

9、ldap注入

https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-090/LdapInjection.ql

10、sql注入

https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-089/SqlTainted.ql

https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-089/SqlUnescaped.ql

11、file权限&目录注入

https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-732/ReadingFromWorldWritableFile.ql

https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-022/TaintedPath.ql

12、xml注入

https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-611/XXE.ql

13、SSL校验

https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-297/UnsafeHostnameVerification.ql

14、弱加密

https://github.com/github/codeql/java/ql/src/Security/CWE/CWE-327/BrokenCryptoAlgorithm.ql

15、随机数种子可预测

https://github.com/github/codeql/blob/main/java/ql/src/Security/CWE/CWE-335/PredictableSeed.ql

实战

宽泛的跨域配置

查看结果 https://lgtm.com/query/7135375648193136280/

代码:

/**
 * @name access-control-allow-origin
 * @description set access-control-allow-origin with *
 * @kind problem
 * @problem.severity error
 * @precision high
 * @id java/corserror
 * @tags security
 *       external/cwe/cwe-113
 */

import java
import semmle.code.java.dataflow.FlowSources
class JaxRsResponseBuilder2 extends Class {
  JaxRsResponseBuilder2() { this.hasQualifiedName("javax.ws.rs.core", "Response$ResponseBuilder") }
}
class JaxRsResponseBuilderMethod extends Method {
  JaxRsResponseBuilderMethod() {
    getDeclaringType() instanceof JaxRsResponseBuilder2 and
    hasName("header")
  }
}
predicate broadCors(MethodAccess ma){
  exists(JaxRsResponseBuilderMethod m|
      ma.getMethod() = m and ma.getArgument(0).(StringLiteral).getValue().toLowerCase() = "access-control-allow-origin" and ma.getArgument(1).(StringLiteral).getValue() = "*"
    )
    
}
predicate broadCors2(MethodAccess ma){
  exists(ResponseSetHeaderMethod m|
      ma.getMethod() = m and ma.getArgument(0).(StringLiteral).getValue().toLowerCase() = "access-control-allow-origin" and ma.getArgument(1).(StringLiteral).getValue() = "*"
    )
    
}
predicate broadCors3(MethodAccess ma){
  exists(ResponseAddHeaderMethod m|
      ma.getMethod() = m and ma.getArgument(0).(StringLiteral).getValue().toLowerCase() = "access-control-allow-origin" and ma.getArgument(1).(StringLiteral).getValue() = "*"
    )
    
}
from MethodAccess ma
where broadCors(ma) or broadCors2(ma) or broadCors3(ma)
select ma, "CORS vulnerability due to this"+" "+ma.getCaller()

 

  • 2
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值