codeql实战:codeql检测sql注入

admin 2026-07-10 06:39:46 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文介绍使用CodeQL检测原生JDBCSQL注入漏洞的方法。文章从官方示例入手,解析了QueryInjectionSink和QueryInjectionFlow两个核心库,前者定义sink点,后者构建数据流。官方已定义常见sink点,可直接运行检测,但暂不包含MyBatis等框架的检测。文章提供了具体代码示例和操作路径,具有较强可操作性。 综合评分: 85 文章分类: 代码审计,漏洞分析,安全工具,WEB安全,渗透测试


cover_image

codeql实战:codeql检测sql注入

原创

信安路漫漫 信安路漫漫

信安路漫漫

2026年7月7日 07:00 上海

在小说阅读器读本章

去阅读

前言

本篇文章来看一下如何利用codeql来检测原生JDBC sql注入查询。这个官方已经有查询示例,我们可以先从官方的实例,然后在扩展到我们的自己的查询。

这个检测暂时不包含使用mybatis等框架的检测,后面会专门出一篇文章来检测mybatis框架下的SQL注入漏洞。

官方示例

下面是官方给出的查询示例。

/** * @name Query built from user-controlled sources * @description Building a SQL or Java Persistence query from user-controlled sources is vulnerable to insertion of *              malicious code by the user. * @kind path-problem * @problem.severity error * @security-severity 8.8 * @precision high * @id java/sql-injection * @tags security *       external/cwe/cwe-089 *       external/cwe/cwe-564 */import javaimport semmle.code.java.dataflow.FlowSourcesimport semmle.code.java.security.SqlInjectionQueryimport QueryInjectionFlow::PathGraphfrom  QueryInjectionSink query, QueryInjectionFlow::PathNode source, QueryInjectionFlow::PathNode sinkwhere queryIsTaintedBy(query, source, sink)select query, source, sink, "This query depends on a $@.", source.getNode(), "user-provided value"

从上面的官方示例中可以看出,主要导入了两个库:SqlInjectionQuery和QueryInjectionFlow。这两个库一个负责定义sink点,一个负责定义数据流。下面可以分别来看一下这两个库。

QueryInjection类:sink点的定义

/** Provides classes to reason about database query language injection vulnerabilities. */overlay[local?]module;import javaimport semmle.code.java.dataflow.DataFlowimport semmle.code.java.frameworks.javaee.Persistenceprivate import semmle.code.java.frameworks.MyBatisprivate import semmle.code.java.dataflow.ExternalFlowprivate import semmle.code.java.dataflow.FlowSinks/** A sink for database query language injection vulnerabilities. */abstract class QueryInjectionSink extends ApiSinkNode { }/** * A unit class for adding additional taint steps. * * Extend this class to add additional taint steps that should apply to the SQL * injection taint configuration. */class AdditionalQueryInjectionTaintStep extends Unit {  /**   * Holds if the step from `node1` to `node2` should be considered a taint   * step for SQL injection taint configurations.   */  abstract predicate step(DataFlow::Node node1, DataFlow::Node node2);}/** A sink for SQL injection vulnerabilities. */private class SqlInjectionSink extends QueryInjectionSink {  SqlInjectionSink() { sinkNode(this, "sql-injection") }}/** A sink for Java Persistence Query Language injection vulnerabilities. */private class PersistenceQueryInjectionSink extends QueryInjectionSink {  PersistenceQueryInjectionSink() {    // the query (first) argument to a `createQuery` or `createNativeQuery` method on `EntityManager`    exists(MethodCall call, TypeEntityManager em | call.getArgument(0) = this.asExpr() |      call.getMethod() = em.getACreateQueryMethod() or      call.getMethod() = em.getACreateNativeQueryMethod()      // note: `createNamedQuery` is safe, as it takes only the query name,      // and named queries can only be constructed using constants as the query text    )  }}/** A sink for MongoDB injection vulnerabilities. */private class MongoDbInjectionSink extends QueryInjectionSink {  MongoDbInjectionSink() {    exists(MethodCall call |      call.getMethod().getDeclaringType().hasQualifiedName("com.mongodb", "BasicDBObject") and      call.getMethod().hasName("parse") and      this.asExpr() = call.getArgument(0)    )    or    exists(CastingExpr c |      c.getExpr() = this.asExpr() and      c.getTypeExpr().getType().(RefType).hasQualifiedName("com.mongodb", "DBObject")    )  }}private class MongoJsonStep extends AdditionalQueryInjectionTaintStep {  override predicate step(DataFlow::Node node1, DataFlow::Node node2) {    exists(MethodCall ma |      ma.getMethod().getDeclaringType().hasQualifiedName("com.mongodb.util", "JSON") and      ma.getMethod().hasName("parse") and      ma.getArgument(0) = node1.asExpr() and      ma = node2.asExpr()    )  }}private class MyBatisSqlInjectionSink extends QueryInjectionSink instanceof MyBatisInjectionSink { }

QueryInjectionSink相当于接口,使用的时候会查找所有的子类实现。

1)SqlInjectionSink定义了在codeql中包含sql-injection标签的就是sql的注入点。

2)QueryInjectionSink相当于接口,使用的时候会查找所有的子类实现。

3)目前大部分常见的sink点都已经被官方定义好了,我们可以直接使用。可以从下面的路径中去查找都定义了哪些sink点。一般是在odeql-codeql-cli-v2.23.8\csharp\ql\lib\这个目录下。

#

sink的标签在哪些位置

codeql-codeql-cli-v2.23.8\csharp\ql\lib\ext\Microsoft.ApplicationBlocks.Data.model.yml

QueryInjectionFlow:数据流的构建

官方写法

module QueryInjectionFlowConfig implements DataFlow::ConfigSig {  predicate isSource(DataFlow::Node src) { src instanceof ActiveThreatModelSource }  predicate isSink(DataFlow::Node sink) { sink instanceof QueryInjectionSink }  predicate isBarrier(DataFlow::Node node) { node instanceof SimpleTypeSanitizer }  predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {    any(AdditionalQueryInjectionTaintStep s).step(node1, node2)  }  predicate observeDiffInformedIncrementalMode() { any() }}

案例

官方对于一般的SQL注入的漏洞点都已经写好,基本不用我们添加什么。我们可以直接运行这个sink点,来检测是否存在sql注入,但是这个检测不到使用了查询框架下的漏洞

import javaimport semmle.code.java.dataflow.FlowSourcesimport semmle.code.java.security.SqlInjectionQueryimport QueryInjectionFlow::PathGraphfrom  QueryInjectionSink query, QueryInjectionFlow::PathNode source, QueryInjectionFlow::PathNode sinkwhere queryIsTaintedBy(query, source, sink)select query, source, sink, "This query depends on a $@.", source.getNode(), "user-provided value"


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:信安路漫漫 信安路漫漫 信安路漫漫《codeql实战:codeql检测sql注入》

评论:0   参与:  0