Cuando 'a' no es igual a 'a'. A raíz de un truco

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.

imagen

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.

imagen

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; //ngx_dump_config = 1; break; 

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.conf
Una 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' :

imagen

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 GDB
gdb (1) - página de manual de Linux
strace (1) - página de manual de Linux
Nginx - Módulo ngx_http_sub_module
Sobre sierras, motosierras y sierras eléctricas

Source: https://habr.com/ru/post/465355/


All Articles