wanalyze: generic traffic analysis tool

wanalyze allows to analyze traffic from packets captured from sniffing or through PCAP replay. It is based on several traffic analyzers, allowing to infer various information from a stream of packets (e.g., decryption keys, profiles, audio stream, keystrokes…). It is intended to be used chained with other WHAD tools.

Usage

... | wanalyze [OPTIONS] [ANALYZER]

By default, wanalyze will use all available traffic analyzers for the traffic linked to the used domain. If provided, only the traffic analyzers provided as a series of expression ANALYZER will be applied. For example, the following command will use all available BLE analyzers:

$ wplay --flush ressources/pcaps/ble_pairing.pcap | wanalyze

The following command will use only “legacy_pairing_cracking” and “encrypted_session_initialization”:

$ wplay --flush ressources/pcaps/ble_pairing.pcap | wanalyze legacy_pairing_cracking encrypted_session_initialization

It is also possible to select only a specific field of an analyzer output, using the expression ANALYZER.FIELD. For example, the following command line will display only the Short-Term Key (STK) of the “legacy_pairing_cracking” analyzer:

$ wplay --flush ressources/pcaps/ble_pairing.pcap | wanalyze legacy_pairing_cracking.stk

Command-line options

wextract supports the following options:

  • --trigger: display when an analyzer has been triggered

  • --json: serialize output into JSON format

  • --packets (-p): display packets associated with the analyzer

  • --label: display labels before output value

  • --delimiter (-d / -D): provide a delimiter inserted between outputs

  • --raw (-r): dump output directly to stdout buffer (e.g., to process raw bytes)

  • --list (-l): display a list of available analyzers

Displaying the available analyzers

To display the list of available analyzers by domain, just use the --list (or -l) option:

$ wanalyze -l
Available analyzers:  ble
- peripheral_information : adv_data, bd_addr, addr_type
- encrypted_session_initialization : master_skd, master_iv, slave_skd, slave_iv, started
- legacy_pairing_cracking : tk, stk
- ltk_distribution : ltk, rand, ediv
- irk_distribution : address, irk
- csrk_distribution : csrk
- profile_discovery : profile

Available analyzers:  rf4ce
- key_cracking : key
- audio : raw_audio
- keystroke : key

Available analyzers:  unifying
- pairing_cracking : key
- mouse : x, y, wheel_x, wheel_y, button
- keystroke : key

Available analyzers:  zigbee
- touchlink_key_cracking : key_index, encrypted_key, decrypted_key
- transport_key_cracking : transport_key

Breaking encryption keys

It’s quite common for wireless protocols to use weak pairing procedures, that can be attacked to recover the encryption keys. WHAD provides various traffic analyzers allowing to perform such offline attacks, targeting various protocols.

Breaking Bluetooth Low Energy legacy pairing

The first version of Bluetooth Low Energy pairing is flawed and is known to be vulnerable to CrackLE attack. wanalyze allows to easily retrieve encryption key if the pairing procedure has been captured and if legacy pairing was in use.

To perform this attack, you can use the “legacy_pairing_cracking” analyzer. To demonstrate the attack, let’s first download a PCAP file containing a vulnerable pairing:

wget https://github.com/whad-team/whad-client/raw/main/ressources/pcaps/ble_pairing.pcap

We can easily replay this PCAP file using wplay tool, with option --flush to display all the traffic without taking into account the timestamps:

$ wplay --flush ble_pairing.pcap
[ raw=True, decrypted=False, timestamp=0, channel=37, rssi=-44, direction=0, connection_handle=0, is_crc_valid=True, relative_timestamp=0 ]
<BTLE  access_addr=0x8e89bed6 crc=0xec6ba9 |<BTLE_ADV  RxAdd=public TxAdd=random ChSel=0 RFU=0 PDU_type=CONNECT_REQ Length=0x22 |<BTLE_CONNECT_REQ  InitA=63:5b:46:e8:b3:81 AdvA=74:da:ea:91:47:e3 AA=0xf5a6dd92 crc_init=0x852f0a win_size=0x2 win_offset=0x1 interval=0x24 latency=0x0 timeout=0x1f4 chM=0x1fffffffff SCA=0 hop=6 |>>>

[ raw=True, decrypted=False, timestamp=341, channel=6, rssi=0, direction=1, connection_handle=0, is_crc_valid=True, relative_timestamp=0 ]
<BTLE  access_addr=0x92dda6f5 crc=0x5509b6 |<BTLE_DATA  RFU=0 MD=0 SN=0 NESN=0 LLID=control len=9 |<BTLE_CTRL  opcode=LL_FEATURE_REQ |<LL_FEATURE_REQ  feature_set=le_encryption+conn_par_req_proc+ext_reject_ind+slave_init_feat_exch+le_ping+le_data_len_ext+ll_privacy+ext_scan_filter+le_2m_phy+rx_mod_idx+le_coded_phy+le_ext_adv+le_periodic_adv+ch_sel_alg |>>>>

[ raw=True, decrypted=False, timestamp=4841, channel=12, rssi=0, direction=1, connection_handle=0, is_crc_valid=True, relative_timestamp=0 ]
<BTLE  access_addr=0x92dda6f5 crc=0x5509b6 |<BTLE_DATA  RFU=0 MD=0 SN=0 NESN=0 LLID=control len=9 |<BTLE_CTRL  opcode=LL_FEATURE_REQ |<LL_FEATURE_REQ  feature_set=le_encryption+conn_par_req_proc+ext_reject_ind+slave_init_feat_exch+le_ping+le_data_len_ext+ll_privacy+ext_scan_filter+le_2m_phy+rx_mod_idx+le_coded_phy+le_ext_adv+le_periodic_adv+ch_sel_alg |>>>>

[ raw=True, decrypted=False, timestamp=4871, channel=12, rssi=0, direction=2, connection_handle=0, is_crc_valid=True, relative_timestamp=0 ]
<BTLE  access_addr=0x92dda6f5 crc=0xba762b |<BTLE_DATA  RFU=0 MD=0 SN=0 NESN=1 LLID=continue len=0 |>>

[ raw=True, decrypted=False, timestamp=9341, channel=18, rssi=0, direction=1, connection_handle=0, is_crc_valid=True, relative_timestamp=0 ]
<BTLE  access_addr=0x92dda6f5 crc=0x1c7b2b |<BTLE_DATA  RFU=0 MD=0 SN=1 NESN=1 LLID=continue len=0 |>>

[...]

Let’s analyze this traffic with our “legacy_pairing_cracking” analyzer:

$ wplay --flush ble_pairing.pcap | wanalyze legacy_pairing_cracking                                                                                                                    ST 27   main
[✓] legacy_pairing_cracking → completed
  - tk:  00000000000000000000000000000000
  - stk:  f72fa81ee5e86708243e920107de31b9

The output indicates both the temporary key (“tk”) and the Short-Term Key (stk).

The Short-Term Key is then used to encrypt the key distribution between the communicating devices. Let’s decrypt the traffic with wplay by using option -d (decrypt) and by providing the STK with option -k (keys):

$ wplay --flush ble_pairing.pcap -d -k f72fa81ee5e86708243e920107de31b9

Then, we can easily extract the various distributed keys using wanalyze on the decrypted stream:

$ wplay --flush ble_pairing.pcap -d -k f72fa81ee5e86708243e920107de31b9 | wanalyze
[...]
[✓] ltk_distribution → completed
  - ltk:  2867a99de17e3548cc17cf16ef96050e
  - rand:  38a7dcd10a1a93c6
  - ediv:  29507

[✓] irk_distribution → completed
  - address:  74:da:ea:91:47:e3
  - irk:  13c3a68f113b764cc8e73f55fc52c002

[✓] csrk_distribution → completed
  - csrk:  c3062f93c91eef96354edcd70a1a0306

[✓] ltk_distribution → completed
  - ltk:  8ec147a3b442e2ea77b3e98705f26ca8
  - rand:  51064044944874a2
  - ediv:  55664

[✓] irk_distribution → completed
  - address:  64:a2:f9:be:de:f1
  - irk:  b3370bec1cef2ecec83a035478eba33a

[✓] csrk_distribution → completed
  - csrk:  9581eb690fbb3b8dfeb97b7293917bd4

Extracting keys from ZigBee join procedure

When a new device wants to join an existing ZigBee network, the Network Key will be transmitted over the air, encrypted with a pre-shared Transport Key. Some Transport Key are publicly known, and can be used to decrypt the packet including the Network Key.

For example, Philips Hue uses the following Transport Key for their ZigBee networks: 81:42:86:86:5D:C1:C8:B2:C8:CB:C5:2E:5D:65:D1:B8.

Let’s download a PCAP file containing such procedure:

$ wget https://github.com/whad-team/whad-client/raw/main/ressources/pcaps/zigbee_philips_hue_association.pcap

We can then replay and decrypt the traffic using wplay with -d (decrypt) option. We need to provide the transport key using -k (keys) option.

$ wplay --flush zigbee_philips_hue_association.pcap -d -k 81:42:86:86:5D:C1:C8:B2:C8:CB:C5:2E:5D:65:D1:B8

To extract the network key, we only need to use wanalyze and observe the output of the analyzer “transport_key_cracking”:

$ wplay --flush zigbee_philips_hue_association.pcap -d -k 81:42:86:86:5D:C1:C8:B2:C8:CB:C5:2E:5D:65:D1:B8 | wanalyze
[✓] transport_key_cracking → completed
  - transport_key:  02398409245156e31d98a92157a8a66f

Breaking RF4CE pairing procedure

RF4CE protocol uses a weak pairing procedure, that can be exploited to recover the encryption key by analyzing pairing traffic.

Let’s download a PCAP file containing such weak pairing procedure:

$ wget https://github.com/whad-team/whad-client/raw/main/ressources/pcaps/rf4ce_pairing_keystrokes_audio.pcap

Then, cracking the key is as simple as running the following command:

$ wplay --flush rf4ce_pairing_keystrokes_audio.pcap | wanalyze
[✓] key_cracking → completed
  - key:  48ca7e9fdbc168b0297dd97d4f7f85a8

We can then easily reuse this key with wplay to decrypt all the encrypted traffic:

$ wplay --flush rf4ce_pairing_keystrokes_audio.pcap -d -k 48ca7e9fdbc168b0297dd97d4f7f85a8

Breaking Logitech Unifying pairing

Wireless keyboards and mices from Logitech commonly relies on Logitech Unifying protocol (or one of its variants). This protocol also uses a vulnerable pairing procedure, which can be attacked easily if the pairing packets have been captured.

You can use wsniff and -p option (pairing) to synchronize with the channel hopping algorithm and sniff a Logitech Unifying pairing:

$ wsniff -i uart0 unifying -p

Alternatively, you can download a PCAP file containing a captured pairing using the following command:

$ wget https://github.com/whad-team/whad-client/raw/main/ressources/pcaps/logitech_pairing.pcap

And replay it using wplay:

$ wplay --flush logitech_pairing.pcap

Recovering the key is then as simple as running wanalyze on the corresponding stream to perform the attack:

$ wplay --flush logitech_pairing.pcap | wanalyze
[✓] pairing_cracking → completed
  - key:  02bea8b5ef61037e87882e4daebf403b

Then, let’s use this key to decrypt some encrypted traffic. Download the PCAP file containing the encrypted traffic:

$ wget https://github.com/whad-team/whad-client/raw/main/ressources/pcaps/logitech_encrypted_traffic.pcap

You can then use wplay with -d option (decrypt) and provide the key using -k (keys):

$ wplay --flush logitech_encrypted_traffic.pcap -d -k 02bea8b5ef61037e87882e4daebf403b
[...]
[ raw=True, decrypted=True, timestamp=50231, channel=0, is_crc_valid=True, address=a8:41:9e:b5:0f ]
<ESB_Hdr  preamble=0xaa address_length=5 address=a8:41:9e:b5:0f payload_length=22 pid=2 no_ack=0 padding=0 valid_crc=yes crc=0xe235 |<Logitech_Unifying_Hdr  dev_index=0x0 frame_type=0xd3 checksum=0x81 |<Logitech_Encrypted_Keystroke_Payload  hid_data='\x00\x0b' unknown=201 aes_counter=3087930536 unused='' |>>>
[...]
[ raw=True, decrypted=True, timestamp=56916, channel=0, is_crc_valid=True, address=a8:41:9e:b5:0f ]
<ESB_Hdr  preamble=0xaa address_length=5 address=a8:41:9e:b5:0f payload_length=22 pid=2 no_ack=0 padding=0 valid_crc=yes crc=0xd893 |<Logitech_Unifying_Hdr  dev_index=0x0 frame_type=0xd3 checksum=0xb1 |<Logitech_Encrypted_Keystroke_Payload  hid_data='' unknown=201 aes_counter=3087930537 unused='' |>>>
[...]

Extract complex data from packet streams

Various complex data can be extracted from packet stream, using various available analyzers.

Extracting Bluetooth Low Energy GATT profile

If a discovery procedure has been captured, it’s possible to use “profile_discovery” to recover the GATT profile.

For example, the following PCAP contain such a discovery procedure:

$ wget https://github.com/whad-team/whad-client/raw/main/ressources/pcaps/ble_pairing.pcap

You can extract the discovered profile using:

$ wplay --flush ble_pairing.pcap | wanalyze profile_discovery
[✓] profile_discovery → completed
  - profile:  Service 1800 (handles from 1 to 11):
  Characteristic 2A00 (handle:2, value handle: 3, props: R)
  Characteristic 2A01 (handle:4, value handle: 5, props: R)
  Characteristic 2A02 (handle:6, value handle: 7, props: R)
  Characteristic 2A03 (handle:8, value handle: 9, props: W)
  Characteristic 2A04 (handle:10, value handle: 11, props: R)
Service 1801 (handles from 12 to 15):
  Characteristic 2A05 (handle:13, value handle: 14, props: I)
    Descriptor 2902 (handle: 15)
Service 180A (handles from 16 to 30):
  Characteristic 2A23 (handle:17, value handle: 18, props: R)
  Characteristic 2A24 (handle:19, value handle: 20, props: R)
  Characteristic 2A25 (handle:21, value handle: 22, props: R)
  Characteristic 2A26 (handle:23, value handle: 24, props: R)
  Characteristic 2A27 (handle:25, value handle: 26, props: R)
  Characteristic 2A28 (handle:27, value handle: 28, props: R)
  Characteristic 2A29 (handle:29, value handle: 30, props: R)
Service a8b3fff0-4834-4051-89d0-3de95cddd318 (handles from 31 to 47):
  Characteristic a8b3fff1-4834-4051-89d0-3de95cddd318 (handle:32, value handle: 33, props: RW)
    Descriptor 2901 (handle: 34)
  Characteristic a8b3fff2-4834-4051-89d0-3de95cddd318 (handle:35, value handle: 36, props: R)
    Descriptor 2901 (handle: 37)
  Characteristic a8b3fff3-4834-4051-89d0-3de95cddd318 (handle:38, value handle: 39, props: W)
    Descriptor 2901 (handle: 40)
  Characteristic a8b3fff4-4834-4051-89d0-3de95cddd318 (handle:41, value handle: 42, props: N)
    Descriptor 2902 (handle: 43)
    Descriptor 2901 (handle: 44)
  Characteristic a8b3fff5-4834-4051-89d0-3de95cddd318 (handle:45, value handle: 46, props: R)
    Descriptor 2901 (handle: 47)
Service a8b3ffe0-4834-4051-89d0-3de95cddd318 (handles from 48 to 57):
  Characteristic a8b3ffe1-4834-4051-89d0-3de95cddd318 (handle:49, value handle: 50, props: R)
    Descriptor 2901 (handle: 51)
  Characteristic a8b3ffe2-4834-4051-89d0-3de95cddd318 (handle:52, value handle: 53, props: RW)
    Descriptor 2901 (handle: 54)
  Characteristic a8b3ffe3-4834-4051-89d0-3de95cddd318 (handle:55, value handle: 56, props: W)
    Descriptor 2901 (handle: 57)
Service f000ffc0-0451-4000-b000-000000000000 (handles from 58 to 65535):
  Characteristic f000ffc1-0451-4000-b000-000000000000 (handle:59, value handle: 60, props: WN)
    Descriptor 2902 (handle: 61)
    Descriptor 2901 (handle: 62)
  Characteristic f000ffc2-0451-4000-b000-000000000000 (handle:63, value handle: 64, props: WN)
    Descriptor 2902 (handle: 65)
    Descriptor 2901 (handle: 66)

If you want to use the profile in another tool, for example wble-periph, you can easily format the output using the --json option:

$ wplay --flush ble_pairing.pcap | wanalyze profile_discovery.profile --json
{"services": [{"uuid": "1800", "type_uuid": "2800", "start_handle": 1, "end_handle": 11, "characteristics": [{"handle": 2, "uuid": "2803", "properties": 2, "security": 0, "value": {"handle": 3, "uuid": "2A00"}, "descriptors": []}, {"handle": 4, "uuid": "2803", "properties": 2, "security": 0, "value": {"handle": 5, "uuid": "2A01"}, "descriptors": []}, {"handle": 6, "uuid": "2803", "properties": 2, "security": 0, "value": {"handle": 7, "uuid": "2A02"}, "descriptors": []}, {"handle": 8, "uuid": "2803", "properties": 8, "security": 0, "value": {"handle": 9, "uuid": "2A03"}, "descriptors": []}, {"handle": 10, "uuid": "2803", "properties": 2, "security": 0, "value": {"handle": 11, "uuid": "2A04"}, "descriptors": []}]}, {"uuid": "1801", "type_uuid": "2800", "start_handle": 12, "end_handle": 15, "characteristics": [{"handle": 13, "uuid": "2803", "properties": 32, "security": 0, "value": {"handle": 14, "uuid": "2A05"}, "descriptors": [{"handle": 15, "uuid": "2902"}]}]}, {"uuid": "180A", "type_uuid": "2800", "start_handle": 16, "end_handle": 30, "characteristics": [{"handle": 17, "uuid": "2803", "properties": 2, "security": 0, "value": {"handle": 18, "uuid": "2A23"}, "descriptors": []}, {"handle": 19, "uuid": "2803", "properties": 2, "security": 0, "value": {"handle": 20, "uuid": "2A24"}, "descriptors": []}, {"handle": 21, "uuid": "2803", "properties": 2, "security": 0, "value": {"handle": 22, "uuid": "2A25"}, "descriptors": []}, {"handle": 23, "uuid": "2803", "properties": 2, "security": 0, "value": {"handle": 24, "uuid": "2A26"}, "descriptors": []}, {"handle": 25, "uuid": "2803", "properties": 2, "security": 0, "value": {"handle": 26, "uuid": "2A27"}, "descriptors": []}, {"handle": 27, "uuid": "2803", "properties": 2, "security": 0, "value": {"handle": 28, "uuid": "2A28"}, "descriptors": []}, {"handle": 29, "uuid": "2803", "properties": 2, "security": 0, "value": {"handle": 30, "uuid": "2A29"}, "descriptors": []}]}, {"uuid": "a8b3fff0-4834-4051-89d0-3de95cddd318", "type_uuid": "2800", "start_handle": 31, "end_handle": 47, "characteristics": [{"handle": 32, "uuid": "2803", "properties": 10, "security": 0, "value": {"handle": 33, "uuid": "a8b3fff1-4834-4051-89d0-3de95cddd318"}, "descriptors": [{"handle": 34, "uuid": "2901"}]}, {"handle": 35, "uuid": "2803", "properties": 2, "security": 0, "value": {"handle": 36, "uuid": "a8b3fff2-4834-4051-89d0-3de95cddd318"}, "descriptors": [{"handle": 37, "uuid": "2901"}]}, {"handle": 38, "uuid": "2803", "properties": 8, "security": 0, "value": {"handle": 39, "uuid": "a8b3fff3-4834-4051-89d0-3de95cddd318"}, "descriptors": [{"handle": 40, "uuid": "2901"}]}, {"handle": 41, "uuid": "2803", "properties": 16, "security": 0, "value": {"handle": 42, "uuid": "a8b3fff4-4834-4051-89d0-3de95cddd318"}, "descriptors": [{"handle": 43, "uuid": "2902"}, {"handle": 44, "uuid": "2901"}]}, {"handle": 45, "uuid": "2803", "properties": 2, "security": 0, "value": {"handle": 46, "uuid": "a8b3fff5-4834-4051-89d0-3de95cddd318"}, "descriptors": [{"handle": 47, "uuid": "2901"}]}]}, {"uuid": "a8b3ffe0-4834-4051-89d0-3de95cddd318", "type_uuid": "2800", "start_handle": 48, "end_handle": 57, "characteristics": [{"handle": 49, "uuid": "2803", "properties": 2, "security": 0, "value": {"handle": 50, "uuid": "a8b3ffe1-4834-4051-89d0-3de95cddd318"}, "descriptors": [{"handle": 51, "uuid": "2901"}]}, {"handle": 52, "uuid": "2803", "properties": 10, "security": 0, "value": {"handle": 53, "uuid": "a8b3ffe2-4834-4051-89d0-3de95cddd318"}, "descriptors": [{"handle": 54, "uuid": "2901"}]}, {"handle": 55, "uuid": "2803", "properties": 8, "security": 0, "value": {"handle": 56, "uuid": "a8b3ffe3-4834-4051-89d0-3de95cddd318"}, "descriptors": [{"handle": 57, "uuid": "2901"}]}]}, {"uuid": "f000ffc0-0451-4000-b000-000000000000", "type_uuid": "2800", "start_handle": 58, "end_handle": 65535, "characteristics": [{"handle": 59, "uuid": "2803", "properties": 28, "security": 0, "value": {"handle": 60, "uuid": "f000ffc1-0451-4000-b000-000000000000"}, "descriptors": [{"handle": 61, "uuid": "2902"}, {"handle": 62, "uuid": "2901"}]}, {"handle": 63, "uuid": "2803", "properties": 28, "security": 0, "value": {"handle": 64, "uuid": "f000ffc2-0451-4000-b000-000000000000"}, "descriptors": [{"handle": 65, "uuid": "2902"}, {"handle": 66, "uuid": "2901"}]}]}]}

It can easily be redirected to a file using a basic bash redirection:

$ wplay --flush ble_pairing.pcap | wanalyze profile_discovery.profile --json > profile.json

Extracting RF4CE keystrokes

RF4CE is commonly used by Remote Controllers (RC), and it’s possible to implement a basic keylogger to retrieve pressed buttons.

For example, the following PCAP file contains such keystrokes:

$ wget https://github.com/whad-team/whad-client/raw/main/ressources/pcaps/rf4ce_pairing_keystrokes_audio.pcap

Let’s decrypt the traffic using the corresponding encryption key:

$ wplay --flush rf4ce_pairing_keystrokes_audio.pcap -d -k 48ca7e9fdbc168b0297dd97d4f7f85a8

Then, the “keystroke” analyzer can be used to infer the keystrokes:

$ wplay --flush rf4ce_pairing_keystrokes_audio.pcap -d -k 48ca7e9fdbc168b0297dd97d4f7f85a8 | wanalyze keystroke
[✓] keystroke → completed
  - key:  7

[✓] keystroke → completed
  - key:  0

[✓] keystroke → completed
  - key:  6

[✓] keystroke → completed
  - key:  1

[✓] keystroke → completed
  - key:  2

[✓] keystroke → completed
  - key:  3

[✓] keystroke → completed
  - key:  4

[✓] keystroke → completed
  - key:  5

[✓] keystroke → completed
  - key:  6

You can display the keystroke without the analyzers information by selecting the key field:

$ wplay --flush rf4ce_pairing_keystrokes_audio.pcap -d -k 48ca7e9fdbc168b0297dd97d4f7f85a8 | wanalyze keystroke.key
7
0
6
1
2
3
4
5
6

Extracting RF4CE audio stream

Some RF4CE Remote Controllers (RC) support audio commands. Such audio streams can be extracted using “audio” analyzers.

The following PCAP file contains such audio stream:

$ wget https://github.com/whad-team/whad-client/raw/main/ressources/pcaps/rf4ce_pairing_keystrokes_audio.pcap

Let’s decrypt the traffic using the corresponding encryption key:

$ wplay --flush rf4ce_pairing_keystrokes_audio.pcap -d -k 48ca7e9fdbc168b0297dd97d4f7f85a8

Finally, we can extract the audio stream by using the “audio” analyzer:

$ wplay --flush rf4ce_pairing_keystrokes_audio.pcap -d -k 48ca7e9fdbc168b0297dd97d4f7f85a8 | wanalyze audio
[✓] audio → completed
  - raw_audio:  52494646e402010057415645666d74201000000001000100803e0000007d00000200100064617461c002010000 [...]

The displayed bytes corresponds to a WAV file. It can be easily dumped by :

  • selecting “raw_audio” field (wanalyze audio.raw_audio)

  • dumping raw bytes to stdout buffer (--raw / -r)

Let’s play it:

$ wplay --flush rf4ce_pairing_keystrokes_audio.pcap -d -k 48ca7e9fdbc168b0297dd97d4f7f85a8 | wanalyze audio.raw_audio --raw | play -

Or export it to a WAV file:

$ wplay --flush rf4ce_pairing_keystrokes_audio.pcap -d -k 48ca7e9fdbc168b0297dd97d4f7f85a8 | wanalyze audio.raw_audio --raw > stream.wav

Extracting Logitech Unifying mouse movements and clicks

wanalyze can be used to extract mouse actions (movements & clicks) from Logitech Unifying mouse traffic.

For example, let’s download a PCAP file corresponding to a capture of a Logitech mouse:

$ wget https://github.com/whad-team/whad-client/raw/main/ressources/pcaps/logitech_mouse.pcap

If you use wanalyze on the corresponding packet stream, the “mouse” analyzer will be automatically triggered:

$ wplay --flush logitech_mouse.pcap | wanalyze
[✓] mouse → completed
  - x:  0
  - y:  -1
  - wheel_x:  0
  - wheel_y:  0
  - button:

[✓] mouse → completed
  - x:  0
  - y:  -2
  - wheel_x:  0
  - wheel_y:  0
  - button:

[✓] mouse → completed
  - x:  1
  - y:  -3
  - wheel_x:  0
  - wheel_y:  0
  - button:

[✓] mouse → completed
  - x:  0
  - y:  -2
  - wheel_x:  0
  - wheel_y:  0
  - button:
[...]

Let’s format the output to be used with wuni-mouse tool:

$ wplay --flush logitech_mouse.pcap | wanalyze mouse.x mouse.y mouse.wheel_x mouse.wheel_y mouse.button -d ","
0,-1,0,0,
0,-2,0,0,
1,-3,0,0,
0,-2,0,0,
0,-2,0,0,
1,-2,0,0,
0,-2,0,0,
1,-2,0,0,
0,-2,0,0,
1,-2,0,0,
0,-2,0,0,
0,-2,0,0,
1,-2,0,0,
0,-2,0,0,
0,-2,0,0,
1,-2,0,0,
0,-1,0,0,
0,-2,0,0,
0,-2,0,0,
[...]

Redirect it to a file:

$ wplay --flush logitech_mouse.pcap | wanalyze mouse.x mouse.y mouse.wheel_x mouse.wheel_y mouse.button -d "," > capture.mouse

You can then easily use it with wuni-mouse tool to replay mouse traffic over the air:

$ cat capture.mouse | wuni-mouse -i uart0 -a ca:e9:06:ec:a4
Mouse found and locked, sending moves received on stdin...

Extracting Logitech Unifying keyboard keystrokes

It’s also quite easy to implement a wireless keylogger targeting Logitech Unifying keyboard using wanalyze.

As an example, let’s download some traffic from a Logitech Unifying keyboard:

$ wget https://github.com/whad-team/whad-client/raw/main/ressources/pcaps/logitech_encrypted_traffic.pcap

You can then use wplay with -d option (decrypt) and provide the key using -k (keys):

$ wplay --flush logitech_encrypted_traffic.pcap -d -k 02bea8b5ef61037e87882e4daebf403b
[...]
[ raw=True, decrypted=True, timestamp=50231, channel=0, is_crc_valid=True, address=a8:41:9e:b5:0f ]
<ESB_Hdr  preamble=0xaa address_length=5 address=a8:41:9e:b5:0f payload_length=22 pid=2 no_ack=0 padding=0 valid_crc=yes crc=0xe235 |<Logitech_Unifying_Hdr  dev_index=0x0 frame_type=0xd3 checksum=0x81 |<Logitech_Encrypted_Keystroke_Payload  hid_data='\x00\x0b' unknown=201 aes_counter=3087930536 unused='' |>>>
[...]
[ raw=True, decrypted=True, timestamp=56916, channel=0, is_crc_valid=True, address=a8:41:9e:b5:0f ]
<ESB_Hdr  preamble=0xaa address_length=5 address=a8:41:9e:b5:0f payload_length=22 pid=2 no_ack=0 padding=0 valid_crc=yes crc=0xd893 |<Logitech_Unifying_Hdr  dev_index=0x0 frame_type=0xd3 checksum=0xb1 |<Logitech_Encrypted_Keystroke_Payload  hid_data='' unknown=201 aes_counter=3087930537 unused='' |>>>
[...]

Extracting the keystrokes is as simple as combining wplay with wanalyze:

$ wplay --flush logitech_encrypted_traffic.pcap -d -k 02bea8b5ef61037e87882e4daebf403b | wanalyze
[✓] keystroke → completed
  - key:  a

[✓] keystroke → completed
  - key:  b

[✓] keystroke → completed
  - key:  c

[✓] keystroke → completed
  - key:  d

[✓] keystroke → completed
  - key:  e
[...]

Output can be formatted easily, by selecting the key field of the “keystroke” analyzer:

$ wplay --flush logitech_encrypted_traffic.pcap -d -k 02bea8b5ef61037e87882e4daebf403b | wanalyze keystroke.key
a
b
c
d
e
f
g
h

Similarly to mouse traffic, you can extract this output in a file:

$ wplay --flush logitech_encrypted_traffic.pcap -d -k 02bea8b5ef61037e87882e4daebf403b | wanalyze keystroke.key > capture.keyboard

And replay it using wuni-keyboard as unencrypted traffic:

$ cat capture.keyboard | wuni-keyboard -i uart0 -a ca:e9:06:ec:a4 -l fr
a
b
c
d
e
f
g
h

Or as encrypted traffic by providing the key:

$ cat capture.keyboard | wuni-keyboard -i uart0 -a ca:e9:06:ec:a4 -l fr -k 02bea8b5ef61037e87882e4daebf403b
a
b
c
d
e
f
g
h