LINUX.ORG.RU

поиск уязвимостей в e2e шифровании поверх Matrix

 , , ,


0

2

Я обнаружил странности в коде bastyon-chat, который интегрирует клиент Element и использует своё шифрование.

В src/application/pcrypto.js (ссылка) я обратил внимание на:

var salt = "PR7srzZt4EfcNb3s27grgmiG8aB9vYNV82";

Главная странность в этой функции (поправил форматирование для вставки):

var eaac = {
    aeskeysls: function (time, block, users, v) {
        if (!time) time = 0;
        if (!block) {
            if (!pcrypto.core.mtrx.kit.tetatetchat(chat)) {
                block = 10;
            } else {
                block = pcrypto.currentblock.height;
            }
        }
        var k = ((users ? 'ul+' + orderedIdsHash(users) : period(time)) + "-" + block) + '-' + (v || self.version);
        var ek = `${lcachekey + pcrypto.user.userinfo.id}-${k}`
        if (!lsspromises[ek]) {
            lsspromises[ek] = ls.get(ek)
                .then((keys) => {
                    const keysPrepared = convert.aeskeys.out(keys);
                    return { keys: keysPrepared, k };
                })
                .catch(async (e) => {
                    const keysPrepared = eaac.aeskeys(time, block, users, v);
                    if (self.preparedUsers(time).length > 1) {
                        const itemId = ek;
                        await ls
                            .set(itemId, convert.aeskeys.inp(keysPrepared))
                            .catch(() => { });
                    }
                    return { keys: keysPrepared, k };
                }).finally(() => {
                    delete lsspromises[ek]
                });
        }
        return lsspromises[ek]
    },
    aeskeys: function (time, block, users, v) {
        if (!time) time = 0;
        if (!block) block = pcrypto.currentblock.height;
        return eaa.aeskeys(time, block, users, v);
    },
};

И вызове этой функции в разных участках кода:

let { keys } = await eaac.aeskeysls(undefined, undefined, undefined, version || undefined);

В любом случае, это известные значения. Я не уверен только насчёт того, откуда берётся version в некоторых местах:

v = f.deep(event, "content.info.secrets.version") || f.deep(event, "content.info.secrets.v") ||
				f.deep(event, "content.pbody.secrets.version") || f.deep(event, "content.pbody.secrets.v") || 1

С зависимостями тоже всё плохо:

$ npm audit
# npm audit report

axios  <=0.21.1
Severity: high
Axios vulnerable to Server-Side Request Forgery - https://github.com/advisories/GHSA-4w2v-q235-vp99
axios Inefficient Regular Expression Complexity vulnerability - https://github.com/advisories/GHSA-cph5-m8f7-6c5x
Depends on vulnerable versions of follow-redirects
No fix available
node_modules/@nelsonomuto/axios-request-timeout/node_modules/axios
  @nelsonomuto/axios-request-timeout  *
  Depends on vulnerable versions of axios
  node_modules/@nelsonomuto/axios-request-timeout

ejs  <3.1.7
Severity: critical
ejs template injection vulnerability - https://github.com/advisories/GHSA-phwq-j96m-2c2q
fix available via `npm audit fix`
node_modules/ejs
  webpack-bundle-analyzer  1.3.0 - 3.9.0
  Depends on vulnerable versions of ejs
  node_modules/@vue/cli-service/node_modules/webpack-bundle-analyzer

follow-redirects  <=1.14.7
Severity: high
Exposure of sensitive information in follow-redirects - https://github.com/advisories/GHSA-74fj-2j2h-c42q
Exposure of Sensitive Information to an Unauthorized Actor in follow-redirects - https://github.com/advisories/GHSA-pw2r-vq6v-hr8c
No fix available
node_modules/@nelsonomuto/axios-request-timeout/node_modules/follow-redirects

glob-parent  <5.1.2
Severity: high
glob-parent before 5.1.2 vulnerable to Regular Expression Denial of Service in enclosure regex - https://github.com/advisories/GHSA-ww39-953v-wcq6
fix available via `npm audit fix --force`
Will install @vue/cli-service@5.0.8, which is a breaking change
node_modules/glob-parent
  chokidar  1.0.0-rc1 - 2.1.8
  Depends on vulnerable versions of glob-parent
  node_modules/watchpack-chokidar2/node_modules/chokidar
  node_modules/webpack-dev-server/node_modules/chokidar
    watchpack-chokidar2  *
    Depends on vulnerable versions of chokidar
    node_modules/watchpack-chokidar2
      watchpack  1.7.2 - 1.7.5
      Depends on vulnerable versions of watchpack-chokidar2
      node_modules/watchpack
        webpack  4.44.0 - 4.46.0
        Depends on vulnerable versions of watchpack
        node_modules/webpack
    webpack-dev-server  2.0.0-beta - 4.7.2
    Depends on vulnerable versions of chokidar
    Depends on vulnerable versions of selfsigned
    node_modules/webpack-dev-server
      @vue/cli-service  <=5.0.0-rc.3
      Depends on vulnerable versions of @intervolga/optimize-cssnano-plugin
      Depends on vulnerable versions of @vue/cli-plugin-router
      Depends on vulnerable versions of @vue/cli-plugin-vuex
      Depends on vulnerable versions of @vue/cli-shared-utils
      Depends on vulnerable versions of copy-webpack-plugin
      Depends on vulnerable versions of cssnano
      Depends on vulnerable versions of globby
      Depends on vulnerable versions of html-webpack-plugin
      Depends on vulnerable versions of webpack-bundle-analyzer
      Depends on vulnerable versions of webpack-dev-server
      node_modules/@vue/cli-service
        @vue/cli-plugin-babel  3.4.0 - 4.5.19
        Depends on vulnerable versions of @vue/cli-service
        Depends on vulnerable versions of @vue/cli-shared-utils
        node_modules/@vue/cli-plugin-babel
        @vue/cli-plugin-vuex  <=4.5.19
        Depends on vulnerable versions of @vue/cli-service
        node_modules/@vue/cli-plugin-vuex
  copy-webpack-plugin  5.0.1 - 5.1.2
  Depends on vulnerable versions of glob-parent
  node_modules/copy-webpack-plugin
  fast-glob  <=2.2.7
  Depends on vulnerable versions of glob-parent
  node_modules/fast-glob
    globby  8.0.0 - 9.2.0
    Depends on vulnerable versions of fast-glob
    node_modules/globby

json5  <1.0.2
Severity: high
Prototype Pollution in JSON5 via Parse Method - https://github.com/advisories/GHSA-9c47-m6qq-7p4h
fix available via `npm audit fix --force`
Will install @vue/cli-service@5.0.8, which is a breaking change
node_modules/html-webpack-plugin/node_modules/json5
  loader-utils  <=1.4.0
  Depends on vulnerable versions of json5
  node_modules/html-webpack-plugin/node_modules/loader-utils
    html-webpack-plugin  2.0.2 - 3.2.0
    Depends on vulnerable versions of loader-utils
    node_modules/html-webpack-plugin


node-forge  <=1.2.1
Severity: high
Prototype Pollution in node-forge debug API. - https://github.com/advisories/GHSA-5rrq-pxf6-6jx5
URL parsing in node-forge could lead to undesired behavior. - https://github.com/advisories/GHSA-gf8q-jrpm-jvxq
Improper Verification of Cryptographic Signature in `node-forge` - https://github.com/advisories/GHSA-2r2c-g63r-vccr
Open Redirect in node-forge - https://github.com/advisories/GHSA-8fr3-hfg3-gpgp
Improper Verification of Cryptographic Signature in node-forge - https://github.com/advisories/GHSA-cfm4-qjh2-4765
Improper Verification of Cryptographic Signature in node-forge - https://github.com/advisories/GHSA-x4jg-mjrx-434g
fix available via `npm audit fix --force`
Will install @vue/cli-service@5.0.8, which is a breaking change
node_modules/node-forge
  selfsigned  1.1.1 - 1.10.14
  Depends on vulnerable versions of node-forge
  node_modules/selfsigned

node-sass  1.2.3 - 7.0.3
Severity: high
Improper Certificate Validation in node-sass - https://github.com/advisories/GHSA-r8f7-9pfq-mjmv
Depends on vulnerable versions of meow
Depends on vulnerable versions of node-gyp
Depends on vulnerable versions of request
Depends on vulnerable versions of sass-graph
fix available via `npm audit fix --force`
Will install node-sass@9.0.0, which is a breaking change
node_modules/node-sass
  sass-loader  0.4.0-beta.1 - 6.0.7 || 8.0.0 - 10.2.1 || 11.0.0 - 12.3.0
  Depends on vulnerable versions of node-sass
  node_modules/sass-loader

nth-check  <2.0.1
Severity: high
Inefficient Regular Expression Complexity in nth-check - https://github.com/advisories/GHSA-rp65-9cf3-cjxr
fix available via `npm audit fix --force`
Will install @vue/cli-service@5.0.8, which is a breaking change
node_modules/svgo/node_modules/nth-check
  css-select  <=3.1.0
  Depends on vulnerable versions of nth-check
  node_modules/svgo/node_modules/css-select
    svgo  1.0.0 - 1.3.2
    Depends on vulnerable versions of css-select
    node_modules/svgo
      postcss-svgo  4.0.0-nightly.2020.1.9 - 5.0.0-rc.2
      Depends on vulnerable versions of svgo
      node_modules/postcss-svgo
        cssnano-preset-default  <=4.0.8
        Depends on vulnerable versions of postcss-svgo
        node_modules/cssnano-preset-default
          @intervolga/optimize-cssnano-plugin  >=1.0.2
          Depends on vulnerable versions of cssnano
          Depends on vulnerable versions of cssnano-preset-default
          node_modules/@intervolga/optimize-cssnano-plugin
          cssnano  4.0.0-nightly.2020.1.9 - 4.1.11
          Depends on vulnerable versions of cssnano-preset-default
          node_modules/cssnano

request  *
Severity: moderate
Server-Side Request Forgery in Request - https://github.com/advisories/GHSA-p8p7-x288-28g6
Depends on vulnerable versions of tough-cookie
fix available via `npm audit fix --force`
Will install node-sass@9.0.0, which is a breaking change
node_modules/request
  @vue/cli-shared-utils  <=4.5.19
  Depends on vulnerable versions of request
  node_modules/@vue/cli-shared-utils
    @vue/cli-plugin-router  <=4.5.19
    Depends on vulnerable versions of @vue/cli-service
    Depends on vulnerable versions of @vue/cli-shared-utils
    node_modules/@vue/cli-plugin-router
  node-gyp  <=7.1.2
  Depends on vulnerable versions of request
  Depends on vulnerable versions of semver
  Depends on vulnerable versions of tar
  node_modules/node-gyp

scss-tokenizer  <=0.4.2
Severity: high
Regular expression denial of service in scss-tokenizer - https://github.com/advisories/GHSA-7mwh-4pqv-wmr8
fix available via `npm audit fix --force`
Will install node-sass@9.0.0, which is a breaking change
node_modules/scss-tokenizer
  sass-graph  2.2.0 - 4.0.0
  Depends on vulnerable versions of scss-tokenizer
  node_modules/sass-graph

semver  <=5.7.1 || 6.0.0 - 6.3.0 || 7.0.0 - 7.5.1
Severity: moderate
semver vulnerable to Regular Expression Denial of Service - https://github.com/advisories/GHSA-c2qf-rxjj-qqgw
semver vulnerable to Regular Expression Denial of Service - https://github.com/advisories/GHSA-c2qf-rxjj-qqgw
semver vulnerable to Regular Expression Denial of Service - https://github.com/advisories/GHSA-c2qf-rxjj-qqgw
fix available via `npm audit fix --force`
Will install node-sass@9.0.0, which is a breaking change
node_modules/copy-webpack-plugin/node_modules/semver
node_modules/cross-spawn/node_modules/semver
node_modules/less/node_modules/semver
node_modules/node-gyp/node_modules/semver
node_modules/normalize-package-data/node_modules/semver
node_modules/semver
node_modules/terser-webpack-plugin/node_modules/semver
node_modules/ts-loader/node_modules/semver

swiper  <6.5.1
Severity: critical
Prototype Pollution in swiper - https://github.com/advisories/GHSA-p3hc-fv2j-rp68
fix available via `npm audit fix --force`
Will install swiper@10.2.0, which is a breaking change
node_modules/swiper
  vue-awesome-swiper  <=4.1.1
  Depends on vulnerable versions of swiper
  node_modules/vue-awesome-swiper

tar  <=4.4.17
Severity: high
Arbitrary File Creation/Overwrite due to insufficient absolute path sanitization - https://github.com/advisories/GHSA-3jfq-g458-7qm9
Arbitrary File Creation/Overwrite via insufficient symlink protection due to directory cache poisoning - https://github.com/advisories/GHSA-r628-mhmh-qjhw
Arbitrary File Creation/Overwrite via insufficient symlink protection due to directory cache poisoning using symbolic links - https://github.com/advisories/GHSA-9r2w-394v-53qc
Arbitrary File Creation/Overwrite on Windows via insufficient relative path sanitization - https://github.com/advisories/GHSA-5955-9wpr-37jh
Arbitrary File Creation/Overwrite via insufficient symlink protection due to directory cache poisoning using symbolic links - https://github.com/advisories/GHSA-qq89-hq3f-393p
fix available via `npm audit fix --force`
Will install node-sass@9.0.0, which is a breaking change
node_modules/tar

tough-cookie  <4.1.3
Severity: moderate
tough-cookie Prototype Pollution vulnerability - https://github.com/advisories/GHSA-72xf-g2v4-qvf3
fix available via `npm audit fix --force`
Will install node-sass@9.0.0, which is a breaking change
node_modules/tough-cookie

trim-newlines  <3.0.1
Severity: high
Uncontrolled Resource Consumption in trim-newlines - https://github.com/advisories/GHSA-7p7h-4mm5-852v
fix available via `npm audit fix --force`
Will install node-sass@9.0.0, which is a breaking change
node_modules/trim-newlines
  meow  3.4.0 - 5.0.0
  Depends on vulnerable versions of trim-newlines
  node_modules/meow

yaml  2.0.0-5 - 2.2.1
Severity: high
Uncaught Exception in yaml - https://github.com/advisories/GHSA-f9xv-q969-pqx4
fix available via `npm audit fix`
node_modules/yaml

45 vulnerabilities (1 low, 6 moderate, 28 high, 10 critical)

To address issues that do not require attention, run:
  npm audit fix

To address all issues possible (including breaking changes), run:
  npm audit fix --force

Some issues need review, and may require choosing
a different dependency.

Человеку свойственно ошибаться. Поэтому, если у кого-то есть желание поковыряться в коде, хотелось бы получить подтверждение или опровержение моих выводов относительно того, что шифрование скомпрометировано и сообщения можно дешифровать. Также не понятно, отключено ли оригинальное e2e шифрование Matrix в этой поделке.

var salt = «PR7srzZt4EfcNb3s27grgmiG8aB9vYNV82»;

Угу, зашитая в код статичная соль, уже весело.

Я не уверен только насчёт того, откуда берётся version в некоторых местах:

Cкорее всего это просто id ключа из пары public-private, который создается при генерации.

получить подтверждение или опровержение моих выводов относительно того, что шифрование скомпрометировано и сообщения можно дешифровать

Тут блочное шифрование с зашитой в код статичной солью, так что алгоритм как минимум ослаблен. Но больше похоже на быдлокод чем на злонамеренные действия, проще самого автора спросить.

alex0x08 ★★★
()
Ответ на: комментарий от alex0x08

Автор ничего не расскажет, потому что я пытаюсь вывести его на чистую воду. Я вспомнил про дебаггер и сделал следующее:

  • поставил брейкпоинты на строки 326, 575, 605, 781, 1030
  • при отправке сообщения можно увидеть его зашифрованное тело в encryptedBody
  • в запросах к серверу видно body в base64, где в encrypted то же самое тело

version это захардкоженная переменная, строка 45

self.version = 2 

В запросе передаются параметры block, version и nonce. Что интересно, nonce — это случайные данные (строка 1021):

window.crypto.getRandomValues(nonce);

time не используется для генерации ключа. Строка 339:

var k =  ((users ? 'ul+' + orderedIdsHash(users) : period(time)) + "-" + block) + '-' + (v || self.version);

Время нужно для истории на клиенте. По дебаггеру это тоже видно: «зашифрованное» сообщение отправляется на сервер, после чего приходит ответ и происходит дешифровка для отображения в UI. Откуда берётся время можно увидеть на строке 573:

const time = event.origin_server_ts || 1;

Вывод напрашивается сам собой. Но я очень хочу ошибиться, поэтому подожду ещё ответов…

snegg21
() автор топика
Ответ на: комментарий от snegg21

Я невнимательный. k используется:

var ek = `${lcachekey + pcrypto.user.userinfo.id}-${k}`

lcachekey известен:

var lcachekey = "pcrypto8_" + chat.roomId + "_";

Судя по дебаггеру, из k всегда вызывается эта функция:

var period = function (time) {
    var period = 0;
    var h = getuserseventshistory();
    for (var i = h.length - 1; i >= 0; i--) {
        if ((h[i].time < time || !time) && !period) {
            period = i;
        }
    }
    return period;
};

getuserseventshistory выдаёт отсортированные события, которые так же известны серверу:

membership == "invite" ||
membership == "join" ||
(membership == "leave" && !tetatet)// ||

Пример значения k: 2-2368697-2

Сути дело это не меняет.

snegg21
() автор топика
Ответ на: комментарий от snegg21
const keysPrepared = eaac.aeskeys(time, block, users, v);

eaac.aeskeys в свою очередь вызывает

eaa.aeskeys(time, block, users, v);

В функции eaa.aeskeys есть вызовы библиотеки public/js/lib/pocketnet/btc17.js. Её код довольно запутан. Особый интерес представляет eaa.userspublics, похоже здесь берутся публичные ключи участников чата:

var publics = _.map(user.keys, function (key) {
    return Buffer.from(key, "hex");
});

Есть надежда, что шифрование не скомпрометировано.

snegg21
() автор топика
Ответ на: комментарий от mrjaggers

С говнокодом и так всё понятно, у меня нет цели искать в нём уязвимости. Я хочу получить ответы только по поводу шифрования. Это довольно трудоёмкий процесс.

snegg21
() автор топика

Так это какая-то поделка нонейма на гитхабе, которой судя по всему никто не пользуется. То что там соль захардкожена уже означает что оно говно.

Также не понятно, отключено ли оригинальное e2e шифрование Matrix в этой поделке.

Запусти да проверь. Я бы поднял тестовый сервер и посмотрел какие сообщения оно гоняет, потому что только код ковырять – слишком долго и мучительно.

hateyoufeel ★★★★★
()