Making defensive copies of mutable method parameters mitigates against a variety of security vulnerabilities; see OBJ06-J. Defensively copy mutable inputs and mutable internal components for additional information. However, inappropriate use of the clone() method can allow an attacker to exploit vulnerabilities by providing arguments that appear normal but subsequently return unexpected values. Such objects may consequently bypass validation and security checks. When such a class might be passed as an argument to a method, treat the argument as untrusted, and do not use the clone() method provided by the class. Also, do not use the clone() method of nonfinal classes to make defensive copies.

This guideline is a specific instance of OBJ57-J. Do not rely on methods that can be overridden by untrusted code.

Noncompliant Code Example

This noncompliant code example defines a validateValue() method that validates a time value:

private Boolean validateValue(long time) {
  // Perform validation
  return true; // If the time is valid	
}

private void storeDateInDB(java.util.Date date) throws SQLException {
  final java.util.Date copy = (java.util.Date)date.clone();
  if (validateValue(copy.getTime())) {
    Connection con = DriverManager.getConnection("jdbc:microsoft:sqlserver://<HOST>:1433","<UID>","<PWD>");
    PreparedStatement pstmt = con.prepareStatement("UPDATE ACCESSDB SET TIME = ?");
    pstmt.setLong(1, copy.getTime());
    // ...
  } 
}	

The storeDateInDB() method accepts an untrusted date argument and attempts to make a defensive copy using its clone() method. This allows an attacker to take control of the program by creating a malicious date class that extends Date. If the attacker's code runs with the same privileges as storeDateInDB(), the attacker merely embeds malicious code inside their clone() method:

class MaliciousDate extends java.util.Date {
  @Override
  public MaliciousDate clone() {
    // Malicious code goes here
  }
}

If, however, the attacker can only provide a malicious date with lessened privileges, the attacker can bypass validation but still confound the remainder of the program. Consider this example:

public class MaliciousDate extends java.util.Date {
  private static int count = 0;
 
  @Override
  public long getTime() {
    java.util.Date d = new java.util.Date();
    return (count++ == 1) ? d.getTime() : d.getTime() - 1000;
  }
}

This malicious date will appear to be a benign date class the first time that getTime() is invoked. This allows it to bypass validation in the storeDateInDB() method. However, the time that is actually stored in the database will be incorrect.

Compliant Solution

This compliant solution avoids using the clone() method. Instead, it creates a new java.util.Date object that is subsequently used for access control checks and insertion into the database:

private void storeDateInDB(java.util.Date date) throws SQLException {
  final java.util.Date copy = new java.util.Date(date.getTime());
  if (validateValue(copy.getTime())) {
    Connection con = DriverManager.getConnection("jdbc:microsoft:sqlserver://<HOST>:1433","<UID>","<PWD>");
    PreparedStatement pstmt = con.prepareStatement("UPDATE ACCESSDB SET TIME = ?");
    pstmt.setLong(1, copy.getTime());
    // ...
  }
}	

Noncompliant Code Example (CVE-2012-0507)

This noncompliant code example shows a constructor of the Java core class AtomicReferenceArray present in the Java 1.7.0 update 2:

public AtomicReferenceArray(E[] array) {
    // Visibility guaranteed by final field guarantees
    this.array = array.clone();
}

This class was subsequently used by the Flashback exploit that infected 550,000 Macintosh computers in April 2012.1

Compliant Solution (CVE-2012-0507)

In Java 1.7.0 update 3, the constructor was modified to use the Arrays.copyOf() method instead of the clone() method, as follows:

public AtomicReferenceArray(E[] array) {
    // Visibility guaranteed by final field guarantees
    this.array = Arrays.copyOf(array, array.length, Object[].class);
}

Applicability

Using the clone() method to copy untrusted arguments affords attackers the opportunity to execute arbitrary code.

Automated Detection

ToolVersionCheckerDescription
Parasoft Jtest
2023.1
CERT.MET52.CIFCOnly "clone()" instances of "final" classes

Bibliography

1 "Exploiting Java Vulnerability CVE-2012-0507 Using Metasploit" is shared by user BreakTheSec on Slideshare.net (July 14, 2012). www.slideshare.net/BreakTheSec/exploiting-java-vulnerability.



6 Comments

  1. The attack scenario for the NCCE was completely wrong (it applies to a different rule). Should be fixed now.

  2. David I think the following code showed clearly how the validation could be bypassed. The attacker subclasses Date and provides the following implementation.

     

    public class MaliciousDate extends java.util.Date {
      private static int count = 0;
    
      @Override
      public long getTime() {
        java.util.Date d = new java.util.Date();
        return (count++ == 1) ? d.getTime() : d.getTime() - 1000;
      }
      
    }

    Why did you delete this?

    I have also clarified the text. Please re-review.

    1. Because, while your attack scenario is plausible, so is the replacement scenario, and its more drastic. An attacker who can provide a malicious Date class could use it to impersonate java.util.Date. But she can more easily pwn the system when her object's clone() method is called.

      1. I am not sure how your attack will work. If untrusted code sneaks in a spurious date instance arg, and our trusted code invokes its clone method, a security exception would occur. That is because privileges are dropped as soon as untrusted code is encountered.

        The NCE explicitly casts to (java.util.Date) so the spurious class must be a subclass of j.u.l.Date.

        My scenario was about bypassing the validation because of mutability of Date (failure of clone()) and j.u.l.Date not being a final class.

        1. I guess it depends on what security restrictions there are on our MaliciousDate class. If we assume it has less privs than the storeDataInDB(), then you're right, MaliciousDate.clone() can't do anything 'harmful'. (It could still fail to clone the object and do other nasties along the same line, but that's not nearly as egregious).

          OTOH if the code is all privileged, (eg for a desktop application), then your example is overkill, and MaliciousDate need only contain a clone() method.

          I resurrected your scenario, to handle the case where MaliciousDate is sandboxed.

          1. Fair enough. Thanks.