Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Depending on how the client code works, signatures may or may not be automatically checked programatically. For example, any instances of URLClassLoader and its subclasses and java.util.jar automatically verify a signature whenever the JAR file is signed. If however, the developer implements a custom classloader that goes on to subclass java.lang.ClassLoader, this step is not performed automatically. Moreover, in the URLClassLoader case, the automatic verification just involves an integrity check and does not authenticate the loaded class. This is because the check uses a public key that is contained within the JAR. The legit JAR file may be replaced with a malicious JAR file containing a different public key and digest values.

Noncompliant Code Example

This noncompliant code example demonstrates the JarRunner application that can be used to dynamically execute a particular class residing within a JAR file (abridged version of the class in [Tutorials 08]). It creates a JarClassLoader that loads an application update, plugin or patch over an untrusted network such as the Internet. The URL to fetch the code is specified as the first argument (for example, http://somewebsite.com/software-updates.jar) and any other arguments specify the arguments that are to be passed to the class to be loaded. Reflection is used to invoke the main method of the loaded class. Unfortunately, by default, JarClassLoader verifies the signature using the public key contained within the JAR file.

Code Block
bgColor#FFcccc
public class JarRunner {
  public static void main(String[] args) throws IOException, 
    ClassNotFoundException,NoSuchMethodException, InvocationTargetException {
  
    URL url = new URL(args[0]);
    
    // Create the class loader for the application jar file
    JarClassLoader cl = new JarClassLoader(url);
    
    // Get the application's main class name
    String name = cl.getMainClassName();
    
    // Get arguments for the application
    String[] newArgs = new String[args.length - 1];
    System.arraycopy(args, 1, newArgs, 0, newArgs.length);
    
    // Invoke application's main class
    cl.invokeClass(name, newArgs);
  }
}

class JarClassLoader extends URLClassLoader {
  private URL url;
  public JarClassLoader(URL url) {
    super(new URL[] { url });
    this.url = url;
  }

  public String getMainClassName() throws IOException {
    URL u = new URL("jar", "", url + "!/");
    JarURLConnection uc = (JarURLConnection) u.openConnection();
    Attributes attr = uc.getMainAttributes();
    return attr != null ? attr.getValue(Attributes.Name.MAIN_CLASS) : null;
  }

  public void invokeClass(String name, String[] args)
      throws ClassNotFoundException, NoSuchMethodException,
      InvocationTargetException {
    Class c = loadClass(name);
    Method m = c.getMethod("main", new Class[] { args.getClass() });
    m.setAccessible(true);
    int mods = m.getModifiers();
    if (m.getReturnType() != void.class || !Modifier.isStatic(mods)
        || !Modifier.isPublic(mods)) { throw new NoSuchMethodException("main"); }
    try {
      m.invoke(null, new Object[] { args });
    } catch (IllegalAccessException e) { System.out.println("Access denied"); }
  }
}

Compliant Solution

If the program expects the user to manually install the new JAR file, the user can explicitly check the signature from the command line. Any malicious tampering results in a SecurityException when the jarsigner tool is invoked with the -verify option.

...

It is not always the case that arbitrary code gets executed. By default, the URLClassLoader and all its subclasses are only given enough permissions to interact with the URL that was specified when the URLClassLoader object was created. This means that the program can only interact with the specified host. However, this does not mitigate the risk completely as the loaded file may have been granted appropriate privileges to perform other sensitive operations such as updating an existing local JAR file.

Risk Assessment

Not verifying the digital signature either manually or programmatically can lead to the execution of malicious code.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

SEC04- J

high

probable

medium

P12

L1

Automated Detection

TODO

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

References

Wiki Markup
\[[API 06|AA. Java References#API 06]\] 
\[[Gong 03|AA. Java References#Gong 03]\] 12.8.3 jarsigner
\[[Eclipse 08|AA. Java References#Eclipse 08]\] [JAR Signing|http://wiki.eclipse.org/JAR_Signing] and [Signed bundles and protecting against malicious code|http://help.eclipse.org/stable/index.jsp?topic=/org.eclipse.platform.doc.isv/guide]
\[[Halloway 01|AA. Java References#Halloway 01]\] 
\[[Flanagan 05|AA. Java References#Flanagan 05]\] Chapter 24. The java.util.jar Package
\[[Oaks 01|AA. Java References#Oaks 01]\] Chapter 12: Digital Signatures, Signed Classes
\[[Tutorials 08|AA. Java References#Tutorials 08]\] [The JarRunner Class|http://java.sun.com/docs/books/tutorial/deployment/jar/jarrunner.html], [Lesson: API and Tools Use for Secure Code and File Exchanges|http://java.sun.com/docs/books/tutorial/security/sigcert/index.html] and [Verifying Signed JAR Files|http://java.sun.com/docs/books/tutorial/deployment/jar/verify.html]
\[[JarSpec 08|AA. Java References#JarSpec 08]\] Signature Validation 
\[[Bea 08|AA. Java References#Bea 08]\] 
\[[Muchow 01|AA. Java References#Muchow 01]\] 
\[[MITRE 09|AA. Java References#MITRE 09]\] [CWE ID 300|http://cwe.mitre.org/data/definitions/300.html] "Channel Accessible by Non-Endpoint (aka 'Man-in-the-Middle')", [CWE ID 319|http://cwe.mitre.org/data/definitions/319.html] "Cleartext Transmission of Sensitive Information", [CWE ID 494|http://cwe.mitre.org/data/definitions/494.html] "Download of Code Without Integrity Check", [CWE ID 347|http://cwe.mitre.org/data/definitions/347.html] "Improperly Verified Signature"

...