Skip to content

Commit

Permalink
feat: prevent bundle unpack path traversal
Browse files Browse the repository at this point in the history
  • Loading branch information
j4k0xb committed Aug 17, 2023
1 parent 4e9d7dc commit 2b2f1f6
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 3 deletions.
7 changes: 5 additions & 2 deletions src/extractor/bundle.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import traverse from '@babel/traverse';
import * as m from '@codemod/matchers';
import debug from 'debug';
import { dirname, join } from 'node:path';
import { dirname, join, normalize } from 'node:path/posix';
import { Module } from './module';

const logger = debug('webcrack:unpack');
Expand Down Expand Up @@ -84,7 +84,10 @@ export class Bundle {

await Promise.all(
Array.from(this.modules.values(), async module => {
const modulePath = join(path, module.path);
const modulePath = normalize(join(path, module.path));
if (!modulePath.startsWith(path)) {
throw new Error(`detected path traversal: ${module.path}`);
}
await mkdir(dirname(modulePath), { recursive: true });
await writeFile(modulePath, module.code, 'utf8');
})
Expand Down
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import generate from '@babel/generator';
import { parse } from '@babel/parser';
import * as m from '@codemod/matchers';
import debug from 'debug';
import { join } from 'node:path';
import { join, normalize } from 'node:path';
import deobfuscator from './deobfuscator';
import debugProtection from './deobfuscator/debugProtection';
import mergeObjectAssignments from './deobfuscator/mergeObjectAssignments';
Expand Down Expand Up @@ -143,6 +143,7 @@ export async function webcrack(
code: outputCode,
bundle,
async save(path) {
path = normalize(path);
if (process.env.browser) {
throw new Error('Not implemented.');
} else {
Expand Down
8 changes: 8 additions & 0 deletions test/extractor.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import assert from 'assert';
import { readFile } from 'fs/promises';
import { tmpdir } from 'os';
import { join } from 'path';
import { describe, expect, test } from 'vitest';
import { webcrack } from '../src/index';
Expand Down Expand Up @@ -52,6 +53,13 @@ describe('extractor', () => {
});
});

test('prevent path traversal', async () => {
const code = await readFile('test/samples/webpack-path-traversal.js', 'utf8');
const result = await webcrack(code);
const dir = join(tmpdir(), 'path-traversal-test');
await expect(result.save(dir)).rejects.toThrow('path traversal');
});

describe('paths', () => {
test('relative paths', () => {
expect(relativePath('./a.js', './x/y.js')).toBe('./x/y.js');
Expand Down
20 changes: 20 additions & 0 deletions test/samples/webpack-path-traversal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
(function (e) {
var n = {};
function o(r) {
if (n[r]) {
return n[r].exports;
}
var a = (n[r] = {
i: r,
l: false,
exports: {},
});
e[r].call(a.exports, a, a.exports, o);
a.l = true;
return a.exports;
}
o.p = '';
o((o.s = 386));
})({
'../tmp.js': function (e, t, n) {},
});

0 comments on commit 2b2f1f6

Please sign in to comment.