Analyze Object - Attempt prototype pollution - console / inspect .js code

 // Usage examples:

// analyzeObject(window.ga, { name: 'ga' });
// analyzeObject(appState, { name: 'appState', maxDepth: 3, tryPollute: true });

(function () {
const SUSPICIOUS_NAME_RE = /(csrf|xsrf|token|auth|secret|session|jwt|apikey|api[-_]?key|bearer|cookie|hdr|header)/i;

function analyzeObject(target, {
name = '(anonymous)',
maxDepth = 2,
tryPollute = false, // off by default; if true, adds & removes a probe on the prototype
showValues = false // keep false to avoid dumping sensitive values to the console
} = {}) {
if (target == null || (typeof target !== 'object' && typeof target !== 'function')) {
console.warn(`[X] Target '${name}' is not an object/function or is null/undefined.`);
return;
}

console.group(`[?] Analyzing '${name}'`);

const ownProps = Object.getOwnPropertyNames(target);
console.log(`[^] Own properties (${ownProps.length}):`, ownProps);

// Classify
const types = ownProps.reduce((acc, p) => {
const t = typeof target[p];
(acc[t] ||= []).push(p);
return acc;
}, {});
console.log("⚡ Functions:", types.function || []);
console.log("[+] Objects:", types.object || []);
console.log("🔤 Primitives:", (types.string||[]).concat(types.number||[], types.boolean||[], types.bigint||[], types.symbol||[]));

// Descriptors
const writableFns = ownProps.filter(p => {
try {
const d = Object.getOwnPropertyDescriptor(target, p);
return d && d.writable && typeof target[p] === 'function';
} catch { return false; }
});
console.log("[!] Writable function props (potential hook points):", writableFns);

const configurableProps = ownProps.filter(p => {
try { const d = Object.getOwnPropertyDescriptor(target, p); return d && d.configurable; }
catch { return false; }
});
console.log("[*] Configurable props:", configurableProps);

// Suspicious names (don’t print values by default)
const suspicious = ownProps.filter(p => SUSPICIOUS_NAME_RE.test(p));
console.log("[*] Suspiciously named props (potential secrets/tokens):", suspicious);

// Walk nested objects to limited depth
const seen = new WeakSet();
const pathsWithSuspicious = [];
const writableAtPaths = [];

function walk(obj, path, depth) {
if (obj == null || (typeof obj !== 'object' && typeof obj !== 'function')) return;
if (seen.has(obj)) return;
seen.add(obj);
if (depth > maxDepth) return;

const props = Object.getOwnPropertyNames(obj);
for (const prop of props) {
let val, desc;
try { val = obj[prop]; } catch {}
try { desc = Object.getOwnPropertyDescriptor(obj, prop); } catch {}

const curPath = path ? `${path}.${prop}` : prop;

if (SUSPICIOUS_NAME_RE.test(prop)) {
pathsWithSuspicious.push(curPath);
if (showValues) console.log(`[-] ${curPath} =`, val);
}

if (desc && (desc.writable || desc.configurable)) {
writableAtPaths.push({ path: curPath, writable: !!desc.writable, configurable: !!desc.configurable, type: typeof val });
}

if (val && (typeof val === 'object' || typeof val === 'function')) {
walk(val, curPath, depth + 1);
}
}
}

walk(target, name, 1);

console.log("- Suspiciously named paths (bounded depth):", pathsWithSuspicious);
console.log("- Writable/configurable paths (bounded depth):", writableAtPaths);

// Prototype info (non-mutating)
const proto = Object.getPrototypeOf(target);
console.group(" Prototype chain (top few)");
let cur = target, steps = 0;
while (cur && steps < 5) {
console.log(cur);
cur = Object.getPrototypeOf(cur);
steps++;
}
console.groupEnd();

// Optional, reversible probe (off by default)
if (tryPollute) {
console.group("[-] Prototype probe");
try {
const protoObj = Object.getPrototypeOf(target);
if (!protoObj) {
console.warn("No prototype to probe.");
} else if (!Object.isExtensible(protoObj)) {
console.warn("Prototype is not extensible; can’t attach probe.");
} else {
const PROBE = Symbol('pp-probe');
const had = Object.prototype.hasOwnProperty.call(protoObj, PROBE);
if (!had) {
Object.defineProperty(protoObj, PROBE, { value: "probe", configurable: true });
console.warn(`[+] Prototype was writable/extensible; probe added, then removed.`);
delete protoObj[PROBE];
} else {
console.warn("Probe already present (unexpected).");
}
}
} catch (e) {
console.error("Probe failed:", e.message);
}
console.groupEnd();
}

console.groupEnd();
}

// Expose helper to the console
window.analyzeObject = analyzeObject;

// Bonus: quick scan of window for globals with suspicious property names (shallow)
window.scanGlobalsForSecrets = function({ showValues = false } = {}) {
const hits = [];
for (const key of Object.getOwnPropertyNames(window)) {
try {
const val = window[key];
if (val && (typeof val === 'object' || typeof val === 'function')) {
const props = Object.getOwnPropertyNames(val);
for (const p of props) {
if (SUSPICIOUS_NAME_RE.test(p)) {
hits.push(`${key}.${p}`);
if (showValues) console.log(`[+] ${key}.${p} =`, val[p]);
}
}
}
} catch {}
}
console.log("[*] Globals w/ suspicious props:", hits);
return hits;
};
})();

Comments

Popular posts from this blog

Repost from LI - New WAF Bypass Discovered - Akamai & Cloudflare

Optimizing the TCP and Kernel of [Ubuntu/kali/Debian]? Here is some optimizations for you (I did not write them / Props to the original author)