Zranitelnosti v kódu pluginů a šablon se objevují neustále. Aktuálně se ale jedná o plugin, který pro zrychlení stránek používá více než milion uživatelů.
Problém poněkud mírní to, že chybu lze využít pouze, když je na webu aktivní i plugin Classic Editor, ale ten má 5 milionů aktivních instalací, takže průnik bude ve stovkách tisíc.
Vše spočívá v tom, že plugin v metodě set_urls_with_terms vkládá do SQL dotazu proměnnou $id, které není dostatečně zkontrolována.
public static function set_urls_with_terms(){
global $wpdb;
$terms = $wpdb->get_results("SELECT * FROM `".$wpdb->prefix."term_relationships` WHERE `object_id`=".static::$id, ARRAY_A);
foreach ($terms as $term_key => $term_val){
static::set_term_urls($term_val["term_taxonomy_id"]);
}
}
Statická proměnná $id, je definována pomocí set_id metody:
public static function set_id(){
if(isset($_GET["post"]) && $_GET["post"]){
static::$id = esc_sql($_GET["post"]);
if(get_post_status(static::$id) != "publish"){
static::$id = 0;
}
}
}
Na první pohled se může zdát, že programátor použitím esc_sql() vše správně vyřešil, ale bohužel, funkce používá metodu _escape třídy WPDB.
function esc_sql( $data ) {
global $wpdb;
return $wpdb->_escape( $data );
}
Když se podíváte na _escape ve WPDB, zjistíte, že přes _real_escape se pro bezpečnou kontrolu používá mysqli_real_escape_string.
Bohužel, to není zcela bezpečné, viz tento komentář na Stack overflow – https://stackoverflow.com/questions/5741187/sql-injection-that-gets-around-mysql-real-escape-string/12118602#12118602
V podstatě jde o to, že když do $_GET[‚post‘] pošlete ‚1234 OR 1=1‘, tak get_post_status sice vrátí stav postu pro 1234, ale v $id stále zůstane řetězec a ten se vloží do SQL dotazu výše.
Protože nesmíte důvěřovat žádnému GET, nebo POST vstupu, mělo by zde být ověření že jde o integer.
JetPack security team, který chybu objevil, již autory pluginu kontaktoval a ti vydali verzi 0.9.5, která obsahuje záplatu:
public static function set_id(){
if(isset($_GET["post"]) && $_GET["post"]){
if(preg_match("/\D+/", $_GET["post"])){
static::$id = 0;
}else{
static::$id = esc_sql($_GET["post"]);
}
if(get_post_status(static::$id) != "publish"){
static::$id = 0;
}
}
}
Odkaz na zdroj: https://jetpack.com/2021/10/14/multiple-vulnerabilities-in-wp-fastest-cache-plugin/
P.S.: na Facebooku při sdílení minulého článku o nějaké zranitelnosti, která se projeví, pouze, když je uživatel přihlášen, někdo argumentoval tím, že když má web, který neumožňuje přihlášení uživatelů do adminu, tak je v pohodě. To je pravda jen do doby, než se objeví jiná díra, která umožní registrovat uživatele, nebo někdo prolomí slabé heslo. Takže i takové aktualizace, které se vás zdánlivě netýkají jsou důležité.
P.S. 2: a také nám podobné články ukazují chyby jiných, z kterých se můžeme poučit a psát lepší a bezpečnější vlastní kód.