initial commit
This commit is contained in:
@@ -0,0 +1,209 @@
|
||||
const LessonModule = require('../base/LessonModule');
|
||||
|
||||
class SQLInjectionShopLesson extends LessonModule {
|
||||
constructor(config) {
|
||||
super(config);
|
||||
}
|
||||
|
||||
// Mock database with products
|
||||
getMockDatabase() {
|
||||
return {
|
||||
products: [
|
||||
{ id: 1, name: 'Laptop Pro 15', price: 1299.99, category: 'Electronics', stock: 15 },
|
||||
{ id: 2, name: 'Wireless Mouse', price: 29.99, category: 'Accessories', stock: 50 },
|
||||
{ id: 3, name: 'USB-C Cable', price: 12.99, category: 'Accessories', stock: 100 },
|
||||
{ id: 4, name: 'Gaming Keyboard', price: 89.99, category: 'Electronics', stock: 25 },
|
||||
{ id: 5, name: 'Monitor 27"', price: 349.99, category: 'Electronics', stock: 20 },
|
||||
{ id: 6, name: 'Webcam HD', price: 79.99, category: 'Electronics', stock: 30 },
|
||||
{ id: 7, name: 'Desk Lamp', price: 34.99, category: 'Office', stock: 40 },
|
||||
{ id: 8, name: 'Notebook Set', price: 15.99, category: 'Office', stock: 60 }
|
||||
],
|
||||
users: [
|
||||
{ id: 1, username: 'admin', password: 'hashed_admin_password', role: 'admin' },
|
||||
{ id: 2, username: 'john_doe', password: 'hashed_user_password', role: 'customer' },
|
||||
{ id: 3, username: 'jane_smith', password: 'hashed_user_password', role: 'customer' }
|
||||
],
|
||||
orders: [
|
||||
{ id: 1, user_id: 2, total: 1329.98, status: 'shipped' },
|
||||
{ id: 2, user_id: 3, total: 89.99, status: 'processing' }
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
// Simulate vulnerable SQL query
|
||||
executeVulnerableQuery(searchTerm) {
|
||||
const db = this.getMockDatabase();
|
||||
|
||||
// Build the "vulnerable" query string for educational display
|
||||
const vulnerableQuery = `SELECT * FROM products WHERE name LIKE '%${searchTerm}%'`;
|
||||
|
||||
// Detect SQL injection attempts
|
||||
const injectionDetected = this.detectInjection(searchTerm);
|
||||
|
||||
let results = [];
|
||||
let injectionType = null;
|
||||
let explanation = '';
|
||||
|
||||
if (injectionDetected) {
|
||||
const injectionInfo = this.analyzeInjection(searchTerm);
|
||||
injectionType = injectionInfo.type;
|
||||
explanation = injectionInfo.explanation;
|
||||
|
||||
// Simulate different injection results
|
||||
if (injectionInfo.type === 'OR_ALWAYS_TRUE') {
|
||||
// Return all products (simulating OR '1'='1')
|
||||
results = db.products;
|
||||
} else if (injectionInfo.type === 'UNION_SELECT') {
|
||||
// Simulate UNION attack showing user data
|
||||
results = [
|
||||
{ id: 'INJECTED', name: 'admin', price: 'hashed_admin_password', category: 'LEAKED DATA', stock: 'admin' },
|
||||
{ id: 'INJECTED', name: 'john_doe', price: 'hashed_user_password', category: 'LEAKED DATA', stock: 'customer' },
|
||||
{ id: 'INJECTED', name: 'jane_smith', price: 'hashed_user_password', category: 'LEAKED DATA', stock: 'customer' }
|
||||
];
|
||||
} else if (injectionInfo.type === 'DROP_TABLE') {
|
||||
// Simulate destructive command
|
||||
results = [];
|
||||
explanation += ' In a real scenario, this could delete the entire products table!';
|
||||
} else if (injectionInfo.type === 'COMMENT_INJECTION') {
|
||||
// Bypass rest of query
|
||||
results = db.products;
|
||||
}
|
||||
} else {
|
||||
// Normal search - filter products by name
|
||||
results = db.products.filter(p =>
|
||||
p.name.toLowerCase().includes(searchTerm.toLowerCase())
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
query: vulnerableQuery,
|
||||
results,
|
||||
injectionDetected,
|
||||
injectionType,
|
||||
explanation,
|
||||
recordCount: results.length
|
||||
};
|
||||
}
|
||||
|
||||
// Detect if input contains SQL injection
|
||||
detectInjection(input) {
|
||||
const injectionPatterns = [
|
||||
/'/, // Single quote
|
||||
/--/, // SQL comment
|
||||
/;/, // Statement separator
|
||||
/union/i, // UNION keyword
|
||||
/select/i, // SELECT keyword
|
||||
/drop/i, // DROP keyword
|
||||
/insert/i, // INSERT keyword
|
||||
/update/i, // UPDATE keyword
|
||||
/delete/i, // DELETE keyword
|
||||
/or\s+['"]?\d+['"]?\s*=\s*['"]?\d+['"]?/i // OR 1=1 pattern
|
||||
];
|
||||
|
||||
return injectionPatterns.some(pattern => pattern.test(input));
|
||||
}
|
||||
|
||||
// Analyze the type of SQL injection
|
||||
analyzeInjection(input) {
|
||||
const lowerInput = input.toLowerCase();
|
||||
|
||||
if (lowerInput.includes('union') && lowerInput.includes('select')) {
|
||||
return {
|
||||
type: 'UNION_SELECT',
|
||||
explanation: '⚠️ UNION SELECT injection detected! This technique combines results from multiple tables, potentially exposing sensitive data like usernames and passwords.'
|
||||
};
|
||||
}
|
||||
|
||||
if (lowerInput.includes('drop')) {
|
||||
return {
|
||||
type: 'DROP_TABLE',
|
||||
explanation: '🚨 DROP TABLE injection detected! This is a destructive attack that could delete entire database tables. Critical data loss would occur!'
|
||||
};
|
||||
}
|
||||
|
||||
if (lowerInput.includes("'") && (lowerInput.includes('or') || lowerInput.includes('||'))) {
|
||||
if (lowerInput.match(/or\s+['"]?\d+['"]?\s*=\s*['"]?\d+['"]?/)) {
|
||||
return {
|
||||
type: 'OR_ALWAYS_TRUE',
|
||||
explanation: "⚠️ OR injection detected! The condition '1'='1' is always true, bypassing the intended filter and returning ALL records."
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (lowerInput.includes('--') || lowerInput.includes('#')) {
|
||||
return {
|
||||
type: 'COMMENT_INJECTION',
|
||||
explanation: '⚠️ Comment injection detected! The -- sequence comments out the rest of the SQL query, potentially bypassing security checks.'
|
||||
};
|
||||
}
|
||||
|
||||
if (lowerInput.includes(';')) {
|
||||
return {
|
||||
type: 'MULTIPLE_STATEMENTS',
|
||||
explanation: '⚠️ Multiple statement injection detected! The semicolon allows execution of additional SQL commands, enabling complex attacks.'
|
||||
};
|
||||
}
|
||||
|
||||
// Generic injection
|
||||
return {
|
||||
type: 'GENERIC',
|
||||
explanation: '⚠️ SQL injection attempt detected! Special characters in the input could manipulate the query structure.'
|
||||
};
|
||||
}
|
||||
|
||||
// Demonstrate safe parameterized query
|
||||
executeSafeQuery(searchTerm) {
|
||||
const db = this.getMockDatabase();
|
||||
|
||||
// Show the safe query with placeholder
|
||||
const safeQuery = `SELECT * FROM products WHERE name LIKE ?`;
|
||||
const parameter = `%${searchTerm}%`;
|
||||
|
||||
// Execute safe search (treats all input as literal data)
|
||||
const results = db.products.filter(p =>
|
||||
p.name.toLowerCase().includes(searchTerm.toLowerCase())
|
||||
);
|
||||
|
||||
return {
|
||||
query: safeQuery,
|
||||
parameter,
|
||||
results,
|
||||
explanation: '✅ Parameterized query used! User input is treated as data only, never as SQL code. Injection is impossible.',
|
||||
recordCount: results.length
|
||||
};
|
||||
}
|
||||
|
||||
// Get interactive data for the SQL shop demo
|
||||
getInteractiveData(stepId) {
|
||||
if (stepId === 'shop-demo') {
|
||||
return {
|
||||
database: this.getMockDatabase(),
|
||||
examples: [
|
||||
{
|
||||
label: 'Normal Search',
|
||||
input: 'laptop',
|
||||
description: 'Search for products containing "laptop"'
|
||||
},
|
||||
{
|
||||
label: 'View All Products (OR injection)',
|
||||
input: "' OR '1'='1",
|
||||
description: 'Exploit: Returns all products by making condition always true'
|
||||
},
|
||||
{
|
||||
label: 'Extract User Data (UNION)',
|
||||
input: "' UNION SELECT id, username, password, role, 'LEAKED' FROM users--",
|
||||
description: 'Exploit: Combines product results with user table data'
|
||||
},
|
||||
{
|
||||
label: 'Destructive Attack (DROP)',
|
||||
input: "'; DROP TABLE products--",
|
||||
description: 'Exploit: Attempts to delete the products table'
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SQLInjectionShopLesson;
|
||||
Reference in New Issue
Block a user