Limitar ataques a xmlrpc en Kubernetes

Disable xml-rpc.php in WordPress

Si has montado un wordpress en un cluster de Kubernetes y lo has publicado, habrás notado que al poco tiempo comienza a dar algunos problemas. No te preocupes no es tu fallo, puedes estar sufriendo un ataque de denegación de servicio. En esta entrada vamos a explicar cómo mitigarlo.

Por si no te suenan las sigas DDoS ( Denial Of Services ) es un tipo de ataque que consigue que un servicio publicado en internet deje de funcionar de forma adecuada. En algunas ocasiones puede ser un ataque completamente dirigido con un objetivo claro y en otras puede ser un daño colateral de cualquier otra actividad. Si se trata del primer caso , la solución puede ser un poco más compleja que la que planteamos hoy aquí , en mi caso se trata de un escaneo masivo desde distintas IP’s a un recurso que está accesible por defecto en WordPress , es «/xmlrpc.php» .

¿Qué hay detrás de XML RPC en WordPress ?

Se trata de un servicio de acceso remoto que permite interactuar con nuestro wordpress. Ideado en 2016 e incluido en la versión 2.6 de WordPress ha sido recientemente «reemplazado» por la API REST. Por tanto es muy probable que no lo necesites más.

¿Por qué es un peligro tenerlo activo?

Desde hace años es posible empleando este servicio que tu WordPress envíe «pings» a otras direcciones web. Un atacante puede usando tu sitio y otros que tengan XML-RPC activo lanzar ataques masivos sobre una Web concreta , por lo que sería partícipe, inconscientemente, del primer caso de DDoS que hemos comentado.

¿Por qué me afecta a mi sitio?

Cuando estos ataques emplean tu web consumen los recursos de tu sistema por lo que puedes experimentar problemas de uso de memoria o lentitud en tu web por falta de CPU. Si prestas atención a tu fichero de logs podrás observar muchas entradas como esta:

1XX.XXX.XXX.XXX - - [01/Jan/2021:00:00:01 +0000] "POST /xmlrpc.php HTTP/1.1" 200 222

¿Cómo puede verificar si está accesible el recurso xmlrpc ?

Una forma muy sencilla es acudir a un servicio de validación, que comprobará tu sitio y te dirá si xmlrpc.php está habilitado.

Servicio de validación de WordPress XML-RPC
WordPress XML-RPC Validation Service

Cuando indique la url de tu wordpress, si el sitio puede acceder a tu xmlrpc te lo indicará con una pantalla como esta.

XML-RPC está accesible y supone un riesgo

En el caso de que esta no sea accesible la pantalla será como la siguiente:

XML-RPC ha sido desactivado

¿Como puedo eliminar el acceso a este recurso?

Cuando se trata de un WordPress alojado en un servicidor VPC , la solución es bastante fácil. Tan solo tenemos que denegar el acceso a este recurso en la configuración de nuestro servidor web. Ya sea mediante configuración o mediante el fichero .htaccess , vamos a indicar como:

En el caso del fichero .htaccess debemos añadir lo siguiente:

# Block WordPress xmlrpc.php requests
<Files xmlrpc.php>
order deny,allow
deny from all
allow from none
</Files>

En el caso de un servidor web nginx, la configuración será :

# IMPORTANT: for security purposes, disable access to xmlrpc
location = /xmlrpc.php {
deny all;
return 404;
access_log off;
log_not_found off;
}

¿Qué pasa cuando WordPress se publica en Kubernetes?

Pues en este caso es probable que emplees un balanceador de carga de tu proveedor y un controlador de ingress dentro del cluster Kuberntes para habilitar el acceso a los distintos servicios que publicas.

En este caso debemos modificar el ingress asociado a WordPress para que descarte las peticiones que van dirigidas al recurso xmlrpc mediante un código de error.

Si como en mi caso empleas un controlador de ingress basado en nginx , uno de los más populares y que mejor rendimiento proporcionan tendrás que seguir los siguientes pasos.

Comencemos listando todos los ingress e identificando el que está asociado al dominio.

kubectl get ingress                                                                                                                                                                                                     
NAME      CLASS    HOSTS             ADDRESS                                     PORTS     AGE
wordpress <none>   www.domain.com    abcdefXXXXXXX.ab-east-4.elb.amazonaws.com   80, 443   1d20h

Ya hemos identificado como se llama , podemos obtener toda la configuración y enviarla a un fichero con :

kubectl get ingress wordpress -o yaml > wordpress.yaml

Veamos el contenido:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/issuer: wordpress-issuer
    kubernetes.io/ingress.class: nginx
    kubernetes.io/tls-acme: "true"
    meta.helm.sh/release-name: wordpress
    meta.helm.sh/release-namespace: default
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
  labels:
    app.kubernetes.io/instance: wordpress
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: wordpress
    helm.sh/chart: wordpress-XX.X.X
  name: wordpress
  namespace: default
spec:
  rules:
  - host: www.domain.com
    http:
      paths:
      - backend:
          serviceName: wordpress-service
          servicePort: http
        path: /
        pathType: ImplementationSpecific
  tls:
  - hosts:
    - www.domain.com
    secretName: wordpress-tls
status:
  loadBalancer:
    ingress:
    - hostname: abcdefXXXXXXX.ab-east-4.elb.amazonaws.com

Debemos agregar a esta configuración una nueva anotación que se encargará de denegar el acceso y enviar un error 403 cuando se solicite el recurso «/xmlrcp.php»

Quedando el fichero así:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/issuer: wordpress-issuer
    kubernetes.io/ingress.class: nginx
    kubernetes.io/tls-acme: "true"
    meta.helm.sh/release-name: wordpress
    meta.helm.sh/release-namespace: default
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    nginx.ingress.kubernetes.io/server-snippet: |
      location ~* "^/xmlrpc.php" {
          deny all;
          return 403;
        }
  labels:
    app.kubernetes.io/instance: wordpress
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: wordpress
    helm.sh/chart: wordpress-XX.X.X
  name: wordpress
  namespace: default
spec:
  rules:
  - host: www.domain.com
    http:
      paths:
      - backend:
          serviceName: wordpress-service
          servicePort: http
        path: /
        pathType: ImplementationSpecific
  tls:
  - hosts:
    - www.domain.com
    secretName: wordpress-tls
status:
  loadBalancer:
    ingress:
    - hostname: abcdefXXXXXXX.ab-east-4.elb.amazonaws.com

Tan solo debemos aplicar la nueva configuración y de inmediato dejarán de estar accesible el recurso.

Si revisar el log del pod asociado a wordpress observarás de inmediato que desaparecen las peticiones al recurso, y verás como se reduce el uso de recursos de la web.

Comments are closed, but trackbacks and pingbacks are open.