Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
kantorkel committed Oct 21, 2022
0 parents commit cb4d737
Show file tree
Hide file tree
Showing 17 changed files with 1,050 additions and 0 deletions.
Binary file added Documentation.pdf
Binary file not shown.
Binary file added IMEI randomization.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 29 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
BSD 3-Clause License

Copyright (c) 2022, SRLabs
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
137 changes: 137 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
include $(TOPDIR)/rules.mk

PKG_NAME:=blue-merle
PKG_VERSION:=1.0.0
PKG_RELEASE:=$(AUTORELEASE)

PKG_MAINTAINER:=Matthias <[email protected]>
PKG_LICENSE:=BSD-3-Clause

include $(INCLUDE_DIR)/package.mk

define Package/blue-merle
SECTION:=utils
CATEGORY:=Utilities
DEPENDS:=+bash +coreutils-shred +python3 +python3-pyserial +patch
TITLE:=Anonymity Enhancements for GL-E750 Mudi
endef

define Package/blue-merle/description
The blue-merle package enhances anonymity and reduces forensic traceability of the GL-E750 Mudi 4G mobile wi-fi router
endef

define Build/Configure
endef

define Build/Compile
endef

define Package/blue-merle/install
$(CP) ./files/* $(1)/
$(INSTALL_BIN) ./files/etc/init.d/* $(1)/etc/init.d/
$(INSTALL_BIN) ./files/lib/blue-merle/mac-wipe.sh $(1)/lib/blue-merle/mac-wipe.sh
$(INSTALL_BIN) ./files/usr/bin/blue-merle $(1)/usr/bin/blue-merle
endef

define Package/blue-merle/preinst
#!/bin/sh
[ -n "$${IPKG_INSTROOT}" ] && exit 0 # if run within buildroot exit

ABORT_GLVERSION () {
echo
if [ -f "/tmp/sysinfo/model" ] && [ -f "/etc/glversion" ]; then
echo "You have a `cat /tmp/sysinfo/model`, running firmware version `cat /etc/glversion`."
fi
echo "blue-merle has only been tested with GL-E750 Mudi Version 3.215."
echo "The device or firmware version you are using have not been verified to work with blue-merle."
echo -n "Would you like to continue on your own risk? (y/N): "
read answer
case $$answer in
y*) answer=0;;
y*) answer=0;;
*) answer=1;;
esac
if [[ "$$answer" -eq 0 ]]; then
exit 0
else
exit 1
fi
}

UPDATE_MCU() {
echo "6e6b86e3ad7fec0d5e426eb9a41c51c6f0d6b68a4d341ec553edeeade3e4b470 /tmp/e750-mcu-V1.0.7.bin" > /tmp/e750-mcu.bin.sha256
wget -O /tmp/e750-mcu-V1.0.7.bin https://github.com/gl-inet/GL-E750-MCU-instruction/blob/master/e750-mcu-V1.0.7-56a1cad7f0eb8318ebe3c3c46a4cf3ff.bin?raw=true
if sha256sum -cs /tmp/e750-mcu.bin.sha256; then
ubus call service delete '{"name":"e750_mcu"}'
mcu_update /tmp/e750-mcu-V1.0.7.bin
else
echo "Failed to update MCU, verification of the binary failed."
echo "Your device needs to be connected to the Internet in order to download the MCU binary."
exit 1
fi
}

CHECK_MCUVERSION() {
function version { echo "$$@" | cut -d' ' -f2 | awk -F. '{ printf("%d%03d%03d%03d\n", $$1,$$2,$$3,$$4); }'; }
mcu_version=`echo \{\"version\": \"1\"} > /dev/ttyS0; sleep 0.1; cat /dev/ttyS0|tr -d '\n'`
if [ $$(version "$$mcu_version") -ge $$(version "V 1.0.7") ]; then
return 0
else
echo
echo "Your MCU version has not been verified to work with blue-merle."
echo "Automatic shutdown may not work."
echo "The install script can initiate an update of the MCU."
echo "The device will reboot and, after reboot, you need to run opkg install blue-merle again."
echo -n "Would you like to update your MCU? (y/N): "
read answer
case $$answer in
Y*) answer=0;;
y*) answer=0;;
*) answer=1;;
esac
if [[ "$$answer" -eq 0 ]]; then
UPDATE_MCU
fi
fi
}

if grep -q "GL.iNet GL-E750" /proc/cpuinfo; then
if grep -q -w "3.215" /etc/glversion; then
CHECK_MCUVERSION
echo "Device is supported, installing blue-merle."
exit 0
else
ABORT_GLVERSION
fi
else
ABORT_GLVERSION
fi
endef

define Package/blue-merle/postinst
#!/bin/sh

patch -b /www/src/temple/settings/index.js /lib/blue-merle/patches/index.js.patch
patch -b /www/src/temple/settings/index.html /lib/blue-merle/patches/index.html.patch
patch -b /usr/bin/switchaction /lib/blue-merle/patches/switchaction.patch
patch -b /usr/bin/switch_queue /lib/blue-merle/patches/switch_queue.patch

uci set glconfig.switch_button='service'
uci set glconfig.switch_button.enable='1'
uci set glconfig.switch_button.function='sim'
uci commit glconfig
endef

define Package/blue-merle/postrm
#!/bin/sh

mv /www/src/temple/settings/index.js.orig /www/src/temple/settings/index.js
mv /www/src/temple/settings/index.html.orig /www/src/temple/settings/index.html
mv /usr/bin/switchaction.orig /usr/bin/switchaction
mv /usr/bin/switch_queue.orig /usr/bin/switch_queue

rm /tmp/sim_change_start
rm /tmp/sim_change_switch
endef
$(eval $(call BuildPackage,$(PKG_NAME)))

86 changes: 86 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# blue-merle

The *blue-merle* software package enhances anonymity and reduces forensic traceability of the **GL-E750 / Mudi 4G mobile wi-fi router ("Mudi router")**. The portable device is explicitly marketed to privacy-interested retail users.

*blue-merle* addresses the traceability drawbacks of the Mudi router by adding the following features to the Mudi router:

1. Mobile Equipment Identity (IMEI) changer

2. Media Access Control (MAC) address log wiper

3. Basic Service Set Identifier (BSSID) randomization

## Installing prebuild package

Download the [prebuild package](https://github.com/srlabs/blue-merle/releases) and copy it onto your Mudi, preferably into the /tmp folder. Then install the package file:

```
opkg update
opkg install blue-merle*.ipk
```

Now you may initiate an IMEI update on the command line by running `blue-merle` or by using Mudi's toggle button. Both the command line and hardware button version of *blue-merle* will guide you through the IMEI update process in order to minimize the risk of IMEI leaks.

The *blue-merle* package has been verified to work with GL-E750 Mudi version 3.215. A MCU version >= 1.0.7 is required. The MCU may be updated through the *blue-merle* package installer or [manually](https://github.com/gl-inet/GL-E750-MCU-instruction). SRLabs cannot guarantee that the project assets within this Git repository will be compatible with future firmware updates.

## Build package
```
git clone https://github.com/openwrt/openwrt
cd openwrt
git clone https://github.com/srlabs/blue-merle package/blue-merle
./scripts/feeds update -a && ./scripts/feeds install -a
make distclean && make clean
make menuconfig
# Target System: Atheros ATH79
# Subtarget Generic Device with NAND flash
# Target Profile: GL.iNet GL-E750
# In Utilities, select <M> for blue-merle package
# Save new configuration
make
make package/blue-merle/compile
```
You will find the package in `./bin/packages/mips_24kc/base/`

## Implementation details

### IMEI randomization

The Mudi router's baseband unit is a Quectel EP06-E/A Series LTE Cat 6 Mini PCIe [module](https://www.quectel.com/wp-content/uploads/pdfupload/Quectel_EP06_Series_LTE-A_Specification_V1.7.pdf>).

The Mudi router's IMEI can be changed by issuing Quectel LTE series-standard AT commands. The AT command to write a new IMEI to a Quectel EP06-E/A-based device is `AT+EGMR`.

Our IMEI randomization functionality is built around this command and implements two approaches to IMEI generation. The first deterministic method seeds the new value with the user's ISMI, while the second generates a random IMEI.

To change the IMEI on the command-line, run `blue-merle` and follow the instructions. Alternatively, you can use the hardware switch button to set a random IMEI.

SRLabs researchers verified that the Mudi router's IMEI can be changed persistently by connecting the device to a custom telco base station set-up. The changed IMEI is recorded within the new base station database entry, confirming that the IMEI change is observed both on the device- and ISP-level.

Furthermore, to ensure that there is no leakage of the old IMEI after changing the SIM card and setting a new IMEI, the Mudi router's radio is turned off in advance. Both the command-line and hardware switch version of *blue-merle* will guide you through the IMEI update process in order to minimize the risk of IMEI leaks.

Running *blue-merle* will disrupt the device's connection with the ISP during the time the IMEI is changed, and by default the connection is only reestablished once the device is rebooted.

This process can be observed in Figure 1, where there is a large break in connectivity between entries 70 and 80. This break is the result of turning the radio off.

![Figure 1. The router's radio is turned off and the IMEI is randomized between entries 70 and 80. The ISP cannot connect to it.](https://github.com/srlabs/blue-merle/blob/main/IMEI%20randomization.png)

[Figure 1](https://github.com/srlabs/blue-merle/blob/main/IMEI%20randomization.png) The router's radio is turned off and the IMEI is randomized between entries 70 and 80. The ISP cannot connect to it.

### Basic Service Set Identifier (BSSID) randomization

The Mudi router BSSID is set by the hostapd process using the `mac80211_prepare_vif()` function in `/rom/lib/netifd/wireless/mac80211.sh`. The resulting BSSID is stored in `/etc/config/wireless`.

The implemented BSSID randomization function generates a valid unicast address value and overrides the current MAC values set within the `wlan0` and `wlan1` interfaces. This is done by issuing OpenWrt uci set commands targeting the macaddr fields of `wireless.@wifi-iface[0]` and `wireless.@wifi-iface[1]`. The Mudi router's wifi is then reset to implement the changes.

The BSSID randomization feature is run on boot, ensuring that a new BSSID is generated each time the device is started.

### MAC address log wiping

Connecting devices' MAC addresses are stored within the Mudi router at `/tmp/tertf(_bak)` and `/etc/tertf(_bak)`. The MAC address log wiper first symbolically links the gl_tertf file responsible for the gltertf process, which reads and writes MAC addresses to the above-mentioned directories. It then kills the gltertf process if active, checks if either directory contains any data, and uses shred to delete any data if found.

The MAC address log wiper is run on boot, ensuring that the Mudi device's initial MAC read/write functionality is disrupted each time the device is started.

## Acknowledgement: blue merle

The Mudi device shares a name with a Hungarian dog breed typically used to guard and herd flocks of livestock. Mudi dogs are agile, fast-learners and extremely friendly.

"Blue merle" is one of the five coat colours recognized for the Mudi dog breed by the Federation Cynologique Internationale and is characterized by its mottled or patched appearance. The black splashes on the blueish-gray coat of the blue merle Mudi inspired the name of this project because of its obscuring appearance and camouflaging symbolism.
Empty file added files/etc/config/blue-merle
Empty file.
17 changes: 17 additions & 0 deletions files/etc/init.d/blue-merle
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/sh /etc/rc.common

. /lib/blue-merle/functions.sh

START=81
STOP=99

start() {
/lib/blue-merle/mac-wipe.sh
CHECKMACSYMLINK
RESET_BSSIDS
}

stop() {
/lib/blue-merle/mac-wipe.sh
}

92 changes: 92 additions & 0 deletions files/lib/blue-merle/functions.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#!/usr/bin/env ash

# This script provides helper functions for blue-merle

# check that MAC wiping/linking to dev/null is still in place
CHECKMACSYMLINK () {
local loc_file="/etc/init.d/gl_tertf"
if [ $(readlink -f "$loc_file") == "/dev/null" ]
then
echo "TEST: EXISTS"
else
echo "TEST: DOES NOT EXIST"
cp "$loc_file" "$loc_file.bak" # todo: consider if we need to move this backup elsewhere?
ln -sf /dev/null "$loc_file"
fi
}

# Restore gl_tertf from back-up
RESTORE_GL_TERTF () {
local loc_file="/etc/init.d/gl_tertf"
local loc_backup="/etc/init.d/gl_tertf.bak"
#local loc_location="/etc/init.d"
rm "$loc_file"
mv "$loc_backup" "$loc_file"
}

UNICAST_MAC_GEN () {
loc_mac_numgen=`python3 -c "import random; print(f'{random.randint(0,2**48) & 0b111111101111111111111111111111111111111111111111:0x}'.zfill(12))"`
loc_mac_formatted=$(echo "$loc_mac_numgen" | sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\).*$/\1:\2:\3:\4:\5:\6/')
echo "$loc_mac_formatted"
}

# randomize BSSID
RESET_BSSIDS () {
uci set wireless.@wifi-iface[1].macaddr=`UNICAST_MAC_GEN`
uci set wireless.@wifi-iface[0].macaddr=`UNICAST_MAC_GEN`
uci commit wireless
wifi # need to reset wifi for changes to apply
}

READ_IMEI () {
local answer=1
while [[ "$answer" -eq 1 ]]; do
local imei=$(gl_modem AT AT+GSN | grep -w -E "[0-9]{14,15}")
if [[ $? -eq 1 ]]; then
echo -n "Failed to read IMEI. Try again? (Y/n): "
read answer
case $answer in
n*) answer=0;;
N*) answer=0;;
*) answer=1;;
esac
if [[ $answer -eq 0 ]]; then
exit 1
fi
else
answer=0
fi
done
echo $imei
}

READ_IMSI () {
local answer=1
while [[ "$answer" -eq 1 ]]; do
local imsi=$(gl_modem AT AT+CIMI | grep -w -E "[0-9]{6,15}")
if [[ $? -eq 1 ]]; then
echo -n "Failed to read IMSI. Try again? (Y/n): "
read answer
case $answer in
n*) answer=0;;
N*) answer=0;;
*) answer=1;;
esac
if [[ $answer -eq 0 ]]; then
exit 1
fi
else
answer=0
fi
done
echo $imsi
}

CHECK_ABORT () {
sim_change_switch=`cat /tmp/sim_change_switch`
if [[ "$sim_change_switch" = "off" ]]; then
e750-mcu "SIM change aborted."
sleep 1
exit 1
fi
}
Loading

0 comments on commit cb4d737

Please sign in to comment.