Embedded Security Labs¶
Welcome to the EMBSEC Lab Exercises! These hands-on labs are designed to teach fundamental security vulnerabilities in embedded systems through practical exploitation exercises.
Overview¶
Each lab recreates a historically significant vulnerability in an embedded context, allowing you to understand both the technical details and the real-world impact of these security flaws. You'll work with actual ARM Cortex-M3 binaries running on emulated hardware, providing a realistic embedded security experience.
Lab Exercises¶
Lab 01: Buffer Overflow¶
Historical Context: Morris Worm (1988)
Difficulty: Easy
Skills: Stack layout, return address control, ARM calling conventions
Recreate the classic gets() vulnerability that enabled the first Internet worm. Learn how unchecked input can lead to arbitrary code execution on embedded systems.
Lab 02: Format String¶
Historical Context: WU-FTPD (2000)
Difficulty: Medium
Skills: Format specifiers, memory disclosure, arbitrary write primitives
Explore the format string vulnerability class that shocked the security community. Master reading and writing arbitrary memory through printf vulnerabilities.
Getting Started¶
Prerequisites¶
- EMBSEC development container
- Basic understanding of C programming
- Familiarity with ARM assembly (helpful but not required)
- Python 3 for exploit development
Setup Instructions¶
-
Start the development container:
-
Flash the target binary:
-
Connect to the serial console:
-
Reset the board (if needed):
- Press Ctrl+A, then K to kill screen session
- Reconnect with screen command
Lab Structure¶
Each lab follows a consistent structure:
labs/XX-vulnerability-name/
├── src/ # Vulnerable source code
├── solution/ # Exploit scripts and writeup
├── tests/ # Automated testing
├── metadata.yml # Lab configuration
└── README.md # Lab-specific instructions
Understanding Lab Structure¶
Learn about the common components, build system, and development workflow for all labs.
Learning Path¶
Beginner Path¶
- Start with Lab 01 (Buffer Overflow)
- Read the historical context carefully
- Use the debug menu to understand memory layout
- Follow hints before attempting exploitation
- Compare your solution with the provided writeup
Advanced Path¶
- Try solving without debug information
- Combine vulnerabilities for advanced exploits
- Bypass additional protections when enabled
- Write ROP chains for code reuse attacks
- Develop universal exploits
Key Concepts¶
ARM Cortex-M3 Specifics¶
- Thumb Mode: All code runs in Thumb mode (16/32-bit instructions)
- Function Pointers: Must have LSB set to 1 for Thumb mode
- Stack Layout: Full descending stack, 4-byte aligned
- No MMU: No virtual memory or ASLR by default
- Limited Protections: Basic embedded systems often lack modern mitigations
Exploitation Primitives¶
- Memory Disclosure: Reading memory contents (stack, heap, code)
- Control Flow Hijacking: Redirecting program execution
- Arbitrary Write: Writing to any memory location
- Code Injection: Placing and executing shellcode
- Return-Oriented Programming: Reusing existing code
Security Mitigations¶
Learn about defenses and how they're bypassed:
Stack Protection¶
- Stack Canaries: Random values to detect overflow
- Guard Pages: Unmapped memory regions
- Stack Isolation: Separate stacks for interrupts
Memory Protection¶
- W^X Policy: Memory is either writable or executable
- MPU Regions: Hardware memory access control
- Secure Boot: Authenticated firmware loading
Runtime Defenses¶
- FORTIFY_SOURCE: Hardened library functions
- Control Flow Integrity: Indirect call validation
- Pointer Authentication: Cryptographic pointer protection
Development Tools¶
Debugging¶
Exploit Development¶
# Pwntools for ARM
from pwn import *
context.arch = 'thumb'
context.bits = 32
# Serial connection
io = serialtube('/dev/ttyACM0', 115200)
Static Analysis¶
# Disassembly
arm-none-eabi-objdump -d lab.elf
# Symbols
arm-none-eabi-nm lab.elf
# Sections
arm-none-eabi-readelf -S lab.elf
Best Practices¶
For Learning¶
- Understand Before Exploiting: Read the vulnerable code first
- Document Your Process: Keep notes on what works and why
- Test Incrementally: Build exploits step by step
- Learn From Failures: Crashes provide valuable information
For Real Systems¶
- Input Validation: Never trust external input
- Safe Functions: Use bounded string operations
- Compiler Protections: Enable all available mitigations
- Defense in Depth: Layer multiple security measures
- Regular Audits: Review code for vulnerability patterns
Resources¶
Recommended Reading¶
- The ARM Cortex-M3 Technical Reference Manual
- Smashing The Stack For Fun And Profit
- Exploiting Format String Vulnerabilities
- The Embedded Systems Security Handbook
Online Resources¶
Community¶
- EMBSEC Discord Server
- /r/embedded security subreddit
- Embedded Security Slack
Contributing¶
Found a bug or have an improvement? We welcome contributions!
- Fork the repository
- Create a feature branch
- Add your lab or improvement
- Submit a pull request
See CONTRIBUTING.md for detailed guidelines.
License¶
These labs are provided for educational purposes only. Do not use these techniques on systems you don't own or without explicit permission.
"Those who do not learn from history are doomed to repeat it." - George Santayana
Happy hacking! 🛡️