From f7b7ce84e7caf81e40a8fa236adca66beb2a9178 Mon Sep 17 00:00:00 2001 From: Robert Fisk Date: Tue, 21 Nov 2017 05:18:19 +1300 Subject: [PATCH] Initial implementation of mouse bot detection --- Downstream/.cproject | 72 ++++---- Downstream/.settings/language.settings.xml | 2 +- Downstream/Src/downstream_hid.c | 8 +- Upstream/.cproject | 167 +++++++++--------- Upstream/.settings/language.settings.xml | 4 +- Upstream/Inc/build_config.h | 29 ++- Upstream/Inc/upstream_hid_botdetect.h | 8 + .../Class/HID/Inc/usbd_hid.h | 1 - .../Class/HID/Src/usbd_hid.c | 4 +- Upstream/Src/upstream_hid.c | 4 +- Upstream/Src/upstream_hid_botdetect.c | 144 +++++++++++++-- 11 files changed, 294 insertions(+), 149 deletions(-) diff --git a/Downstream/.cproject b/Downstream/.cproject index 6296ec7..8330fa6 100644 --- a/Downstream/.cproject +++ b/Downstream/.cproject @@ -142,39 +142,41 @@ - diff --git a/Downstream/.settings/language.settings.xml b/Downstream/.settings/language.settings.xml index 72387b0..0cebdf1 100644 --- a/Downstream/.settings/language.settings.xml +++ b/Downstream/.settings/language.settings.xml @@ -16,7 +16,7 @@ - + diff --git a/Downstream/Src/downstream_hid.c b/Downstream/Src/downstream_hid.c index 00760b1..859ea8a 100644 --- a/Downstream/Src/downstream_hid.c +++ b/Downstream/Src/downstream_hid.c @@ -268,7 +268,7 @@ static HAL_StatusTypeDef Downstream_HID_GetNextReportItem(void) ReportDataPointer += itemLength; return HAL_OK; } -#endif +#endif //#ifdef CONFIG_MOUSE_ENABLED @@ -305,7 +305,7 @@ void Downstream_HID_PacketProcessor(DownstreamPacketTypeDef* receivedPacket) Downstream_PacketProcessor_NotifyDisconnectReplyRequired(); return; } -#endif +#endif //#ifdef CONFIG_KEYBOARD_ENABLED //else: Downstream_PacketProcessor_FreakOut(); @@ -402,7 +402,7 @@ static uint8_t Downstream_HID_Mouse_Extract8BitValue(HID_HandleTypeDef* hidHandl if (readData > INT8_MAX) readData = INT8_MAX; return (int8_t)readData; } -#endif +#endif //#ifdef CONFIG_MOUSE_ENABLED #ifdef CONFIG_KEYBOARD_ENABLED @@ -425,7 +425,7 @@ static void Downstream_HID_Keyboard_ExtractDataFromReport(DownstreamPacketTypeDe packetToSend->Data[i] = readData; } } -#endif +#endif //#ifdef CONFIG_KEYBOARD_ENABLED diff --git a/Upstream/.cproject b/Upstream/.cproject index 4592d4a..e083790 100755 --- a/Upstream/.cproject +++ b/Upstream/.cproject @@ -5,53 +5,55 @@ + - - + - @@ -137,50 +140,52 @@ + - - + - @@ -284,4 +290,5 @@ + diff --git a/Upstream/.settings/language.settings.xml b/Upstream/.settings/language.settings.xml index 8fb4179..063351b 100755 --- a/Upstream/.settings/language.settings.xml +++ b/Upstream/.settings/language.settings.xml @@ -5,7 +5,7 @@ - + @@ -16,7 +16,7 @@ - + diff --git a/Upstream/Inc/build_config.h b/Upstream/Inc/build_config.h index f402eaf..f43f944 100644 --- a/Upstream/Inc/build_config.h +++ b/Upstream/Inc/build_config.h @@ -20,11 +20,16 @@ #define CONFIG_KEYBOARD_BOT_DETECT_ENABLED #define CONFIG_MOUSE_ENABLED -//#define CONFIG_MOUSE_BOT_DETECT_ENABLED +#define CONFIG_MOUSE_BOT_DETECT_ENABLED -//Configure keyboard rate-limiting (bot detection) here: +//Configure keyboard bot detection here: #ifdef CONFIG_KEYBOARD_BOT_DETECT_ENABLED + //----------------------------------------------------------- + //Adjust this threshold first to tune keyboard bot detection. Lower values = more sensitive + #define KEYBOARD_BOTDETECT_TEMPORARY_LOCKOUT_BIN_THRESHOLD 4 + //----------------------------------------------------------- + #define KEYBOARD_BOTDETECT_FAST_BIN_WIDTH_MS 10 //10ms per bin #define KEYBOARD_BOTDETECT_SLOW_BIN_WIDTH_MS 20 //20ms per bin #define KEYBOARD_BOTDETECT_FAST_BIN_COUNT 25 //25 bins at 10ms = 250ms fast coverage @@ -32,16 +37,24 @@ #define KEYBOARD_BOTDETECT_FAST_BIN_DRAIN_DIVIDER 2 #define KEYBOARD_BOTDETECT_SLOW_BIN_DRAIN_DIVIDER 4 - #define KEYBOARD_BOTDETECT_TEMPORARY_LOCKOUT_BIN_THRESHOLD 4 - - #define KEYBOARD_BOTDETECT_TEMPORARY_LOCKOUT_TIME_MS 4000 - #define KEYBOARD_BOTDETECT_TEMPORARY_LOCKOUT_FLASH_TIME_MS 60000 //Flash fault LED for 60 seconds after temporary lockout #endif - -//Configure mouse rate-limiting (bot detection) here: +//Configure mouse bot detection here: #ifdef CONFIG_MOUSE_BOT_DETECT_ENABLED + //----------------------------------------------------------- + //Adjust this threshold first to tune mouse bot detection. Lower values = more sensitive + #define MOUSE_BOTDETECT_TEMPORARY_LOCKOUT_VELOCITY_THRESHOLD 4 + //----------------------------------------------------------- + + #define MOUSE_BOTDETECT_VELOCITY_HISTORY_SIZE 12 + #define MOUSE_BOTDETECT_MOVE_DELAY_LIMIT 5 + +#endif +//Configuration common to all bot detectors +#if defined CONFIG_KEYBOARD_BOT_DETECT_ENABLED || defined CONFIG_MOUSE_BOT_DETECT_ENABLED + #define BOTDETECT_TEMPORARY_LOCKOUT_TIME_MS 4000 + #define BOTDETECT_TEMPORARY_LOCKOUT_FLASH_TIME_MS 60000 //Flash fault LED for 60 seconds after temporary lockout #endif diff --git a/Upstream/Inc/upstream_hid_botdetect.h b/Upstream/Inc/upstream_hid_botdetect.h index e5bf9d2..a37feb2 100644 --- a/Upstream/Inc/upstream_hid_botdetect.h +++ b/Upstream/Inc/upstream_hid_botdetect.h @@ -38,9 +38,17 @@ typedef struct } KeyTimerLogTypeDef; +typedef struct +{ + uint8_t moveDelay; + uint16_t velocity; +} +MouseVelocityHistoryTypeDef; + void Upstream_HID_BotDetect_Systick(void); void Upstream_HID_BotDetectKeyboard(uint8_t* keyboardInData); +void Upstream_HID_BotDetectMouse(uint8_t* mouseInData); diff --git a/Upstream/Middlewares/ST/STM32_USB_Device_Library/Class/HID/Inc/usbd_hid.h b/Upstream/Middlewares/ST/STM32_USB_Device_Library/Class/HID/Inc/usbd_hid.h index 46bbb06..d2a0045 100644 --- a/Upstream/Middlewares/ST/STM32_USB_Device_Library/Class/HID/Inc/usbd_hid.h +++ b/Upstream/Middlewares/ST/STM32_USB_Device_Library/Class/HID/Inc/usbd_hid.h @@ -64,7 +64,6 @@ #define HID_HS_BINTERVAL 0x07 #define HID_FS_BINTERVAL 0x0A -#define HID_POLLING_INTERVAL 0x0A #define HID_REQ_SET_PROTOCOL 0x0B #define HID_REQ_GET_PROTOCOL 0x03 diff --git a/Upstream/Middlewares/ST/STM32_USB_Device_Library/Class/HID/Src/usbd_hid.c b/Upstream/Middlewares/ST/STM32_USB_Device_Library/Class/HID/Src/usbd_hid.c index bf52e40..b8cb27c 100644 --- a/Upstream/Middlewares/ST/STM32_USB_Device_Library/Class/HID/Src/usbd_hid.c +++ b/Upstream/Middlewares/ST/STM32_USB_Device_Library/Class/HID/Src/usbd_hid.c @@ -255,14 +255,14 @@ __ALIGN_BEGIN static uint8_t HID_KEYBOARD_ReportDesc[HID_KEYBOARD_REPORT_DESC_SI 0x95, 0x01, // REPORT_COUNT (1) 0x75, 0x08, // REPORT_SIZE (8) 0x81, 0x03, // INPUT (Cnst,Var,Abs) - 0x95, HID_KEYBOARD_MAX_LED, // REPORT_COUNT (5) + 0x95, HID_KEYBOARD_MAX_LED, // REPORT_COUNT (3) 0x75, 0x01, // REPORT_SIZE (1) 0x05, 0x08, // USAGE_PAGE (LEDs) 0x19, 0x01, // USAGE_MINIMUM (Num Lock) 0x29, 0x03, // USAGE_MAXIMUM (Scroll Lock) 0x91, 0x02, // OUTPUT (Data,Var,Abs) 0x95, 0x01, // REPORT_COUNT (1) - 0x75, (8 - HID_KEYBOARD_MAX_LED), // REPORT_SIZE (3) + 0x75, (8 - HID_KEYBOARD_MAX_LED), // REPORT_SIZE (5) 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) 0x95, 0x06, // REPORT_COUNT (6) 0x75, 0x08, // REPORT_SIZE (8) diff --git a/Upstream/Src/upstream_hid.c b/Upstream/Src/upstream_hid.c index 601aa30..1799190 100644 --- a/Upstream/Src/upstream_hid.c +++ b/Upstream/Src/upstream_hid.c @@ -167,7 +167,9 @@ static void Upstream_HID_ReceiveInterruptReportCallback(UpstreamPacketTypeDef* r } } - //Other mouse sanity checks & stuff go here... +#ifdef CONFIG_MOUSE_BOT_DETECT_ENABLED + Upstream_HID_BotDetectMouse(receivedPacket->Data); +#endif } else #endif diff --git a/Upstream/Src/upstream_hid_botdetect.c b/Upstream/Src/upstream_hid_botdetect.c index 6fe0fe2..7ce542a 100644 --- a/Upstream/Src/upstream_hid_botdetect.c +++ b/Upstream/Src/upstream_hid_botdetect.c @@ -13,6 +13,8 @@ #include "upstream_hid_botdetect.h" #include "upstream_hid.h" #include "build_config.h" +#include "usbd_hid.h" +#include "math.h" @@ -26,6 +28,7 @@ volatile LockoutStateTypeDef LockoutState = LOCKOUT_STATE_INACTIVE; #if defined (CONFIG_KEYBOARD_ENABLED) && defined (CONFIG_KEYBOARD_BOT_DETECT_ENABLED) uint32_t LastKeyDownTime = 0; KeyTimerLogTypeDef KeyTimerLog[KEYBOARD_BOTDETECT_MAX_ACTIVE_KEYS] = {0}; + uint8_t OldKeyboardInData[HID_KEYBOARD_INPUT_DATA_LEN] = {0}; uint8_t KeyDelayFastBinDrainDivideCount = 0; uint8_t KeyDelaySlowBinDrainDivideCount = 0; @@ -35,20 +38,31 @@ volatile LockoutStateTypeDef LockoutState = LOCKOUT_STATE_INACTIVE; uint8_t KeyDelaySlowBinArray[KEYBOARD_BOTDETECT_SLOW_BIN_COUNT] = {0}; uint8_t KeyDowntimeFastBinArray[KEYBOARD_BOTDETECT_FAST_BIN_COUNT] = {0}; uint8_t KeyDowntimeSlowBinArray[KEYBOARD_BOTDETECT_SLOW_BIN_COUNT] = {0}; - uint8_t OldKeyboardInData[HID_KEYBOARD_INPUT_DATA_LEN] = {0}; //Debug: // uint8_t KeyDelayFastBinArrayPeak; // uint8_t KeyDelaySlowBinArrayPeak; // uint8_t KeyDowntimeFastBinArrayPeak; // uint8_t KeyDowntimeSlowBinArrayPeak; + + static uint32_t Upstream_HID_BotDetectKeyboard_RolloverCheck(uint8_t* keyboardInData); + static void Upstream_HID_BotDetectKeyboard_DoLockout(void); + static void Upstream_HID_BotDetectKeyboard_KeyDown(uint8_t keyCode); + static void Upstream_HID_BotDetectKeyboard_KeyUp(uint8_t keyCode); #endif //Variables specific to mouse bot detection: #if defined (CONFIG_MOUSE_ENABLED) && defined (CONFIG_MOUSE_BOT_DETECT_ENABLED) + uint32_t LastMouseMoveTime = 0; + MouseVelocityHistoryTypeDef MouseVelocityHistory[MOUSE_BOTDETECT_VELOCITY_HISTORY_SIZE] = {0}; + + uint8_t SameVelocityCounter = 0; + //Debug: +// uint8_t SameVelocityCounterMax = 0; + static void Upstream_HID_BotDetectMouse_DoLockout(void); #endif @@ -56,13 +70,6 @@ volatile LockoutStateTypeDef LockoutState = LOCKOUT_STATE_INACTIVE; //Code specific to keyboard bot detection: #if defined (CONFIG_KEYBOARD_ENABLED) && defined (CONFIG_KEYBOARD_BOT_DETECT_ENABLED) -static uint32_t Upstream_HID_BotDetectKeyboard_RolloverCheck(uint8_t* keyboardInData); -static void Upstream_HID_BotDetectKeyboard_DoLockout(void); -static void Upstream_HID_BotDetectKeyboard_KeyDown(uint8_t keyCode); -static void Upstream_HID_BotDetectKeyboard_KeyUp(uint8_t keyCode); - - - //Checks if received keyboard data is from a real human. //This is not entirely bulletproof as an attacking device may randomize its keypresses. void Upstream_HID_BotDetectKeyboard(uint8_t* keyboardInData) @@ -131,7 +138,6 @@ void Upstream_HID_BotDetectKeyboard(uint8_t* keyboardInData) Upstream_HID_BotDetectKeyboard_DoLockout(); break; } - //Debug: // if (KeyDelayFastBinArray[i] > KeyDelayFastBinArrayPeak) KeyDelayFastBinArrayPeak = KeyDelayFastBinArray[i]; // if (KeyDowntimeFastBinArray[i] > KeyDowntimeFastBinArrayPeak) KeyDowntimeFastBinArrayPeak = KeyDowntimeFastBinArray[i]; @@ -144,7 +150,6 @@ void Upstream_HID_BotDetectKeyboard(uint8_t* keyboardInData) Upstream_HID_BotDetectKeyboard_DoLockout(); break; } - //Debug: // if (KeyDelaySlowBinArray[i] > KeyDelaySlowBinArrayPeak) KeyDelaySlowBinArrayPeak = KeyDelaySlowBinArray[i]; // if (KeyDowntimeSlowBinArray[i] > KeyDowntimeSlowBinArrayPeak) KeyDowntimeSlowBinArrayPeak = KeyDowntimeSlowBinArray[i]; @@ -345,31 +350,140 @@ static void Upstream_HID_BotDetectKeyboard_KeyUp(uint8_t keyCode) //Called by Systick_Handler every 1ms, at high interrupt priority. void Upstream_HID_BotDetect_Systick(void) { -//Keyboard-specific stuff: -#if defined (CONFIG_KEYBOARD_ENABLED) && defined (CONFIG_KEYBOARD_BOT_DETECT_ENABLED) +#if (defined (CONFIG_KEYBOARD_ENABLED) && defined (CONFIG_KEYBOARD_BOT_DETECT_ENABLED)) || \ + (defined (CONFIG_MOUSE_ENABLED) && defined (CONFIG_MOUSE_BOT_DETECT_ENABLED)) + //Check if temporary lockout has expired if (LockoutState == LOCKOUT_STATE_TEMPORARY_ACTIVE) { - if (TemporaryLockoutTimeMs++ > KEYBOARD_BOTDETECT_TEMPORARY_LOCKOUT_TIME_MS) + if (TemporaryLockoutTimeMs++ > BOTDETECT_TEMPORARY_LOCKOUT_TIME_MS) { LockoutState = LOCKOUT_STATE_TEMPORARY_FLASHING; } } else if (LockoutState == LOCKOUT_STATE_TEMPORARY_FLASHING) { - if (TemporaryLockoutTimeMs++ > KEYBOARD_BOTDETECT_TEMPORARY_LOCKOUT_FLASH_TIME_MS) + if (TemporaryLockoutTimeMs++ > BOTDETECT_TEMPORARY_LOCKOUT_FLASH_TIME_MS) { LED_SetState(LED_STATUS_OFF); LockoutState = LOCKOUT_STATE_INACTIVE; } } #endif +} + +//Code specific to mouse bot detection: #if defined (CONFIG_MOUSE_ENABLED) && defined (CONFIG_MOUSE_BOT_DETECT_ENABLED) -#endif +void Upstream_HID_BotDetectMouse(uint8_t* mouseInData) +{ + uint32_t i; + uint32_t now = HAL_GetTick(); + uint32_t moveDelay; + uint32_t velocity; + uint32_t newAverageVelocity; + uint32_t oldAverageVelocity; + int8_t mouseX; + int8_t mouseY; + + mouseX = mouseInData[1]; + mouseY = mouseInData[2]; + velocity = (sqrtf(((int32_t)mouseX * mouseX) + + ((int32_t)mouseY * mouseY))) * 8; //Multiply floating-point sqrt result to avoid integer rounding + + moveDelay = ((now - LastMouseMoveTime) + (HID_FS_BINTERVAL / 2)) / HID_FS_BINTERVAL; //Number of poll intervals since last movement + if (moveDelay > MOUSE_BOTDETECT_MOVE_DELAY_LIMIT) moveDelay = MOUSE_BOTDETECT_MOVE_DELAY_LIMIT; + + if ((velocity != 0) && (moveDelay != 0)) + { + LastMouseMoveTime = now; + for (i = (MOUSE_BOTDETECT_VELOCITY_HISTORY_SIZE - 1); i > 0; i--) //Shuffle down history data + { + MouseVelocityHistory[i] = MouseVelocityHistory[i - 1]; + } + MouseVelocityHistory[0].moveDelay = moveDelay; //Store latest data at head + MouseVelocityHistory[0].velocity = velocity; + + if (MouseVelocityHistory[(MOUSE_BOTDETECT_VELOCITY_HISTORY_SIZE - 1)].velocity > 0) + { + moveDelay = 0; //Calculate new and old average velocities + velocity = 0; + for (i = 0; i < (MOUSE_BOTDETECT_VELOCITY_HISTORY_SIZE / 2); i++) + { + moveDelay += MouseVelocityHistory[i].moveDelay; + velocity += MouseVelocityHistory[i].velocity; + } + newAverageVelocity = (velocity * 8) / moveDelay; //Multiply velocity up to avoid rounding errors on divide + + moveDelay = 0; + velocity = 0; + for (i = (MOUSE_BOTDETECT_VELOCITY_HISTORY_SIZE / 2); i < MOUSE_BOTDETECT_VELOCITY_HISTORY_SIZE; i++) + { + moveDelay += MouseVelocityHistory[i].moveDelay; + velocity += MouseVelocityHistory[i].velocity; + } + oldAverageVelocity = (velocity * 8) / moveDelay; //Multiply velocity up to avoid rounding errors on divide + if (newAverageVelocity == oldAverageVelocity) + { + SameVelocityCounter++; + if (SameVelocityCounter > MOUSE_BOTDETECT_TEMPORARY_LOCKOUT_VELOCITY_THRESHOLD) + { + Upstream_HID_BotDetectMouse_DoLockout(); + } + + //Debug: +// if (SameVelocityCounter > SameVelocityCounterMax) SameVelocityCounterMax = SameVelocityCounter; + } + else + { + SameVelocityCounter = 0; + } + } + } + else + { + mouseInData[1] = 0; //If we don't want to process this event, makes sure no movement data gets through + mouseInData[2] = 0; + } + + //Host receives no data if we are locked + if ((LockoutState == LOCKOUT_STATE_TEMPORARY_ACTIVE) || + (LockoutState == LOCKOUT_STATE_PERMANENT_ACTIVE)) + { + for (i = 0; i < HID_MOUSE_INPUT_DATA_LEN; i++) + { + mouseInData[i] = 0; + } + } } +static void Upstream_HID_BotDetectMouse_DoLockout(void) +{ + uint32_t i; + + if (LockoutState == LOCKOUT_STATE_PERMANENT_ACTIVE) return; + + //Are we already in warning state? -> activate permanent lockout + if ((LockoutState == LOCKOUT_STATE_TEMPORARY_ACTIVE) || + (LockoutState == LOCKOUT_STATE_TEMPORARY_FLASHING)) + { + LockoutState = LOCKOUT_STATE_PERMANENT_ACTIVE; + return; + } + + //Otherwise, reset counters and give warning + for (i = 0; i < MOUSE_BOTDETECT_VELOCITY_HISTORY_SIZE; i++) + { + MouseVelocityHistory[i].velocity = 0; + } + SameVelocityCounter = 0; + + TemporaryLockoutTimeMs = 0; + LockoutState = LOCKOUT_STATE_TEMPORARY_ACTIVE; + LED_SetState(LED_STATUS_FLASH_BOTDETECT); +} +#endif