AlkantarClanX12
| Current Path : /www/capitalgmcbuickregina_830/public/wp-content/mu-plugins/ |
| Current File : /www/capitalgmcbuickregina_830/public/wp-content/mu-plugins/lbx-block-user-enum.php |
<?php
/**
* Plugin Name: LBX Security Defense
* Description: Blocks unauthenticated /wp-json/wp/v2/users enumeration, ?author=N redirects, oembed author leaks, and known attacker IPs from the April 2026 campaign. Deployed fleet-wide as response to CVE-2026-0740 aftermath.
* Version: 2.1.0
* Author: Leadbox Security
*/
if (!defined('ABSPATH')) exit;
/**
* 0. Deny known attacker IPs at the earliest possible moment.
* These IPs were observed actively exploiting CVE-2026-0740 and/or
* performing user enumeration reconnaissance against the Leadbox fleet.
*/
$lbx_blocked_ips = [
// User enumeration wave (2026-04-09)
'62.60.131.158',
'62.60.131.175',
// Indonesian credential-stuffing wave (2026-04-12)
'180.252.169.1',
'36.37.209.184',
// Chinese webshell + wp-file-manager abuse (2026-04-24, capitalgmcbuickregina)
'23.142.200.55',
// CVE-2026-0740 exploitation wave (2026-04-07/08)
'109.107.178.102',
'176.213.124.119',
'46.246.126.191',
'185.36.143.39',
'192.36.61.172',
'194.31.175.187',
'18.182.54.150',
];
$lbx_client_ip = null;
foreach (['HTTP_CF_CONNECTING_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_REAL_IP', 'REMOTE_ADDR'] as $h) {
if (!empty($_SERVER[$h])) {
$candidate = explode(',', $_SERVER[$h])[0];
$lbx_client_ip = trim($candidate);
break;
}
}
// Stage 1 (pre-WP): check hardcoded list immediately
if ($lbx_client_ip && in_array($lbx_client_ip, $lbx_blocked_ips, true)) {
header('HTTP/1.1 403 Forbidden');
header('Content-Type: text/plain; charset=utf-8');
header('X-Robots-Tag: noindex, nofollow');
echo "403 Forbidden";
exit;
}
/**
* 1. Unregister /wp/v2/users endpoint entirely for unauthenticated requests.
*/
add_filter('rest_endpoints', function ($endpoints) {
if (is_user_logged_in()) {
return $endpoints;
}
if (isset($endpoints['/wp/v2/users'])) {
unset($endpoints['/wp/v2/users']);
}
if (isset($endpoints['/wp/v2/users/(?P<id>[\d]+)'])) {
unset($endpoints['/wp/v2/users/(?P<id>[\d]+)']);
}
return $endpoints;
});
/**
* 2. Belt-and-suspenders REST rejection for /users/*.
*/
add_filter('rest_pre_dispatch', function ($result, $server, $request) {
$route = $request->get_route();
if (strpos($route, '/wp/v2/users') === 0 && !is_user_logged_in()) {
return new WP_Error(
'rest_forbidden',
'User listing is not exposed.',
['status' => 401]
);
}
return $result;
}, 10, 3);
/**
* 3. Block ?author=N enumeration.
*/
add_action('template_redirect', function () {
if (is_author() && !is_user_logged_in()) {
wp_safe_redirect(home_url('/'), 301);
exit;
}
});
/**
* 4. Strip author info from oEmbed responses.
*/
add_filter('oembed_response_data', function ($data) {
unset($data['author_name'], $data['author_url']);
return $data;
});
/**
* 5. Remove author info from RSS feeds.
*/
add_filter('the_author', function ($author) {
if (is_feed()) {
return get_bloginfo('name');
}
return $author;
});
/**
* 6. Block user sitemap (wp-sitemap-users-1.xml).
* WordPress 5.5+ auto-generates this, leaking all author slugs.
*/
add_filter('wp_sitemaps_add_provider', function ($provider, $name) {
if ($name === 'users') {
return false;
}
return $provider;
}, 10, 2);
/**
* 7. Strip author info from posts/pages REST responses (unauthenticated).
* Prevents username harvesting via /wp-json/wp/v2/posts?_embed
*/
function lbx_strip_author_from_rest($response, $post, $request) {
if (is_user_logged_in()) {
return $response;
}
$data = $response->get_data();
if (isset($data['author'])) {
$data['author'] = 0;
}
$response->set_data($data);
$response->remove_link('author');
return $response;
}
add_filter('rest_prepare_post', 'lbx_strip_author_from_rest', 10, 3);
add_filter('rest_prepare_page', 'lbx_strip_author_from_rest', 10, 3);
/**
* 8. Stage 2 IP check: merge hardcoded + configurable blocklist after WP loads.
* Allows adding IPs without redeploying via:
* wp option patch insert lbx_blocked_ips '' '1.2.3.4'
*/
add_action('muplugins_loaded', function () {
global $lbx_client_ip, $lbx_blocked_ips;
if (!$lbx_client_ip) return;
$db_ips = get_option('lbx_blocked_ips', []);
if (!is_array($db_ips)) $db_ips = [];
$all_ips = array_unique(array_merge($lbx_blocked_ips, $db_ips));
if (in_array($lbx_client_ip, $all_ips, true) && !in_array($lbx_client_ip, $lbx_blocked_ips, true)) {
// This IP was in the DB list but not the hardcoded list — block it now
header('HTTP/1.1 403 Forbidden');
header('Content-Type: text/plain; charset=utf-8');
echo "403 Forbidden";
exit;
}
});
/**
* Helper: get full merged blocklist (called by lbx-login-monitor.php).
*/
function lbx_get_full_blocklist() {
global $lbx_blocked_ips;
$db_ips = get_option('lbx_blocked_ips', []);
if (!is_array($db_ips)) $db_ips = [];
return array_unique(array_merge($lbx_blocked_ips, $db_ips));
}