1 实验环境

  1. 操作系统版本:Windows 11 家庭中文版23H2
  2. VMware® Workstation 16 Pro:16.2.3 build-19376536
  3. Metasploitable2虚拟机版本:2.6.24-16-server

2 实验内容

2.1 判断注入点与注入类型

(1)分别测试输入:1及1”

图2.1 判断注入类型:输入1

图2.2 判断注入类型:输入1”

由图2.2所示,从网页的url可知,页面采用GET方法提交数据,并且输入“1””后能够正确得到查询结果,所以推测注入类型为字符注入。

(2)测试输入:1及1’

之后输入1’进行测试,数据库报错如图2.3,这个错误提示是在使用MySQL数据库时,使用的SQL语法有问题,具体是在’1’处,所以可以推测SQL语句的闭合方式是单引号,并发现数据库为MySQL。

图2.3 判断注入类型:输入1’

(3)测试输入:1 and 1 = 1和1 and 1 = 2

图2.4 判断注入类型:输入1 and 1 = 1

图2.5 判断注入类型:输入1 and 1 = 2

由图2.4和图2.5所示,查询的结果都是相当于查询id=1的结果,现在来分析一下为什么会这样。通过上面的分析,可以推断这是一个字符注入,所以说输入的数据会被当作一个字符串插入到SQL语句中,由于查询的id是一个整型,所以它会从当前输入的字符串中识别第一个数字并进行查询,所以我们只要在第一个数字1的后面加上空格后,不管后面输入什么都是相当于查询id=1的数据。

如果不为字符型注入,那么就不会当作一个字符串插入到SQL语句中进行查询,那么执行的时候肯定会报错。

(4)测试输入:1’ and ‘1’ = ‘1

图2.6 判断注入类型:输入1’ and ‘1’ = ‘1

由此可以发现注入类型为字符型注入,且是以单引号结束。

2.2 获取SQL语句中的字段数

使用order by来判断SQL语句中由多少个字段,

(1)输入:1’ order by 1#

order by 1表示按照第一个列进行排序。在SQL中,`order by`子句用于指定查询结果的排序方式,后面可以跟列名或者列的位置(从1开始计数)。因此,`order by 1`表示按照第一个列(查询结果中的第一个列)进行升序排序。`#`符号是SQL中的注释符号,表示后面的内容将被忽略。因此,整个SQL语句的含义是选择数据并按照第一个列进行排序。

结果如图2.7所示,可以看成执行查询成功,所以SQL语句中字段数大于等于1。

图2.7 判断注入类型:输入1’ order by 1#

(2)输入:1’ order by 2#

结果如图2.8所示,可以看成执行查询成功,所以SQL语句中字段数大于等于2。

图2.8 判断注入类型:输入1’ order by 2#

(3)输入:1’ order by 3#

结果如图2.9所示,查询失败,所以可以确定SQL语句中查询字段数为2。

图2.9 判断注入类型:输入1’ order by 3#

2.3 判断回显位置

判断回显位置用来判断目标信息的输出位置,使用union关键字进行分析。

图2.10 判断回显位置

如图2.10所示,查询结果的显示位置是在First name和Surname字段之后。

2.4 获取数据库信息

输入:1’ union select 1,database()#,如图2.11所示,可以得到数据库名为“dvwa”。

图2.11 获取数据库信息

2.5 获取数据库中表名

输入:1’ union select 111,table_name from information_schema.tables where table_schema=’dvwa’#。如图2.12所示,可以得到数据库dvwa中有2个表,分别为guestbook和users。

图2.12 获取数据库中的表名

2.6 获取数据库中表中字段名

这里查询users表中的列名,输入:1’ union select 111,column_name from information_schema.columns where table_schema=’dvwa’ and table_name=’users’#,如图2.13所示。

图2.13 获取users表中的字段名

可以得到users表中一共有user_id、first_name、last_name、user、password和avatar6个列。

2.7 获取字段中的值

获取users表中的user_id和avatar字段数据为例,输入:1’ union select user_id, avatar from users #,如图2.14所示,查询得到了所有的用户id以及对应的头像。

图2.14 获取users表中的user\_id和avatar字段

2.8 通过SQL注入获取guestbook表中的字段

要获取guestbook表中的字段值,可以使用类似上述的查询语句,输入:1’ union select 111,column_name from information_schema.columns where table_schema=’dvwa’ and table_name=’guestbook’#,查询结果如图2.15所示。

图2.15 获取guestbook表中的字段名

可以看到guestbook表中的信息有comment_id、comment和name,之后也可以查询一些guestbook表中的其他信息,过程与上面查询users表类似,不再赘述。

2.9 防止SQL注入攻击

防止字符型SQL注入攻击的关键在于正确地对用户输入进行处理和验证,以确保不会在SQL查询中执行恶意代码,防范字符型SQL注入攻击可以采用以下方法。

  1. 使用参数化查询:使用参数化查询(Prepared Statements)是防范SQL注入攻击的最佳方式之一。参数化查询能够将用户输入的数据与SQL查询逻辑分离,数据库系统会将输入数据视为数据而不是代码,从而防止恶意代码的注入。
  2. 使用**ORM**框架:使用ORM(Object-Relational Mapping)框架可以避免直接编写SQL查询,它们通常会自动处理参数化查询,从而降低了SQL注入攻击的风险。
  3. 输入验证和过滤:对用户输入的数据进行验证和过滤,只允许预期的数据类型和格式通过。例如,如果用户只应该输入数字,则验证输入是否为数字,如果用户只能输入字母,则确保输入仅包含字母等。
  4. 避免动态拼接SQL查询:避免在代码中动态拼接SQL查询,特别是直接将用户输入作为SQL查询的一部分。即使对用户输入进行了过滤和验证,也不应该信任用户输入直接构建SQL查询。

3 实验总结

  1. 通过SQL注入,攻击者可以基本上可以获得数据库的任何信息,同时,我也了解到,攻击者可以通过SQL注入来获取数据库所在平台的一些文件,并进行篡改。
  2. 本次实验虽然步骤较简单,但是需要我们对基本的SQL语句的语法有一定的了解,并且要有学习数据库相关的知识,了解基本的数据库类型。不能仅仅把每一个步骤的实验结果图截下来就行了,而是要理解其背后的原理。