¡El 2018 ha comenzado con un ataque a nuestros servidores!
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.
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.