为什么`(backtick)能做"注释符"

文章用markdown写的,用`的时候老是成了代码块,找了会资料都没转义掉,以下用backtick代替`。

很久以前的一个Paper,介绍了mysql下的注释符,里面包含了两种不常见的"注释符"。

今天有小伙伴刚好来问了一下我, 为啥backtick做注释符时,并不是通用的, 也就是有时候并不能注释掉,不能像#这种注释符通用。
(其实paper里的NOTE已经基本解答了这个问题,不过NOTE写的是只能用在别名处)

Note:

The backtick can only be used to end a query when used as an alias.

他给我的语句类似于

select * from qs_members where username = 'x' and password = 'x';

然后他盲注,插入payload
1' and if(substr((select password from qs_admin limit 1),1,1)='a',sleep(1),1)` 语句就成了

select * from qs_members where username='1'and if(substr((select password from qs_admin limit 1),1,1)='a',sleep(1),1)` and password='admin';

然后这时候语句就开始报错了, 但是如果把backtick换成#,语句就能正常执行, 说明这个时候backtick没有了注释效果。

首先来看一下mysql手册的comment Syntax

From a # character to the end of the line.

From a – sequence to the end of the line. In MySQL, the – (double-dash) comment style requires the second dash to be followed by at least one whitespace or control character (such as a space, tab, newline, and so on). This syntax differs slightly from standard SQL comment syntax, as discussed in Section 1.8.2.4, “'–' as the Start of a Comment”.

From a /* sequence to the following */ sequence, as in the C programming language. This syntax enables a comment to extend over multiple lines because the beginning and closing sequences need not be on the same line.

官方所介绍的注释只有前三种, backtick并不是一个真正的注释符, 而是一个identifier quote。

Backticks for enclosing identifiers such as table and column names,
Backticks are generally used to indicate an identifier and as well be safe from accidentally using the Reserved Keywords.

一般用来引住表名,列名,别名。

那为什么backtick 能当作"注释符"呢,
其实这是因为, 在mysql query 执行sql的时候, 不知道啥原因(翻了会google也没找到具体的解,感觉还是最后的时候mysql给它给闭合了?) backtick在不闭合的情况下, 也能够正常执行。

别名、表名、列名在backtick的引用下,可以写任意字符。
所以

select username from qs_members where username = '' and password = '';
我们在username处插入yu' union select 1 from qs_admin `
语句就成了
select username from qs_members where username = 'yu' union select 1 from qs_admin `' and password = ''

给起别名的时候,as是可以省略的,
所以后面的' and password = '' 这些字符都成了qs_admin表的别名,
也就相当于成了一个"注释符",让后面的内容不再有以前的效果。

那为什么有时候backtick 又不能当做注释符呢?
select * from qs_members where username='1' and if(substr((select password from qs_admin limit 1),1,1)='a',sleep(1),1)` and password='admin';
像上面我小伙伴失败的那个语句, 很明显backtick在的这个地方, 是一个不允许起别名的地方,所以语句就报错了。
还有一种失败的情况是,

当sql语句为 select * from xxx where `username` = 'a' union select 1,2` and `password`='xxxx'
很多查询会把column用`给引住, 在这种情况下, `也不能当作注释符, 因为我们插的` 和后面一个列的` 所闭合, 导致了没办法当作注释。

所以呢,backtick要起一个注释效果, 是需要在允许写表名、列名、别名的地方。

那么盲注、报错之类不用union的注入, 如何使用backtick 来注释呢。
方法很多, 比如可以找一个可以用列名的地方, 例如 order by,having 之类的。

盲注的话, 会提示找不到这个column

加个@即可