diff --git a/src/core/shell.cpp b/src/core/shell.cpp index 80ee917..cb6fa8f 100644 --- a/src/core/shell.cpp +++ b/src/core/shell.cpp @@ -12,9 +12,7 @@ Module* makeBusDump(); Module* makeCrypto(); Module* makeExfil(); Module* makeThemePicker(); -Module* makeCan(); Module* makeUartPlus(); -Module* makeProtocol(); Module* makeMemSearch(); Module* makeSessionLogger(); Module* makeInjector(); @@ -22,35 +20,16 @@ Module* makeScope(); Module* makeWizard(); Module* makeSettings(); Module* makeUsbShell(); -Module* makeCryptoAttack(); -Module* makeMemEditor(); -Module* makeBootExp(); Module* makeFwPatch(); -Module* makePrivEsc(); -Module* makeDma(); -Module* makeHidInjector(); -Module* makeUsbGadget(); -Module* makeJtagUsbBridge(); -Module* makeRndisBridge(); -Module* makeUsbSniffer(); -Module* makePolyglot(); -Module* makeWiFiDash(); -Module* makeBtDominator(); -Module* makeEthernetRouter(); -Module* makeWiFiClone(); Module* makeExploitChain(); Module* makeHoneypot(); -Module* makeUniversalProto(); -Module* makeIoTSwarm(); -Module* makeIndustrialScada(); -Module* makeVehicleComm(); -Module* makeMessageForge(); Module* makeUIStudio(); -Module* makeTerminalShell(); -Module* makePacketSniffer(); -Module* makeProcessMonitor(); Module* makeActiveExploit(); Module* makeLogViewer(); +Module* makeWiFiScan(); +Module* makeI2CProbe(); +Module* makeSPIFlashID(); +Module* makeLogicProbes(); void Shell::begin() { theme::load(); @@ -63,9 +42,7 @@ void Shell::begin() { add(makeCrypto()); add(makeExfil()); add(makeThemePicker()); - add(makeCan()); add(makeUartPlus()); - add(makeProtocol()); add(makeMemSearch()); add(makeSessionLogger()); add(makeInjector()); @@ -73,48 +50,40 @@ void Shell::begin() { add(makeWizard()); add(makeSettings()); add(makeUsbShell()); - add(makeCryptoAttack()); - add(makeMemEditor()); - add(makeBootExp()); add(makeFwPatch()); - add(makePrivEsc()); - add(makeDma()); - add(makeHidInjector()); - add(makeUsbGadget()); - add(makeJtagUsbBridge()); - add(makeRndisBridge()); - add(makeUsbSniffer()); - add(makePolyglot()); - add(makeWiFiDash()); - add(makeBtDominator()); - add(makeEthernetRouter()); - add(makeWiFiClone()); add(makeExploitChain()); add(makeHoneypot()); - add(makeUniversalProto()); - add(makeIoTSwarm()); - add(makeIndustrialScada()); - add(makeVehicleComm()); - add(makeMessageForge()); add(makeUIStudio()); - add(makeTerminalShell()); - add(makePacketSniffer()); - add(makeProcessMonitor()); add(makeActiveExploit()); add(makeLogViewer()); + add(makeWiFiScan()); + add(makeI2CProbe()); + add(makeSPIFlashID()); + add(makeLogicProbes()); ui::bootSplash(); drawMenu(true); } void Shell::drawMenu(bool force) { auto& d = M5.Display; + constexpr int ROWH = 12; + constexpr int VIS = (ui::BODY_H / ROWH) - 1; // visible rows (top line = page indicator) + // keep selection in view + if (sel < top) top = sel; + if (sel >= top + VIS) top = sel - VIS + 1; if (force) { d.fillScreen(ui::bg()); ui::titleBar("Card-Crack", CARDCRACK_VERSION); - d.setTextColor(ui::fg(), ui::bg()); + ui::clearBody(); d.setTextSize(1); - for (int i = 0; i < nmods; i++) { - d.setCursor(5, ui::BODY_Y + i * 12 + 1); + d.setTextColor(ui::dim(), ui::bg()); + d.setCursor(5, ui::BODY_Y + 1); + d.printf("%d/%d modules (;/. nav)", nmods, nmods); + for (int r = 0; r < VIS; r++) { + int i = top + r; + if (i >= nmods) break; + d.setTextColor(ui::fg(), ui::bg()); + d.setCursor(5, ui::BODY_Y + (r + 1) * ROWH + 1); d.printf(" %-9s %s", mods[i]->name(), mods[i]->blurb()); } ui::hintBar("; up . down enter open home-lab only"); @@ -125,10 +94,12 @@ void Shell::drawMenu(bool force) { for (int k = 0; k < 2; k++) { int i = rows[k]; if (i < 0 || i >= nmods) continue; + int r = i - top; + if (r < 0 || r >= VIS) continue; bool cur = (i == sel); - int y = ui::BODY_Y + i * 12; + int y = ui::BODY_Y + (r + 1) * ROWH; uint16_t sb = cur ? ui::mix(theme::active().panel, theme::active().accent, 0.25f + 0.25f * ui::pulse(900)) : ui::bg(); - d.fillRect(0, y, ui::W, 12, sb); + d.fillRect(0, y, ui::W, ROWH, sb); d.setTextColor(cur ? ui::accent() : ui::fg(), sb); d.setTextSize(1); d.setCursor(5, y + 1); diff --git a/src/core/shell.h b/src/core/shell.h index 5facb71..507fe93 100644 --- a/src/core/shell.h +++ b/src/core/shell.h @@ -12,6 +12,7 @@ private: Module* mods[MAX]; int nmods = 0; int sel = 0; // menu cursor int active = -1; // -1 == in menu + int top = 0; // first visible menu row uint32_t lastTick = 0; void add(Module* m) { if (nmods < MAX) mods[nmods++] = m; } void drawMenu(bool force = false); diff --git a/src/modules/attackvis.cpp b/src/modules/attackvis.cpp index 2b10806..6ebe262 100644 --- a/src/modules/attackvis.cpp +++ b/src/modules/attackvis.cpp @@ -1,79 +1,53 @@ #include "../core/module.h" #include "../core/ui.h" +#include -// Active Exploit: real attack execution with progress feedback. -// Actually run exploits via Exploit Chain module, show real execution stages with feedback. -// Display real privilege escalation, real shell spawning, actual exfiltration data. +// Bench Assistant: live system telemetry for THIS device (heap, temp, SD, +// uptime) plus a quick self-test. Honest diagnostics — replaces the old +// "active exploit" theater module. -class ActiveExploit : public Module { - enum Stage { SCANNING, ENUMERATING, EXPLOITING, ESCALATING, EXFILTRATING, DONE } stage = SCANNING; +class BenchDiag : public Module { bool running = false; - uint32_t stageTime = 0; - uint32_t bytesExfed = 0; - uint32_t targetsCompromised = 0; + uint32_t freeHeap = 0, minHeap = 0; + float tempC = 0; + bool sdOk = false; char msg[3][40] = {{0},{0},{0}}; public: - const char* name() const override { return "Active Exploit"; } - const char* blurb() const override { return "real exploit execution"; } + const char* name() const override { return "Bench Diag"; } + const char* blurb() const override { return "self telemetry + selftest"; } - void onEnter() override { - running = false; - stage = SCANNING; - stageTime = 0; - bytesExfed = 0; - targetsCompromised = 0; - say("Exploit ready: [space] to start"); - } + void onEnter() override { running = false; say("[space] run self-test"); } void onExit() override { running = false; } bool onKey(char c) override { - if (c == ' ') { if (!running) { startExploit(); } else { running = false; } return true; } + if (c == ' ') { running = true; say("self-test running..."); return true; } return false; } void tick() override { if (!running) return; + freeHeap = ESP.getFreeHeap(); + minHeap = ESP.getMinFreeHeap(); + tempC = temperatureRead(); + sdOk = SD.begin(); + running = false; - stageTime++; - - // Real exploit orchestration via Exploit Chain - // Actual stages: scan → enum → exploit → escalate → exfil - if (stageTime == 100 && stage == SCANNING) { stage = ENUMERATING; stageTime = 0; } - if (stageTime == 100 && stage == ENUMERATING) { stage = EXPLOITING; stageTime = 0; } - if (stageTime == 150 && stage == EXPLOITING) { stage = ESCALATING; stageTime = 0; } - if (stageTime == 100 && stage == ESCALATING) { stage = EXFILTRATING; stageTime = 0; } - if (stageTime == 200 && stage == EXFILTRATING) { stage = DONE; running = false; targetsCompromised++; } - - // Real data during exfiltration - if (stage == EXFILTRATING) { - bytesExfed += (512 + (stageTime % 512)); - } + say("heap free %lu KB", (unsigned long)(freeHeap / 1024)); + say("heap min %lu KB", (unsigned long)(minHeap / 1024)); + say("temp %.1fC SD %s", tempC, sdOk ? "ok" : "MISSING"); + say("self-test complete"); } void draw() override { - const char* sn[] = {"SCAN", "ENUM", "EXPLOIT", "ESCALATE", "EXFIL", "DONE"}; - uint16_t col = ui::accent(); - if (stage == EXPLOITING || stage == ESCALATING) col = ui::warn(); - if (stage == EXFILTRATING) col = ui::glow(); - - ui::lineC(0, col, "%s [%u%%]", sn[stage], (running ? stageTime : 0) % 100); - - if (running) { - ui::bar(2, stageTime / (stage == EXFILTRATING ? 200.0f : 150.0f), col, sn[stage]); - } else if (targetsCompromised > 0) { - ui::lineC(2, ui::glow(), "COMPROMISED: %u targets", targetsCompromised); - } else { - ui::line(2, "status: ready"); - } - - if (stage == EXFILTRATING) { - ui::line(3, "Exfiltrated: %u KB", bytesExfed / 1024); - } - - for (int i = 0; i < 3; i++) ui::line(7 + i, "%s", msg[i]); + ui::lineC(0, ui::accent(), "Bench Diag %s", running ? "TEST" : "ready"); + ui::line(1, "heap: %lu KB (min %lu KB)", (unsigned long)(freeHeap / 1024), (unsigned long)(minHeap / 1024)); + ui::line(2, "cpu temp: %.1f C", tempC); + ui::line(3, "microSD: %s", sdOk ? "mounted" : "not detected"); + ui::line(4, "uptime: %lu s", (unsigned long)(millis() / 1000)); + for (int i = 0; i < 3; i++) ui::line(5 + i, "%s", msg[i]); if (running) ui::spinner(228, ui::BODY_Y + 1, ui::glow()); - ui::hintBar("[space]exploit [`]back"); + ui::hintBar("[space]test [`]back"); } private: @@ -81,14 +55,6 @@ private: for (int i = 2; i > 0; i--) strncpy(msg[i], msg[i-1], 39); va_list ap; va_start(ap, fmt); vsnprintf(msg[0], 40, fmt, ap); va_end(ap); } - - void startExploit() { - running = true; - stage = SCANNING; - stageTime = 0; - bytesExfed = 0; - say("Starting real exploit chain..."); - } }; -Module* makeActiveExploit() { return new ActiveExploit(); } +Module* makeActiveExploit() { return new BenchDiag(); } diff --git a/src/modules/bootexp.cpp b/src/modules/bootexp.cpp deleted file mode 100644 index 3affb1a..0000000 --- a/src/modules/bootexp.cpp +++ /dev/null @@ -1,115 +0,0 @@ -#include "../core/module.h" -#include "../core/ui.h" -#include "../core/pins.h" - -// Bootloader Exploit: detect bootloader types, try default passwords, bypass security, -// unlock boot mode, attempt rollback to older firmware versions. -// For boards you own; useful for unbricking or firmware modification. - -class BootExp : public Module { - enum Loader { UBOOT, ESPROM, MEDIATEK, UNKNOWN } loader = UNKNOWN; - HardwareSerial& port = Serial1; - bool detected = false; - bool unlocked = false; - uint32_t attempts = 0; - char msg[3][40] = {{0},{0},{0}}; - -public: - const char* name() const override { return "Boot Exploit"; } - const char* blurb() const override { return "bootloader detect + bypass"; } - - void onEnter() override { - port.begin(115200, SERIAL_8N1, pins::GROVE_A, pins::GROVE_B); - detected = false; - unlocked = false; - attempts = 0; - detect(); - } - void onExit() override { port.end(); } - - bool onKey(char c) override { - if (c == 'd') { detect(); return true; } - if (c == 't') { tryDefaultPwd(); return true; } - if (c == 'b') { tryBypass(); return true; } - if (c == 'r') { tryRollback(); return true; } - return false; - } - - void draw() override { - const char* ln[] = {"U-Boot", "ESP-ROM", "MediaTek", "Unknown"}; - ui::lineC(0, ui::accent(), "%s %s", ln[loader], unlocked ? "UNLOCKED" : "locked"); - ui::line(1, "detected: %s attempts: %lu", detected ? "yes" : "no", (unsigned long)attempts); - for (int i = 0; i < 3; i++) ui::line(3 + i, "%s", msg[i]); - ui::hintBar("[d]etect [t]ry-pwd [b]ypass [r]ollback [`]back"); - } - -private: - void say(const char* fmt, ...) { - for (int i = 2; i > 0; i--) strncpy(msg[i], msg[i-1], 39); - va_list ap; va_start(ap, fmt); vsnprintf(msg[0], 40, fmt, ap); va_end(ap); - } - - void detect() { - port.write("\r\n\r\n"); - delay(100); - - String resp = ""; - uint32_t t0 = millis(); - while (millis() - t0 < 500 && port.available()) { - resp += (char)port.read(); - } - - if (resp.indexOf("U-Boot") >= 0) { loader = UBOOT; detected = true; } - else if (resp.indexOf("ets Jun") >= 0) { loader = ESPROM; detected = true; } - else if (resp.indexOf("MTK") >= 0) { loader = MEDIATEK; detected = true; } - else { loader = UNKNOWN; } - - say("detected: %s", detected ? "yes" : "no"); - } - - void tryDefaultPwd() { - if (!detected) { say("detect first"); return; } - - static const char* pwds[] = {"admin", "password", "1234", ""}; - for (auto pwd : pwds) { - port.printf("%s\r\n", pwd); - attempts++; - delay(100); - if (port.available()) { - String resp = ""; - while (port.available()) resp += (char)port.read(); - if (resp.indexOf("password") < 0 && resp.indexOf("denied") < 0) { - unlocked = true; - say("pwd OK: %s", pwd[0] ? pwd : "(blank)"); - return; - } - } - } - say("no match"); - } - - void tryBypass() { - if (loader == UBOOT) { - // U-Boot bypass: hit Ctrl-C during boot countdown - port.write(0x03); // Ctrl-C - delay(100); - port.printf("setenv bootdelay 0\r\n"); - say("U-Boot: bypass attempted"); - } else if (loader == ESPROM) { - // ESP-ROM: use ROM command mode (0xc0 sync byte) - port.write(0xc0); - port.write(0xc0); - delay(50); - say("ESP-ROM: sync attempted"); - unlocked = true; - } - } - - void tryRollback() { - if (!unlocked) { say("must unlock first"); return; } - say("rollback: erase OTA flag (stub)"); - // Real impl: erase OTA status flag so device boots old firmware - } -}; - -Module* makeBootExp() { return new BootExp(); } diff --git a/src/modules/btdominator.cpp b/src/modules/btdominator.cpp deleted file mode 100644 index a041c5b..0000000 --- a/src/modules/btdominator.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#include "../core/module.h" -#include "../core/ui.h" - -// Bluetooth Dominator: force BT connections, spoof devices, create BT tunnel. -// Scan nearby, force pair without PIN, create serial port profile, intercept traffic. -// Acts as BT man-in-the-middle or rogue BT peripheral. - -class BtDominator : public Module { - enum Mode { SCAN_PAIR, SERIAL_BRIDGE, MITM, SPOOF } mode = SCAN_PAIR; - bool active = false; - uint32_t devicesFound = 0; - uint32_t packetsSniffer = 0; - char targetAddr[18] = "00:00:00:00:00:00"; - char msg[3][40] = {{0},{0},{0}}; - -public: - const char* name() const override { return "BT Dominator"; } - const char* blurb() const override { return "force BT connections"; } - - void onEnter() override { - active = false; - devicesFound = 0; - packetsSniffer = 0; - say("BT scanner ready"); - if (startBtScan()) { - active = true; - say("Scanning for BT devices..."); - } - } - void onExit() override { active = false; } - - bool onKey(char c) override { - if (c == 'm') { mode = (Mode)((mode + 1) % 4); return true; } - if (c == 'p') { if (devicesFound > 0) forcePair(); return true; } - return false; - } - - void tick() override { - if (!active) return; - - if (devicesFound < 8) { - devicesFound++; - if (devicesFound == 2) say("BT: device -45dBm @08:92:1A"); - if (devicesFound == 4) say("BT: device -52dBm @BD:55:8E"); - if (devicesFound == 6) say("BT: device -38dBm @C4:3D:5F"); - if (devicesFound == 8) say("8 devices found, [p]air"); - } - - if (mode == MITM && devicesFound >= 2) { - packetsSniffer++; - if (packetsSniffer == 50) say("BT MITM: intercepting L2CAP"); - if (packetsSniffer == 100) say("Captured: 2.3KB encrypted traffic"); - } - } - - void draw() override { - const char* mn[] = {"SCAN/PAIR", "SERIAL", "MITM", "SPOOF"}; - ui::lineC(0, ui::accent(), "BT Dominator: %s %s", mn[mode], active ? "ACTIVE" : "idle"); - ui::line(1, "target: %s", targetAddr); - ui::line(2, "devices found: %lu", (unsigned long)devicesFound); - if (mode == MITM) ui::bar(3, packetsSniffer / 150.0f, ui::glow(), "sniff"); - for (int i = 0; i < 3; i++) ui::line(5 + i, "%s", msg[i]); - if (active) ui::spinner(228, ui::BODY_Y + 1, ui::glow()); - ui::hintBar("[m]ode [p]air [`]back"); - } - -private: - void say(const char* fmt, ...) { - for (int i = 2; i > 0; i--) strncpy(msg[i], msg[i-1], 39); - va_list ap; va_start(ap, fmt); vsnprintf(msg[0], 40, fmt, ap); va_end(ap); - } - - bool startBtScan() { - // Real impl: use BlueZ or NimBLE to scan, dump addresses/RSSI/services - // Stub: simulate scan results - return true; - } - - void forcePair() { - // Attempt to pair without PIN via LMP spoofing or service fuzzing - // Real: BlueZ pairing agent bypass, LMP packet injection - switch (mode) { - case SCAN_PAIR: - say("Forcing pair to %s...", targetAddr); - say("Bypassing PIN requirement"); - break; - case SERIAL_BRIDGE: - say("Creating RFCOMM serial port"); - say("Tunnel ready at /dev/rfcomm0"); - break; - case MITM: - say("Positioning as MITM proxy"); - say("Intercepting GATT/L2CAP"); - break; - case SPOOF: - say("Spoofing device %s", targetAddr); - say("Advertising malicious services"); - break; - } - } -}; - -Module* makeBtDominator() { return new BtDominator(); } diff --git a/src/modules/can.cpp b/src/modules/can.cpp deleted file mode 100644 index 4d4c0ad..0000000 --- a/src/modules/can.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include "../core/module.h" -#include "../core/ui.h" -#include "../core/pins.h" -#include -#include - -// CAN Bus sniffer. Listen on MCP2515 over SPI for OBD/automotive frames. -// Passive only; displays frame ID, DLC, data; logs to SD. - -class CanSniff : public Module { - static constexpr int CS = pins::PROBE[0]; - bool running = false, sdOk = false; - uint32_t fcount = 0, lastMs = 0; - uint8_t speed = 0; // 0=500k, 1=250k, 2=125k - char msg[3][40] = {{0},{0},{0}}; - File logfile; - -public: - const char* name() const override { return "CAN Bus"; } - const char* blurb() const override { return "OBD/automotive sniffer"; } - - void onEnter() override { - running = false; fcount = 0; - sdOk = SD.begin(); - initMcp2515(); - } - void onExit() override { running = false; if (logfile) logfile.close(); } - - bool onKey(char c) override { - if (c == ' ') { running = !running; if (running) fcount = 0; return true; } - if (c == 's') { speed = (speed + 1) % 3; initMcp2515(); return true; } - if (c == 'c') { fcount = 0; say("cleared"); return true; } - return false; - } - - void tick() override { - if (!running) return; - if (millis() - lastMs < 50) return; - lastMs = millis(); - uint32_t id = 0; uint8_t dlc = 0, data[8] = {0}; - if (readFrame(id, dlc, data)) { - fcount++; - if (sdOk && !logfile) { - SD.mkdir("/logs"); - logfile = SD.open("/logs/can.txt", FILE_APPEND); - } - if (logfile) logfile.printf("%08lX %d [", (unsigned long)id, dlc); - for (int i = 0; i < dlc; i++) { - if (logfile) logfile.printf("%02X ", data[i]); - } - if (logfile) logfile.println("]"); - } - } - - void draw() override { - const char* sp[] = {"500k", "250k", "125k"}; - ui::lineC(0, ui::accent(), "CAN %s %s", sp[speed], running ? "LISTEN" : "idle"); - ui::line(1, "frames: %lu", (unsigned long)fcount); - for (int i = 0; i < 3; i++) ui::line(3 + i, "%s", msg[i]); - if (running) ui::spinner(228, ui::BODY_Y + 1, ui::glow()); - ui::hintBar("[s]peed [c]lear [space]go [`]back"); - } - -private: - void say(const char* fmt, ...) { - for (int i = 2; i > 0; i--) strncpy(msg[i], msg[i-1], 39); - va_list ap; va_start(ap, fmt); vsnprintf(msg[0], 40, fmt, ap); va_end(ap); - } - - void initMcp2515() { - SPI.begin(pins::PROBE[3], pins::PROBE[4], pins::PROBE[5], CS); - pinMode(CS, OUTPUT); digitalWrite(CS, HIGH); - // Reset + config for passive listening (stub; real impl uses full MCP2515 init) - say("CAN init %s", speed < 3 ? "ok" : "fail"); - } - - bool readFrame(uint32_t& id, uint8_t& dlc, uint8_t* data) { - // Stub: real impl reads MCP2515 RXn buffers via SPI - // For now, return false (no frames) - return false; - } -}; - -Module* makeCan() { return new CanSniff(); } diff --git a/src/modules/cryptoattack.cpp b/src/modules/cryptoattack.cpp deleted file mode 100644 index 9032f30..0000000 --- a/src/modules/cryptoattack.cpp +++ /dev/null @@ -1,89 +0,0 @@ -#include "../core/module.h" -#include "../core/ui.h" -#include "mbedtls/md5.h" -#include "mbedtls/sha1.h" -#include - -// Crypto Attack Suite: weak key detection, dictionary attacks, hash cracking. -// Tests common patterns (default creds, weak passwords, repeated keys). -// Manual-trigger only; builds wordlists from dumped firmware. - -class CryptoAttack : public Module { - enum Attack { DICT, WEAK_KEY, HASH_CRACK } attack = DICT; - static const char* WORDLIST[]; - static const int WCOUNT = 24; - - bool running = false; - uint32_t tested = 0, cracked = 0; - char target[32] = ""; - char found[40] = ""; - char msg[3][40] = {{0},{0},{0}}; - -public: - const char* name() const override { return "Crypto Attack"; } - const char* blurb() const override { return "dict/weak-key/hash crack"; } - - void onEnter() override { running = false; tested = 0; cracked = 0; say("ready"); } - void onExit() override { running = false; } - - bool onKey(char c) override { - if (c == 'a') { attack = (Attack)((attack + 1) % 3); running = false; return true; } - if (c == ' ') { running = !running; if (running) { tested = 0; cracked = 0; } return true; } - return false; - } - - void tick() override { - if (!running) return; - if (tested >= WCOUNT) { running = false; say("-- done --"); return; } - - const char* word = WORDLIST[tested]; - - if (attack == DICT) { - // Stub: would test login/hash against known targets - tested++; - } else if (attack == WEAK_KEY) { - // Check for weak patterns: repeated bytes, sequential, all-zero, etc. - if (isWeakKey(word)) { cracked++; snprintf(found, sizeof(found), "weak: %s", word); } - tested++; - } else if (attack == HASH_CRACK) { - // MD5/SHA1 against wordlist - uint8_t md5out[16]; - mbedtls_md5((const uint8_t*)word, strlen(word), md5out); - // Would compare md5out against target hash - tested++; - } - } - - void draw() override { - const char* an[] = {"DICT", "WEAK_KEY", "HASH_CRACK"}; - ui::lineC(0, ui::accent(), "%s attack %s", an[attack], running ? "GO" : "idle"); - ui::line(1, "tested: %lu cracked: %lu", (unsigned long)tested, (unsigned long)cracked); - if (cracked) ui::lineC(2, ui::glow(), "%s", found); - for (int i = 0; i < 3; i++) ui::line(4 + i, "%s", msg[i]); - if (running) ui::spinner(228, ui::BODY_Y + 1, ui::glow()); - ui::hintBar("[a]ttack [space]go [`]back"); - } - -private: - void say(const char* fmt, ...) { - for (int i = 2; i > 0; i--) strncpy(msg[i], msg[i-1], 39); - va_list ap; va_start(ap, fmt); vsnprintf(msg[0], 40, fmt, ap); va_end(ap); - } - - bool isWeakKey(const char* word) { - // Detect repeated bytes: "aaaa", "1111", etc. - if (strlen(word) < 4) return false; - char c = word[0]; - for (int i = 1; i < 4; i++) if (word[i] != c) return false; - return true; - } -}; - -const char* CryptoAttack::WORDLIST[] = { - "admin", "password", "123456", "qwerty", "abc123", "letmein", - "welcome", "monkey", "password123", "admin123", "root", "toor", - "12345678", "password1", "123123", "1q2w3e4r", "qwertyuiop", "1234567890", - "000000", "111111", "aaaaaa", "123456789", "default", "guest" -}; - -Module* makeCryptoAttack() { return new CryptoAttack(); } diff --git a/src/modules/datastream.cpp b/src/modules/datastream.cpp deleted file mode 100644 index 3d39584..0000000 --- a/src/modules/datastream.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include "../core/module.h" -#include "../core/ui.h" - -// Packet Sniffer: real network packet capture and hex dump display. -// Actual packet data from UART/USB/network interface, real hex dumps, real protocols. -// Display actual captured network traffic, not fake data. - -class PacketSniffer : public Module { - enum Source { UART_UART, USB_HOST, NETWORK_BRIDGE } source = UART_UART; - bool sniffing = false; - uint32_t packetCount = 0; - uint32_t bytesCaptured = 0; - uint32_t displayOffset = 0; - char msg[3][40] = {{0},{0},{0}}; - -public: - const char* name() const override { return "Packet Sniffer"; } - const char* blurb() const override { return "real packet capture"; } - - void onEnter() override { - sniffing = false; - packetCount = 0; - bytesCaptured = 0; - displayOffset = 0; - say("Sniffer: ready"); - } - void onExit() override { if (sniffing) stopSniff(); } - - bool onKey(char c) override { - if (c == 's') { source = (Source)((source + 1) % 3); return true; } - if (c == ' ') { if (!sniffing) startSniff(); else stopSniff(); return true; } - if (c == '+') { displayOffset += 16; return true; } - if (c == '-' && displayOffset >= 16) { displayOffset -= 16; return true; } - return false; - } - - void tick() override { - if (!sniffing) return; - // Real impl: read actual packet data from UART/USB/network - // Parse packet headers, track statistics - bytesCaptured += (rand() % 256); - if (bytesCaptured % 1024 == 0) { - packetCount++; - say("[PKT %u] %u bytes", packetCount, bytesCaptured); - } - } - - void draw() override { - const char* sn[] = {"UART", "USB HOST", "NETWORK"}; - ui::lineC(0, ui::accent(), "Sniffer: %s %s", sn[source], sniffing ? "CAPTURING" : "idle"); - - // Display hex dump of captured data - ui::line(2, "0x%04x: [real packet data]", displayOffset); - ui::line(3, "packets: %lu bytes: %lu KB", (unsigned long)packetCount, (unsigned long)(bytesCaptured/1024)); - - if (sniffing) { - ui::bar(4, (bytesCaptured % 4096) / 4096.0f, ui::glow(), "cap"); - } - - for (int i = 0; i < 3; i++) ui::line(7 + i, "%s", msg[i]); - if (sniffing) ui::spinner(228, ui::BODY_Y + 1, ui::glow()); - ui::hintBar("[s]ource [space]sniff [+/-]scroll [`]back"); - } - -private: - void say(const char* fmt, ...) { - for (int i = 2; i > 0; i--) strncpy(msg[i], msg[i-1], 39); - va_list ap; va_start(ap, fmt); vsnprintf(msg[0], 40, fmt, ap); va_end(ap); - } - - void startSniff() { - sniffing = true; - packetCount = 0; - bytesCaptured = 0; - say("Starting packet capture..."); - } - - void stopSniff() { - sniffing = false; - say("Capture stopped: %u packets", packetCount); - } -}; - -Module* makePacketSniffer() { return new PacketSniffer(); } diff --git a/src/modules/dma.cpp b/src/modules/dma.cpp deleted file mode 100644 index 93a75cd..0000000 --- a/src/modules/dma.cpp +++ /dev/null @@ -1,99 +0,0 @@ -#include "../core/module.h" -#include "../core/ui.h" - -// DMA Attack Simulator: memory-to-memory transfers with privilege bypass. -// On systems with a DMA controller or I/O-MMU, attempt to: -// - Read/write arbitrary addresses -// - Bypass MPU/paging restrictions -// - Exfiltrate kernel memory -// - Inject code via DMA into code regions - -class DmaAttack : public Module { - enum Target { KERNEL_MEM, IOCTL_ARGS, PAGE_TABLE } target = KERNEL_MEM; - uint32_t srcAddr = 0x40000000; // Assume kernel region start - uint32_t dstAddr = 0x20000000; // User SRAM - uint32_t size = 256; - uint32_t transferred = 0; - bool active = false; - char msg[3][40] = {{0},{0},{0}}; - -public: - const char* name() const override { return "DMA Attack"; } - const char* blurb() const override { return "memory-to-memory with privesc"; } - - void onEnter() override { - active = false; - transferred = 0; - say("DMA controller: probing..."); - } - void onExit() override { active = false; } - - bool onKey(char c) override { - if (c == 't') { target = (Target)((target + 1) % 3); return true; } - if (c == '+') { size = (size * 2 > 4096) ? 256 : size * 2; return true; } - if (c == 's') { startTransfer(); return true; } - return false; - } - - void tick() override { - if (!active) return; - if (transferred >= size) { active = false; say("-- transfer done --"); return; } - - // Simulate DMA: read from srcAddr, write to dstAddr - // Bypass normal CPU cache/MMU on each chunk - uint32_t chunk = 64; - if (transferred + chunk > size) chunk = size - transferred; - - // Attempt unprotected read/write - uint8_t* src = (uint8_t*)srcAddr; - uint8_t* dst = (uint8_t*)dstAddr; - - // Disable cache during "transfer" (hardware normally does this) - // memcpy(dst, src, chunk); // Stub: real DMA would bypass MMU - - transferred += chunk; - } - - void draw() override { - const char* tn[] = {"KERNEL", "IOCTL", "PGTBL"}; - ui::lineC(0, ui::accent(), "DMA: %s %s", tn[target], active ? "XFER" : "idle"); - ui::line(1, "src:0x%08lx dst:0x%08lx sz:%lu", (unsigned long)srcAddr, - (unsigned long)dstAddr, (unsigned long)size); - ui::bar(2, transferred / (float)size, ui::glow(), "dma"); - for (int i = 0; i < 3; i++) ui::line(4 + i, "%s", msg[i]); - ui::hintBar("[t]arget [+]size [s]tart [`]back"); - } - -private: - void say(const char* fmt, ...) { - for (int i = 2; i > 0; i--) strncpy(msg[i], msg[i-1], 39); - va_list ap; va_start(ap, fmt); vsnprintf(msg[0], 40, fmt, ap); va_end(ap); - } - - void startTransfer() { - // Attempt to configure DMA without privilege - // Real systems use MMIO to program DMA, check: - // - is DMA controller accessible from user space? - // - are address restrictions enforced by I/O-MMU? - - transferred = 0; - active = true; - - switch (target) { - case KERNEL_MEM: - srcAddr = 0x40000000; - say("DMA: read kernel @0x%08lx", (unsigned long)srcAddr); - break; - case IOCTL_ARGS: - srcAddr = 0x20010000; - say("DMA: snoop IOCTL args"); - break; - case PAGE_TABLE: - srcAddr = 0xC0000000; // Assume kernel page table - say("DMA: exfil page table"); - break; - } - } -}; - -Module* makeDma() { return new DmaAttack(); } diff --git a/src/modules/ethernetrouter.cpp b/src/modules/ethernetrouter.cpp deleted file mode 100644 index d39e868..0000000 --- a/src/modules/ethernetrouter.cpp +++ /dev/null @@ -1,107 +0,0 @@ -#include "../core/module.h" -#include "../core/ui.h" - -// Ethernet Router: turn Cardputer into full gateway with ARP spoofing, traffic interception. -// Proxy HTTP/HTTPS, capture credentials, inject payloads mid-flight, DNS poisoning. -// Acts as transparent man-in-the-middle for entire wired network segment. - -class EthernetRouter : public Module { - enum Feature { GATEWAY, ARP_SPOOF, HTTP_INTERCEPT, DNS_POISON } feature = GATEWAY; - bool active = false; - uint32_t gatewayIp = 0xC0A80101; // 192.168.1.1 - uint32_t hostCount = 0; - uint32_t intercepted = 0; - char msg[3][40] = {{0},{0},{0}}; - -public: - const char* name() const override { return "Ethernet Router"; } - const char* blurb() const override { return "MITM gateway/ARP spoof"; } - - void onEnter() override { - active = false; - hostCount = 0; - intercepted = 0; - say("Ethernet: configuring gateway"); - if (startRouting()) { - active = true; - say("Gateway active: 192.168.1.1"); - } - } - void onExit() override { if (active) stopRouting(); } - - bool onKey(char c) override { - if (c == 'f') { feature = (Feature)((feature + 1) % 4); return true; } - if (c == ' ') { active = !active; return true; } - return false; - } - - void tick() override { - if (!active) return; - - // Simulate ARP spoofing and traffic interception - if (hostCount < 12) { - hostCount++; - if (hostCount % 3 == 0) say("ARP: spoofed %u hosts", hostCount); - } - - if (feature == HTTP_INTERCEPT) { - intercepted++; - if (intercepted == 50) say("HTTP: captured 3 requests"); - if (intercepted == 100) say("Creds: user/pass logged"); - if (intercepted == 150) say("Injecting payload into response"); - } - } - - void draw() override { - const char* fn[] = {"GATEWAY", "ARP SPOOF", "HTTP INTERCEPT", "DNS POISON"}; - ui::lineC(0, ui::accent(), "Ethernet Router: %s", fn[feature]); - ui::line(1, "Gateway: 192.168.1.1 hosts: %lu", (unsigned long)hostCount); - if (feature == HTTP_INTERCEPT) { - ui::bar(2, intercepted / 200.0f, ui::glow(), "intercept"); - ui::lineC(3, ui::glow(), "MITM: active"); - } else if (feature == DNS_POISON) { - ui::lineC(2, ui::glow(), "DNS: spoofing *.internal"); - } else { - ui::bar(2, hostCount / 12.0f, active ? ui::glow() : ui::dim(), "arp"); - } - for (int i = 0; i < 3; i++) ui::line(5 + i, "%s", msg[i]); - if (active) ui::spinner(228, ui::BODY_Y + 1, ui::glow()); - ui::hintBar("[f]eature [space]toggle [`]back"); - } - -private: - void say(const char* fmt, ...) { - for (int i = 2; i > 0; i--) strncpy(msg[i], msg[i-1], 39); - va_list ap; va_start(ap, fmt); vsnprintf(msg[0], 40, fmt, ap); va_end(ap); - } - - bool startRouting() { - // Real impl: configure iptables NAT, ARP spoofing, traffic interception - // Use: arpspoof, mitmproxy, dsnmasq, ebtables for transparent bridging - switch (feature) { - case GATEWAY: - say("NAT: enabling ip_forward"); - say("DHCP: 192.168.1.100-200"); - break; - case ARP_SPOOF: - say("ARP: scanning subnet"); - say("ARP: becoming default gateway"); - break; - case HTTP_INTERCEPT: - say("Intercepting HTTP (port 80)"); - say("Transparent proxy: localhost:3128"); - break; - case DNS_POISON: - say("DNS: intercepting :53"); - say("Poisoning all A records"); - break; - } - return true; - } - - void stopRouting() { - say("Routing: disabling gateway"); - } -}; - -Module* makeEthernetRouter() { return new EthernetRouter(); } diff --git a/src/modules/exploitchain.cpp b/src/modules/exploitchain.cpp index a4eac29..125d71c 100644 --- a/src/modules/exploitchain.cpp +++ b/src/modules/exploitchain.cpp @@ -1,95 +1,95 @@ #include "../core/module.h" #include "../core/ui.h" +#include "../core/pins.h" +#include -// Exploit Chain: automated attack workflow - scan → enumerate → exploit → escalate → exfil. -// Links multiple modules together: pin scan finds UART, UART sniff identifies protocol, -// sends payload via injector, escalates privileges, downloads memory. -// One-button full compromise chain. +// Auto-Recon: real bench workflow — voltage sense → UART baud probe → +// capture → SD log. Every stage measures actual hardware; no simulated +// results. Replaces the old "exploit chain" theater. -class ExploitChain : public Module { - enum Stage { SCAN, ENUM, EXPLOIT, ESCALATE, EXFIL, DONE } stage = SCAN; - bool running = false; - uint32_t progress = 0; - uint32_t targetsChained = 0; - char targetName[40] = "unknown device"; +class ReconChain : public Module { + enum Stage { IDLE, VSENSE, BAUD, CAPTURE, LOGGED, FAIL } stage = IDLE; + uint32_t mv = 0; + uint32_t foundBaud = 0; + uint32_t captured = 0; char msg[3][40] = {{0},{0},{0}}; + static const int NBAUDS = 6; + static const long BAUDS[NBAUDS]; + public: - const char* name() const override { return "Exploit Chain"; } - const char* blurb() const override { return "auto attack workflow"; } + const char* name() const override { return "Auto Recon"; } + const char* blurb() const override { return "sense>probe>capture>log"; } void onEnter() override { - running = false; - progress = 0; - targetsChained = 0; - say("Chain executor ready"); + stage = IDLE; mv = 0; foundBaud = 0; captured = 0; + say("[space] run full recon chain"); } - void onExit() override { running = false; } + void onExit() override { Serial1.end(); } bool onKey(char c) override { - if (c == ' ') { running = !running; if (running) startChain(); return true; } + if (c == ' ' && stage == IDLE) { stage = VSENSE; say("stage 1: voltage sense"); return true; } return false; } void tick() override { - if (!running) return; + if (stage == IDLE || stage == FAIL || stage == LOGGED) return; - progress++; - - switch (stage) { - case SCAN: - if (progress == 10) say("1. Pin scan: UART @RX/TX found"); - if (progress == 30) { stage = ENUM; progress = 0; } - break; - case ENUM: - if (progress == 10) say("2. Enum: 115200 baud, Linux CLI"); - if (progress == 25) { stage = EXPLOIT; progress = 0; } - break; - case EXPLOIT: - if (progress == 15) say("3. Exploit: buffer overflow @0x40"); - if (progress == 30) { stage = ESCALATE; progress = 0; } - break; - case ESCALATE: - if (progress == 10) say("4. Escalate: ptrace() via UAF"); - if (progress == 25) say(" uid=0 shell achieved"); - if (progress == 30) { stage = EXFIL; progress = 0; } - break; - case EXFIL: - if (progress == 10) say("5. Exfil: dumping /dev/mem"); - if (progress == 20) say(" crypto keys extracted"); - if (progress == 30) { stage = DONE; say("-- FULL COMPROMISE --"); running = false; targetsChained++; } - break; - case DONE: - running = false; - break; + if (stage == VSENSE) { + // average a few ADC reads on the VSENSE pin (through external divider) + uint32_t acc = 0; + for (int i = 0; i < 16; i++) { acc += analogReadMilliVolts(pins::VSENSE_ADC); delay(2); } + mv = acc / 16; + say("target ~%lu mV", (unsigned long)mv); + stage = BAUD; + } + else if (stage == BAUD) { + // try each baud: look for any RX traffic within a window + foundBaud = 0; + for (int i = 0; i < NBAUDS && !foundBaud; i++) { + Serial1.begin(BAUDS[i], SERIAL_8N1, pins::PROBE[1], pins::PROBE[0]); + delay(60); + uint32_t n = 0; + uint32_t t0 = millis(); + while (millis() - t0 < 400) { if (Serial1.available()) { Serial1.read(); n++; } } + if (n >= 4) foundBaud = BAUDS[i]; + } + if (foundBaud) { say("UART alive @ %lu", (unsigned long)foundBaud); stage = CAPTURE; } + else { say("no UART traffic found"); stage = FAIL; } + } + else if (stage == CAPTURE) { + uint32_t t0 = millis(); + while (millis() - t0 < 1500) { + while (Serial1.available()) { Serial1.read(); captured++; } + } + say("captured %lu bytes", (unsigned long)captured); + if (captured && SD.begin()) { + SD.mkdir("/logs"); + File f = SD.open("/logs/recon.txt", FILE_APPEND); + if (f) { f.printf("%lu mV, %lu baud, %lu bytes\n", (unsigned long)mv, (unsigned long)foundBaud, (unsigned long)captured); f.close(); } + say("logged to /logs/recon.txt"); + } + stage = LOGGED; } } void draw() override { - const char* sn[] = {"SCAN", "ENUM", "EXPLOIT", "ESCALATE", "EXFIL", "DONE"}; - ui::lineC(0, ui::accent(), "Exploit Chain: %s %s", sn[stage], running ? "GO" : "idle"); - ui::line(1, "target: %s", targetName); - ui::bar(2, progress / 30.0f, running ? ui::glow() : ui::dim(), sn[stage]); - if (targetsChained > 0) ui::lineC(3, ui::glow(), "Compromised: %lu targets", (unsigned long)targetsChained); - for (int i = 0; i < 3; i++) ui::line(5 + i, "%s", msg[i]); - if (running) ui::spinner(228, ui::BODY_Y + 1, ui::glow()); - ui::hintBar("[space]run auto-chain [`]back"); + const char* sn[] = {"idle", "V-SENSE", "BAUD", "CAPTURE", "LOGGED", "no signal"}; + uint16_t col = stage == FAIL ? ui::bad() : ui::accent(); + ui::lineC(0, col, "Auto Recon: %s", sn[stage]); + ui::line(1, "voltage: %lu mV", (unsigned long)mv); + ui::line(2, "baud: %lu bytes: %lu", (unsigned long)foundBaud, (unsigned long)captured); + for (int i = 0; i < 3; i++) ui::line(4 + i, "%s", msg[i]); + if (stage != IDLE && stage != LOGGED && stage != FAIL) ui::spinner(228, ui::BODY_Y + 1, ui::glow()); + ui::hintBar("[space]run [`]back"); } - private: void say(const char* fmt, ...) { for (int i = 2; i > 0; i--) strncpy(msg[i], msg[i-1], 39); va_list ap; va_start(ap, fmt); vsnprintf(msg[0], 40, fmt, ap); va_end(ap); } - - void startChain() { - stage = SCAN; - progress = 0; - running = true; - say("Starting auto-chain..."); - // Real impl: orchestrate Pin Scan → UART Sniff → Injector → PrivEsc → Exfil - // Chain API calls between modules, pass results through pipeline - } }; -Module* makeExploitChain() { return new ExploitChain(); } +const long ReconChain::BAUDS[ReconChain::NBAUDS] = {9600, 19200, 38400, 57600, 115200, 230400}; + +Module* makeExploitChain() { return new ReconChain(); } diff --git a/src/modules/hidinjector.cpp b/src/modules/hidinjector.cpp deleted file mode 100644 index af1d856..0000000 --- a/src/modules/hidinjector.cpp +++ /dev/null @@ -1,108 +0,0 @@ -#include "../core/module.h" -#include "../core/ui.h" - -// HID Injector: Cardputer emulates a USB keyboard/mouse. Silently type commands -// on any host that plugs in. Inject keystrokes, mouse clicks, execute payloads. -// Auto-triggers on host detection; requires USB OTG in device mode (host sees Cardputer as keyboard). - -class HidInjector : public Module { - enum Type { KEYBOARD, MOUSE, BOTH } type = KEYBOARD; - bool active = false; - uint32_t sent = 0; - char payload[128] = "whoami\n"; - char msg[3][40] = {{0},{0},{0}}; - -public: - const char* name() const override { return "HID Inject"; } - const char* blurb() const override { return "USB keyboard/mouse emulation"; } - - void onEnter() override { - active = false; - sent = 0; - initUsb(); - say("HID device ready"); - if (detectHostConnection()) { - active = true; - say("Host detected, auto-injecting"); - } - } - void onExit() override { active = false; } - - bool onKey(char c) override { - if (c == 't') { type = (Type)((type + 1) % 3); return true; } - if (c == ' ') { active = !active; if (active) sent = 0; return true; } - if (c == 'p') { editPayload(); return true; } - return false; - } - - void tick() override { - if (!active || sent >= strlen(payload)) { active = false; return; } - - char ch = payload[sent++]; - uint8_t keycode = charToHid(ch); - - if (keycode) { - // Send HID keyboard report: [modifier, reserved, keycode1, 0, 0, 0, 0, 0] - uint8_t report[8] = {0, 0, keycode, 0, 0, 0, 0, 0}; - sendHidReport(report); - delay(50); - - // Release key - uint8_t release[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - sendHidReport(release); - delay(50); - } - } - - void draw() override { - const char* tn[] = {"KEYBOARD", "MOUSE", "BOTH"}; - ui::lineC(0, ui::accent(), "%s inject %s", tn[type], active ? "GO" : "idle"); - ui::line(1, "sent: %lu / %u payload: %s", (unsigned long)sent, (unsigned)strlen(payload), - payload[0] ? payload : "(empty)"); - for (int i = 0; i < 3; i++) ui::line(3 + i, "%s", msg[i]); - if (active) ui::spinner(228, ui::BODY_Y + 1, ui::glow()); - ui::hintBar("[t]ype [p]ayload [space]send [`]back"); - } - -private: - void say(const char* fmt, ...) { - for (int i = 2; i > 0; i--) strncpy(msg[i], msg[i-1], 39); - va_list ap; va_start(ap, fmt); vsnprintf(msg[0], 40, fmt, ap); va_end(ap); - } - - void initUsb() { - // Stub: on a real S3, configure USB OTG in device mode as HID keyboard - // This would use the TinyUSB or ESP-IDF USB device stack - } - - uint8_t charToHid(char c) { - // Map ASCII to HID keycodes (simplified) - if (c >= 'a' && c <= 'z') return 0x04 + (c - 'a'); - if (c >= 'A' && c <= 'Z') return 0x04 + (c - 'A'); - if (c >= '0' && c <= '9') return (c == '0') ? 0x27 : 0x1E + (c - '1'); - if (c == ' ') return 0x2C; - if (c == '\n') return 0x28; - if (c == '.') return 0x37; - if (c == '/') return 0x38; - if (c == '-') return 0x2D; - return 0; - } - - void sendHidReport(uint8_t* report) { - // Stub: send HID report to USB host via TinyUSB - // Real impl: tud_hid_keyboard_report(REPORT_ID_KEYBOARD, 0, report + 2); - } - - void editPayload() { - // Stub: interactive payload editor (would use on-device keyboard) - say("payload: %s", payload); - } - - bool detectHostConnection() { - // Probe for host connection: check USB VBUS, enumerate handshake, SOF tokens - // Stub: real impl would check hardware USB state - return true; // Auto-trigger when module enters - } -}; - -Module* makeHidInjector() { return new HidInjector(); } diff --git a/src/modules/honeypot.cpp b/src/modules/honeypot.cpp index 350e406..a71e882 100644 --- a/src/modules/honeypot.cpp +++ b/src/modules/honeypot.cpp @@ -1,66 +1,61 @@ #include "../core/module.h" #include "../core/ui.h" +#include -// Honeypot: create fake services (SSH, HTTP, Telnet, MySQL) to trap exploits. -// Log all connection attempts, exploit payloads, credentials, attack patterns. -// Analyze attacker behavior, extract 0-days, generate defensive signatures. +// Honeypot (DEFENSIVE, bench-use): logs anything this device receives on the +// serial console / SD as connection attempts. A real network honeypot needs +// TCP listeners (future WiFi work). No attack traffic is simulated — every +// counter reflects actual observed events only. class Honeypot : public Module { - enum Service { SSH, HTTP, TELNET, MYSQL, ALL } service = ALL; bool active = false; - uint32_t attacks = 0; - uint32_t credAttempts = 0; - uint32_t payloadsLogged = 0; + uint32_t events = 0; + File logfile; char msg[3][40] = {{0},{0},{0}}; public: const char* name() const override { return "Honeypot"; } - const char* blurb() const override { return "trap & analyze exploits"; } + const char* blurb() const override { return "log & analyze attempts"; } void onEnter() override { active = false; - attacks = 0; - credAttempts = 0; - payloadsLogged = 0; - say("Honeypot services: ready"); + events = 0; + say("Honeypot: ready"); } - void onExit() override { active = false; } + void onExit() override { active = false; if (logfile) logfile.close(); } bool onKey(char c) override { - if (c == 's') { service = (Service)((service + 1) % 5); return true; } - if (c == ' ') { active = !active; if (active) startHoneypot(); return true; } + if (c == ' ') { + active = !active; + if (active) { + if (!SD.begin()) say("no SD — serial log only"); + else { SD.mkdir("/logs"); logfile = SD.open("/logs/honeypot.txt", FILE_APPEND); } + say("listening (passive)"); + } else if (logfile) logfile.close(); + return true; + } return false; } void tick() override { if (!active) return; - - // Simulate attacks against honeypot services - if (attacks < 50) { - attacks++; - - if (attacks == 5) say("SSH: brute-force attempt (50 tries)"); - if (attacks == 10) say("HTTP: SQL injection in /login"); - if (attacks == 15) { credAttempts++; say("Creds: admin/admin123"); } - if (attacks == 20) say("Telnet: overflow in USER field"); - if (attacks == 25) { payloadsLogged++; say("Payload: x86 reverse shell"); } - if (attacks == 30) say("MySQL: default credentials attempt"); - if (attacks == 35) { credAttempts++; say("Creds: root/12345678"); } - if (attacks == 40) { payloadsLogged++; say("Payload: bash $(cat /etc/passwd)"); } - if (attacks == 45) say("HTTP: command injection detected"); - if (attacks == 50) say("Logged to /logs/honeypot_*.log"); + // Log actual serial input as events (real observed data only) + while (Serial.available()) { + char c = (char)Serial.read(); + if (c == '\n' || c == '\r') continue; + events++; + if (logfile) { logfile.print(millis()); logfile.print(" : "); logfile.println(c); } + if (events <= 5) say("event #%lu logged", (unsigned long)events); } } void draw() override { - const char* sn[] = {"SSH", "HTTP", "TELNET", "MYSQL", "ALL"}; - ui::lineC(0, ui::accent(), "Honeypot: %s %s", sn[service], active ? "ACTIVE" : "idle"); - ui::line(1, "attacks: %lu creds: %lu payloads: %lu", (unsigned long)attacks, (unsigned long)credAttempts, (unsigned long)payloadsLogged); - ui::bar(2, attacks / 50.0f, active ? ui::glow() : ui::dim(), "attacks"); - if (payloadsLogged > 0) ui::lineC(3, ui::glow(), "0-days extracted: %lu", (unsigned long)payloadsLogged); - for (int i = 0; i < 3; i++) ui::line(5 + i, "%s", msg[i]); + ui::lineC(0, ui::accent(), "Honeypot %s", active ? "LISTEN" : "idle"); + ui::line(1, "events: %lu", (unsigned long)events); + ui::line(2, "log: /logs/honeypot.txt"); + for (int i = 0; i < 3; i++) ui::line(4 + i, "%s", msg[i]); if (active) ui::spinner(228, ui::BODY_Y + 1, ui::glow()); - ui::hintBar("[s]ervice [space]trap [`]back"); + ui::hintBar("[space]listen [`]back"); } private: @@ -68,28 +63,6 @@ private: for (int i = 2; i > 0; i--) strncpy(msg[i], msg[i-1], 39); va_list ap; va_start(ap, fmt); vsnprintf(msg[0], 40, fmt, ap); va_end(ap); } - - void startHoneypot() { - active = true; - say("Starting honeypot services..."); - switch (service) { - case SSH: - say("SSH @22: fake OpenSSH_7.4"); - break; - case HTTP: - say("HTTP @80: fake Apache with vulns"); - break; - case TELNET: - say("Telnet @23: fake Linux login"); - break; - case MYSQL: - say("MySQL @3306: fake 5.5.20"); - break; - case ALL: - say("All services: SSH/HTTP/Telnet/MySQL"); - break; - } - } }; Module* makeHoneypot() { return new Honeypot(); } diff --git a/src/modules/i2cprobe.cpp b/src/modules/i2cprobe.cpp new file mode 100644 index 0000000..7589b73 --- /dev/null +++ b/src/modules/i2cprobe.cpp @@ -0,0 +1,95 @@ +#include "../core/module.h" +#include "../core/ui.h" +#include +#include "../core/pins.h" + +// I2C Probe: REAL bus scan + register read on the Grove port pins. +// Uses hardware Wire on pins::PROBE pins. Finds actual device addresses, +// reads actual registers. This is the honest replacement for the old +// protocol-sniffing stubs. + +class I2CProbe : public Module { + bool scanning = false; + uint8_t addr = 0; + int found = 0; + uint8_t regVal = 0; + char msg[3][40] = {{0},{0},{0}}; + +public: + const char* name() const override { return "I2C Probe"; } + const char* blurb() const override { return "real bus scan + rw"; } + + void onEnter() override { + scanning = false; addr = 0; found = 0; regVal = 0; + say("[s] scan [;/.] addr [r] read"); + } + void onExit() override { Wire.end(); } + + bool onKey(char c) override { + if (c == 's') { scan(); return true; } + if (c == ';') { if (addr > 0) addr--; return true; } + if (c == '.') { if (addr < 0x78) addr++; return true; } + if (c == 'r') { readReg(); return true; } + if (c == '+') { writeInc(); return true; } + return false; + } + + void tick() override { } + + void draw() override { + ui::lineC(0, ui::accent(), "I2C Probe %s", found ? "READY" : "idle"); + ui::line(1, "devices found: %d", found); + ui::line(2, "addr: 0x%02X reg0: 0x%02X", addr, regVal); + for (int i = 0; i < 3; i++) ui::line(4 + i, "%s", msg[i]); + ui::hintBar("[s]can [;/.]addr [r]ead [+]inc [`]back"); + } + +private: + void begin() { + Wire.begin(pins::PROBE[1], pins::PROBE[0]); // SDA, SCL on Grove + } + + void scan() { + begin(); + found = 0; addr = 0; + for (uint8_t a = 0x08; a < 0x78; a++) { + Wire.beginTransmission(a); + if (Wire.endTransmission() == 0) { + if (!addr) addr = a; + found++; + say("device @ 0x%02X", a); + } + } + if (!found) say("no I2C devices"); + Wire.end(); + } + + void readReg() { + if (!addr) { say("scan first"); return; } + begin(); + Wire.beginTransmission(addr); + Wire.write(0x00); + if (Wire.endTransmission(false) == 0 && Wire.requestFrom((int)addr, 1)) { + regVal = Wire.read(); + say("0x%02X[0] = 0x%02X", addr, regVal); + } else say("read fail @ 0x%02X", addr); + Wire.end(); + } + + void writeInc() { + if (!addr) { say("scan first"); return; } + begin(); + Wire.beginTransmission(addr); + Wire.write(0x00); Wire.write(regVal + 1); + if (Wire.endTransmission() == 0) { regVal++; say("wrote 0x%02X", regVal); } + else say("write fail"); + Wire.end(); + } + + void say(const char* fmt, ...) { + for (int i = 2; i > 0; i--) strncpy(msg[i], msg[i-1], 39); + va_list ap; va_start(ap, fmt); vsnprintf(msg[0], 40, fmt, ap); va_end(ap); + } +}; + +Module* makeI2CProbe() { return new I2CProbe(); } diff --git a/src/modules/industrial.cpp b/src/modules/industrial.cpp deleted file mode 100644 index bb8e2a0..0000000 --- a/src/modules/industrial.cpp +++ /dev/null @@ -1,114 +0,0 @@ -#include "../core/module.h" -#include "../core/ui.h" - -// Industrial SCADA: speak SCADA/industrial protocols - Modbus, Profibus, OPC-UA, EtherCAT. -// Control PLCs, read/write registers, extract sensor data, trigger industrial processes. -// Access factory automation, HVAC, power systems, water treatment, manufacturing equipment. - -class IndustrialScada : public Module { - enum Protocol { MODBUS_TCP, MODBUS_RTU, PROFIBUS, OPC_UA, ETHERCAT } protocol = MODBUS_TCP; - bool connected = false; - uint32_t registersRead = 0; - uint32_t registersWritten = 0; - uint16_t holdingReg = 0; - char targetPLC[40] = "192.168.1.200"; - char msg[3][40] = {{0},{0},{0}}; - -public: - const char* name() const override { return "Industrial SCADA"; } - const char* blurb() const override { return "SCADA/PLC control"; } - - void onEnter() override { - connected = false; - registersRead = 0; - registersWritten = 0; - holdingReg = 0; - say("SCADA engine: ready"); - } - void onExit() override { if (connected) disconnect(); } - - bool onKey(char c) override { - if (c == 'p') { protocol = (Protocol)((protocol + 1) % 5); return true; } - if (c == 'c') { if (!connected) connectPLC(); else disconnect(); return true; } - if (c == 'r') { if (connected) readRegisters(); return true; } - if (c == 'w') { if (connected) writeRegister(); return true; } - return false; - } - - void tick() override { - if (!connected) return; - - if (registersRead > 0 && registersRead % 20 == 0) { - say("REG[40]: %.0f bar (pressure)", 2.5f + (registersRead % 5) * 0.1f); - } - if (registersWritten > 0 && registersWritten % 25 == 0) { - say("Motor: speed set to %u RPM", 1200 + (registersWritten % 300)); - } - } - - void draw() override { - const char* pn[] = {"Modbus TCP", "Modbus RTU", "Profibus", "OPC-UA", "EtherCAT"}; - ui::lineC(0, ui::accent(), "Industrial: %s %s", pn[protocol], connected ? "CONNECTED" : "idle"); - ui::line(1, "PLC: %s", targetPLC); - ui::line(2, "read: %lu write: %lu holding: %u", - (unsigned long)registersRead, (unsigned long)registersWritten, holdingReg); - if (connected) { - ui::bar(3, (registersRead + registersWritten) / 100.0f, ui::glow(), "io"); - ui::lineC(4, ui::glow(), "Industrial process: running"); - } - for (int i = 0; i < 3; i++) ui::line(6 + i, "%s", msg[i]); - if (connected) ui::spinner(228, ui::BODY_Y + 1, ui::glow()); - ui::hintBar("[p]rotocol [c]onnect [r]ead [w]rite [`]back"); - } - -private: - void say(const char* fmt, ...) { - for (int i = 2; i > 0; i--) strncpy(msg[i], msg[i-1], 39); - va_list ap; va_start(ap, fmt); vsnprintf(msg[0], 40, fmt, ap); va_end(ap); - } - - void connectPLC() { - connected = true; - say("%s: connecting to PLC...", protoName()); - switch (protocol) { - case MODBUS_TCP: - say("Modbus: unit_id=1 connected"); - break; - case MODBUS_RTU: - say("Modbus RTU: /dev/ttyUSB0 9600"); - break; - case PROFIBUS: - say("Profibus: PA=125 connected"); - break; - case OPC_UA: - say("OPC-UA: ns=2;s=PLC.VAR"); - break; - case ETHERCAT: - say("EtherCAT: slave 1 online"); - break; - } - } - - void disconnect() { - connected = false; - say("Disconnected from PLC"); - } - - void readRegisters() { - registersRead += 10; - say("READ 40001-40010 (%u bytes)", registersRead); - } - - void writeRegister() { - registersWritten++; - holdingReg = 4000 + registersWritten; - say("WRITE %u -> holding[10]", holdingReg); - } - - const char* protoName() { - const char* pn[] = {"Modbus TCP", "Modbus RTU", "Profibus", "OPC-UA", "EtherCAT"}; - return pn[protocol]; - } -}; - -Module* makeIndustrialScada() { return new IndustrialScada(); } diff --git a/src/modules/iotswarm.cpp b/src/modules/iotswarm.cpp deleted file mode 100644 index 9a3a149..0000000 --- a/src/modules/iotswarm.cpp +++ /dev/null @@ -1,93 +0,0 @@ -#include "../core/module.h" -#include "../core/ui.h" - -// IoT Swarm: speak IoT protocols - MQTT broker, CoAP server, Zigbee coordinator, Z-Wave controller. -// Auto-discover IoT devices, inject commands, extract sensor data, control lights/locks/appliances. -// Single interface to entire smart home. - -class IoTSwarm : public Module { - enum Protocol { MQTT, COAP, ZIGBEE, ZWAVE, THREAD, LORA } protocol = MQTT; - bool active = false; - uint32_t devicesDiscovered = 0; - uint32_t commandsSent = 0; - uint32_t dataCollected = 0; - char msg[3][40] = {{0},{0},{0}}; - -public: - const char* name() const override { return "IoT Swarm"; } - const char* blurb() const override { return "smart home control"; } - - void onEnter() override { - active = false; - devicesDiscovered = 0; - commandsSent = 0; - dataCollected = 0; - say("IoT discovery: starting"); - discoverDevices(); - } - void onExit() override { active = false; } - - bool onKey(char c) override { - if (c == 'p') { protocol = (Protocol)((protocol + 1) % 6); return true; } - if (c == 'c') { if (devicesDiscovered > 0) sendCommand(); return true; } - return false; - } - - void tick() override { - if (!active) return; - - if (devicesDiscovered > 0) { - commandsSent++; - if (commandsSent % 15 == 0) { - dataCollected += 128 + (commandsSent % 64); - say("Sensor: temp=%.1f temp hum=%.0f%%", 22.5f + (commandsSent % 5), 65.0f); - } - if (commandsSent == 30) say("Light: brightness set to 75%%"); - if (commandsSent == 60) say("Lock: front door unlocked"); - if (commandsSent == 90) say("Thermostat: target 24C"); - } - } - - void draw() override { - const char* pn[] = {"MQTT", "CoAP", "Zigbee", "Z-Wave", "Thread", "LoRa"}; - ui::lineC(0, ui::accent(), "IoT Swarm: %s", pn[protocol]); - ui::line(1, "devices: %lu commands: %lu data: %lu KB", - (unsigned long)devicesDiscovered, (unsigned long)commandsSent, (unsigned long)(dataCollected/1024)); - if (devicesDiscovered > 0) { - ui::bar(2, commandsSent / 100.0f, ui::glow(), "activity"); - ui::lineC(3, ui::glow(), "Control: lights, locks, sensors"); - } else { - ui::line(2, "status: scanning..."); - } - for (int i = 0; i < 3; i++) ui::line(5 + i, "%s", msg[i]); - if (devicesDiscovered > 0) ui::spinner(228, ui::BODY_Y + 1, ui::glow()); - ui::hintBar("[p]rotocol [c]ommand [`]back"); - } - -private: - void say(const char* fmt, ...) { - for (int i = 2; i > 0; i--) strncpy(msg[i], msg[i-1], 39); - va_list ap; va_start(ap, fmt); vsnprintf(msg[0], 40, fmt, ap); va_end(ap); - } - - void discoverDevices() { - say("Scanning %s network...", protoName()); - // Real impl: MQTT subscribe to $SYS, CoAP multicast discover, Zigbee permit-join, Z-Wave node info - devicesDiscovered = 5 + (protocol * 2); - active = (devicesDiscovered > 0); - if (active) say("Found: %lu devices online", (unsigned long)devicesDiscovered); - } - - void sendCommand() { - commandsSent++; - const char* cmds[] = {"SET power ON", "GET temperature", "SET brightness", "LOCK door", "GET humidity", "SET thermostat"}; - say("TX: %s", cmds[commandsSent % 6]); - } - - const char* protoName() { - const char* pn[] = {"MQTT", "CoAP", "Zigbee", "Z-Wave", "Thread", "LoRa"}; - return pn[protocol]; - } -}; - -Module* makeIoTSwarm() { return new IoTSwarm(); } diff --git a/src/modules/jtagusbbridge.cpp b/src/modules/jtagusbbridge.cpp deleted file mode 100644 index 0cda68d..0000000 --- a/src/modules/jtagusbbridge.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "../core/module.h" -#include "../core/ui.h" - -// JTAG/SWD USB Bridge: tunnel debug port to host as USB device. -// Exposes JTAG/SWD interface via USB so host sees Cardputer as a JTAG/SWD debugger. -// Auto-detect probe protocol (JTAG bitbang or SWD), enumerate as FTDI or Segger clone. - -class JtagUsbBridge : public Module { - enum Protocol { JTAG, SWD } protocol = JTAG; - bool active = false; - uint32_t packets = 0; - char msg[3][40] = {{0},{0},{0}}; - -public: - const char* name() const override { return "JTAG USB Bridge"; } - const char* blurb() const override { return "tunnel JTAG/SWD to host"; } - - void onEnter() override { - active = false; - packets = 0; - say("USB debug bridge: ready"); - autoDetectProtocol(); - if (protocol != JTAG || protocol == SWD) { - active = true; - say("Bridge active, waiting for host"); - } - } - void onExit() override { active = false; } - - bool onKey(char c) override { - if (c == 'p') { protocol = (Protocol)((protocol + 1) % 2); return true; } - if (c == ' ') { active = !active; if (active) packets = 0; return true; } - return false; - } - - void tick() override { - if (!active) return; - - // Simulate tunneling debug commands over USB - if (packets < 100) { - packets++; - if (packets == 10) say("USB: FTDI enum as debugger"); - if (packets == 25) say("Host: OpenOCD connected"); - if (packets == 50) say("JTAG: target detected, TCO=0x%x", 0x12345678); - } - } - - void draw() override { - const char* pn[] = {"JTAG", "SWD"}; - ui::lineC(0, ui::accent(), "Debug Bridge: %s %s", pn[protocol], active ? "BRIDGE" : "idle"); - ui::line(1, "packets: %lu", (unsigned long)packets); - if (active && packets >= 50) ui::lineC(2, ui::glow(), "Target IDCODE locked"); - for (int i = 0; i < 3; i++) ui::line(4 + i, "%s", msg[i]); - if (active) ui::spinner(228, ui::BODY_Y + 1, ui::glow()); - ui::hintBar("[p]rotocol [space]bridge [`]back"); - } - -private: - void say(const char* fmt, ...) { - for (int i = 2; i > 0; i--) strncpy(msg[i], msg[i-1], 39); - va_list ap; va_start(ap, fmt); vsnprintf(msg[0], 40, fmt, ap); va_end(ap); - } - - void autoDetectProtocol() { - // Probe JTAG/SWD pins: attempt TCO/TDI handshake or SWD SWCLK/SWDIO sync - // Stub: real impl would toggle pins, measure response timing, detect protocol - say("auto-detect: %s", protocol == JTAG ? "JTAG" : "SWD"); - } -}; - -Module* makeJtagUsbBridge() { return new JtagUsbBridge(); } diff --git a/src/modules/logicprobes.cpp b/src/modules/logicprobes.cpp new file mode 100644 index 0000000..cd5a341 --- /dev/null +++ b/src/modules/logicprobes.cpp @@ -0,0 +1,78 @@ +#include "../core/module.h" +#include "../core/ui.h" +#include "../core/pins.h" + +// GPIO Logic Analyzer: REAL pin sampling on the probe header pins. +// Samples at ~5kHz per channel, shows live hi/lo state, counts edges, +// estimates frequency. Actual GPIO reads — no simulation. + +class LogicProbes : public Module { + bool running = false; + uint8_t state[4] = {0,0,0,0}; + uint32_t edges[4] = {0,0,0,0}; + uint32_t freq[4] = {0,0,0,0}; // Hz estimate + char msg[3][40] = {{0},{0},{0}}; + + // probe header pins to sample + static constexpr int NP = 4; + static const int PINS[NP]; + +public: + const char* name() const override { return "Logic Probes"; } + const char* blurb() const override { return "live GPIO states+freq"; } + + void onEnter() override { + running = false; + for (int i = 0; i < NP; i++) pinMode(PINS[i], INPUT_PULLUP); + say("[space] start/stop sampling"); + } + void onExit() override { running = false; } + + bool onKey(char c) override { + if (c == ' ') { running = !running; if (running) { for (int i=0;i= 1000) { + for (int i = 0; i < NP; i++) { freq[i] = edgeCount[i] / 2; edgeCount[i] = 0; } + winStart = now; + } + } + + void draw() override { + ui::lineC(0, ui::accent(), "Logic Probes %s", running ? "RUN" : "idle"); + for (int i = 0; i < NP; i++) { + ui::line(1 + i, "G%-2d: %s edges:%-6lu ~%lu Hz", + PINS[i], state[i] ? "HIGH" : "LOW ", + (unsigned long)edges[i], (unsigned long)freq[i]); + } + for (int i = 0; i < 3; i++) ui::line(6 + i, "%s", msg[i]); + if (running) ui::spinner(228, ui::BODY_Y + 1, ui::glow()); + ui::hintBar("[space]sample [`]back"); + } + +private: + void say(const char* fmt, ...) { + for (int i = 2; i > 0; i--) strncpy(msg[i], msg[i-1], 39); + va_list ap; va_start(ap, fmt); vsnprintf(msg[0], 40, fmt, ap); va_end(ap); + } +}; + +const int LogicProbes::PINS[LogicProbes::NP] = {8, 9, 10, 11}; + +Module* makeLogicProbes() { return new LogicProbes(); } diff --git a/src/modules/memedit.cpp b/src/modules/memedit.cpp deleted file mode 100644 index 9b72fc2..0000000 --- a/src/modules/memedit.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include "../core/module.h" -#include "../core/ui.h" - -// Memory Editor: direct read/write to address space with privilege escalation attempts. -// Probe MPU configuration, bypass restrictions, dump page tables, modify DRAM directly. -// For devices you own; useful for RTOS/embedded kernel debugging. - -class MemEditor : public Module { - uint32_t baseAddr = 0x20000000; // Default: SRAM start on ESP32 - uint8_t data[32]; - int dataLen = 0; - uint32_t mpu_ctrl = 0; - char msg[4][40] = {{0},{0},{0},{0}}; - bool elevated = false; - -public: - const char* name() const override { return "MemEdit"; } - const char* blurb() const override { return "direct memory read/write + privesc"; } - - void onEnter() override { - dataLen = 0; - probeMpu(); - attemptEscalation(); - } - void onExit() override {} - - bool onKey(char c) override { - if (c == 'r') { readMem(); return true; } - if (c == 'w') { writeMem(0xDEADBEEF); return true; } - if (c == 'm') { baseAddr += 0x1000; return true; } - if (c == 'p') { probeMpu(); return true; } - if (c == 'e') { attemptEscalation(); return true; } - return false; - } - - void draw() override { - ui::lineC(0, ui::accent(), "Memory Editor priv:%s", elevated ? "OK" : "user"); - ui::line(1, "addr: 0x%08lx MPU: %s", (unsigned long)baseAddr, mpu_ctrl ? "ON" : "OFF"); - if (dataLen) { - char hex[32]; int p = 0; - for (int i = 0; i < dataLen && i < 8; i++) - p += snprintf(hex + p, sizeof(hex) - p, "%02X ", data[i]); - ui::line(2, "data: %s", hex); - } - for (int i = 0; i < 4; i++) ui::line(4 + i, "%s", msg[i]); - ui::hintBar("[r]ead [w]rite [m]ove [p]robe [e]levate [`]back"); - } - -private: - void say(const char* fmt, ...) { - for (int i = 3; i > 0; i--) strncpy(msg[i], msg[i-1], 39); - va_list ap; va_start(ap, fmt); vsnprintf(msg[0], 40, fmt, ap); va_end(ap); - } - - void probeMpu() { - // Read MPU_CTRL on ARM Cortex (if available) - // ESP32 uses a different MMU model, so this is a stub - mpu_ctrl = 0; // Assume no MPU or disabled - say("MPU: probed (check DRAM access)"); - } - - void attemptEscalation() { - // Try common escalation patterns: - // 1. Disable MPU (write 0 to MPU_CTRL) - // 2. Set all permissions to RWX - // 3. Access kernel memory regions - - // For ESP32: attempt to read from protected bootloader region - uint32_t bootloader_addr = 0x1000; - uint8_t test = *(volatile uint8_t*)bootloader_addr; - - if (test == 0xe9 || test == 0xfe) { // Common bootloader magics - elevated = true; - say("escalation: bootloader readable!"); - } else { - say("escalation: blocked by MPU/fuse"); - } - } - - void readMem() { - for (int i = 0; i < 32; i++) { - data[i] = *(volatile uint8_t*)(baseAddr + i); - } - dataLen = 32; - say("read 32B from 0x%08lx", (unsigned long)baseAddr); - } - - void writeMem(uint32_t val) { - // Attempt to write a test pattern - *(volatile uint32_t*)baseAddr = val; - uint32_t readback = *(volatile uint32_t*)baseAddr; - if (readback == val) { - say("write OK: 0x%08lx", (unsigned long)val); - } else { - say("write blocked or faulted"); - } - } -}; - -Module* makeMemEditor() { return new MemEditor(); } diff --git a/src/modules/messageforge.cpp b/src/modules/messageforge.cpp deleted file mode 100644 index b35d2a2..0000000 --- a/src/modules/messageforge.cpp +++ /dev/null @@ -1,97 +0,0 @@ -#include "../core/module.h" -#include "../core/ui.h" - -// Message Forge: craft & parse ANY binary protocol - create custom messages, fuzz protocols, -// inject payloads into existing formats. Supports: JSON, protobuf, custom binary, hex strings. -// Understand any message format and generate valid protocol messages on the fly. - -class MessageForge : public Module { - enum Format { FMT_HEX, JSON, PROTOBUF, CUSTOM_BINARY, XML } format = FMT_HEX; - uint32_t messagesForged = 0; - uint32_t payloadsInjected = 0; - char lastMessage[128] = "00 01 02 03 04 05"; - char msg[3][40] = {{0},{0},{0}}; - -public: - const char* name() const override { return "Message Forge"; } - const char* blurb() const override { return "craft any protocol message"; } - - void onEnter() override { - messagesForged = 0; - payloadsInjected = 0; - say("Message forge: ready"); - } - void onExit() override { } - - bool onKey(char c) override { - if (c == 'f') { format = (Format)((format + 1) % 5); return true; } - if (c == 'c') { craftMessage(); return true; } - if (c == 'i') { injectPayload(); return true; } - return false; - } - - void tick() override { } - - void draw() override { - const char* fn[] = {"HEX", "JSON", "PROTOBUF", "BINARY", "XML"}; - ui::lineC(0, ui::accent(), "Message Forge: %s", fn[format]); - ui::line(1, "forged: %lu injected: %lu", (unsigned long)messagesForged, (unsigned long)payloadsInjected); - ui::line(2, "last: %s", lastMessage); - if (messagesForged > 0) { - ui::bar(3, messagesForged / 20.0f, ui::glow(), "forge"); - } else { - ui::line(3, "status: ready"); - } - for (int i = 0; i < 3; i++) ui::line(5 + i, "%s", msg[i]); - ui::hintBar("[f]ormat [c]raft [i]nject [`]back"); - } - -private: - void say(const char* fmt, ...) { - for (int i = 2; i > 0; i--) strncpy(msg[i], msg[i-1], 39); - va_list ap; va_start(ap, fmt); vsnprintf(msg[0], 40, fmt, ap); va_end(ap); - } - - void craftMessage() { - messagesForged++; - switch (format) { - case FMT_HEX: - strncpy(lastMessage, "48 65 6c 6c 6f 20 57 6f 72 6c 64", 127); - say("HEX: crafted %lu byte message", (unsigned long)(messagesForged * 11)); - break; - case JSON: - strncpy(lastMessage, "{\"cmd\":\"exploit\",\"payload\":\"...", 127); - say("JSON: generated object structure"); - break; - case PROTOBUF: - strncpy(lastMessage, "08 96 01 12 04 74 65 73 74", 127); - say("Protobuf: compiled proto3 message"); - break; - case CUSTOM_BINARY: - strncpy(lastMessage, "MAGIC[0x41424344] + payload", 127); - say("Binary: crafted custom format"); - break; - case XML: - strncpy(lastMessage, "bypass", 127); - say("XML: generated request document"); - break; - } - } - - void injectPayload() { - if (messagesForged == 0) { - say("ERROR: craft message first"); - return; - } - payloadsInjected++; - say("Injected: reverse shell in %s", formatName()); - say("Size: %u bytes (encoded)", 128 + (payloadsInjected * 64)); - } - - const char* formatName() { - const char* fn[] = {"HEX", "JSON", "PROTOBUF", "BINARY", "XML"}; - return fn[format]; - } -}; - -Module* makeMessageForge() { return new MessageForge(); } diff --git a/src/modules/polyglot.cpp b/src/modules/polyglot.cpp deleted file mode 100644 index 71b5944..0000000 --- a/src/modules/polyglot.cpp +++ /dev/null @@ -1,234 +0,0 @@ -#include "../core/module.h" -#include "../core/ui.h" - -// Polyglot Code Gen: generate exploits/payloads in multiple programming languages. -// Python, Bash, PowerShell, C, Go, Rust, Ruby, Perl. Output ready-to-execute code -// targeting the same payload/technique across different execution contexts. - -class Polyglot : public Module { - enum Lang { PYTHON, BASH, POWERSHELL, C, GO, RUST, RUBY, PERL } lang = PYTHON; - enum PayloadType { REVERSE_SHELL, CREDS_DUMP, MEMORY_READ, KEYLOGGER } ptype = REVERSE_SHELL; - uint32_t codeSize = 0; - char lhost[40] = "192.168.1.100"; - uint16_t lport = 4444; - char msg[3][40] = {{0},{0},{0}}; - -public: - const char* name() const override { return "Polyglot"; } - const char* blurb() const override { return "multi-language payload gen"; } - - void onEnter() override { - codeSize = 0; - say("Code generator ready"); - } - void onExit() override { } - - bool onKey(char c) override { - if (c == 'l') { lang = (Lang)((lang + 1) % 8); return true; } - if (c == 'p') { ptype = (PayloadType)((ptype + 1) % 4); return true; } - if (c == 'g') { generatePayload(); return true; } - return false; - } - - void tick() override { } - - void draw() override { - const char* ln[] = {"PYTHON", "BASH", "POWERSHELL", "C", "GO", "RUST", "RUBY", "PERL"}; - const char* pt[] = {"REV_SHELL", "CREDS_DUMP", "MEM_READ", "KEYLOG"}; - ui::lineC(0, ui::accent(), "%s → %s", ln[lang], pt[ptype]); - ui::line(1, "target: %s:%u", lhost, lport); - if (codeSize > 0) { - ui::lineC(2, ui::glow(), "Generated: %lu bytes", (unsigned long)codeSize); - } else { - ui::line(2, "status: ready"); - } - for (int i = 0; i < 3; i++) ui::line(4 + i, "%s", msg[i]); - ui::hintBar("[l]ang [p]ayload [g]en [`]back"); - } - -private: - void say(const char* fmt, ...) { - for (int i = 2; i > 0; i--) strncpy(msg[i], msg[i-1], 39); - va_list ap; va_start(ap, fmt); vsnprintf(msg[0], 40, fmt, ap); va_end(ap); - } - - void generatePayload() { - // Generate polyglot payload in target language - // Save to /payloads/exploit.py / exploit.sh / exploit.ps1 etc - say("generating %s...", langName()); - - switch (ptype) { - case REVERSE_SHELL: - generateReverseShell(); - break; - case CREDS_DUMP: - generateCredsDump(); - break; - case MEMORY_READ: - generateMemoryRead(); - break; - case KEYLOGGER: - generateKeylogger(); - break; - } - } - - void generateReverseShell() { - codeSize = 0; - switch (lang) { - case PYTHON: - codeSize = 287; - say("Python: import socket,subprocess..."); - break; - case BASH: - codeSize = 156; - say("Bash: bash -i >& /dev/tcp/..."); - break; - case POWERSHELL: - codeSize = 342; - say("PS: IEX(New-Object Net.WebClient)..."); - break; - case C: - codeSize = 512; - say("C: socket(),fork(),dup2()..."); - break; - case GO: - codeSize = 401; - say("Go: net.Dial(), os/exec..."); - break; - case RUST: - codeSize = 478; - say("Rust: std::net::TcpStream..."); - break; - case RUBY: - codeSize = 298; - say("Ruby: TCPSocket, system()..."); - break; - case PERL: - codeSize = 267; - say("Perl: IO::Socket, system()..."); - break; - } - } - - void generateCredsDump() { - codeSize = 0; - switch (lang) { - case PYTHON: - codeSize = 412; - say("Python: /etc/shadow, SAM parsing"); - break; - case BASH: - codeSize = 89; - say("Bash: cat /etc/passwd /etc/shadow"); - break; - case POWERSHELL: - codeSize = 256; - say("PS: Get-WmiObject, registry dump"); - break; - case C: - codeSize = 624; - say("C: fopen() /etc/shadow, pwd.h"); - break; - case GO: - codeSize = 498; - say("Go: ioutil.ReadFile, os/user"); - break; - case RUST: - codeSize = 556; - say("Rust: fs::read(), parsing"); - break; - case RUBY: - codeSize = 334; - say("Ruby: File.read(), Struct"); - break; - case PERL: - codeSize = 301; - say("Perl: open(), split on ':'"); - break; - } - } - - void generateMemoryRead() { - codeSize = 0; - switch (lang) { - case PYTHON: - codeSize = 289; - say("Python: ctypes, mmap, /proc"); - break; - case BASH: - codeSize = 145; - say("Bash: dd if=/proc/mem bs=1"); - break; - case POWERSHELL: - codeSize = 378; - say("PS: ReadProcessMemory() API"); - break; - case C: - codeSize = 412; - say("C: ptrace(), /proc/[pid]/mem"); - break; - case GO: - codeSize = 445; - say("Go: syscall, mmap, ptrace"); - break; - case RUST: - codeSize = 501; - say("Rust: libc bindings, unsafe"); - break; - case RUBY: - codeSize = 367; - say("Ruby: FFI, Fiddle, ptrace"); - break; - case PERL: - codeSize = 298; - say("Perl: Sys::Ptrace, pack/unpack"); - break; - } - } - - void generateKeylogger() { - codeSize = 0; - switch (lang) { - case PYTHON: - codeSize = 356; - say("Python: pynput, evdev, logging"); - break; - case BASH: - codeSize = 201; - say("Bash: cat /dev/input/event*"); - break; - case POWERSHELL: - codeSize = 489; - say("PS: SetWindowsHookEx() Win32"); - break; - case C: - codeSize = 667; - say("C: X11 XNextEvent(), uinput"); - break; - case GO: - codeSize = 512; - say("Go: robotgo, evdev binding"); - break; - case RUST: - codeSize = 578; - say("Rust: evdev-rs, X11-xcb"); - break; - case RUBY: - codeSize = 423; - say("Ruby: pry-byebug, ObjectSpace"); - break; - case PERL: - codeSize = 389; - say("Perl: X11::Protocol, select()"); - break; - } - } - - const char* langName() { - const char* ln[] = {"PYTHON", "BASH", "POWERSHELL", "C", "GO", "RUST", "RUBY", "PERL"}; - return ln[lang]; - } -}; - -Module* makePolyglot() { return new Polyglot(); } diff --git a/src/modules/privesc.cpp b/src/modules/privesc.cpp deleted file mode 100644 index 1bc4100..0000000 --- a/src/modules/privesc.cpp +++ /dev/null @@ -1,127 +0,0 @@ -#include "../core/module.h" -#include "../core/ui.h" - -// Privilege Escalation Suite: common embedded system exploits. -// Stack overflow patterns, UAF detection, integer overflows in kernel syscalls, -// race conditions in driver code. Attempts to escalate from user to kernel context. - -class PrivEsc : public Module { - enum Exploit { STACK_SMASH, UAF, INT_OVERFLOW, RACE } exploit = STACK_SMASH; - bool running = false; - uint32_t attempts = 0, successes = 0; - char msg[4][40] = {{0},{0},{0},{0}}; - -public: - const char* name() const override { return "PrivEsc"; } - const char* blurb() const override { return "embedded OS exploit patterns"; } - - void onEnter() override { running = false; attempts = 0; successes = 0; } - void onExit() override { running = false; } - - bool onKey(char c) override { - if (c == 'e') { exploit = (Exploit)((exploit + 1) % 4); running = false; return true; } - if (c == ' ') { running = !running; if (running) { attempts = 0; successes = 0; } return true; } - return false; - } - - void tick() override { - if (!running || attempts >= 10) return; - delay(100); - attempts++; - - switch (exploit) { - case STACK_SMASH: if (testStackSmash()) successes++; break; - case UAF: if (testUAF()) successes++; break; - case INT_OVERFLOW: if (testIntOverflow()) successes++; break; - case RACE: if (testRace()) successes++; break; - } - } - - void draw() override { - const char* en[] = {"STACK", "UAF", "INT_OV", "RACE"}; - ui::lineC(0, ui::accent(), "%s exploit %s", en[exploit], running ? "GO" : "idle"); - ui::line(1, "attempts: %lu hits: %lu", (unsigned long)attempts, (unsigned long)successes); - if (successes > 0) ui::lineC(2, ui::glow(), "ESCALATED!"); - for (int i = 0; i < 4; i++) ui::line(4 + i, "%s", msg[i]); - if (running) ui::spinner(228, ui::BODY_Y + 1, ui::glow()); - ui::hintBar("[e]xploit [space]run [`]back"); - } - -private: - void say(const char* fmt, ...) { - for (int i = 3; i > 0; i--) strncpy(msg[i], msg[i-1], 39); - va_list ap; va_start(ap, fmt); vsnprintf(msg[0], 40, fmt, ap); va_end(ap); - } - - bool testStackSmash() { - // Attempt a classic stack overflow: overflow a buffer on the stack - // and overwrite a return address with a gadget address. - // On a real system, this would trigger a crash or unexpected jump. - - volatile uint32_t canary = 0xDEADBEEF; - volatile char buf[16]; - - // Simulate overflow - memset((void*)buf, 'A', 32); // Write past buffer end - - // Check if canary was corrupted - if (canary != 0xDEADBEEF) { - say("stack canary overwritten"); - return true; - } - return false; - } - - bool testUAF() { - // Use-After-Free: allocate, free, then use a pointer. - // On a system with no heap protection, this could leak/corrupt data. - - uint32_t* ptr = (uint32_t*)malloc(16); - if (!ptr) return false; - - uint32_t original = *ptr; - free(ptr); - - // Unsafe dereference (UAF) - uint32_t value = *ptr; - - // If value differs from original or system didn't crash, UAF is possible - say("UAF: read freed mem"); - return true; - } - - bool testIntOverflow() { - // Integer overflow in size calculation: - // uint32_t size = (uint32_t)height * (uint32_t)width; - // if size overflows, malloc gets tiny buffer, overflow ensues. - - uint32_t h = 65536, w = 65536; - uint32_t size = h * w; // Overflows to 0 - - if (size == 0 || size < h * w) { - say("integer overflow detected"); - return true; - } - return false; - } - - bool testRace() { - // Race condition detection: quick acquire/release of a resource - // to detect TOCTOU (time-of-check-time-of-use) bugs. - - static volatile uint32_t flag = 0; - flag = 0; - // Check - if (flag == 0) { - // Use (window for race) - flag = 1; - if (flag == 0) { // Should be impossible if no race - say("race detected"); - return true; - } - } - return false; - } -}; - -Module* makePrivEsc() { return new PrivEsc(); } diff --git a/src/modules/protocol.cpp b/src/modules/protocol.cpp deleted file mode 100644 index 99afa43..0000000 --- a/src/modules/protocol.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "../core/module.h" -#include "../core/ui.h" -#include "../core/pins.h" - -// Protocol sniffer menu: UART/SPI/I2C in one module with shared capture/replay logic. -// Real-time stats: packets/sec, data rate, frame errors. - -class ProtocolSniff : public Module { - enum Proto { UART_P, SPI_P, I2C_P } proto = UART_P; - bool capturing = false; - uint32_t pkts = 0, bytes = 0, errors = 0, startMs = 0; - uint8_t buf[512]; int bufLen = 0; - char msg[3][40] = {{0},{0},{0}}; - -public: - const char* name() const override { return "Protocol"; } - const char* blurb() const override { return "UART/SPI/I2C unified sniff"; } - - void onEnter() override { capturing = false; pkts = 0; bytes = 0; errors = 0; } - void onExit() override { capturing = false; } - - bool onKey(char c) override { - if (c == 'm') { proto = (Proto)((proto + 1) % 3); capturing = false; say("mode: %s", protoName()); return true; } - if (c == ' ') { capturing = !capturing; if (capturing) { pkts = 0; bytes = 0; startMs = millis(); } return true; } - return false; - } - - void tick() override { - if (!capturing) return; - // Stub: real impl reads from the selected protocol's bus - // For demo: increment counters slowly - if (millis() % 100 == 0) { pkts++; bytes += random(1, 20); } - } - - void draw() override { - ui::lineC(0, ui::accent(), "%s %s", protoName(), capturing ? "SNIFF" : "idle"); - uint32_t elapsed = capturing ? (millis() - startMs) : 1; - float pps = pkts * 1000.0f / (elapsed + 1); - ui::line(1, "pkts: %lu bytes: %lu rate: %.1f p/s", (unsigned long)pkts, - (unsigned long)bytes, pps); - ui::line(2, "errors: %lu", (unsigned long)errors); - for (int i = 0; i < 3; i++) ui::line(4 + i, "%s", msg[i]); - if (capturing) ui::spinner(228, ui::BODY_Y + 1, ui::glow()); - ui::hintBar("[m]ode [space]capture [`]back"); - } - -private: - const char* protoName() { - return proto == UART_P ? "UART" : proto == SPI_P ? "SPI" : "I2C"; - } - - void say(const char* fmt, ...) { - for (int i = 2; i > 0; i--) strncpy(msg[i], msg[i-1], 39); - va_list ap; va_start(ap, fmt); vsnprintf(msg[0], 40, fmt, ap); va_end(ap); - } -}; - -Module* makeProtocol() { return new ProtocolSniff(); } diff --git a/src/modules/rndisbridge.cpp b/src/modules/rndisbridge.cpp deleted file mode 100644 index 7d9c1e5..0000000 --- a/src/modules/rndisbridge.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "../core/module.h" -#include "../core/ui.h" - -// RNDIS Bridge: Remote Network Driver Interface Specification over USB. -// Create virtual ethernet link to host, assign IP (192.168.7.1), enable DHCP server, -// pivot to host network, scan/attack on that link. - -class RndisBridge : public Module { - enum Mode { DHCP_SERVER, STATIC_IP } mode = DHCP_SERVER; - bool active = false; - uint32_t clientCount = 0; - uint32_t dataXfer = 0; - char msg[3][40] = {{0},{0},{0}}; - -public: - const char* name() const override { return "RNDIS Bridge"; } - const char* blurb() const override { return "virtual ethernet over USB"; } - - void onEnter() override { - active = true; - clientCount = 0; - dataXfer = 0; - say("RNDIS: USB ethernet gadget"); - say("Auto-starting ethernet bridge"); - } - void onExit() override { active = false; } - - bool onKey(char c) override { - if (c == 'm') { mode = (Mode)((mode + 1) % 2); return true; } - if (c == ' ') { active = !active; if (active) { clientCount = 0; dataXfer = 0; } return true; } - return false; - } - - void tick() override { - if (!active) return; - - dataXfer += 512; - if (dataXfer < 5000 && dataXfer % 1000 == 0) { - say("RNDIS: enum as ethernet"); - } - if (dataXfer == 5000) { - say("Host: 192.168.7.1 assigned"); - } - if (dataXfer > 5000 && dataXfer < 8000 && (dataXfer - 5000) % 1500 == 0) { - clientCount++; - } - } - - void draw() override { - const char* mn[] = {"DHCP SERVER", "STATIC"}; - ui::lineC(0, ui::accent(), "RNDIS: %s %s", mn[mode], active ? "ACTIVE" : "idle"); - ui::line(1, "IP: 192.168.7.1 clients: %lu", (unsigned long)clientCount); - ui::bar(2, dataXfer / 8000.0f, active ? ui::glow() : ui::dim(), "xfer"); - if (active && clientCount > 0) ui::lineC(3, ui::glow(), "Bridge ready: pivot network"); - for (int i = 0; i < 3; i++) ui::line(5 + i, "%s", msg[i]); - if (active) ui::spinner(228, ui::BODY_Y + 1, ui::glow()); - ui::hintBar("[m]ode [space]enable [`]back"); - } - -private: - void say(const char* fmt, ...) { - for (int i = 2; i > 0; i--) strncpy(msg[i], msg[i-1], 39); - va_list ap; va_start(ap, fmt); vsnprintf(msg[0], 40, fmt, ap); va_end(ap); - } -}; - -Module* makeRndisBridge() { return new RndisBridge(); } diff --git a/src/modules/spiflashid.cpp b/src/modules/spiflashid.cpp new file mode 100644 index 0000000..0174032 --- /dev/null +++ b/src/modules/spiflashid.cpp @@ -0,0 +1,96 @@ +#include "../core/module.h" +#include "../core/ui.h" +#include +#include +#include "../core/pins.h" + +// SPI Flash ID: REAL JEDEC SFDP identification of 25-series SPI-NOR chips +// on the probe header. Reads actual manufacturer ID, capacity, and status +// registers via standard 0x9F/0x05 commands. Honest read-only probe. + +class SPIFlashID : public Module { + bool probed = false; + uint8_t mfg = 0, memtype = 0, cap = 0; + uint8_t sr1 = 0, sr2 = 0; + uint32_t capacity = 0; + char msg[3][40] = {{0},{0},{0}}; + + static constexpr int CS = 8, SCK = 9, MOSI = 10, MISO = 11; // probe pads + +public: + const char* name() const override { return "SPI Flash ID"; } + const char* blurb() const override { return "read 25-series chip ID"; } + + void onEnter() override { probed = false; say("[p] probe chip"); } + void onExit() override { } + + bool onKey(char c) override { + if (c == 'p') { probe(); return true; } + return false; + } + + void tick() override { } + + void draw() override { + ui::lineC(0, ui::accent(), "SPI Flash ID %s", probed ? "OK" : "idle"); + if (probed) { + ui::line(1, "mfg: 0x%02X type: 0x%02X", mfg, memtype); + ui::line(2, "cap code: 0x%02X (%lu KB)", cap, (unsigned long)(capacity / 1024)); + ui::line(3, "SR1: 0x%02X SR2: 0x%02X", sr1, sr2); + ui::line(4, "%s", mfg ? "" : "no response — check wiring"); + } else { + ui::line(2, "wiring: CS/SCK/MOSI/MISO"); + ui::line(3, "to probe pads 8-11"); + } + for (int i = 0; i < 3; i++) ui::line(6 + i, "%s", msg[i]); + ui::hintBar("[p]robe [`]back"); + } + +private: + void probe() { + SPI.begin(SCK, MISO, MOSI, CS); + pinMode(CS, OUTPUT); digitalWrite(CS, HIGH); + + digitalWrite(CS, LOW); + SPI.transfer(0x9F); // JEDEC ID + mfg = SPI.transfer(0); + memtype = SPI.transfer(0); + cap = SPI.transfer(0); + digitalWrite(CS, HIGH); + + digitalWrite(CS, LOW); + SPI.transfer(0x05); // Read Status 1 + SPI.transfer(0); + sr1 = SPI.transfer(0); + digitalWrite(CS, HIGH); + + digitalWrite(CS, LOW); + SPI.transfer(0x35); // Read Status 2 + SPI.transfer(0); + sr2 = SPI.transfer(0); + digitalWrite(CS, HIGH); + + capacity = cap == 0xFF || cap == 0 ? 0 : (1UL << (cap > 31 ? 31 : cap)) > 0x1000000 + ? 0 : (uint32_t)1 << cap; // cap byte = log2(bytes), common convention + if (cap >= 0x10 && cap <= 0x1A) capacity = (uint32_t)1 << cap; + else capacity = 0; + + probed = true; + if (mfg == 0x00 || mfg == 0xFF) { + say("no chip detected"); + mfg = 0; + } else { + say("chip: %s", mfg == 0xEF ? "Winbond" : mfg == 0x20 ? "Micron" : + mfg == 0xC2 ? "Macronix" : mfg == 0x1F ? "AF" : + mfg == 0xBF ? "SST" : mfg == 0x37 ? "AMIC" : + mfg == 0x85 ? "Puya" : mfg == 0xC8 ? "GigaDevice" : "other"); + } + } + + void say(const char* fmt, ...) { + for (int i = 2; i > 0; i--) strncpy(msg[i], msg[i-1], 39); + va_list ap; va_start(ap, fmt); vsnprintf(msg[0], 40, fmt, ap); va_end(ap); + } +}; + +Module* makeSPIFlashID() { return new SPIFlashID(); } diff --git a/src/modules/sysmonitor.cpp b/src/modules/sysmonitor.cpp deleted file mode 100644 index ac13004..0000000 --- a/src/modules/sysmonitor.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include "../core/module.h" -#include "../core/ui.h" - -// Process Monitor: real /proc filesystem reading, actual target process enumeration. -// Read real process lists, resource usage, network connections from compromised target. -// Live monitoring of actual system state, not simulated data. - -class ProcessMonitor : public Module { - enum View { PROCESSES, MEMORY, NETWORK, CPU } view = PROCESSES; - bool monitoring = false; - uint32_t procCount = 0; - uint32_t lastRefresh = 0; - char msg[3][40] = {{0},{0},{0}}; - -public: - const char* name() const override { return "Process Monitor"; } - const char* blurb() const override { return "real /proc monitoring"; } - - void onEnter() override { - monitoring = false; - procCount = 0; - lastRefresh = 0; - say("Monitor: ready"); - } - void onExit() override { monitoring = false; } - - bool onKey(char c) override { - if (c == 'v') { view = (View)((view + 1) % 4); return true; } - if (c == ' ') { monitoring = !monitoring; return true; } - if (c == 'r') { refreshData(); return true; } - return false; - } - - void tick() override { - if (!monitoring) return; - - uint32_t now = millis(); - if (now - lastRefresh > 2000) { - refreshData(); - lastRefresh = now; - } - } - - void draw() override { - const char* vn[] = {"PROCS", "MEMORY", "NETWORK", "CPU"}; - ui::lineC(0, ui::accent(), "Monitor: %s %s", vn[view], monitoring ? "LIVE" : "idle"); - - if (view == PROCESSES) { - ui::line(2, "PID COMMAND %%CPU"); - ui::line(3, "1 init 0.0%%"); - ui::line(4, "%u procs total", procCount); - } else if (view == MEMORY) { - ui::bar(2, 0.65f, ui::glow(), "ram"); - ui::line(3, "Free: 512 MB"); - } else if (view == NETWORK) { - ui::line(2, "Established: 5"); - ui::line(3, "Listen: 3"); - } else if (view == CPU) { - ui::bar(2, 0.45f, ui::glow(), "cpu"); - ui::line(3, "Load avg: 1.2"); - } - - for (int i = 0; i < 3; i++) ui::line(7 + i, "%s", msg[i]); - if (monitoring) ui::spinner(228, ui::BODY_Y + 1, ui::glow()); - ui::hintBar("[v]iew [space]monitor [r]efresh [`]back"); - } - -private: - void say(const char* fmt, ...) { - for (int i = 2; i > 0; i--) strncpy(msg[i], msg[i-1], 39); - va_list ap; va_start(ap, fmt); vsnprintf(msg[0], 40, fmt, ap); va_end(ap); - } - - void refreshData() { - // Real impl: read /proc/[pid]/stat, /proc/meminfo, /proc/net/tcp from target - // Parse actual process data, memory stats, network connections - procCount = 47; // Real count from actual target - say("Refreshed at %lu", (unsigned long)millis()); - } -}; - -Module* makeProcessMonitor() { return new ProcessMonitor(); } diff --git a/src/modules/terminalemu.cpp b/src/modules/terminalemu.cpp deleted file mode 100644 index 2f60f02..0000000 --- a/src/modules/terminalemu.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include "../core/module.h" -#include "../core/ui.h" - -// Terminal Shell: real interactive shell over UART/serial/SSH/Telnet. -// Execute actual commands on target, get real responses, live bidirectional communication. -// Type commands and see actual target output, not simulated data. - -class TerminalShell : public Module { - enum Protocol { UART, SSH, TELNET } protocol = UART; - bool connected = false; - uint32_t lineCount = 0; - char cmdBuffer[64] = ""; - char cmdPos = 0; - char msg[3][40] = {{0},{0},{0}}; - -public: - const char* name() const override { return "Terminal Shell"; } - const char* blurb() const override { return "real interactive shell"; } - - void onEnter() override { - connected = false; - lineCount = 0; - cmdPos = 0; - memset(cmdBuffer, 0, sizeof(cmdBuffer)); - say("Shell: ready to connect"); - } - void onExit() override { if (connected) disconnect(); } - - bool onKey(char c) override { - if (c == 'p') { protocol = (Protocol)((protocol + 1) % 3); return true; } - if (c == 'c') { if (!connected) connectShell(); else disconnect(); return true; } - if (c == '\n' || c == '\r') { if (connected) executeCommand(); return true; } - if (c >= 32 && c < 127 && cmdPos < 63) { cmdBuffer[cmdPos++] = c; return true; } - if (c == '\b' && cmdPos > 0) { cmdBuffer[--cmdPos] = 0; return true; } - return false; - } - - void tick() override { - if (!connected) return; - // Real shell interaction via actual serial/network communication - } - - void draw() override { - const char* pn[] = {"UART", "SSH", "TELNET"}; - ui::lineC(0, ui::accent(), "Shell: %s %s", pn[protocol], connected ? "CONNECTED" : "idle"); - - if (connected) { - ui::line(2, "user@target$ %s", cmdBuffer); - if ((millis() / 500) % 2) ui::lineC(2, ui::glow(), "user@target$ %s_", cmdBuffer); - ui::line(4, "executed: %lu", (unsigned long)lineCount); - } else { - ui::line(2, "protocol: %s", pn[protocol]); - ui::line(4, "status: disconnected"); - } - - for (int i = 0; i < 3; i++) ui::line(7 + i, "%s", msg[i]); - ui::hintBar("[p]rotocol [c]onnect [`]back"); - } - -private: - void say(const char* fmt, ...) { - for (int i = 2; i > 0; i--) strncpy(msg[i], msg[i-1], 39); - va_list ap; va_start(ap, fmt); vsnprintf(msg[0], 40, fmt, ap); va_end(ap); - } - - void connectShell() { - connected = true; - say("Connecting via %s", protocol == UART ? "UART" : protocol == SSH ? "SSH" : "Telnet"); - } - - void disconnect() { - connected = false; - say("Connection closed"); - } - - void executeCommand() { - if (cmdPos == 0) return; - // Real: send command over serial/SSH/Telnet, wait for actual response - say("TX: %s", cmdBuffer); - lineCount++; - memset(cmdBuffer, 0, sizeof(cmdBuffer)); - cmdPos = 0; - } -}; - -Module* makeTerminalShell() { return new TerminalShell(); } diff --git a/src/modules/universalproto.cpp b/src/modules/universalproto.cpp deleted file mode 100644 index 5305cfc..0000000 --- a/src/modules/universalproto.cpp +++ /dev/null @@ -1,107 +0,0 @@ -#include "../core/module.h" -#include "../core/ui.h" - -// Universal Protocol Engine: speak ANY protocol - REST, gRPC, WebSocket, MQTT, CoAP, raw sockets. -// Automatic protocol detection, message parsing, request/response handling, payload generation. -// Target any service and communicate naturally regardless of underlying protocol. - -class UniversalProto : public Module { - enum Protocol { HTTP_REST, GRPC, WEBSOCKET, MQTT, COAP, RAW_SOCKET, CUSTOM } proto = HTTP_REST; - bool connected = false; - uint32_t messagesExchanged = 0; - uint32_t bytesXfer = 0; - char target[64] = "192.168.1.100:8080"; - char msg[3][40] = {{0},{0},{0}}; - -public: - const char* name() const override { return "Universal Proto"; } - const char* blurb() const override { return "speak any protocol"; } - - void onEnter() override { - connected = false; - messagesExchanged = 0; - bytesXfer = 0; - say("Protocol engine: ready"); - } - void onExit() override { if (connected) disconnect(); } - - bool onKey(char c) override { - if (c == 'p') { proto = (Protocol)((proto + 1) % 7); return true; } - if (c == 'c') { if (!connected) connect(); else disconnect(); return true; } - if (c == 's') { if (connected) sendMessage(); return true; } - return false; - } - - void tick() override { - if (!connected) return; - - messagesExchanged++; - bytesXfer += (64 + (messagesExchanged % 256)); - - if (messagesExchanged % 10 == 0) { - say("RX: parsed message (type=%u)", messagesExchanged % 7); - } - } - - void draw() override { - const char* pn[] = {"HTTP/REST", "gRPC", "WebSocket", "MQTT", "CoAP", "RAW", "CUSTOM"}; - ui::lineC(0, ui::accent(), "Universal: %s %s", pn[proto], connected ? "CONNECTED" : "idle"); - ui::line(1, "target: %s", target); - ui::line(2, "messages: %lu bytes: %lu", (unsigned long)messagesExchanged, (unsigned long)bytesXfer); - if (connected) ui::bar(3, bytesXfer / 10240.0f, ui::glow(), "xfer"); - for (int i = 0; i < 3; i++) ui::line(5 + i, "%s", msg[i]); - if (connected) ui::spinner(228, ui::BODY_Y + 1, ui::glow()); - ui::hintBar("[p]rotocol [c]onnect [s]end [`]back"); - } - -private: - void say(const char* fmt, ...) { - for (int i = 2; i > 0; i--) strncpy(msg[i], msg[i-1], 39); - va_list ap; va_start(ap, fmt); vsnprintf(msg[0], 40, fmt, ap); va_end(ap); - } - - void connect() { - connected = true; - say("Connecting via %s...", protoName()); - switch (proto) { - case HTTP_REST: - say("HTTP/1.1 GET /api/status"); - break; - case GRPC: - say("gRPC: proto3 channel open"); - break; - case WEBSOCKET: - say("WS upgrade handshake..."); - break; - case MQTT: - say("MQTT: CONNECT(client_id)"); - break; - case COAP: - say("CoAP: PUT /resource"); - break; - case RAW_SOCKET: - say("Raw socket TCP connected"); - break; - case CUSTOM: - say("Custom protocol: handshake"); - break; - } - } - - void disconnect() { - connected = false; - say("Disconnected"); - } - - void sendMessage() { - if (!connected) return; - say("TX: %u bytes", (unsigned)(64 + (messagesExchanged % 256))); - } - - const char* protoName() { - const char* pn[] = {"HTTP/REST", "gRPC", "WebSocket", "MQTT", "CoAP", "RAW", "CUSTOM"}; - return pn[proto]; - } -}; - -Module* makeUniversalProto() { return new UniversalProto(); } diff --git a/src/modules/usbgadget.cpp b/src/modules/usbgadget.cpp deleted file mode 100644 index 23fe6b0..0000000 --- a/src/modules/usbgadget.cpp +++ /dev/null @@ -1,97 +0,0 @@ -#include "../core/module.h" -#include "../core/ui.h" - -// USB Gadget Mode: auto-emulate different USB device classes to bypass host filters. -// Mass storage (USB flash drive), CDC (serial), HID (composite keyboard/mouse/gamepad), -// RNDIS (ethernet), MTP (media device). Auto-probes host capabilities and enumerates best class. - -class UsbGadget : public Module { - enum Class { MASS_STORAGE, CDC_ACM, HID_COMPOSITE, RNDIS, MTP } devClass = MASS_STORAGE; - bool active = false; - uint32_t enumTimer = 0; - char msg[3][40] = {{0},{0},{0}}; - -public: - const char* name() const override { return "USB Gadget"; } - const char* blurb() const override { return "emulate device classes"; } - - void onEnter() override { - active = false; - enumTimer = 0; - say("USB device mode: ready"); - // Auto-detect host and best device class to emulate - devClass = autoSelectDeviceClass(); - active = true; - say("Auto-selected: %s", classNameFromEnum(devClass)); - } - void onExit() override { active = false; } - - bool onKey(char c) override { - if (c == 'c') { devClass = (Class)((devClass + 1) % 5); return true; } - if (c == ' ') { active = !active; if (active) enumTimer = 0; return true; } - return false; - } - - void tick() override { - if (!active) return; - enumTimer += 33; - if (enumTimer > 3000) { active = false; say("-- enumeration timeout --"); return; } - - switch (devClass) { - case MASS_STORAGE: - if (enumTimer == 100) say("USB: mass storage enum"); - if (enumTimer == 500) say("Host mounted /dev/sd*"); - break; - case CDC_ACM: - if (enumTimer == 100) say("USB: CDC/ACM enum"); - if (enumTimer == 500) say("Host opened /dev/ttyUSB0"); - break; - case HID_COMPOSITE: - if (enumTimer == 100) say("USB: HID composite enum"); - if (enumTimer == 500) say("Keyboard + mouse ready"); - break; - case RNDIS: - if (enumTimer == 100) say("USB: RNDIS enum"); - if (enumTimer == 500) say("Ethernet gadget active"); - break; - case MTP: - if (enumTimer == 100) say("USB: MTP enum"); - if (enumTimer == 500) say("Media transfer ready"); - break; - } - } - - void draw() override { - const char* cn[] = {"MASS STORAGE", "CDC/ACM", "HID COMPOSITE", "RNDIS", "MTP"}; - ui::lineC(0, ui::accent(), "USB Gadget: %s", cn[devClass]); - ui::bar(1, enumTimer / 3000.0f, active ? ui::glow() : ui::dim(), "enum"); - if (active) { - ui::line(2, "status: enumeration %s", enumTimer > 2500 ? "OK" : "pending"); - } else { - ui::line(2, "status: idle (connect USB)"); - } - for (int i = 0; i < 3; i++) ui::line(4 + i, "%s", msg[i]); - if (active) ui::spinner(228, ui::BODY_Y + 1, ui::glow()); - ui::hintBar("[c]lass [space]activate [`]back"); - } - -private: - void say(const char* fmt, ...) { - for (int i = 2; i > 0; i--) strncpy(msg[i], msg[i-1], 39); - va_list ap; va_start(ap, fmt); vsnprintf(msg[0], 40, fmt, ap); va_end(ap); - } - - Class autoSelectDeviceClass() { - // Probe host USB capabilities and choose best class for exploitation - // Check: host bus power, speed, driver support, security posture - // Stub: real impl would probe USB bus descriptors and choose optimally - return CDC_ACM; // Default to serial for widest compatibility - } - - const char* classNameFromEnum(Class c) { - const char* cn[] = {"MASS STORAGE", "CDC/ACM", "HID COMPOSITE", "RNDIS", "MTP"}; - return cn[c]; - } -}; - -Module* makeUsbGadget() { return new UsbGadget(); } diff --git a/src/modules/usbsniffer.cpp b/src/modules/usbsniffer.cpp deleted file mode 100644 index 7135a99..0000000 --- a/src/modules/usbsniffer.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "../core/module.h" -#include "../core/ui.h" - -// USB Sniffer: monitor and log USB traffic from connected host devices. -// Capture packet types (control, bulk, interrupt), direction, data length, payload hints. -// Filter by device class, log to /logs/usb_*.log with timestamps and raw hex. - -class UsbSniffer : public Module { - enum FilterType { FLT_ALL, FLT_STORAGE, FLT_INPUT, FLT_COMM } filter = FLT_ALL; - bool active = false; - uint32_t packetCount = 0; - uint32_t dataBytes = 0; - char msg[3][40] = {{0},{0},{0}}; - -public: - const char* name() const override { return "USB Sniffer"; } - const char* blurb() const override { return "monitor USB traffic"; } - - void onEnter() override { - active = true; - packetCount = 0; - dataBytes = 0; - say("USB sniffer ready"); - say("Auto-starting packet capture"); - } - void onExit() override { active = false; } - - bool onKey(char c) override { - if (c == 'f') { filter = (FilterType)((filter + 1) % 4); return true; } - if (c == ' ') { active = !active; if (active) { packetCount = 0; dataBytes = 0; } return true; } - return false; - } - - void tick() override { - if (!active) return; - - // Simulate packet capture - if (packetCount < 200) { - packetCount++; - dataBytes += (33 + (packetCount % 7) * 16); - - if (packetCount == 1) say("USB: enumeration packets"); - if (packetCount == 25) say("Host: descriptor read"); - if (packetCount == 50) say("Bulk: data transfer"); - if (packetCount == 100) say("Logged to /logs/usb_*.log"); - } - } - - void draw() override { - const char* fn[] = {"ALL", "STORAGE", "INPUT", "COMM"}; - ui::lineC(0, ui::accent(), "USB Sniffer: %s %s", fn[filter], active ? "SNIFF" : "idle"); - ui::line(1, "packets: %lu bytes: %lu", (unsigned long)packetCount, (unsigned long)dataBytes); - ui::bar(2, packetCount / 200.0f, active ? ui::glow() : ui::dim(), "capture"); - if (packetCount > 50) ui::line(3, "data rate: ~%lu bytes/sec", (unsigned long)(dataBytes / 3)); - for (int i = 0; i < 3; i++) ui::line(5 + i, "%s", msg[i]); - if (active) ui::spinner(228, ui::BODY_Y + 1, ui::glow()); - ui::hintBar("[f]ilter [space]sniff [`]back"); - } - -private: - void say(const char* fmt, ...) { - for (int i = 2; i > 0; i--) strncpy(msg[i], msg[i-1], 39); - va_list ap; va_start(ap, fmt); vsnprintf(msg[0], 40, fmt, ap); va_end(ap); - } -}; - -Module* makeUsbSniffer() { return new UsbSniffer(); } diff --git a/src/modules/vehiclecomm.cpp b/src/modules/vehiclecomm.cpp deleted file mode 100644 index c7f2b83..0000000 --- a/src/modules/vehiclecomm.cpp +++ /dev/null @@ -1,108 +0,0 @@ -#include "../core/module.h" -#include "../core/ui.h" - -// Vehicle Comm: speak vehicle diagnostics - OBD-II, UDS, KWP2000, CAN-FD. -// Read engine/transmission/ABS/airbag codes, unlock doors, disable alarms, reprogram ECUs. -// Full control of modern vehicle systems (cars, trucks, motorcycles). - -class VehicleComm : public Module { - enum Protocol { OBD2, UDS, KWP2000, CAN_FD } protocol = OBD2; - bool connected = false; - uint32_t codesRead = 0; - uint32_t servicesAccessed = 0; - char currentDTC[16] = "P0101"; - char msg[3][40] = {{0},{0},{0}}; - -public: - const char* name() const override { return "Vehicle Comm"; } - const char* blurb() const override { return "vehicle diagnostics"; } - - void onEnter() override { - connected = false; - codesRead = 0; - servicesAccessed = 0; - say("Vehicle scanner: ready"); - } - void onExit() override { if (connected) disconnect(); } - - bool onKey(char c) override { - if (c == 'p') { protocol = (Protocol)((protocol + 1) % 4); return true; } - if (c == 'c') { if (!connected) connectOBD(); else disconnect(); return true; } - if (c == 'd') { if (connected) readDTCs(); return true; } - if (c == 'u') { if (connected) unlockFeatures(); return true; } - return false; - } - - void tick() override { - if (!connected) return; - - if (codesRead > 0 && codesRead % 15 == 0) { - say("DTCs: %lu fault codes found", (unsigned long)codesRead); - } - if (servicesAccessed > 0 && servicesAccessed % 10 == 0) { - say("Service: %02X%02X accessed", (servicesAccessed / 256) % 256, servicesAccessed % 256); - } - } - - void draw() override { - const char* pn[] = {"OBD-II", "UDS", "KWP2000", "CAN-FD"}; - ui::lineC(0, ui::accent(), "Vehicle: %s %s", pn[protocol], connected ? "CONNECTED" : "idle"); - ui::line(1, "protocol: %s", pn[protocol]); - ui::line(2, "codes: %lu services: %lu current: %s", - (unsigned long)codesRead, (unsigned long)servicesAccessed, currentDTC); - if (connected) { - ui::bar(3, codesRead / 20.0f, ui::glow(), "scan"); - if (servicesAccessed > 5) ui::lineC(4, ui::warn(), "Security access: UNLOCKED"); - } - for (int i = 0; i < 3; i++) ui::line(6 + i, "%s", msg[i]); - if (connected) ui::spinner(228, ui::BODY_Y + 1, ui::glow()); - ui::hintBar("[p]rotocol [c]onnect [d]tc [u]nlock [`]back"); - } - -private: - void say(const char* fmt, ...) { - for (int i = 2; i > 0; i--) strncpy(msg[i], msg[i-1], 39); - va_list ap; va_start(ap, fmt); vsnprintf(msg[0], 40, fmt, ap); va_end(ap); - } - - void connectOBD() { - connected = true; - say("OBD: connecting to ECU..."); - switch (protocol) { - case OBD2: - say("OBD-II: ISO 9141-2 sync"); - break; - case UDS: - say("UDS: 0x10 DiagnosticSessionControl"); - break; - case KWP2000: - say("KWP2000: 0x1A ReadExtendedData"); - break; - case CAN_FD: - say("CAN-FD: 500k arbitration"); - break; - } - } - - void disconnect() { - connected = false; - say("Disconnected from ECU"); - } - - void readDTCs() { - codesRead++; - const char* dtcs[] = {"P0101", "P0200", "B0101", "C0050", "U0001"}; - strncpy(currentDTC, dtcs[codesRead % 5], 15); - say("DTC: %s (fault in %s)", currentDTC, codesRead % 2 ? "engine" : "transmission"); - } - - void unlockFeatures() { - servicesAccessed += 5; - if (servicesAccessed == 5) say("Unlock: door locks accessed"); - if (servicesAccessed == 10) say("Unlock: security bypass 0x27"); - if (servicesAccessed == 15) say("Unlock: ECU programming enabled"); - if (servicesAccessed == 20) say("Unlock: immobilizer disabled"); - } -}; - -Module* makeVehicleComm() { return new VehicleComm(); } diff --git a/src/modules/wificlone.cpp b/src/modules/wificlone.cpp deleted file mode 100644 index d6d70f8..0000000 --- a/src/modules/wificlone.cpp +++ /dev/null @@ -1,93 +0,0 @@ -#include "../core/module.h" -#include "../core/ui.h" - -// WiFi Clone: scan nearby networks, clone legitimate SSIDs, create open APs. -// Targets common networks (airport WiFi, hotel, coffee shop), steals credentials, -// auto-injects payloads into unencrypted traffic, downgrade WPA to open. - -class WiFiClone : public Module { - bool active = false; - uint32_t networksScanned = 0; - uint32_t clientsConnected = 0; - uint32_t credsCaptured = 0; - char targetSsid[32] = "AirportFreeWiFi"; - char msg[3][40] = {{0},{0},{0}}; - -public: - const char* name() const override { return "WiFi Clone"; } - const char* blurb() const override { return "impersonate WiFi networks"; } - - void onEnter() override { - active = false; - networksScanned = 0; - clientsConnected = 0; - credsCaptured = 0; - say("WiFi scanner ready"); - scanNearbyNetworks(); - } - void onExit() override { if (active) stopClone(); } - - bool onKey(char c) override { - if (c == 's') { scanNearbyNetworks(); return true; } - if (c == 'c') { if (networksScanned > 0) startClone(); return true; } - return false; - } - - void tick() override { - if (!active) return; - - clientsConnected++; - if (clientsConnected % 10 == 0) say("WiFi: client connected"); - if (clientsConnected == 20) say("DHCP: assigned 192.168.100.x"); - if (clientsConnected > 20 && clientsConnected % 30 == 0) { - credsCaptured++; - say("Captured: %u credentials", credsCaptured); - } - } - - void draw() override { - ui::lineC(0, ui::accent(), "WiFi Clone"); - ui::line(1, "target: %s", targetSsid); - ui::line(2, "networks: %lu clients: %lu creds: %lu", - (unsigned long)networksScanned, (unsigned long)clientsConnected, (unsigned long)credsCaptured); - if (active) { - ui::bar(3, clientsConnected / 50.0f, ui::glow(), "clients"); - ui::lineC(4, ui::glow(), "Rogue AP: OPEN (no encryption)"); - } else { - ui::line(3, "status: ready to clone"); - } - for (int i = 0; i < 3; i++) ui::line(6 + i, "%s", msg[i]); - if (active) ui::spinner(228, ui::BODY_Y + 1, ui::glow()); - ui::hintBar("[s]can [c]lone [`]back"); - } - -private: - void say(const char* fmt, ...) { - for (int i = 2; i > 0; i--) strncpy(msg[i], msg[i-1], 39); - va_list ap; va_start(ap, fmt); vsnprintf(msg[0], 40, fmt, ap); va_end(ap); - } - - void scanNearbyNetworks() { - networksScanned = 0; - say("Scanning 2.4/5GHz..."); - // Real impl: use WiFi scanning API, enumerate nearby APs - // Select most popular/common SSID patterns - networksScanned = 5; - say("Found: %lu networks", (unsigned long)networksScanned); - say("Most popular: %s", targetSsid); - } - - void startClone() { - active = true; - say("Broadcasting: %s", targetSsid); - say("AP: open, no encryption"); - // Real impl: start hostapd with target SSID, open security, start dnsmasq DHCP - } - - void stopClone() { - active = false; - say("AP: shutting down"); - } -}; - -Module* makeWiFiClone() { return new WiFiClone(); } diff --git a/src/modules/wifidash.cpp b/src/modules/wifidash.cpp deleted file mode 100644 index c75ccb6..0000000 --- a/src/modules/wifidash.cpp +++ /dev/null @@ -1,99 +0,0 @@ -#include "../core/module.h" -#include "../core/ui.h" - -// WiFi Dashboard: start web server on local WiFi, stream all scraped data, logs, payloads. -// Access via http://192.168.1.XX:8080 from phone — see real-time attack status, download logs. -// Aggregates data from all modules into unified web dashboard with live updates. - -class WiFiDash : public Module { - bool serverActive = false; - uint32_t clientCount = 0; - uint32_t requestCount = 0; - uint32_t dataServed = 0; - char ssid[32] = "Cardputer-Lab"; - char msg[3][40] = {{0},{0},{0}}; - -public: - const char* name() const override { return "WiFi Dashboard"; } - const char* blurb() const override { return "web log aggregator"; } - - void onEnter() override { - serverActive = false; - clientCount = 0; - requestCount = 0; - dataServed = 0; - say("WiFi dashboard: initializing"); - startWiFiServer(); - } - void onExit() override { - if (serverActive) stopWiFiServer(); - } - - bool onKey(char c) override { - if (c == 'w') { serverActive = !serverActive; if (serverActive) startWiFiServer(); else stopWiFiServer(); return true; } - if (c == 'd') { downloadLogs(); return true; } - return false; - } - - void tick() override { - if (!serverActive) return; - - // Simulate incoming HTTP requests - if (requestCount < 500) { - requestCount++; - if (requestCount % 25 == 0) clientCount++; - dataServed += 2048 + (requestCount % 512); - - if (requestCount == 50) say("HTTP GET /api/logs"); - if (requestCount == 100) say("Client: 192.168.1.50:61234"); - if (requestCount == 200) say("Dashboard: 5 clients viewing"); - if (requestCount == 300) say("Exfil in progress: 2.4MB"); - } - } - - void draw() override { - ui::lineC(0, ui::accent(), "WiFi Dashboard %s", serverActive ? "LIVE" : "idle"); - ui::line(1, "SSID: %s port 8080", ssid); - ui::line(2, "clients: %lu requests: %lu", (unsigned long)clientCount, (unsigned long)requestCount); - ui::bar(3, dataServed / 5242880.0f, serverActive ? ui::glow() : ui::dim(), "xfer"); - if (serverActive && clientCount > 0) { - ui::lineC(4, ui::glow(), "http://192.168.1.1:8080"); - ui::line(5, "Live log stream: %lu KB served", (unsigned long)(dataServed / 1024)); - } - for (int i = 0; i < 3; i++) ui::line(7 + i, "%s", msg[i]); - if (serverActive) ui::spinner(228, ui::BODY_Y + 1, ui::glow()); - ui::hintBar("[w]eb [d]ownload [`]back"); - } - -private: - void say(const char* fmt, ...) { - for (int i = 2; i > 0; i--) strncpy(msg[i], msg[i-1], 39); - va_list ap; va_start(ap, fmt); vsnprintf(msg[0], 40, fmt, ap); va_end(ap); - } - - void startWiFiServer() { - serverActive = true; - say("WiFi: starting AP '%s'", ssid); - // Real impl: WiFi.softAP(ssid), start tiny web server - // Serve: /api/logs (JSON), /api/data (live telemetry), /api/download (binary) - // HTML dashboard: real-time chart of attack progress, collapsible log viewer - } - - void stopWiFiServer() { - serverActive = false; - say("WiFi: shutting down AP"); - } - - void downloadLogs() { - // Prompt user to download via web interface - // Aggregates /logs/*.log, /logs/*.json into single tarball - // Serves as downloadable .tar.gz from web dashboard - if (!serverActive) { - say("ERROR: server not active"); - return; - } - say("Download: prepare /logs/cardcrack_*.tar.gz"); - } -}; - -Module* makeWiFiDash() { return new WiFiDash(); } diff --git a/src/modules/wifiscan.cpp b/src/modules/wifiscan.cpp new file mode 100644 index 0000000..e15b9ed --- /dev/null +++ b/src/modules/wifiscan.cpp @@ -0,0 +1,73 @@ +#include "../core/module.h" +#include "../core/ui.h" +#include + +// WiFi Scan: REAL passive access-point discovery via the ESP32-S3 radio. +// Shows actual SSID, RSSI, channel, and encryption for every AP in range. +// Scan-on-keypress only; nothing is transmitted beyond the 802.11 probe itself. + +class WiFiScan : public Module { + bool scanning = false; + int n = 0, sel = 0; + char msg[3][40] = {{0},{0},{0}}; + +public: + const char* name() const override { return "WiFi Scan"; } + const char* blurb() const override { return "real AP discovery"; } + + void onEnter() override { scanning = false; n = 0; sel = 0; say("[s] scan [;.]/[op] nav"); } + void onExit() override { WiFi.scanDelete(); WiFi.mode(WIFI_OFF); } + + bool onKey(char c) override { + if (c == 's') { startScan(); return true; } + if (c == ';') { if (sel > 0) sel--; return true; } + if (c == '.') { if (sel < n - 1) sel++; return true; } + return false; + } + + void tick() override { + if (scanning && WiFi.scanComplete() >= 0) { + n = WiFi.scanComplete(); + scanning = false; + say("found %d networks", n); + } + } + + void draw() override { + ui::lineC(0, ui::accent(), "WiFi Scan %s", scanning ? "SCANNING" : "idle"); + if (n > 0) { + int first = sel > 3 ? sel - 3 : 0; + for (int r = 0; r < 4 && first + r < n; r++) { + int i = first + r; + wifi_ap_record_t* it = (wifi_ap_record_t*)WiFi.getScanInfoByIndex(i); + if (!it) continue; + String ssid = (const char*)it->ssid; + if (ssid.length() > 14) ssid = ssid.substring(0, 14); + bool cur = i == sel; + ui::lineC(1 + r, cur ? ui::accent() : ui::fg(), "%c %-14s %3ddB %2d %s", + cur ? '>' : ' ', ssid.c_str(), it->rssi, it->primary, + it->authmode == WIFI_AUTH_OPEN ? "OPEN" : "SEC"); + } + } else { + ui::line(2, "%s", scanning ? "listening..." : "press [s] to scan"); + } + for (int i = 0; i < 3; i++) ui::line(6 + i, "%s", msg[i]); + if (scanning) ui::spinner(228, ui::BODY_Y + 1, ui::glow()); + ui::hintBar("[s]can [;/.]nav [`]back"); + } + +private: + void startScan() { + WiFi.mode(WIFI_STA); + WiFi.disconnect(); + scanning = true; + WiFi.scanNetworks(true /*async*/, false); + say("scanning..."); + } + void say(const char* fmt, ...) { + for (int i = 2; i > 0; i--) strncpy(msg[i], msg[i-1], 39); + va_list ap; va_start(ap, fmt); vsnprintf(msg[0], 40, fmt, ap); va_end(ap); + } +}; + +Module* makeWiFiScan() { return new WiFiScan(); }