¡El 2018 ha comenzado con un ataque a nuestros servidores!

per Victor Carceler darrera modificació 2020-03-25T15:33:22+01:00

Ha sido llegar la primera semana lectiva del 2018 y encontrar problemas en el acceso a nuestros servicios web. Suerte que, de momento, todo ha vuelto a la normalidad. Pero como precisamente estos días estamos viendo en clase los proxys y los servidores web aprovecho para contar lo sucedido y dejarlo documentado por si a alguien le resulta útil la experiencia.

Stranger things...

Lunes 8 de enero, de forma puntual se detectan problemas al acceder a nuestros servicios web: https://elpuig.xeill.net, https://moodle.elpuig.xeill.net, https://blog.elpuig.xeill.net y otros...

Curiosamente el acceso a Internet no falla y no se percibe ningún otro problema en la red, pero lo extraño es que nuestros servicios están alojados en nuestra propia LAN. Así que si no hay problemas en nuestra red ... ¿por qué tardan tanto en contestar? Normalmente contestan muy rápido y así debe seguir siendo.

Un poco de infraestructura

Todos nuestros servicios se ejecutan en máquinas virtuales lo que, entre otras ventajas, permite tener una máquina adecuada a las necesidades de cada servicio sin complicar la infraestructura. Así hay una máquina (virtual) para la web del centro, otra para el blog, el servidor moodle, etc...

Frente a estas máquinas, que tienen su propio servidor web, hay otro servidor frontal que actúa de terminador TLS. En este servidor se configura todo lo necesario para que los clientes accedan mediante HTTPS en único sitio. Por supuesto, gracias a Let's Encrypt, utilizamos certificados web reconocidos por los navegadores para no espantar a los usuarios con alertas. Y llegado el caso, lo que quiere decir la próxima Ubuntu 18.04 LTS, este servidor se podrá actualizar para que atienda a los clientes utilizando HTTP/2.

https://en.wikipedia.org/wiki/File:SSL_termination_proxy.svg

Tanto los clientes que se encuentran en Internet como los que están en la propia LAN del centro acceden al mismo servidor web, que implementa HTTPS y hace de proxy, para visitar cualquiera de nuestros servicios web. Pues bien, este servidor web (la versión estable y actualizada de Apache que se incluye en Ubuntu 16.04 LTS) ha sido la víctima del ataque.

Sobre la víctima

En otros sitios con más recursos, o con un administador más sensato, puede que tengan su servidor web en una máquina de verdad. Ni que decir tiene que no es nuestro caso.

La víctima es un Apache 2.4 que se ejecuta en un contenedor LXD con el descriptivo nombre de Letsencrypt que, a su vez, corre sobre una máquina virtual KVM (con el apropiado nombre de Matrioska). La cual, por muy loco que esté uno, ya se ejecuta sobre hardware físico.

Las características del contenedor son las siguientes:

Contenedor LXD Letsencrypt
Núcleos:

2

La máquina física utiliza Intel(R) Xeon(R) CPU E3-1240 v3 @ 3.40GHz.

RAM: 2 GB
SO: Ubuntu 16.04 LTS
Apache: Apache2 (2.4.18-2ubuntu3.5) (mpm-event)
Kernel: Linux 4.4.0-104-generic

En condiciones normales suficiente para cumplir con su función la mar de bien.

Sobre el ataque

El primer síntoma que se detecta es el bajo rendimiento al acceder a nuestros servicios web e incluso, de manera puntual, su no disponibilidad.

El fichero de registro de Apache (/var/log/error.log) muestra los problemas:

[Mon Jan 08 12:21:19.310455 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:21:20.311533 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:21:21.312605 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:21:22.313201 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:21:23.314258 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:21:24.315319 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:21:25.316418 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:21:26.317511 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:21:50.342261 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:21:51.343344 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:21:52.344416 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:21:53.345191 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:21:54.346248 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:21:55.347312 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:21:56.348397 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:21:57.349461 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:21:58.350566 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:21:59.351638 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:22:00.352742 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:22:01.353813 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:22:03.356700 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:22:04.357808 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:22:05.358881 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:22:06.359949 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:22:07.361208 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:22:08.362278 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:22:09.363377 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:22:10.364500 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:22:11.365576 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:22:12.366957 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:22:13.368031 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:22:14.369144 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:22:15.370252 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:22:16.371339 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:22:17.372660 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:22:18.373775 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:22:19.374878 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:22:20.375965 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:22:21.377063 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:22:22.378417 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers
[Mon Jan 08 12:22:23.379501 2018] [mpm_event:error] [pid 396:tid 140667322115968] AH00485: scoreboard is full, not at MaxRequestWorkers

Y al día siguiente, cuando los problemas vuelven a suceder y reinicio Apache, se puede comprobar cómo al arrancar inmediatamente vuelve a sufrir el ataque:

[Tue Jan 09 12:11:09.836330 2018] [mpm_event:notice] [pid 16043:tid 140175127529344] AH00491: caught SIGTERM, shutting down
[Tue Jan 09 12:11:15.566788 2018] [mpm_event:notice] [pid 16169:tid 139948376389504] AH00489: Apache/2.4.18 (Ubuntu) OpenSSL/1.0.2g configured -- resuming normal operations
[Tue Jan 09 12:11:15.566807 2018] [core:notice] [pid 16169:tid 139948376389504] AH00094: Command line: '/usr/sbin/apache2'
[Tue Jan 09 12:13:18.688886 2018] [mpm_event:error] [pid 16169:tid 139948376389504] AH00484: server reached MaxRequestWorkers setting, consider raising the MaxRequestWorkers setting
[Tue Jan 09 12:13:47.717852 2018] [mpm_event:error] [pid 16169:tid 139948376389504] AH00485: scoreboard is full, not at MaxRequestWorkers
[Tue Jan 09 12:13:48.718970 2018] [mpm_event:error] [pid 16169:tid 139948376389504] AH00485: scoreboard is full, not at MaxRequestWorkers
[Tue Jan 09 12:13:49.720058 2018] [mpm_event:error] [pid 16169:tid 139948376389504] AH00485: scoreboard is full, not at MaxRequestWorkers
[Tue Jan 09 12:13:50.721169 2018] [mpm_event:error] [pid 16169:tid 139948376389504] AH00485: scoreboard is full, not at MaxRequestWorkers
[Tue Jan 09 12:13:51.722247 2018] [mpm_event:error] [pid 16169:tid 139948376389504] AH00485: scoreboard is full, not at MaxRequestWorkers
[Tue Jan 09 12:13:52.722905 2018] [mpm_event:error] [pid 16169:tid 139948376389504] AH00485: scoreboard is full, not at MaxRequestWorkers
[Tue Jan 09 12:13:53.723993 2018] [mpm_event:error] [pid 16169:tid 139948376389504] AH00485: scoreboard is full, not at MaxRequestWorkers
[Tue Jan 09 12:13:54.725358 2018] [mpm_event:error] [pid 16169:tid 139948376389504] AH00485: scoreboard is full, not at MaxRequestWorkers

¿Por qué? ¿quién está molestando a nuestro pobre Apache? Un vistazo rápido a las conexiones con netstat nos lo desvela:

tcp6       0      0 192.168.0.5:443         207.46.13.177:14369     TIME_WAIT   -               
tcp6       0      0 192.168.0.5:80          185.93.3.108:53245      ESTABLISHED -              
tcp6       0      0 192.168.0.5:80          185.93.3.108:57958      SYN_RECV    -              
tcp6       0      0 192.168.0.5:80          185.93.3.108:53249      ESTABLISHED -              
tcp6       0      0 192.168.0.5:80          185.93.3.108:53214      ESTABLISHED -              
tcp6       0    481 192.168.0.5:80          185.93.3.108:53060      FIN_WAIT1   -              
tcp6       0      0 192.168.0.5:80          185.93.3.108:57921      SYN_RECV    -              
tcp6       0      0 192.168.0.5:80          185.93.3.108:57887      SYN_RECV    -              
tcp6       0    481 192.168.0.5:80          185.93.3.108:53124      FIN_WAIT1   -              
tcp6       0      0 192.168.0.5:80          192.168.0.10:52084      ESTABLISHED -              
tcp6       0    481 192.168.0.5:80          185.93.3.108:53083      FIN_WAIT1   -              
tcp6       0      0 192.168.0.5:80          192.168.0.10:34932      TIME_WAIT   -              
tcp6       0    481 192.168.0.5:80          185.93.3.108:53114      FIN_WAIT1   -              
tcp6       0    481 192.168.0.5:80          185.93.3.108:53017      FIN_WAIT1   -              
tcp6       0    481 192.168.0.5:80          185.93.3.108:53063      FIN_WAIT1   -              
tcp6       0    481 192.168.0.5:80          185.93.3.108:53013      FIN_WAIT1   -              
tcp6       0      0 192.168.0.5:80          185.93.3.108:53272      ESTABLISHED -              
tcp6       0      0 192.168.0.5:443         203.77.230.114:47609    TIME_WAIT   -              
tcp6       0      0 192.168.0.5:80          185.93.3.108:53222      ESTABLISHED -              
tcp6       0      0 192.168.0.5:80          185.93.3.108:53277      ESTABLISHED -              
tcp6       0      0 192.168.0.5:80          192.168.0.10:38940      TIME_WAIT   -              
tcp6       0     32 192.168.0.5:443         79.144.0.195:53500      LAST_ACK    -              
tcp6       0      0 192.168.0.5:80          185.93.3.108:53273      ESTABLISHED -              
tcp6       0      0 192.168.0.5:80          185.93.3.108:53268      ESTABLISHED -              
tcp6       0   1010 192.168.0.5:80          46.229.168.74:32016     LAST_ACK    -              
tcp6       0      0 192.168.0.5:80          185.93.3.108:57750      SYN_RECV    -              
tcp6       0      0 192.168.0.5:80          185.93.3.108:53260      ESTABLISHED -              
tcp6       0      0 192.168.0.5:80          185.93.3.108:53205      ESTABLISHED -              
tcp6       0      0 192.168.0.5:80          185.93.3.108:53263      ESTABLISHED -              
tcp6       0    481 192.168.0.5:80          185.93.3.108:53121      FIN_WAIT1   -              
tcp6       0      0 192.168.0.5:80          192.168.0.10:39052      TIME_WAIT   -              
tcp6       0    481 192.168.0.5:80          185.93.3.108:53058      FIN_WAIT1   -              
tcp6       0      0 192.168.0.5:80          185.93.3.108:53276      ESTABLISHED -              
tcp6       0      0 192.168.0.5:80          185.93.3.108:53176      ESTABLISHED -              
tcp6       0      0 192.168.0.5:80          185.93.3.108:53254      ESTABLISHED -              
tcp6       0      0 192.168.0.5:80          192.168.0.10:53400      ESTABLISHED -              
tcp6       0    481 192.168.0.5:80          185.93.3.108:53042      FIN_WAIT1   -              
tcp6       0    481 192.168.0.5:80          185.93.3.108:53031      FIN_WAIT1   - 

Respuesta:

La máquina 185.93.3.108 abre todas las conexiones que puede con nuestro servidor. De acuerdo, nuestras páginas son interesantes, pero con pedirlas una vez (de tanto en tanto) es suficiente ¿verdad?

No tiene sentido aumentar el valor de MaxRequestWorkers en la configuración de Apache porque, ante tal avalancha, nunca serán suficientes.

Así que lo que toca es rechazar el tráfico desde la dirección del atacante:

iptables -A INPUT -s 185.93.3.108 -j DROP

Para descubrir que desde 185.93.3.107 también nos están molestando:

tcp6       0      0 192.168.0.5:80          185.93.3.107:53652      ESTABLISHED -               
tcp6       0      0 192.168.0.5:80          185.93.3.107:53669      ESTABLISHED -              
tcp6       0      0 192.168.0.5:80          185.93.3.107:53770      ESTABLISHED -              
tcp6       0      0 192.168.0.5:80          185.93.3.107:53723      ESTABLISHED -              
tcp6       0      0 192.168.0.5:80          185.93.3.107:57607      SYN_RECV    -              
tcp6       0      0 192.168.0.5:80          185.93.3.107:53646      ESTABLISHED -              
tcp6       0      0 192.168.0.5:80          185.93.3.107:57158      SYN_RECV    -              
tcp6       0      0 192.168.0.5:80          185.93.3.107:53804      ESTABLISHED -              
tcp6       0      0 192.168.0.5:80          185.93.3.107:53666      ESTABLISHED -              
tcp6       0      0 192.168.0.5:80          185.93.3.107:53800      ESTABLISHED -              
tcp6      62      0 192.168.0.5:80          185.93.3.107:53938      ESTABLISHED -              
tcp6       0      0 192.168.0.5:80          185.93.3.107:53805      ESTABLISHED -              
tcp6       0      0 192.168.0.5:80          185.93.3.107:57588      SYN_RECV    -              
tcp6       0      0 192.168.0.5:80          185.93.3.107:53802      ESTABLISHED -              
tcp6      62      0 192.168.0.5:80          185.93.3.107:53846      ESTABLISHED -              
tcp6       0      0 192.168.0.5:80          185.93.3.107:53830      ESTABLISHED -              
tcp6       0      0 192.168.0.5:80          185.93.3.107:57685      SYN_RECV    -              
tcp6      62      0 192.168.0.5:80          185.93.3.107:53897      ESTABLISHED -              
tcp6      62      0 192.168.0.5:80          185.93.3.107:53880      ESTABLISHED -              
tcp6       0      0 192.168.0.5:80          185.93.3.107:53725      ESTABLISHED -   

Y aquí es donde a un servidor se le acaba la paciencia y bloquea de manera indiscrimindada 185.93.0.0/16. Desde entonces todo va como la seda y la regla del cortafuegos se ha aplicado 68746 veces.

root@letsencrypt:~# iptables -L -v -n
Chain INPUT (policy ACCEPT 70M packets, 202G bytes)
 pkts bytes target     prot opt in     out     source               destination         
68746 3495K DROP       all  --  *      *       185.93.0.0/16        0.0.0.0/0           

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 47M packets, 200G bytes)
 pkts bytes target     prot opt in     out     source               destination         
root@letsencrypt:~#

 

Epílogo

Poco después de aplicar el bloqueo deja de aumentar el contador de paquetes recibidos. Es decir, el atacante se aburre y deja de molestar.

En este caso hemos padecido un ataque de poca monta, pero también es cierto que nuestra infraestructura tampoco es muy resistente y que en Internet se han registrado ataques DDoS grandísimos contra los que cuesta mucho luchar. Para mitigar estos ataques hay toda una industria montada, por ejemplo, Cloudflare o Akamai son empresas que ofrecen una Content Delivery Network (CDN). Por ejemplo, Cloudflare tiene una página en la que para ilustrar las bondades de su servicio se precia de haber mitigado los atáques de mayor volumen.

El bloqueo de la subred 185.93.0.0/16 es indiscriminado y, una vez que el ataque cesa, conviene levantarlo. Pero demuestra lo efectivo que pueden ser los cortafuegos.

Sin embargo el propio servidor Apache cuenta con el módulo mod_evasive que permite mitigar de manera automática ciertos tipos de ataques.