Show description
SQL_BREAKER // INJECTION_LAB
SQL_BREAKER // INJECTION_LAB
SQL_BREAKER // INJECTION_LAB
VULNERABILITY SIMULATOR
1. Vulnerable Frontend
SECURE MODE (PREPARED STMT)
Username
Password
Inject Payload
Log In
2. Backend Logic (Live Query Builder)
RED indicates parts of the input interpreted as SQL Logic instead of data.
3. Database Table (users)
ID
USERNAME
PASSWORD (HASH)
ROLE
STATUS
SQL_BREAKER // INJECTION_LAB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SQL_BREAKER // INJECTION_LAB</title>
<style>
:root {
--bg-core: #0a0a0a;
--bg-panel: #111;
--text-main: #eee;
--text-dim: #666;
--accent-safe: #00ff9d; /* Neon Green */
--accent-danger: #ff0055; /* Neon Red */
--accent-warn: #ffcc00; /* Yellow */
--code-str: #a5d6ff;
--code-key: #ff7b72;
--font-mono: 'JetBrains Mono', 'Fira Code', Consolas, monospace;
--glass-border: 1px solid rgba(255,255,255,0.1);
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
background-color: var(--bg-core);
color: var(--text-main);
font-family: var(--font-mono);
height: 100vh;
display: flex;
flex-direction: column;
overflow: hidden;
}
/* HEADER */
header {
padding: 1rem 2rem;
border-bottom: var(--glass-border);
display: flex;
justify-content: space-between;
align-items: center;
background: #000;
}
h1 { font-size: 1.1rem; letter-spacing: 2px; color: var(--accent-safe); }
.badge { font-size: 0.75rem; padding: 4px 8px; border: 1px solid var(--text-dim); border-radius: 4px; color: var(--text-dim); }
/* MAIN LAYOUT */
main {
flex: 1;
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: auto 1fr;
gap: 0;
}
/* SECTIONS */
.section {
border: var(--glass-border);
padding: 1.5rem;
position: relative;
background: var(--bg-panel);
display: flex;
flex-direction: column;
}
.label {
position: absolute;
top: 10px;
left: 10px;
font-size: 0.7rem;
color: var(--text-dim);
text-transform: uppercase;
letter-spacing: 1px;
}
/* 1. LOGIN FORM */
.login-container {
grid-column: 1;
grid-row: 1;
display: flex;
flex-direction: column;
gap: 1rem;
justify-content: center;
}
.input-group { display: flex; flex-direction: column; gap: 0.5rem; }
input {
background: #000;
border: 1px solid #333;
color: #fff;
padding: 10px;
font-family: var(--font-mono);
border-radius: 4px;
outline: none;
transition: 0.2s;
}
input:focus { border-color: var(--accent-safe); }
.btn-row { display: flex; gap: 10px; margin-top: 10px; }
button {
padding: 10px 20px;
background: #222;
border: 1px solid #444;
color: #fff;
font-family: var(--font-mono);
cursor: pointer;
border-radius: 4px;
transition: 0.2s;
flex: 1;
}
button:hover { background: #333; }
button.action-hack { border-color: var(--accent-danger); color: var(--accent-danger); }
button.action-hack:hover { background: rgba(255, 0, 85, 0.1); }
button.action-login { background: var(--accent-safe); color: #000; font-weight: bold; border: none; }
button.action-login:hover { box-shadow: 0 0 15px rgba(0,255,157,0.4); }
/* 2. BACKEND VISUALIZER */
.backend-view {
grid-column: 2;
grid-row: 1;
background: #050505;
font-size: 0.9rem;
justify-content: center;
}
.code-block {
background: #000;
padding: 1.5rem;
border-radius: 6px;
border: 1px solid #222;
line-height: 1.6;
color: #ccc;
}
.kw { color: var(--code-key); font-weight: bold; } /* Keyword */
.str { color: var(--code-str); } /* String */
.danger { color: var(--accent-danger); text-shadow: 0 0 5px var(--accent-danger); font-weight: bold; animation: pulse 1s infinite; }
.comment { color: #555; font-style: italic; }
/* 3. DATABASE VIEW */
.db-view {
grid-column: 1 / span 2;
grid-row: 2;
border-top: none;
overflow: auto;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 1rem;
font-size: 0.9rem;
}
th { text-align: left; border-bottom: 2px solid #333; padding: 10px; color: var(--text-dim); }
td { padding: 10px; border-bottom: 1px solid #222; color: var(--text-main); transition: 0.3s; }
tr.selected td {
background: rgba(0, 255, 157, 0.1);
color: var(--accent-safe);
border-bottom: 1px solid var(--accent-safe);
}
/* 4. SECURITY TOGGLE */
.toggle-container {
position: absolute;
top: 20px;
right: 20px;
display: flex;
align-items: center;
gap: 10px;
}
.switch {
position: relative;
display: inline-block;
width: 40px;
height: 20px;
}
.switch input { opacity: 0; width: 0; height: 0; }
.slider {
position: absolute;
cursor: pointer;
top: 0; left: 0; right: 0; bottom: 0;
background-color: #333;
transition: .4s;
border-radius: 20px;
}
.slider:before {
position: absolute;
content: "";
height: 16px;
width: 16px;
left: 2px;
bottom: 2px;
background-color: white;
transition: .4s;
border-radius: 50%;
}
input:checked + .slider { background-color: var(--accent-safe); }
input:checked + .slider:before { transform: translateX(20px); }
/* RESULT OVERLAY */
#resultMsg {
margin-top: 1rem;
padding: 10px;
text-align: center;
border-radius: 4px;
font-weight: bold;
display: none;
}
@keyframes pulse { 0% { opacity: 0.7; } 50% { opacity: 1; } 100% { opacity: 0.7; } }
/* RESPONSIVE */
@media (max-width: 800px) {
main { grid-template-columns: 1fr; grid-template-rows: auto auto 1fr; }
.login-container { grid-column: 1; grid-row: 1; }
.backend-view { grid-column: 1; grid-row: 2; }
.db-view { grid-column: 1; grid-row: 3; }
}
</style>
</head>
<body>
<header>
<h1>SQL_BREAKER // INJECTION_LAB</h1>
<div class="badge">VULNERABILITY SIMULATOR</div>
</header>
<main>
<!-- LOGIN FORM -->
<div class="section login-container">
<span class="label">1. Vulnerable Frontend</span>
<div class="toggle-container">
<span style="font-size: 0.7rem; color: #888;">SECURE MODE (PREPARED STMT)</span>
<label class="switch">
<input type="checkbox" id="secureToggle">
<span class="slider"></span>
</label>
</div>
<div class="input-group">
<label>Username</label>
<input type="text" id="userInput" value="admin" placeholder="Enter username">
</div>
<div class="input-group">
<label>Password</label>
<input type="text" id="passInput" placeholder="Enter password">
</div>
<div class="btn-row">
<button class="action-hack" onclick="injectPayload()">Inject Payload</button>
<button class="action-login" onclick="attemptLogin()">Log In</button>
</div>
<div id="resultMsg"></div>
</div>
<!-- BACKEND CODE -->
<div class="section backend-view">
<span class="label">2. Backend Logic (Live Query Builder)</span>
<div class="code-block" id="codeDisplay">
<!-- JS will inject code here -->
</div>
<div style="margin-top: 1rem; font-size: 0.8rem; color: #666;">
<span style="color: var(--accent-danger)">RED</span> indicates parts of the input interpreted as SQL Logic instead of data.
</div>
</div>
<!-- DATABASE -->
<div class="section db-view">
<span class="label">3. Database Table (users)</span>
<table id="dbTable">
<thead>
<tr>
<th>ID</th>
<th>USERNAME</th>
<th>PASSWORD (HASH)</th>
<th>ROLE</th>
<th>STATUS</th>
</tr>
</thead>
<tbody>
<!-- JS Rows -->
</tbody>
</table>
</div>
</main>
<script>
// --- MOCK DATABASE ---
const users = [
{ id: 1, user: 'admin', pass: 'sUp3r_R00t', role: 'ADMIN', active: true },
{ id: 2, user: 'alice', pass: 'wonderland', role: 'USER', active: true },
{ id: 3, user: 'bob', pass: 'builder123', role: 'USER', active: true },
{ id: 4, user: 'guest', pass: 'guest', role: 'GUEST', active: false }
];
// --- STATE ---
const userInput = document.getElementById('userInput');
const passInput = document.getElementById('passInput');
const codeDisplay = document.getElementById('codeDisplay');
const secureToggle = document.getElementById('secureToggle');
const resultMsg = document.getElementById('resultMsg');
const dbTableBody = document.querySelector('#dbTable tbody');
let isSecure = false;
// --- RENDER DATABASE ---
function renderDB(highlightAll = false, highlightUser = null) {
dbTableBody.innerHTML = '';
users.forEach(u => {
const tr = document.createElement('tr');
// Logic: Highlight if Injection Success (all) OR if normal login (specific user)
if (highlightAll || (highlightUser && u.user === highlightUser)) {
tr.classList.add('selected');
}
tr.innerHTML = `
<td>${u.id}</td>
<td>${u.user}</td>
<td>${maskPass(u.pass)}</td>
<td>${u.role}</td>
<td>${u.active ? 'ACTIVE' : 'LOCKED'}</td>
`;
dbTableBody.appendChild(tr);
});
}
function maskPass(p) { return '*'.repeat(8); }
// --- QUERY BUILDER & VISUALIZER ---
function updateQueryView() {
const userVal = userInput.value;
const passVal = passInput.value;
// Detect Injection Pattern (Simple check for ' OR )
// We look for the closing quote followed by OR
const injectionPattern = /'\s+OR\s+/i;
const isInjecting = injectionPattern.test(passVal) && !isSecure;
let html = '';
if (isSecure) {
// Prepared Statement View
html += `<span class="kw">const</span> query = <span class="str">"SELECT * FROM users WHERE user = ? AND pass = ?"</span>;<br>`;
html += `<span class="kw">const</span> params = [<span class="str">"${userVal}"</span>, <span class="str">"${passVal}"</span>];<br>`;
html += `<span class="comment">// Input is treated strictly as data, not code.</span>`;
} else {
// Vulnerable String Concatenation View
html += `<span class="kw">const</span> query = <span class="str">"SELECT * FROM users WHERE user = '"</span> + <span class="str">"${userVal}"</span> + <span class="str">"' AND pass = '"</span> + `;
// Visual Logic for Highlighting the Break
if (isInjecting) {
// Split the passVal to highlight the injection
// Standard hack: ' OR 1=1 --
const parts = passVal.split("'");
// The first part is inside the quotes (maybe empty)
// The quote itself breaks out
// The rest is danger
html += `<span class="str">"${parts[0]}"</span>`; // The innocent part
html += ` + <span class="str">"'"</span>`; // The closing quote (part of input)
// The rest of the string is the injection
const rest = passVal.substring(parts[0].length + 1);
html += ` + <span class="danger">"${rest}"</span>`;
} else {
html += `<span class="str">"${passVal}"</span>`;
}
html += ` + <span class="str">"';"</span>;`;
if (isInjecting) {
html += `<br><br><span class="comment">// WARNING: Input contains SQL tokens that alter logic!</span>`;
}
}
codeDisplay.innerHTML = html;
}
// --- LOGIN LOGIC (SIMULATION) ---
function attemptLogin() {
const userVal = userInput.value;
const passVal = passInput.value;
resultMsg.style.display = 'block';
resultMsg.className = '';
// 1. SECURE MODE LOGIC
if (isSecure) {
const found = users.find(u => u.user === userVal && u.pass === passVal);
if (found) {
success(`Login Successful! Welcome, ${found.user}.`);
renderDB(false, found.user);
} else {
fail("Login Failed: Invalid credentials.");
renderDB(false, null);
}
return;
}
// 2. VULNERABLE MODE LOGIC
// We define "Injection Success" if the password field contains the Tautology payload
// In a real SQL engine, ' OR 1=1 -- comments out the password check.
// Normalize for demo
const cleanPass = passVal.trim();
// Check for the Tautology Attack: ' OR 1=1 --
// Logic: It closes the quote ('), adds an OR condition that is true (1=1), and comments out the rest (--)
if (cleanPass.includes("' OR 1=1")) {
// Determine if the user part is valid or if this returns ALL rows
// Usually SELECT * ... OR 1=1 returns the first row (Admin) or All Rows depending on app logic.
// We will simulate returning ALL rows (Database Dump).
hackSuccess("SYSTEM BREACHED: Tautology detected. Authentication bypassed. Dumping database...");
renderDB(true); // Highlight ALL
}
// Standard Check
else {
const found = users.find(u => u.user === userVal && u.pass === passVal);
if (found) {
success(`Login Successful! Welcome, ${found.user}.`);
renderDB(false, found.user);
} else {
fail("Login Failed: Invalid credentials.");
renderDB(false, null);
}
}
}
// --- HELPERS ---
function injectPayload() {
// Fills the field with the classic attack
passInput.value = `' OR 1=1 --`;
updateQueryView();
// Flash the input
passInput.style.backgroundColor = "rgba(255, 0, 85, 0.2)";
setTimeout(() => passInput.style.backgroundColor = "#000", 300);
}
function success(msg) {
resultMsg.innerText = msg;
resultMsg.style.backgroundColor = "rgba(0, 255, 157, 0.2)";
resultMsg.style.color = "var(--accent-safe)";
resultMsg.style.border = "1px solid var(--accent-safe)";
}
function hackSuccess(msg) {
resultMsg.innerText = msg;
resultMsg.style.backgroundColor = "rgba(255, 0, 85, 0.2)";
resultMsg.style.color = "var(--accent-danger)";
resultMsg.style.border = "1px solid var(--accent-danger)";
}
function fail(msg) {
resultMsg.innerText = msg;
resultMsg.style.backgroundColor = "rgba(255, 255, 255, 0.1)";
resultMsg.style.color = "#ccc";
resultMsg.style.border = "1px solid #444";
}
// --- EVENT LISTENERS ---
userInput.addEventListener('input', updateQueryView);
passInput.addEventListener('input', updateQueryView);
secureToggle.addEventListener('change', (e) => {
isSecure = e.target.checked;
updateQueryView();
resultMsg.style.display = 'none';
renderDB(false);
});
// Init
renderDB();
updateQueryView();
</script>
</body>
</html>