第五篇 SQL注入基础知识


1 什么是SQL注入

一种将SQL语句插入到用户输入的参数中,进行攻击,这些会通过后端服务器传入到SQL服务器,执行对应的SQL语句,比如可以获取数据库信息、用户信息、管理员权限等

2 常见的SQL注入技巧

2.1 识别数据库类型

常见的数据库类型有:Oracle、MySQL、SQL Server、Access、Postgresql等

  • 首先根据web前端的技术栈,如:
asp和.net 通常使用sqlserver,asp有的时候也适用access
php通常使用mysql,postgresql
java通常使用oracle,mysql

  • 其次根据使用的操作系统进行判断,比如windows,使用的数据库很有可能就是sqlserver,linux一般都是mysql,postgresql

  • 再次,基于查询、报错信息进行识别

1. 基于version:

	sqlserver :
		1)select @@version, 返回结果示例:
			Microsoft SQL Server 2019 (RTM-CU14) (KB5007182) - 15.0.4188.2 (X64) 
	
	mysql:
		1)select @@version,返回结果示例:
			+-----------+
			| @@version |
			+-----------+
			| 8.0.26    |
			+-----------+
		2)  select version(),返回结果示例:
			+-----------+
			| version() |
			+-----------+
			| 8.0.26    |
			+-----------+
			
	postgresql:
		1)select version(),返回结果示例:
			PostgreSQL 14.1 (Debian 14.1-1.pgdg110+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 10.2.1-6) 10.2.1 20210110, 64-bit

	oracle:
		1) select banner from v$version,返回结果示例:
			Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
			PL/SQL Release 11.2.0.1.0 - Production
			CORE	11.2.0.1.0	Production
			TNS for Linux: Version 11.2.0.1.0 - Production
			NLSRTL Version 11.2.0.1.0 - Production
			
2. 基于字符串的拼接方式:somestring
	
	sqlserver: select 'some'+'string';
	mysql:select 'some' 'string'
	postgresql:select 'some' || 'string'
	oracle:select 'some' || 'string' from dual
	
3. 使用数字参数

	sqlserver:
		1) @@pack_reveived:返回数据包信息,示例:
		
			1> select @@pack_received
			2> go

			-----------
					132
		2) @@rowcount:返回上一句影响的行数,示例:
		
			1> select @@rowcount
			2> go

			-----------
					  1
					  
	mysql:
		1)connection_id():返回连接的id,示例:
		
			mysql> select connection_id();
				+-----------------+
				| connection_id() |
				+-----------------+
				|              12 |
				+-----------------+
				1 row in set (0.00 sec)
		2)last_insert_id():获取最近插入主键的id,示例:
		
			mysql> select last_insert_id();
				+------------------+
				| last_insert_id() |
				+------------------+
				|                0 |
				+------------------+
				
		3)row_count():获取上次受影响的行数,示例:
		
			mysql> select row_count();
				+-------------+
				| row_count() |
				+-------------+
				|          -1 |
				+-------------+

	oracle:
		1)bitand:返回按位进行运算的结果,示例:
		
			SQL> select bitand(1,1) from dual;

				BITAND(1,1)
				-----------
					  1

	postgresql:
		1)extract():提取时间或者日期信息,示例:
		
			postgres=# select extract(dow from now());
				 extract 
				---------
					   4
				(1 row)
				
4. 注释

	mysql:#,--,/* */
	oracle和sqlserver:--,/* */,oracle不支持;符号
	
	

2.2 常用注入语句

2.2.1 UNION语句

用来合并两条或多条SELECT语句的查询结果

SELECT col1,col2 ... coln FROM table1
UNION
SELECT col1,col2 ... coln FROM table2

默认情况下,结果中只包含不同的值,如果需要包含所有的值,就需要改为:UNION ALL,如果应用程序返回第一个表查询所得的数据,那么就可以利用UNION来查询任何一张表,但是也需要满足一定的条件

1)两个查询返回的列数必须相同。想要获取准确的列数,有两种方法:
     a)通过对第二个语句进行注入多次,每次逐渐增大列数,直到查询正确执行,为了避免数据类型不一致导致错误,可以使用null来代替
	 b)使用ORDER BY子句,可以增大列的数字来判断列数,示例:ORDER BY 1(2,3,等),如果ORDER BY 3报错,证明是2列,该方法比较推荐,主要原因是可以使用二分查找的方式,速度更快,同时留下的痕迹更少
	 
2)两个SELECT语句对应列所返回的数据类型必须相同(或至少是兼容的)。在获取列数之后,想要判断数据类型,就可以通过null的方式来进行替换,比如:UNION SELECT 'test', NULL,NULL ...

2.2.2 条件语句

有的情况,查询结果只有两种答案:是或否,这个时候就可以通过使用条件语句,格式示例:

IF 条件 THEN 执行 ELSE 执行其他
2.2.2.1 基于时间

比如想知道执行查询的语句是不是系统管理员账号

常用的有:

  • 获取数据库信息,比如:数据库名(substr(),left()),数据库长度(length()),示例猜测数据库长度

  • 获取数据表信息,示例猜测表名长度

  • 获取列信息,示例猜测列名长度

2.2.2.2 基于错误

基于时间不适用于提取多位信息,比如出现1和0的概率都是一样的,主要方法有利用回显的报错注入和利用报错信息的报错注入