Skip to content

Commit 025a81c

Browse files
authored
Merge pull request #7 from thisis0xczar/update-20250415-191101
Full update from Mac on 20250415-191101
2 parents e2e7f3f + 2fabd95 commit 025a81c

File tree

15 files changed

+1290
-716
lines changed

15 files changed

+1290
-716
lines changed

background.js

Lines changed: 162 additions & 470 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

content_forwarder.js

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,36 @@
11
/**
22
* FrogPost Extension
33
* Originally Created by thisis0xczar/Lidor JFrog AppSec Team
4-
* Refined on: 2025-04-12
4+
* Refined on: 2025-04-15
55
*/
66
(() => {
77
const FORWARDER_FLAG = '__frogPostForwarderInjected_v2';
88
if (window[FORWARDER_FLAG]) return;
99
window[FORWARDER_FLAG] = true;
1010

1111
function safeGetLocation(win) {
12-
try { if (win?.location?.href) return win.location.href; } catch (e) {}
12+
try {
13+
if (win?.location?.href) return win.location.href;
14+
} catch (e) {}
1315
return 'access-denied-or-invalid';
1416
}
1517

1618
window.addEventListener('message', (event) => {
1719
if (event.source === window && event.data?.type === 'frogPostAgent->ForwardToBackground') {
1820
if (chrome?.runtime?.id && chrome.runtime.sendMessage) {
1921
try {
20-
chrome.runtime.sendMessage({
21-
type: "runtimeListenerCaptured",
22-
payload: event.data.payload
23-
}, (response) => {
24-
if (chrome.runtime.lastError) {} else {}
25-
});
22+
chrome.runtime.sendMessage({ type: "runtimeListenerCaptured", payload: event.data.payload }, (response) => { if (chrome.runtime.lastError) {} else {} });
2623
} catch (e) {}
2724
}
28-
}
29-
else {
30-
if (event.data?.type?.startsWith('frogPostAgent')) return;
31-
if (!event.data || !event.source) return;
25+
} else if (event.data && event.data.type === '__FROGPOST_SET_INDEX__') {
26+
return;
27+
} else {
28+
const messageInternalType = event.data?.type;
29+
if (typeof messageInternalType === 'string' && messageInternalType.startsWith('frogPostAgent')) {
30+
return;
31+
}
32+
if (!event.source) return;
33+
3234
try {
3335
let messageType = 'unknown';
3436
const data = event.data;
@@ -59,8 +61,7 @@
5961
});
6062

6163
if(chrome?.runtime?.id) {
62-
chrome.runtime.sendMessage({ type: "contentScriptReady", url: window.location.href })
63-
.catch(error => {});
64+
chrome.runtime.sendMessage({ type: "contentScriptReady", url: window.location.href }).catch(error => {});
6465
}
6566

6667
})();

content_monitor.js

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/**
2+
* FrogPost Extension
3+
* Originally Created by thisis0xczar/Lidor JFrog AppSec Team
4+
* Refined on: 2025-04-15
5+
*/
6+
(() => {
7+
const MONITOR_FLAG = '__frogPostMonitorInjected_v3';
8+
const CONSOLE_FLAG = '__frogPostConsoleHooked_v2';
9+
if (window[MONITOR_FLAG]) {
10+
return;
11+
}
12+
window[MONITOR_FLAG] = true;
13+
14+
const CONSOLE_MARKER = "FROGPWNED_CONSOLE_XSS";
15+
let lastKnownPayloadIndexFromFuzzer = -1;
16+
17+
try {
18+
window.addEventListener('message', (event) => {
19+
if (event.source === window.parent && event.data && event.data.type === '__FROGPOST_SET_INDEX__' && typeof event.data.index === 'number') {
20+
lastKnownPayloadIndexFromFuzzer = event.data.index;
21+
}
22+
}, false);
23+
} catch(e) {
24+
console.error("FrogPost Monitor: Failed to add index listener", e);
25+
}
26+
27+
if (!window[CONSOLE_FLAG]) {
28+
try {
29+
const originalConsoleLog = window.console.log;
30+
window.console.log = function(...args) {
31+
let markerFound = false;
32+
let detectedPayloadIndex = lastKnownPayloadIndexFromFuzzer;
33+
try {
34+
if (args.some(arg => typeof arg === 'string' && arg.includes(CONSOLE_MARKER))) {
35+
markerFound = true;
36+
if (chrome?.runtime?.id) {
37+
chrome.runtime.sendMessage({
38+
type: "FROGPOST_CONSOLE_SUCCESS",
39+
detail: { markerFound: true, firstArg: String(args[0]).substring(0, 100), timestamp: new Date().toISOString() },
40+
location: window.location.href,
41+
payloadIndex: detectedPayloadIndex
42+
}).catch(e => {});
43+
}
44+
}
45+
} catch (e) {
46+
console.warn("FrogPost Monitor: Error processing console log hook", e);
47+
}
48+
originalConsoleLog.apply(console, args);
49+
};
50+
window[CONSOLE_FLAG] = true;
51+
} catch (e) {
52+
console.error("FrogPost Monitor: Failed to hook console.log", e);
53+
}
54+
}
55+
56+
const SUSPICIOUS_TAGS = new Set(['SCRIPT', 'IFRAME', 'OBJECT', 'EMBED', 'APPLET', 'VIDEO', 'AUDIO', 'LINK', 'FORM', 'DETAILS', 'MARQUEE', 'SVG', 'MATH', 'BUTTON']);
57+
const SUSPICIOUS_ATTRS = new Set(['onerror', 'onload', 'onclick', 'onmouseover', 'onfocus', 'onpageshow', 'onwheel', 'ontoggle', 'onbegin', 'formaction', 'srcdoc', 'background', 'style']);
58+
const SUSPICIOUS_ATTR_VALUES = /^(javascript:|vbscript:|data:)/i;
59+
const SUSPICIOUS_SRC_HREF_ATTRS = new Set(['src', 'href', 'action', 'formaction', 'background', 'data']);
60+
61+
function getElementDescription(node) { if (!node || node.nodeType !== Node.ELEMENT_NODE) return 'NonElementNode'; let desc = `<${node.nodeName.toLowerCase()}`; for (const attr of node.attributes) { desc += ` ${attr.name}="${String(attr.value || '').substring(0, 20)}..."`; } return desc.substring(0, 100) + (desc.length > 100 ? '>...' : '>'); }
62+
63+
function isSuspiciousMutation(mutation) { try { if (mutation.type === 'childList') { for (const node of mutation.addedNodes) { if (node.nodeType === Node.ELEMENT_NODE) { const nodeName = node.nodeName.toUpperCase(); if (SUSPICIOUS_TAGS.has(nodeName)) { return { reason: `Added suspicious tag: <${nodeName}>`, nodeInfo: node.outerHTML?.substring(0, 150) }; } if (node.matches && node.matches('[onerror], [onload], [onclick], [onmouseover], [onfocus]')) { return { reason: `Added node with suspicious event handler`, nodeInfo: node.outerHTML.substring(0, 100) }; } const suspiciousAttr = node.getAttributeNames().find(attr => SUSPICIOUS_ATTRS.has(attr.toLowerCase())); if(suspiciousAttr) { return { reason: `Added node with suspicious attribute: ${suspiciousAttr}`, nodeInfo: getElementDescription(node), attributeValue: node.getAttribute(suspiciousAttr)?.substring(0, 50) }; } for(const attrName of node.getAttributeNames()) { const lowerAttrName = attrName.toLowerCase(); if (SUSPICIOUS_SRC_HREF_ATTRS.has(lowerAttrName)) { const value = node.getAttribute(attrName); if(value && SUSPICIOUS_ATTR_VALUES.test(value)) { return { reason: `Added node with suspicious protocol in attribute: ${lowerAttrName}`, nodeInfo: getElementDescription(node), attributeValue: value.substring(0, 50) }; } } } if (nodeName === 'SCRIPT' && node.innerHTML?.length > 0) { return { reason: `Added script tag with content`, nodeInfo: node.outerHTML?.substring(0, 150) }; } } } } else if (mutation.type === 'attributes') { const attrName = mutation.attributeName?.toLowerCase(); const targetNode = mutation.target; if (targetNode?.nodeType !== Node.ELEMENT_NODE) return null; const targetDesc = getElementDescription(targetNode); if (SUSPICIOUS_ATTRS.has(attrName)) { const value = targetNode.getAttribute(mutation.attributeName); return { reason: `Suspicious attribute modified/added: ${attrName}`, target: targetNode.nodeName, value: value?.substring(0, 100), nodeInfo: targetDesc }; } if (SUSPICIOUS_SRC_HREF_ATTRS.has(attrName)) { const value = targetNode.getAttribute(mutation.attributeName); if(value && SUSPICIOUS_ATTR_VALUES.test(value)) { return { reason: `Suspicious protocol set for attribute: ${attrName}`, target: targetNode.nodeName, value: value.substring(0, 100), nodeInfo: targetDesc }; } } } } catch(e) { console.warn("FrogPost Monitor: Error checking mutation", e); } return null; }
64+
65+
const observerCallback = (mutationsList, observer) => {
66+
let currentPayloadIndex = lastKnownPayloadIndexFromFuzzer; // Capture index at time of mutation batch
67+
for (const mutation of mutationsList) {
68+
const suspiciousDetail = isSuspiciousMutation(mutation);
69+
if (suspiciousDetail) {
70+
try {
71+
suspiciousDetail.timestamp = new Date().toISOString();
72+
if (chrome?.runtime?.id) {
73+
chrome.runtime.sendMessage({ type: "FROGPOST_MUTATION", detail: suspiciousDetail, location: window.location.href, payloadIndex: currentPayloadIndex }).catch(e => {});
74+
} else { observer.disconnect(); break; }
75+
} catch (e) { console.warn("FrogPost Monitor: Failed to send mutation message", e); }
76+
}
77+
}
78+
};
79+
80+
const observer = new MutationObserver(observerCallback);
81+
const config = { attributes: true, childList: true, subtree: true, attributeOldValue: false };
82+
83+
const startObserving = () => {
84+
const initialTarget = document.documentElement;
85+
let bodyObserverActive = false;
86+
const observeBody = () => { if (document.body && !bodyObserverActive) { try { observer.disconnect(); } catch(e){} try { observer.observe(document.body, config); bodyObserverActive = true; } catch(e) { console.error("FrogPost Monitor: Failed to observe document.body", e); } } };
87+
try { observer.observe(initialTarget, { childList: true, subtree: true }); } catch(e) { console.error("FrogPost Monitor: Failed to observe documentElement", e); return; }
88+
if (document.body) { observeBody(); }
89+
else { const bodyWaitObserver = new MutationObserver(() => { if (document.body) { bodyWaitObserver.disconnect(); observeBody(); } }); try { bodyWaitObserver.observe(document.documentElement, { childList: true }); } catch(e) { console.error("FrogPost Monitor: Failed to observe documentElement for body wait", e); if(document.body) observeBody(); } }
90+
};
91+
92+
if (document.readyState === 'loading') {
93+
document.addEventListener('DOMContentLoaded', startObserving, { once: true });
94+
} else {
95+
startObserving();
96+
}
97+
98+
})();

dashboard/dashboard.html

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
<script src="../static/handler-extractor.js"></script>
1313
<script src="../static/trace-report-storage.js"></script>
1414
<script src="../static/static-handler-analyzer.js"></script>
15+
1516
<script type="module" src="../fuzzer/fuzzer.js"></script>
1617
<script type="module" src="../static/tracer.js"></script>
1718
<script type="module" src="./dashboard.js"></script>
@@ -26,8 +27,9 @@ <h1 id="postmessage-inspector" class="dashboard-title">FrogPost</h1>
2627
<div class="header-controls">
2728
<input type="file" id="customPayloadsFile" accept=".txt" style="display: none;">
2829
<span id="customPayloadStatus" style="font-size: 12px; margin-left: 10px;"></span>
29-
<button id="uploadCustomPayloadsBtn" class="control-button secondary-button">Upload Payloads</button>
30+
<button id="uploadCustomPayloadsBtn" class="control-button secondary">Upload Payloads</button>
3031
<button id="clearCustomPayloadsBtn" class="control-button secondary-button" style="display: none;">Clear Payloads</button>
32+
<button id="openOptionsBtn" class="control-button secondary">Custom Rules / Settings</button>
3133
<button id="checkAll" class="control-button" aria-label="Check All Endpoints">Check All</button>
3234
<button id="clearMessages" class="control-button" aria-label="Clear Messages">Clear All</button>
3335
<button id="exportMessages" class="control-button" aria-label="Export Messages">Export</button>
@@ -82,5 +84,6 @@ <h1 id="postmessage-inspector" class="dashboard-title">FrogPost</h1>
8284
<div id="handlerDisplayModalContainer"></div>
8385

8486
</div>
87+
8588
</body>
8689
</html>

0 commit comments

Comments
 (0)