Securing LDAP with LDAPS via Traefik
TLDR; To use the Unifi LTE Backup Pro with your own SIM card, edit the binary /usr/bin/uiwwand and bounce it.
Resources Consulted
- https://old.reddit.com/r/Ubiquiti/comments/1ddtzrr/using_ultebackup_pro_us_model_with_nonatt_sim/
NOTE: I’ve only tested this with T-mobile. YMMV
The Problem
The Unifi-LTE-Backup-Pro allows users to insert their own SIM card into the device. Unfortunately users are carrier-locked into using AT&T SIM cards, and I’m more of a T-Mobile guy. The Sierra Wireless RC7611 modem chip the LTE router uses doesn’t appear to be locked to a fixed carrier.
Gathering Information
Issuing AT-Commands
AT Commands are a special set of commands that a lot of telecom modems use.
RC76xx AT-Command Reference Manual: https://www.bipom.com/documents/sierra/AirPrime%20-%20RC76xx%20-%20AT%20Command%20Reference%20Guide%20-%20Rev4.0.pdf
If we SSH into the LTE Router, we can issue AT-commands to gleam some valuable info. The modem in our LTE-Backup-Pro is mounted on /dev/ttyUSB2 To read AT-command output and send AT-commands, run the following after SSH-ing into the LTE router: cat < /dev/ttyUSB2. In a separate SSH session run echo "ATI" > /dev/ttyUSB2. You should receive output similar to the following (the redactions are my own):
root@U-LTE-Pro:~# cat < /dev/ttyUSB2
ATI
Manufacturer: Sierra Wireless, Incorporated
Model: RC7611
Revision: SWI9X07H_00.08.20.00 d73df7 jenkins 2021/10/14 00:48:45
IMEI: [REDACTED]
IMEI SV: 18
FSN: [REDACTED]
+GCAP: +CGSM
OK
This printout confirms that the device uses an RC7611 modem chip and is running what appears to be generic firmware?
uiwwand
What is this binary?
The U-LTE-Backup-Pro runs a watchdog script that starts/checks/bounces the binary /usr/bin/uiwwand.
root@U-LTE-Pro:~# ps w | grep "watch"
1403 root 1248 S {modem_watchdog.} /bin/sh /etc/ltecfg/modem_watchdog.sh
13578 root 1264 R sh /usr/etc/syswrapper.sh ssh-trace-cmd -c ps w | grep "watch" -n 4 -i
13580 root 1208 S grep watch
If we search for strings in the /usr/bin/uiwwand binary, we can find SIM-related terms:
root@U-LTE-Pro:~# grep "SIM" /usr/bin/uiwwand
EVENT_SIM_READY
EVENT_SIM_REMOVED
STATE_SIM_ACTIVATION
SIM card removed
AUTO-SIM
uim: PIN '%s' is eligible to be verified for SIM with ICCID %s
uim: PIN '%s' was detected as incorrect previously for SIM with ICCID %s, refusing to verify
uim: PIN '%s' is eligible to be verified for SIM with ICCID %s (PIN1 retries = 3)
Incompatible SIM (MCC: %d, MNC: %d)
SIM powered off
SIM powered on
MNC length from SIM: %d
MCC %d, MNC %d from SIM
SIM data read successfully
SIM data could not be read
AUTO-SIM
ULTE-Pro-US: Canada SIM detected: mcc=%i mnc=%i (PRI=%s)
ULTE-Pro-US: %s'AT&T (US)' SIM detected:mcc=%i mnc=%i (PRI=%s)
ULTE-Pro-US: SIM is incompatible
Skip enable_autoconnect() because the SIM card is not compatible
Skip seq_set_profile() because the SIM card is not compatible
This binary is clearly important
SCP the binary
The U-LTE-Backup-Pro runs some sort of read-only RamFS Linux OS. In order to SCP files on and off the device, you will need to run SCP in legacy mode as SFTP is not available, ie:
scp -O root@192.168.0.137:/usr/bin/uiwwand .
Ghidra
We can run the binary thru Ghidra and search for relevant strings. Eventually, you’ll come across the following functions. I’ve gone ahead and annotated the function and variable names so we can see what’s going on.
void FUN_0041a7c4(void)
{
int is_canadian_mcc;
char is_mcc_canadian;
undefined *prepend_str;
char profile_to_load [20];
if ((((DAT_00433e74 == '\0') || (DAT_00433e76 == '\0')) || (DAT_00433e77 == '\0')) ||
(DAT_00433e75 == '\0')) {
is_sim_readable = '\0';
}
else {
is_sim_readable = '\x01';
}
if (is_sim_readable == '\0') {
some_sort_of_print_function(1,3,"SIM data could not be read");
}
else {
some_sort_of_print_function(1,6,"SIM data read successfully");
}
DAT_00433e79 = 1;
is_sim_unsupported = '\0';
if (DAT_00434189 != '\0') {
is_mcc_canadian = func_is_mcc_canadian(mcc_value); // <- this function checks to see if the MCC (mobile country code) is equal to 302 (ie Canada)
if (is_mcc_canadian == 0) {
// MCC is not Canadian (302). `/usr/bin/uiwwand` assumes the SIM is American
is_sim_ATT = FUN_0040c66c(mcc_value,mnc_value); // <- Checks to see if MMC/MNC combo is part of AT&T. Basically a tabular lookup
is_sim_unsupported = is_sim_ATT == '\0'; // <- If SIM is not AT&T, then it is unsupported
builtin_strncpy(profile_to_load,"ATT",4); // <- If the SIM is American, uiwwand assumes it's AT&T and loads the ATT profile
if (is_sim_ATT == '\0') {
prepend_str = &DAT_0041fa4c; // MNC/MCC combo is not AT&T, code will print non-AT&T (US) SIM detected
}
else {
prepend_str = &DAT_0041f438; // MNC/MCC combo is AT&T, code will print AT&T (US) SIM detected
}
some_sort_of_print_function(1,6,"ULTE-Pro-US: %s\'AT&T (US)\' SIM detected:mcc=%i mnc=%i (PRI=%s)",prepend_str,
mcc_value,mnc_value,profile_to_load);
}
else {
// MCC is 302. `uiwwand` assumes the SIM is Canadian
is_sim_unsupported = '\0';
builtin_strncpy(profile_to_load,"AUTO-SIM",9);
some_sort_of_print_function(1,6,"ULTE-Pro-US: Canada SIM detected: mcc=%i mnc=%i (PRI=%s)",mcc_value,
mnc_value,profile_to_load);
}
if (is_sim_unsupported != '\0') { // watch out for the double-negative variable
// If we enter the function, then the SIM is unsupported
some_sort_of_print_function(1,6,"ULTE-Pro-US: SIM is incompatible");
}
is_currently_loaded_profile_equal_profile_to_load = strncmp(¤tly_loaded_profile,profile_to_load,0x14);
if (is_currently_loaded_profile_equal_profile_to_load != 0) {
// Profile needs to be reloaded
snprintf(¤tly_loaded_profile,0x14,"%s",profile_to_load);
DAT_00433fd4 = 0;
FUN_00414db4(&PTR_FUN_004331e8);
}
}
if (is_sim_unsupported != '\0') { // watch out for the double-negative variable
// If we enter the function, then the SIM is unsupported
FUN_0040c5c4(mcc_value,mnc_value);
}
FUN_0040c150(&DAT_00433d5c);
if (is_sim_unsupported != '\x01') { // watch out for the double-negative variable
// If we enter this function, then SIM is supported
FUN_00406efc(6);
}
return;
}
If we ignore the cruft of prints and loading of profiles, we essentially just need to focus on the following logic:
void FUN_0041a7c4(void)
{
/* A bunch of SIM readability checks */
if (DAT_00434189 != '\0') {
is_mcc_canadian = func_is_mcc_canadian(mcc_value); // <- this function checks to see if the MCC (mobile country code) is equal to 302 (ie Canada)
if (is_mcc_canadian == 0) {
/* If SIM is not Canadian AND is part of AT&T, load ATT Profile, else error out. */
}
else {
/* IF SIM is Canadian, load AUTO-SIM Profile */
}
/* Check if SIM is supported, check if profile needs to be loaded, etc. */
}
/* Various printouts and checks related to SIM supportability */
return;
}
Notice that if we can trick uiwwand into thinking the SIM card is Canadian, then it’ll load the “AUTO-SIM” profile which allows it to work w/ non-AT&T SIMs. If we disassemble the function func_is_mcc_canadian, the code is pretty straight-forward.
[ ... Start of function, a bunch of stack pointer stuff ...]
0040c944 24 02 01 2e li v0,0x12e // Load 302 into v0
0040c948 14 62 00 04 bne v1,v0,LAB_0040c95c // If v1 != 302 (v0), branch to LAB_0040c95c
0040c94c 00 00 00 00 _nop
0040c950 24 02 00 01 li v0,0x1 // Load 1 into v0
0040c954 10 00 00 02 b LAB_0040c960 // Skip clearing v0
0040c958 00 00 00 00 _nop
LAB_0040c95c XREF[1]: 0040c948(j)
0040c95c 00 00 10 21 clear v0
LAB_0040c960 XREF[1]: 0040c954(j)
[ ... A bunch of stack pointer stuff, set v0 to return value, then jr ra ... ]
u/MrNerdHair points out in his post that change the binary 14 62 00 04 -> 14 62 00 01 sets bne’s jump offset to 1, so it basically becomes a no-op. The consequence of this is that the function will always return true, ie we always assume the SIM is Canadian and the load “AUTO-SIM” profile. This binary sequence is distinctive and only appears once in the file.
Conclusion
In order to get the U-LTE-Backup-Pro to run off of a non-AT&T SIM is to run the following script:
hexdump -v -e '/1 "%02x"' /usr/bin/uiwwand > /tmp/uiwwand.hex && \
grep -c "2402012e14620004" /tmp/uiwwand.hex && \
echo "Pattern found, starting patch..." && \
sed -i 's/2402012e14620004/2402012e14620001/' /tmp/uiwwand.hex && \
echo "File patched. Converting back to binary" && \
rm -f /tmp/uiwwand.bin && \
while read -n2 hex; do
printf "\\x$hex" >> /tmp/uiwwand.bin
done < /tmp/uiwwand.hex && \
echo "Double-checking patch: " && \
hexdump /tmp/uiwwand.bin | grep "2402 012e 1462" && \
echo "Replacing and bouncing..." && \
cp /tmp/uiwwand.bin /usr/bin/uiwwand && \
chmod +x /usr/bin/uiwwand && \
killall uiwwand && \
echo "done!"
Unfortunately the U-LTE-Backup-Pro’s filesystem is read-only and resets on reboot. You’ll need to run some sort of cron job on a separate host, maybe a UDM-Pro?