Compare commits

..

3 Commits

5 changed files with 194 additions and 9 deletions

View File

@@ -3,6 +3,7 @@
#include "theme.h" #include "theme.h"
#include <M5Cardputer.h> #include <M5Cardputer.h>
Module* makeQuickAttack();
Module* makePinScan(); Module* makePinScan();
Module* makeVSense(); Module* makeVSense();
Module* makeUartSniff(); Module* makeUartSniff();
@@ -54,6 +55,7 @@ Module* makeLogViewer();
void Shell::begin() { void Shell::begin() {
theme::load(); theme::load();
add(makeQuickAttack());
add(makePinScan()); add(makePinScan());
add(makeVSense()); add(makeVSense());
add(makeUartSniff()); add(makeUartSniff());
@@ -154,24 +156,25 @@ void Shell::back() {
void Shell::loop() { void Shell::loop() {
M5Cardputer.update(); M5Cardputer.update();
checkUsbAutoTrigger();
if (M5Cardputer.Keyboard.isChange() && M5Cardputer.Keyboard.isPressed()) { if (M5Cardputer.Keyboard.isChange() && M5Cardputer.Keyboard.isPressed()) {
auto st = M5Cardputer.Keyboard.keysState(); auto st = M5Cardputer.Keyboard.keysState();
for (char c : st.word) { for (char c : st.word) {
if (c == '`') { if (active >= 0) back(); continue; } if (c == '`' || c == 27) { if (active >= 0) { back(); continue; } }
if (active < 0) { if (active < 0) {
if (c == ';') { sel = (sel - 1 + nmods) % nmods; drawMenu(); } if (c == ';') { sel = (sel - 1 + nmods) % nmods; drawMenu(); }
else if (c == '.') { sel = (sel + 1) % nmods; drawMenu(); } else if (c == '.') { sel = (sel + 1) % nmods; drawMenu(); }
else if (c == '\r' || c == ' ') enter(sel); else if (c == '\r' || c == ' ') enter(sel);
} else { } else {
mods[active]->onKey(c); bool consumed = mods[active]->onKey(c);
if (!consumed && c == '`') back();
} }
} }
if (st.enter && active < 0) enter(sel); if (st.enter && active < 0) enter(sel);
} }
if (active < 0) { if (active < 0) {
// keep the selection glow breathing — repaints only the bar strip (flicker-free)
if (millis() - lastTick > 90) { lastTick = millis(); drawMenu(false); } if (millis() - lastTick > 90) { lastTick = millis(); drawMenu(false); }
return; return;
} }
@@ -181,3 +184,25 @@ void Shell::loop() {
mods[active]->draw(); 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,7 +8,7 @@ public:
void begin(); void begin();
void loop(); void loop();
private: private:
static constexpr int MAX = 12; static constexpr int MAX = 50;
Module* mods[MAX]; int nmods = 0; Module* mods[MAX]; int nmods = 0;
int sel = 0; // menu cursor int sel = 0; // menu cursor
int active = -1; // -1 == in menu int active = -1; // -1 == in menu
@@ -17,4 +17,5 @@ private:
void drawMenu(bool force = false); void drawMenu(bool force = false);
void enter(int i); void enter(int i);
void back(); void back();
void checkUsbAutoTrigger();
}; };

View File

@@ -21,12 +21,13 @@ public:
void onEnter() override { void onEnter() override {
active = false; active = false;
sent = 0; sent = 0;
say("HID ready, plug USB host"); say("HID ready");
#ifdef HAVE_TINYSB #ifdef HAVE_TINYSB
if (tud_mounted()) { if (tud_mounted()) {
active = true; active = true;
sent = 0; sent = 0;
say("Host detected - injecting"); say("Host detected!");
say("Injecting...");
} }
#endif #endif
} }

155
src/modules/quickattack.cpp Normal file
View File

@@ -0,0 +1,155 @@
#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

@@ -43,10 +43,13 @@ public:
void tick() override { void tick() override {
if (!connected) return; if (!connected) return;
while (ser.available()) { uint32_t start = millis();
while (ser.available() && millis() - start < 10) {
char c = ser.read(); char c = ser.read();
if (rxPos < sizeof(rxBuffer) - 1) rxBuffer[rxPos++] = c; if (rxPos < sizeof(rxBuffer) - 1) {
if (rxPos >= sizeof(rxBuffer) - 1) rxPos = sizeof(rxBuffer) - 1; rxBuffer[rxPos++] = c;
if (c == '\n') rxPos = 0;
}
} }
} }