Executing Shellcode via Bluetooth Device Authentication

by | Jan 13, 2025 | #_shellntel, Blog, Remote Access

While reading through the MSDN documentation for Bluetooth, I started thinking about what opportunities there were to leverage Bluetooth for offensive purposes. I ended up creating a shellcode loader that triggers a nearby Bluetooth device to authenticate to the victim machine which will execute shellcode. In this post, I will talk about how the method works, and its pros and cons. The nomenclature used by these Bluetooth WinAPIs is Radio for local Bluetooth radio’s on the machine, and Device for external Bluetooth devices and I will continue to refer to these throughout the article.

Shellcode loaders are a means of delivering and executing shellcode (usually to establish C2) onto a victim machine. At a basic level they perform the following actions:

  1. Allocate memory in the process to hold the shellcode.
  2. Decrypt the shellcode (If its encrypted).
  3. Copy the shellcode into the allocated memory.
  4. Change the memory protections to be executable.
  5. Create a thread to run the shellcode.

The API’s used to perform these actions are heavily scrutinized by EDR due to the widespread use in malware. Also, any process that performs these actions is very likely to flagged by EDR. However, the point you are most likely to get flagged would be in step 5 when you are trying to execute the shellcode. For example, via a call to CreateThread. To help get around this, there has been research done on alternative methods to execute the shellcode via callbacks which avoids a call to CreateThread and executes the shellcode through various callbacks to other, non-sketchy functions. At the end of the day, this is simply just another callback that can be used to execute shellcode. Where things get interesting is how Bluetooth is used for this. Which comes with its own set of pros and cons.

What does it do?

At a high level, the program will check to ensure that Bluetooth is enabled on the machine, search for nearby Bluetooth devices, register an authentication callback pointing to the memory address of the shellcode, and trigger the discovered device to authenticate to the machine which will execute the shellcode.

The cool part is during the device authentication, no user interaction is required, and no popups are displayed to the user. What I mean by this is that the user does not need to “approve” the authentication for this to work. Their machine will not even show that a device is trying to authenticate. The device authentication also does not even have to succeed. However, the user does still need to run the payload on their machine. My thought was for this to be used as an initial access payload, delivered through social engineering or other means. In an office environment, there are likely to be many TV’s, speakers, headphones, etc. that could be used to trigger the execution.

The only downside of this is that there must be a discoverable Bluetooth device in the vicinity in order to execute the shellcode. This is not a super tall order; I work remotely and had no problem discovering a suitable Bluetooth device in my home. So, an office would probably be a pretty target rich environment. I’d go to Vegas with those odds. However, it would be such a shame to have a user execute the malware from your sweet social engineering ruse, only to have it fail because there weren’t any Bluetooth devices nearby. So it’s definitely not suitable for every scenario, but in the right conditions it could be quite powerful.

How does it work?

First, the program will try and discover a Bluetooth radio on the machine via a call to BluetoothFindFirstRadio (win | rust). The machine the malware is executed on not only needs to have the Bluetooth hardware installed, but Bluetooth also needs to be turned on.

This is also a very good anti-emulation defensive measure because many malware sandboxes will not have the hardware to support Bluetooth, so the malware will never execute.

After obtaining a handle to the Bluetooth radio on the machine, the next step is to search for nearby Bluetooth devices. This is done by calling BluetoothFindFirstDevice (win | rust) and passing it a struct of BLUETOOTH_DEVICE_SEARCH_PARAMS (win | rust), telling it to find all devices and start a new query, as well as passing a pointer to a BLUETOOTH_DEVICE_INFO struct (win | rust) that will contain information about the discovered device. If a discovered device is already authenticated, it will call BluetoothFindNextDevice (win | rust) to search for other devices, until it finds one that is not already authenticated.

This is also great for anti-emulation because even in the event the sandbox did have Bluetooth enabled, it would still need to find a nearby Bluetooth device in order to execute. I would guess the odds of this happening are slim to none.

Next, it’s time to load the payload. The function is pretty straightforward and it’s just returning the memory address where the shellcode has been loaded.

Now for the fun part, creating and registering the callback. The interesting function here is BluetoothRegisterForAuthenticationEx (win | rust). The first and third parameters are the important ones. It takes in a pointer to a BLUETOOTH_DEVICE_INFO struct, which is the discovered device; and a pointer to the function to be called when the authentication event occurs.

https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/Devices/Bluetooth/fn.BluetoothRegisterForAuthenticationEx.html

The type definition for PFN_AUTHENTICATION_CALLBACK_EX (win | rust) is as follows:

unsafe extern “system” fn(pvparam: *const c_void, pauthcallbackparams: *const BLUETOOTH_AUTHENTICATION_CALLBACK_PARAMS) -> BOOL>;

Type casting in Rust isn’t quite as straightforward as in C, but it’s not too bad. I am creating a variable of the aforementioned type and calling mem::transmute() and passing the memory address of the shellcode. With the function pointer set, it’s time to call BluetoothRegisterForAuthenticationEx and pass the struct containing the device info and the function pointer callback.

Now, calling BluetoothAuthenticateDevice (win | rust) will trigger the target device to authenticate to the machine, which will execute the callback.

Here is a demo using btexec to establish a Havoc C2 beacon:

Full source code can be found here:

https://github.com/djackreuter/btexec