Blind SQL Injection error-based no WordPress
Recentemente identificamos alguns plugins do WordPress com uma falha específica de SQL Injection, o Blind SQL Injection error-based. Segue alguns dos links publicados:
- Profile Builder & Profile Builder Pro < 3.3.3 – Authenticated Blind SQL Injection
- Media Library Assistant < 2.90 – Authenticated Blind SQL Injection
Qual o problema?
Essa falha explora o retorno do erro de uma query mal feita, através de tentativa e erro, validando um retorno correto e outro com problema, se quiser entender melhor temos um post inteiro a falar sobre o Error-based aqui.
Vale lembrar que essa falha só vai ocorrer se o modo debug estiver ativado.
Mas qual o motivo de estarmos encontrando tanto plugins com grande quantidade de downloads ativos com esse mesmo problema?
Existe algumas explicações:
O WordPress tenta da melhor forma escapar dados de entrada principalmente quando se é usado na clausula WHERE. Mas esquecem de escapar parâmetros que vêm depois, como ORDER BY Column e o posicionamento como ASC e DESC, ou uso do GROUP BY e LIMIT.
Todos esses itens podem ser explorados e precisam ser escapados.
Examplo:
$results = $wpdb->get_results("SELECT ID,post_title FROM {$wpdb->posts} WHERE id=$id ORDER BY $orderby limit $limit");
WHERE id=$id -> Falha de SQL Injection clássica. ORDER BY $orderby limit $limit -> Explorada com Error-based Sql Injection nas variáveis $orderby e $limit.
E como se proteger?
Não devemos escapar apenas as clausulas WHERE, por segurança devemos escapar qualquer tipo de parâmetro que seja inserido na query de acordo com sua característica.
O WordPress tem alguns métodos que podem ajudar como sanitize_sql_orderby para os parâmetros do order by o intval() ou int() para parâmetros limit.
Usar esc_attr ou esc_html não irá resolver esse tipo de solução, para cada problema existe uma solução específica.
Outra dica boa é usar sempre valores pré definidos pelo sistema e nunca deixar que ele complete a query completamente, por exemplo usa um if baseado no dado de entrada para saber se ele vai usar ASC ou DESC no order by.
$orderBy = ‘ASC’;
if($var != ‘ASC’){
$orderBy = ‘DESC’;
}
$wpdb->get_results("SELECT ID,post_title FROM {$wpdb->posts} WHERE id=1 ORDER BY ID $orderBy ");