Κρίσιμο κενό ασφαλείας στο WPvivid Backup: unauthenticated arbitrary file upload με πιθανό πλήρες takeover σε sites με ενεργό “send backup to site” key
Αν τρέχεις WordPress σε παραγωγή, ξέρεις ότι τα backup/migration plugins είναι από τα πιο «ευαίσθητα» σημεία, γιατί αναγκαστικά αγγίζουν αρχεία, paths και διαδικασίες μεταφοράς δεδομένων. Σε αυτή την περίπτωση, το WPvivid Backup (WPvivid Backup & Migration / Migration, Backup, Staging) βρέθηκε να έχει μια unauthenticated arbitrary file upload ευπάθεια, η οποία μπορεί να καταλήξει σε Remote Code Execution (RCE) και πρακτικά σε πλήρες compromise.
Το advisory αφορά plugin με πάνω από 800.000 ενεργές εγκαταστάσεις. Παρότι η εκμετάλλευση είναι ιδιαίτερα σοβαρή, υπάρχει μια σημαντική λεπτομέρεια: σύμφωνα με την ανάλυση, το κρίσιμο impact αφορά κυρίως sites που έχουν ενεργοποιήσει/χρησιμοποιήσει τη λειτουργία λήψης backup από άλλο site, δηλαδή έχουν δημιουργήσει “generated key” στις ρυθμίσεις του plugin. Η λειτουργία αυτή είναι απενεργοποιημένη από προεπιλογή, και το key μπορεί να έχει διάρκεια το πολύ 24 ώρες (μέγιστο expiration).
Τι ακριβώς είναι το κενό (CVE-2026-1357) και ποιες εκδόσεις επηρεάζει
- CVE: CVE-2026-1357
- CVSS: 9.8 (Critical)
- Επηρεαζόμενες εκδόσεις: <= 0.9.123
- Διορθωμένη έκδοση: 0.9.124
- Συσχετιζόμενο plugin/slug: wpvivid-backuprestore (WPvivid Backup & Migration / Migration, Backup, Staging)
- Είδος: Unauthenticated Arbitrary File Upload με δυνατότητα Remote Code Execution
Το πρακτικό σενάριο επίθεσης είναι κλασικό για file upload ευπάθειες: ο επιτιθέμενος καταφέρνει να ανεβάσει αυθαίρετο αρχείο (π.χ. ένα PHP webshell) σε directory που είναι προσβάσιμο από το web. Έπειτα το καλεί με HTTP request και εκτελεί κώδικα στον server.
Σημείωση για το πραγματικό exposure
Η εκμετάλλευση περιγράφεται ως unauthenticated, αλλά το advisory υπογραμμίζει ότι το «κρίσιμο» impact αφορά κυρίως περιπτώσεις όπου έχει δημιουργηθεί key στις ρυθμίσεις για να επιτρέπεται σε άλλο site να στείλει backup στο δικό σου. Αυτή η δυνατότητα είναι disabled by default και το expiration του key δεν ξεπερνά τις 24 ώρες.
Πώς “δένει” τεχνικά η εκμετάλλευση: crypto error handling + path traversal
Η τεχνική ρίζα του προβλήματος (όπως παρουσιάστηκε) είναι ένας συνδυασμός από δύο θέματα: (α) χειρισμός σφάλματος στη διαδικασία RSA decryption που τελικά οδηγεί σε προβλέψιμο κλειδί για AES/Rijndael, και (β) έλλειψη απολύμανσης (sanitization) του path/filename όταν γράφονται τα uploaded αρχεία στο filesystem.
Το WPvivid έχει δυνατότητα να λάβει backup από άλλο site. Αυτό γίνεται μέσω handler που, με βάση την ανάλυση, περνά από τη μέθοδο send_to_site() (στην κλάση WPvivid_Send_to_site) και αξιοποιεί ένα short-term key που δημιουργείται στις ρυθμίσεις.
Στο κομμάτι της κρυπτογράφησης/αποκρυπτογράφησης, η αλυσίδα (σε επίπεδο λογικής) έχει ως εξής:
- Το plugin λαμβάνει
wpvivid_content(base64) από POST και το περνά σε διαδικασία decrypt μέσωdecrypt_message(). - Η
decrypt_message()επιχειρεί να κάνει RSA decrypt ενός session key (με βάση public/private key pair). - Όταν το RSA decrypt αποτυγχάνει, αντί να τερματίσει σωστά, το αποτέλεσμα του decrypt μπορεί να είναι
false. - Αυτό το
falseπερνιέται στη βιβλιοθήκη κρυπτογράφησης (phpseclib / Rijndael/AES initialization), όπου αντιμετωπίζεται σαν string από null bytes, άρα προκύπτει ένα προβλέψιμο “null-byte key”. - Με προβλέψιμο κλειδί, ένας επιτιθέμενος μπορεί να δημιουργήσει “έγκυρο” κρυπτογραφημένο payload (ή καλύτερα: payload που θα αποκρυπτογραφηθεί με το null-byte key).
- Παράλληλα, το plugin δέχεται filename από το αποκρυπτογραφημένο payload χωρίς επαρκές sanitization, επιτρέποντας directory traversal ώστε να ξεφύγει από τον «προστατευμένο» backup φάκελο.
- Έτσι μπορεί να γραφτεί αυθαίρετο PHP αρχείο σε web-accessible directory και να επιτευχθεί RCE.
Η εκμετάλλευση αναφέρεται ότι μπορεί να γίνει μέσω παραμέτρου/ενέργειας wpvivid_action=send_to_site.
Ενδεικτικά σημεία κώδικα που σχετίζονται με το flow
Το παρακάτω απόσπασμα (όπως παρουσιάστηκε) δείχνει το flow στη send_to_site() όπου διαβάζεται το token/option, γίνεται decode του POST body και καλείται το decrypt:
public function send_to_site()
{
include_once WPVIVID_PLUGIN_DIR . '/includes/class-wpvivid-crypt.php';
$test_log = new WPvivid_Log();
$test_log->CreateLogFile('test_backup','no_folder','transfer');
$test_log->WriteLog('test upload.','notice');
try
{
if(isset($_POST['wpvivid_content']))
{
global $wpvivid_plugin;
$wpvivid_plugin->wpvivid_log = new WPvivid_Log();
$default = array();
$option = get_option('wpvivid_api_token',$default);
if(empty($option))
{
die();
}
if($option['expires'] != 0 && $option['expires'] < time())
{
die();
}
$crypt = new WPvivid_crypt(base64_decode($option['private_key']));
$body = base64_decode($_POST['wpvivid_content']);
$data = $crypt->decrypt_message($body);
}
}
catch(Exception $e)
{
// ...
}
}Το κρίσιμο σημείο είναι ότι το RSA decrypt αποτυγχάνει και επιστρέφει false, και αυτό το false μπορεί να φτάσει να χρησιμοποιηθεί ως key στο Rijndael/AES:
public function decrypt_message($message)
{
$len = substr($message, 0, 3);
$len = hexdec($len);
$key = substr($message, 3, $len);
$cipherlen = substr($message, ($len + 3), 16);
$cipherlen = hexdec($cipherlen);
$data = substr($message, ($len + 19), $cipherlen);
$rsa = new Crypt_RSA();
$rsa->loadKey($this->public_key);
$key = $rsa->decrypt($key);
$rij = new Crypt_Rijndael();
$rij->setKey($key);
return $rij->decrypt($data);
}Σύμφωνα με την περιγραφή, ο συνδυασμός «μη τερματισμού» σε decrypt failure και του τρόπου που η βιβλιοθήκη αντιμετωπίζει το false (σαν null bytes) επιτρέπει στον επιτιθέμενο να κατασκευάσει κρυπτογραφημένο περιεχόμενο με προβλέψιμο κλειδί.
Το δεύτερο κομμάτι είναι ότι τα filenames από το αποκρυπτογραφημένο payload δεν καθαρίζονταν σωστά, ανοίγοντας χώρο για directory traversal, άρα για εγγραφή αρχείων εκτός του backup directory.
Τι άλλαξε στο patch (0.9.124): έλεγχος κλειδιού + έλεγχος extensions
Η διόρθωση έγινε σε δύο επίπεδα:
- Προστέθηκε έλεγχος ώστε, αν το RSA-decrypted
$keyείναιfalseή κενό, να επιστρέφειfalseκαι να μην συνεχίζει η αποκρυπτογράφηση με «τυχαίο/προβλέψιμο» κλειδί. - Προστέθηκε έλεγχος επέκτασης αρχείου στην
send_to_site()ώστε να επιτρέπονται μόνο backup-related τύποι.
Το patch στο decrypt_message() όπως παρουσιάστηκε:
public function decrypt_message($message)
{
$len = substr($message, 0, 3);
$len = hexdec($len);
$key = substr($message, 3, $len);
$cipherlen = substr($message, ($len + 3), 16);
$cipherlen = hexdec($cipherlen);
$data = substr($message, ($len + 19), $cipherlen);
$rsa = new Crypt_RSA();
$rsa->loadKey($this->public_key);
$key = $rsa->decrypt($key);
if ($key === false || empty($key))
{
return false;
}
$rij = new Crypt_Rijndael();
$rij->setKey($key);
return $rij->decrypt($data);
}Και ο έλεγχος επέκτασης που προστέθηκε στη send_to_site() (με basename(), preg_replace() για safe filename και allowlist extensions):
$safe_name = basename($params['name']);
$safe_name = preg_replace('/[^a-zA-Z0-9._-]/', '', $safe_name);
$allowed_extensions = array('zip', 'gz', 'tar', 'sql');
$file_ext = strtolower(pathinfo($safe_name, PATHINFO_EXTENSION));
if (!in_array($file_ext, $allowed_extensions, true))
{
$ret['result'] = WPVIVID_FAILED;
$ret['error'] = 'Invalid file type - only backup files allowed.';
echo wp_json_encode($ret);
die();
}Ποιος κινδυνεύει περισσότερο (και γιατί έχει σημασία το generated key)
Το advisory επιμένει στο operational detail: η επίθεση «δένει» πάνω στη ροή λήψης backup από άλλο site. Δηλαδή, αν έχεις ενεργοποιήσει τη δυνατότητα να στείλει ένα άλλο site backup στο δικό σου, θα δημιουργήσεις ένα key στις ρυθμίσεις. Αυτό το key είναι χρονικά περιορισμένο (έως 24 ώρες), όμως αρκεί να υπάρχει ενεργό παράθυρο όπου ο endpoint δέχεται τέτοιου τύπου αιτήματα.
Σε πρακτικό επίπεδο, αυτό σημαίνει ότι δύο sites με ίδιο plugin δεν έχουν ίδιο ρίσκο: ένα που απλώς κάνει τοπικά backups (χωρίς send/receive) έχει μικρότερο exposure σε αυτό το συγκεκριμένο vector, σε σχέση με ένα που χρησιμοποιεί ενεργά την “send backup to site” λειτουργία.
Τι πρέπει να κάνεις τώρα (checklist για developers/ops)
- Έλεγξε αν το plugin είναι εγκατεστημένο: WPvivid Backup & Migration (slug:
wpvivid-backuprestore). - Επιβεβαίωσε την έκδοση. Αν είναι 0.9.123 ή παλαιότερη, θεωρείται ευάλωτη.
- Κάνε άμεσο update στη διορθωμένη έκδοση 0.9.124 (όπως αναφέρεται στο advisory, αυτή είναι η patched έκδοση τη στιγμή της δημοσίευσης).
- Αν χρησιμοποιείς τη λειτουργία λήψης backup από άλλο site, έλεγξε αν υπάρχει ενεργό/πρόσφατα ενεργό generated key και περιόρισε τη χρήση της μόνο όταν είναι απαραίτητη.
- Αν έχεις Wordfence, λάβε υπόψη ότι οι χρήστες Wordfence Premium / Care / Response έλαβαν firewall rule στις 22 Ιανουαρίου 2026, ενώ οι χρήστες Wordfence Free (σύμφωνα με το χρονοδιάγραμμα) θα λάβουν την ίδια προστασία στις 21 Φεβρουαρίου 2026.
Σημείωση για το Wordfence firewall rule
Το firewall rule είναι επιπλέον άμυνα, όχι υποκατάστατο του update. Η ουσιαστική αντιμετώπιση είναι το patch στην έκδοση 0.9.124.
Disclosure timeline (όπως δημοσιεύτηκε)
- January 12, 2026 – Υποβλήθηκε αναφορά για Arbitrary File Upload στο WPvivid Backup μέσω του Wordfence Bug Bounty Program.
- January 22, 2026 – Επιβεβαίωση/validation και proof-of-concept exploit. Επικοινωνία με vendor και πρόσκληση χρήσης του Wordfence Vulnerability Management Portal.
- January 22, 2026 – Wordfence Premium/Care/Response έλαβαν firewall rule για προστασία από exploits που στοχεύουν το κενό.
- January 23, 2026 – Ο vendor απάντησε και επέλεξε email για τη διαδικασία disclosure.
- January 23, 2026 – Εστάλησαν οι πλήρεις λεπτομέρειες στον vendor, έγινε αποδοχή της αναφοράς και ξεκίνησε η διόρθωση.
- January 28, 2026 – Κυκλοφόρησε η πλήρως patched έκδοση 0.9.124.
- February 21, 2026 – (Προγραμματισμένο) Wordfence Free θα λάβει την ίδια προστασία.
Γιατί αυτό το incident είναι καλό παράδειγμα “defense in depth”
Εδώ φαίνεται καθαρά πώς ένα exploit chain μπορεί να προκύψει από φαινομενικά «δευτερεύον» λάθος: αποτυχία σε openssl_private_decrypt()/RSA decrypt που δεν τερματίζει σωστά, μεταφορά λάθους τύπου δεδομένου (false) σε crypto initialization και στη συνέχεια file write χωρίς ισχυρούς περιορισμούς (sanitization/allowlist). Σε plugins που διαχειρίζονται μεταφορά backup, κάθε στάδιο πρέπει να είναι αυστηρό: fail-closed στη κρυπτογράφηση και αυστηρά allowlists (paths, extensions, MIME, storage isolation).
Σύνοψη
Το WPvivid Backup επηρεάστηκε από μια Critical ευπάθεια (CVE-2026-1357) που επιτρέπει unauthenticated arbitrary file upload και δυνητικά RCE, με μεγαλύτερο ρίσκο για installations που έχουν ενεργοποιήσει τη λήψη backup μέσω generated key. Η ευπάθεια διορθώθηκε πλήρως στην 0.9.124 με έλεγχο για αποτυχία/κενό RSA key στο decrypt και με allowlist ελέγχου extensions για τα uploads.
Νίκος Αντωνίου
Μέντορας του μεσογειακού οικοσυστήματος startups και τεχνολογικός σύμβουλος. Ειδικός στην ελληνική και κυπριακή τεχνολογική σκηνή. Η τοπική καινοτομία έχει παγκόσμιο αντίκτυπο.
Όλες οι αναρτήσεις