绕过 mysql_real_escape_string() 的 SQL 注入

2023-11-27

即使使用时是否也存在 SQL 注入的可能性mysql_real_escape_string()功能?

考虑这个示例情况。 SQL 在 PHP 中的构造如下:

$login = mysql_real_escape_string(GetFromPost('login'));
$password = mysql_real_escape_string(GetFromPost('password'));

$sql = "SELECT * FROM table WHERE login='$login' AND password='$password'";

我听到很多人对我说,这样的代码仍然很危险,即使使用mysql_real_escape_string()使用的功能。但我想不出任何可能的利用?

经典的注射是这样的:

aaa' OR 1=1 --

不工作。

你知道有什么可能的注入可以通过上面的 PHP 代码吗?


简短的答案是是的,是的,有办法绕过mysql_real_escape_string()。 #对于非常模糊的边缘情况!!!

长答案并不那么容易。它基于攻击在这里展示.

攻击

那么,让我们首先展示攻击......

mysql_query('SET NAMES gbk');
$var = mysql_real_escape_string("\xbf\x27 OR 1=1 /*");
mysql_query("SELECT * FROM test WHERE name = '$var' LIMIT 1");

在某些情况下,这将返回多于 1 行。让我们剖析一下这里发生了什么:

  1. 选择字符集

    mysql_query('SET NAMES gbk');
    

    为了使这种攻击起作用,我们需要服务器期望在连接上进行编码'如 ASCII 所示,即0x27 and某些字符的最后一个字节是 ASCII\ i.e. 0x5c。事实证明,MySQL 5.6 默认支持 5 种这样的编码:big5, cp932, gb2312, gbk and sjis。我们会选择gbk here.

    现在,注意使用非常重要SET NAMES这里。这设置了字符集在服务器上。如果我们使用C API函数的调用mysql_set_charset(),我们会没事的(自 2006 年以来的 MySQL 版本)。但稍后会详细说明原因......

  2. 有效载荷

    我们将用于此注入的有效负载以字节序列开始0xbf27. In gbk,这是一个无效的多字节字符;在latin1,这是字符串¿'。请注意,在latin1 and gbk, 0x27其本身就是一个字面意思'特点。

    我们选择这个有效负载是因为,如果我们调用addslashes()在它上面,我们插入一个 ASCII\ i.e. 0x5c, 之前'特点。所以我们最终会得到0xbf5c27,其中在gbk是一个两个字符的序列:0xbf5c其次是0x27。或者换句话说,一个valid字符后跟未转义的字符'。但我们没有使用addslashes()。那么继续下一步...

  3. mysql_real_escape_string()

    C API 调用mysql_real_escape_string()不同于addslashes()因为它知道连接字符集。因此它可以对服务器期望的字符集正确执行转义。然而,到目前为止,客户认为我们仍在使用latin1对于这种联系,因为我们从未另外说过。我们确实告诉了server我们正在使用gbk,但是client仍然认为是latin1.

    因此调用mysql_real_escape_string()插入反斜杠,我们就有了一个自由悬挂'我们“逃脱”内容中的角色!事实上,如果我们看一下$var in the gbk字符集,我们会看到:

    
    縗' OR 1=1 /*  

    这是到底是什么攻击需要。

  4. 查询

    这部分只是一种形式,但这是呈现的查询:

    SELECT * FROM test WHERE name = '縗' OR 1=1 /*' LIMIT 1
    

恭喜,您刚刚成功攻击了一个程序mysql_real_escape_string()...

The Bad

情况变得更糟。PDO默认为模仿使用 MySQL 准备好的语句。这意味着在客户端,它基本上通过 sprintf 进行mysql_real_escape_string()(在 C 库中),这意味着以下内容将导致成功注入:

$pdo->query('SET NAMES gbk');
$stmt = $pdo->prepare('SELECT * FROM test WHERE name = ? LIMIT 1');
$stmt->execute(array("\xbf\x27 OR 1=1 /*"));

现在,值得注意的是,您可以通过禁用模拟的准备语句来防止这种情况:

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

这会usually产生真正的准备好的语句(即数据在与查询不同的数据包中发送)。但是,请注意,PDO 会默默地fallback模拟 MySQL 本身无法准备的语句:它可以的语句是listed手册中,但要注意选择适当的服务器版本)。

The Ugly

我一开始就说过,如果我们使用的话,我们本可以避免这一切mysql_set_charset('gbk')代替SET NAMES gbk。如果您使用 2006 年以来的 MySQL 版本,情况确实如此。

如果您使用的是早期的 MySQL 版本,那么bug in mysql_real_escape_string()意味着无效的多字节字符(例如我们的有效负载中的字符)被视为单个字节以用于转义目的即使客户端已被正确告知连接编码所以这次攻击还是会成功的。 MySQL 中的错误已修复4.1.20, 5.0.22 and 5.1.11.

但最糟糕的是PDO没有公开 C APImysql_set_charset()直到 5.3.6,所以在之前的版本中cannot针对每个可能的命令防止这种攻击! 现在它被曝光为DSN参数.

拯救的恩典

正如我们一开始所说的,要使这种攻击起作用,数据库连接必须使用易受攻击的字符集进行编码。utf8mb4 is 不脆弱但还可以支持everyUnicode 字符:因此您可以选择使用它,但它仅从 MySQL 5.5.3 开始可用。另一种选择是utf8,这也是不脆弱并且可以支持整个Unicode基础多语种飞机.

或者,您可以启用NO_BACKSLASH_ESCAPESSQL 模式,它(除其他外)改变了mysql_real_escape_string()。启用此模式后,0x27将被替换为0x2727而不是0x5c27以及转义过程cannot在以前不存在的任何易受攻击的编码中创建有效字符(即0xbf27还是0xbf27等)——因此服务器仍然会拒绝该字符串,因为该字符串无效。不过,请参阅@eggyal 的回答针对使用此 SQL 模式可能出现的不同漏洞。

安全示例

以下示例是安全的:

mysql_query('SET NAMES utf8');
$var = mysql_real_escape_string("\xbf\x27 OR 1=1 /*");
mysql_query("SELECT * FROM test WHERE name = '$var' LIMIT 1");

因为服务器正在等待utf8...

mysql_set_charset('gbk');
$var = mysql_real_escape_string("\xbf\x27 OR 1=1 /*");
mysql_query("SELECT * FROM test WHERE name = '$var' LIMIT 1");

因为我们已经正确设置了字符集,所以客户端和服务器匹配。

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$pdo->query('SET NAMES gbk');
$stmt = $pdo->prepare('SELECT * FROM test WHERE name = ? LIMIT 1');
$stmt->execute(array("\xbf\x27 OR 1=1 /*"));

因为我们已经关闭了模拟准备语句。

$pdo = new PDO('mysql:host=localhost;dbname=testdb;charset=gbk', $user, $password);
$stmt = $pdo->prepare('SELECT * FROM test WHERE name = ? LIMIT 1');
$stmt->execute(array("\xbf\x27 OR 1=1 /*"));

因为我们已经正确设置了字符集。

$mysqli->query('SET NAMES gbk');
$stmt = $mysqli->prepare('SELECT * FROM test WHERE name = ? LIMIT 1');
$param = "\xbf\x27 OR 1=1 /*";
$stmt->bind_param('s', $param);
$stmt->execute();

因为 MySQLi 始终执行真正的准备好的语句。

包起来

If you:

  • 使用现代版本的 MySQL(5.1 晚期、所有 5.5、5.6 等)AND mysql_set_charset() / $mysqli->set_charset()/PDO 的 DSN 字符集参数(在 PHP ≥ 5.3.6 中)

OR

  • 不要使用易受攻击的字符集进行连接编码(您只使用utf8 / latin1 / ascii / etc)

你100%安全。

否则你很脆弱即使你正在使用mysql_real_escape_string()...

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

绕过 mysql_real_escape_string() 的 SQL 注入 的相关文章

  • 用于存储和检索每个用户敏感数据的.Net 设计模式

    Net 服务器应用程序是否有与存储和检索敏感的每个用户信息 例如第 3 方凭据 相关的参考模式 我的初步设计思路是 生成具有适当强私钥的自签名 X509 证书 导出证书和密钥并将其存储在 USB 密钥中 该 USB 密钥将被锁在宝箱中并由龙
  • 如何将 ctype_alpha 与 UTF-8 结合使用

    如何将 ctype alpha 与 UTF 8 一起使用 我有这个代码 if empty POST false if isset POST first name empty POST first name if ctype alpha PO
  • SQL COUNT(*) 返回错误答案

    以下脚本应返回部门名称以及这些部门中的员工人数 营销 行政和销售部门有 0 名员工 但返回值不是 0 而是 1 我怎样才能纠正它 select Department Departments DepartmentID count as Num
  • 使用 php 将 HLS Segment (ts) 视频转换并加入到 mp4

    你好我正在使用这个工具 https github com Ejz HLSDownloader https github com Ejz HLSDownloader将 HLS 视频片段从 m3u8 播放列表下载到 ts 文件中 不 我不知道如
  • PHP header() 和 jquery mobile

    我想使用 php header Location newpage php 进行重定向 我没有收到错误 但 Jquery mobile 似乎无法加载目标页面 并且地址栏仍保留旧地址 请问您有什么建议吗 Thanks 尝试添加data ajax
  • SQL Server:比较两个表中的列

    我最近完成了从某些应用程序的旧版本到当前版本的迁移 在迁移数据库时遇到了一些问题 我需要一个可以帮助我比较两个表中的列的查询 我的意思不是行中的数据 我需要比较列本身来弄清楚我错过了表结构的哪些变化 看一下红门 SQL 比较 http ww
  • Propel Query 中的动态表名称

    我想知道您是否可以使 propel 查询的表名称动态化 有点像变量 一个例子类似于 DynamicVar Query create 我让它在 ifs 中工作 就像下面的例子一样 但如果更动态地制作 可以删除相当多的行 这些表的设置都是相同的
  • CSV 从 UTF8 到 ISO-8859-1

    我正在尝试修改我的 CSV 导出 但它不会将我的 CSV 从 UTF 8 转换 保存为 ISO 8859 1 请问我做错了什么吗 实际上自从修改了这个之后 我得到了一个空的 CSV 文件 php 7 0 x function my Gene
  • 无效的 PDO 查询不会返回错误

    下面的第二条 SQL 语句在 phpMyAdmin 中返回错误 SET num 2000040 INSERT INTO artikel artikel nr lieferant nr bezeichnung 1 bezeichnung 1
  • 对时间序列数据重新采样

    我有一个以毫秒为单位的时间序列列表 我想对时间序列进行重新采样并对组应用平均值 我如何在 Postgres 中实现它 重新采样 是指聚合一秒或一分钟内的所有时间戳 一秒或一分钟内的所有行形成一组 表结构 date x y z Use dat
  • ON DUPLICATE KEY UPDATE 的自动增量过多

    我有一个包含列的基本表 id 主要是AI 名称 唯一 etc 如果唯一列不存在 则插入该行 否则更新该行 INSERT INTO pages name etc VALUES bob randomness ON DUPLICATE KEY U
  • cURL '格式错误的网址'

    This url 在浏览器中工作得很好 但 cURL 返回错误 3 格式错误的 url 关于解决方法有什么想法吗 EDIT 卷曲代码 function get web page url options array CURLOPT RETUR
  • 如何在 joomla 模块中通过 javascript 发送输入文件类型

    我想将带有 javascript 的文件发送到 php 文件 我的 php 文件中有这个表单
  • 将秒转换为天、小时、分钟和秒

    我想转换一个变量 uptime这是秒 分为天 小时 分钟和秒 Example uptime 1640467 结果应该是 18 days 23 hours 41 minutes 这可以通过以下方式实现DateTime http php net
  • php,in_array,0值

    我试图理解in array下一个场景的行为 arr array 2 gt Bye 52 77 3 gt Hey var dump in array 0 arr 返回值in array 是布尔值true 正如你所看到的no值等于0 所以有人可
  • 从外部 bash 设置环境变量

    我试图使用 PHP 从命令行 设置 bash 环境变量 但没有成功 buff array buff VARTESTKEY VARTESTVALUE buff export VARTESTKEY file put contents scrip
  • 转换MAC地址格式

    我刚刚编写了一个小脚本 从交换机中提取数百个 MAC 地址进行比较 但它们的格式为 0025 9073 3014 而不是标准的 00 25 90 73 30 14 我对如何转换它感到困惑 我能想到的最好的办法就是在 处将它们分解成碎片 然后
  • 阻止对单个 Mercurial 存储库中特定分支的写访问

    是否可以在 Mercurial 中编写某种方式的钩子来拒绝影响存储库中特定命名分支的变更集 我们有一个托管项目 并希望允许任何开发人员将他们的更改推送到我们的存储库 只要他们位于他们自己的命名分支中 这使我们能够在同一存储库中管理单个构建机
  • NodeJS 和 PHP (Laravel) 集成用于 Socket.IO 实时聊天

    目前我有一个我写过的网站PHP通过Laravel 框架 我已经使用写了一个实时聊天nodeJS with 套接字IO and Express现在我想做的是将它集成到我已经编写的 Laravel 网站中 问题是聊天必须在主页中 当前由 Lar
  • PHP - 查找和比较日期

    你好 我有 foreach 我可以在其中获取数据库中的事件数据 我使用数据库中的日期名称 例如 event date 我需要在一个 div 中比较具有相同日期和输出的操作 例如我有这个事件 活动一 9 月 13 日 活动二 9 月 1 日

随机推荐