Reversing ArubaOS Firmware and Licensing

2024-02-05 10:13:45

References

  1. 一种获取 FortiGate 权限的方法 & License 授权分析 - CataLpa: This blog post reverse-engineered the FortiGate firmware and licensing mechanism, and published a tool to generate the license keys.
  2. Reversing ArubaOS Firmware - SerializingMe: This blog post explores the ArubaOS firmware using Binwalk, but it doesn’t go into the details.
  3. Aruba Authentication Bypass / Insecure Transport / Tons Of Issues ≈ Packet Storm: This blog post published a collection of vulnerabilities in ArubaOS, including arbitrary modification of /etc/ntp.conf, static password of privileged “support” account and hardcoded “arubasecretadmin” account in /etc/passwd. The most important part is:
    1. It says the IV required for 3DES consists of 8
      random bytes, and is stored as the first 8 byte of the encrypted password
      , which may also be used in ArubaOS for lisensing mechanism, I guess.
    2. It leaked the hardcoded 3DES key in the firmware.
  4. Remote Code Execution in Aruba Mobility Controller (ArubaOS) - CVE-2018-7081: This blog post describes simulating the ArubaOS in QEMU and intercepting the communication of PAPI.

Exploration

By chance, I obtained a brand new Aruba 650 controller with full licenses, at a few years ago with an irresistible price. The licensing mechanism is complete off-line, which means that all necessary information is hashed/encoded as a part of the license key, including the serial number, feature set, expiration date, and so on.

  • Device serial number: AR00XXXXX
  • License: XXXXXXXX-XXXXXXXX-XXXXXXXX-XXXXXXXX-XXXXXXXX-XXX
    • Length with hyphens: 48
    • Length without hyphens: 43
    • Length of license without hyphens in base64: 64
1
2
3
filename: ArubaOS_6xx_6.4.4.25_79899
SHA-1: defbb8709b90b14c4f78fa5ae64b0c39276d90df
MD5: f038d7810c4f036005a6a4ef86a18137

By simply running binwalk -re --dd=".*" ArubaOS_6xx_6.4.4.25_79899, we can extract the firmware from the image.

1
2
3
DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
512 0x200 ELF, 32-bit MSB MIPS-IV executable, MIPS, version 1 (SYSV)

Then, do the same thing for the extracted ELF file 200: binwalk -e 200, now we obtained a compressed file 5B4000.7z. On Windows 10, we can use Bandizip to extract it, and we got a core_image_files.tar, which is the root filesystem of the ArubaOS. This step seems cannot be done on macOS, for unknown reasons. The file tree is attached.

As for its name, core_image_files/mswitch/bin/licensemgr, it seems to be the license manager of the ArubaOS. Based on the existing knowledge and with the help of ChatGPT, we can perform deobfucation to some extent.

1
2
3
filename: licensemgr
SHA-1: a3f12c8357297a361ec3d112313aa4cc8af0e7e0
MD5: be48ae6c4cb5822885237001a847f2d9

By looking into IDA, we have the pseudo code as follows:

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
_BYTE *__fastcall _license_user_to_base64(char *a1, int a2)
{
char v2; // $v1
int v4; // $v0
int i; // $a1
_BYTE *v6; // $a2
int v7; // $v1
int v8; // $v1
_BYTE *result; // $v0

v2 = *a1;
v4 = *a1;
for (i = 0; *a1; v4 = *a1)
{
v6 = (_BYTE *)(i + a2);
if (v4 != 45)
{
++i;
*v6 = v2;
}
v2 = *++a1;
}
if (i == 32)
goto LABEL_10;
v7 = 1;
if (i != 43)
v7 = 6 - i % 6;
v8 = v7 - 1;
result = (_BYTE *)(a2 + i);
if (v8 != -1)
{
do
{
--v8;
*(_BYTE *)(i + a2) = 61;
++i;
} while (v8 != -1);
LABEL_10:
result = (_BYTE *)(a2 + i);
}
*result = 0;
return result;
}

With the help of ChatGPT, we obtained the following deobfuscated code, with some comments generated by ChatGPT as well:

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// Function to convert a string to base64 with certain conditions
// Parameters:
// - a1: Input string
// - a2: Base address for output

_BYTE *__fastcall _license_user_to_base64(char *a1, int a2)
{
char currentChar; // Current character in the input string
int i; // Counter for the loop
_BYTE *output; // Pointer to the output buffer
int paddingCount; // Number of '=' padding characters to be added

currentChar = *a1; // Initialize currentChar with the first character of the input string
i = 0; // Initialize the loop counter
output = (_BYTE *)(i + a2); // Initialize the output pointer based on the provided base address

// Iterate through the characters of the input string
while (*a1)
{
// If the current character is not '-', copy it to the output buffer
if (currentChar != 45)
{
++i; // Increment the counter
*output = currentChar; // Copy the character to the output buffer
}
currentChar = *++a1; // Move to the next character in the input string
}

// Check if the total count is 32
if (i == 32)
goto LABEL_10;

// Calculate the number of '=' padding characters to be added
paddingCount = 1;
if (i != 43) // the length without hyphens
paddingCount = 6 - i % 6;

// Add the required '=' padding characters to the output buffer
while (paddingCount != -1)
{
--paddingCount;
*(_BYTE *)(i + a2) = 61; // '=' character
++i; // Increment the counter
}

LABEL_10:
result = (_BYTE *)(a2 + i); // Set the result pointer to the end of the output buffer
*result = 0; // Null-terminate the output buffer
return result; // Return the result pointer
}

So basically, it removes the hyphens from the input string, and adds padding for making it as a valid base64 string. By checking XREF information, we can found that this function is called by _license_decrypt_bundle_key, _license_decrypt_feature_key and _license_decrypt_platform_key.

Let’s focus on _license_decrypt_bundle_key first, it first calls _license_user_to_base64 to convert the input string to base64, then calls _license_str_to_byte to convert the base64 string to byte array and check format validity, and finally calls _license_decrypt to decrypt the byte array.

1
license_decrypt((int)licenseInBytes, lic_b64_length_int_64 / 2, (int)output, 51)

Since then I stucked, the _license_base64_dec is so complicated.

Prev
2024-02-05 10:13:45
Next