ARGUS WordPress Defence 1.0.0 — first production release
Automatic WordPress security: local firewall, malware and file-integrity scanning, vulnerability protection, quarantine, scheduled backups, an optional page cache, and automatic global threat intelligence. See README.md for installation, update, and uninstall instructions.
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class Argus_API_Guard {
|
||||
|
||||
public static function init() {
|
||||
add_filter( 'xmlrpc_methods', array( __CLASS__, 'strip_pingback' ) );
|
||||
add_action( 'rest_api_init', array( __CLASS__, 'guard_user_enumeration' ) );
|
||||
}
|
||||
|
||||
public static function strip_pingback( $methods ) {
|
||||
if ( ! Argus_Settings::get( 'xmlrpc_block_pingback', true ) ) {
|
||||
return $methods;
|
||||
}
|
||||
unset( $methods['pingback.ping'], $methods['pingback.extensions.getPingbacks'] );
|
||||
return $methods;
|
||||
}
|
||||
|
||||
public static function guard_user_enumeration() {
|
||||
if ( ! Argus_Settings::get( 'rest_api_protection_enabled', true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_filter(
|
||||
'rest_pre_dispatch',
|
||||
function ( $result, $server, $request ) {
|
||||
if ( is_user_logged_in() ) {
|
||||
return $result;
|
||||
}
|
||||
$route = $request->get_route();
|
||||
if ( 0 !== strpos( $route, '/wp/v2/users' ) ) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$ip = Argus_Request_Inputs::client_ip();
|
||||
|
||||
if ( Argus_Ban_Engine::is_banned( $ip ) ) {
|
||||
Argus_Policy_Engine::deny_already_banned( $ip );
|
||||
return $result;
|
||||
}
|
||||
|
||||
$recent = self::recent_user_enumeration_hits( $ip );
|
||||
|
||||
if ( $recent >= 10 ) {
|
||||
|
||||
$decision = Argus_Policy_Engine::evaluate( $ip, 'rest_abuse', array( 'route' => $route, 'recent_hits' => $recent ) );
|
||||
|
||||
Argus_Findings::record(
|
||||
'account',
|
||||
'high',
|
||||
array(
|
||||
|
||||
'what_happened' => sprintf( 'Unauthenticated user-enumeration probing from %s targeting %s', $ip, $route ),
|
||||
'why_it_matters' => 'Repeated unauthenticated requests to the users endpoint are a well-known reconnaissance step -- enumerating valid usernames to fuel a subsequent brute-force run.',
|
||||
'what_argus_found' => sprintf( '%d unauthenticated requests to %s from %s. Action taken: %s (%s).', $recent, $route, $ip, $decision['action'], $decision['observation_only'] ? 'observed only, MONITOR mode' : 'enforced' ),
|
||||
'when_it_happened' => current_time( 'mysql' ),
|
||||
'why_suspicious' => 'A real client has no reason to request this endpoint repeatedly without authenticating -- this pattern is consistent with an automated recon/scanning tool.',
|
||||
'what_could_be_affected' => 'Enumerated usernames are commonly fed into a follow-up brute-force or credential-stuffing attack against wp-login.php.',
|
||||
'what_should_you_do' => $decision['observation_only']
|
||||
? 'ARGUS is in MONITOR mode and did not block this. Review recent activity and switch to BLOCK mode once you are confident legitimate traffic is not being flagged.'
|
||||
: 'No action needed -- ARGUS already blocked this IP.',
|
||||
),
|
||||
array( 'ip' => $ip, 'route' => $route, 'recent_hits' => $recent, 'decision' => $decision )
|
||||
);
|
||||
|
||||
Argus_Policy_Engine::enforce_decision( $ip, 'rest_abuse', $decision, array( 'route' => $route, 'recent_hits' => $recent ) );
|
||||
} else {
|
||||
Argus_Events::record( 'rest_user_enum_probe', 'low', 'Unauthenticated request to ' . $route, array( 'route' => $route ), $ip );
|
||||
}
|
||||
|
||||
return $result;
|
||||
},
|
||||
10,
|
||||
3
|
||||
);
|
||||
}
|
||||
|
||||
protected static function recent_user_enumeration_hits( $ip ) {
|
||||
global $wpdb;
|
||||
$table = Argus_DB::table( 'events' );
|
||||
$since = gmdate( 'Y-m-d H:i:s', time() - 300 );
|
||||
|
||||
return (int) $wpdb->get_var(
|
||||
$wpdb->prepare(
|
||||
"SELECT COUNT(*) FROM {$table} WHERE event_type = %s AND ip = %s AND created_at >= %s", // phpcs:ignore
|
||||
'rest_user_enum_probe',
|
||||
$ip,
|
||||
$since
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user