Skip to content

Commit

Permalink
Added CDROM USB device support, dep upgrades and bugfixes
Browse files Browse the repository at this point in the history
Added CDROM USB device support, dep upgrades and bugfixes
  • Loading branch information
i-am-shodan authored Jan 21, 2025
2 parents 320a76a + 1683782 commit 02e5188
Show file tree
Hide file tree
Showing 23 changed files with 440 additions and 45 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ This project implements a variety of attacks based around an easily concealable
| [Simple UI](./examples/simple_ui/) | A simple yet powerful UI to select scripts/images and run these using the hardware button. Shows how you can build complex UI interactions simply. |
| [Stream Mic audio over WiFi](./examples/hotmic/) | The M5Stack AtomS3U has a microphone that you can stream over WiFi. |
| [Instantly crash Linux boxes](./examples/linux_panic/) | Deploy a bad filesystem which cause Linux machines which automount to panic. |
| [Evil USB CDROM/NIC](./examples/malicious_ethernet_adapter/) | Pretend to be a USB NICs which requires a driver from a CDROM device that appears when you plug the NIC in. |

## Supported Hardware

Expand Down
57 changes: 55 additions & 2 deletions data/autorun.ds
Original file line number Diff line number Diff line change
@@ -1,2 +1,55 @@
REM This file is only used by platforms without an SD card
REM Replace this file with your own content
REM This is the system test for M5-Atom-S3 based boards
REM These do not have a screen or SD card.

REM To run these tests copy this file to the data directory and use the upload filesystem command or platformio
REM You'll also need to have the agent running. You should see:

REM * Web page loaded via badUSB

REM You should connect to the device over WiFi and check
REM * The web interface loads
REM * VNC works
REM * You can see logs
REM * Results from the agent run are in the logs

REM Now press the button and ensure the LED cycles
REM * RED
REM * GREEN
REM * BLUE
REM * OFF

REM Press the button again and the device will do an ESP32 Maurader rick roll
REM * Ensure that the lyrics can be seen over WiFi

REM Press once more for a reset
REM * Device resetting

WHILE (AGENT_CONNECTED() == FALSE)
DELAY 2000
END_WHILE

REM Run a command to ensure we can handle the results
AGENT_RUN dir
WAIT_FOR_AGENT_RUN_RESULT

REM Load a webpage to ensure USB + HID is working
GUI
DELAY 1000
STRING https://github.com/i-am-shodan/USBArmyKnife/blob/master/docs/images/interface-status.png
ENTER

LED_R
WAIT_FOR_BUTTON_PRESS
LED_G
WAIT_FOR_BUTTON_PRESS
LED_B
WAIT_FOR_BUTTON_PRESS
LED_OFF

WIFI_OFF
ESP32M attack -t rickroll
WAIT_FOR_BUTTON_PRESS

REM reset the device and do it all again
DELAY 5000
RESET
21 changes: 21 additions & 0 deletions examples/malicious_ethernet_adapter/autorun.ds
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
REM when running this script make sure your device starts in Serial mode
DEFINE #SETTING_NAME usbDeviceType
VAR $SETTING_USB_DEVICE_TYPE_ETHERNET = 2

IF (GET_SETTING_VALUE() != $SETTING_USB_DEVICE_TYPE_ETHERNET) THEN
USB_MOUNT_CDROM_READ_ONLY /cdrom.iso

REM wait for the user to install the driver
REM on some OS' a popup will appear but on most modern ones the
REM user will need to be encouraged!
WHILE (AGENT_CONNECTED() == FALSE)
DELAY 2000
END_WHILE

REM We now need to change the device into a USB ethernet adapter
SET_SETTING_UINT16 usbDeviceType $SETTING_USB_DEVICE_TYPE_ETHERNET
REM this requires a reset
RESET
ELSE
REM add some DNS entries?
END_IF
Binary file added examples/malicious_ethernet_adapter/cdrom.iso
Binary file not shown.
7 changes: 1 addition & 6 deletions lib/ESP32Marauder/esp32_marauder/SDInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,7 @@ bool SDInterface::initSD() {
}

File SDInterface::getFile(String path) {
if (this->supported) {
File file = SD.open(path, FILE_READ);

//if (file)
return file;
}
return SD.open(path, FILE_READ);
}

bool SDInterface::removeFile(String file_path) {
Expand Down
8 changes: 7 additions & 1 deletion lib/ESP32Marauder/esp32_marauder/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ bool Settings::toggleSetting(String key) {

if (deserializeJson(json, this->json_settings_string)) {
esp32m_println("\nCould not parse json");
return false;
}

for (int i = 0; i < json["Settings"].size(); i++) {
Expand All @@ -215,6 +216,8 @@ bool Settings::toggleSetting(String key) {
return false;
}
}

return true;
}

String Settings::setting_index_to_name(int i) {
Expand Down Expand Up @@ -242,12 +245,15 @@ String Settings::getSettingType(String key) {

if (deserializeJson(json, this->json_settings_string)) {
esp32m_println("\nCould not parse json");
return "";
}

for (int i = 0; i < json["Settings"].size(); i++) {
if (json["Settings"][i]["name"].as<String>() == key)
return json["Settings"][i]["type"];
}

return "";
}

void Settings::printJsonSettings(String json_string) {
Expand All @@ -267,7 +273,7 @@ void Settings::printJsonSettings(String json_string) {
}

bool Settings::createDefaultSettings(fs::FS &fs) {
createDefaultSettings(fs, DEFAULT_SETTING_FILE);
return createDefaultSettings(fs, DEFAULT_SETTING_FILE);
}

bool Settings::createDefaultSettings(fs::FS &fs, String filename) {
Expand Down
16 changes: 7 additions & 9 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ build_flags =
-D CFG_TUD_ENABLED
;-D DUCKY_CUSTOM_LOG
lib_deps_core =
https://github.com/i-am-shodan/DuckScriptInterpreter#4a614fd9debf3370cf32ef8eb6929877d8084114
https://github.com/i-am-shodan/DuckScriptInterpreter#b2bb33bf8d5e10a8726962b32552179f23c999ae
bblanchon/ArduinoJson@^7.0.3
ivanseidel/[email protected]+sha.dac3874d28
https://github.com/i-am-shodan/Uptime-Library
Expand All @@ -75,7 +75,7 @@ lib_deps_core =
extends = core
platform = https://github.com/platformio/platform-espressif32.git
platform_packages =
platformio/framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.3
platformio/framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.5
platformio/framework-arduinoespressif32-libs @ https://github.com/espressif/esp32-arduino-libs.git#idf-release/v5.1
monitor_filters = esp32_exception_decoder
monitor_speed = 115200
Expand All @@ -93,10 +93,9 @@ build_flags =
-D CONFIG_ASYNC_TCP_MAX_ACK_TIME=3000
lib_deps =
${core.lib_deps_core}
AsyncTCP=https://github.com/mathieucarbou/AsyncTCP
AsyncTCP-esphome=https://github.com/mathieucarbou/AsyncTCP
https://github.com/i-am-shodan/Adafruit_TinyUSB_Arduino
ESPAsyncWebServer=https://github.com/mathieucarbou/ESPAsyncWebServer
https://github.com/mathieucarbou/AsyncTCPSock/archive/refs/tags/v1.0.3-dev.zip
https://github.com/i-am-shodan/Adafruit_TinyUSB_Arduino#migrateTo334
ESPAsyncWebServer=https://github.com/i-am-shodan/ESPAsyncWebServer
ayushsharma82/[email protected]

[core-esp32-s3]
Expand Down Expand Up @@ -183,7 +182,7 @@ build_flags =
-D HAS_SD ; ESP32 Maurader
-D USE_SD_MMC_INTERFACE ; ESP32 Maurader
-D NO_MIC
-D BOARD_HAS_PSRAM
;-D BOARD_HAS_PSRAM
;;;;;;;; Pin Config for TFT ;;;;;;;;
-D DISPLAY_RST=39
-D DISPLAY_DC=41
Expand All @@ -208,11 +207,10 @@ build_flags =
-D BTN_PIN=0
-D NUM_LEDS=1
-D LED_DI_PIN=38
-D LED_CI_PIN=38
;;;;;;;; End of Pin Config ;;;;;;;;
lib_deps =
${core-esp32-s3.lib_deps}
https://github.com/pololu/apa102-arduino
fastled/FastLED

[env:Generic-ESP32-S2]
extends = core-esp32
Expand Down
23 changes: 12 additions & 11 deletions src/Attacks/Ducky/DuckyPayload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ static UserDefinedConstants consts;
static std::string localCmdLineToExecute;
static bool wasLastPressLong = false; // For buttons
static int lastSuccessfullyEvaluatedLine = 0;
static Preferences *preferences = nullptr;

static std::string readCmdLine(const std::string &filename, int lineNum);

Expand Down Expand Up @@ -276,6 +277,7 @@ DuckyPayload::DuckyPayload()

void DuckyPayload::begin(Preferences &prefs)
{
preferences = &prefs;
addDuckyScriptExtensions(extCommands, consts);
}

Expand Down Expand Up @@ -311,6 +313,16 @@ void DuckyPayload::loop(Preferences &prefs)
lastExecutionResult = duckyFileParser.Execute(executeFile ? currentlyExecutingFile : "", extCommands, consts);
const bool executionHasCompleted = lastExecutionResult == DuckyInterpreter::SCRIPT_ERROR || lastExecutionResult == DuckyInterpreter::END_OF_FILE;

if (lastExecutionResult == DuckyInterpreter::SCRIPT_ERROR)
{
Debug::Log.error(LOG_DUCKY, executeFile ? ("Script error near line " + std::to_string(lastSuccessfullyEvaluatedLine + 1)) : "Error executing command");
totalErrors++;
}
else if (lastExecutionResult == DuckyInterpreter::END_OF_FILE)
{
Debug::Log.info(LOG_DUCKY, "Script finished execution");
}

if (executionHasCompleted)
{
// we are safe to clear both of these in whatever mode we are running in
Expand All @@ -319,17 +331,6 @@ void DuckyPayload::loop(Preferences &prefs)
lastSuccessfullyEvaluatedLine = 0;
duckyFileParser.Restart();
}

if (lastExecutionResult == DuckyInterpreter::SCRIPT_ERROR)
{
Debug::Log.error(LOG_DUCKY, executeFile ? ("Script error near line " + std::to_string(lastSuccessfullyEvaluatedLine + 1)) : "Error executing command");
totalErrors++;

}
else if (lastExecutionResult == DuckyInterpreter::END_OF_FILE)
{
Debug::Log.info(LOG_DUCKY, "Script finished execution");
}
}
else if (firstRun)
{
Expand Down
84 changes: 83 additions & 1 deletion src/Attacks/Ducky/Extensions.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#include "../../Attacks/Marauder/Marauder.h"
#include "../../Attacks/Agent/Agent.h"

#include "../../Utilities/Settings.h"

#include "DuckyPayload.h"

// For VID and PID str handling
Expand All @@ -29,6 +31,10 @@ static const std::string Constant_FileIndexFileName = "#_FILE_INDEX_FILE_NAME_";
static std::vector<std::string> curListOfFiles;
static int curFileIndexVariable = 0;

bool startsWith(const std::string& str, const std::string& prefix) {
return str.rfind(prefix, 0) == 0;
}

static int handleCalc(const std::string &str, const std::unordered_map<std::string, std::string> &constants, const std::unordered_map<std::string, int> &variables)
{
Devices::USB::HID.consumer_device_keypress(HID_USAGE_CONSUMER_AL_CALCULATOR);
Expand Down Expand Up @@ -103,13 +109,15 @@ static int handleDisplayText(const std::string &str, const std::unordered_map<st

static int handleUSBMode(const std::string &str, const std::unordered_map<std::string, std::string> &constants, const std::unordered_map<std::string, int> &variables)
{
bool mountAsCdrom = startsWith(str, "USB_MOUNT_CDROM_READ_ONLY");

std::string arg = str.substr(str.find(' ') + 1);
const auto entries = Ducky::SplitString(arg);

if (entries.size() == 1)
{
Debug::Log.info(LOG_DUCKY, "Mounting disk " + entries[0]);
return Devices::USB::MSC.mountDiskImage(entries[0]);
return Devices::USB::MSC.mountDiskImage(entries[0], mountAsCdrom);
}
else
{
Expand Down Expand Up @@ -211,6 +219,45 @@ static int handleSerial(const std::string &str, const std::unordered_map<std::st
return true;
}

static int handleSetSetting(const std::string &str, const std::unordered_map<std::string, std::string> &constants, const std::unordered_map<std::string, int> &variables)
{
bool ret = false;

do
{
const auto split = Ducky::SplitString(str);
if (split.size() != 3)
{
Debug::Log.error(LOG_DUCKY, "SET_SETTING needs two arguments has: "+std::to_string(split.size() - 1));
Debug::Log.error(LOG_DUCKY, str);
totalErrors++;
break;
}

const auto settingName = split[1];
auto settingValue = split[2];

if (startsWith(str, "SET_SETTING_UINT16") && settingValue.rfind("0x", 0) != 0)
{
// need to add 0x to front
settingValue = "0x" + settingValue;
}

if (startsWith(str, "SET_SETTING_BOOL") && !(settingValue[0] == 0 || settingValue[0] == 1))
{
Debug::Log.error(LOG_DUCKY, "Invalid bool type, should be 0 or 1");
totalErrors++;
break;
}

Debug::Log.info(LOG_DUCKY, "Trying to set "+settingName+" to " +settingValue);
ret = setSettingValue(*preferences, settingName, settingValue);

} while (false);

return ret;
}

static int handleUsbNcmPcapOn(const std::string &str, const std::unordered_map<std::string, std::string> &constants, const std::unordered_map<std::string, int> &variables)
{
Devices::USB::NCM.startPacketCollection();
Expand Down Expand Up @@ -347,6 +394,34 @@ static int handleButtonPress(const std::string &str, const std::unordered_map<st
}
}

static int handleGetSettingValue(const std::string &str, const std::unordered_map<std::string, std::string> &constants, const std::unordered_map<std::string, int> &variables)
{
// str is the current line, we need to peak in the constant #FILE
if (constants.find("#SETTING_NAME") != constants.cend())
{
bool error = false;
uint16_t value = getIntegerSettingValue(*preferences, constants.at("#SETTING_NAME"), error);
if (error)
{
// todo, this isn't a great pattern. We should be able to set an error here to stop further script
// execution. The best we can do is return 0 but what if a setting was really 0.
// DuckyScript interpeter either needs:
// * a method we can call to stop execution
// * a better function declation that we can return an error through
Debug::Log.error(LOG_DUCKY, "GET_SETTING_VALUE() error, setting is unknown or string type");
totalErrors++;
return 0;
}
Debug::Log.info(LOG_DUCKY, "GET_SETTING_VALUE() returned " + std::to_string(value));
return value;
}
else
{
Debug::Log.info(LOG_DUCKY, "Error handling GET_SETTING_VALUE() no param");
return false;
}
}

static int handleRunPayload(const std::string &str, const std::unordered_map<std::string, std::string> &constants, const std::unordered_map<std::string, int> &variables)
{
const std::string arg = str.substr(str.find(' ') + 1);
Expand Down Expand Up @@ -572,9 +647,15 @@ void addDuckyScriptExtensions(
extCommands["WIFI_OFF"] = handleWiFiOff;
extCommands["WIFI_ON"] = handleWiFiOn;
extCommands["SERIAL"] = handleSerial;
extCommands["SET_SETTING_BOOL"] = handleSetSetting;
extCommands["SET_SETTING_INT16"] = handleSetSetting;
extCommands["SET_SETTING_UINT16"] = handleSetSetting;
extCommands["SET_SETTING_STRING"] = handleSetSetting;


// USB
extCommands["USB_MOUNT_DISK_READ_ONLY"] = handleUSBMode;
extCommands["USB_MOUNT_CDROM_READ_ONLY"] = handleUSBMode;
extCommands["USB_NCM_PCAP_ON"] = handleUsbNcmPcapOn;
extCommands["USB_NCM_PCAP_OFF"] = handleUsbNcmPcapOff;
extCommands["WAIT_FOR_USB_STORAGE_ACTIVITY"] = handleWaitForUSBStorageActivity;
Expand All @@ -594,6 +675,7 @@ void addDuckyScriptExtensions(
extCommands["LOAD_FILES_FROM_SD()"] = handleFileIndex;
extCommands["BUTTON_LONG_PRESS()"] = handleButtonPress;
extCommands["BUTTON_SHORT_PRESS()"] = handleButtonPress;
extCommands["GET_SETTING_VALUE()"] = handleGetSettingValue;

consts.emplace_back([]
{
Expand Down
Loading

0 comments on commit 02e5188

Please sign in to comment.