crowdsecurity / hub

Main repository for crowdsec scenarios/parsers
https://hub.crowdsec.net
162 stars 150 forks source link

http-bf-wordpress_bf and admin-ajax.php #1148

Open tomazbc opened 2 weeks ago

tomazbc commented 2 weeks ago

I think it should also trigger on admin-ajax.php like below. Don't know if this is something new but everything posts to admin-ajax.php on my WP sites when trying to login.

type: leaky
name: crowdsecurity/http-bf-wordpress_bf
description: "Detect WordPress bruteforce on admin interface"
debug: false
# failed auth on wp-login.php returns 200
filter: "evt.Meta.log_type == 'http_access-log' && evt.Parsed.file_name == 'wp-login.php' || evt.Parsed.file_name == 'admin-ajax.php' && evt.Parsed.verb == 'POST' && evt.Meta.http_status == '200'"
groupby: evt.Meta.source_ip
capacity: 5
leakspeed: 10s
blackhole: 5m
labels:
  confidence: 3
  spoofable: 0
  classification:
    - attack.T1110
  behavior: "http:bruteforce"
  label: "WordPress Bruteforce"
  service: wordpress
  remediation: true
LaurenceJJones commented 1 week ago

Don't know if this is something new but everything posts to admin-ajax.php on my WP sites when trying to login.

We always wary about adding any files that are used by plugins to issue commands via a backend API. Since we don't know how the developer will implement these calls we found that they can be very false positive prone depending on which plugins you use.

tomazbc commented 1 week ago

Makes sense, I understand. Might be my Wordfence that's installed on all pages that's causing this.

Thanks for taking the time to reply.

GNU-Plus-Windows-User commented 1 week ago

@tomazbc Newer versions of WordPress have switched to using /wp-admin/admin-ajax.php endpoint for logins instead of /wp-login.php. As Loz has explained it's hard to block brute force attacks based on that endpoint.

WordPress brute force attacks will have to be detected via a WAF like CrowdSec's AppSec since it can inspect the HTTP traffic in detail. I posted a workaround in the Discord (Using ModSecurity, I don't know how to write AppSec rules, maybe somebody else can convert what I wrote in SecLang to CrowdSec DSL) so I'll share it here:

Copy this ModSecurity rule:

SecRule REQUEST_FILENAME "@endsWith /wp-admin/admin-ajax.php" \
    "id:1,\
    phase:2,\
    pass,\
    t:none,\
    t:lowercase,\
    t:normalizePathWin,\
    chain"
    SecRule &ARGS:pwd "!@eq 0" \
        "t:none,\
        chain"
        SecRule ARGS:log "@rx ^.*$" \
            "t:none,\
            msg:'WordPress: Login attempt for user: %{MATCHED_VAR}.',\
            ctl:auditLogParts=-C"

Then install the CrowdSec ModSecurity collection, and create this scenario file:

type: leaky
# debug: true
name: your-username/wordpress-bf
description: "WordPress bruteforce attack detected via ModSecurity"
# modsec for nginx only logs the numerical value of the severity
filter: evt.Meta.log_type == 'modsecurity' && evt.Parsed.ruleid == '1'
capacity: 5
leakspeed: "10s"
blackhole: 5m
groupby: "evt.Meta.source_ip"
labels:
  remediation: true
  classification:
    - attack.T1110
  behavior: "http:bruteforce"
  label: "WordPress Bruteforce (ModSecurity)"
  spoofable: 0
  confidence: 3
  service: wordpress
---
type: leaky
# debug: true
name: your-username/wordpress-bf-user-enumeration
description: "WordPress bruteforce user enumeration attack detected via ModSecurity"
# modsec for nginx only logs the numerical value of the severity
filter: evt.Meta.log_type == 'modsecurity' && evt.Parsed.ruleid == '1'
distinct: evt.Parsed.rulemessage
capacity: 5
leakspeed: "15s"
blackhole: 5m
groupby: "evt.Meta.source_ip"
labels:
  remediation: true
  classification:
    - attack.T1589
  behavior: "http:scan"
  label: "WordPress Bruteforce (ModSecurity)"
  spoofable: 0
  confidence: 3
  service: wordpress

Brute force attacks should be detectable now