Околу една ранливост во...

Околу една ранливост во...

Пред една година, 21 март 2019 година, во програма за баунтирање грешки Mail.Ru многу добар дојде до HackerOne извештај за грешка од максар. Кога се воведува нулта бајт (ASCII 0) во параметарот POST на едно од барањата за API на веб-пошта што враќа HTTP пренасочување, делови од неиницијализирана меморија биле видливи во податоците за пренасочување, во кои фрагменти од GET параметри и заглавија на други барања до истиот сервер.

Ова е критична ранливост бидејќи ... барањата содржат и колачиња за сесија. Неколку часа подоцна, беше направена привремена поправка што го филтрира нула бајт (како што се покажа подоцна, ова не беше доволно, бидејќи сè уште постоеше можност за инјектирање CRLF / ASCII 13, 10, што ви овозможува да манипулирате со заглавијата и податоци за одговорот на HTTP, ова е помалку критично, но сепак непријатно). Во исто време, проблемот беше префрлен на безбедносните аналитичари и програмери за да ги пронајдат и елиминираат причините за грешката.

Поштата на Mail.ru е многу сложена апликација голем број на различни предни/задни компоненти, како со отворен код (голема благодарност до сите развивачи на слободен софтвер) така и внатре развиени, можат да бидат вклучени во генерирањето на одговорот. Успеавме да ги исклучиме сите компоненти освен nginx и openresty и да го локализираме проблемот пред да се јавиме ngx.req.set_uri() во скрипта OpenResty што не се однесуваше како што се очекуваше (вметнување нула бајт или линија преку параметрите GET со rewrite во ngx_http_rewrite_module, која, според документацијата, се користи и, се чини, треба да работи на ист начин, ќе не работи). Можните последици беа елиминирани, филтрирањето беше додадено што е можно построго, а филтрирањето беше потврдено за да се елиминираат сите можни вектори. Но, механизмот што доведе до протекување на содржината на меморијата остана мистерија. Еден месец подоцна, извештајот за грешка беше затворен како решен, а анализата на причините за бубачката беше одложена за подобри времиња.

OpenResty е многу популарен приклучок кој ви овозможува да пишувате Lua скрипти во nginx, а се користи во неколку проекти на Mail.ru, така што проблемот не се сметаше за решен. И по некое време, тие конечно се вратија на него за да ги разберат вистинските причини, можните последици и да дадат препораки за програмерите. Учествувал во ископувањето на изворниот код Денис Денисов и Николај Ермишкин. Се покажа дека:

  • Во nginx, кога се користи препишување со кориснички податоци, постои можност за преминување директориуми (и веројатно SSRF) во некои конфигурации, но ова е познат факт и треба да се открие со статички конфигурациски анализатори во Nginx Amplify и Ixикси од Yandex (да, го користиме и тоа, благодарам). Кога користите OpenResty, оваа функција лесно се пропушта, но тоа не влијаеше на нашата конфигурација.

    пример за конфигурација:

    location ~ /rewrite {
        rewrite ^.*$ $arg_x;
    }
    
    location / {
        root html;
        index index.html index.htm;
    }

    резултат

    curl localhost:8337/rewrite?x=/../../../../../../../etc/passwd
    root:x:0:0:root:/root:/bin/bash
    daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
    bin:x:2:2:bin:/bin:/usr/sbin/nologin
    ...

  • Nginx има грешка што предизвикува протекување на меморијата ако линијата за препишување содржи нула бајт. Кога се издава пренасочување, nginx доделува нов мемориски бафер што одговара на целата должина на линијата, но ја копира линијата таму преку функцијата на линијата во која нултиот бајт е терминатор на линија, така што линијата се копира само до нула бајт; остатокот од баферот содржи неиницијализирани податоци. Може да се најде детална анализа тука.

    пример за конфигурација (^@ нула бајт)

    
    location ~ /memleak {
        rewrite ^.*$ "^@asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdasdf";
    }
    
    location / {
        root html;
        index index.html index.htm;
    }

    резултат
    curl localhost:8337/secret -vv
    ...
    curl localhost:8337/memleak -vv
    ...
    Location: http://localhost:8337/secret
    ...

  • Nginx ги штити GET параметрите од вбризгување на услужни знаци и овозможува користење само GET параметри при препишување. Затоа, не е можно да се искористи инјекцијата преку параметри контролирани од корисникот во nginx. Параметрите на POST не се заштитени. OpenResty ви овозможува да работите и со параметрите GET и POST, така што кога користите POST параметри преку OpenResty, станува возможно да се инјектираат специјални знаци.

    пример за конфигурација:

    location ~ /memleak {
        rewrite_by_lua_block {
            ngx.req.read_body();
            local args, err = ngx.req.get_post_args();
            ngx.req.set_uri( args["url"], true );
        }
    }
    
    location / {
        root html;
        index index.html index.htm;
    }
    

    резултат:

    curl localhost:8337 -d "url=secret" -vv
    ...
    curl localhost:8337 -d "url=%00asdfasdfasdfasdfasdfasdfasdfasdf" -vv
    ...
    Location: http://localhost:8337/{...может содержать secret...}
    ...

Понатамошна реакција

Проблемот беше пријавен кај развивачите на nginx и OpenResty, програмерите не го сметаат проблемот како безбедносен баг во nginx, бидејќи во самиот nginx не постои начин да се искористи грешката преку вбризгување специјални знаци, поправете откривање меморија беше објавено на 16 декември. Во 4-те месеци од извештајот, не се направени никакви промени на OpenResty, иако беше разбрано дека е потребна безбедна верзија на функцијата ngx.req.set_uri(). На 18 март 2020 година објавивме информации, на 21 март беше објавен OpenResty верзија 1.15.8.3, кој додава валидација на URI.

Портсвигер пишува добра статија и зедов коментари од OpenResty и Nginx (иако коментарот дека е изложен само мал фрагмент од меморијата е неточен и погрешен, ова се одредува според должината на линијата што следи по нула бајт и, во отсуство на експлицитни ограничувања на должина, може да биде контролирана од напаѓачот).

Значи, што беше грешката и што може да се направи за да се спречи?

Дали имаше грешка во nginx? Да, тоа беше, бидејќи протекувањето на содржината на меморијата е грешка во секој случај.

Дали имаше грешка во OpenResty? Да, барем прашањето за безбедноста на функционалноста што ја нуди OpenResty не е истражено и документирано.

Дали имаше грешка во конфигурацијата/користењето со OpenResty? Да, бидејќи во отсуство на експлицитна изјава, беше направена непроверена претпоставка за безбедноста на функционалноста што се користи.

Која од овие грешки е безбедносна ранливост со награда од 10000 долари? За нас тоа генерално не е важно. Во секој софтвер, особено на пресекот на неколку компоненти, особено оние обезбедени од различни проекти и развивачи, никој никогаш не може да гарантира дека сите карактеристики на нивната работа се познати и документирани и дека нема грешки. Затоа, секоја безбедносна ранливост се јавува токму онаму каде што влијае на безбедноста.

Во секој случај, добра практика е да се нормализираат или ограничат/филтрираат колку што е можно повеќе влезните податоци што влегуваат во кој било надворешен модул/API, освен ако нема експлицитни упатства и јасно разбирање дека тоа не е потребно.

Ерата

Од искуство претходната статија, заради зачувување на чистотата на јазикот:

награда за бубачки — натпревар во лов на бубачки
извештај за грешка - известување за грешка
пренасочување - пренасочување
отворен извор - отворен извор
погрешно - работи на грешки

Извор: www.habr.com