Skip to content

Instantly share code, notes, and snippets.

@GermaniumSystem
Created December 8, 2019 21:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save GermaniumSystem/eac00c5264900c6e889089631acce8fd to your computer and use it in GitHub Desktop.
Save GermaniumSystem/eac00c5264900c6e889089631acce8fd to your computer and use it in GitHub Desktop.
A shell script for sending BTLE commands to the DEFCON Furs DC27 badge. Requires Bash, BlueZ, and not much else.
#!/bin/bash
set -e
MAGIC_RAND_COLOR='7e'
MAGIC_AWOO='a0'
MAGIC_BEACON='00'
# The docs say MAGIC_EMOTE is b3. The docs are wrong.
MAGIC_EMOTE='b2'
MFG_FLAGS='ff ff 71'
DEV_NAME='BOGOBLE'
color="$MAGIC_RAND_COLOR"
iface='hci0'
sn='8678'
function printHelp {
cat <<EOHELP
BTLEComm.sh - Control nearby DEFCON Furs DC26 badges via BTLE beaconns.
Usage:
BTLEComm.sh [-i interface] [-s serial] <command> [argument]
Flags:
-c, --color COLOR Hex byte for the color using the badge's weird
format. Examples below.
00 = red
28 = green
50 = blue
78 = red
There are two special values.
7e = white
7f = random
-i, --interface IFACE The Bluetooth interface to broadcast from.
Defaults to $iface.
-s, --serial SERIALNUM The badge serial number to use.
Default to $sn.
-t, --time SECONDS Duration of the broadcase. Infinite by default.
Commands:
awoo - Starts a howl with a maximum TTL.
beacon - Broadcasts the same beacons that an idle badge would.
emote [face] - Causes nearby badges to display an emote.
Accepts an optional argument to specify 2 characters for
the face. Only uppercase letters, numbers, most special
characters, and lowercase "o" are supported. Examples below.
emote '^^'
emote '>>'
emote 'oO'
Special emotes such as 'owo' appear to have been removed.
EOHELP
exit
}
function decToHex {
printf "%02x" "$1"
}
function genFieldLength {
data="$1"
data_len="$(($(echo "$data" | sed 's/ //g' | wc -c - | sed 's/ .*//') / 2))"
data_hex_len="$(decToHex "$data_len")"
echo "$data_hex_len"
}
function setAdvertParams {
payload="$1"
mfg_len="$(genFieldLength "$MFG_FLAGS $payload")"
hex_name="$(asciiToHex "$DEV_NAME")"
name_len="$(($(genFieldLength "$hex_name") + 1))"
pkt="03 19 dc 27 02 01 06 $name_len 09 $hex_name $mfg_len $MFG_FLAGS $payload"
pkt_len="$(genFieldLength "$pkt")"
# https://gist.github.com/GermaniumSystem/d785ab9717dda672419740a40b0623bb
hcitool -i "$iface" cmd 0x08 0x0008 $pkt_len $pkt >/dev/null
}
function asciiToHex {
# This limits the input to 16 bytes, but no commands should be this long.
printf -- "$1" | od -t x1 | head -n 1 | sed -r 's/^[^ ]+ //'
}
function serialHex {
# The two bytes need to be flipped for the subsequent hcitool command.
printf "%04x\n" "$sn" | sed -r 's/(..)(..)/\2 \1/'
}
function stop_tx {
# Stop transmitting on ^C.
hciconfig "$iface" noleadv
echo -e "\nTransmission stopped."
}
# Sanity checks.
if [ -z "$(which hciconfig)" ] ; then
echo "Could not locate hciconfig! Does this system have BlueZ?"
exit 10
fi
if [ -z "$1" ] ; then
printHelp
fi
if [ "$(id -u)" -ne "0" ] ; then
echo -e "\nWARNING: This script probably won't work when not run by root.\n"
fi
if ps ax | grep -v 'grep' | grep -qi 'bluetoothd' ; then
echo -e "\nWARNING: bluetoothd is running! This may break things.\n"
fi
# Parse args.
while [[ $# -gt 0 ]]; do
key=$1
case $key in
-h|--help)
printHelp
;;
-c|--color)
color="$2"
shift
shift
;;
-i|--interface)
iface="$2"
shift
shift
;;
-s|--serial)
sn="$2"
shift
shift
;;
-t|--time)
txtime="$2"
shift
shift
;;
*)
cmd="$1"
if [ -n "$2" ] ; then
arg="$2"
shift
fi
shift
;;
esac
done
#echo "Generating payload..."
sn_bytes="$(serialHex)"
case $cmd in
awoo)
# Magic byte, two serial num bytes, TTL byte, two origin serial num bytes.
data="$MAGIC_AWOO $sn_bytes ff $sn_bytes"
;;
beacon)
# Magic byte, two serial num bytes.
data="$MAGIC_BEACON $sn_bytes"
;;
emote)
# Magic byte, optional color byte, 2 optional emote bytes.
data="$MAGIC_EMOTE"
if [ -n "$arg" ] ; then
arg_hex="$(asciiToHex "$arg")"
data="$MAGIC_EMOTE $color $arg_hex"
fi
echo "$data"
;;
*)
echo "Unknown command '$cmd'"
exit 2
;;
esac
echo "Bringing interface $IFACE up..."
hciconfig "$IFACE" up
#echo "Setting advertisement parameters..."
setAdvertParams "$data"
#echo "Enabling advertisement..."
hciconfig "$IFACE" leadv 3
trap stop_tx INT # Stop trasmitting if ^C is pressed.
if [ -n "$txtime" ] ; then
printf "Broadcasting! Stopping transmission in $txtime seconds."
for i in $(seq 1 "$txtime"); do
printf '.'
sleep 1s
done
stop_tx
else
printf "Broadcasting! Press ^C to stop transmission."
while true ; do
printf '.'
sleep 1s
done
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment