Skip to content

Commit

Permalink
Handle Document.prototype.open bypass (#156)
Browse files Browse the repository at this point in the history
  • Loading branch information
weizman authored Nov 15, 2023
1 parent 4129b8d commit ecf1add
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 23 deletions.
26 changes: 15 additions & 11 deletions snow.js
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ const {
getFrameElement
} = __webpack_require__(14);
const {
makeWindowUtilSetter
makeDescriptorSetter
} = __webpack_require__(648);
const {
isMarked,
Expand All @@ -299,13 +299,13 @@ const {
ERR_CB_MUST_BE_FUNCTION,
ERR_MARK_NEW_WINDOW_FAILED
} = __webpack_require__(312);
const setSnowWindowUtil = makeWindowUtilSetter('SNOW_WINDOW', function (win) {
const setSnowWindowUtil = makeDescriptorSetter('SNOW_WINDOW', function (win) {
onWin(win);
});
const setSnowFrameUtil = makeWindowUtilSetter('SNOW_FRAME', function (frame) {
const setSnowFrameUtil = makeDescriptorSetter('SNOW_FRAME', function (frame) {
hook(frame);
});
const setSnowUtil = makeWindowUtilSetter('SNOW', snow);
const setSnowUtil = makeDescriptorSetter('SNOW', snow);
function shouldHook(win) {
try {
const run = !isMarked(win);
Expand Down Expand Up @@ -951,8 +951,12 @@ function hook(win, native, cb, isWindowProxy) {
};
}
function hookOpen(win) {
win.open = hook(win, win.open, hookMessageEvent, true);
win.document.open = hook(win, win.document.open, hookMessageEvent, false);
Object.defineProperty(win, 'open', {
value: hook(win, win.open, hookMessageEvent, true)
});
Object.defineProperty(win.Document.prototype, 'open', {
value: hook(win, win.document.open, hookMessageEvent, false)
});
}
module.exports = hookOpen;

Expand Down Expand Up @@ -1284,12 +1288,12 @@ function isShadow(node) {
function isTrustedHTML(node) {
return trustedHTMLs.includes(node);
}
function makeWindowUtilSetter(prop, val) {
function makeDescriptorSetter(prop, val) {
const desc = Object.create(null);
desc.value = val;
return function (win) {
if (!Object.getOwnPropertyDescriptor(win, prop)) {
Object.defineProperty(win, prop, desc);
return function (obj) {
if (!Object.getOwnPropertyDescriptor(obj, prop)) {
Object.defineProperty(obj, prop, desc);
}
};
}
Expand Down Expand Up @@ -1377,7 +1381,7 @@ function fillArrayUniques(arr, items) {
}
module.exports = {
getDeclarativeShadows,
makeWindowUtilSetter,
makeDescriptorSetter,
toArray,
isTagFramable,
getOwnerWindowOfNode,
Expand Down
2 changes: 1 addition & 1 deletion snow.prod.js

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ const hookWorker = require('./worker');
const hookTrustedHTMLs = require('./trusteds');
const {hookShadowDOM} = require('./shadow');
const {Array, push, addEventListener, getFrameElement} = require('./natives');
const {makeWindowUtilSetter} = require('./utils');
const {makeDescriptorSetter} = require('./utils');
const {isMarked, mark} = require('./mark');
const {error, ERR_CB_MUST_BE_FUNCTION, ERR_MARK_NEW_WINDOW_FAILED} = require('./log');

const setSnowWindowUtil = makeWindowUtilSetter('SNOW_WINDOW', function(win) { onWin(win) });
const setSnowFrameUtil = makeWindowUtilSetter('SNOW_FRAME', function(frame) { hook(frame); });
const setSnowUtil = makeWindowUtilSetter('SNOW', snow);
const setSnowWindowUtil = makeDescriptorSetter('SNOW_WINDOW', function(win) { onWin(win) });
const setSnowFrameUtil = makeDescriptorSetter('SNOW_FRAME', function(frame) { hook(frame); });
const setSnowUtil = makeDescriptorSetter('SNOW', snow);

function shouldHook(win) {
try {
Expand Down
8 changes: 6 additions & 2 deletions src/open.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,12 @@ function hook(win, native, cb, isWindowProxy) {
}

function hookOpen(win) {
win.open = hook(win, win.open, hookMessageEvent, true);
win.document.open = hook(win, win.document.open, hookMessageEvent, false);
Object.defineProperty(win, 'open', {
value: hook(win, win.open, hookMessageEvent, true),
});
Object.defineProperty(win.Document.prototype, 'open', {
value: hook(win, win.document.open, hookMessageEvent, false),
});
}

module.exports = hookOpen;
10 changes: 5 additions & 5 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ function isTrustedHTML(node) {
return trustedHTMLs.includes(node);
}

function makeWindowUtilSetter(prop, val) {
function makeDescriptorSetter(prop, val) {
const desc = Object.create(null);
desc.value = val;
return function(win) {
if (!Object.getOwnPropertyDescriptor(win, prop)) {
Object.defineProperty(win, prop, desc)
return function(obj) {
if (!Object.getOwnPropertyDescriptor(obj, prop)) {
Object.defineProperty(obj, prop, desc)
}
};
}
Expand Down Expand Up @@ -131,4 +131,4 @@ function fillArrayUniques(arr, items) {
return isArrUpdated;
}

module.exports = {getDeclarativeShadows, makeWindowUtilSetter, toArray, isTagFramable, getOwnerWindowOfNode, getContentWindowOfFrame, getFramesArray, getFrameTag, shadows, trustedHTMLs};
module.exports = {getDeclarativeShadows, makeDescriptorSetter, toArray, isTagFramable, getOwnerWindowOfNode, getContentWindowOfFrame, getFramesArray, getFrameTag, shadows, trustedHTMLs};
12 changes: 12 additions & 0 deletions test/open.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,18 @@ describe('window.open API (same origin)', () => {
describe('document.open API', () => {
beforeEach(setup);

it('should fail to use atob of a window that was created via Document.prototype.open API', async function () {
const result = await browser.executeAsync(function(done) {
top.done = done;
top.bypass = (wins) => done(wins.map(win => (win && win.atob ? win : top).atob('WA==')).join(','));
(function(){
const win = Document.prototype.open.call(document, '', '', '');
bypass([win]);
}());
});
expect(result).toBe(generateErrorMessage(ERR_OPENED_PROP_ACCESS_BLOCKED));
});

it('should fail to use atob of a window that was created via document.open API', async function () {
const result = await browser.executeAsync(function(done) {
top.done = done;
Expand Down

0 comments on commit ecf1add

Please sign in to comment.