Una historia desagradable le sucedió a uno de mis amigos. Pero por lo que resultó ser desagradable para Mikhail, fue igual de entretenido para mí.
Debo decir que mi amigo es un gran usuario de
UNIX : puede instalar el sistema él mismo, instalar
mysql ,
php y hacer la configuración
nginx más simple.
Y tiene una docena y media de sitios dedicados a herramientas de construcción.
Uno de estos sitios, dedicado a las motosierras, se encuentra firmemente en los motores de búsqueda TOP. Este sitio es un revisor sin fines de lucro, pero alguien se cruzó en su garganta y lo atacó. O
DDoS , luego la fuerza bruta, luego los comentarios escribirán obscenos y enviarán abusos al host y al ILV.
De repente, todo se calmó y esta pausa no fue buena, y el sitio comenzó a dejar gradualmente las primeras líneas de los resultados.

Ese era un dicho, luego la bicicleta de administración en sí.
Se acercaba la hora de dormir cuando sonó el teléfono: “Sanya, ¿no mirarás mi servidor? Me parece que me piratearon, no puedo probarlo, pero la sensación no se ha ido la tercera semana. ¿Tal vez solo tengo que ser tratado por paranoia?
Luego vino una discusión de media hora que se puede resumir de la siguiente manera:
- el caldo de cultivo era bastante fértil;
- el cracker podría obtener derechos de superusuario;
- el ataque (si tuvo lugar) fue dirigido específicamente a este sitio;
- las áreas problemáticas están solucionadas y solo necesita comprender si hubo un hecho de penetración;
- la piratería no pudo tocar el código del sitio y las bases de datos.
Sobre el último párrafo.

Solo la interfaz de IP blanca está mirando hacia el mundo. No hay intercambio entre backends y frontend, excepto http (s), los usuarios / contraseñas son diferentes, las claves no se intercambian. En direcciones grises, todos los puertos excepto 80/443 están cerrados. Los backends IP blancos son conocidos solo por dos usuarios en quienes Michael confía plenamente.
Debian 9 está instalado en el front-end y en el momento de la llamada, el sistema está aislado del mundo por un firewall externo y se detiene.
"Ok, dame acceso", decido posponer el sueño por una hora. "Veré con mis propios ojos".
De aquí en adelante:
$ grep -F PRETTY_NAME /etc/*releas* PRETTY_NAME="Debian GNU/Linux 9 (stretch)" $ `echo $SHELL` --version GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu) $ nginx -v nginx version: nginx/1.10.3 $ gdb --version GNU gdb (Debian 8.2.1-2) 8.2.1
En busca de un posible hack
Inicio el servidor, primero en
modo rescate . Monto discos,
hojeo registros,
historial , registros del sistema, etc., si es posible, verifico las fechas de creación del archivo, aunque entiendo que una galleta normal "sudaría" detrás de él, y Misha ya "pisoteó" a sabiendas mientras se buscaba.
Comienzo en modo normal, especialmente aún sin saber qué buscar, estoy estudiando configuraciones. Está principalmente interesado en
nginx ya que, en general, no hay nada más que él en la interfaz.
Las configuraciones son pequeñas, bien estructuradas en una docena de archivos; solo las reviso por
cat ' a su vez. Todo parece estar limpio, pero nunca te perdiste algunos
incluyen , haré una lista completa:
$ nginx -T nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful
No entendí: "¿Dónde está el listado?"
$ nginx -V nginx version: nginx/1.10.3 TLS SNI support enabled configure arguments: --with-cc-opt='-g -O2' --with-ld-opt='-Wl,-z,relro -Wl,-z,now' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-ipv6 --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_sub_module --with-stream=dynamic --with-stream_ssl_module --with-mail=dynamic --with-mail_ssl_module
El segundo se agrega a la pregunta de la lista: "¿Por qué una versión tan antigua de nginx?"
Además, el sistema cree que la versión se instala fresca:
$ dpkg -l nginx | grep "[n]ginx" ii nginx 1.14.2-2+deb10u1 all small, powerful, scalable web/proxy server
Estoy llamando:
- Misha, ¿por qué estás reconstruyendo
nginx ?
- Ok, ¡ni siquiera sé cómo hacerlo!
- Ok, bueno, duerme ...
Nginx es reensamblado sin ambigüedades y la lista de listados para "-T" está oculta por alguna razón. No hay duda acerca de la piratería y puedes aceptarlo y (dado que Misha reemplazó el servidor por uno nuevo de todos modos), considera el problema resuelto.
Y de hecho, dado que alguien obtuvo
privilegios de root , tiene sentido hacer solo la
reinstalación del sistema y buscar lo que se usó mal allí, pero esta vez la curiosidad derrotó el sueño. ¿Cómo averiguar qué querían escondernos?
Intentemos rastrear:
$ strace nginx -T
Miramos a través del rastro claramente no hay suficientes líneas a la
write(1, "/etc/nginx/nginx.conf", 21/etc/nginx/nginx.conf) = 21 write(1, "... write(1, "\n", 1
Por diversión, compara las conclusiones
$ strace nginx -T 2>&1 | wc -l 264 $ strace nginx -t 2>&1 | wc -l 264
Creo que parte del código
/src/core/nginx.c case 't': ngx_test_config = 1; break; case 'T': ngx_test_config = 1; ngx_dump_config = 1; break;
se redujo a la forma:
case 't': ngx_test_config = 1; break; case 'T': ngx_test_config = 1;
o
case 't': ngx_test_config = 1; break; case 'T': ngx_test_config = 1; ngx_dump_config = 0; break;
por lo tanto, no se muestra el listado por -T.
¿Pero cómo ver nuestra configuración?
Si mi idea es correcta y el problema está solo en la variable
ngx_dump_config, intentaremos instalarlo usando
gdb , ya que la clave
--with-cc-opt -g está presente y esperamos que la optimización
-O2 no nos perjudique. Al mismo tiempo, dado que no sé cómo se podría procesar
ngx_dump_config en el
caso 'T' : , no llamaremos a este bloque, sino que lo instalaremos usando el
caso 't':¿Por qué puedo usar '-t' junto con '-T'?El procesamiento del bloque
if (ngx_dump_config) ocurre dentro de
if (ngx_test_config) :
if (ngx_test_config) { if (!ngx_quiet_mode) { ngx_log_stderr(0, "configuration file %s test is successful", cycle->conf_file.data); } if (ngx_dump_config) { cd = cycle->config_dump.elts; for (i = 0; i < cycle->config_dump.nelts; i++) { ngx_write_stdout("# configuration file "); (void) ngx_write_fd(ngx_stdout, cd[i].name.data, cd[i].name.len); ngx_write_stdout(":" NGX_LINEFEED); b = cd[i].buffer; (void) ngx_write_fd(ngx_stdout, b->pos, b->last - b->pos); ngx_write_stdout(NGX_LINEFEED); } } return 0; }
Por supuesto, si el código se cambia en esta parte, y no en el
caso 'T' :, entonces mi método no funcionará.
Prueba nginx.confUna vez resuelto el problema empíricamente, se descubrió que para el funcionamiento del malware se necesita una configuración mínima
nginx del formulario:
events { } http { include /etc/nginx/sites-enabled/*; }
Lo usaremos por brevedad en el artículo.
Ejecute el depurador $ gdb --silent --args nginx -t Reading symbols from nginx...done. (gdb) break main Breakpoint 1 at 0x1f390: file src/core/nginx.c, line 188. (gdb) run Starting program: nginx -t [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". Breakpoint 1, main (argc=2, argv=0x7fffffffebc8) at src/core/nginx.c:188 188 src/core/nginx.c: No such file or directory. (gdb) print ngx_dump_config=1 $1 = 1 (gdb) continue Continuing. nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful # configuration file /etc/nginx/nginx.conf: events { } http { map $http_user_agent $sign_user_agent { "~*yandex.com/bots" 1; "~*www.google.com/bot.html" 1; default 0; } map $uri $sign_uri { "~*/wp-" 1; default 0; } map :$sign_user_agent:$sign_uri $sign_o { :1:0 o; default ; } map :$sign_user_agent:$sign_uri $sign_a { :1:0 a; default ; } sub_filter_once off; sub_filter '' $sign_o; sub_filter '' $sign_a; include /etc/nginx/sites-enabled/*; } # configuration file /etc/nginx/sites-enabled/default: [Inferior 1 (process 32581) exited normally] (gdb) quit
Los pasos:
- establecer un punto de interrupción en la función main ()
- ejecuta el programa
- cambiar el valor de la variable que define la salida de la configuración ngx_dump_config = 1
- continuar / finalizar el programa
Como puede ver, la configuración real es diferente de la nuestra, seleccionamos una pieza espuria de ella:
map $http_user_agent $sign_user_agent { "~*yandex.com/bots" 1; "~*www.google.com/bot.html" 1; default 0; } map $uri $sign_uri { "~*/wp-" 1; default 0; } map :$sign_user_agent:$sign_uri $sign_o { :1:0 o; default ; } map :$sign_user_agent:$sign_uri $sign_a { :1:0 a; default ; } sub_filter_once off; sub_filter '' $sign_o; sub_filter '' $sign_a;
Consideremos en orden lo que está sucediendo aquí.
Definido por
el agente de usuario yandex / google:
map $http_user_agent $sign_user_agent { "~*yandex.com/bots" 1; "~*www.google.com/bot.html" 1; default 0; }
Se
excluyen las páginas de servicio de Wordpress:
map $uri $sign_uri { "~*/wp-" 1; default 0; }
Y para aquellos que caen bajo las dos condiciones anteriores
map :$sign_user_agent:$sign_uri $sign_o { :1:0 o; default ; } map :$sign_user_agent:$sign_uri $sign_a { :1:0 a; default ; }
en el texto de la página
html , cambia
'o' a
'o' y
'a' a
'a' :
sub_filter_once off; sub_filter '' $sign_o; sub_filter '' $sign_a;
Exactamente, la sutileza es que
'a'! = 'A' es lo mismo que
'o'! = 'O' :

Por lo tanto, los robots de los motores de búsqueda reciben, en lugar del texto 100% cirílico normal, basura modificada diluida con el latín
'a' y
'o' . No pretendo discutir cómo esto afecta el SEO, pero es poco probable que un hash tan literal afecte positivamente las posiciones en el SERP.
Lo que dicen chicos con fantasía.
Referencias
Depuración con GDBgdb (1) - página de manual de Linuxstrace (1) - página de manual de LinuxNginx - Módulo ngx_http_sub_moduleSobre sierras, motosierras y sierras eléctricas