原文链接:
https://medium.com/@ngocnb.915/sql-injection-in-wordpress-core-zdi-can-15541-a451c492897
0x00前言:
在5.8.3版本中,wordpress已经修复了这个错误,比较commit的变化,可以在clean_query函数中看到在处理query['terms']变量之前已经添加了query['field']检查。
0x01漏洞分析:
从get_sql_for_clause调用clean_query函数。阅读该函数的代码会发现该函数的工作是为SQL查询中的条件创建子句,具体而言,它的工作是处理接收到的数据,将这些数据组合成SQL查询中的条件。将其返回给父函数。所以我们可以控制这个函数的返回数据,也就是说我们可以控制SQL查询和执行SQL注入。
回到clean_query函数,没有这个改变,默认情况下query['terms']中的值只会被删除,然后调用this->transform_query(query, 'term_taxonomy_id');为避免 if,query['taxonomy']需要为空或is_taxonomy_hierarchical的值返回false。
在函数transform_query会检查query['field'] == resulting_field,如果为true将返回并且不做进一步处理,所以如果query['field']变量是term_taxonomy_id那么我们可以在不改变query的情况下退出函数['terms']变量值。
(这里的比较是使用==,使用的是弱比较),在某些情况下这个错误可以用来随意创建条件句)。
退出函数后,会回到调用clean_query函数的位置,也就是get_sql_for_clause函数,$query['terms']变量中的值会直接作为SQL查询的条件,并导致SQL 注入。
总而言之,要产生 SQL 注入,必须满足两个条件:
(1)$query['field'] 是 term_taxonomy_id
(2)query['taxonomy'] 为空或 is_taxonomy_hierarchical(query['taxonomy']) === false
0x02开发:
虽然这是wordpress核心的错误,但是wordpress核心使用的方式并没有触发错误,所以我转而寻找插件和主题的错误。当您想查询数据库时,插件/主题将调用 WP_Query 类,从源代码中了解错误的方法是使用 WP_Query(data) 和 data 是您可以控制的。
例如,new WP_Query(json_decode($_POST['query_vars'])),有效载荷将采用以下形式:
query_vars={"tax_query":{"0":{"field":"term_taxonomy_id","terms":[""]}}}
或者
query_vars={"tax_query":{"0":{"taxonomy":"nav_menu","field":true,"terms":[""]}}}
在搭建测试环境时,启用debug功能可以通过基于错误的方式检测 SQL 注入:
0x03结论:
在wordpress补丁中添加了query['field']首先检查,否则query['terms'] 将被转换为整数,因此SQL注入不会发生。发现相当多的插件和主题受到该漏洞的影响(authen和unauthen)。
团队在9月底向ZDI报告了此漏洞,3个月后,wordpress在其核心中修复了该漏洞。具体来说,时间线如下:
推荐阅读: