[XSS] Take in account the whole redirection chain (thanks NDevTK for reporting).

This commit is contained in:
hackademix 2024-09-05 11:35:12 +02:00
parent 5f768bd416
commit 10e2c40c1c
No known key found for this signature in database
GPG Key ID: 231A83AFDA9C2434
2 changed files with 38 additions and 7 deletions

View File

@ -42,8 +42,9 @@ XSS.Exceptions = (() => {
function logEx(...args) { function logEx(...args) {
debug("[XSS preprocessing] Ignoring %o", xssReq, ...args); debug("[XSS preprocessing] Ignoring %o", xssReq, ...args);
} }
log(`Processing exceptions for `, xssReq);
let { let {
isCrossSite,
srcObj, srcObj,
destObj, destObj,
srcUrl, srcUrl,
@ -55,8 +56,9 @@ XSS.Exceptions = (() => {
isPost isPost
} = xssReq; } = xssReq;
// same srcUrl // let same-site requests alone
if (srcOrigin === destOrigin) { if (!isCrossSite ||
/^https:/.test(srcOrigin) && xssReq.srcDomain === xssReq.destDomain) {
return true; return true;
} }

View File

@ -26,6 +26,8 @@ var XSS = (() => {
let baseTTL = 20000; // timeout in milliseconds for each worker to perform let baseTTL = 20000; // timeout in milliseconds for each worker to perform
const redirMap = new Map();
let workersMap = new Map(); let workersMap = new Map();
let promptsMap = new Map(); let promptsMap = new Map();
let blockedTabs = new Map(); let blockedTabs = new Map();
@ -67,6 +69,7 @@ var XSS = (() => {
function doneListener(request) { function doneListener(request) {
let {requestId} = request; let {requestId} = request;
redirMap.delete(requestId);
let worker = workersMap.get(requestId); let worker = workersMap.get(requestId);
if (worker) { if (worker) {
worker.terminate(); worker.terminate();
@ -233,10 +236,19 @@ var XSS = (() => {
parseRequest(request) { parseRequest(request) {
let { let {
requestId,
url: destUrl, url: destUrl,
originUrl: srcUrl, originUrl: srcUrl,
method method
} = request; } = request;
let redirects;
if (redirMap.has(requestId)) {
redirects = redirMap.get(requestId);
} else {
redirMap.set(requestId, redirects = []);
}
let destObj; let destObj;
try { try {
destObj = parseUrl(destUrl); destObj = parseUrl(destUrl);
@ -253,16 +265,31 @@ var XSS = (() => {
srcUrl = ""; srcUrl = "";
} }
let unescapedDest = unescape(destUrl);
let srcOrigin = srcObj ? srcObj.origin : ""; let srcOrigin = srcObj ? srcObj.origin : "";
if (srcOrigin === "null") { if (srcOrigin === "null") {
srcOrigin = srcObj.href.replace(/[\?#].*/, ''); srcOrigin = srcObj.href.replace(/[\?#].*/, '');
} }
let destOrigin = destObj.origin; let destOrigin = destObj.origin;
let isGet = method === "GET"; let isCrossSite = srcOrigin !== destOrigin;
return {
if (!isCrossSite) {
// check the whole redirection chain, if any
for (let r of redirects) {
if (r.destOrigin !== destOrigin) {
({destUrl: srcUrl, destObj: srcObj, destOrigin: srcOrigin} = r);
isCrossSite = true;
break;
}
}
}
const isGet = method === "GET";
const xssReq = {
request, request,
redirects,
isCrossSite,
srcUrl, srcUrl,
destUrl, destUrl,
srcObj, srcObj,
@ -272,12 +299,14 @@ var XSS = (() => {
srcDomain: srcObj && srcObj.hostname && tld.getDomain(srcObj.hostname) || "", srcDomain: srcObj && srcObj.hostname && tld.getDomain(srcObj.hostname) || "",
destDomain: tld.getDomain(destObj.hostname), destDomain: tld.getDomain(destObj.hostname),
originKey: `${srcOrigin}>${destOrigin}`, originKey: `${srcOrigin}>${destOrigin}`,
unescapedDest, unescapedDest: unescape(destUrl),
isGet, isGet,
isPost: !isGet && method === "POST", isPost: !isGet && method === "POST",
timestamp: Date.now(), timestamp: Date.now(),
debugging: ns.local.debug, debugging: ns.local.debug,
} }
redirects.unshift(xssReq);
return xssReq;
}, },
async saveUserChoices(xssUserChoices = this._userChoices || {}) { async saveUserChoices(xssUserChoices = this._userChoices || {}) {