Compare commits
3 Commits
43b28ea2e7
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8d77131a2 | ||
|
|
c6dfc19578 | ||
|
|
b76f016bcd |
@@ -3,6 +3,7 @@
|
||||
#include "theme.h"
|
||||
#include <M5Cardputer.h>
|
||||
|
||||
Module* makeQuickAttack();
|
||||
Module* makePinScan();
|
||||
Module* makeVSense();
|
||||
Module* makeUartSniff();
|
||||
@@ -54,6 +55,7 @@ Module* makeLogViewer();
|
||||
|
||||
void Shell::begin() {
|
||||
theme::load();
|
||||
add(makeQuickAttack());
|
||||
add(makePinScan());
|
||||
add(makeVSense());
|
||||
add(makeUartSniff());
|
||||
@@ -154,24 +156,25 @@ 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 == '`') { if (active >= 0) back(); continue; }
|
||||
if (c == '`' || c == 27) { 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 {
|
||||
mods[active]->onKey(c);
|
||||
bool consumed = mods[active]->onKey(c);
|
||||
if (!consumed && c == '`') back();
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
@@ -181,3 +184,25 @@ 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;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ public:
|
||||
void begin();
|
||||
void loop();
|
||||
private:
|
||||
static constexpr int MAX = 12;
|
||||
static constexpr int MAX = 50;
|
||||
Module* mods[MAX]; int nmods = 0;
|
||||
int sel = 0; // menu cursor
|
||||
int active = -1; // -1 == in menu
|
||||
@@ -17,4 +17,5 @@ private:
|
||||
void drawMenu(bool force = false);
|
||||
void enter(int i);
|
||||
void back();
|
||||
void checkUsbAutoTrigger();
|
||||
};
|
||||
|
||||
@@ -21,12 +21,13 @@ public:
|
||||
void onEnter() override {
|
||||
active = false;
|
||||
sent = 0;
|
||||
say("HID ready, plug USB host");
|
||||
say("HID ready");
|
||||
#ifdef HAVE_TINYSB
|
||||
if (tud_mounted()) {
|
||||
active = true;
|
||||
sent = 0;
|
||||
say("Host detected - injecting");
|
||||
say("Host detected!");
|
||||
say("Injecting...");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
155
src/modules/quickattack.cpp
Normal file
155
src/modules/quickattack.cpp
Normal 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(); }
|
||||
@@ -43,10 +43,13 @@ public:
|
||||
|
||||
void tick() override {
|
||||
if (!connected) return;
|
||||
while (ser.available()) {
|
||||
uint32_t start = millis();
|
||||
while (ser.available() && millis() - start < 10) {
|
||||
char c = ser.read();
|
||||
if (rxPos < sizeof(rxBuffer) - 1) rxBuffer[rxPos++] = c;
|
||||
if (rxPos >= sizeof(rxBuffer) - 1) rxPos = sizeof(rxBuffer) - 1;
|
||||
if (rxPos < sizeof(rxBuffer) - 1) {
|
||||
rxBuffer[rxPos++] = c;
|
||||
if (c == '\n') rxPos = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user