Card-Crack: Cardputer ESP32-S3 home-lab recon toolkit

Manual-trigger firmware toolkit for pentesting owned devices:
- Pin Scan: UART/JTAG/SWD detection (baud est + IDCODE reads)
- V-Sense: target voltage probe w/ logic-family guess
- UART Sniff: passive capture + manual-only frame replay
- USB Enum: ESP32-S3 host, read-only descriptor fingerprinting
- DefCred: single-host factory-default login check, rate-limited

Modular shell (core/ + modules/), PlatformIO build, hardware/safety docs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AAhMHMRAQLQ9hSbBECKNfn
This commit is contained in:
Indiana Holmes
2026-09-10 18:12:42 +00:00
commit 79612197a1
16 changed files with 967 additions and 0 deletions

62
src/modules/vsense.cpp Normal file
View File

@@ -0,0 +1,62 @@
#include "../core/module.h"
#include "../core/ui.h"
#include "../core/pins.h"
// Voltage sensing. Reads the ADC behind an external divider and reports
// a live voltage plus a guess at the logic family, so you know what
// you're probing BEFORE you drive a pin into it. Min/max are held so a
// brief transient (e.g. a bus idling high) is captured.
//
// The ESP32-S3 ADC is non-linear near the rails; we use the Arduino
// analogReadMilliVolts() calibration path and apply the divider ratio.
class VSense : public Module {
float v = 0, vmin = 99, vmax = 0;
uint32_t lastMs = 0;
public:
const char* name() const override { return "V-Sense"; }
const char* blurb() const override { return "target voltage probe"; }
void onEnter() override {
analogReadResolution(12);
pinMode(pins::VSENSE_ADC, INPUT);
vmin = 99; vmax = 0;
}
bool onKey(char c) override {
if (c == 'r') { vmin = 99; vmax = 0; return true; } // reset hold
return false;
}
void tick() override {
if (millis() - lastMs < 100) return;
lastMs = millis();
uint32_t mv = analogReadMilliVolts(pins::VSENSE_ADC);
v = (mv / 1000.0f) * pins::VSENSE_RATIO;
if (v < vmin) vmin = v;
if (v > vmax) vmax = v;
}
void draw() override {
ui::lineC(0, ui::accent(), "Vin = %5.2f V", v);
ui::line(1, "min %4.2f max %4.2f (ratio %.1f)", vmin, vmax, pins::VSENSE_RATIO);
ui::lineC(3, family(v).color, "logic: %s", family(v).name);
ui::line(5, "wire target -> divider -> G%d", pins::VSENSE_ADC);
ui::hintBar("[r]eset hold [`]back");
}
private:
struct Fam { const char* name; uint16_t color; };
Fam family(float x) {
if (x < 0.3f) return {"floating / GND", ui::fg()};
if (x < 1.5f) return {"1.2V core rail", ui::warn()};
if (x < 2.1f) return {"1.8V logic", ui::warn()};
if (x < 3.0f) return {"2.5V logic", ui::warn()};
if (x < 3.9f) return {"3.3V logic OK", ui::accent()};
if (x < 6.0f) return {"5V ! shift req", ui::bad()};
return {"HIGH >6V DANGER", ui::bad()};
}
};
Module* makeVSense() { return new VSense(); }