Compare commits

..

1 Commits

40 changed files with 510 additions and 2969 deletions

View File

@@ -3,7 +3,6 @@
#include "theme.h"
#include <M5Cardputer.h>
Module* makeQuickAttack();
Module* makePinScan();
Module* makeVSense();
Module* makeUartSniff();
@@ -13,9 +12,7 @@ Module* makeBusDump();
Module* makeCrypto();
Module* makeExfil();
Module* makeThemePicker();
Module* makeCan();
Module* makeUartPlus();
Module* makeProtocol();
Module* makeMemSearch();
Module* makeSessionLogger();
Module* makeInjector();
@@ -23,39 +20,19 @@ 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();
add(makeQuickAttack());
add(makePinScan());
add(makeVSense());
add(makeUartSniff());
@@ -65,9 +42,7 @@ void Shell::begin() {
add(makeCrypto());
add(makeExfil());
add(makeThemePicker());
add(makeCan());
add(makeUartPlus());
add(makeProtocol());
add(makeMemSearch());
add(makeSessionLogger());
add(makeInjector());
@@ -75,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");
@@ -127,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);
@@ -156,25 +125,24 @@ void Shell::back() {
void Shell::loop() {
M5Cardputer.update();
checkUsbAutoTrigger();
if (M5Cardputer.Keyboard.isChange() && M5Cardputer.Keyboard.isPressed()) {
auto st = M5Cardputer.Keyboard.keysState();
for (char c : st.word) {
if (c == '`' || c == 27) { if (active >= 0) { back(); continue; } }
if (c == '`') { if (active >= 0) back(); continue; }
if (active < 0) {
if (c == ';') { sel = (sel - 1 + nmods) % nmods; drawMenu(); }
else if (c == '.') { sel = (sel + 1) % nmods; drawMenu(); }
else if (c == '\r' || c == ' ') enter(sel);
} else {
bool consumed = mods[active]->onKey(c);
if (!consumed && c == '`') back();
mods[active]->onKey(c);
}
}
if (st.enter && active < 0) enter(sel);
}
if (active < 0) {
// keep the selection glow breathing — repaints only the bar strip (flicker-free)
if (millis() - lastTick > 90) { lastTick = millis(); drawMenu(false); }
return;
}
@@ -184,25 +152,3 @@ void Shell::loop() {
mods[active]->draw();
}
}
void Shell::checkUsbAutoTrigger() {
static uint32_t lastCheck = 0;
static bool wasPlugged = false;
if (millis() - lastCheck < 500) return;
lastCheck = millis();
bool isPlugged = false;
#if __has_include("tusb.h")
isPlugged = tud_mounted();
#endif
if (isPlugged && !wasPlugged) {
for (int i = 0; i < nmods; i++) {
if (strcmp(mods[i]->name(), "HID Inject") == 0) {
enter(i);
return;
}
}
}
wasPlugged = isPlugged;
}

View File

@@ -8,14 +8,14 @@ public:
void begin();
void loop();
private:
static constexpr int MAX = 50;
static constexpr int MAX = 12;
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);
void enter(int i);
void back();
void checkUsbAutoTrigger();
};

View File

@@ -1,79 +1,53 @@
#include "../core/module.h"
#include "../core/ui.h"
#include <SD.h>
// 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(); }

View File

@@ -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");
}
};
Module* makeBootExp() { return new BootExp(); }

View File

@@ -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() {
return true;
}
void forcePair() {
// Attempt to pair without PIN via LMP spoofing or service fuzzing
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(); }

View File

@@ -1,111 +0,0 @@
#include "../core/module.h"
#include "../core/ui.h"
#include "../core/pins.h"
#include <SPI.h>
#include <SD.h>
// 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);
digitalWrite(CS, LOW); SPI.transfer(0xC0); digitalWrite(CS, HIGH); delay(10);
// Set CNF registers for desired baud rate
digitalWrite(CS, LOW);
SPI.transfer(0x80); // Write instruction
SPI.transfer(0x2A); // CNF1 address
if (speed == 0) { SPI.transfer(0x00); SPI.transfer(0xA3); SPI.transfer(0x13); } // 500k
else if (speed == 1) { SPI.transfer(0x00); SPI.transfer(0xA3); SPI.transfer(0x25); } // 250k
else { SPI.transfer(0x00); SPI.transfer(0xA3); SPI.transfer(0x2B); } // 125k
digitalWrite(CS, HIGH);
// Set CANCTRL for normal mode
digitalWrite(CS, LOW);
SPI.transfer(0x80);
SPI.transfer(0x0F); // CANCTRL address
SPI.transfer(0x00); // Normal mode
digitalWrite(CS, HIGH);
say("CAN %s mode ok", speed == 0 ? "500k" : speed == 1 ? "250k" : "125k");
}
bool readFrame(uint32_t& id, uint8_t& dlc, uint8_t* data) {
digitalWrite(CS, LOW);
SPI.transfer(0x03); // Read RX0 buffer status/id
uint8_t sidh = SPI.transfer(0);
uint8_t sidl = SPI.transfer(0);
uint8_t eid8 = SPI.transfer(0);
uint8_t eid0 = SPI.transfer(0);
dlc = SPI.transfer(0) & 0x0F;
for (int i = 0; i < dlc && i < 8; i++) data[i] = SPI.transfer(0);
digitalWrite(CS, HIGH);
id = ((uint32_t)sidh << 3) | ((sidl >> 5) & 0x07);
return dlc > 0;
}
};
Module* makeCan() { return new CanSniff(); }

View File

@@ -1,89 +0,0 @@
#include "../core/module.h"
#include "../core/ui.h"
#include "mbedtls/md5.h"
#include "mbedtls/sha1.h"
#include <string.h>
// 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) {
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(); }

View File

@@ -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;
// 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(); }

View File

@@ -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);
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(); }

View File

@@ -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() {
// 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(); }

View File

@@ -1,88 +1,95 @@
#include "../core/module.h"
#include "../core/ui.h"
#include <HardwareSerial.h>
#include "../core/pins.h"
#include <SD.h>
class ExploitChain : public Module {
enum Stage { ARMED, RUN_CMD1, RUN_CMD2, RUN_CMD3, RUN_CMD4, DONE } stage = ARMED;
bool running = false;
uint32_t stageTime = 0;
uint32_t txCount = 0;
char responses[3][40] = {{0},{0},{0}};
HardwareSerial ser;
uint32_t rxBytes = 0;
// 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 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 "manual exploit send"; }
const char* name() const override { return "Auto Recon"; }
const char* blurb() const override { return "sense>probe>capture>log"; }
void onEnter() override {
running = false;
stage = ARMED;
stageTime = 0;
txCount = 0;
rxBytes = 0;
memset(responses, 0, sizeof(responses));
say("UART ready: [space] to send payloads");
ser.begin(115200, SERIAL_8N1, 16, 17);
stage = IDLE; mv = 0; foundBaud = 0; captured = 0;
say("[space] run full recon chain");
}
void onExit() override { running = false; ser.end(); }
void onExit() override { Serial1.end(); }
bool onKey(char c) override {
if (c == ' ') { running = !running; if (running) { stage = RUN_CMD1; stageTime = 0; } return true; }
if (c == 'r') { say("Reset"); stage = ARMED; running = false; stageTime = 0; 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;
stageTime++;
// Read any incoming data
while (ser.available() && rxBytes < 2000) rxBytes += ser.read();
switch (stage) {
case RUN_CMD1:
if (stageTime == 5) { ser.println("id"); txCount++; say("TX: id"); }
if (stageTime == 50) { stage = RUN_CMD2; stageTime = 0; }
break;
case RUN_CMD2:
if (stageTime == 5) { ser.println("uname -a"); txCount++; say("TX: uname -a"); }
if (stageTime == 50) { stage = RUN_CMD3; stageTime = 0; }
break;
case RUN_CMD3:
if (stageTime == 5) { ser.println("cat /proc/version"); txCount++; say("TX: cat /proc/version"); }
if (stageTime == 50) { stage = RUN_CMD4; stageTime = 0; }
break;
case RUN_CMD4:
if (stageTime == 5) { ser.println("whoami"); txCount++; say("TX: whoami"); }
if (stageTime == 50) { stage = DONE; running = false; say("Done: %u cmds, %lu rx", (unsigned)txCount, rxBytes); }
break;
case DONE: running = false; break;
default: 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;
}
break;
case DONE:
running = false;
break;
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[] = {"ARMED", "CMD1", "CMD2", "CMD3", "CMD4", "DONE"};
ui::lineC(0, ui::accent(), "Exploit: %s %s", sn[stage], running ? "ACTIVE" : "idle");
ui::line(1, "sent: %u cmds rx: %lu bytes", (unsigned)txCount, rxBytes);
if (running) ui::bar(2, stageTime / 50.0f, ui::glow(), "progress");
for (int i = 0; i < 3; i++) ui::line(4 + i, "%s", responses[i]);
if (running) ui::spinner(228, ui::BODY_Y + 1, ui::glow());
ui::hintBar("[space]execute [r]eset [`]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(responses[i], responses[i-1], 39);
va_list ap; va_start(ap, fmt); vsnprintf(responses[0], 40, fmt, ap); va_end(ap);
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* makeExploitChain() { return new ExploitChain(); }
const long ReconChain::BAUDS[ReconChain::NBAUDS] = {9600, 19200, 38400, 57600, 115200, 230400};
Module* makeExploitChain() { return new ReconChain(); }

View File

@@ -4,7 +4,7 @@
// Firmware Patcher: on-the-fly firmware modification for devices you own.
// Find/replace bytes in firmware images, patch out auth checks, modify config regions,
// inject shellcodes. All changes logged and reversible.
// inject shellcode stubs. All changes logged and reversible.
class FwPatch : public Module {
static constexpr int CAP = 4096;
@@ -87,7 +87,7 @@ private:
if (!fwLen) { say("load fw first"); return; }
// Stub: look for "if(strcmp(...) != 0)" and patch the != to always false
for (uint32_t i = 0; i < fwLen - 3; i++) {
// Pattern: CMP result, JNZ error -> becomes NOP, NOP, JMP (always pass)
if (fwBuf[i] == 0x75) { // JNZ x86

View File

@@ -1,116 +0,0 @@
#include "../core/module.h"
#include "../core/ui.h"
#include <M5Cardputer.h>
#if __has_include("class/hid/hid.h")
#include "tusb.h"
#define HAVE_TINYSB 1
#endif
class HidInjector : public Module {
bool active = false;
uint32_t sent = 0;
uint32_t lastKey = 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 "keyboard/mouse emulation"; }
void onEnter() override {
active = false;
sent = 0;
say("HID ready");
#ifdef HAVE_TINYSB
if (tud_mounted()) {
active = true;
sent = 0;
say("Host detected!");
say("Injecting...");
}
#endif
}
void onExit() override { active = false; }
bool onKey(char c) override {
if (c == ' ') { active = !active; if (active) sent = 0; return true; }
if (c == 'p') { editPayload(); return true; }
if (c == 'c') { clearPayload(); return true; }
return false;
}
void tick() override {
if (!active) return;
#ifdef HAVE_TINYSB
if (!tud_mounted()) { active = false; say("Host disconnected"); return; }
if (sent >= strlen(payload)) { active = false; say("Injection complete: %u chars", (unsigned)sent); return; }
uint32_t now = millis();
if (now - lastKey < 50) return;
lastKey = now;
char ch = payload[sent++];
sendChar(ch);
#endif
}
void draw() override {
ui::lineC(0, ui::accent(), "HID Inject %s", active ? "ACTIVE" : "idle");
ui::line(1, "payload: %s", payload[0] ? payload : "(empty)");
ui::line(2, "sent: %lu / %u", (unsigned long)sent, (unsigned)strlen(payload));
if (active) ui::bar(3, sent / (float)(strlen(payload) + 1), ui::glow(), "inject");
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("[p]ayload [c]lear [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);
}
#ifdef HAVE_TINYSB
void sendChar(char c) {
uint8_t keycode = 0;
uint8_t mod = 0;
if (c >= 'a' && c <= 'z') keycode = 0x04 + (c - 'a');
else if (c >= 'A' && c <= 'Z') { keycode = 0x04 + (c - 'A'); mod = 0x02; }
else if (c >= '0' && c <= '9') keycode = (c == '0') ? 0x27 : 0x1E + (c - '1');
else if (c == ' ') keycode = 0x2C;
else if (c == '\n') keycode = 0x28;
else if (c == '\r') keycode = 0x28;
else if (c == '.') keycode = 0x37;
else if (c == '/') keycode = 0x38;
else if (c == '-') keycode = 0x2D;
else if (c == '=') keycode = 0x2E;
if (keycode) {
uint8_t report[8] = {mod, 0, keycode, 0, 0, 0, 0, 0};
tud_hid_keyboard_report(0, mod, &keycode, 1);
delay(30);
tud_hid_keyboard_report(0, 0, nullptr, 0);
}
}
#else
void sendChar(char c) {
say("TinyUSB not available");
}
#endif
void editPayload() {
strncpy(payload, "id; uname -a\n", sizeof(payload) - 1);
sent = 0;
say("payload set to: id; uname -a");
}
void clearPayload() {
memset(payload, 0, sizeof(payload));
sent = 0;
say("payload cleared");
}
};
Module* makeHidInjector() { return new HidInjector(); }

View File

@@ -1,66 +1,61 @@
#include "../core/module.h"
#include "../core/ui.h"
#include <SD.h>
// 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(); }

95
src/modules/i2cprobe.cpp Normal file
View File

@@ -0,0 +1,95 @@
#include "../core/module.h"
#include "../core/ui.h"
#include <Wire.h>
#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(); }

View File

@@ -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(); }

View File

@@ -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());
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(); }

View File

@@ -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
say("auto-detect: %s", protocol == JTAG ? "JTAG" : "SWD");
}
};
Module* makeJtagUsbBridge() { return new JtagUsbBridge(); }

View File

@@ -104,7 +104,7 @@ private:
void exportLogs() {
say("export: tar feature pending");
// Real impl: tar /logs to /logs/backup_<ts>.tar.gz on SD
}
};

View File

@@ -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<NP;i++) edges[i]=0; } return true; }
return false;
}
void tick() override {
if (!running) return;
static uint32_t winStart = 0;
static uint32_t edgeCount[NP] = {0,0,0,0};
uint32_t now = millis();
for (int i = 0; i < NP; i++) {
uint8_t s = digitalRead(PINS[i]);
if (s != state[i]) {
state[i] = s;
edges[i]++;
edgeCount[i]++;
}
}
if (now - winStart >= 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(); }

View File

@@ -36,7 +36,7 @@ public:
void tick() override {
if (!tailing) return;
// Real impl: read actual log files from SD card or remote target
// Parse /logs/cardcrack_*.log, /logs/session_*.json, /logs/exploit_*.log
// Display real attack logs in real-time
lineCount++;
@@ -68,7 +68,7 @@ private:
}
void clearLog() {
// Real impl: delete log file from SD card
lineCount = 0;
fileSize = 0;
say("Log cleared");

View File

@@ -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
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(); }

View File

@@ -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, "<request><auth>bypass</auth>", 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(); }

View File

@@ -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(); }

View File

@@ -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(); }

View File

@@ -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;
// 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(); }

View File

@@ -1,155 +0,0 @@
#include "../core/module.h"
#include "../core/ui.h"
#include <HardwareSerial.h>
class QuickAttack : public Module {
enum Mode { DETECT, HID_INJECT, SERIAL_SHELL, DONE } mode = DETECT;
bool running = false;
uint32_t progress = 0;
uint32_t commands_sent = 0;
char response[256] = "";
HardwareSerial ser;
char msg[3][40] = {{0},{0},{0}};
public:
const char* name() const override { return "Quick Attack"; }
const char* blurb() const override { return "one-button compromise"; }
void onEnter() override {
running = false;
mode = DETECT;
progress = 0;
commands_sent = 0;
memset(response, 0, sizeof(response));
say("Auto-detect + attack");
ser.begin(115200, SERIAL_8N1, 16, 17);
delay(100);
detect();
}
void onExit() override { running = false; ser.end(); }
bool onKey(char c) override {
if (c == ' ') { if (!running) startAttack(); else running = false; return true; }
if (c == 'd') { mode = DETECT; progress = 0; detect(); return true; }
if (c == 's') { sendCommand("id"); return true; }
if (c == 'w') { sendCommand("whoami"); return true; }
return false;
}
void tick() override {
if (!running) return;
progress++;
if (mode == HID_INJECT) {
#ifdef HAVE_TINYSUB
if (progress < 50) {
static const char* cmds[] = {"id\n", "uname -a\n", "cat /proc/version\n"};
if (progress == 10) { sendHidString(cmds[0]); }
if (progress == 25) { sendHidString(cmds[1]); }
if (progress == 40) { sendHidString(cmds[2]); }
} else {
mode = DONE;
running = false;
say("HID injection complete");
}
#endif
} else if (mode == SERIAL_SHELL) {
while (ser.available()) {
char c = ser.read();
if (strlen(response) < sizeof(response) - 1) {
response[strlen(response)] = c;
}
}
if (progress > 100) {
mode = DONE;
running = false;
say("Shell commands sent: %u", (unsigned)commands_sent);
}
}
}
void draw() override {
const char* modes[] = {"DETECT", "HID_INJECT", "SHELL", "DONE"};
ui::lineC(0, ui::accent(), "Quick Attack: %s", modes[mode]);
ui::line(1, "status: %s", running ? "RUNNING" : "ready");
if (mode == DETECT) {
ui::line(2, "detecting target...");
} else if (mode == HID_INJECT) {
ui::bar(2, progress / 50.0f, ui::glow(), "inject");
ui::line(3, "typing commands...");
} else if (mode == SERIAL_SHELL) {
ui::line(2, "commands sent: %u", (unsigned)commands_sent);
if (response[0]) ui::line(3, "RX: %.30s", response);
} else {
ui::lineC(2, ui::glow(), "COMPLETE");
}
for (int i = 0; i < 3; i++) ui::line(7 + i, "%s", msg[i]);
if (running) ui::spinner(228, ui::BODY_Y + 1, ui::glow());
ui::hintBar("[space]attack [s]end-id [w]hoami [d]etect [`]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() {
say("Probing...");
#ifdef HAVE_TINYSUB
if (tud_mounted()) {
mode = HID_INJECT;
say("USB device: HID mode");
return;
}
#endif
ser.write("\r\n");
delay(200);
if (ser.available()) {
mode = SERIAL_SHELL;
say("UART detected: shell mode");
} else {
say("No target detected");
}
}
void startAttack() {
running = true;
progress = 0;
commands_sent = 0;
memset(response, 0, sizeof(response));
say("Attacking...");
}
void sendCommand(const char* cmd) {
ser.print(cmd);
ser.flush();
commands_sent++;
say("TX: %s", cmd);
}
void sendHidString(const char* str) {
#ifdef HAVE_TINYSUB
for (size_t i = 0; i < strlen(str); i++) {
uint8_t keycode = 0;
if (str[i] >= 'a' && str[i] <= 'z') keycode = 0x04 + (str[i] - 'a');
else if (str[i] >= 'A' && str[i] <= 'Z') keycode = 0x04 + (str[i] - 'A');
else if (str[i] >= '0' && str[i] <= '9') keycode = (str[i] == '0') ? 0x27 : 0x1E + (str[i] - '1');
else if (str[i] == ' ') keycode = 0x2C;
else if (str[i] == '\n') keycode = 0x28;
else if (str[i] == '-') keycode = 0x2D;
if (keycode) {
tud_hid_keyboard_report(0, 0, &keycode, 1);
delay(30);
tud_hid_keyboard_report(0, 0, nullptr, 0);
}
}
#endif
commands_sent++;
}
};
Module* makeQuickAttack() { return new QuickAttack(); }

View File

@@ -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(); }

View File

@@ -76,7 +76,7 @@ private:
void importConfig() {
File f = SD.open("/logs/config.json", FILE_READ);
if (f) {
// Stub: parse JSON (would use a lightweight parser)
f.close();
say("imported config");
} else say("import fail");

View File

@@ -0,0 +1,96 @@
#include "../core/module.h"
#include "../core/ui.h"
#include <SPI.h>
#include <SD.h>
#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(); }

View File

@@ -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() {
// 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(); }

View File

@@ -1,123 +0,0 @@
#include "../core/module.h"
#include "../core/ui.h"
#include <M5Cardputer.h>
#include <HardwareSerial.h>
class TerminalShell : public Module {
bool connected = false;
uint32_t baudrate = 115200;
uint32_t cmdCount = 0;
char cmdBuffer[64] = "";
char cmdPos = 0;
char rxBuffer[256] = "";
uint16_t rxPos = 0;
char msg[3][40] = {{0},{0},{0}};
HardwareSerial ser;
public:
const char* name() const override { return "Terminal Shell"; }
const char* blurb() const override { return "serial/UART shell"; }
void onEnter() override {
connected = false;
cmdCount = 0;
cmdPos = 0;
rxPos = 0;
memset(cmdBuffer, 0, sizeof(cmdBuffer));
memset(rxBuffer, 0, sizeof(rxBuffer));
say("UART ready, select baud");
}
void onExit() override { if (connected) disconnect(); }
bool onKey(char c) override {
if (c == 'b') { cycleBaudrate(); return true; }
if (c == 'c') { if (!connected) connectSerial(); else disconnect(); return true; }
if (c == 'x') { memset(rxBuffer, 0, sizeof(rxBuffer)); rxPos = 0; say("RX cleared"); return true; }
if (connected) {
if (c == '\n' || c == '\r') { sendCommand(); 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;
uint32_t start = millis();
while (ser.available() && millis() - start < 10) {
char c = ser.read();
if (rxPos < sizeof(rxBuffer) - 1) {
rxBuffer[rxPos++] = c;
if (c == '\n') rxPos = 0;
}
}
}
void draw() override {
ui::lineC(0, ui::accent(), "UART %lu baud %s", baudrate, connected ? "CONNECTED" : "idle");
if (connected) {
ui::line(2, "$ %s", cmdBuffer);
if ((millis() / 500) % 2) ui::lineC(2, ui::glow(), "$ %s_", cmdBuffer);
ui::line(3, "RX: %u bytes", rxPos);
if (rxPos > 0) {
int end = rxPos > 30 ? rxPos - 30 : 0;
ui::line(4, "%.31s", rxBuffer + end);
}
ui::line(5, "sent: %lu cmds", (unsigned long)cmdCount);
} else {
ui::line(2, "baud: %lu", baudrate);
ui::line(3, "connect to open serial");
}
for (int i = 0; i < 3; i++) ui::line(8 + i, "%s", msg[i]);
if (connected) ui::spinner(228, ui::BODY_Y + 1, ui::glow());
ui::hintBar("[b]aud [c]onnect [x]clear RX [`]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 cycleBaudrate() {
const uint32_t bauds[] = {9600, 19200, 38400, 57600, 115200, 230400};
for (int i = 0; i < 6; i++) {
if (bauds[i] == baudrate) {
baudrate = bauds[(i + 1) % 6];
say("baud: %lu", baudrate);
if (connected) { disconnect(); delay(100); connectSerial(); }
return;
}
}
baudrate = 115200;
}
void connectSerial() {
// Use GPIO16/GPIO17 as UART (RX2/TX2 on M5 boards)
ser.begin(baudrate, SERIAL_8N1, 16, 17);
connected = true;
cmdCount = 0;
rxPos = 0;
say("connected @ %lu", baudrate);
}
void disconnect() {
ser.end();
connected = false;
say("disconnected");
}
void sendCommand() {
if (cmdPos == 0) return;
cmdBuffer[cmdPos] = '\n';
ser.write((uint8_t*)cmdBuffer, cmdPos + 1);
ser.flush();
cmdCount++;
cmdPos = 0;
memset(cmdBuffer, 0, sizeof(cmdBuffer));
say("sent %u bytes", (unsigned)cmdCount);
}
};
Module* makeTerminalShell() { return new TerminalShell(); }

View File

@@ -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(); }

View File

@@ -1,74 +0,0 @@
#include "../core/module.h"
#include "../core/ui.h"
#include <M5Cardputer.h>
#if __has_include("tusb.h")
#include "tusb.h"
#define HAVE_TINYSUB 1
#endif
class UsbGadget : public Module {
enum Class { CDC_ACM, HID_KEYBOARD, MASS_STORAGE } devClass = CDC_ACM;
bool active = false;
uint32_t enumTime = 0;
uint32_t enumOk = 0;
char msg[3][40] = {{0},{0},{0}};
public:
const char* name() const override { return "USB Gadget"; }
const char* blurb() const override { return "emulate USB device"; }
void onEnter() override {
active = false;
enumTime = 0;
enumOk = 0;
say("USB gadget ready");
#ifdef HAVE_TINYSUB
if (tud_mounted()) {
active = true;
say("Host connected");
}
#endif
}
void onExit() override { active = false; }
bool onKey(char c) override {
if (c == 'c') { devClass = (Class)((devClass + 1) % 3); return true; }
if (c == ' ') { active = !active; if (active) enumTime = 0; return true; }
return false;
}
void tick() override {
if (!active) return;
#ifdef HAVE_TINYSUB
if (!tud_mounted()) { active = false; enumOk = 0; return; }
enumTime = millis();
if (!enumOk && enumTime > 500) enumOk = 1;
#endif
}
void draw() override {
const char* cn[] = {"CDC/ACM SERIAL", "HID KEYBOARD", "MASS STORAGE"};
ui::lineC(0, ui::accent(), "USB Gadget: %s", cn[devClass]);
if (active) {
ui::lineC(1, ui::glow(), "ENUMERATED OK");
if (devClass == CDC_ACM) ui::line(2, "Serial ready /dev/ttyUSB0");
else if (devClass == HID_KEYBOARD) ui::line(2, "Keyboard ready");
else ui::line(2, "Storage ready /dev/sd*");
} else {
ui::line(1, "status: idle");
ui::line(2, "plug USB host to enable");
}
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("[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);
}
};
Module* makeUsbGadget() { return new UsbGadget(); }

View File

@@ -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(); }

View File

@@ -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(); }

View File

@@ -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...");
// 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");
}
void stopClone() {
active = false;
say("AP: shutting down");
}
};
Module* makeWiFiClone() { return new WiFiClone(); }

View File

@@ -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);
// 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(); }

73
src/modules/wifiscan.cpp Normal file
View File

@@ -0,0 +1,73 @@
#include "../core/module.h"
#include "../core/ui.h"
#include <WiFi.h>
// 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(); }

View File

@@ -55,7 +55,7 @@ private:
}
Wire.end();
// Try SWD
// Try SWD (stub)
say("no device detected");
}