作为计算机安全入门课程的一部分,我们有一个关于 SQL 注入的简短单元。其中一项作业是一个基本的未经清理的登录页面。预期的解决方案是沿着经典路线的' or 1=1; --
,但我们始终欢迎学生找到非传统的解决方案。
最近向我提出了这样的解决方案:输入'--'
密码似乎执行了成功的 SQL 注入。这将导致查询被评估为如下所示:
SELECT * FROM users WHERE name='admin' AND password=''--'';
这里,--'';
不被解析为注释,因为 MariaDB 要求注释后面跟空格。事实上,如果双破折号被解析为注释,则该查询根本不会返回任何内容;password=''
同样地,假设密码非空,我们将得到,其计算结果为 false。
末尾的额外一对引号似乎是必要的:将其保留为password=''--;
或在其后面插入其他数据 ( password=''--1;
) 会导致条件被评估为 false,如预期的那样。
一些快速测试无法在其他数据库中重现这种行为——据我所知,这是 MariaDB 特有的行为。该文档确认两个不带空格的破折号不会被解析为注释,但没有详细说明它们被解析为什么。编辑:不知何故,我设法忽略了 MySQL 中也发生这种情况的事实。事实上,这种行为发生在任何 MySQL 分支(不仅仅是 MariaDB)中。
--
当它后面没有空格时会发生什么?为什么它会导致比较结果为 true?
一个玩具示例:
CREATE TABLE users (
userid INTEGER PRIMARY KEY,
username TEXT NOT NULL,
password TEXT NOT NULL
);
INSERT INTO users VALUES (0001, 'admin', 'S3cur3P4ssw0rd!');
INSERT INTO users VALUES (0002, 'generic_user', 'Password');
SELECT * FROM users WHERE username='admin' AND password=''; -- empty password, query returns no users
SELECT * FROM users WHERE username='admin' AND password=''-- ''; -- parsed as comment, equivalent to above query, returns no users
SELECT * FROM users WHERE username='admin' AND password=''--''; -- query returns admin user
SELECT * FROM users WHERE username='admin' AND password=''--; -- query returns zero users
SELECT * FROM users WHERE username='admin' AND password=''--1; -- query returns zero users
这个具体的SQL注入用到了两个方面:
首先,
--
没有空格,连同其后面的值,被解析为负数的减法。当您运行查询时您将得到以下结果:
所以当你运行查询时
0
您将得到第一个数字 ( ) 减去第二个负数 ( )的结果-0
,结果为0
。第二部分是当上下文要求字符串为数字时,MariaDB(和 MySQL)尝试将字符串转换为数字。请参阅以下查询:
这没有什么特别的结果:
但是当你做这样的算术时
你得到这个:
这可以通过上面的算术来对付你,其结果是
0
。查询将显示以下结果(我添加了一个密码开头为数字的新用户):
在这里您可以看到,它首先会将密码转换为数字(很可能是 )
0
,然后将其与0
中的“您的”值进行比较''--''
,从而导致 SQL 注入成功。