initial commit
This commit is contained in:
@@ -0,0 +1,930 @@
|
||||
# Security Awareness Lessons Documentation
|
||||
|
||||
This document provides comprehensive information about all available lessons in the platform, including learning objectives, content structure, interactive components, and implementation details.
|
||||
|
||||
---
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Phishing Email Detection Basics](#1-phishing-email-detection-basics)
|
||||
2. [SQL Injection Attack - Online Shop Demo](#2-sql-injection-attack---online-shop-demo)
|
||||
3. [Browser-in-the-Browser (BitB) Attack](#3-browser-in-the-browser-bitb-attack)
|
||||
4. [Creating New Lessons](#creating-new-lessons)
|
||||
|
||||
---
|
||||
|
||||
## 1. Phishing Email Detection Basics
|
||||
|
||||
### Overview
|
||||
|
||||
**Lesson Key:** `phishing-email-basics`
|
||||
**Difficulty:** Beginner
|
||||
**Duration:** 15 minutes
|
||||
**Category:** Social Engineering / Email Security
|
||||
|
||||
### Learning Objectives
|
||||
|
||||
By the end of this lesson, participants will be able to:
|
||||
- Identify common characteristics of phishing emails
|
||||
- Recognize suspicious sender addresses and domains
|
||||
- Detect urgency tactics used by attackers
|
||||
- Understand link verification techniques
|
||||
- Apply best practices for handling suspicious emails
|
||||
|
||||
### Content Structure
|
||||
|
||||
#### Steps:
|
||||
|
||||
1. **Introduction to Phishing** (Content)
|
||||
- Definition and impact of phishing
|
||||
- Statistics on phishing attacks
|
||||
- Why email is a primary attack vector
|
||||
|
||||
2. **Common Red Flags** (Content)
|
||||
- Suspicious sender addresses
|
||||
- Spelling and grammar errors
|
||||
- Urgent or threatening language
|
||||
- Requests for sensitive information
|
||||
- Suspicious links and attachments
|
||||
|
||||
3. **Question 1: Identify Phishing Indicators** (Multiple Choice)
|
||||
- **Points:** 50 total
|
||||
- **Correct Answers:**
|
||||
- Misspelled sender domain (15 pts)
|
||||
- Generic greeting instead of name (10 pts)
|
||||
- Urgent threat about account closure (15 pts)
|
||||
- Suspicious link destination (10 pts)
|
||||
- **Topic:** Recognition of multiple warning signs
|
||||
|
||||
4. **Email Analysis Techniques** (Content)
|
||||
- How to inspect sender information
|
||||
- Hovering over links to check destinations
|
||||
- Checking email headers
|
||||
- Verifying legitimacy through official channels
|
||||
|
||||
5. **Question 2: Safe Email Practices** (Single Choice)
|
||||
- **Points:** 25 total
|
||||
- **Correct Answer:** "Hover over links to verify destination before clicking"
|
||||
- **Topic:** Proactive defense techniques
|
||||
|
||||
6. **Question 3: Reporting Procedures** (Free Text)
|
||||
- **Points:** 25 total
|
||||
- **Validation:** Must mention "report", "IT", and "forward"
|
||||
- **Topic:** Organizational response to phishing
|
||||
|
||||
### Scoring
|
||||
|
||||
- **Total Points:** 100
|
||||
- **Passing Score:** 70%
|
||||
- **Question Distribution:**
|
||||
- Multiple choice: 50 points (partial credit)
|
||||
- Single choice: 25 points (all or nothing)
|
||||
- Free text: 25 points (keyword-based)
|
||||
|
||||
### Implementation Details
|
||||
|
||||
**Files:**
|
||||
- Config: `backend/lessons/configs/phishing-email-basics.yaml`
|
||||
- Module: `backend/lessons/modules/phishing-email-basics/index.js`
|
||||
|
||||
**Question Types:**
|
||||
- Uses standard base class validation
|
||||
- No custom interactive components
|
||||
- Text-based content delivery
|
||||
|
||||
### Best Practices for Teaching
|
||||
|
||||
- Start with real-world examples
|
||||
- Show actual phishing emails (sanitized)
|
||||
- Emphasize the cost of successful attacks
|
||||
- Practice with interactive email analysis
|
||||
- Reinforce reporting procedures
|
||||
|
||||
---
|
||||
|
||||
## 2. SQL Injection Attack - Online Shop Demo
|
||||
|
||||
### Overview
|
||||
|
||||
**Lesson Key:** `sql-injection-shop`
|
||||
**Difficulty:** Intermediate
|
||||
**Duration:** 20 minutes
|
||||
**Category:** Web Application Security / OWASP Top 10
|
||||
|
||||
### Learning Objectives
|
||||
|
||||
By the end of this lesson, participants will be able to:
|
||||
- Understand how SQL injection vulnerabilities work
|
||||
- Recognize vulnerable code patterns
|
||||
- Execute SQL injection attacks in a safe environment
|
||||
- Understand the difference between vulnerable and secure queries
|
||||
- Apply parameterized queries as the primary defense
|
||||
|
||||
### Content Structure
|
||||
|
||||
#### Steps:
|
||||
|
||||
1. **What is SQL Injection?** (Content)
|
||||
- Definition and mechanism
|
||||
- Types of damage (data theft, modification, deletion)
|
||||
- Authentication bypass techniques
|
||||
- Administrative operation exploitation
|
||||
|
||||
2. **Vulnerable Online Shop** (Interactive)
|
||||
- **Component:** `SQLShopDemo`
|
||||
- Live product search with vulnerable SQL backend
|
||||
- Real-time query visualization
|
||||
- Injection detection and explanation
|
||||
|
||||
3. **Question 1: Identify SQL Injection Payloads** (Multiple Choice)
|
||||
- **Points:** 40 total
|
||||
- **Correct Answers:**
|
||||
- `' OR '1'='1` (15 pts) - Always-true condition
|
||||
- `' UNION SELECT username, password FROM users--` (15 pts) - Data extraction
|
||||
- `'; DROP TABLE products--` (10 pts) - Destructive attack
|
||||
- **Topic:** Recognition of injection syntax
|
||||
|
||||
4. **How SQL Injection Works** (Content)
|
||||
- Query structure explanation
|
||||
- Normal vs malicious input comparison
|
||||
- Step-by-step breakdown of attacks
|
||||
- Impact demonstration
|
||||
|
||||
5. **Question 2: Prevention Methods** (Single Choice)
|
||||
- **Points:** 30 total
|
||||
- **Correct Answer:** "Use parameterized queries (prepared statements)"
|
||||
- **Topic:** Gold-standard defense mechanism
|
||||
|
||||
6. **Preventing SQL Injection** (Content)
|
||||
- Parameterized queries (primary defense)
|
||||
- Input validation strategies
|
||||
- Least privilege principle
|
||||
- Web Application Firewalls
|
||||
- Security auditing
|
||||
|
||||
7. **Question 3: Explain Parameterized Queries** (Free Text)
|
||||
- **Points:** 30 total
|
||||
- **Validation:** Must mention "parameter", "data", and "separate"
|
||||
- **Minimum Length:** 50 characters
|
||||
- **Topic:** Understanding separation of code and data
|
||||
|
||||
### Interactive Component: SQLShopDemo
|
||||
|
||||
#### Features:
|
||||
|
||||
**Mock Database:**
|
||||
```javascript
|
||||
products: 8 items (laptops, accessories, office supplies)
|
||||
users: 3 accounts (admin, john_doe, jane_smith)
|
||||
orders: 2 sample orders
|
||||
```
|
||||
|
||||
**Attack Scenarios:**
|
||||
|
||||
1. **OR Injection:**
|
||||
- Input: `' OR '1'='1`
|
||||
- Result: Returns ALL products
|
||||
- Explanation: Bypasses WHERE clause with always-true condition
|
||||
|
||||
2. **UNION SELECT:**
|
||||
- Input: `' UNION SELECT id, username, password, role, 'LEAKED' FROM users--`
|
||||
- Result: Displays user credentials in product table
|
||||
- Explanation: Combines product data with user table
|
||||
|
||||
3. **DROP TABLE:**
|
||||
- Input: `'; DROP TABLE products--`
|
||||
- Result: Simulates table deletion
|
||||
- Explanation: Executes destructive SQL command
|
||||
|
||||
**UI Elements:**
|
||||
- Search input with monospace font for code clarity
|
||||
- "Vulnerable Search" button (red) - executes unsafe query
|
||||
- "Safe Search" button (green) - uses parameterized query
|
||||
- Quick-load example buttons
|
||||
- Real-time SQL query display with syntax highlighting
|
||||
- Injection detection warnings with emoji indicators
|
||||
- Results table showing affected data
|
||||
- Color-coded feedback (red for exploits, green for safe)
|
||||
|
||||
#### Technical Implementation:
|
||||
|
||||
**Backend Methods:**
|
||||
```javascript
|
||||
executeVulnerableQuery(searchTerm)
|
||||
- Simulates vulnerable string concatenation
|
||||
- Detects injection patterns
|
||||
- Returns appropriate results based on attack type
|
||||
|
||||
executeSafeQuery(searchTerm)
|
||||
- Demonstrates parameterized approach
|
||||
- Treats all input as literal data
|
||||
- Shows query with placeholder syntax
|
||||
|
||||
detectInjection(input)
|
||||
- Regex-based pattern matching
|
||||
- Identifies quotes, comments, SQL keywords
|
||||
|
||||
analyzeInjection(input)
|
||||
- Classifies injection type
|
||||
- Generates educational explanation
|
||||
```
|
||||
|
||||
**Frontend API Call:**
|
||||
```javascript
|
||||
participantAPI.executeLessonAction(
|
||||
eventLessonId,
|
||||
'execute-query',
|
||||
{ searchTerm, mode: 'vulnerable' | 'safe' }
|
||||
)
|
||||
```
|
||||
|
||||
### Scoring
|
||||
|
||||
- **Total Points:** 100
|
||||
- **Passing Score:** 70%
|
||||
- **Question Distribution:**
|
||||
- Multiple choice: 40 points (partial credit)
|
||||
- Single choice: 30 points
|
||||
- Free text: 30 points (keyword validation)
|
||||
|
||||
### Implementation Details
|
||||
|
||||
**Files:**
|
||||
- Config: `backend/lessons/configs/sql-injection-shop.yaml`
|
||||
- Module: `backend/lessons/modules/sql-injection-shop/index.js`
|
||||
- Component: `frontend/src/components/lessons/InteractiveContent/SQLShopDemo.jsx`
|
||||
|
||||
**Dependencies:**
|
||||
- Extends `LessonModule` base class
|
||||
- Custom `executeVulnerableQuery` method
|
||||
- Custom `executeSafeQuery` method
|
||||
- Interactive data provider
|
||||
|
||||
**API Endpoint:**
|
||||
- `POST /api/lesson/:eventLessonId/action/execute-query`
|
||||
- Requires participant authentication
|
||||
- Validates lesson is started
|
||||
|
||||
### Best Practices for Teaching
|
||||
|
||||
- Start with normal searches to establish baseline
|
||||
- Progress from simple to complex injections
|
||||
- Always compare vulnerable vs safe implementations
|
||||
- Emphasize that filtering alone is insufficient
|
||||
- Show real-world impact examples
|
||||
- Demonstrate UNION attacks to highlight data exposure risk
|
||||
- Use color coding to make injection obvious
|
||||
- Provide immediate feedback on each attempt
|
||||
|
||||
### Real-World Context
|
||||
|
||||
**OWASP Ranking:** #3 in OWASP Top 10 (Injection)
|
||||
|
||||
**Notable Incidents:**
|
||||
- 2019: British Airways breach (380,000 transactions)
|
||||
- 2020: Freepik SQL injection (8.3 million accounts)
|
||||
- Ongoing: Automated scanning for vulnerable endpoints
|
||||
|
||||
**Industry Standards:**
|
||||
- OWASP recommends parameterized queries
|
||||
- PCI DSS requires SQL injection prevention
|
||||
- ISO 27001 covers secure coding practices
|
||||
|
||||
---
|
||||
|
||||
## 3. Browser-in-the-Browser (BitB) Attack
|
||||
|
||||
### Overview
|
||||
|
||||
**Lesson Key:** `browser-in-browser-attack`
|
||||
**Difficulty:** Advanced
|
||||
**Duration:** 25 minutes
|
||||
**Category:** Social Engineering / Advanced Phishing
|
||||
|
||||
### Learning Objectives
|
||||
|
||||
By the end of this lesson, participants will be able to:
|
||||
- Understand Browser-in-the-Browser attack methodology
|
||||
- Differentiate between real and fake browser windows
|
||||
- Apply physical testing techniques to detect fake popups
|
||||
- Recognize OAuth/SSO popup security implications
|
||||
- Understand why password managers provide protection
|
||||
|
||||
### Content Structure
|
||||
|
||||
#### Steps:
|
||||
|
||||
1. **What is Browser-in-the-Browser?** (Content)
|
||||
- Definition and attack mechanism
|
||||
- Why it's effective (mimics trusted UI)
|
||||
- Comparison to traditional phishing
|
||||
- Historical context (2022 emergence)
|
||||
|
||||
2. **How the Attack Works** (Content)
|
||||
- Traditional OAuth flow diagram
|
||||
- BitB attack flow comparison
|
||||
- Technical explanation (HTML/CSS fake browser)
|
||||
- Visual deception techniques
|
||||
|
||||
3. **Interactive BitB Demo** (Interactive)
|
||||
- **Component:** `BitBDemo`
|
||||
- Side-by-side real vs fake comparison
|
||||
- Interactive detection testing
|
||||
- Real-world attack examples
|
||||
|
||||
4. **Question 1: Detection Indicators** (Multiple Choice)
|
||||
- **Points:** 40 total
|
||||
- **Correct Answers:**
|
||||
- "Window cannot be dragged outside browser" (20 pts)
|
||||
- "Right-click shows 'Inspect Element' on address bar" (20 pts)
|
||||
- **Topic:** Physical behavior testing
|
||||
|
||||
5. **Detection Techniques** (Content)
|
||||
- Drag window test (primary method)
|
||||
- Address bar selectability check
|
||||
- Right-click inspection test
|
||||
- Pixel-perfect detail examination
|
||||
- Taskbar appearance verification
|
||||
- Browser extension usage
|
||||
|
||||
6. **Question 2: Safest Approach** (Single Choice)
|
||||
- **Points:** 35 total
|
||||
- **Correct Answer:** "Try to drag the popup outside browser window"
|
||||
- **Topic:** Practical defense technique
|
||||
|
||||
7. **Protecting Against BitB** (Content)
|
||||
- User defenses (testing, 2FA, manual navigation)
|
||||
- Developer responsibilities (education, redirect flow)
|
||||
- Organizational measures (training, hardware keys)
|
||||
|
||||
8. **Question 3: Password Manager Protection** (Free Text)
|
||||
- **Points:** 25 total
|
||||
- **Validation:** Must mention "domain", "autofill", and "real"
|
||||
- **Minimum Length:** 40 characters
|
||||
- **Topic:** Technical security controls
|
||||
|
||||
### Interactive Component: BitBDemo
|
||||
|
||||
#### Features:
|
||||
|
||||
**Two Scenarios:**
|
||||
|
||||
1. **Legitimate OAuth Popup (Simulated Real)**
|
||||
- Provider: Google
|
||||
- Domain: `accounts.google.com`
|
||||
- Indicators shown for educational purposes
|
||||
- Green "✅ REAL" badge
|
||||
|
||||
2. **BitB Attack (Fake Popup)**
|
||||
- Provider: Microsoft
|
||||
- Domain: `login.microsoftonline.com`
|
||||
- Trapped within page boundaries
|
||||
- Red "⚠️ FAKE" badge
|
||||
|
||||
**Interactive Tests:**
|
||||
|
||||
1. **Drag Test:**
|
||||
- Real: Would allow dragging (simulated)
|
||||
- Fake: Cannot drag outside browser
|
||||
- Feedback: Yellow warning appears when attempted
|
||||
|
||||
2. **Right-Click Test:**
|
||||
- Real: Browser context menu (simulated)
|
||||
- Fake: Shows "Inspect Element" menu
|
||||
- Feedback: Warning about HTML detection
|
||||
|
||||
3. **Visual Inspection:**
|
||||
- Fake window controls (non-functional buttons)
|
||||
- Fake address bar (styled HTML div)
|
||||
- Fake HTTPS lock icon (just an image)
|
||||
|
||||
**UI Elements:**
|
||||
- Side-by-side scenario cards
|
||||
- Provider-specific styling (Google blue, Microsoft blue)
|
||||
- Launch buttons to open fake popups
|
||||
- Dark overlay when popup is active
|
||||
- Educational indicators list
|
||||
- Real-world attack timeline
|
||||
- Test instructions panel
|
||||
|
||||
**Realistic Browser Chrome:**
|
||||
```
|
||||
- macOS-style window controls (red, yellow, green)
|
||||
- Address bar with lock icon
|
||||
- Provider-specific branding
|
||||
- Login form (email + password)
|
||||
- Sign-in button
|
||||
```
|
||||
|
||||
#### Technical Implementation:
|
||||
|
||||
**Frontend Structure:**
|
||||
```javascript
|
||||
renderFakeBrowser(scenario)
|
||||
- Creates modal overlay
|
||||
- Renders fake browser window
|
||||
- Applies provider styling
|
||||
- Handles drag attempts
|
||||
- Handles right-click detection
|
||||
- Shows feedback badges
|
||||
```
|
||||
|
||||
**Drag Detection:**
|
||||
```javascript
|
||||
handleDragStart(e, isReal)
|
||||
- Sets dragAttempted flag
|
||||
- Prevents drag if fake (e.preventDefault)
|
||||
- Shows educational feedback
|
||||
```
|
||||
|
||||
**Right-Click Detection:**
|
||||
```javascript
|
||||
handleAddressBarRightClick(e, isReal)
|
||||
- Sets inspectAttempted flag
|
||||
- Allows context menu on fake popup
|
||||
- Shows educational feedback
|
||||
```
|
||||
|
||||
**Real-World Examples Data:**
|
||||
```javascript
|
||||
[
|
||||
{ year: 2022, target: 'Corporate employees', provider: 'Microsoft OAuth' },
|
||||
{ year: 2022, target: 'Cryptocurrency users', provider: 'Google Sign-in' },
|
||||
{ year: 2023, target: 'GitHub developers', provider: 'GitHub OAuth' }
|
||||
]
|
||||
```
|
||||
|
||||
### Scoring
|
||||
|
||||
- **Total Points:** 100
|
||||
- **Passing Score:** 75%
|
||||
- **Question Distribution:**
|
||||
- Multiple choice: 40 points (physical testing)
|
||||
- Single choice: 35 points (best practice)
|
||||
- Free text: 25 points (technical understanding)
|
||||
|
||||
### Implementation Details
|
||||
|
||||
**Files:**
|
||||
- Config: `backend/lessons/configs/browser-in-browser-attack.yaml`
|
||||
- Module: `backend/lessons/modules/browser-in-browser-attack/index.js`
|
||||
- Component: `frontend/src/components/lessons/InteractiveContent/BitBDemo.jsx`
|
||||
|
||||
**Dependencies:**
|
||||
- Extends `LessonModule` base class
|
||||
- Custom `getInteractiveData` method
|
||||
- React state management for popups
|
||||
- CSS-in-JS for fake browser styling
|
||||
|
||||
**Special Features:**
|
||||
- Modal overlay system
|
||||
- Drag prevention
|
||||
- Context menu detection
|
||||
- Provider theming
|
||||
- Responsive design
|
||||
|
||||
### Best Practices for Teaching
|
||||
|
||||
- Emphasize that visual inspection alone is insufficient
|
||||
- Demonstrate the drag test as the most reliable method
|
||||
- Show how convincing the fake popups can be
|
||||
- Discuss password manager benefits
|
||||
- Explain why manual navigation is safest
|
||||
- Reference real-world incidents
|
||||
- Practice detection multiple times
|
||||
- Warn about new variations
|
||||
|
||||
### Real-World Context
|
||||
|
||||
**Discovery:** 2022 by security researcher mr.d0x
|
||||
|
||||
**Attack Campaign Examples:**
|
||||
- **March 2022:** Steam account phishing
|
||||
- **April 2022:** Cryptocurrency exchange targeting
|
||||
- **May 2022:** Corporate credential harvesting
|
||||
- **2023:** GitHub and GitLab developer targeting
|
||||
|
||||
**Affected Platforms:**
|
||||
- Any OAuth/SSO provider (Google, Microsoft, Facebook, GitHub)
|
||||
- Banking sites with "secure" login popups
|
||||
- Enterprise SSO systems
|
||||
- Cryptocurrency wallets
|
||||
|
||||
**Why It's Effective:**
|
||||
- Mimics trusted UI perfectly
|
||||
- Bypasses traditional phishing training
|
||||
- Works on security-aware users
|
||||
- No browser warnings triggered
|
||||
- HTTPS indicators can be faked
|
||||
|
||||
**Defense Evolution:**
|
||||
- Hardware security keys (FIDO2/WebAuthn) immune
|
||||
- Password managers check real domain
|
||||
- Browser extensions can detect fake UI
|
||||
- User education most critical
|
||||
|
||||
---
|
||||
|
||||
## Creating New Lessons
|
||||
|
||||
### Overview
|
||||
|
||||
This section provides guidance for creating new lessons in the platform.
|
||||
|
||||
### Lesson Structure
|
||||
|
||||
Every lesson consists of two main components:
|
||||
|
||||
1. **YAML Configuration File** (`lessons/configs/*.yaml`)
|
||||
- Defines lesson metadata
|
||||
- Structures content steps
|
||||
- Configures questions and answers
|
||||
- Sets scoring rules
|
||||
|
||||
2. **JavaScript Module** (`lessons/modules/*/index.js`)
|
||||
- Extends `LessonModule` base class
|
||||
- Implements custom validation logic
|
||||
- Provides interactive data
|
||||
- Handles special behaviors
|
||||
|
||||
### YAML Configuration Format
|
||||
|
||||
```yaml
|
||||
lessonKey: "unique-lesson-identifier"
|
||||
title: "Lesson Display Title"
|
||||
description: "Brief description for lesson catalog"
|
||||
difficultyLevel: "beginner|intermediate|advanced"
|
||||
estimatedDuration: 15 # minutes
|
||||
module: "module-directory-name"
|
||||
|
||||
steps:
|
||||
- id: "step-1"
|
||||
type: "content|question|interactive"
|
||||
title: "Step Title"
|
||||
content: "Step content (can be multiline)"
|
||||
|
||||
- id: "question-1"
|
||||
type: "question"
|
||||
questionType: "single_choice|multiple_choice|free_text"
|
||||
question: "The question text?"
|
||||
options: # for choice questions
|
||||
- id: "option-1"
|
||||
text: "Option text"
|
||||
isCorrect: true|false
|
||||
points: 10
|
||||
validationRules: # for free_text questions
|
||||
keywords:
|
||||
required: ["keyword1", "keyword2"]
|
||||
partialCredit: 5
|
||||
minLength: 50
|
||||
maxPoints: 25
|
||||
feedback:
|
||||
correct: "Positive feedback"
|
||||
incorrect: "Educational feedback"
|
||||
|
||||
scoring:
|
||||
passingScore: 70
|
||||
maxTotalPoints: 100
|
||||
```
|
||||
|
||||
### JavaScript Module Structure
|
||||
|
||||
```javascript
|
||||
const LessonModule = require('../base/LessonModule');
|
||||
|
||||
class YourLessonModule extends LessonModule {
|
||||
constructor(config) {
|
||||
super(config);
|
||||
}
|
||||
|
||||
// Optional: Custom answer validation
|
||||
async validateAnswer(questionId, answer) {
|
||||
// Custom logic here, or use:
|
||||
return super.validateAnswer(questionId, answer);
|
||||
}
|
||||
|
||||
// Optional: Provide data for interactive components
|
||||
getInteractiveData(stepId) {
|
||||
if (stepId === 'your-interactive-step') {
|
||||
return {
|
||||
// Data your frontend component needs
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Optional: Custom methods for lesson-specific actions
|
||||
yourCustomMethod(params) {
|
||||
// Implementation
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = YourLessonModule;
|
||||
```
|
||||
|
||||
### Question Types
|
||||
|
||||
#### 1. Single Choice
|
||||
```yaml
|
||||
questionType: "single_choice"
|
||||
options:
|
||||
- id: "correct-option"
|
||||
text: "The right answer"
|
||||
isCorrect: true
|
||||
points: 25
|
||||
- id: "wrong-option"
|
||||
text: "An incorrect answer"
|
||||
isCorrect: false
|
||||
points: 0
|
||||
```
|
||||
- Only one correct answer
|
||||
- All-or-nothing scoring
|
||||
- Radio button UI
|
||||
|
||||
#### 2. Multiple Choice
|
||||
```yaml
|
||||
questionType: "multiple_choice"
|
||||
options:
|
||||
- id: "correct-1"
|
||||
text: "First correct answer"
|
||||
isCorrect: true
|
||||
points: 15
|
||||
- id: "correct-2"
|
||||
text: "Second correct answer"
|
||||
isCorrect: true
|
||||
points: 15
|
||||
- id: "wrong-1"
|
||||
text: "Incorrect answer"
|
||||
isCorrect: false
|
||||
points: 0
|
||||
```
|
||||
- Multiple correct answers
|
||||
- Partial credit awarded per correct selection
|
||||
- Checkbox UI
|
||||
|
||||
#### 3. Free Text
|
||||
```yaml
|
||||
questionType: "free_text"
|
||||
validationRules:
|
||||
keywords:
|
||||
required: ["must", "contain", "these"]
|
||||
partialCredit: 10 # points if some keywords present
|
||||
minLength: 50 # minimum character count
|
||||
maxPoints: 25
|
||||
```
|
||||
- Open-ended response
|
||||
- Keyword-based validation
|
||||
- Minimum length requirement
|
||||
|
||||
### Interactive Components
|
||||
|
||||
#### Creating a New Interactive Component
|
||||
|
||||
1. **Define in YAML:**
|
||||
```yaml
|
||||
- id: "interactive-demo"
|
||||
type: "interactive"
|
||||
title: "Interactive Demo"
|
||||
interactiveComponent: "YourComponentName"
|
||||
content: "Instructions for the interactive element"
|
||||
```
|
||||
|
||||
2. **Provide Data in Module:**
|
||||
```javascript
|
||||
getInteractiveData(stepId) {
|
||||
if (stepId === 'interactive-demo') {
|
||||
return {
|
||||
data: 'Your component data',
|
||||
config: {}
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
```
|
||||
|
||||
3. **Create React Component:**
|
||||
```javascript
|
||||
// frontend/src/components/lessons/InteractiveContent/YourComponent.jsx
|
||||
import React from 'react';
|
||||
|
||||
const YourComponent = ({ lessonData, eventLessonId }) => {
|
||||
const interactiveData = lessonData?.interactiveData || {};
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* Your interactive UI */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default YourComponent;
|
||||
```
|
||||
|
||||
4. **Register in LessonView:**
|
||||
```javascript
|
||||
// frontend/src/pages/LessonView.jsx
|
||||
import YourComponent from '../components/lessons/InteractiveContent/YourComponent';
|
||||
|
||||
// In render:
|
||||
{currentStep.interactiveComponent === 'YourComponent' && (
|
||||
<YourComponent lessonData={lesson} eventLessonId={eventLessonId} />
|
||||
)}
|
||||
```
|
||||
|
||||
### Lesson-Specific Actions
|
||||
|
||||
For interactive components that need backend processing:
|
||||
|
||||
1. **Add Method to Module:**
|
||||
```javascript
|
||||
yourCustomAction(params) {
|
||||
// Process params
|
||||
return result;
|
||||
}
|
||||
```
|
||||
|
||||
2. **Handle in Controller:**
|
||||
```javascript
|
||||
// backend/src/controllers/lesson.controller.js
|
||||
if (action === 'your-action' && lessonModule.yourCustomAction) {
|
||||
result = lessonModule.yourCustomAction(actionData);
|
||||
}
|
||||
```
|
||||
|
||||
3. **Call from Frontend:**
|
||||
```javascript
|
||||
participantAPI.executeLessonAction(
|
||||
eventLessonId,
|
||||
'your-action',
|
||||
{ data }
|
||||
)
|
||||
```
|
||||
|
||||
### Seeding New Lessons
|
||||
|
||||
1. **Add to Catalog:**
|
||||
```javascript
|
||||
// backend/seed-lessons.js
|
||||
const lessons = [
|
||||
{
|
||||
lesson_key: 'your-lesson-key',
|
||||
title: 'Your Lesson Title',
|
||||
description: 'Description',
|
||||
module_path: 'your-module-directory',
|
||||
config_path: 'your-config.yaml',
|
||||
difficulty_level: 'intermediate',
|
||||
estimated_duration: 20
|
||||
}
|
||||
];
|
||||
```
|
||||
|
||||
2. **Run Seed Script:**
|
||||
```bash
|
||||
docker exec lernplattform_backend node seed-lessons.js
|
||||
```
|
||||
|
||||
### Best Practices
|
||||
|
||||
**Content Design:**
|
||||
- Start with clear learning objectives
|
||||
- Use progressive difficulty (easy → hard)
|
||||
- Provide immediate feedback
|
||||
- Include real-world examples
|
||||
- Make it hands-on when possible
|
||||
|
||||
**Question Design:**
|
||||
- Multiple choice: 2-4 options, avoid "all of the above"
|
||||
- Free text: Clear validation criteria
|
||||
- Feedback: Educational, not just correct/incorrect
|
||||
- Points: Reflect question difficulty
|
||||
|
||||
**Interactive Elements:**
|
||||
- Make them essential, not decorative
|
||||
- Provide clear instructions
|
||||
- Give immediate visual feedback
|
||||
- Include educational explanations
|
||||
- Allow experimentation
|
||||
|
||||
**Code Quality:**
|
||||
- Follow existing patterns
|
||||
- Handle errors gracefully
|
||||
- Validate all inputs
|
||||
- Comment complex logic
|
||||
- Test thoroughly
|
||||
|
||||
**Security:**
|
||||
- Never execute actual SQL
|
||||
- Sandbox all demonstrations
|
||||
- Validate on both frontend and backend
|
||||
- Don't leak sensitive information
|
||||
- Use appropriate warnings
|
||||
|
||||
### Testing New Lessons
|
||||
|
||||
1. **Lesson Content:**
|
||||
- All steps render correctly
|
||||
- Images/media load properly
|
||||
- Text formatting is correct
|
||||
|
||||
2. **Questions:**
|
||||
- Correct answers award proper points
|
||||
- Wrong answers give appropriate feedback
|
||||
- Partial credit calculates correctly
|
||||
- Free text validation works
|
||||
|
||||
3. **Interactive Components:**
|
||||
- Components load without errors
|
||||
- Actions execute successfully
|
||||
- Feedback displays correctly
|
||||
- Edge cases handled
|
||||
|
||||
4. **Scoring:**
|
||||
- Total points sum correctly
|
||||
- Passing threshold works
|
||||
- Score persists properly
|
||||
- Leaderboard updates
|
||||
|
||||
5. **Progress:**
|
||||
- Lesson marked as started
|
||||
- Navigation works (prev/next)
|
||||
- Completion triggers properly
|
||||
- Locked lessons stay locked
|
||||
|
||||
### File Checklist
|
||||
|
||||
- [ ] YAML config created
|
||||
- [ ] Module directory created
|
||||
- [ ] Module class implemented
|
||||
- [ ] Interactive components (if any) created
|
||||
- [ ] Seed script updated
|
||||
- [ ] Lesson seeded to database
|
||||
- [ ] Tested in browser
|
||||
- [ ] Documentation updated
|
||||
|
||||
---
|
||||
|
||||
## Appendix
|
||||
|
||||
### Lesson Difficulty Guidelines
|
||||
|
||||
**Beginner:**
|
||||
- Foundational concepts
|
||||
- No prior security knowledge required
|
||||
- 10-15 minute duration
|
||||
- Basic terminology introduction
|
||||
- Real-world relevance emphasized
|
||||
|
||||
**Intermediate:**
|
||||
- Builds on basic security awareness
|
||||
- Requires understanding of systems/networks
|
||||
- 15-25 minute duration
|
||||
- Hands-on demonstrations
|
||||
- Technical explanations
|
||||
|
||||
**Advanced:**
|
||||
- Assumes security knowledge
|
||||
- Complex attack scenarios
|
||||
- 20-30 minute duration
|
||||
- In-depth technical details
|
||||
- Sophisticated defenses
|
||||
|
||||
### Scoring Philosophy
|
||||
|
||||
- **Partial Credit:** Encourage learning, reward partial knowledge
|
||||
- **Passing Score:** 70-75% allows mistakes while ensuring competency
|
||||
- **Question Weight:** Harder questions = more points
|
||||
- **Immediate Feedback:** Don't wait until end of lesson
|
||||
|
||||
### Content Style Guide
|
||||
|
||||
**Tone:**
|
||||
- Professional but approachable
|
||||
- Educational, not preachy
|
||||
- Objective about risks
|
||||
- Encouraging about defenses
|
||||
|
||||
**Formatting:**
|
||||
- Use bullet points for lists
|
||||
- Bold important terms on first use
|
||||
- Code blocks for technical content
|
||||
- Clear step-by-step instructions
|
||||
|
||||
**Examples:**
|
||||
- Prefer real-world incidents
|
||||
- Include dates and sources
|
||||
- Show impact (financial, reputational)
|
||||
- Demonstrate both attacks and defenses
|
||||
|
||||
---
|
||||
|
||||
## Support
|
||||
|
||||
For questions about lesson development:
|
||||
- Review existing lessons as templates
|
||||
- Check base class methods in `LessonModule.js`
|
||||
- Test in development environment first
|
||||
- Document any new patterns
|
||||
|
||||
**Last Updated:** 2026-01-12
|
||||
**Platform Version:** 1.0.0
|
||||
**Total Lessons:** 3
|
||||
@@ -0,0 +1,310 @@
|
||||
# Lessons Directory
|
||||
|
||||
This directory contains all lesson content for the security awareness training platform.
|
||||
|
||||
## Structure
|
||||
|
||||
```
|
||||
lessons/
|
||||
├── configs/ # YAML lesson configurations
|
||||
│ ├── phishing-email-basics.yaml
|
||||
│ ├── sql-injection-shop.yaml
|
||||
│ └── browser-in-browser-attack.yaml
|
||||
├── modules/ # JavaScript lesson modules
|
||||
│ ├── base/
|
||||
│ │ └── LessonModule.js # Base class all lessons extend
|
||||
│ ├── phishing-email-basics/
|
||||
│ │ └── index.js
|
||||
│ ├── sql-injection-shop/
|
||||
│ │ └── index.js
|
||||
│ └── browser-in-browser-attack/
|
||||
│ └── index.js
|
||||
├── lesson-schema.json # JSON schema for validation (optional)
|
||||
├── README.md # This file
|
||||
└── LESSONS_DOCUMENTATION.md # Comprehensive lesson docs
|
||||
```
|
||||
|
||||
## Available Lessons
|
||||
|
||||
### 1. Phishing Email Detection Basics
|
||||
- **Key:** `phishing-email-basics`
|
||||
- **Difficulty:** Beginner
|
||||
- **Duration:** 15 minutes
|
||||
- **Topics:** Email security, social engineering, red flags
|
||||
- **Interactive:** No
|
||||
|
||||
### 2. SQL Injection Attack - Online Shop Demo
|
||||
- **Key:** `sql-injection-shop`
|
||||
- **Difficulty:** Intermediate
|
||||
- **Duration:** 20 minutes
|
||||
- **Topics:** Web security, OWASP Top 10, SQL injection
|
||||
- **Interactive:** Yes - Fake shop with vulnerable search
|
||||
|
||||
### 3. Browser-in-the-Browser (BitB) Attack
|
||||
- **Key:** `browser-in-browser-attack`
|
||||
- **Difficulty:** Advanced
|
||||
- **Duration:** 25 minutes
|
||||
- **Topics:** Advanced phishing, OAuth security, UI spoofing
|
||||
- **Interactive:** Yes - Fake browser popup demos
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Adding a New Lesson
|
||||
|
||||
1. **Create YAML config:**
|
||||
```bash
|
||||
cp configs/phishing-email-basics.yaml configs/your-lesson.yaml
|
||||
# Edit the file with your lesson content
|
||||
```
|
||||
|
||||
2. **Create module:**
|
||||
```bash
|
||||
mkdir modules/your-lesson
|
||||
# Create index.js extending LessonModule
|
||||
```
|
||||
|
||||
3. **Seed to database:**
|
||||
```bash
|
||||
# Add to seed script
|
||||
docker exec lernplattform_backend node seed-lessons.js
|
||||
```
|
||||
|
||||
4. **Assign to event:**
|
||||
- Use admin panel to assign lesson to events
|
||||
- Configure points, weight, and order
|
||||
|
||||
### Testing a Lesson
|
||||
|
||||
1. **Seed the lesson** (see above)
|
||||
2. **Assign to a test event** via admin panel
|
||||
3. **Join event as participant** from hub page
|
||||
4. **Complete the lesson** and verify:
|
||||
- All steps render correctly
|
||||
- Questions award proper points
|
||||
- Interactive components work
|
||||
- Score calculates correctly
|
||||
|
||||
## Lesson Configuration Format
|
||||
|
||||
### Minimal YAML Example
|
||||
|
||||
```yaml
|
||||
lessonKey: "my-lesson"
|
||||
title: "My Lesson Title"
|
||||
description: "Brief description"
|
||||
difficultyLevel: "beginner"
|
||||
estimatedDuration: 15
|
||||
module: "my-lesson"
|
||||
|
||||
steps:
|
||||
- id: "intro"
|
||||
type: "content"
|
||||
title: "Introduction"
|
||||
content: "Lesson content here..."
|
||||
|
||||
- id: "q1"
|
||||
type: "question"
|
||||
questionType: "single_choice"
|
||||
question: "What is the answer?"
|
||||
options:
|
||||
- id: "correct"
|
||||
text: "The right answer"
|
||||
isCorrect: true
|
||||
points: 100
|
||||
- id: "wrong"
|
||||
text: "Wrong answer"
|
||||
isCorrect: false
|
||||
points: 0
|
||||
maxPoints: 100
|
||||
feedback:
|
||||
correct: "Great job!"
|
||||
incorrect: "Try again!"
|
||||
|
||||
scoring:
|
||||
passingScore: 70
|
||||
maxTotalPoints: 100
|
||||
```
|
||||
|
||||
### Minimal Module Example
|
||||
|
||||
```javascript
|
||||
const LessonModule = require('../base/LessonModule');
|
||||
|
||||
class MyLesson extends LessonModule {
|
||||
constructor(config) {
|
||||
super(config);
|
||||
}
|
||||
|
||||
// Use base class validation by default
|
||||
// Override only if custom logic needed
|
||||
}
|
||||
|
||||
module.exports = MyLesson;
|
||||
```
|
||||
|
||||
## Question Types
|
||||
|
||||
### Single Choice
|
||||
- One correct answer
|
||||
- Radio buttons in UI
|
||||
- All-or-nothing scoring
|
||||
|
||||
### Multiple Choice
|
||||
- Multiple correct answers
|
||||
- Checkboxes in UI
|
||||
- Partial credit per correct selection
|
||||
|
||||
### Free Text
|
||||
- Open-ended response
|
||||
- Keyword-based validation
|
||||
- Minimum length requirement
|
||||
|
||||
## Interactive Components
|
||||
|
||||
For lessons with interactive demos:
|
||||
|
||||
1. **Define in YAML:**
|
||||
```yaml
|
||||
- id: "demo"
|
||||
type: "interactive"
|
||||
title: "Interactive Demo"
|
||||
interactiveComponent: "MyComponent"
|
||||
```
|
||||
|
||||
2. **Provide data in module:**
|
||||
```javascript
|
||||
getInteractiveData(stepId) {
|
||||
if (stepId === 'demo') {
|
||||
return { /* component data */ };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
```
|
||||
|
||||
3. **Create React component:**
|
||||
```
|
||||
frontend/src/components/lessons/InteractiveContent/MyComponent.jsx
|
||||
```
|
||||
|
||||
4. **Register in LessonView.jsx**
|
||||
|
||||
## File Naming Conventions
|
||||
|
||||
- **Lesson keys:** lowercase-with-hyphens
|
||||
- **Config files:** `{lesson-key}.yaml`
|
||||
- **Module directories:** `{lesson-key}/`
|
||||
- **Module entry:** `index.js`
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Content
|
||||
- Start with clear learning objectives
|
||||
- Use real-world examples
|
||||
- Progress from easy to hard
|
||||
- Provide immediate feedback
|
||||
- Make it hands-on when possible
|
||||
|
||||
### Questions
|
||||
- 2-4 options for choice questions
|
||||
- Clear, unambiguous wording
|
||||
- Educational feedback (not just "correct"/"incorrect")
|
||||
- Points reflect difficulty
|
||||
|
||||
### Code
|
||||
- Extend `LessonModule` base class
|
||||
- Use base class methods when possible
|
||||
- Comment complex logic
|
||||
- Handle errors gracefully
|
||||
- Validate all inputs
|
||||
|
||||
### Security
|
||||
- Never execute actual dangerous commands
|
||||
- Sandbox all demonstrations
|
||||
- Use appropriate warnings
|
||||
- Don't leak sensitive data
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Multi-step Content Lesson
|
||||
```yaml
|
||||
steps:
|
||||
- type: content (intro)
|
||||
- type: content (main content)
|
||||
- type: question
|
||||
- type: content (summary)
|
||||
- type: question
|
||||
```
|
||||
|
||||
### Interactive Demo Lesson
|
||||
```yaml
|
||||
steps:
|
||||
- type: content (intro)
|
||||
- type: interactive (hands-on)
|
||||
- type: question (about demo)
|
||||
- type: content (explanation)
|
||||
- type: question (best practices)
|
||||
```
|
||||
|
||||
### Progressive Learning
|
||||
```yaml
|
||||
# Start easy
|
||||
- Single choice with obvious answer
|
||||
# Build complexity
|
||||
- Multiple choice with several correct answers
|
||||
# Test understanding
|
||||
- Free text requiring explanation
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Lesson not appearing in admin panel
|
||||
- Check if lesson was seeded to database
|
||||
- Verify `lesson_key` matches between YAML and database
|
||||
- Check database logs for errors
|
||||
|
||||
### Questions not scoring correctly
|
||||
- Verify `maxPoints` matches sum of correct option points
|
||||
- For multiple choice, ensure points are on correct options
|
||||
- Check `isCorrect` boolean values
|
||||
|
||||
### Interactive component not loading
|
||||
- Verify component name matches in YAML
|
||||
- Check component is imported in LessonView.jsx
|
||||
- Look for console errors in browser
|
||||
- Verify `getInteractiveData()` returns data
|
||||
|
||||
### Module not found errors
|
||||
- Check `module_path` in database matches directory name
|
||||
- Verify `index.js` exists in module directory
|
||||
- Ensure `module.exports` is present
|
||||
- Check for syntax errors in module
|
||||
|
||||
## Documentation
|
||||
|
||||
- **Comprehensive Guide:** [LESSONS_DOCUMENTATION.md](./LESSONS_DOCUMENTATION.md)
|
||||
- **Base Class:** [modules/base/LessonModule.js](./modules/base/LessonModule.js)
|
||||
- **Examples:** See existing lessons in `configs/` and `modules/`
|
||||
|
||||
## Development Workflow
|
||||
|
||||
1. **Design** lesson content and questions
|
||||
2. **Create** YAML config and module
|
||||
3. **Test** locally with seed script
|
||||
4. **Assign** to test event
|
||||
5. **Validate** all questions and interactions
|
||||
6. **Review** scoring and feedback
|
||||
7. **Deploy** to production event
|
||||
|
||||
## Support
|
||||
|
||||
For questions or issues:
|
||||
1. Review existing lesson implementations
|
||||
2. Check base class documentation
|
||||
3. Test in development environment first
|
||||
4. Review error logs for debugging
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** 2026-01-12
|
||||
**Total Lessons:** 3
|
||||
**Platform Version:** 1.0.0
|
||||
@@ -0,0 +1,174 @@
|
||||
lessonKey: "browser-in-browser-attack"
|
||||
title: "Browser-in-the-Browser (BitB) Attack"
|
||||
description: "Learn to identify sophisticated phishing attacks that mimic legitimate browser windows"
|
||||
difficultyLevel: "advanced"
|
||||
estimatedDuration: 25
|
||||
module: "browser-in-browser-attack"
|
||||
|
||||
steps:
|
||||
- id: "intro"
|
||||
type: "content"
|
||||
title: "What is Browser-in-the-Browser?"
|
||||
content: |
|
||||
Browser-in-the-Browser (BitB) is an advanced phishing technique that creates a fake browser window inside a webpage. It's designed to trick users into thinking they're interacting with a legitimate OAuth/SSO login popup.
|
||||
|
||||
Why it's dangerous:
|
||||
• Looks identical to real browser popup windows
|
||||
• Shows a fake address bar with HTTPS lock icon
|
||||
• Mimics trusted services (Google, Microsoft, Facebook)
|
||||
• Can steal credentials even from security-aware users
|
||||
• Bypasses traditional phishing detection
|
||||
|
||||
This attack gained prominence in 2022 and has been used in targeted attacks against organizations.
|
||||
|
||||
- id: "how-it-works"
|
||||
type: "content"
|
||||
title: "How the Attack Works"
|
||||
content: |
|
||||
Traditional OAuth Flow:
|
||||
1. User clicks "Sign in with Google" on a website
|
||||
2. Browser opens a REAL popup to google.com
|
||||
3. User enters credentials on Google's actual site
|
||||
4. Google redirects back with authentication token
|
||||
|
||||
BitB Attack Flow:
|
||||
1. User clicks "Sign in with Google" on malicious site
|
||||
2. Site creates a FAKE popup using HTML/CSS/JavaScript
|
||||
3. Fake popup shows fake address bar displaying "accounts.google.com"
|
||||
4. User enters credentials on attacker's fake page
|
||||
5. Attacker captures credentials and simulates success
|
||||
|
||||
The entire "browser window" is actually just HTML elements styled to look like a browser!
|
||||
|
||||
- id: "bitb-demo"
|
||||
type: "interactive"
|
||||
title: "Interactive BitB Demo"
|
||||
interactiveComponent: "BitBDemo"
|
||||
content: |
|
||||
Below you'll see two login scenarios. One uses a REAL browser popup (secure), and one uses a BitB attack (malicious).
|
||||
|
||||
Can you identify the fake? Pay close attention to the details!
|
||||
|
||||
- id: "question-1"
|
||||
type: "question"
|
||||
questionType: "multiple_choice"
|
||||
question: "What are the key indicators that can help identify a Browser-in-the-Browser attack?"
|
||||
options:
|
||||
- id: "https-lock"
|
||||
text: "The presence of HTTPS and a lock icon in the address bar"
|
||||
isCorrect: false
|
||||
points: 0
|
||||
- id: "window-behavior"
|
||||
text: "The popup window cannot be dragged outside the main browser window"
|
||||
isCorrect: true
|
||||
points: 20
|
||||
- id: "inspect-element"
|
||||
text: "Right-clicking allows you to 'Inspect Element' on the address bar"
|
||||
isCorrect: true
|
||||
points: 20
|
||||
- id: "domain-name"
|
||||
text: "The domain name shown in the address bar"
|
||||
isCorrect: false
|
||||
points: 0
|
||||
maxPoints: 40
|
||||
feedback:
|
||||
correct: "Excellent! Real browser windows can be moved anywhere and their UI cannot be inspected as HTML elements."
|
||||
incorrect: "Think about what differentiates a real browser window from HTML/CSS elements on a webpage. The lock icon and domain can both be faked!"
|
||||
|
||||
- id: "detection-techniques"
|
||||
type: "content"
|
||||
title: "Detecting BitB Attacks"
|
||||
content: |
|
||||
How to spot a Browser-in-the-Browser attack:
|
||||
|
||||
1. **Try to Drag the Window**
|
||||
• Real popups can be dragged outside the browser
|
||||
• Fake popups are trapped within the main window
|
||||
|
||||
2. **Check if Address Bar is Selectable**
|
||||
• Real address bars: text is selectable
|
||||
• Fake address bars: usually just an image or styled div
|
||||
|
||||
3. **Right-Click the Address Bar**
|
||||
• Real browser: no "Inspect Element" option
|
||||
• Fake browser: shows HTML inspection menu
|
||||
|
||||
4. **Look for Pixel-Perfect Details**
|
||||
• Fake windows may have slight styling differences
|
||||
• Shadow effects, fonts, or spacing might be off
|
||||
|
||||
5. **Check Your Browser's Task Bar**
|
||||
• Real popups appear as separate windows in taskbar
|
||||
• Fake popups don't create new window entries
|
||||
|
||||
6. **Use Browser Extensions**
|
||||
• Some extensions can detect fake browser UI
|
||||
|
||||
- id: "question-2"
|
||||
type: "question"
|
||||
questionType: "single_choice"
|
||||
question: "A website asks you to 'Sign in with Microsoft' and a popup appears. What is the SAFEST approach?"
|
||||
options:
|
||||
- id: "trust-https"
|
||||
text: "Check for HTTPS in the address bar and proceed if present"
|
||||
isCorrect: false
|
||||
points: 0
|
||||
- id: "test-window"
|
||||
text: "Try to drag the popup outside the browser window to verify it's real"
|
||||
isCorrect: true
|
||||
points: 35
|
||||
- id: "check-domain"
|
||||
text: "Carefully read the domain name to ensure it's Microsoft's real domain"
|
||||
isCorrect: false
|
||||
points: 0
|
||||
- id: "close-and-manual"
|
||||
text: "Close the popup and manually navigate to Microsoft's site"
|
||||
isCorrect: false
|
||||
points: 10
|
||||
maxPoints: 35
|
||||
feedback:
|
||||
correct: "Perfect! Testing if the window can be dragged outside the browser is the most reliable quick check. Though manually navigating is also very safe!"
|
||||
incorrect: "While checking the domain helps, it can be faked in a BitB attack. The physical behavior of the window (can it be dragged out?) reveals the truth."
|
||||
|
||||
- id: "prevention"
|
||||
type: "content"
|
||||
title: "Protecting Against BitB Attacks"
|
||||
content: |
|
||||
For Users:
|
||||
• Always test if popup windows can be moved freely
|
||||
• Use password managers (they check actual domains)
|
||||
• Enable 2FA/MFA for additional security layer
|
||||
• Be suspicious of unexpected login prompts
|
||||
• Manually navigate to sites instead of clicking links
|
||||
|
||||
For Developers:
|
||||
• Educate users about OAuth popup behavior
|
||||
• Use OAuth redirect flow instead of popups when possible
|
||||
• Implement additional verification steps
|
||||
• Consider passwordless authentication methods
|
||||
• Show clear security indicators in your app
|
||||
|
||||
For Organizations:
|
||||
• Train employees to recognize advanced phishing
|
||||
• Deploy anti-phishing browser extensions
|
||||
• Use hardware security keys (FIDO2/WebAuthn)
|
||||
• Monitor for suspicious authentication attempts
|
||||
• Implement conditional access policies
|
||||
|
||||
- id: "question-3"
|
||||
type: "question"
|
||||
questionType: "free_text"
|
||||
question: "Why are password managers particularly effective at protecting against BitB attacks?"
|
||||
validationRules:
|
||||
keywords:
|
||||
required: ["domain", "autofill", "real"]
|
||||
partialCredit: 8
|
||||
minLength: 40
|
||||
maxPoints: 25
|
||||
feedback:
|
||||
correct: "Excellent! Password managers check the actual domain of the page and won't autofill credentials on fake domains, even if they look legitimate."
|
||||
incorrect: "Think about how password managers verify which site they're on before filling in credentials. They check the real URL, not what's displayed visually."
|
||||
|
||||
scoring:
|
||||
passingScore: 75
|
||||
maxTotalPoints: 100
|
||||
@@ -0,0 +1,117 @@
|
||||
lessonKey: "phishing-email-basics"
|
||||
title: "Phishing Email Detection Basics"
|
||||
description: "Learn to identify common phishing tactics in emails and protect yourself from email-based attacks"
|
||||
difficultyLevel: "beginner"
|
||||
estimatedDuration: 15
|
||||
module: "phishing-email-basics"
|
||||
|
||||
steps:
|
||||
- id: "intro"
|
||||
type: "content"
|
||||
title: "What is Phishing?"
|
||||
content: |
|
||||
Phishing is a type of cyber attack where attackers impersonate legitimate organizations
|
||||
to steal sensitive information like passwords, credit card numbers, or personal data.
|
||||
|
||||
Phishing emails often:
|
||||
- Create a sense of urgency
|
||||
- Contain suspicious links or attachments
|
||||
- Have spelling and grammar errors
|
||||
- Use generic greetings like "Dear Customer"
|
||||
- Request sensitive information
|
||||
|
||||
- id: "example-1"
|
||||
type: "content"
|
||||
title: "Example Phishing Email"
|
||||
content: |
|
||||
**From:** security@paypa1-verify.com
|
||||
**Subject:** Urgent: Verify Your Account Now!
|
||||
|
||||
Dear Valued Customer,
|
||||
|
||||
Your PayPal account has been temporarily suspended due to unusual activity.
|
||||
To restore your account, please verify your information immediately by clicking
|
||||
the link below:
|
||||
|
||||
[Verify Account Now]
|
||||
|
||||
Failure to verify within 24 hours will result in permanent account suspension.
|
||||
|
||||
Thank you,
|
||||
PayPal Security Team
|
||||
|
||||
- id: "question-1"
|
||||
type: "question"
|
||||
questionType: "multiple_choice"
|
||||
question: "What are the suspicious elements in this email? (Select all that apply)"
|
||||
options:
|
||||
- id: "misspelled-domain"
|
||||
text: "The sender's domain is misspelled (paypa1 instead of paypal)"
|
||||
isCorrect: true
|
||||
points: 15
|
||||
- id: "urgent-language"
|
||||
text: "Uses urgent/threatening language to create pressure"
|
||||
isCorrect: true
|
||||
points: 15
|
||||
- id: "generic-greeting"
|
||||
text: "Uses generic greeting 'Dear Valued Customer'"
|
||||
isCorrect: true
|
||||
points: 10
|
||||
- id: "requests-action"
|
||||
text: "Requests immediate action via a link"
|
||||
isCorrect: true
|
||||
points: 10
|
||||
- id: "legitimate"
|
||||
text: "This appears to be a legitimate email"
|
||||
isCorrect: false
|
||||
points: 0
|
||||
maxPoints: 50
|
||||
feedback:
|
||||
correct: "Excellent! You identified all the key phishing indicators."
|
||||
partial: "Good job! You spotted some red flags, but review the email again carefully."
|
||||
incorrect: "Not quite. Let's review the common signs of phishing emails."
|
||||
|
||||
- id: "question-2"
|
||||
type: "question"
|
||||
questionType: "single_choice"
|
||||
question: "What should you do if you receive a suspicious email like this?"
|
||||
options:
|
||||
- id: "click-link"
|
||||
text: "Click the link to verify my account"
|
||||
isCorrect: false
|
||||
points: 0
|
||||
- id: "reply-email"
|
||||
text: "Reply to the email asking if it's legitimate"
|
||||
isCorrect: false
|
||||
points: 0
|
||||
- id: "delete-report"
|
||||
text: "Delete the email and report it as phishing"
|
||||
isCorrect: true
|
||||
points: 25
|
||||
- id: "forward-friends"
|
||||
text: "Forward it to friends to warn them"
|
||||
isCorrect: false
|
||||
points: 0
|
||||
maxPoints: 25
|
||||
feedback:
|
||||
correct: "Perfect! Deleting and reporting phishing emails is the right approach."
|
||||
incorrect: "That's not safe. Never click links or reply to suspicious emails. Delete and report them."
|
||||
|
||||
- id: "question-3"
|
||||
type: "question"
|
||||
questionType: "free_text"
|
||||
question: "Describe at least three things you should check before clicking a link in an email."
|
||||
validationRules:
|
||||
- type: "contains_keywords"
|
||||
keywords: ["sender", "domain", "url", "link", "https", "hover", "address", "spelling", "grammar"]
|
||||
minMatches: 3
|
||||
- type: "min_length"
|
||||
value: 50
|
||||
maxPoints: 25
|
||||
feedback:
|
||||
correct: "Great answer! You understand the importance of verifying emails before taking action."
|
||||
incorrect: "Consider checking the sender's email address, hovering over links to see the real URL, and looking for HTTPS."
|
||||
|
||||
scoring:
|
||||
passingScore: 70
|
||||
maxTotalPoints: 100
|
||||
@@ -0,0 +1,143 @@
|
||||
lessonKey: "sql-injection-shop"
|
||||
title: "SQL Injection Attack - Online Shop Demo"
|
||||
description: "Learn how SQL injection vulnerabilities work through a realistic online shop scenario"
|
||||
difficultyLevel: "intermediate"
|
||||
estimatedDuration: 20
|
||||
module: "sql-injection-shop"
|
||||
|
||||
steps:
|
||||
- id: "intro"
|
||||
type: "content"
|
||||
title: "What is SQL Injection?"
|
||||
content: |
|
||||
SQL Injection is one of the most dangerous web application vulnerabilities. It occurs when an attacker can insert malicious SQL code into a query, allowing them to:
|
||||
|
||||
• Access unauthorized data
|
||||
• Modify or delete database records
|
||||
• Bypass authentication
|
||||
• Execute administrative operations
|
||||
|
||||
In this lesson, you'll explore a vulnerable online shop to understand how SQL injection works and why proper input validation is critical.
|
||||
|
||||
- id: "shop-demo"
|
||||
type: "interactive"
|
||||
title: "Vulnerable Online Shop"
|
||||
interactiveComponent: "SQLShopDemo"
|
||||
content: |
|
||||
Below is a simplified online shop with a product search feature. The search functionality is vulnerable to SQL injection.
|
||||
|
||||
Try searching for normal products first, then experiment with SQL injection techniques.
|
||||
|
||||
- id: "question-1"
|
||||
type: "question"
|
||||
questionType: "multiple_choice"
|
||||
question: "Which of the following search inputs could be used to exploit SQL injection?"
|
||||
options:
|
||||
- id: "normal-search"
|
||||
text: "laptop"
|
||||
isCorrect: false
|
||||
points: 0
|
||||
- id: "single-quote"
|
||||
text: "' OR '1'='1"
|
||||
isCorrect: true
|
||||
points: 15
|
||||
- id: "union-select"
|
||||
text: "' UNION SELECT username, password FROM users--"
|
||||
isCorrect: true
|
||||
points: 15
|
||||
- id: "drop-table"
|
||||
text: "'; DROP TABLE products--"
|
||||
isCorrect: true
|
||||
points: 10
|
||||
maxPoints: 40
|
||||
feedback:
|
||||
correct: "Correct! These inputs manipulate the SQL query structure."
|
||||
incorrect: "Review the demo. SQL injection exploits use special characters like quotes and SQL keywords."
|
||||
|
||||
- id: "detection"
|
||||
type: "content"
|
||||
title: "How SQL Injection Works"
|
||||
content: |
|
||||
A vulnerable query might look like:
|
||||
|
||||
SELECT * FROM products WHERE name LIKE '%[USER_INPUT]%'
|
||||
|
||||
When a user searches for "laptop", the query becomes:
|
||||
SELECT * FROM products WHERE name LIKE '%laptop%'
|
||||
|
||||
But if they enter "' OR '1'='1", it becomes:
|
||||
SELECT * FROM products WHERE name LIKE '%' OR '1'='1%'
|
||||
|
||||
The OR '1'='1' condition is always true, so ALL products are returned!
|
||||
|
||||
More dangerous attacks can extract data from other tables or even delete data.
|
||||
|
||||
- id: "question-2"
|
||||
type: "question"
|
||||
questionType: "single_choice"
|
||||
question: "What is the BEST way to prevent SQL injection vulnerabilities?"
|
||||
options:
|
||||
- id: "input-filtering"
|
||||
text: "Filter out dangerous characters like quotes and semicolons"
|
||||
isCorrect: false
|
||||
points: 0
|
||||
- id: "parameterized-queries"
|
||||
text: "Use parameterized queries (prepared statements)"
|
||||
isCorrect: true
|
||||
points: 30
|
||||
- id: "stored-procedures"
|
||||
text: "Only use stored procedures for database access"
|
||||
isCorrect: false
|
||||
points: 0
|
||||
- id: "input-length"
|
||||
text: "Limit the length of user inputs"
|
||||
isCorrect: false
|
||||
points: 0
|
||||
maxPoints: 30
|
||||
feedback:
|
||||
correct: "Excellent! Parameterized queries separate SQL code from user data, making injection impossible."
|
||||
incorrect: "While filtering helps, parameterized queries are the gold standard. They ensure user input is always treated as data, never as SQL code."
|
||||
|
||||
- id: "mitigation"
|
||||
type: "content"
|
||||
title: "Preventing SQL Injection"
|
||||
content: |
|
||||
Best practices to prevent SQL injection:
|
||||
|
||||
1. **Parameterized Queries** (Most Important)
|
||||
• Use prepared statements with bound parameters
|
||||
• Never concatenate user input into SQL strings
|
||||
|
||||
2. **Input Validation**
|
||||
• Validate data types (numbers, emails, etc.)
|
||||
• Use allowlists for expected values
|
||||
|
||||
3. **Least Privilege**
|
||||
• Database accounts should have minimal permissions
|
||||
• Read-only accounts for read operations
|
||||
|
||||
4. **Web Application Firewalls**
|
||||
• Can detect and block SQL injection attempts
|
||||
• Should be used as an additional layer, not primary defense
|
||||
|
||||
5. **Regular Security Audits**
|
||||
• Code reviews and penetration testing
|
||||
• Automated vulnerability scanning
|
||||
|
||||
- id: "question-3"
|
||||
type: "question"
|
||||
questionType: "free_text"
|
||||
question: "In your own words, explain why parameterized queries prevent SQL injection."
|
||||
validationRules:
|
||||
keywords:
|
||||
required: ["parameter", "data", "separate"]
|
||||
partialCredit: 10
|
||||
minLength: 50
|
||||
maxPoints: 30
|
||||
feedback:
|
||||
correct: "Great explanation! You understand that parameterized queries keep SQL structure separate from user data."
|
||||
incorrect: "Think about how parameterized queries treat user input differently than string concatenation. Key concepts: separation of code and data."
|
||||
|
||||
scoring:
|
||||
passingScore: 70
|
||||
maxTotalPoints: 100
|
||||
@@ -0,0 +1,230 @@
|
||||
/**
|
||||
* Base class for all lesson modules
|
||||
* All lesson modules should extend this class
|
||||
*/
|
||||
class LessonModule {
|
||||
constructor(config) {
|
||||
this.config = config;
|
||||
this.lessonKey = config.lessonKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate an answer for a specific question
|
||||
* @param {string} questionId - The question identifier
|
||||
* @param {any} answer - The participant's answer
|
||||
* @returns {Object} { isCorrect, pointsAwarded, feedback }
|
||||
*/
|
||||
async validateAnswer(questionId, answer) {
|
||||
const step = this.config.steps.find(s => s.id === questionId);
|
||||
if (!step || step.type !== 'question') {
|
||||
throw new Error(`Question ${questionId} not found`);
|
||||
}
|
||||
|
||||
return this._validateQuestionType(step, answer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal validation based on question type
|
||||
*/
|
||||
_validateQuestionType(step, answer) {
|
||||
switch (step.questionType) {
|
||||
case 'single_choice':
|
||||
return this._validateSingleChoice(step, answer);
|
||||
case 'multiple_choice':
|
||||
return this._validateMultipleChoice(step, answer);
|
||||
case 'free_text':
|
||||
return this._validateFreeText(step, answer);
|
||||
default:
|
||||
throw new Error(`Unknown question type: ${step.questionType}`);
|
||||
}
|
||||
}
|
||||
|
||||
_validateSingleChoice(step, answer) {
|
||||
const selectedOption = step.options.find(opt => opt.id === answer);
|
||||
if (!selectedOption) {
|
||||
return {
|
||||
isCorrect: false,
|
||||
pointsAwarded: 0,
|
||||
feedback: step.feedback?.incorrect || 'Incorrect answer'
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
isCorrect: selectedOption.isCorrect,
|
||||
pointsAwarded: selectedOption.isCorrect ? selectedOption.points : 0,
|
||||
feedback: selectedOption.isCorrect
|
||||
? (step.feedback?.correct || 'Correct!')
|
||||
: (step.feedback?.incorrect || 'Incorrect answer')
|
||||
};
|
||||
}
|
||||
|
||||
_validateMultipleChoice(step, answers) {
|
||||
// answers should be an array of option IDs
|
||||
if (!Array.isArray(answers)) {
|
||||
return {
|
||||
isCorrect: false,
|
||||
pointsAwarded: 0,
|
||||
feedback: step.feedback?.incorrect || 'Invalid answer format'
|
||||
};
|
||||
}
|
||||
|
||||
const correctOptions = step.options.filter(opt => opt.isCorrect).map(opt => opt.id);
|
||||
const selectedCorrect = answers.filter(a => correctOptions.includes(a));
|
||||
const selectedIncorrect = answers.filter(a => !correctOptions.includes(a));
|
||||
|
||||
// Calculate points
|
||||
const pointsAwarded = selectedCorrect.reduce((sum, id) => {
|
||||
const option = step.options.find(opt => opt.id === id);
|
||||
return sum + (option?.points || 0);
|
||||
}, 0);
|
||||
|
||||
const isFullyCorrect = selectedCorrect.length === correctOptions.length &&
|
||||
selectedIncorrect.length === 0;
|
||||
const isPartiallyCorrect = selectedCorrect.length > 0 && !isFullyCorrect;
|
||||
|
||||
let feedback = step.feedback?.incorrect || 'Incorrect answer';
|
||||
if (isFullyCorrect) {
|
||||
feedback = step.feedback?.correct || 'Correct!';
|
||||
} else if (isPartiallyCorrect) {
|
||||
feedback = step.feedback?.partial || step.feedback?.correct || 'Partially correct';
|
||||
}
|
||||
|
||||
return {
|
||||
isCorrect: isFullyCorrect,
|
||||
isPartial: isPartiallyCorrect,
|
||||
pointsAwarded,
|
||||
feedback
|
||||
};
|
||||
}
|
||||
|
||||
_validateFreeText(step, answer) {
|
||||
if (!answer || typeof answer !== 'string') {
|
||||
return {
|
||||
isCorrect: false,
|
||||
pointsAwarded: 0,
|
||||
feedback: step.feedback?.incorrect || 'Answer is required'
|
||||
};
|
||||
}
|
||||
|
||||
if (!step.validationRules || step.validationRules.length === 0) {
|
||||
// No validation rules, accept any non-empty answer
|
||||
const points = answer.trim().length > 0 ? step.maxPoints : 0;
|
||||
return {
|
||||
isCorrect: points > 0,
|
||||
pointsAwarded: points,
|
||||
feedback: points > 0
|
||||
? (step.feedback?.correct || 'Answer received')
|
||||
: (step.feedback?.incorrect || 'Answer is too short')
|
||||
};
|
||||
}
|
||||
|
||||
let passedRules = 0;
|
||||
const totalRules = step.validationRules.length;
|
||||
|
||||
for (const rule of step.validationRules) {
|
||||
if (this._checkValidationRule(rule, answer)) {
|
||||
passedRules++;
|
||||
}
|
||||
}
|
||||
|
||||
const scorePercentage = passedRules / totalRules;
|
||||
const pointsAwarded = Math.round(step.maxPoints * scorePercentage);
|
||||
const isCorrect = scorePercentage >= 0.7; // 70% threshold
|
||||
|
||||
return {
|
||||
isCorrect,
|
||||
pointsAwarded,
|
||||
feedback: isCorrect
|
||||
? (step.feedback?.correct || 'Good answer!')
|
||||
: (step.feedback?.incorrect || 'Please review your answer')
|
||||
};
|
||||
}
|
||||
|
||||
_checkValidationRule(rule, answer) {
|
||||
const lowerAnswer = (answer || '').toLowerCase();
|
||||
|
||||
switch (rule.type) {
|
||||
case 'contains_keywords':
|
||||
const matches = rule.keywords.filter(keyword =>
|
||||
lowerAnswer.includes(keyword.toLowerCase())
|
||||
).length;
|
||||
return matches >= (rule.minMatches || 1);
|
||||
|
||||
case 'min_length':
|
||||
return answer.length >= rule.value;
|
||||
|
||||
case 'max_length':
|
||||
return answer.length <= rule.value;
|
||||
|
||||
case 'regex':
|
||||
return new RegExp(rule.pattern, rule.flags || 'i').test(answer);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get interactive component data for a step
|
||||
* Can be overridden by subclasses for dynamic content
|
||||
*/
|
||||
async getInteractiveData(stepId) {
|
||||
const step = this.config.steps.find(s => s.id === stepId);
|
||||
if (!step || step.type !== 'interactive') {
|
||||
throw new Error(`Interactive step ${stepId} not found`);
|
||||
}
|
||||
|
||||
return {
|
||||
component: step.interactiveComponent,
|
||||
props: step.componentProps || {}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get lesson content for rendering (without answers)
|
||||
*/
|
||||
getContent() {
|
||||
return {
|
||||
lessonKey: this.lessonKey,
|
||||
title: this.config.title,
|
||||
description: this.config.description,
|
||||
difficultyLevel: this.config.difficultyLevel,
|
||||
estimatedDuration: this.config.estimatedDuration,
|
||||
steps: this.config.steps.map(step => ({
|
||||
id: step.id,
|
||||
type: step.type,
|
||||
title: step.title,
|
||||
content: step.content,
|
||||
// For question steps, don't send correct answers
|
||||
...(step.type === 'question' && {
|
||||
questionType: step.questionType,
|
||||
question: step.question,
|
||||
maxPoints: step.maxPoints,
|
||||
options: step.options?.map(opt => ({
|
||||
id: opt.id,
|
||||
text: opt.text
|
||||
// isCorrect and points are intentionally omitted
|
||||
}))
|
||||
}),
|
||||
// For interactive steps, send component info
|
||||
...(step.type === 'interactive' && {
|
||||
interactiveComponent: step.interactiveComponent,
|
||||
componentProps: step.componentProps
|
||||
})
|
||||
})),
|
||||
scoring: {
|
||||
maxTotalPoints: this.config.scoring?.maxTotalPoints || 100,
|
||||
passingScore: this.config.scoring?.passingScore || 70
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get full configuration (for debugging/admin)
|
||||
*/
|
||||
getFullConfig() {
|
||||
return this.config;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = LessonModule;
|
||||
@@ -0,0 +1,83 @@
|
||||
const LessonModule = require('../base/LessonModule');
|
||||
|
||||
class BrowserInBrowserLesson extends LessonModule {
|
||||
constructor(config) {
|
||||
super(config);
|
||||
}
|
||||
|
||||
// Get interactive data for the BitB demo
|
||||
getInteractiveData(stepId) {
|
||||
if (stepId === 'bitb-demo') {
|
||||
return {
|
||||
scenarios: [
|
||||
{
|
||||
id: 'legitimate',
|
||||
title: 'Legitimate OAuth Popup',
|
||||
provider: 'Google',
|
||||
domain: 'accounts.google.com',
|
||||
isReal: true,
|
||||
description: 'This simulates how a REAL browser popup would behave',
|
||||
indicators: [
|
||||
'Can be dragged outside browser window',
|
||||
'Has native window controls',
|
||||
'Address bar text is not selectable (real browser UI)',
|
||||
'Right-click shows browser context menu, not page menu',
|
||||
'Appears as separate window in system taskbar'
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'bitb-attack',
|
||||
title: 'Browser-in-the-Browser Attack',
|
||||
provider: 'Microsoft',
|
||||
domain: 'login.microsoftonline.com',
|
||||
isReal: false,
|
||||
description: 'This is a FAKE popup window created with HTML/CSS/JavaScript',
|
||||
indicators: [
|
||||
'Cannot be dragged outside the main browser window',
|
||||
'Entire window is trapped within the page boundaries',
|
||||
'Address bar is just HTML text/image (right-click shows Inspect)',
|
||||
'Window controls (minimize, maximize, close) are fake buttons',
|
||||
'Does not appear in system taskbar as separate window'
|
||||
]
|
||||
}
|
||||
],
|
||||
testInstructions: [
|
||||
'Try to drag each popup window outside the main browser area',
|
||||
'Right-click on the address bar to see if you can inspect it as HTML',
|
||||
'Look for subtle differences in fonts, spacing, or shadows',
|
||||
'Check if the window controls behave like real browser buttons',
|
||||
'Notice if the popup can extend beyond the main window boundaries'
|
||||
],
|
||||
realWorldExamples: [
|
||||
{
|
||||
year: 2022,
|
||||
target: 'Corporate employees',
|
||||
provider: 'Microsoft OAuth',
|
||||
description: 'Attackers used BitB to steal enterprise credentials'
|
||||
},
|
||||
{
|
||||
year: 2022,
|
||||
target: 'Cryptocurrency users',
|
||||
provider: 'Google Sign-in',
|
||||
description: 'Fake crypto platforms used BitB for account takeovers'
|
||||
},
|
||||
{
|
||||
year: 2023,
|
||||
target: 'GitHub developers',
|
||||
provider: 'GitHub OAuth',
|
||||
description: 'Malicious sites mimicked GitHub login to steal tokens'
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Validate specific BitB detection knowledge
|
||||
async validateAnswer(questionId, answer) {
|
||||
// Use base class validation for standard question types
|
||||
return super.validateAnswer(questionId, answer);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BrowserInBrowserLesson;
|
||||
@@ -0,0 +1,16 @@
|
||||
const LessonModule = require('../base/LessonModule');
|
||||
|
||||
/**
|
||||
* Phishing Email Detection Basics Lesson
|
||||
* Teaches participants to identify common phishing tactics
|
||||
*/
|
||||
class PhishingEmailBasicsLesson extends LessonModule {
|
||||
constructor(config) {
|
||||
super(config);
|
||||
}
|
||||
|
||||
// This lesson uses the default validation from the base class
|
||||
// No custom validation needed for this beginner lesson
|
||||
}
|
||||
|
||||
module.exports = PhishingEmailBasicsLesson;
|
||||
@@ -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