När 'a' inte är lika med 'a'. I spåren av ett hack

En mycket obehaglig historia hände en av mina vänner. Men lika obehagligt som det visade sig vara för Mikhail så var det lika underhållande för mig.

Jag måste säga att min vän är ganska UNIX-användare: kan installera systemet själv mysql, php och gör enkla inställningar nginx.
Och han har ett dussin eller en och en halv webbplatser dedikerade till byggverktyg.

En av dessa webbplatser dedikerade till motorsågar sitter stadigt i toppen av sökmotorerna. Den här webbplatsen är en icke-kommersiell recensent, men någon fick för vana att attackera den. Den där DDoS, sedan brute force, sedan skriver de obscena kommentarer och skickar övergrepp till värdskapet och till RKN.
Plötsligt lugnade allt ner sig och det här lugnet visade sig inte vara bra, och sajten började gradvis lämna de översta linjerna i sökresultaten.

När 'a' inte är lika med 'a'. I spåren av ett hack

Det var ett talesätt, sedan själva administratörens berättelse.

Det närmade sig läggdags när telefonen ringde: "San, vill du inte titta på min server? Det verkar för mig att jag blev hackad, jag kan inte bevisa det, men känslan har inte lämnat mig för tredje veckan. Kanske är det bara dags för mig att få behandling för paranoia?”

Det som följde var en halvtimmes diskussion som kan sammanfattas så här:

  • jorden för hackning var ganska bördig;
  • en angripare kan få superanvändarrättigheter;
  • attacken (om den ägde rum) riktades specifikt mot denna plats;
  • problemområden har korrigerats och du behöver bara förstå om det fanns någon penetration;
  • hacket kunde inte påverka webbplatsens kod och databaser.

Angående den sista punkten.

När 'a' inte är lika med 'a'. I spåren av ett hack

Endast den vita frontend-IP:en ser ut i världen. Det finns inget utbyte mellan backends och frontend förutom http(s), användarna/lösenorden är olika, inga nycklar utbyttes. På grå adresser är alla portar utom 80/443 stängda. Vita backend-IP:er är bara kända för två användare, som Mikhail helt litar på.

Installerad på fronten Debian 9 och när samtalet görs är systemet isolerat från världen av en extern brandvägg och stoppat.

"Ok, ge mig tillgång," jag bestämmer mig för att skjuta upp sömnen i en timme. "Jag ska se med mina egna ögon."

Här och vidare:

$ 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

Letar efter ett möjligt hack

Jag startar servern, först in räddningsläge. Jag monterar skivorna och bläddrar igenom dem autent-loggar, historia, systemloggar etc., om möjligt, kontrollerar jag datumen för filskapandet, även om jag förstår att en vanlig cracker skulle ha "sopat upp" efter sig själv, och Misha hade redan "trampat ner" mycket medan han letade efter sig själv .

Jag börjar i normalt läge, förstår ännu inte riktigt vad jag ska leta efter, jag studerar konfigurationerna. Först och främst är jag intresserad av nginx eftersom det i allmänhet inte finns något annat på frontend förutom det.
Konfigurationerna är små, välstrukturerade i ett dussin filer, jag tittar bara igenom dem katt'åh en efter en. Allt verkar vara rent, men man vet aldrig om jag har missat något innefattar, låt mig göra en fullständig lista:

$ 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

Jag förstod inte: "Var är listan?"

$ 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

En andra fråga läggs till listningsfrågan: "Varför en sådan uråldrig version av nginx?"

Dessutom tror systemet att den senaste versionen är installerad:

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

Jag ringer:
- Misha, varför satte du ihop dig igen nginx?
- Vänta, jag vet inte ens hur man gör det här!
- Okej, gå och sova...

nginx det är tydligt ombyggt och utdata från listningen med "-T" är dold av en anledning. Det finns inte längre några tvivel om hacking och du kan helt enkelt acceptera det och (eftersom Misha ändå ersatte servern med en ny) anser att problemet är löst.

Och faktiskt, eftersom någon fick rättigheterna rot'ah, då är det bara vettigt att göra installera om systemet, och det var värdelöst att leta efter vad som var fel där, men den här gången besegrade nyfikenheten sömnen. Hur kan vi ta reda på vad de ville dölja för oss?

Låt oss försöka spåra:

$ strace nginx -T

Vi tittar på det, det finns tydligen inte tillräckligt med linjer i spåret a la

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

Bara för skojs skull, låt oss jämföra resultaten.

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

Jag tror en del av koden /src/core/nginx.c

            case 't':
                ngx_test_config = 1;
                break;

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

fördes till formen:

            case 't':
                ngx_test_config = 1;
                break;

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

eller

            case 't':
                ngx_test_config = 1;
                break;

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

därför visas inte listan med "-T".

Men hur kan vi se vår konfiguration?

Om min tanke är korrekt och problemet bara finns i variabeln ngx_dump_config låt oss försöka installera det med hjälp av gdb, lyckligtvis finns det en nyckel --med-cc-opt -g närvarande och hoppas att optimering -O2 det kommer inte att skada oss. Samtidigt, eftersom jag inte vet hur ngx_dump_config kunde bearbetas i fall 'T':, kommer vi inte att kalla detta block, utan installera det med hjälp av fall 't':

Varför du kan använda "-t" såväl som "-T"Blockbearbetning if(ngx_dump_config) händer inuti 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;
    }

Naturligtvis, om koden ändras i denna del och inte i fall 'T':, då fungerar inte min metod.

Testa nginx.confEfter att redan ha löst problemet experimentellt fastställdes det att en minimikonfiguration krävs för att skadlig programvara ska fungera nginx typ:

events {
}

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

Vi kommer att använda det för korthet i artikeln.

Starta felsökaren

$ 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

Steg för steg:

  • ställ in en brytpunkt i funktionen main ()
  • starta programmet
  • ändra värdet på variabeln som bestämmer utdata från konfigurationen ngx_dump_config=1
  • fortsätta/avsluta programmet

Som vi kan se skiljer sig den verkliga konfigurationen från vår, vi väljer en parasitisk del från den:

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;

Låt oss ta en titt på vad som händer här i ordning.

Fast besluten User-Agents yandex/google:

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

Servicesidor är exkluderade wordpress:

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

Och för dem som faller under båda ovanstående villkor

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

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

i texten HTML-sidor ändras 'O''O' и 'A''a':

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

Det stämmer, den enda subtiliteten är det 'a' != 'a' såväl som 'o' != 'o':

När 'a' inte är lika med 'a'. I spåren av ett hack

Således får sökmotorrobotar, istället för normal 100 % kyrillisk text, modifierat skräp utspätt med latin 'a' и 'O'. Jag vågar inte diskutera hur detta påverkar SEO, men det är osannolikt att ett sådant virrvarr av bokstäver kommer att ha en positiv inverkan på positionerna i sökresultaten.

Vad kan jag säga, killar med fantasi.

referenser

Felsökning med GDB
gdb(1) — Linuxmanpage
strace(1) — Linuxmanpage
Nginx - Modul ngx_http_sub_module
Om sågar, motorsågar och elsågar

Källa: will.com

Lägg en kommentar