CodeQL库学习-SSRF漏洞挖掘
字数 1494 2025-08-06 18:08:11

CodeQL库学习:SSRF漏洞挖掘

1. CodeQL简介

CodeQL是GitHub开发的语义代码分析引擎,它将代码转换为可查询的数据库,允许开发者编写查询来发现代码中的漏洞模式。主要特点包括:

  • 支持多种语言:Java, JavaScript/TypeScript, Python, C/C++, C#, Go等
  • 将代码视为数据,可以进行复杂的语义分析
  • 内置大量安全规则
  • 可扩展自定义查询

2. SSRF漏洞概述

服务器端请求伪造(SSRF)是一种安全漏洞,攻击者诱使服务器向内部系统发起非预期的请求。典型危害:

  • 访问内部服务
  • 绕过访问控制
  • 扫描内部网络
  • 攻击内部脆弱服务

3. CodeQL中的SSRF检测规则

3.1 基本检测原理

CodeQL检测SSRF主要通过以下模式:

  1. 识别用户可控的输入源(Source)
  2. 跟踪数据流到网络请求的发起点(Sink)
  3. 验证是否存在适当的防护措施

3.2 Java中的SSRF检测

关键类和方法

  • java.net.URL 类及其 openConnection() 方法
  • java.net.HttpURLConnection
  • java.net.URI
  • org.apache.http.client.HttpClient 及相关方法

查询示例

import java
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.security.SSRF

from SSRFRequest ssrf
select ssrf, "This HTTP request is potentially vulnerable to SSRF."

3.3 Python中的SSRF检测

关键模块和函数

  • urllib.request.urlopen()
  • requests.get(), requests.post()
  • httpx.get(), httpx.post()
  • aiohttp.ClientSession().get()

查询示例

import python
import semmle.python.security.SSRF

from SSRFRequest ssrf
select ssrf, "Potential SSRF vulnerability in Python code."

4. 高级SSRF检测技术

4.1 数据流分析

CodeQL的强大之处在于可以跟踪复杂的数据流:

import java
import semmle.code.java.dataflow.DataFlow

from DataFlow::Node source, DataFlow::Node sink
where DataFlow::localFlow(source, sink)
select source, sink

4.2 污点跟踪

识别用户输入如何影响网络请求:

import java
import semmle.code.java.dataflow.TaintTracking

from TaintTracking::Configuration config, DataFlow::Node source, DataFlow::Node sink
where config.hasFlow(source, sink)
select source, sink, "User input flows to network request"

4.3 识别防护措施

检测是否存在SSRF防护:

import java
import semmle.code.java.security.SSRF

from SSRFRequest ssrf
where not ssrf.hasProtection()
select ssrf, "Unprotected SSRF vulnerability"

5. 实战案例

5.1 案例1:简单的Java SSRF

String url = request.getParameter("url");
URL u = new URL(url);
URLConnection conn = u.openConnection();

CodeQL会标记这种直接使用用户输入发起请求的模式。

5.2 案例2:间接SSRF

String apiEndpoint = "http://internal/api/" + userInput;
HttpClient.newBuilder().build().send(
    HttpRequest.newBuilder().uri(URI.create(apiEndpoint)).build(),
    HttpResponse.BodyHandlers.ofString());

CodeQL能跟踪字符串拼接后的数据流。

5.3 案例3:绕过防护的SSRF

String url = sanitizeUrl(request.getParameter("url"));
if(url.startsWith("http://example.com")) {
    HttpClient.newHttpClient().send(
        HttpRequest.newBuilder().uri(URI.create(url)).build(),
        HttpResponse.BodyHandlers.ofString());
}

CodeQL可以检测不充分的URL验证。

6. 防护建议

在CodeQL查询中可以验证的防护措施:

  1. 白名单验证
  2. 禁用协议(如file://, gopher://)
  3. 使用内部DNS解析
  4. 网络层限制(如防火墙规则)

7. 自定义SSRF查询开发

7.1 定义Source

override predicate isSource(DataFlow::Node source) {
    source.asParameter() = any(Request::getParameter).getAnUntrustedParameter()
    or
    source.asExpr() = any(RemoteFlowSource::remoteUserInput)
}

7.2 定义Sink

override predicate isSink(DataFlow::Node sink) {
    exists(MethodAccess ma |
        ma.getMethod().hasName("openConnection") and
        ma.getMethod().getDeclaringType().hasQualifiedName("java.net", "URL") and
        sink.asExpr() = ma
    )
}

7.3 完整查询示例

/**
 * @name SSRF via URL.openConnection()
 * @description Detects when user input flows into URL.openConnection()
 * @kind path-problem
 * @problem.severity warning
 * @id java/ssrf-url-connection
 */

import java
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.dataflow.TaintTracking
import DataFlow::PathGraph

class SSRFConfig extends TaintTracking::Configuration {
    SSRFConfig() { this = "SSRFConfig" }
    
    override predicate isSource(DataFlow::Node source) {
        source instanceof RemoteFlowSource
    }
    
    override predicate isSink(DataFlow::Node sink) {
        exists(MethodAccess ma |
            ma.getMethod().hasName("openConnection") and
            ma.getMethod().getDeclaringType().hasQualifiedName("java.net", "URL") and
            sink.asExpr() = ma
        )
    }
}

from SSRFConfig config, DataFlow::PathNode source, DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "Potential SSRF vulnerability"

8. 优化查询技巧

  1. 提高精度:添加更多限制条件减少误报
  2. 提高召回率:扩大source和sink定义
  3. 性能优化:限制分析范围,使用更精确的数据流步骤
  4. 结果排序:按风险程度排序结果

9. 集成到CI/CD

将CodeQL SSRF检测集成到开发流程:

  1. 在PR时自动运行扫描
  2. 设置质量门限
  3. 与漏洞管理系统集成
  4. 定期更新查询规则库

10. 资源与进阶

  1. 官方文档:https://codeql.github.com/docs/
  2. GitHub高级安全:https://docs.github.com/en/code-security
  3. CodeQL标准库:https://github.com/github/codeql
  4. 社区查询:https://github.com/github/codeql/tree/main/java/ql/src/Security

通过系统学习和实践CodeQL的SSRF检测技术,可以显著提高代码审计效率,在开发早期发现潜在的安全风险。

CodeQL库学习:SSRF漏洞挖掘 1. CodeQL简介 CodeQL是GitHub开发的语义代码分析引擎,它将代码转换为可查询的数据库,允许开发者编写查询来发现代码中的漏洞模式。主要特点包括: 支持多种语言:Java, JavaScript/TypeScript, Python, C/C++, C#, Go等 将代码视为数据,可以进行复杂的语义分析 内置大量安全规则 可扩展自定义查询 2. SSRF漏洞概述 服务器端请求伪造(SSRF)是一种安全漏洞,攻击者诱使服务器向内部系统发起非预期的请求。典型危害: 访问内部服务 绕过访问控制 扫描内部网络 攻击内部脆弱服务 3. CodeQL中的SSRF检测规则 3.1 基本检测原理 CodeQL检测SSRF主要通过以下模式: 识别用户可控的输入源(Source) 跟踪数据流到网络请求的发起点(Sink) 验证是否存在适当的防护措施 3.2 Java中的SSRF检测 关键类和方法 java.net.URL 类及其 openConnection() 方法 java.net.HttpURLConnection 类 java.net.URI 类 org.apache.http.client.HttpClient 及相关方法 查询示例 3.3 Python中的SSRF检测 关键模块和函数 urllib.request.urlopen() requests.get() , requests.post() httpx.get() , httpx.post() aiohttp.ClientSession().get() 查询示例 4. 高级SSRF检测技术 4.1 数据流分析 CodeQL的强大之处在于可以跟踪复杂的数据流: 4.2 污点跟踪 识别用户输入如何影响网络请求: 4.3 识别防护措施 检测是否存在SSRF防护: 5. 实战案例 5.1 案例1:简单的Java SSRF CodeQL会标记这种直接使用用户输入发起请求的模式。 5.2 案例2:间接SSRF CodeQL能跟踪字符串拼接后的数据流。 5.3 案例3:绕过防护的SSRF CodeQL可以检测不充分的URL验证。 6. 防护建议 在CodeQL查询中可以验证的防护措施: 白名单验证 禁用协议(如file://, gopher://) 使用内部DNS解析 网络层限制(如防火墙规则) 7. 自定义SSRF查询开发 7.1 定义Source 7.2 定义Sink 7.3 完整查询示例 8. 优化查询技巧 提高精度:添加更多限制条件减少误报 提高召回率:扩大source和sink定义 性能优化:限制分析范围,使用更精确的数据流步骤 结果排序:按风险程度排序结果 9. 集成到CI/CD 将CodeQL SSRF检测集成到开发流程: 在PR时自动运行扫描 设置质量门限 与漏洞管理系统集成 定期更新查询规则库 10. 资源与进阶 官方文档:https://codeql.github.com/docs/ GitHub高级安全:https://docs.github.com/en/code-security CodeQL标准库:https://github.com/github/codeql 社区查询:https://github.com/github/codeql/tree/main/java/ql/src/Security 通过系统学习和实践CodeQL的SSRF检测技术,可以显著提高代码审计效率,在开发早期发现潜在的安全风险。