sqli-labs打靶记:第1-4关,报错注入&联合注入

一直工具一直爽,手工注入火葬场!

最近在做关于SQL注入的题的时候,深感自己在这一块上过于依赖工具。不是说好了脚本小子进阶之旅吗,这可不行!我对自己的要求是,工具要会,原理要懂,哪里不会补哪里。于是我火速搭建了sqli-labs靶场,查漏补缺,勤学不辍。

一、SQL注入方法论(基于sqli前四关,非盲注)

开干之前,先构建一套知识体系非常重要,要不然上手的时候会比较茫然,不知道从哪里切入。SQL注入的门类,根据参数、技巧、提交方式可以分为若干类,基本上每次注入都是多种类型的叠加:

根据输入参数分为:数字型注入、字符型注入
根据注入技巧分为:联合注入、盲注(布尔盲注、延时盲注)、堆叠注入、报错注入、二次注入、宽字节注入
根据提交类型分为:GET 注入、POST 注入、COOKIE 注入、HTTP 头部注入

我先快速过了一遍sqli靶场里的题目,其中前1-4关是有一些共性的,比如说,从注入技巧上看全是报错注入和联合注入,从提交类型看都是GET注入,从输入参数看,包括了数字型和字符型注入两大类型。这个题目的坡度设计,对于想要快速熟悉SQL注入基本操作的人来说,是新手友好同时,又兼顾了广度。前4关做下来,应该能对SQL注入的思路、步骤有一个大概的认识了。

我参考了奇安信社区385大佬的文章(结构化很强,条理清晰,非常推荐),一般来说,SQL手工注入主要分为以下几个步骤:

  • 判断注入类型
  • 查字段数
  • 查找显示位
  • 爆库名
  • 爆表名
  • 爆列名
  • 爆信息

这7个步骤是联合注入的框架,基本上对大部分SQL注入都适用,但因为注入类型的不同,构造载荷的手法有所不同。我自己做题下来,感觉不同注入类型之间的区别,主要在第一步判断注入类型上。如果对测试体系有了解,SQL注入就相当于是黑盒测试。

当你面对一个存在SQL注入漏洞的站点时,你除了知道存在漏洞外,这个网站后台的SQL语句结构、传参方式,你是一无所知的。你得不断加参数调试,观察页面回显信息,让网站后台数据库报错,再通过报错信息,一点点地拼凑、还原原始的SQL语句,这样才能构造出有效的载荷。举个例子,假设有一个动态参数?id=,当你输入1’后,页面回显报错:

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''1'' LIMIT 0,1' at line 1

去掉最外层,自动加上的引号,可以得到实际执行的SQL语句片段:

'1'' LIMIT 0,1

可以看出,输入的参数1’被单引号包裹了。那么由此可以推断出后台的SQL语句实际为:

SELECT * FROM TABLE WHERE id='input' LIMIT 0,1;

原始SQL语句暴露出来后,用注释闭合掉后面的部分,亦或是构建载荷,都会比较顺手了。所以说,各种门类的SQL注入,首要就是找好参数,还原SQL语句。

二、打靶实战

sqli前4关除了第2关是数字型注入外,其他都是字符型注入,所以我这里完整地打一套第2关做说明,其他几关就讲解开头(后面的操作基本上重复)。

  • 第一步:判断注入类型

1、单引号法

这里先打上一个1’看下页面回显。果不其然,报错了。这里注意一下,这个单引号不管是在数字型还是字符型注入中都会报错,不能作为判断类型的依据,只能说明存在注入点。

2、永真式与永假式

知道存在注入点后,接下来就是判断是数字型还是字符型注入,这里就要引入永真式和永假式的概念:

# 判断数字型
1 and 1=1 #永真式,执行成功,数据能正常回显
1 and 1=2 #永假式,SQL语句没有语法错误,不会报错,页面没有数据回显

#判断字符型
1' and '1'='1 #永真式,执行成功,数据能正常回显
1' and '1'='2 #永假式,SQL语句没有语法错误,不会报错,页面没有数据回显

#其实永真、永假可以等价为true,和false

套用到这里,执行永假式的时候页面不报错也没有数据,确定是数字型注入无误。为了最佳实践,最好在载荷之后打上–+或者#(+号会被浏览器理解为空格,而– 和#在SQL中表示注释),把原始语句后面的表达式注释掉。

这一步其实可以归纳为:先单引号(双引号)测试是否存在注入点,再永真式与永假式测试是否满足条件。

  • 第二步:查字段数

这里用order by一个个试,直到报错为止,这里实践出来的字段数是3:

  • 第三步:查找显示位

所谓查找显示位,就是探明白,我们在上一步中得知的这三个字段,有哪几个会显示在页面上。这里采用union操作符,不过构建载荷的时候要做一些小小的改动,要把id设置为一个不存在的数字,比如-1(或者一些很离谱的数字,总之让它结果为空就行),这样第一句结果就为空,页面只会展示第二句的结果。

# 字段有几个就写几个数,这里是3个,当然你也可以写4,5,6
?id=-1 union select 1,2,3

执行结果显示,只有2和3会显示在页面上。

  • 第四步:爆库名

既然已经得知显示位在第2号和第3号字段,那么接下来就是借助显示位,爆出需要的信息,库名、表名、列名、信息等等。如果已知显示位是2和3,那么替换2或者3任意一个为想要爆的信息即可。接下来的所有操作都依赖于已知的显示位。

这里我选了2号显示位爆库名,当然选择3号显示位也可以。

  • 第五步:爆表名

知道了数据库后,下一步就要探明这个库中有哪些数据表。此时就要借助于MySQL的自带数据库information_schema,它存储了这个数据库内的所有元数据。如果继续选择2号显示位爆表名,因为可能存在多张表,所以采用group_concat来聚合表名:

注意这里载荷要符合SQL语法规范,如果选择3号位来爆表名,写法是这样的:

http://localhost/sqli-labs-master/Less-2/?id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() --+
  • 第六步:爆列名

接下来继续用information_schema爆出列名,这次选择爆emails表:

可以看到emails表有2列。

  • 第七步:爆信息

知道表名、列名后就好办啦。直接走起:

为了提高可读性,可以用concat_ws添加连接符,例如:

http://localhost/sqli-labs-master/Less-2/?id=-1 union select 1,group_concat(concat_ws('-',email_id,id)),3 from emails --+

完成!

三、除第2关外其他各关解法

  • 第1关

简单的字符型注入。永假式测试通过,其余步骤与第二节中一致:

  • 第3关

字符型注入。输入1’,出现报错信息:

由报错信息可知,输入的1’被括号包裹,可以推断出原始SQL语句为:

SELECT * FROM TABLE WHERE id=('input') LIMIT 0,1

载荷构造即为:

http://localhost/sqli-labs-master/Less-3/?id=1') --+
  • 第4关

双引号字符型注入。输入1’,不报错;输入1”(两个单引号),不报错;输入1″(一个双引号),报错。

输入的1″被双引号和括号包裹,可以推断出原始SQL语句为:

SELECT * FROM TABLE WHERE id=("input") LIMIT 0,1

载荷即为:

http://localhost/sqli-labs-master/Less-4/?id=1") --+

发布者

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注