2020-09-18 11:12:05

by Alex Lu

[permalink] [raw]
Subject: [PATCH] Bluetooth: Fix the vulnerable issue on enc key size

When someone attacks the service provider, it creates connection,
authenticates. Then it requests key size of one byte and it identifies
the key with brute force methods.

After l2cap info req/resp exchange is complete. the attacker sends l2cap
connect with specific PSM.

In above procedure, there is no chance for the service provider to check
the encryption key size before l2cap_connect(). Because the state of
l2cap chan in conn->chan_l is BT_LISTEN, there is no l2cap chan with the
state of BT_CONNECT or BT_CONNECT2.

So service provider should check the encryption key size in
l2cap_connect()

Signed-off-by: Alex Lu <[email protected]>
---
net/bluetooth/l2cap_core.c | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index ade83e224567..63df961d402d 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -4150,6 +4150,13 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn,

if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
if (l2cap_chan_check_security(chan, false)) {
+ if (!l2cap_check_enc_key_size(conn->hcon)) {
+ l2cap_state_change(chan, BT_DISCONN);
+ __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
+ result = L2CAP_CR_SEC_BLOCK;
+ status = L2CAP_CS_NO_INFO;
+ goto response;
+ }
if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) {
l2cap_state_change(chan, BT_CONNECT2);
result = L2CAP_CR_PEND;
--
2.21.0


2020-09-20 06:18:15

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH] Bluetooth: Fix the vulnerable issue on enc key size

Hi Alex,

> When someone attacks the service provider, it creates connection,
> authenticates. Then it requests key size of one byte and it identifies
> the key with brute force methods.
>
> After l2cap info req/resp exchange is complete. the attacker sends l2cap
> connect with specific PSM.
>
> In above procedure, there is no chance for the service provider to check
> the encryption key size before l2cap_connect(). Because the state of
> l2cap chan in conn->chan_l is BT_LISTEN, there is no l2cap chan with the
> state of BT_CONNECT or BT_CONNECT2.
>
> So service provider should check the encryption key size in
> l2cap_connect()
>
> Signed-off-by: Alex Lu <[email protected]>
> ---
> net/bluetooth/l2cap_core.c | 7 +++++++
> 1 file changed, 7 insertions(+)
>
> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> index ade83e224567..63df961d402d 100644
> --- a/net/bluetooth/l2cap_core.c
> +++ b/net/bluetooth/l2cap_core.c
> @@ -4150,6 +4150,13 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn,
>
> if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
> if (l2cap_chan_check_security(chan, false)) {
> + if (!l2cap_check_enc_key_size(conn->hcon)) {
> + l2cap_state_change(chan, BT_DISCONN);
> + __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
> + result = L2CAP_CR_SEC_BLOCK;
> + status = L2CAP_CS_NO_INFO;
> + goto response;
> + }
> if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) {
> l2cap_state_change(chan, BT_CONNECT2);
> result = L2CAP_CR_PEND;

I am not following what you are trying to fix here. Can you show this with a btmon trace from an attacking device?

Regards

Marcel

2020-09-21 06:09:08

by Alex Lu

[permalink] [raw]
Subject: Re: [PATCH] Bluetooth: Fix the vulnerable issue on enc key size

Hi Marcel,

> On September 20, 2020 14:10, Marcel Holtmann wrote:
>
> Hi Alex,
>
> > When someone attacks the service provider, it creates connection,
> > authenticates. Then it requests key size of one byte and it identifies
> > the key with brute force methods.
> >
> > After l2cap info req/resp exchange is complete. the attacker sends l2cap
> > connect with specific PSM.
> >
> > In above procedure, there is no chance for the service provider to check
> > the encryption key size before l2cap_connect(). Because the state of
> > l2cap chan in conn->chan_l is BT_LISTEN, there is no l2cap chan with the
> > state of BT_CONNECT or BT_CONNECT2.
> >
> > So service provider should check the encryption key size in
> > l2cap_connect()
> >
> > Signed-off-by: Alex Lu <[email protected]>
> > ---
> > net/bluetooth/l2cap_core.c | 7 +++++++
> > 1 file changed, 7 insertions(+)
> >
> > diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> > index ade83e224567..63df961d402d 100644
> > --- a/net/bluetooth/l2cap_core.c
> > +++ b/net/bluetooth/l2cap_core.c
> > @@ -4150,6 +4150,13 @@ static struct l2cap_chan *l2cap_connect(struct
> l2cap_conn *conn,
> >
> > if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
> > if (l2cap_chan_check_security(chan, false)) {
> > + if (!l2cap_check_enc_key_size(conn->hcon)) {
> > + l2cap_state_change(chan, BT_DISCONN);
> > + __set_chan_timer(chan,
> L2CAP_DISC_TIMEOUT);
> > + result = L2CAP_CR_SEC_BLOCK;
> > + status = L2CAP_CS_NO_INFO;
> > + goto response;
> > + }
> > if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) {
> > l2cap_state_change(chan, BT_CONNECT2);
> > result = L2CAP_CR_PEND;
>
> I am not following what you are trying to fix here. Can you show this with a
> btmon trace from an attacking device?
>
> Regards
>
> Marcel
>
>

I'm sorry, I didn't have btmon trace from an attacking device.
I didn't have the real attacking device. I just simulate the attacking.
I have a device that can create one byte size encryption key.
It uses the link key that was produced by pairing with the service provider. Actually the KNOB (Key Negotiation of Bluetooth Attack) says, the link key is unnecessary for the reconnection.
I use this device to reconnect to service provider, and then initiate the Key Negotiation for one byte size encryption key. Actually the attacker identified the encryption key with some brute force methods.

I want to provide the trace on service provider side.

> HCI Event: Connect Request (0x04) plen 10 #1 [hci0] 42.932585
Address: 00:3F:22:EE:11:33 (OUI 00-3F-22)
Class: 0x00010c
Major class: Computer (desktop, notebook, PDA, organizers)
Minor class: Laptop
Link type: ACL (0x01)
< HCI Command: Accept Connection Request (0x01|0x0009) plen 7 #2 [hci0] 42.932795
Address: 00:3F:22:EE:11:33 (OUI 00-3F-22)
Role: Slave (0x01)
> HCI Event: Command Status (0x0f) plen 4 #3 [hci0] 42.934509
Accept Connection Request (0x01|0x0009) ncmd 2
Status: Success (0x00)
> HCI Event: Connect Complete (0x03) plen 11 #4 [hci0] 42.964568
Status: Success (0x00)
Handle: 1
Address: 00:3F:22:EE:11:33 (OUI 00-3F-22)
Link type: ACL (0x01)
Encryption: Disabled (0x00)
< HCI Command: Read Remote Supported Features (0x01|0x001b) plen 2 #5 [hci0] 42.964815
Handle: 1
> HCI Event: Max Slots Change (0x1b) plen 3 #6 [hci0] 42.970516
Handle: 1
Max slots: 5
> HCI Event: Command Status (0x0f) plen 4 #7 [hci0] 42.971592
Read Remote Supported Features (0x01|0x001b) ncmd 2
Status: Success (0x00)
> HCI Event: Max Slots Change (0x1b) plen 3 #8 [hci0] 42.976516
Handle: 1
Max slots: 5
> HCI Event: Read Remote Supported Features (0x0b) plen 11 #9 [hci0] 42.980521
Status: Success (0x00)
Handle: 1
Features: 0xff 0xff 0xff 0xfe 0xdb 0xfd 0x7b 0x87
3 slot packets
5 slot packets
Encryption
Slot offset
Timing accuracy
Role switch
Hold mode
Sniff mode
Park state
Power control requests
Channel quality driven data rate (CQDDR)
SCO link
HV2 packets
HV3 packets
u-law log synchronous data
A-law log synchronous data
CVSD synchronous data
Paging parameter negotiation
Power control
Transparent synchronous data
Flow control lag (least significant bit)
Flow control lag (middle bit)
Flow control lag (most significant bit)
Broadcast Encryption
Enhanced Data Rate ACL 2 Mbps mode
Enhanced Data Rate ACL 3 Mbps mode
Enhanced inquiry scan
Interlaced inquiry scan
Interlaced page scan
RSSI with inquiry results
Extended SCO link (EV3 packets)
EV4 packets
EV5 packets
AFH capable slave
AFH classification slave
LE Supported (Controller)
3-slot Enhanced Data Rate ACL packets
5-slot Enhanced Data Rate ACL packets
Pause encryption
AFH capable master
AFH classification master
Enhanced Data Rate eSCO 2 Mbps mode
Enhanced Data Rate eSCO 3 Mbps mode
3-slot Enhanced Data Rate eSCO packets
Extended Inquiry Response
Simultaneous LE and BR/EDR (Controller)
Secure Simple Pairing
Encapsulated PDU
Erroneous Data Reporting
Non-flushable Packet Boundary Flag
Link Supervision Timeout Changed Event
Inquiry TX Power Level
Enhanced Power Control
Extended features
< HCI Command: Read Remote Extended Features (0x01|0x001c) plen 3 #10 [hci0] 42.980677
Handle: 1
Page: 1
> HCI Event: Command Status (0x0f) plen 4 #11 [hci0] 42.982510
Read Remote Extended Features (0x01|0x001c) ncmd 2
Status: Success (0x00)
> HCI Event: Read Remote Extended Features (0x23) plen 13 #12 [hci0] 42.989523
Status: Success (0x00)
Handle: 1
Page: 1/2
Features: 0x03 0x00 0x00 0x00 0x00 0x00 0x00 0x00
Secure Simple Pairing (Host Support)
LE Supported (Host)
< HCI Command: Remote Name Request (0x01|0x0019) plen 10 #13 [hci0] 42.989697
Address: 00:3F:22:EE:11:33 (OUI 00-3F-22)
Page scan repetition mode: R2 (0x02)
Page scan mode: Mandatory (0x00)
Clock offset: 0x0000
< ACL Data TX: Handle 1 flags 0x00 dlen 10 #14 [hci0] 42.989720
L2CAP: Information Request (0x0a) ident 1 len 2
Type: Extended features supported (0x0002)
> HCI Event: Command Status (0x0f) plen 4 #15 [hci0] 42.991510
Remote Name Request (0x01|0x0019) ncmd 2
Status: Success (0x00)
> HCI Event: Number of Completed Packets (0x13) plen 5 #16 [hci0] 42.992498
Num handles: 1
Handle: 1
Count: 1
> HCI Event: Remote Name Req Complete (0x07) plen 255 #17 [hci0] 43.011514
Status: Success (0x00)
Address: 00:3F:22:EE:11:33 (OUI 00-3F-22)
Name: dell
@ MGMT Event: Device Connected (0x000b) plen 24 {0x0002} [hci0] 43.011578
BR/EDR Address: 00:3F:22:EE:11:33 (OUI 00-3F-22)
Flags: 0x00000000
Data length: 11
Name (complete): dell
Class: 0x00010c
Major class: Computer (desktop, notebook, PDA, organizers)
Minor class: Laptop
@ MGMT Event: Device Connected (0x000b) plen 24 {0x0001} [hci0] 43.011578
BR/EDR Address: 00:3F:22:EE:11:33 (OUI 00-3F-22)
Flags: 0x00000000
Data length: 11
Name (complete): dell
Class: 0x00010c
Major class: Computer (desktop, notebook, PDA, organizers)
Minor class: Laptop
> HCI Event: Link Key Request (0x17) plen 6 #18 [hci0] 43.021510
Address: 00:3F:22:EE:11:33 (OUI 00-3F-22)
< HCI Command: Link Key Request Reply (0x01|0x000b) plen 22 #19 [hci0] 43.021580
Address: 00:3F:22:EE:11:33 (OUI 00-3F-22)
Link key: 8edcbbcfbfd9be102bac0004cc887c88
> HCI Event: Command Complete (0x0e) plen 10 #20 [hci0] 43.027544
Link Key Request Reply (0x01|0x000b) ncmd 2
Status: Success (0x00)
Address: 00:3F:22:EE:11:33 (OUI 00-3F-22)
> HCI Event: Encryption Change (0x08) plen 4 #21 [hci0] 43.089692
Status: Success (0x00)
Handle: 1
Encryption: Enabled with E0 (0x01)
< HCI Command: Read Encryption Key Size (0x05|0x0008) plen 2 #22 [hci0] 43.089859
Handle: 1
> HCI Event: Command Complete (0x0e) plen 7 #23 [hci0] 43.091528
Read Encryption Key Size (0x05|0x0008) ncmd 2
Status: Success (0x00)
Handle: 1
Key size: 1
> ACL Data RX: Handle 1 flags 0x02 dlen 10 #24 [hci0] 43.140888
L2CAP: Information Request (0x0a) ident 1 len 2
Type: Extended features supported (0x0002)
< ACL Data TX: Handle 1 flags 0x00 dlen 16 #25 [hci0] 43.140951
L2CAP: Information Response (0x0b) ident 1 len 8
Type: Extended features supported (0x0002)
Result: Success (0x0000)
Features: 0x000002b8
Enhanced Retransmission Mode
Streaming Mode
FCS Option
Fixed Channels
Unicast Connectionless Data Reception
> ACL Data RX: Handle 1 flags 0x02 dlen 16 #26 [hci0] 43.142308
L2CAP: Information Response (0x0b) ident 1 len 8
Type: Extended features supported (0x0002)
Result: Success (0x0000)
Features: 0x000002b8
Enhanced Retransmission Mode
Streaming Mode
FCS Option
Fixed Channels
Unicast Connectionless Data Reception
< ACL Data TX: Handle 1 flags 0x00 dlen 10 #27 [hci0] 43.142369
L2CAP: Information Request (0x0a) ident 2 len 2
Type: Fixed channels supported (0x0003)
> HCI Event: Number of Completed Packets (0x13) plen 5 #28 [hci0] 43.143567
Num handles: 1
Handle: 1
Count: 1
> ACL Data RX: Handle 1 flags 0x02 dlen 10 #29 [hci0] 43.145034
L2CAP: Information Request (0x0a) ident 2 len 2
Type: Fixed channels supported (0x0003)
< ACL Data TX: Handle 1 flags 0x00 dlen 20 #30 [hci0] 43.145093
L2CAP: Information Response (0x0b) ident 2 len 12
Type: Fixed channels supported (0x0003)
Result: Success (0x0000)
Channels: 0x0000000000000006
L2CAP Signaling (BR/EDR)
Connectionless reception
> HCI Event: Number of Completed Packets (0x13) plen 5 #31 [hci0] 43.145523
Num handles: 1
Handle: 1
Count: 1
> ACL Data RX: Handle 1 flags 0x02 dlen 20 #32 [hci0] 43.145922
L2CAP: Information Response (0x0b) ident 2 len 12
Type: Fixed channels supported (0x0003)
Result: Success (0x0000)
Channels: 0x0000000000000006
L2CAP Signaling (BR/EDR)
Connectionless reception
> HCI Event: Number of Completed Packets (0x13) plen 5 #33 [hci0] 43.147548
Num handles: 1
Handle: 1
Count: 1
> ACL Data RX: Handle 1 flags 0x02 dlen 12 #34 [hci0] 43.148405
L2CAP: Connection Request (0x02) ident 3 len 4
PSM: 3 (0x0003)
Source CID: 64
< ACL Data TX: Handle 1 flags 0x00 dlen 16 #35 [hci0] 43.148594
L2CAP: Connection Response (0x03) ident 3 len 8
Destination CID: 64
Source CID: 64
Result: Connection successful (0x0000)
Status: No further information available (0x0000)
< ACL Data TX: Handle 1 flags 0x00 dlen 23 #36 [hci0] 43.148622
L2CAP: Configure Request (0x04) ident 3 len 15
Destination CID: 64
Flags: 0x0000
Option: Retransmission and Flow Control (0x04) [mandatory]
Mode: Basic (0x00)
TX window size: 0
Max transmit: 0
Retransmission timeout: 0
Monitor timeout: 0
Maximum PDU size: 0
< HCI Command: Vendor (0x3f|0x0019) plen 5 #37 [hci0] 43.148741
01 01 00 08 00 .....
> HCI Event: Command Complete (0x0e) plen 4 #38 [hci0] 43.150506
Vendor (0x3f|0x0019) ncmd 2
Status: Success (0x00)
> HCI Event: Number of Completed Packets (0x13) plen 5 #39 [hci0] 43.151502
Num handles: 1
Handle: 1
Count: 1
> ACL Data RX: Handle 1 flags 0x02 dlen 23 #40 [hci0] 43.152429
L2CAP: Configure Request (0x04) ident 4 len 15
Destination CID: 64
Flags: 0x0000
Option: Retransmission and Flow Control (0x04) [mandatory]
Mode: Basic (0x00)
TX window size: 0
Max transmit: 0
Retransmission timeout: 0
Monitor timeout: 0
Maximum PDU size: 0
> HCI Event: Number of Completed Packets (0x13) plen 5 #41 [hci0] 43.152494
Num handles: 1
Handle: 1
Count: 1
< ACL Data TX: Handle 1 flags 0x00 dlen 18 #42 [hci0] 43.152508
L2CAP: Configure Response (0x05) ident 4 len 10
Source CID: 64
Flags: 0x0000
Result: Success (0x0000)
Option: Maximum Transmission Unit (0x01) [mandatory]
MTU: 672
> ACL Data RX: Handle 1 flags 0x02 dlen 18 #43 [hci0] 43.154567
L2CAP: Configure Response (0x05) ident 3 len 10
Source CID: 64
Flags: 0x0000
Result: Success (0x0000)
Option: Maximum Transmission Unit (0x01) [mandatory]
MTU: 672
> HCI Event: Number of Completed Packets (0x13) plen 5 #44 [hci0] 43.155496
Num handles: 1
Handle: 1
Count: 1

Thanks,
BRs,
Alex Lu.

2020-09-25 17:34:08

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH] Bluetooth: Fix the vulnerable issue on enc key size

Hi Alex,

>>> When someone attacks the service provider, it creates connection,
>>> authenticates. Then it requests key size of one byte and it identifies
>>> the key with brute force methods.
>>>
>>> After l2cap info req/resp exchange is complete. the attacker sends l2cap
>>> connect with specific PSM.
>>>
>>> In above procedure, there is no chance for the service provider to check
>>> the encryption key size before l2cap_connect(). Because the state of
>>> l2cap chan in conn->chan_l is BT_LISTEN, there is no l2cap chan with the
>>> state of BT_CONNECT or BT_CONNECT2.
>>>
>>> So service provider should check the encryption key size in
>>> l2cap_connect()
>>>
>>> Signed-off-by: Alex Lu <[email protected]>
>>> ---
>>> net/bluetooth/l2cap_core.c | 7 +++++++
>>> 1 file changed, 7 insertions(+)
>>>
>>> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
>>> index ade83e224567..63df961d402d 100644
>>> --- a/net/bluetooth/l2cap_core.c
>>> +++ b/net/bluetooth/l2cap_core.c
>>> @@ -4150,6 +4150,13 @@ static struct l2cap_chan *l2cap_connect(struct
>> l2cap_conn *conn,
>>>
>>> if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
>>> if (l2cap_chan_check_security(chan, false)) {
>>> + if (!l2cap_check_enc_key_size(conn->hcon)) {
>>> + l2cap_state_change(chan, BT_DISCONN);
>>> + __set_chan_timer(chan,
>> L2CAP_DISC_TIMEOUT);
>>> + result = L2CAP_CR_SEC_BLOCK;
>>> + status = L2CAP_CS_NO_INFO;
>>> + goto response;
>>> + }
>>> if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) {
>>> l2cap_state_change(chan, BT_CONNECT2);
>>> result = L2CAP_CR_PEND;
>>
>> I am not following what you are trying to fix here. Can you show this with a
>> btmon trace from an attacking device?
>>
>> Regards
>>
>> Marcel
>>
>>
>
> I'm sorry, I didn't have btmon trace from an attacking device.
> I didn't have the real attacking device. I just simulate the attacking.
> I have a device that can create one byte size encryption key.
> It uses the link key that was produced by pairing with the service provider. Actually the KNOB (Key Negotiation of Bluetooth Attack) says, the link key is unnecessary for the reconnection.
> I use this device to reconnect to service provider, and then initiate the Key Negotiation for one byte size encryption key. Actually the attacker identified the encryption key with some brute force methods.
>
> I want to provide the trace on service provider side.

what kernel version are you running? I wonder if we should always return L2CAP_CR_PEND here. Do you have a reproducer code?

The problem really is that the MASK_REQ_DONE indication is not enough to make a decision for the key size. We have to ensure that also the key size is actually available. If that is not yet done, then we should not check it. This means that any response to L2CAP_Connect_Request PDU needs to be delayed until the key size has been read.

Regards

Marcel

2020-09-27 05:48:37

by Alex Lu

[permalink] [raw]
Subject: Re: [PATCH] Bluetooth: Fix the vulnerable issue on enc key size

Hi Marcel,

> On 26 September 2020 at 1:34, Marcel Holtmann wrote:
>
> Hi Alex,
>
> >>> When someone attacks the service provider, it creates connection,
> >>> authenticates. Then it requests key size of one byte and it identifies
> >>> the key with brute force methods.
> >>>
> >>> After l2cap info req/resp exchange is complete. the attacker sends l2cap
> >>> connect with specific PSM.
> >>>
> >>> In above procedure, there is no chance for the service provider to check
> >>> the encryption key size before l2cap_connect(). Because the state of
> >>> l2cap chan in conn->chan_l is BT_LISTEN, there is no l2cap chan with the
> >>> state of BT_CONNECT or BT_CONNECT2.
> >>>
> >>> So service provider should check the encryption key size in
> >>> l2cap_connect()
> >>>
> >>> Signed-off-by: Alex Lu <[email protected]>
> >>> ---
> >>> net/bluetooth/l2cap_core.c | 7 +++++++
> >>> 1 file changed, 7 insertions(+)
> >>>
> >>> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> >>> index ade83e224567..63df961d402d 100644
> >>> --- a/net/bluetooth/l2cap_core.c
> >>> +++ b/net/bluetooth/l2cap_core.c
> >>> @@ -4150,6 +4150,13 @@ static struct l2cap_chan *l2cap_connect(struct
> >> l2cap_conn *conn,
> >>>
> >>> if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
> >>> if (l2cap_chan_check_security(chan, false)) {
> >>> + if (!l2cap_check_enc_key_size(conn->hcon)) {
> >>> + l2cap_state_change(chan, BT_DISCONN);
> >>> + __set_chan_timer(chan,
> >> L2CAP_DISC_TIMEOUT);
> >>> + result = L2CAP_CR_SEC_BLOCK;
> >>> + status = L2CAP_CS_NO_INFO;
> >>> + goto response;
> >>> + }
> >>> if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) {
> >>> l2cap_state_change(chan, BT_CONNECT2);
> >>> result = L2CAP_CR_PEND;
> >>
> >> I am not following what you are trying to fix here. Can you show this with
> a
> >> btmon trace from an attacking device?
> >>
> >> Regards
> >>
> >> Marcel
> >>
> >>
> >
> > I'm sorry, I didn't have btmon trace from an attacking device.
> > I didn't have the real attacking device. I just simulate the attacking.
> > I have a device that can create one byte size encryption key.
> > It uses the link key that was produced by pairing with the service provider.
> Actually the KNOB (Key Negotiation of Bluetooth Attack) says, the link key is
> unnecessary for the reconnection.
> > I use this device to reconnect to service provider, and then initiate the Key
> Negotiation for one byte size encryption key. Actually the attacker identified
> the encryption key with some brute force methods.
> >
> > I want to provide the trace on service provider side.
>
> what kernel version are you running? I wonder if we should always return
> L2CAP_CR_PEND here. Do you have a reproducer code?

I'm running kernel 5.8.0-rc6 on acceptor and kernel 5.8.5 on the initiator which acts as an attacker.
For the attack simulation, some code needs to be changed on each size.
On the acceptor, the master parameter for bt_io_listen() in bluetoothd should be changed to FALSE in profiles/audio/a2dp.c a2dp_server_listen() and profiles/audio/avctp.c avctp_server_socket().
The change makes the kernel not to change the role to master when it receives hci conn req event.
I did the change in order to make the controller to send LMP_ENCRYPTION_KEY_SIZE_REQ PDU for one byte key size.

On the initiator, the below encryption key size check should be removed.
@@ -1622,10 +1624,13 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
continue;
}

- if (l2cap_check_enc_key_size(conn->hcon))
- l2cap_start_connection(chan);
- else
- l2cap_chan_close(chan, ECONNREFUSED);
+ /* Just simulate KNOB */
+ l2cap_start_connection(chan);
+ /* if (l2cap_check_enc_key_size(conn->hcon))
+ * l2cap_start_connection(chan);
+ * else
+ * l2cap_chan_close(chan, ECONNREFUSED);
+ */

At last, I did the test as below:
1. On the initiator, pair acceptor
2. Run l2test -r -P 3 on the acceptor
3. Run l2test -n -P 3 <bdaddr> on the initiator

>
> The problem really is that the MASK_REQ_DONE indication is not enough to
> make a decision for the key size. We have to ensure that also the key size is
> actually available. If that is not yet done, then we should not check it. This
> means that any response to L2CAP_Connect_Request PDU needs to be
> delayed until the key size has been read.

In my test case, the key size has been read from controller before the l2cap conn request PDU is received.

< HCI Command: Read Encryption Key Size (0x05|0x0008) plen 2 #22 [hci0] 43.089859
Handle: 1
> HCI Event: Command Complete (0x0e) plen 7 #23 [hci0] 43.091528
Read Encryption Key Size (0x05|0x0008) ncmd 2
Status: Success (0x00)
Handle: 1
Key size: 1
> ACL Data RX: Handle 1 flags 0x02 dlen 10 #24 [hci0] 43.140888
L2CAP: Information Request (0x0a) ident 1 len 2
Type: Extended features supported (0x0002)
......
> ACL Data RX: Handle 1 flags 0x02 dlen 12 #34 [hci0] 43.148405
L2CAP: Connection Request (0x02) ident 3 len 4
PSM: 3 (0x0003)
Source CID: 64

>
> Regards
>
> Marcel
>
>

2020-09-27 12:05:38

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH] Bluetooth: Fix the vulnerable issue on enc key size

Hi Alex,

>>>>> When someone attacks the service provider, it creates connection,
>>>>> authenticates. Then it requests key size of one byte and it identifies
>>>>> the key with brute force methods.
>>>>>
>>>>> After l2cap info req/resp exchange is complete. the attacker sends l2cap
>>>>> connect with specific PSM.
>>>>>
>>>>> In above procedure, there is no chance for the service provider to check
>>>>> the encryption key size before l2cap_connect(). Because the state of
>>>>> l2cap chan in conn->chan_l is BT_LISTEN, there is no l2cap chan with the
>>>>> state of BT_CONNECT or BT_CONNECT2.
>>>>>
>>>>> So service provider should check the encryption key size in
>>>>> l2cap_connect()
>>>>>
>>>>> Signed-off-by: Alex Lu <[email protected]>
>>>>> ---
>>>>> net/bluetooth/l2cap_core.c | 7 +++++++
>>>>> 1 file changed, 7 insertions(+)
>>>>>
>>>>> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
>>>>> index ade83e224567..63df961d402d 100644
>>>>> --- a/net/bluetooth/l2cap_core.c
>>>>> +++ b/net/bluetooth/l2cap_core.c
>>>>> @@ -4150,6 +4150,13 @@ static struct l2cap_chan *l2cap_connect(struct
>>>> l2cap_conn *conn,
>>>>>
>>>>> if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
>>>>> if (l2cap_chan_check_security(chan, false)) {
>>>>> + if (!l2cap_check_enc_key_size(conn->hcon)) {
>>>>> + l2cap_state_change(chan, BT_DISCONN);
>>>>> + __set_chan_timer(chan,
>>>> L2CAP_DISC_TIMEOUT);
>>>>> + result = L2CAP_CR_SEC_BLOCK;
>>>>> + status = L2CAP_CS_NO_INFO;
>>>>> + goto response;
>>>>> + }
>>>>> if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) {
>>>>> l2cap_state_change(chan, BT_CONNECT2);
>>>>> result = L2CAP_CR_PEND;
>>>>
>>>> I am not following what you are trying to fix here. Can you show this with
>> a
>>>> btmon trace from an attacking device?
>>>>
>>>> Regards
>>>>
>>>> Marcel
>>>>
>>>>
>>>
>>> I'm sorry, I didn't have btmon trace from an attacking device.
>>> I didn't have the real attacking device. I just simulate the attacking.
>>> I have a device that can create one byte size encryption key.
>>> It uses the link key that was produced by pairing with the service provider.
>> Actually the KNOB (Key Negotiation of Bluetooth Attack) says, the link key is
>> unnecessary for the reconnection.
>>> I use this device to reconnect to service provider, and then initiate the Key
>> Negotiation for one byte size encryption key. Actually the attacker identified
>> the encryption key with some brute force methods.
>>>
>>> I want to provide the trace on service provider side.
>>
>> what kernel version are you running? I wonder if we should always return
>> L2CAP_CR_PEND here. Do you have a reproducer code?
>
> I'm running kernel 5.8.0-rc6 on acceptor and kernel 5.8.5 on the initiator which acts as an attacker.
> For the attack simulation, some code needs to be changed on each size.
> On the acceptor, the master parameter for bt_io_listen() in bluetoothd should be changed to FALSE in profiles/audio/a2dp.c a2dp_server_listen() and profiles/audio/avctp.c avctp_server_socket().
> The change makes the kernel not to change the role to master when it receives hci conn req event.
> I did the change in order to make the controller to send LMP_ENCRYPTION_KEY_SIZE_REQ PDU for one byte key size.
>
> On the initiator, the below encryption key size check should be removed.
> @@ -1622,10 +1624,13 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
> continue;
> }
>
> - if (l2cap_check_enc_key_size(conn->hcon))
> - l2cap_start_connection(chan);
> - else
> - l2cap_chan_close(chan, ECONNREFUSED);
> + /* Just simulate KNOB */
> + l2cap_start_connection(chan);
> + /* if (l2cap_check_enc_key_size(conn->hcon))
> + * l2cap_start_connection(chan);
> + * else
> + * l2cap_chan_close(chan, ECONNREFUSED);
> + */
>
> At last, I did the test as below:
> 1. On the initiator, pair acceptor
> 2. Run l2test -r -P 3 on the acceptor
> 3. Run l2test -n -P 3 <bdaddr> on the initiator
>
>>
>> The problem really is that the MASK_REQ_DONE indication is not enough to
>> make a decision for the key size. We have to ensure that also the key size is
>> actually available. If that is not yet done, then we should not check it. This
>> means that any response to L2CAP_Connect_Request PDU needs to be
>> delayed until the key size has been read.
>
> In my test case, the key size has been read from controller before the l2cap conn request PDU is received.
>
> < HCI Command: Read Encryption Key Size (0x05|0x0008) plen 2 #22 [hci0] 43.089859
> Handle: 1
>> HCI Event: Command Complete (0x0e) plen 7 #23 [hci0] 43.091528
> Read Encryption Key Size (0x05|0x0008) ncmd 2
> Status: Success (0x00)
> Handle: 1
> Key size: 1
>> ACL Data RX: Handle 1 flags 0x02 dlen 10 #24 [hci0] 43.140888
> L2CAP: Information Request (0x0a) ident 1 len 2
> Type: Extended features supported (0x0002)
> ......
>> ACL Data RX: Handle 1 flags 0x02 dlen 12 #34 [hci0] 43.148405
> L2CAP: Connection Request (0x02) ident 3 len 4
> PSM: 3 (0x0003)
> Source CID: 64

the easiest way to fake this is just to assign a different value than the one returned by Read Encryption Key Size on the acceptor side. No need to mess with LMP details.

diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 1df95145f574..741b7ad31ff8 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3034,7 +3034,7 @@ static void read_enc_key_size_complete(struct hci_dev *hdev, u8 status,
handle);
conn->enc_key_size = 0;
} else {
- conn->enc_key_size = rp->key_size;
+ conn->enc_key_size = 1;
}

If you add this change to both sides, what are the steps to reproduce this and what does btmon show? You might have to also enable dynamic_debug for l2cap.ko so that we see the function call trace.

I am a bit pedantic with this one, since it is critical to understand where the current changes to handle anything KNOB related have their shortcomings. I spent so much time testing every single corner case. Certainly I could have missed something, but if I really did, this time around I want to either simplify the code or properly comment it at least.

Please see the other email thread / patch from Archie trying to also add another encryption key size check.

Regards

Marcel