Executive Summary
Rasmus Moorats reverse-engineered the firmware of the Creative Sound Blaster Katana V2X — a USB-connected PC soundbar — and chained four findings into a remote, no-touch attack on the host the speaker is plugged into. The Katana V2X exposes a proprietary command channel called the Creative Transport Protocol (CTP) over both USB and Bluetooth Low Energy. On USB, CTP is gated by a challenge-response that uses a static key extractable from the Creative desktop app. On Bluetooth, the same CTP commands are accepted with no pairing and no authentication at all. CTP carries firmware-upgrade transactions. The firmware is protected only by a SHA-256 checksum (CHK2) over the container, which is trivial to recompute. There is no signature, no bootloader unlock, no secure boot. Combine those facts and you get over-the-air firmware delivery to an unpaired Bluetooth device within ~15 metres of the victim.
The payload — ~280 bytes of hand-written ARM Thumb assembly plus an 83-byte USB report descriptor patch — turns the soundbar’s existing HID Consumer Control interface into a full HID keyboard, then quietly types a command line into the host operating system. The host trusts the keystrokes because the speaker is, in Windows / Linux / macOS terms, a “trusted USB HID device”. The result is a remote Rubber Ducky that nobody had to plug in. Creative’s first response, after almost two months of disclosure delay routed through SingCERT, was that this is not a cybersecurity issue. They have since revised that position, but at the time of the original publication there is no fixed firmware available and the patcher tool Moorats released has been broken by Creative pulling the official firmware download URLs.
Background: what the Creative Transport Protocol does
Creative’s mobile and desktop control panel lets a user reconfigure the Katana V2X — DSP profile, LED pattern, output routing — through a proprietary on-wire format that Moorats calls CTP, the Creative Transport Protocol. The protocol’s framing always starts with the byte 0x5a followed by an opcode and an argument blob. On USB, CTP is authenticated by a challenge-response that the Creative app handles: a key derivable from the desktop binary is mixed with a nonce, and the soundbar verifies the response before honoring any commands. Firmware upgrades happen over the same CTP channel.

To get hands on the firmware Moorats sniffed that USB traffic with Wireshark, reassembled the upload, and pulled the raw image out. The container itself is a small Zip-shaped wrapper holding three relevant blobs: FBOOT (the bootloader, also responsible for the recovery mode reached by holding the SOURCE button at power-on), FMAIN (the main firmware image, roughly 6.5× the bootloader’s size), and CHK2 (a SHA-256 over the rest of the container). Both halves of the firmware are built on a heavily-modified FreeRTOS 8.2.3 — you can see the build host’s path baked into the binaries:
/home/jieyi/mcuos2.5/kernel/freertos-8.2.3/
Firmware analysis: the CHK2 checksum is the entire protection
The container does not carry a signature. There is no public-key verification, no bootloader unlock requirement, and no anti-rollback. The only thing the device checks before accepting a firmware image is the CHK2 SHA-256, which the attacker can recompute trivially after modifying any byte of the container. Moorats demonstrates this with a minimum-viable patch: replace the boot string WELCOME with PATCHED, recompute CHK2, flash. The Katana V2X comes up and proudly announces its compromise on the front-panel segment display.

Everybody loves Bluetooth
The Katana V2X advertises a Bluetooth Low Energy GATT service so the Creative app on a phone can configure it without a USB cable. BLE technically allows connection without pairing — pairing exists to negotiate link-layer encryption, not to gate which characteristics a peer can read or write. The Creative control panel coaxes users into pairing by displaying “please press the POWER button to pair”, but nothing on the device requires it.
Sniffing the BLE traffic during a setup reveals that the phone writes a payload starting with 5a 0b ... to characteristic 9e9daaec-3a10-4fe8-b69f-7397aff77886 and reads the response from 9e9daaeb-3a10-4fe8-b69f-7397aff77886. That leading 0x5a is the CTP start byte. Decompiling CtpService_Init in Ghidra confirms what the traffic suggests: the same handler is hooked to both transports.

CtpService_Init. The CTP handler is wired to both USB and the BLE characteristic pair — the root cause of the no-pairing CTP-over-Bluetooth issue. Source: original article.To test, Moorats sent the CTP “read firmware version” command — 5a 09 01 02, normally gated by the USB challenge-response — straight to the BLE characteristic. The full firmware version string came back. The BLE side simply does not run the authentication path. Any device in radio range can speak CTP to the speaker.
Over-the-air firmware updates (the bad kind)
The firmware upload transaction is itself a CTP exchange. Moorats wrote a short Python script that drives the upload sequence over BLE instead of USB and timed a full custom firmware push: roughly ten minutes from CTP “start update” to a clean reboot on the new image. The immediate implication is bad enough on its own — the Katana V2X has a microphone (the Creative app uses it for voice calls), so a malicious firmware can quietly turn the speaker into a covert monitoring device. The more interesting implication is that the speaker is, by definition, attached to the host as a trusted USB peripheral. What if the malicious firmware made it pretend to be a keyboard?
Living off the kernel land: turning the speaker into a keyboard
Adding a complete HID stack to an unfamiliar embedded firmware from scratch would be a non-trivial project. The Katana V2X spares us: it already enumerates as a HID Consumer Control device (that is what the volume and play/pause buttons on the soundbar talk to the host through), and the firmware already contains the routine that hands HID reports off to the USB driver.

dmesg on a Linux host before the patch: the factory Katana attaches as a HID Consumer Control device. Source: original article.The patch needs three pieces. First, an 83-byte append to the USB report descriptor that adds a keyboard report on top of the existing Consumer Control one, so the host enumerates the device as a composite HID with a keyboard interface. Second, a 102-byte Thumb assembly routine that constructs HID reports from a list of two-byte (modifier, keycode) pairs and pumps them through the existing report-send routine. Third, somewhere to put that routine. Moorats overwrote the diagnostic task — a FreeRTOS task that is built into the firmware but does nothing in normal operation — with code that waits ~20 seconds for the USB subsystem to come up, types echo pwned at ~20 ms per keystroke, then exits cleanly so the rest of the soundbar keeps working.

dmesg after the patch: the same speaker, the same USB port, now a keyboard. The OS trusts it the same way it would trust a USB Rubber Ducky — with the difference that no human ever plugged anything in. Source: original article.The result
Chained together: an attacker within Bluetooth range pushes a hand-patched firmware to the unpaired Katana V2X over BLE in about ten minutes, the speaker reboots, and twenty seconds after USB enumeration the host receives a stream of HID keyboard reports that type echo pwned into the foreground shell or terminal. A real engagement would replace echo pwned with whatever one-liner is appropriate — powershell.exe -nop -w hidden -enc ... on Windows, the equivalent dropper on macOS or Linux — and would also patch out the firmware-upgrade handler in normal and recovery mode so the victim can’t wipe the implant. The speaker keeps Bluetooth on in sleep state and has no user-facing way to disable the radio.

echo pwned into the host’s foreground terminal. Source: original article.Remediation — and the disclosure story
Creative does not publish a security contact. Moorats tried twice through the public support web form, received no reply, and escalated through SingCERT (the Singapore CERT, where Creative is headquartered) as an intermediary. Creative took nearly two months to reply through SingCERT and stated initially that “they do not consider this to be a vulnerability, as it does not present a cybersecurity risk.” With no vendor fix incoming, Moorats wrote a defensive firmware patch that disables the CTP-over-Bluetooth handler (the trade-off is that the official mobile app stops working) and shipped a tool that downloads the official firmware from Creative’s servers, applies the patch in memory, and re-flashes the Katana over USB. The tool lives at git.dog/xx/v2x-patcher and builds with cargo.
Eleven days later Creative reversed course. The quoted response below is reproduced verbatim from the original disclosure post:
We also want to acknowledge the frustrating experience you had when trying to contact us through our support form. On review, we found that your message had been automatically flagged as spam by our support system, which is why you did not receive a Case ID or acknowledgement. We have corrected this so that legitimate security reports are no longer caught by that filter, and we are looking at putting a dedicated channel in place to make disclosures like yours more straightforward going forward. The team is already developing a series of fixes to address the issues you identified.
Creative, quoted in the 2026-06-18 update on the original article
That is the right answer eventually, but the path to it — SingCERT as a courier, almost two months of silence, a dismissal, and a firmware-download takedown that pushed legitimate Katana owners further from a fix — is the part of this story most worth reading the original disclosure post for.
Reverse-engineering notes
The body of the original post devotes considerable space to the Ghidra-side mechanics. Three observations are general enough that they apply to any unfamiliar Cortex-M firmware, not just this one.
Memory layout: scatter-loaded firmware throws off auto-analysis
Ghidra’s automatic analysis depends on the user giving it a correct base address for the binary. FMAIN.bin would not converge with the obvious guess of 0x10000000 because it is not a single monolithic image: it is scatter-loaded, with different file regions mapped to different RAM and ROM addresses at load time. Moorats deduced the layout by walking device memory directly (using the R/W primitives described below) and reports the following correspondences:
| File Offset | Address | Content |
|---|---|---|
| 0x0000–0x89EF | 0x10000000 | Kernel code: vector table, startup, FreeRTOS core, exception handlers |
| 0x89F0–0xBDDC7 | 0x40000008 | App code: main application, drivers, task handlers |
| 0xBDDC8–0x164A0B | N/A | Const / read-only data: DSP coefficients, config tables |
| 0x164A0C–0x1682DB | 0x100089E8 | .data init values for kernel SRAM |
| 0x1682DC–0x16B003 | 0x400B5400 | .data init values for app RAM |
String cross-references through movw / movt pairs
Even with the right memory map, Ghidra’s string cross-references were patchy. The reason is the standard ARM idiom for loading a 32-bit constant: a movw instruction fills the low 16 bits of a register and a movt immediately after fills the high 16 bits. Ghidra’s analysis was not stitching the pairs back into a single address for the purpose of recognising string pointers. The disassembly looks like this:
movw r0, #0x29A4 ; low 16 bits
movt r0, #0x400A ; high 16 bits, r0 = 0x400A29A4
A short Ghidra script that walks the listing, pairs every movw with the matching movt loading into the same destination register, filters for the addresses that fall inside a known section, and creates an explicit data reference, recovers about thirteen thousand previously-missing string references. The cost is a handful of lines of Jython; the saving is much of the firmware now reads naturally in the decompiler.
Memory R / W / X primitives over CTP
Iterating on patches by reflashing each candidate is slow, and a broken patch typically means a boot-loop into recovery mode. To shorten the loop, Moorats hijacked the CTP echo command (opcode 0x54, about 106 bytes in the firmware) and rewrote it in place as a three-command dispatcher implementing arbitrary memory read, memory write, and code-execute primitives in 96 bytes total. He then patched v2x-ctl on the host to expose those primitives. The result is fast, in-process iteration without reflashing the whole image — useful for validating the scatter-load deductions above, and indispensable for the next subsection.
Watchdogs and where you cannot block
The first attempt at the keystroke injector called vTaskDelay from inside the USB receive callback so that the typing loop could pace itself. The Katana rebooted partway through every test. The cause was straightforward: the firmware runs per-task watchdog timers, and the USB-handling task is configured with a watchdog window that does not tolerate the ~20 ms inter-keystroke pacing. Moving the typing loop into the (unused, idle-context) diagnostic task instead of running it inside the USB callback resolves it entirely, because diagnostic is allowed to sleep. This is a general lesson: in any small FreeRTOS firmware, your first question after a “mysterious reboot during a new feature” should be “which task am I in, and what does its watchdog look like”.
For completeness, all of the work in the post is on firmware version 1.3.230619.1820.
Key Takeaways
- A USB peripheral that also speaks BLE is a USB peripheral with a remote attack surface. Treat the Bluetooth side with the same scepticism you give the USB side, especially for any “mobile companion app” protocol.
- BLE pairing is link-layer encryption, not authorization. If your device’s command protocol is reachable on an unpaired GATT characteristic, anyone in radio range can drive it.
- A SHA-256 over a firmware container is not signing. Without an asymmetric verification step on the bootloader side, the checksum is just an integrity check the attacker recomputes after their edits.
- If the device already implements any HID class — consumer control, system control, even a single function key — adding a HID keyboard report is small. The cost of “turn this speaker / camera / printer into a keyboard” is now in the 80-to-300 bytes of patch, not the multi-kilobyte rewrite you would expect.
- Modifying a CTP-style echo opcode into a 96-byte R/W/X dispatcher is a generally-useful technique on any embedded firmware where you have a control protocol — it cuts the iteration loop from “reflash and reboot” to “round-trip a control message”.
- FreeRTOS per-task watchdogs determine which contexts may block; the same code that runs fine in an idle task can reboot the system from a USB-receive callback. Pick the host task accordingly.
- When a vendor has no security contact, expect months of latency and at least one “this is not a vulnerability” before you reach an engineer. National CERTs are useful intermediaries but they do not shorten the loop the way a dedicated PSIRT does.
Defensive Recommendations
- For vendors shipping USB peripherals with BLE: apply the same authentication and authorization checks on the Bluetooth transport that you apply on USB. Sharing a single command dispatcher across both transports is fine; sharing it without the auth gate is not.
- For vendors shipping any firmware-updatable device: sign the firmware with an asymmetric key. Verify the signature in the bootloader, before scheduling the new image. Treat any integrity-only check (CRC32, SHA-256) as anti-corruption, not anti-tamper.
- For vendors: publish a security contact. A
security.txtat the root of your domain costs nothing and saves months of escalations like the SingCERT route used here. Make sure your support-ticket spam filter does not eat reports. - For Windows / Linux / macOS administrators on hardened endpoints: consider USB HID-class allow-lists that block keyboard / pointer enumeration from devices whose
idVendor:idProductdoes not match a known approved set. Workstation EDR products typically expose this as a “BadUSB / Rubber Ducky” policy. - For incident responders: if you suspect a peripheral implant, dump the device’s firmware over USB before power-cycling. Many embedded firmwares wipe writable state on reset.
- For threat modelling: include peripherals with persistent storage (soundbars, monitors, keyboards, webcams, printers) in your “what can hold an implant” inventory. The trust model assumes they are dumb; this disclosure is another reminder that they are not.
- For users of an affected Katana V2X / V2 / SE today: until Creative ships a fixed firmware, disable Bluetooth pairing in the companion app, treat the speaker as untrusted, and unplug the USB cable when the host is not actively in use. There is no clean mitigation from the host side alone.
Conclusion
The Pwnd Blaster chain is a textbook example of how a small set of individually-reasonable design choices compound into a remote, no-touch implant: a useful proprietary control protocol gets a second transport because BLE is convenient; the second transport skips authentication because pairing “feels like” authorization; firmware integrity becomes a checksum because asymmetric signing is “too much” for a soundbar; and the existing HID Consumer Control interface, present so that the volume buttons work, becomes the foothold that makes the keyboard pivot trivial. The reason this lands rather than just being a curiosity is that nothing in the chain requires the attacker to ever touch the target. The full disclosure post by Rasmus Moorats walks the path in considerably more detail than this summary — for the Ghidra screenshots, the BLE characteristic UUIDs, the exact firmware blob layout, and the vendor-disclosure timeline, read the original at blog.nns.ee.
Original text: “Pwnd Blaster: Hacking your PC using your speaker without ever touching it” by Rasmus Moorats at blog.nns.ee.

