summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md4
-rw-r--r--changelog10
-rw-r--r--debian/changelog12
-rw-r--r--debian/control4
-rw-r--r--debian/gitlab-ci.yml9
-rw-r--r--debian/libubertooth1.symbols1
-rw-r--r--firmware/bluetooth_rxtx/bluetooth_rxtx.c122
-rw-r--r--firmware/bluetooth_rxtx/ubertooth_usb.c4
-rw-r--r--host/cmake/set_release.cmake2
-rw-r--r--host/libubertooth/src/ubertooth_control.c22
-rw-r--r--host/libubertooth/src/ubertooth_control.h1
-rw-r--r--host/libubertooth/src/ubertooth_interface.h6
-rwxr-xr-xhost/python/specan_ui/ubertooth-specan-ui130
-rw-r--r--host/ubertooth-tools/src/CMakeLists.txt2
-rw-r--r--host/ubertooth-tools/src/ubertooth-btle.c4
-rw-r--r--host/ubertooth-tools/src/ubertooth-ducky.c288
-rw-r--r--tools/RELEASENOTES47
17 files changed, 542 insertions, 126 deletions
diff --git a/README.md b/README.md
index 2c10dbd..9b7c9ac 100644
--- a/README.md
+++ b/README.md
@@ -6,10 +6,10 @@ suitable for Bluetooth experimentation. Ubertooth ships with a capable
BLE (Bluetooth Smart) sniffer and can sniff some data from Basic Rate
(BR) Bluetooth Classic connections.
-The latest release is [2018-08-R1](https://github.com/greatscottgadgets/ubertooth/releases/tag/2018-08-R1).
+The latest release is [2018-12-R1](https://github.com/greatscottgadgets/ubertooth/releases/tag/2018-12-R1).
The latest firmware build can be found on the release page.
-This release is paired with [libbtbb 2018-08-R1](https://github.com/greatscottgadgets/libbtbb/releases/tag/2018-08-R1).
+This release is paired with [libbtbb 2018-12-R1](https://github.com/greatscottgadgets/libbtbb/releases/tag/2018-12-R1).
Instructions for flashing the firmware can be found [on the corresponding Wiki page](https://github.com/greatscottgadgets/ubertooth/wiki/Firmware).
Instructions for building libbrbb can be found [on the corresponding Wiki page](https://github.com/greatscottgadgets/ubertooth/wiki/Build-Guide).
diff --git a/changelog b/changelog
index 1e02d2e..5550fe2 100644
--- a/changelog
+++ b/changelog
@@ -1,7 +1,15 @@
+ubertooth (2018-12-R1) unstable; urgency=low
+ * Trigger an Uberducky with ubertooth-ducky
+ * Bugfixes in ubertooth-btle slave mode
+ * Improvements to spectrum analyzer UI
+ * USB API version bumped to 1.06
+
+ -- Mike Ryan <mikeryan@lacklustre.net> 04 Dec 2018 21:50:00 -0800
+
ubertooth (2018-08-R1) unstable; urgency=low
* Support for partial channel map updates
* LE no-follow mode (advertising packets only)
- * USB API version bumped to 1.04
+ * USB API version bumped to 1.05
-- Mike Ryan <mikeryan@lacklustre.net> 07 Aug 2018 15:20:00 -0700
diff --git a/debian/changelog b/debian/changelog
index a94f58e..f39361c 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,15 @@
+ubertooth (2018.12.R1-1) unstable; urgency=medium
+
+ * New upstream release
+ * debian/control:
+ - Move Vcs from github to salsa
+ * debian/libubertooth1.symbols:
+ - Added new symbol in symbols file
+ * debian/gitlab-ci.yml:
+ - Enable CI on salsa.debian.org
+
+ -- Ruben Undheim <ruben.undheim@gmail.com> Thu, 20 Dec 2018 10:36:18 +0100
+
ubertooth (2018.08.R1-4) unstable; urgency=medium
[ Helmut Grohne ]
diff --git a/debian/control b/debian/control
index e53c8ee..395b839 100644
--- a/debian/control
+++ b/debian/control
@@ -15,8 +15,8 @@ Build-Depends-Indep: gcc-arm-none-eabi,
libnewlib-arm-none-eabi,
libstdc++-arm-none-eabi-newlib
Standards-Version: 4.2.1
-Vcs-Browser: https://github.com/rubund/debian-ubertooth/tree/master
-Vcs-Git: https://github.com/rubund/debian-ubertooth.git
+Vcs-Browser: https://salsa.debian.org/rubund/ubertooth
+Vcs-Git: https://salsa.debian.org/rubund/ubertooth.git
Homepage: http://ubertooth.sourceforge.net/
Package: libubertooth1
diff --git a/debian/gitlab-ci.yml b/debian/gitlab-ci.yml
new file mode 100644
index 0000000..d9acd28
--- /dev/null
+++ b/debian/gitlab-ci.yml
@@ -0,0 +1,9 @@
+image: registry.salsa.debian.org/salsa-ci-team/ci-image-git-buildpackage:latest
+
+build:
+ artifacts:
+ paths:
+ - "*.deb"
+ expire_in: 1 day
+ script:
+ - gitlab-ci-git-buildpackage-all
diff --git a/debian/libubertooth1.symbols b/debian/libubertooth1.symbols
index 47d11e5..992fd27 100644
--- a/debian/libubertooth1.symbols
+++ b/debian/libubertooth1.symbols
@@ -77,6 +77,7 @@ libubertooth.so.1 libubertooth1 #MINVER#
cmd_afh@Base 2015.10.R1+20161126gitf85a6a2
cmd_fix_clock_drift@Base 2015.10.R1+20161126gitf85a6a2
cmd_hop@Base 2015.10.R1+20161126gitf85a6a2
+ cmd_le_set_adv_data@Base 2018.12.R1
cmd_trim_clock@Base 2015.10.R1+20161126gitf85a6a2
cmd_tx_syms@Base 2015.10.R1+20161126gitf85a6a2
do_exit@Base 2015.10.R1+20161126gitf85a6a2
diff --git a/firmware/bluetooth_rxtx/bluetooth_rxtx.c b/firmware/bluetooth_rxtx/bluetooth_rxtx.c
index 3bfbec3..288212c 100644
--- a/firmware/bluetooth_rxtx/bluetooth_rxtx.c
+++ b/firmware/bluetooth_rxtx/bluetooth_rxtx.c
@@ -75,8 +75,10 @@ volatile int8_t rssi_threshold = -30; // -54dBm - 30 = -84dBm
/* Generic TX stuff */
generic_tx_packet tx_pkt;
-/* le stuff */
+/* le slave stuff */
uint8_t slave_mac_address[6] = { 0, };
+uint8_t le_adv_data[LE_ADV_MAX_LEN] = { 0x02, 0x01, 0x05 };
+unsigned le_adv_len = 3;
le_state_t le = {
.access_address = 0x8e89bed6, // advertising channel access address
@@ -191,6 +193,7 @@ static int vendor_request_handler(uint8_t request, uint16_t* request_params, uin
usb_pkt_rx* p = NULL;
uint16_t reg_val;
uint8_t i;
+ unsigned data_in_len = request_params[2];
switch (request) {
@@ -646,11 +649,19 @@ static int vendor_request_handler(uint8_t request, uint16_t* request_params, uin
requested_mode = MODE_BT_SLAVE_LE;
break;
+ case UBERTOOTH_LE_SET_ADV_DATA:
+ // make sure the data fits in our buffer
+ if (data_in_len > LE_ADV_MAX_LEN)
+ return 0;
+ le_adv_len = data_in_len;
+ memcpy(le_adv_data, data, le_adv_len);
+ break;
+
case UBERTOOTH_BTLE_SET_TARGET:
// Addresses appear in packets in reverse-octet order.
// Store the target address in reverse order so that we can do a simple memcmp later
if (data[6] > 48) {
- return 1; // invalid mask
+ return 0; // invalid mask
}
else if (data[6] == 0) {
le.target_set = 0;
@@ -1096,52 +1107,45 @@ static void cc2400_tx_sync(uint32_t sync)
* All modulation parameters are set within this function. The data
* should not be pre-whitened, but the CRC should be calculated and
* included in the data length.
+ *
+ * FIXME: Total packet len must be <= 32 bytes for Reasons. Longer
+ * packets will be quietly truncated.
*/
void le_transmit(u32 aa, u8 len, u8 *data)
{
unsigned i, j;
int bit;
- u8 txbuf[64];
- u8 tx_len;
+ u8 txbuf[32];
u8 byte;
- u16 gio_save;
+ uint32_t sync = rbit(aa);
- // first four bytes: AA
- for (i = 0; i < 4; ++i) {
- byte = aa & 0xff;
- aa >>= 8;
- txbuf[i] = 0;
- for (j = 0; j < 8; ++j) {
- txbuf[i] |= (byte & 1) << (7 - j);
- byte >>= 1;
- }
- }
+ // lol
+ if (len > 32)
+ len = 32;
// whiten the data and copy it into the txbuf
int idx = whitening_index[btle_channel_index(channel)];
for (i = 0; i < len; ++i) {
byte = data[i];
- txbuf[i+4] = 0;
+ txbuf[i] = 0;
for (j = 0; j < 8; ++j) {
bit = (byte & 1) ^ whitening[idx];
idx = (idx + 1) % sizeof(whitening);
byte >>= 1;
- txbuf[i+4] |= bit << (7 - j);
+ txbuf[i] |= bit << (7 - j);
}
}
- len += 4; // include the AA in len
-
// Bluetooth-like modulation
cc2400_set(MANAND, 0x7fff);
cc2400_set(LMTST, 0x2b22); // LNA and receive mixers test register
cc2400_set(MDMTST0, 0x134b); // no PRNG
- cc2400_set(GRMDM, 0x0c01);
- // 0 00 01 1 000 00 0 00 0 1
+ cc2400_set(GRMDM, 0x0ce1);
+ // 0 00 01 1 001 11 0 00 0 1
// | | | | +--------> CRC off
- // | | | +-----------> sync word: 8 MSB bits of SYNC_WORD
- // | | +---------------> 0 preamble bytes of 01010101
+ // | | | +-----------> sync word: all 32 bits of SYNC_WORD
+ // | | +---------------> 1 preamble byte of 01010101
// | +-----------------> packet mode
// +--------------------> buffered mode
@@ -1150,16 +1154,11 @@ void le_transmit(u32 aa, u8 len, u8 *data)
cc2400_set(MDMCTRL, 0x0040); // 250 kHz frequency deviation
cc2400_set(INT, 0x0014); // FIFO_THRESHOLD: 20 bytes
- // sync byte depends on the first transmitted bit of the AA
- if (aa & 1)
- cc2400_set(SYNCH, 0xaaaa);
- else
- cc2400_set(SYNCH, 0x5555);
-
- // set GIO to FIFO_FULL
- gio_save = cc2400_get(IOCFG);
- cc2400_set(IOCFG, (GIO_FIFO_FULL << 9) | (gio_save & 0x1ff));
+ // set sync word to bit-reversed AA
+ cc2400_set(SYNCL, sync & 0xffff);
+ cc2400_set(SYNCH, (sync >> 16) & 0xffff);
+ // turn on the radio
while (!(cc2400_status() & XOSC16M_STABLE));
cc2400_strobe(SFSON);
while (!(cc2400_status() & FS_LOCK));
@@ -1168,16 +1167,10 @@ void le_transmit(u32 aa, u8 len, u8 *data)
PAEN_SET;
#endif
while ((cc2400_get(FSMSTATE) & 0x1f) != STATE_STROBE_FS_ON);
- cc2400_strobe(STX);
- // put the packet into the FIFO
- for (i = 0; i < len; i += 16) {
- while (GIO6) ; // wait for the FIFO to drain (FIFO_FULL false)
- tx_len = len - i;
- if (tx_len > 16)
- tx_len = 16;
- cc2400_fifo_write(tx_len, txbuf + i);
- }
+ // copy the packet to the FIFO and strobe STX
+ cc2400_fifo_write(len, txbuf);
+ cc2400_strobe(STX);
while ((cc2400_get(FSMSTATE) & 0x1f) != STATE_STROBE_FS_ON);
TXLED_CLR;
@@ -1188,9 +1181,6 @@ void le_transmit(u32 aa, u8 len, u8 *data)
#ifdef UBERTOOTH_ONE
PAEN_CLR;
#endif
-
- // reset GIO
- cc2400_set(IOCFG, gio_save);
}
void le_jam(void) {
@@ -2323,43 +2313,45 @@ void bt_promisc_le() {
void bt_slave_le() {
u32 calc_crc;
int i;
+ uint8_t adv_ind[32] = { 0x00, };
+ uint8_t adv_ind_len;
- u8 adv_ind[] = {
- // LL header
- 0x00, 0x09,
-
- // advertising address
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-
- // advertising data
- 0x02, 0x01, 0x05,
-
- // CRC (calc)
- 0xff, 0xff, 0xff,
- };
+ if (le_adv_len > LE_ADV_MAX_LEN) {
+ requested_mode = MODE_IDLE;
+ return;
+ }
- u8 adv_ind_len = sizeof(adv_ind) - 3;
+ adv_ind_len = 6 + le_adv_len;
+ adv_ind[1] = adv_ind_len;
// copy the user-specified mac address
for (i = 0; i < 6; ++i)
adv_ind[i+2] = slave_mac_address[5-i];
+ // copy in the adv data
+ memcpy(adv_ind + 2 + 6, le_adv_data, le_adv_len);
+
+ // total: 2 + 6 + le_adv_len
+ adv_ind_len += 2;
+
calc_crc = btle_calc_crc(le.crc_init_reversed, adv_ind, adv_ind_len);
- adv_ind[adv_ind_len+0] = (calc_crc >> 0) & 0xff;
- adv_ind[adv_ind_len+1] = (calc_crc >> 8) & 0xff;
- adv_ind[adv_ind_len+2] = (calc_crc >> 16) & 0xff;
+ adv_ind[adv_ind_len + 0] = (calc_crc >> 0) & 0xff;
+ adv_ind[adv_ind_len + 1] = (calc_crc >> 8) & 0xff;
+ adv_ind[adv_ind_len + 2] = (calc_crc >> 16) & 0xff;
clkn_start();
+ // enable USB interrupts due to busy waits
+ ISER0 = ISER0_ISE_USB;
+
// spam advertising packets
while (requested_mode == MODE_BT_SLAVE_LE) {
- ICER0 = ICER0_ICE_USB;
- ICER0 = ICER0_ICE_DMA;
le_transmit(0x8e89bed6, adv_ind_len+3, adv_ind);
- ISER0 = ISER0_ISE_USB;
- ISER0 = ISER0_ISE_DMA;
msleep(100);
}
+
+ // disable USB interrupts
+ ICER0 = ICER0_ICE_USB;
}
void rx_generic_sync(void) {
diff --git a/firmware/bluetooth_rxtx/ubertooth_usb.c b/firmware/bluetooth_rxtx/ubertooth_usb.c
index cc27a18..b1bd464 100644
--- a/firmware/bluetooth_rxtx/ubertooth_usb.c
+++ b/firmware/bluetooth_rxtx/ubertooth_usb.c
@@ -91,7 +91,7 @@ static u8 abDescriptors[] = {
MAX_PACKET_SIZE0, // bMaxPacketSize
LE_WORD(ID_VENDOR), // idVendor
LE_WORD(ID_PRODUCT), // idProduct
- LE_WORD(0x0105), // bcdDevice
+ LE_WORD(0x0106), // bcdDevice
0x01, // iManufacturer
0x02, // iProduct
0x03, // iSerialNumber
@@ -212,7 +212,7 @@ VendorRequestHandler *v_req_handler;
BOOL usb_vendor_request_handler(TSetupPacket *pSetup, int *piLen, u8 **ppbData)
{
int rv;
- u16 params[2] = {pSetup->wValue, pSetup->wIndex};
+ u16 params[3] = {pSetup->wValue, pSetup->wIndex, pSetup->wLength};
rv = v_req_handler(pSetup->bRequest, params, *ppbData, piLen);
return (BOOL) (rv==1);
}
diff --git a/host/cmake/set_release.cmake b/host/cmake/set_release.cmake
index 74628b2..50208e3 100644
--- a/host/cmake/set_release.cmake
+++ b/host/cmake/set_release.cmake
@@ -6,7 +6,7 @@
# tagged
if(NOT DEFINED RELEASE_STRING)
- set(LATEST_RELEASE "2018-08-R1")
+ set(LATEST_RELEASE "2018-12-R1")
execute_process(
COMMAND git log -n 1 --format=%h
diff --git a/host/libubertooth/src/ubertooth_control.c b/host/libubertooth/src/ubertooth_control.c
index a542caf..23ee7bf 100644
--- a/host/libubertooth/src/ubertooth_control.c
+++ b/host/libubertooth/src/ubertooth_control.c
@@ -935,6 +935,28 @@ int cmd_btle_slave(struct libusb_device_handle* devh, u8 *mac_address)
return 0;
}
+int cmd_le_set_adv_data(struct libusb_device_handle* devh, uint8_t *data, unsigned data_len) {
+ int r;
+
+ if (data_len > LE_ADV_MAX_LEN) {
+ fprintf(stderr, "Ubertooth USB error: LE advertising data too long (%u > %u)\n", data_len, LE_ADV_MAX_LEN);
+ return -1;
+ }
+
+ r = libusb_control_transfer(devh, CTRL_OUT, UBERTOOTH_LE_SET_ADV_DATA, 0, 0,
+ data, data_len, 1000);
+ if (r < 0) {
+ if (r == LIBUSB_ERROR_PIPE) {
+ fprintf(stderr, "control message unsupported\n");
+ } else {
+ show_libusb_error(r);
+ }
+ return r;
+ }
+
+ return 0;
+}
+
int cmd_btle_set_target(struct libusb_device_handle* devh, uint8_t *mac_address, uint8_t mac_mask)
{
int r;
diff --git a/host/libubertooth/src/ubertooth_control.h b/host/libubertooth/src/ubertooth_control.h
index 675b899..72284d5 100644
--- a/host/libubertooth/src/ubertooth_control.h
+++ b/host/libubertooth/src/ubertooth_control.h
@@ -135,6 +135,7 @@ int cmd_poll(struct libusb_device_handle* devh, usb_pkt_rx *p);
int cmd_btle_promisc(struct libusb_device_handle* devh);
int cmd_read_register(struct libusb_device_handle* devh, u8 reg);
int cmd_btle_slave(struct libusb_device_handle* devh, u8 *mac_address);
+int cmd_le_set_adv_data(struct libusb_device_handle* devh, uint8_t *data, unsigned data_len);
int cmd_btle_set_target(struct libusb_device_handle* devh, uint8_t *mac_address, uint8_t mac_mask);
int cmd_set_jam_mode(struct libusb_device_handle* devh, int mode);
int cmd_ego(struct libusb_device_handle* devh, int mode);
diff --git a/host/libubertooth/src/ubertooth_interface.h b/host/libubertooth/src/ubertooth_interface.h
index b170332..95882a3 100644
--- a/host/libubertooth/src/ubertooth_interface.h
+++ b/host/libubertooth/src/ubertooth_interface.h
@@ -25,7 +25,7 @@
#include <stdint.h>
// increment on every API change
-#define UBERTOOTH_API_VERSION 0x0105
+#define UBERTOOTH_API_VERSION 0x0106
#define DMA_SIZE 50
@@ -111,8 +111,12 @@ enum ubertooth_usb_commands {
UBERTOOTH_TX_GENERIC_PACKET = 68,
UBERTOOTH_FIX_CLOCK_DRIFT = 69,
UBERTOOTH_CANCEL_FOLLOW = 70,
+ UBERTOOTH_LE_SET_ADV_DATA = 71,
};
+// maximum adv data len: 32 - (2 + 6 + 3)
+#define LE_ADV_MAX_LEN 21
+
enum jam_modes {
JAM_NONE = 0,
JAM_ONCE = 1,
diff --git a/host/python/specan_ui/ubertooth-specan-ui b/host/python/specan_ui/ubertooth-specan-ui
index 8a3fac9..43ebd52 100755
--- a/host/python/specan_ui/ubertooth-specan-ui
+++ b/host/python/specan_ui/ubertooth-specan-ui
@@ -24,13 +24,20 @@ import sys
import threading
import numpy
-from optparse import OptionParser
+from argparse import ArgumentParser
-from PySide import QtCore, QtGui
-from PySide.QtCore import Qt, QPointF, QLineF
+from PySide2 import QtCore, QtGui, QtWidgets
+from PySide2.QtCore import Qt, QPointF, QLineF
from specan import Ubertooth
+DEFAULT_LOWER_FREQ = 2400
+DEFAULT_UPPER_FREQ = 2483
+
+# going much further causes the Ubertooth to stop responding :(
+
+MIN_FREQ = 2300
+MAX_FREQ = 2600
class SpecanThread(threading.Thread):
def __init__(self, device, low_frequency, high_frequency, new_frame_callback, ubertooth_device=-1):
@@ -58,9 +65,9 @@ class SpecanThread(threading.Thread):
self._stopped = True
-class RenderArea(QtGui.QWidget):
- def __init__(self, device, parent=None, ubertooth_device=-1):
- QtGui.QWidget.__init__(self, parent)
+class RenderArea(QtWidgets.QWidget):
+ def __init__(self, device, parent=None, ubertooth_device=-1, lower_freq=DEFAULT_LOWER_FREQ, upper_freq=DEFAULT_UPPER_FREQ):
+ QtWidgets.QWidget.__init__(self, parent)
self._graph = None
self._reticle = None
@@ -71,8 +78,8 @@ class RenderArea(QtGui.QWidget):
self._persisted_frames_depth = 350
self._path_max = None
- self._low_frequency = 2.400e9
- self._high_frequency = 2.483e9
+ self._low_frequency = lower_freq * 1e6
+ self._high_frequency = upper_freq * 1e6
self._frequency_step = 1e6
self._high_dbm = 0.0
self._low_dbm = -100.0
@@ -83,6 +90,8 @@ class RenderArea(QtGui.QWidget):
self._mouse_x2 = None
self._mouse_y2 = None
+ self._clear_scheduled = False
+
self._thread = SpecanThread(self._device,
self._low_frequency,
self._high_frequency,
@@ -90,6 +99,9 @@ class RenderArea(QtGui.QWidget):
ubertooth_device=ubertooth_device)
self._thread.start()
+ def schedule_clear(self):
+ self._clear_scheduled = True
+
def stop_thread(self):
self._thread.stop()
@@ -112,6 +124,7 @@ class RenderArea(QtGui.QWidget):
return QtCore.QSize(x_points * 4, y_points * 1)
def _new_frame(self, frequency_axis, rssi_values):
+
self._frame = (frequency_axis, rssi_values)
if self._persisted_frames is None:
self._new_persisted_frames(len(frequency_axis))
@@ -120,6 +133,12 @@ class RenderArea(QtGui.QWidget):
self.update()
def _draw_graph(self):
+ if self._clear_scheduled:
+ frequency_axis, _ = self._frame
+ self._clear_scheduled = False
+ self._new_graph()
+ self._new_persisted_frames(len(frequency_axis))
+
if self._graph is None:
self._new_graph()
elif self._graph.size() != self.size():
@@ -278,15 +297,15 @@ class RenderArea(QtGui.QWidget):
return self._high_dbm - delta
-class Window(QtGui.QWidget):
- def __init__(self, parent=None, ubertooth_device=-1):
- QtGui.QWidget.__init__(self, parent)
+class Window(QtWidgets.QWidget):
+ def __init__(self, parent=None, ubertooth_device=-1, lower_freq=DEFAULT_LOWER_FREQ, upper_freq=DEFAULT_UPPER_FREQ):
+ QtWidgets.QWidget.__init__(self, parent)
self._device = self._open_device()
- self.render_area = RenderArea(self._device, ubertooth_device=ubertooth_device)
+ self.render_area = RenderArea(self._device, ubertooth_device=ubertooth_device, lower_freq=lower_freq, upper_freq=upper_freq)
- main_layout = QtGui.QGridLayout()
+ main_layout = QtWidgets.QGridLayout()
main_layout.setContentsMargins(0, 0, 0, 0)
main_layout.addWidget(self.render_area, 0, 0)
self.setLayout(main_layout)
@@ -337,6 +356,7 @@ class Window(QtGui.QWidget):
print(' <LEFT MOUSE> Mark LEFT frequency / signal strength at pointer')
print(' <RIGHT MOUSE> Mark RIGHT frequency / signal strength at pointer')
print(' <MIDDLE MOUSE> Toggle visibility of frequency / signal strength markers')
+ print(' C Clear graph')
print(' H Print this HELP text')
print(' M Simulate MIDDLE MOUSE click (for those with trackpads)')
print(' Q Quit')
@@ -348,6 +368,9 @@ class Window(QtGui.QWidget):
self.render_area._mouse_y2 = None
self.render_area._hide_markers = not self.render_area._hide_markers
return
+ if key == 'C':
+ self.render_area.schedule_clear()
+ return
if key == 'Q':
print('Quit!')
self.close()
@@ -357,23 +380,92 @@ class Window(QtGui.QWidget):
def sigint_handler(*args):
"""Handler for the SIGINT signal."""
- QtGui.QApplication.quit()
+ QtWidgets.QApplication.quit()
+
+
+def convert_wifi(channel):
+ if channel < 1 or channel > 14:
+ print("ERROR: channel " + str(channel) + " is not a valid wifi channel")
+ raise ValueError()
+
+ if channel == 14:
+ return 2482
+ else:
+ return channel * 5 + 2407
+
+def check_freq(freq):
+ if freq < MIN_FREQ:
+ print("ERROR: frequency of " + str(freq) + " MHz is below minimum frequency of " + str(MIN_FREQ))
+ raise ValueError()
+ if freq > MAX_FREQ:
+ print("ERROR: frequency of " + str(freq) + " MHz is above maximum frequency of " + str(MAX_FREQ))
+ raise ValueError()
+
+
+def check_freq_pair(freq1, freq2):
+ check_freq(freq1)
+ check_freq(freq2)
+
+ if freq1 > freq2:
+ print("ERROR: lower frequency of " + str(freq1) + " MHz is above upper frequency of " + str(freq2) + " MHz")
+ raise ValueError()
if __name__ == '__main__':
signal.signal(signal.SIGINT, sigint_handler)
- parser = OptionParser()
- parser.add_option("-U", type="int", dest="device",
+ parser = ArgumentParser()
+ parser.add_argument("-U", type=int, dest="device",
help="set ubertooth device to use")
+ parser.add_argument("-l", type=int, dest="lower_freq", help="lower bound for scan, in MHz (no less than " + str(MIN_FREQ) + ")")
+ parser.add_argument("-u", type=int, dest="upper_freq", help="upper bound for scan, in MHz (no more than " + str(MAX_FREQ) + ")")
+ parser.add_argument("--wifi", type=str, nargs='?', dest="wifi", metavar="channel(s)", help="display the spectrum for the wifi channels provided, either as a single number for one channel, or a range (e.g. 1-11) for two channels", const="1", default=False)
+ parser.add_argument("--padding", type=int, dest="padding", help="padding on both ends when using --wifi, measured in MHz (default 10)", default=10)
- (options, args) = parser.parse_args()
+ (options, extras) = parser.parse_known_args()
ubertooth_device = options.device
if ubertooth_device is None:
ubertooth_device = -1
- app = QtGui.QApplication(sys.argv)
- window = Window(ubertooth_device=ubertooth_device)
+ lower_freq = options.lower_freq
+ upper_freq = options.upper_freq
+
+ if options.wifi:
+
+ lower_channel = upper_channel = None
+
+ parts = options.wifi.split("-")
+
+ try:
+ if len(parts) == 1:
+ lower_channel = upper_channel = int(parts[0])
+ elif len(parts) == 2:
+ lower_channel = int(parts[0])
+ upper_channel = int(parts[1])
+ else:
+ raise ValueError()
+ except ValueError:
+ print("ERROR: invalid channel range: " + options.wifi)
+ sys.exit(1)
+
+ try:
+ lower_freq = convert_wifi(lower_channel) - options.padding
+ upper_freq = convert_wifi(upper_channel) + options.padding
+ except ValueError:
+ sys.exit(1)
+ else:
+ if not lower_freq:
+ lower_freq = DEFAULT_LOWER_FREQ
+ if not upper_freq:
+ upper_freq = DEFAULT_UPPER_FREQ
+
+ try:
+ check_freq_pair(lower_freq, upper_freq)
+ except ValueError:
+ sys.exit(1)
+
+ app = QtWidgets.QApplication(sys.argv)
+ window = Window(ubertooth_device=ubertooth_device, lower_freq=lower_freq, upper_freq=upper_freq)
window.show()
sys.exit(app.exec_())
diff --git a/host/ubertooth-tools/src/CMakeLists.txt b/host/ubertooth-tools/src/CMakeLists.txt
index 16b74b7..94fc5fe 100644
--- a/host/ubertooth-tools/src/CMakeLists.txt
+++ b/host/ubertooth-tools/src/CMakeLists.txt
@@ -59,7 +59,7 @@ if(USE_OWN_GNU_GETOPT)
LIST(APPEND TOOLS_LINK_LIBS libgetopt_static)
endif(USE_OWN_GNU_GETOPT)
-LIST(APPEND TOOLS ubertooth-rx ubertooth-tx ubertooth-dump ubertooth-util ubertooth-btle ubertooth-dfu ubertooth-specan ubertooth-ego ubertooth-afh)
+LIST(APPEND TOOLS ubertooth-rx ubertooth-tx ubertooth-dump ubertooth-util ubertooth-btle ubertooth-dfu ubertooth-specan ubertooth-ego ubertooth-afh ubertooth-ducky)
if( USE_BLUEZ AND NOT ${LIBBLUETOOTH_FOUND} )
message( FATAL_ERROR
diff --git a/host/ubertooth-tools/src/ubertooth-btle.c b/host/ubertooth-tools/src/ubertooth-btle.c
index 2959a2c..02a3dd5 100644
--- a/host/ubertooth-tools/src/ubertooth-btle.c
+++ b/host/ubertooth-tools/src/ubertooth-btle.c
@@ -387,6 +387,10 @@ int main(int argc, char *argv[])
channel = 2480;
cmd_set_channel(ut->devh, channel);
+ // flags: LE Limited Discovery
+ uint8_t adv_data[] = { 0x02, 0x01, 0x05 };
+ cmd_le_set_adv_data(ut->devh, adv_data, sizeof(adv_data));
+
cmd_btle_slave(ut->devh, mac_address);
}
diff --git a/host/ubertooth-tools/src/ubertooth-ducky.c b/host/ubertooth-tools/src/ubertooth-ducky.c
new file mode 100644
index 0000000..ce993dd
--- /dev/null
+++ b/host/ubertooth-tools/src/ubertooth-ducky.c
@@ -0,0 +1,288 @@
+/*
+ * Copyright 2018 Michael Ryan
+ *
+ * This file is part of Project Ubertooth.
+ *
+ * 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, 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "ubertooth.h"
+#include "ubertooth_callback.h"
+#include <ctype.h>
+#include <getopt.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define DEFAULT_UUID "fd123ff9-9e30-45b2-af0d-b85b7d2dc80c"
+#define BOOTLOADER_UUID "344bc7f2-5619-4953-9be8-9888fe29d996"
+
+int running = 1;
+
+static void quit(int sig __attribute__((unused))) {
+ running = 0;
+}
+
+void print_mac(uint8_t *mac_address) {
+ unsigned i;
+ for (i = 0; i < 5; ++i)
+ printf("%02x:", mac_address[i]);
+ printf("%02x", mac_address[5]);
+}
+
+int convert_mac_address(char *s, uint8_t *o) {
+ int i;
+
+ // validate length
+ if (strlen(s) != 6 * 2 + 5) {
+ printf("Error: MAC address is wrong length\n");
+ return 0;
+ }
+
+ // validate hex chars and : separators
+ for (i = 0; i < 6*3; i += 3) {
+ if (!isxdigit(s[i]) ||
+ !isxdigit(s[i+1])) {
+ printf("Error: BD address contains invalid character(s)\n");
+ return 0;
+ }
+ if (i < 5*3 && s[i+2] != ':') {
+ printf("Error: BD address contains invalid character(s)\n");
+ return 0;
+ }
+ }
+
+ // sanity: checked; convert
+ for (i = 0; i < 6; ++i) {
+ unsigned byte;
+ sscanf(&s[i*3], "%02x",&byte);
+ o[i] = byte;
+ }
+
+ return 1;
+}
+
+int parse_uuid(char *s, uint8_t *uuid_out) {
+ unsigned i, n;
+
+ if (s == NULL || strlen(s) != 36)
+ return 0;
+
+ for (i = 0, n = 0; i < 36 && n < 32; ++i) {
+ unsigned nibble = 0;
+ char lower;
+
+ if (s[i] == '-')
+ continue;
+ if (isxdigit(s[i])) {
+ if (s[i] >= '0' && s[i] <= '9')
+ nibble = s[i] - '0';
+ else {
+ lower = tolower(s[i]);
+ nibble = lower - 'a' + 10;
+ }
+
+ uuid_out[n/2] |= nibble << (n & 1 ? 0 : 4);
+ ++n;
+ } else {
+ return 0;
+ }
+ }
+
+ return n == 32;
+}
+
+void print_uuid(uint8_t *uuid) {
+ unsigned i;
+ for (i = 0; i < 4; ++i) printf("%02x", uuid[i]);
+ printf("-");
+ for (i = 4; i < 6; ++i) printf("%02x", uuid[i]);
+ printf("-");
+ for (i = 6; i < 8; ++i) printf("%02x", uuid[i]);
+ printf("-");
+ for (i = 8; i < 10; ++i) printf("%02x", uuid[i]);
+ printf("-");
+ for (i = 10; i < 16; ++i) printf("%02x", uuid[i]);
+}
+
+#define DUCKLEN 7
+char *duck[DUCKLEN] = {
+ " _\n",
+ " /`6\\__ .oO( %s ! )\n",
+ " ,_ \\ _.==' \n",
+ " `) `\"\"\"\"`~~\\\n",
+ " -~ \\ '~-. / ~-\n",
+ " ~- `~-====-' ~_ ~-\n",
+ " ~ - ~ ~- ~ - ~ -\n",
+};
+
+void print_duck(int s) {
+ unsigned i;
+ for (i = 0; i < DUCKLEN; ++i) {
+ if (i != 1) {
+ printf("%s", duck[i]);
+ } else {
+ printf(duck[i], s ? "FLAT" : "UBERDUCKY");
+ }
+ }
+}
+
+
+static void usage(void) {
+ printf("ubertooth-ducky - make an Uberducky quack like a USB Rubber Ducky\n");
+ printf("Usage:\n");
+ printf("\t-q [uuid] quack!\n");
+ printf("\t-b signal Uberducky to enter bootloader\n");
+ printf("\n");
+ printf("\t-A <index> advertising channel index (default: 38)\n");
+ printf("\t-a <BD ADDR> Bluetooth address (default: random)\n");
+ printf("\t-h this help\n");
+ printf("\n");
+ printf("For more information on Uberducky, visit:\n");
+ printf("https://github.com/mikeryan/uberducky\n");
+}
+
+int main(int argc, char *argv[])
+{
+ int opt;
+ int do_quack, do_adv_index;
+ int addr_set, be_sarcastic;
+ char *uuid_str = NULL;
+ uint8_t uuid[16] = { 0, };
+ uint8_t bd_addr[6] = { 0, };
+ uint8_t adv_data[16+2] = { 0, };
+ int ubertooth_device = -1;
+ ubertooth_t* ut = ubertooth_init();
+
+ int r;
+
+ do_quack = 0;
+ do_adv_index = 38;
+ addr_set = 0;
+ be_sarcastic = 0;
+
+ while ((opt=getopt(argc,argv,"q::bA:a:hs")) != EOF) {
+ switch(opt) {
+ case 'q':
+ do_quack = 1;
+ uuid_str = strdup(optarg ? optarg : DEFAULT_UUID);
+ break;
+
+ case 'b':
+ do_quack = 1;
+ uuid_str = strdup(BOOTLOADER_UUID);
+ break;
+
+ case 'A':
+ do_adv_index = atoi(optarg);
+ if (do_adv_index < 37 || do_adv_index > 39) {
+ printf("Error: advertising index must be 37, 38, or 39\n");
+ usage();
+ return 1;
+ }
+ break;
+
+ case 'a':
+ r = convert_mac_address(optarg, bd_addr);
+ if (!r) {
+ printf("Error parsing BD ADDR '%s'\n", optarg);
+ usage();
+ return 1;
+ }
+ addr_set = 1;
+ break;
+
+ case 's':
+ be_sarcastic = 1;
+ break;
+
+ case 'h':
+ default:
+ usage();
+ return 1;
+ }
+ }
+
+ if (do_quack) {
+ FILE *random;
+
+ r = parse_uuid(uuid_str, uuid);
+ if (!r) {
+ if (!be_sarcastic)
+ printf("Error parsing UUID '%s'\n", optarg);
+ else
+ printf("UUID's fucked mate. Did an upright duck tell you to type that?\n");
+ return 1;
+ }
+ free(uuid_str);
+
+ if (!addr_set) {
+ random = fopen("/dev/urandom", "r");
+ fread(bd_addr, 6, 1, random);
+ fclose(random);
+ }
+
+ }
+
+ r = ubertooth_connect(ut, ubertooth_device);
+ if (r < 0) {
+ usage();
+ return 1;
+ }
+
+ r = ubertooth_check_api(ut);
+ if (r < 0)
+ return 1;
+
+ // quit on ctrl-C
+ signal(SIGINT, quit);
+ signal(SIGQUIT, quit);
+ signal(SIGTERM, quit);
+
+ if (do_quack) {
+ uint16_t channel;
+ unsigned i;
+
+ print_duck(be_sarcastic);
+ printf("\n");
+ printf("Quacking ");
+ print_uuid(uuid);
+ printf(" as ");
+ print_mac(bd_addr);
+ printf("\n");
+
+ adv_data[0] = 0x11; // 17 bytes
+ adv_data[1] = 0x07; // 128 bit UUIDs
+ for (i = 0; i < 16; ++i) // reverse byte order
+ adv_data[2+i] = uuid[15-i];
+
+ if (do_adv_index == 37)
+ channel = 2402;
+ else if (do_adv_index == 38)
+ channel = 2426;
+ else
+ channel = 2480;
+
+ cmd_set_channel(ut->devh, channel);
+ cmd_le_set_adv_data(ut->devh, adv_data, sizeof(adv_data));
+ cmd_btle_slave(ut->devh, bd_addr);
+
+ sleep(2);
+ ubertooth_stop(ut);
+ }
+ return 0;
+}
diff --git a/tools/RELEASENOTES b/tools/RELEASENOTES
index ed64d7f..c99805a 100644
--- a/tools/RELEASENOTES
+++ b/tools/RELEASENOTES
@@ -1,49 +1,32 @@
-Ubertooth 2018-08-R1 Release Notes
+Ubertooth 2018-12-R1 Release Notes
==============================
-The Ubertooth host utilities in this release require libbtbb-2018-08-R1
-(https://github.com/greatscottgadgets/libbtbb/releases/tag/2018-08-R1) or
+The Ubertooth host utilities in this release require libbtbb-2018-12-R1
+(https://github.com/greatscottgadgets/libbtbb/releases/tag/2018-12-R1) or
greater.
Changes
-------
-**New LE sniffing engine** - The BLE sniffing engine has been completely
-rewritten using interrupts to drive an event-based core. The new
-sniffing engine is considerably more robust than previous versions and
-should have a higher packet capture rate. This code has received less
-testing than previous versions, but in the experience of the author has
-been exceptionally stable and is superior to previous versions in almost
-every way.
-
-**Partial channel map support** - As part of the new BLE sniffing
-engine, there is now support for partial channel maps when an LE
-connection is established as well as support for the Channel Map Update
-Link Layer Procedure. This allows capturing connections from virtually
-all modern BLE devices.
-
-**Connection update support** - Support for Connection Update Link Layer
-Procedure has been reimplemented as of this update. This was a feature
-degradation in 2018-06-R1 but has been fixed.
-
-**Improved filtering** - LE filtering now applies to all advertising
-packets, not just connections. Packets that do not match the filter are
-silently dropped. Filters can include a CIDR-style netmask, allowing as
-few as 1 or as many as 48 bits to be included in the BD ADDR filter.
-
-**No-follow mode** - In LE, it is now a first-class operation to only
-log advertising packets (inhibit connection following). The previous
-mechanism of using a filter of 00:00:00:00:00:00 is no longer
-functional, and this new feature should be used instead.
+**Uberducky triggering** - Uberducky is a new project built on Ubertooth
+hardware that acts like a USB Rubber Ducky. You can use a second
+Ubertooth to trigger it to inject keystrokes using the `ubertooth-ducky`
+command. See the [Uberducky repo](https://github.com/mikeryan/uberducky)
+for more info.
+
+**Spectrum Analyzer UI improvements** - Thank you Steven Haussmann and
+Andrew Browning!
+
+**Bug fixes** - Improvements to `ubertooth-btle`'s faux slave mode.
**USB API version** - As with the previous release, we are using USB API
versioning to improve the experience of failures due to mismatched
firmware and host code. As of this release, the USB API has been bumped
-to 1.04. If the Ubertooth tools complain that your firmware is out of
+to 1.06. If the Ubertooth tools complain that your firmware is out of
date, please update your firmware. Updating firmware is simple and
reliable, please follow the instructions on the wiki
https://github.com/greatscottgadgets/ubertooth/wiki/Firmware
A release archive with precompiled firmware is available from
-https://github.com/greatscottgadgets/ubertooth/releases/download/2018-08-R1/ubertooth-2018-08-R1.tar.xz
+https://github.com/greatscottgadgets/ubertooth/releases/download/2018-12-R1/ubertooth-2018-12-R1.tar.xz
Support
-------