Skip to content

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

  1. Start the development container:

    cd embsec-kit
    docker-compose up -d
    docker exec -it embsec-dev bash
    

  2. Flash the target binary:

    cd /labs/01-buffer-overflow
    make flash
    

  3. Connect to the serial console:

    screen /dev/ttyACM0 115200
    

  4. Reset the board (if needed):

  5. Press Ctrl+A, then K to kill screen session
  6. 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

  1. Start with Lab 01 (Buffer Overflow)
  2. Read the historical context carefully
  3. Use the debug menu to understand memory layout
  4. Follow hints before attempting exploitation
  5. Compare your solution with the provided writeup

Advanced Path

  1. Try solving without debug information
  2. Combine vulnerabilities for advanced exploits
  3. Bypass additional protections when enabled
  4. Write ROP chains for code reuse attacks
  5. 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

# GDB with ARM support
arm-none-eabi-gdb lab.elf
(gdb) target remote :3333
(gdb) monitor reset halt

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

  1. Understand Before Exploiting: Read the vulnerable code first
  2. Document Your Process: Keep notes on what works and why
  3. Test Incrementally: Build exploits step by step
  4. Learn From Failures: Crashes provide valuable information

For Real Systems

  1. Input Validation: Never trust external input
  2. Safe Functions: Use bounded string operations
  3. Compiler Protections: Enable all available mitigations
  4. Defense in Depth: Layer multiple security measures
  5. Regular Audits: Review code for vulnerability patterns

Resources

Online Resources

Community

  • EMBSEC Discord Server
  • /r/embedded security subreddit
  • Embedded Security Slack

Contributing

Found a bug or have an improvement? We welcome contributions!

  1. Fork the repository
  2. Create a feature branch
  3. Add your lab or improvement
  4. 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! 🛡️