Created
November 4, 2024 23:31
-
-
Save greenido/41fdc120bad04f3d44b9651688e57515 to your computer and use it in GitHub Desktop.
Chrome Extension example: Drive-by downloads
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// DriveByProtector.js | |
class DriveByProtector { | |
constructor() { | |
this.suspiciousPatterns = { | |
fileTypes: /\.(exe|msi|dmg|pkg|deb|bat|cmd|sh|ps1|vbs|jar|dll|scr)$/i, | |
mimeTypes: [ | |
'application/x-msdownload', | |
'application/x-msdos-program', | |
'application/x-executable', | |
'application/x-dosexec', | |
'application/octet-stream', | |
'application/x-javascript', | |
'application/java-archive' | |
], | |
suspiciousStrings: [ | |
'eval(', | |
'document.write(', | |
'fromCharCode', | |
'String.fromCharCode', | |
'unescape(', | |
'escape(', | |
'atob(', | |
'btoa(' | |
] | |
}; | |
this.initializeProtection(); | |
} | |
initializeProtection() { | |
// Initialize all protection mechanisms | |
this.monitorDOMChanges(); | |
this.monitorNetworkRequests(); | |
this.preventAutoDownloads(); | |
this.monitorScriptExecution(); | |
this.protectAgainstExploits(); | |
this.monitorIframeActivity(); | |
} | |
monitorDOMChanges() { | |
const observer = new MutationObserver((mutations) => { | |
mutations.forEach((mutation) => { | |
mutation.addedNodes.forEach((node) => { | |
if (this.isSuspiciousElement(node)) { | |
this.handleSuspiciousElement(node); | |
} | |
}); | |
}); | |
}); | |
observer.observe(document.documentElement, { | |
childList: true, | |
subtree: true | |
}); | |
} | |
isSuspiciousElement(node) { | |
if (node.nodeName) { | |
const suspiciousElements = ['IFRAME', 'OBJECT', 'EMBED', 'APPLET']; | |
return suspiciousElements.includes(node.nodeName); | |
} | |
return false; | |
} | |
monitorNetworkRequests() { | |
// Monitor XHR | |
const originalXHR = window.XMLHttpRequest; | |
window.XMLHttpRequest = function() { | |
const xhr = new originalXHR(); | |
const originalOpen = xhr.open; | |
const originalSend = xhr.send; | |
const self = this; | |
xhr.open = function() { | |
this._url = arguments[1]; | |
return originalOpen.apply(this, arguments); | |
}; | |
xhr.send = function() { | |
xhr.addEventListener('load', function() { | |
self.checkResponse(this); | |
}); | |
return originalSend.apply(this, arguments); | |
}; | |
return xhr; | |
}; | |
// Monitor Fetch | |
const originalFetch = window.fetch; | |
window.fetch = function() { | |
return originalFetch.apply(this, arguments) | |
.then(response => { | |
this.checkResponse(response); | |
return response; | |
}); | |
}; | |
} | |
checkResponse(response) { | |
const contentType = response.getResponseHeader?.('content-type') || | |
response.headers?.get('content-type'); | |
if (contentType && this.suspiciousPatterns.mimeTypes.includes(contentType)) { | |
this.logThreat({ | |
type: 'suspicious_download', | |
url: response._url || response.url, | |
contentType: contentType | |
}); | |
return false; | |
} | |
return true; | |
} | |
preventAutoDownloads() { | |
// Override download attribute | |
document.addEventListener('click', (event) => { | |
const link = event.target.closest('a'); | |
if (link?.hasAttribute('download')) { | |
event.preventDefault(); | |
this.handleDownloadAttempt(link); | |
} | |
}, true); | |
// Monitor Blob URLs | |
const originalCreateObjectURL = URL.createObjectURL; | |
URL.createObjectURL = (blob) => { | |
if (this.isSuspiciousBlob(blob)) { | |
this.logThreat({ | |
type: 'suspicious_blob', | |
mimeType: blob.type, | |
size: blob.size | |
}); | |
return null; | |
} | |
return originalCreateObjectURL(blob); | |
}; | |
} | |
isSuspiciousBlob(blob) { | |
return this.suspiciousPatterns.mimeTypes.includes(blob.type) || | |
blob.size > 10 * 1024 * 1024; // Files larger than 10MB | |
} | |
monitorScriptExecution() { | |
// Monitor eval | |
const originalEval = window.eval; | |
window.eval = (code) => { | |
if (this.containsSuspiciousCode(code)) { | |
this.logThreat({ | |
type: 'suspicious_eval', | |
code: code.substring(0, 100) // Log first 100 chars | |
}); | |
return null; | |
} | |
return originalEval(code); | |
}; | |
// Monitor new Function | |
const originalFunction = window.Function; | |
window.Function = function() { | |
const code = Array.from(arguments).join(''); | |
if (this.containsSuspiciousCode(code)) { | |
this.logThreat({ | |
type: 'suspicious_function', | |
code: code.substring(0, 100) | |
}); | |
return function() {}; | |
} | |
return originalFunction.apply(this, arguments); | |
}; | |
} | |
containsSuspiciousCode(code) { | |
return this.suspiciousPatterns.suspiciousStrings.some(pattern => | |
code.includes(pattern)); | |
} | |
protectAgainstExploits() { | |
// Freeze important objects | |
Object.freeze(Object.prototype); | |
Object.freeze(Array.prototype); | |
Object.freeze(Function.prototype); | |
// Prevent prototype pollution | |
const preventPollution = (obj) => { | |
if (obj.constructor === Object) { | |
Object.seal(obj); | |
} | |
return obj; | |
}; | |
// Override JSON parse | |
const originalParse = JSON.parse; | |
JSON.parse = function() { | |
const obj = originalParse.apply(this, arguments); | |
return preventPollution(obj); | |
}; | |
} | |
monitorIframeActivity() { | |
// Monitor iframe creation | |
const createElementOriginal = document.createElement; | |
document.createElement = function() { | |
const element = createElementOriginal.apply(this, arguments); | |
if (arguments[0].toLowerCase() === 'iframe') { | |
this.handleIframeCreation(element); | |
} | |
return element; | |
}; | |
// Monitor postMessage | |
window.addEventListener('message', (event) => { | |
this.handlePostMessage(event); | |
}, true); | |
} | |
handleIframeCreation(iframe) { | |
iframe.sandbox = 'allow-scripts'; // Restrict iframe capabilities | |
iframe.addEventListener('load', () => { | |
try { | |
// Check if iframe content is accessible | |
const iframeDoc = iframe.contentDocument || iframe.contentWindow.document; | |
this.scanDocument(iframeDoc); | |
} catch (e) { | |
// Cross-origin iframe - can't access content | |
this.logThreat({ | |
type: 'suspicious_iframe', | |
src: iframe.src | |
}); | |
} | |
}); | |
} | |
handlePostMessage(event) { | |
if (this.containsSuspiciousCode(event.data)) { | |
this.logThreat({ | |
type: 'suspicious_postMessage', | |
origin: event.origin, | |
data: event.data.substring(0, 100) | |
}); | |
event.preventDefault(); | |
} | |
} | |
handleSuspiciousElement(element) { | |
const elementInfo = { | |
type: element.nodeName, | |
src: element.src || element.data, | |
id: element.id, | |
className: element.className | |
}; | |
this.logThreat({ | |
type: 'suspicious_element', | |
element: elementInfo | |
}); | |
// Optionally remove or sanitize the element | |
element.remove(); | |
} | |
handleDownloadAttempt(link) { | |
const url = link.href; | |
const filename = link.download || url.split('/').pop(); | |
if (this.isSuspiciousDownload(url, filename)) { | |
this.logThreat({ | |
type: 'blocked_download', | |
url: url, | |
filename: filename | |
}); | |
return; | |
} | |
// Show confirmation dialog | |
if (confirm(`Do you want to download ${filename}?`)) { | |
window.location.href = url; | |
} | |
} | |
isSuspiciousDownload(url, filename) { | |
return this.suspiciousPatterns.fileTypes.test(filename) || | |
url.includes('data:') || | |
url.includes('blob:'); | |
} | |
scanDocument(doc) { | |
// Scan for suspicious elements | |
const suspiciousElements = doc.querySelectorAll('iframe, object, embed, applet'); | |
suspiciousElements.forEach(element => { | |
this.handleSuspiciousElement(element); | |
}); | |
// Scan inline scripts | |
const scripts = doc.querySelectorAll('script'); | |
scripts.forEach(script => { | |
if (this.containsSuspiciousCode(script.textContent)) { | |
this.logThreat({ | |
type: 'suspicious_inline_script', | |
content: script.textContent.substring(0, 100) | |
}); | |
script.remove(); | |
} | |
}); | |
} | |
logThreat(threat) { | |
// Add common threat information | |
threat.timestamp = new Date().toISOString(); | |
threat.url = window.location.href; | |
threat.userAgent = navigator.userAgent; | |
// Log to console | |
console.warn('Security Threat Detected:', threat); | |
// Send to security monitoring system | |
this.reportThreat(threat); | |
// Trigger any registered callbacks | |
this.onThreatDetected?.(threat); | |
} | |
reportThreat(threat) { | |
// Implementation depends on your security infrastructure | |
// Example: | |
fetch('/api/security/threats', { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json' | |
}, | |
body: JSON.stringify(threat) | |
}).catch(error => console.error('Failed to report threat:', error)); | |
} | |
} | |
// Initialize protection | |
const protector = new DriveByProtector(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment