文章总结: 本文介绍使用CodeQL检测原生JDBCSQL注入漏洞的方法。文章从官方示例入手,解析了QueryInjectionSink和QueryInjectionFlow两个核心库,前者定义sink点,后者构建数据流。官方已定义常见sink点,可直接运行检测,但暂不包含MyBatis等框架的检测。文章提供了具体代码示例和操作路径,具有较强可操作性。 综合评分: 85 文章分类: 代码审计,漏洞分析,安全工具,WEB安全,渗透测试
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注入》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。







评论