Lucene search

K
attackerkbAttackerKBAKB:45C06F42-EE61-4551-8298-0B856111798F
HistoryAug 28, 2012 - 12:00 a.m.

Java 7 Applet Remote Code Execution

2012-08-2800:00:00
attackerkb.com
14

10 High

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

COMPLETE

Integrity Impact

COMPLETE

Availability Impact

COMPLETE

AV:N/AC:L/Au:N/C:C/I:C/A:C

0.975 High

EPSS

Percentile

100.0%

Multiple vulnerabilities in the Java Runtime Environment (JRE) component in Oracle Java SE 7 Update 6 and earlier allow remote attackers to execute arbitrary code via a crafted applet that bypasses SecurityManager restrictions by (1) using com.sun.beans.finder.ClassFinder.findClass and leveraging an exception with the forName method to access restricted classes from arbitrary packages such as sun.awt.SunToolkit, then (2) using “reflection with a trusted immediate caller” to leverage the getField method to access and modify private fields, as exploited in the wild in August 2012 using Gondzz.class and Gondvv.class.

Recent assessments:

wchen-r7 at September 12, 2019 6:07pm UTC reported:

References

References about the attack:

References about the Java API used:

getField() wasn’t always public, see the following for an example:

<http://javasourcecode.org/html/open-source/jdk/jdk-6u23/sun/awt/SunToolkit.java.html&gt;

Summary

This is a vulnerability specifically targeting Java 7. Some reports reveal the origin of the 0day
exploit comes from a popular exploit kit named “Gondad Exploit Kit” (google “ZZVnxA1X”), some people
also claim the 0day originally comes from VulnDisco, which is an exploit pack used by Immunity
Canvas. No matter, the public noticed the attack as a malware being hosted at 59.120.154.62, which
is a server located in Taiwan. The decompiled source also has strings (lyrics) such as
“woyouyizhixiaomaolv” and “conglaiyebuqi” indicating that whoever wrote it must know Mandarin Chinese
quite well, possibly China because that’s “Pinyin” input method, and he probably grew up there
due the choice of the song. It would be reasonable to say that someone in China has been using the
exploit, and hosts the malicious code on a compromised server in Taiwan.

The actual link to the live exploit is:
hxxp://59.120.154.62/meeting/index.html

The exploit takes advantage of two issues: The ClassFinder and MethodFinder.findMethod(). Both
were newly introduced in JDK 7. ClassFinder is a replacement for classForName back in JDK 6. It
allows untrusted code to obtain a reference and have access to a restricted package in JDK 7, which
can be used to abuse sun.awt.SunToolkit (a restricted package). With sun.awt.SunToolkit, we can
actually invoke getField() by abusing findMethod() in Statement.invokeInternal() (but getField()
must be public, and that’s not always the case in JDK 6) in order to access Statement.acc’s private
field, modify AccessControlContext, and then disable Security Manager. Once Security Manager is
disabled, we can execute arbitrary Java code.

Our exploit has been tested successfully against multiple platforms, including: IE, Firefox, Safari,
Chrome; Windows, Ubuntu, OS X, etc. We have even received reports claiming the exploit also works
against Solaris.

Timeline

Aug xx 2011 – Vulnerable code was introduced in JDK7
Apr xx 2012 – Oracle already aware of the vulnerabilities: <http://www.theregister.co.uk/2012/08/30/oracle_knew_about_flaws/&gt;
Jun xx 2012 – Infected server hosting malware code: <http://urlquery.net/report.php?id=70896&gt;
Aug 26 2012 – First blog emerged about the Java 0day: <http://blog.fireeye.com/research/2012/08/zero-day-season-is-not-over-yet.html&gt;
Aug 26 2012 – PoC extracted from the malicious site by Joshua Drake: <https://twitter.com/jduck1337/status/239875285913317376&gt;
Aug 27 2012 – Metasploit exploit available: <https://community.rapid7.com/community/metasploit/blog/2012/08/27/lets-start-the-week-with-a-new-java-0day&gt;
Aug 28 2012 – CVE assigned as CVE-2012-4681
Aug 30 2012 – Java 7 Update 7 available (out of band patch)

Exceptions happens on this line of the Exploit:

GetClass("sun.awt.SunToolkit")

    private Class GetClass(String paramString)
        throws Throwable
    {
        Object arrayOfObject[] = new Object[1];
        arrayOfObject[0] = paramString;
        Expression localExpression = new Expression(Class.class, "forName", arrayOfObject); &lt;===
        localExpression.execute(); // (3) Fails !!! &lt;====
        return (Class)localExpression.getValue();
    }

Through Expression it tries to do Class.forName(“sun.awt.SunToolkit”). Despite the use of
Expression, according to the Exception on Java6 root cause seems to be on Class.forName.

When checking java 7 api you can read:

public static Class classForName(String name) throws ClassNotFoundException
Deprecated! As - of JDK version 7, replaced by ClassFinder#resolveClass(String) .

Returns the Class object associated with the class or interface with the given string name, using the default class loader

So maybe something was lost con ClassFinder#resolveClass….

Digging into source code of openjdk:

  • On Java 7
    ======

    jdk/src/share/classes/java/lang/Class.java

    public static Class&lt;?&gt; forName(String className)
                throws ClassNotFoundException {
        return forName0(className, true, ClassLoader.getCallerClassLoader());
    }
    
    
    /** Called after security checks have been made. */
    private static native Class&lt;?&gt; forName0(String name, boolean initialize,
                                            ClassLoader loader)
        throws ClassNotFoundException;
    

    jdk/src/share/native/java/lang/Class.c

    JNIEXPORT jclass JNICALL
    Java_java_lang_Class_forName0(JNIEnv *env, jclass this, jstring classname,
    jboolean initialize, jobject loader)


    cls = JVM_FindClassFromClassLoader(env, clname, initialize,
    loader, JNI_FALSE);

hotspot/src/share/vm/prims/jvm.cpp

JVM_ENTRY(jclass, JVM_FindClassFromClassLoader(JNIEnv* env, const char* name,
                                               jboolean init, jobject loader,
                                               jboolean throwError))
  JVMWrapper3("JVM_FindClassFromClassLoader %s throw %s", name,
               throwError ? "error" : "exception");
  // Java libraries should ensure that name is never null...
  if (name == NULL || (int)strlen(name) &gt; Symbol::max_length()) {
    // It's impossible to create this class;  the name cannot fit
    // into the constant pool.
    if (throwError) {
      THROW_MSG_0(vmSymbols::java_lang_NoClassDefFoundError(), name);
    } else {
      THROW_MSG_0(vmSymbols::java_lang_ClassNotFoundException(), name);
    }
  }
  TempNewSymbol h_name = SymbolTable::new_symbol(name, CHECK_NULL);
  Handle h_loader(THREAD, JNIHandles::resolve(loader));
  jclass result = find_class_from_class_loader(env, h_name, init, h_loader,
                                               Handle(), throwError, THREAD);

  if (TraceClassResolution && result != NULL) {
    trace_class_resolution(java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(result)));
  }
  return result;
JVM_END

hotspot/src/share/vm/classfile/systemDictionary.cpp

jclass find_class_from_class_loader(JNIEnv* env, symbolHandle name, jboolean init, Handle loader, Handle protection_domain, jboolean throwError, TRAPS) {
  // Security Note:
  //   The Java level wrapper will perform the necessary security check allowing
  //   us to pass the NULL as the initiating class loader.
  klassOop klass = SystemDictionary::resolve_or_fail(name, loader, protection_domain, throwError != 0, CHECK_NULL);

  KlassHandle klass_handle(THREAD, klass);
  // Check if we should initialize the class
  if (init && klass_handle-&gt;oop_is_instance()) {
    klass_handle-&gt;initialize(CHECK_NULL);
  }
  return (jclass) JNIHandles::make_local(env, klass_handle-&gt;java_mirror());
}

hotspot/src/share/vm/classfile/systemDictionary.cpp

klassOop SystemDictionary::resolve_or_fail(symbolHandle class_name, Handle class_loader, Handle protection_domain, bool throw_error, TRAPS) {
  klassOop klass = resolve_or_null(class_name, class_loader, protection_domain, THREAD);
  if (HAS_PENDING_EXCEPTION || klass == NULL) {
    KlassHandle k_h(THREAD, klass);
    // can return a null klass
    klass = handle_resolution_exception(class_name, class_loader, protection_domain, throw_error, k_h, THREAD);
  }
  return klass;
}

klassOop SystemDictionary::resolve_or_null(symbolHandle class_name, Handle class_loader, Handle protection_domain, TRAPS) {
  assert(!THREAD-&gt;is_Compiler_thread(), "Can not load classes with the Compiler thread");
  if (FieldType::is_array(class_name())) {
    return resolve_array_class_or_null(class_name, class_loader, protection_domain, CHECK_NULL);
  } else {
    return resolve_instance_class_or_null(class_name, class_loader, protection_domain, CHECK_NULL);
  }
}

…. First review of resolve_instance_class_or_null doesn’t spot anything interesting at first view! Maybe
I should check carefully

  • On java6:
    =====

    jdk/src/share/native/java/lang/Class.c

    public static Class&lt;?&gt; forName(String className)
                throws ClassNotFoundException {
        return forName0(className, true, ClassLoader.getCallerClassLoader());
    }
    
    
    /** Called after security checks have been made. */
    private static native Class forName0(String name, boolean initialize,
                                            ClassLoader loader)
        throws ClassNotFoundException;
    

hotspot/src/share/vm/prims/jvm.cpp

JVM_ENTRY(jclass, JVM_FindClassFromClassLoader(JNIEnv* env, const char* name,
                                               jboolean init, jobject loader,
                                               jboolean throwError))
  JVMWrapper3("JVM_FindClassFromClassLoader %s throw %s", name,
               throwError ? "error" : "exception");
  // Java libraries should ensure that name is never null...
  if (name == NULL || (int)strlen(name) &gt; symbolOopDesc::max_length()) {
    // It's impossible to create this class;  the name cannot fit
    // into the constant pool.
    if (throwError) {
      THROW_MSG_0(vmSymbols::java_lang_NoClassDefFoundError(), name);
    } else {
      THROW_MSG_0(vmSymbols::java_lang_ClassNotFoundException(), name);
    }
  }
  symbolHandle h_name = oopFactory::new_symbol_handle(name, CHECK_NULL);
  Handle h_loader(THREAD, JNIHandles::resolve(loader));
  jclass result = find_class_from_class_loader(env, h_name, init, h_loader,
                                               Handle(), throwError, THREAD);

  if (TraceClassResolution && result != NULL) {
    trace_class_resolution(java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(result)));
  }
  return result;
JVM_END



jclass find_class_from_class_loader(JNIEnv* env, Symbol* name, jboolean init, Handle loader, Handle protection_domain, jboolean throwError, TRAPS) {
  // Security Note:
  //   The Java level wrapper will perform the necessary security check allowing
  //   us to pass the NULL as the initiating class loader.
  klassOop klass = SystemDictionary::resolve_or_fail(name, loader, protection_domain, throwError != 0, CHECK_NULL);

  KlassHandle klass_handle(THREAD, klass);
  // Check if we should initialize the class
  if (init && klass_handle-&gt;oop_is_instance()) {
    klass_handle-&gt;initialize(CHECK_NULL);
  }
  return (jclass) JNIHandles::make_local(env, klass_handle-&gt;java_mirror());
}

hotspot/src/share/vm/classfile/systemDictionary.cpp

klassOop SystemDictionary::resolve_or_fail(Symbol* class_name, Handle class_loader, Handle protection_domain, bool throw_error, TRAPS) {
  klassOop klass = resolve_or_null(class_name, class_loader, protection_domain, THREAD);
  if (HAS_PENDING_EXCEPTION || klass == NULL) {
    KlassHandle k_h(THREAD, klass);
    // can return a null klass
    klass = handle_resolution_exception(class_name, class_loader, protection_domain, throw_error, k_h, THREAD);
  }
  return klass;



klassOop SystemDictionary::resolve_or_null(Symbol* class_name, Handle class_loader, Handle protection_domain, TRAPS) {
  assert(!THREAD-&gt;is_Compiler_thread(), "Can not load classes with the Compiler thread");
  if (FieldType::is_array(class_name)) {
    return resolve_array_class_or_null(class_name, class_loader, protection_domain, CHECK_NULL);
  } else if (FieldType::is_obj(class_name)) {
    ResourceMark rm(THREAD);
    // Ignore wrapping L and ;.
    TempNewSymbol name = SymbolTable::new_symbol(class_name-&gt;as_C_string() + 1,
                                   class_name-&gt;utf8_length() - 2, CHECK_NULL);
    return resolve_instance_class_or_null(name, class_loader, protection_domain, CHECK_NULL);
  } else {
    return resolve_instance_class_or_null(class_name, class_loader, protection_domain, CHECK_NULL);
  }
}

…. First review of resolve_instance_class_or_null doesn’t spot anything interesting at first view! Maybe
I should check carefully

So going high level….

As have been said before, on JDK 7, classForName has been replaced by ClassFinder#resolveClass

public static Class classForName(String name) throws ClassNotFoundException
Deprecated! As - of JDK version 7, replaced by ClassFinder#resolveClass(String) .

ClassFinder doesn't exist on JDK 6, so digging into JDK 7:

     * @see #resolveClass(String,ClassLoader)
     */
    public static Class&lt;?&gt; resolveClass(String name) throws ClassNotFoundException {
        return resolveClass(name, null);
    }

calls with loader == null....

    /**
     * Returns the {@code Class} object associated with
     * the class or interface with the given string name,
     * using the given class loader.
     * <p>
     * The {@code name} can denote an array class
     * (see {@link Class#getName} for details).
     * <p>
     * If the parameter {@code loader} is null,
     * the class is loaded through the default class loader.
     * <p>
     * This method can be used to obtain
     * any of the {@code Class} objects
     * representing {@code void} or primitive Java types:
     * {@code char}, {@code byte}, {@code short},
     * {@code int}, {@code long}, {@code float},
     * {@code double} and {@code boolean}.
     *
     * @param name    fully qualified name of the desired class
     * @param loader  class loader from which the class must be loaded
     * @return class object representing the desired class
     *
     * @throws ClassNotFoundException  if the class cannot be located
     *                                 by the specified class loader
     *
     * @see #findClass(String,ClassLoader)
     * @see PrimitiveTypeMap#getType(String)
     */
    public static Class&lt;?&gt; resolveClass(String name, ClassLoader loader) throws ClassNotFoundException {
        Class&lt;?&gt; type = PrimitiveTypeMap.getType(name);
        return (type == null)
                ? findClass(name, loader)
                : type;
    }


    /**
     * Returns the {@code Class} object associated with
     * the class or interface with the given string name,
     * using the given class loader.
     * <p>
     * The {@code name} can denote an array class
     * (see {@link Class#getName} for details).
     * <p>
     * If the parameter {@code loader} is null,
     * the class is loaded through the default class loader.
     *
     * @param name    fully qualified name of the desired class
     * @param loader  class loader from which the class must be loaded
     * @return class object representing the desired class
     *
     * @throws ClassNotFoundException  if the class cannot be located
     *                                 by the specified class loader
     *
     * @see #findClass(String,ClassLoader)
     * @see Class#forName(String,boolean,ClassLoader)
     */
    public static Class&lt;?&gt; findClass(String name, ClassLoader loader) throws ClassNotFoundException {
        if (loader != null) {
            try {
                return Class.forName(name, false, loader);
            } catch (ClassNotFoundException exception) {
                // use default class loader instead
            } catch (SecurityException exception) {
                // use default class loader instead
            }
        }
        return findClass(name);
    }

Will call…. so here we go…. I suppose the difference could be how
Java 7 calls to Class.forName maybe….:

    /**
     * Returns the {@code Class} object associated
     * with the class or interface with the given string name,
     * using the default class loader.
     * <p>
     * The {@code name} can denote an array class
     * (see {@link Class#getName} for details).
     *
     * @param name  fully qualified name of the desired class
     * @return class object representing the desired class
     *
     * @throws ClassNotFoundException  if the class cannot be located
     *                                 by the specified class loader
     *
     * @see Class#forName(String)
     * @see Class#forName(String,boolean,ClassLoader)
     * @see ClassLoader#getSystemClassLoader()
     * @see Thread#getContextClassLoader()
     */
    public static Class&lt;?&gt; findClass(String name) throws ClassNotFoundException {
        try {
            ClassLoader loader = Thread.currentThread().getContextClassLoader();
            if (loader == null) {
                // can be null in IE (see 6204697)
                loader = ClassLoader.getSystemClassLoader();
            }
            if (loader != null) {
                return Class.forName(name, false, loader);
            }

        } catch (ClassNotFoundException exception) {
            // use current class loader instead
        } catch (SecurityException exception) {
            // use current class loader instead
        }
        return Class.forName(name);
    }

In Java6

	at java.security.AccessControlContext.checkPermission(Unknown Source)
	at java.security.AccessController.checkPermission(Unknown Source)
	at java.lang.SecurityManager.checkPermission(Unknown Source)
	at java.lang.SecurityManager.checkPackageAccess(Unknown Source)
	at sun.plugin2.applet.Applet2SecurityManager.checkPackageAccess(Unknown Source)
	at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
	at java.lang.ClassLoader.loadClass(Unknown Source)
	at sun.plugin2.applet.Plugin2ClassLoader.loadClass0(Unknown Source)
	at sun.plugin2.applet.Plugin2ClassLoader.loadClass(Unknown Source)
	at sun.plugin2.applet.Plugin2ClassLoader.loadClass0(Unknown Source)
	at sun.plugin2.applet.Plugin2ClassLoader.loadClass(Unknown Source)
	at sun.plugin2.applet.Plugin2ClassLoader.loadClass(Unknown Source)
	at java.lang.ClassLoader.loadClass(Unknown Source)
	at java.lang.Class.forName0(Native Method)
	at java.lang.Class.forName(Unknown Source)

My feeling is…. on Java7 the sun.plugin2.applet.Plugin2ClassLoader is not
being used…… sooo…. whhich one?... maybe:

ClassLoader loader = Thread.currentThread().getContextClassLoader();
if (loader == null) {
	// can be null in IE (see 6204697)
	loader = ClassLoader.getSystemClassLoader();
}

maybe??? not sure 100% sorry, I would need debug it to see a little better…

The difference, could be, with JDK6, where the ClassFinder doesn’t exist, is which
forName would be call and ClassLoader.getCallerClassLoader() will be used…. could be???

    /**
     * Returns the {@code Class} object associated with the class or
     * interface with the given string name.  Invoking this method is
     * equivalent to:
     *
     * <blockquote>
     *  {@code Class.forName(className, true, currentLoader)}
     * </blockquote>
     *
     * where {@code currentLoader} denotes the defining class loader of
     * the current class.
     *
     * <p> For example, the following code fragment returns the
     * runtime {@code Class} descriptor for the class named
     * {@code java.lang.Thread}:
     *
     * <blockquote>
     *   {@code Class t = Class.forName("java.lang.Thread")}
     * </blockquote>
     * <p>
     * A call to {@code forName("X")} causes the class named
     * {@code X} to be initialized.
     *
     * @param      className   the fully qualified name of the desired class.
     * @return     the {@code Class} object for the class with the
     *             specified name.
     * @exception LinkageError if the linkage fails
     * @exception ExceptionInInitializerError if the initialization provoked
     *            by this method fails
     * @exception ClassNotFoundException if the class cannot be located
     */
    public static Class&lt;?&gt; forName(String className)
                throws ClassNotFoundException {
        return forName0(className, true, ClassLoader.getCallerClassLoader());
    }

busterb at October 30, 2019 8:54pm UTC reported:

References

References about the attack:

References about the Java API used:

getField() wasn’t always public, see the following for an example:

<http://javasourcecode.org/html/open-source/jdk/jdk-6u23/sun/awt/SunToolkit.java.html&gt;

Summary

This is a vulnerability specifically targeting Java 7. Some reports reveal the origin of the 0day
exploit comes from a popular exploit kit named “Gondad Exploit Kit” (google “ZZVnxA1X”), some people
also claim the 0day originally comes from VulnDisco, which is an exploit pack used by Immunity
Canvas. No matter, the public noticed the attack as a malware being hosted at 59.120.154.62, which
is a server located in Taiwan. The decompiled source also has strings (lyrics) such as
“woyouyizhixiaomaolv” and “conglaiyebuqi” indicating that whoever wrote it must know Mandarin Chinese
quite well, possibly China because that’s “Pinyin” input method, and he probably grew up there
due the choice of the song. It would be reasonable to say that someone in China has been using the
exploit, and hosts the malicious code on a compromised server in Taiwan.

The actual link to the live exploit is:
hxxp://59.120.154.62/meeting/index.html

The exploit takes advantage of two issues: The ClassFinder and MethodFinder.findMethod(). Both
were newly introduced in JDK 7. ClassFinder is a replacement for classForName back in JDK 6. It
allows untrusted code to obtain a reference and have access to a restricted package in JDK 7, which
can be used to abuse sun.awt.SunToolkit (a restricted package). With sun.awt.SunToolkit, we can
actually invoke getField() by abusing findMethod() in Statement.invokeInternal() (but getField()
must be public, and that’s not always the case in JDK 6) in order to access Statement.acc’s private
field, modify AccessControlContext, and then disable Security Manager. Once Security Manager is
disabled, we can execute arbitrary Java code.

Our exploit has been tested successfully against multiple platforms, including: IE, Firefox, Safari,
Chrome; Windows, Ubuntu, OS X, etc. We have even received reports claiming the exploit also works
against Solaris.

Timeline

Aug xx 2011 – Vulnerable code was introduced in JDK7
Apr xx 2012 – Oracle already aware of the vulnerabilities: <http://www.theregister.co.uk/2012/08/30/oracle_knew_about_flaws/&gt;
Jun xx 2012 – Infected server hosting malware code: <http://urlquery.net/report.php?id=70896&gt;
Aug 26 2012 – First blog emerged about the Java 0day: <http://blog.fireeye.com/research/2012/08/zero-day-season-is-not-over-yet.html&gt;
Aug 26 2012 – PoC extracted from the malicious site by Joshua Drake: <https://twitter.com/jduck1337/status/239875285913317376&gt;
Aug 27 2012 – Metasploit exploit available: <https://community.rapid7.com/community/metasploit/blog/2012/08/27/lets-start-the-week-with-a-new-java-0day&gt;
Aug 28 2012 – CVE assigned as CVE-2012-4681
Aug 30 2012 – Java 7 Update 7 available (out of band patch)

Exceptions happens on this line of the Exploit:

GetClass("sun.awt.SunToolkit")

    private Class GetClass(String paramString)
        throws Throwable
    {
        Object arrayOfObject[] = new Object[1];
        arrayOfObject[0] = paramString;
        Expression localExpression = new Expression(Class.class, "forName", arrayOfObject); &lt;===
        localExpression.execute(); // (3) Fails !!! &lt;====
        return (Class)localExpression.getValue();
    }

Through Expression it tries to do Class.forName(“sun.awt.SunToolkit”). Despite the use of
Expression, according to the Exception on Java6 root cause seems to be on Class.forName.

When checking java 7 api you can read:

public static Class classForName(String name) throws ClassNotFoundException
Deprecated! As - of JDK version 7, replaced by ClassFinder#resolveClass(String) .

Returns the Class object associated with the class or interface with the given string name, using the default class loader

So maybe something was lost con ClassFinder#resolveClass….

Digging into source code of openjdk:

  • On Java 7
    ======

    jdk/src/share/classes/java/lang/Class.java

    public static Class&lt;?&gt; forName(String className)
                throws ClassNotFoundException {
        return forName0(className, true, ClassLoader.getCallerClassLoader());
    }
    
    
    /** Called after security checks have been made. */
    private static native Class&lt;?&gt; forName0(String name, boolean initialize,
                                            ClassLoader loader)
        throws ClassNotFoundException;
    

    jdk/src/share/native/java/lang/Class.c

    JNIEXPORT jclass JNICALL
    Java_java_lang_Class_forName0(JNIEnv *env, jclass this, jstring classname,
    jboolean initialize, jobject loader)


    cls = JVM_FindClassFromClassLoader(env, clname, initialize,
    loader, JNI_FALSE);

hotspot/src/share/vm/prims/jvm.cpp

JVM_ENTRY(jclass, JVM_FindClassFromClassLoader(JNIEnv* env, const char* name,
                                               jboolean init, jobject loader,
                                               jboolean throwError))
  JVMWrapper3("JVM_FindClassFromClassLoader %s throw %s", name,
               throwError ? "error" : "exception");
  // Java libraries should ensure that name is never null...
  if (name == NULL || (int)strlen(name) &gt; Symbol::max_length()) {
    // It's impossible to create this class;  the name cannot fit
    // into the constant pool.
    if (throwError) {
      THROW_MSG_0(vmSymbols::java_lang_NoClassDefFoundError(), name);
    } else {
      THROW_MSG_0(vmSymbols::java_lang_ClassNotFoundException(), name);
    }
  }
  TempNewSymbol h_name = SymbolTable::new_symbol(name, CHECK_NULL);
  Handle h_loader(THREAD, JNIHandles::resolve(loader));
  jclass result = find_class_from_class_loader(env, h_name, init, h_loader,
                                               Handle(), throwError, THREAD);

  if (TraceClassResolution && result != NULL) {
    trace_class_resolution(java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(result)));
  }
  return result;
JVM_END

hotspot/src/share/vm/classfile/systemDictionary.cpp

jclass find_class_from_class_loader(JNIEnv* env, symbolHandle name, jboolean init, Handle loader, Handle protection_domain, jboolean throwError, TRAPS) {
  // Security Note:
  //   The Java level wrapper will perform the necessary security check allowing
  //   us to pass the NULL as the initiating class loader.
  klassOop klass = SystemDictionary::resolve_or_fail(name, loader, protection_domain, throwError != 0, CHECK_NULL);

  KlassHandle klass_handle(THREAD, klass);
  // Check if we should initialize the class
  if (init && klass_handle-&gt;oop_is_instance()) {
    klass_handle-&gt;initialize(CHECK_NULL);
  }
  return (jclass) JNIHandles::make_local(env, klass_handle-&gt;java_mirror());
}

hotspot/src/share/vm/classfile/systemDictionary.cpp

klassOop SystemDictionary::resolve_or_fail(symbolHandle class_name, Handle class_loader, Handle protection_domain, bool throw_error, TRAPS) {
  klassOop klass = resolve_or_null(class_name, class_loader, protection_domain, THREAD);
  if (HAS_PENDING_EXCEPTION || klass == NULL) {
    KlassHandle k_h(THREAD, klass);
    // can return a null klass
    klass = handle_resolution_exception(class_name, class_loader, protection_domain, throw_error, k_h, THREAD);
  }
  return klass;
}

klassOop SystemDictionary::resolve_or_null(symbolHandle class_name, Handle class_loader, Handle protection_domain, TRAPS) {
  assert(!THREAD-&gt;is_Compiler_thread(), "Can not load classes with the Compiler thread");
  if (FieldType::is_array(class_name())) {
    return resolve_array_class_or_null(class_name, class_loader, protection_domain, CHECK_NULL);
  } else {
    return resolve_instance_class_or_null(class_name, class_loader, protection_domain, CHECK_NULL);
  }
}

…. First review of resolve_instance_class_or_null doesn’t spot anything interesting at first view! Maybe
I should check carefully

  • On java6:
    =====

    jdk/src/share/native/java/lang/Class.c

    public static Class&lt;?&gt; forName(String className)
                throws ClassNotFoundException {
        return forName0(className, true, ClassLoader.getCallerClassLoader());
    }
    
    
    /** Called after security checks have been made. */
    private static native Class forName0(String name, boolean initialize,
                                            ClassLoader loader)
        throws ClassNotFoundException;
    

hotspot/src/share/vm/prims/jvm.cpp

JVM_ENTRY(jclass, JVM_FindClassFromClassLoader(JNIEnv* env, const char* name,
                                               jboolean init, jobject loader,
                                               jboolean throwError))
  JVMWrapper3("JVM_FindClassFromClassLoader %s throw %s", name,
               throwError ? "error" : "exception");
  // Java libraries should ensure that name is never null...
  if (name == NULL || (int)strlen(name) &gt; symbolOopDesc::max_length()) {
    // It's impossible to create this class;  the name cannot fit
    // into the constant pool.
    if (throwError) {
      THROW_MSG_0(vmSymbols::java_lang_NoClassDefFoundError(), name);
    } else {
      THROW_MSG_0(vmSymbols::java_lang_ClassNotFoundException(), name);
    }
  }
  symbolHandle h_name = oopFactory::new_symbol_handle(name, CHECK_NULL);
  Handle h_loader(THREAD, JNIHandles::resolve(loader));
  jclass result = find_class_from_class_loader(env, h_name, init, h_loader,
                                               Handle(), throwError, THREAD);

  if (TraceClassResolution && result != NULL) {
    trace_class_resolution(java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(result)));
  }
  return result;
JVM_END



jclass find_class_from_class_loader(JNIEnv* env, Symbol* name, jboolean init, Handle loader, Handle protection_domain, jboolean throwError, TRAPS) {
  // Security Note:
  //   The Java level wrapper will perform the necessary security check allowing
  //   us to pass the NULL as the initiating class loader.
  klassOop klass = SystemDictionary::resolve_or_fail(name, loader, protection_domain, throwError != 0, CHECK_NULL);

  KlassHandle klass_handle(THREAD, klass);
  // Check if we should initialize the class
  if (init && klass_handle-&gt;oop_is_instance()) {
    klass_handle-&gt;initialize(CHECK_NULL);
  }
  return (jclass) JNIHandles::make_local(env, klass_handle-&gt;java_mirror());
}

hotspot/src/share/vm/classfile/systemDictionary.cpp

klassOop SystemDictionary::resolve_or_fail(Symbol* class_name, Handle class_loader, Handle protection_domain, bool throw_error, TRAPS) {
  klassOop klass = resolve_or_null(class_name, class_loader, protection_domain, THREAD);
  if (HAS_PENDING_EXCEPTION || klass == NULL) {
    KlassHandle k_h(THREAD, klass);
    // can return a null klass
    klass = handle_resolution_exception(class_name, class_loader, protection_domain, throw_error, k_h, THREAD);
  }
  return klass;



klassOop SystemDictionary::resolve_or_null(Symbol* class_name, Handle class_loader, Handle protection_domain, TRAPS) {
  assert(!THREAD-&gt;is_Compiler_thread(), "Can not load classes with the Compiler thread");
  if (FieldType::is_array(class_name)) {
    return resolve_array_class_or_null(class_name, class_loader, protection_domain, CHECK_NULL);
  } else if (FieldType::is_obj(class_name)) {
    ResourceMark rm(THREAD);
    // Ignore wrapping L and ;.
    TempNewSymbol name = SymbolTable::new_symbol(class_name-&gt;as_C_string() + 1,
                                   class_name-&gt;utf8_length() - 2, CHECK_NULL);
    return resolve_instance_class_or_null(name, class_loader, protection_domain, CHECK_NULL);
  } else {
    return resolve_instance_class_or_null(class_name, class_loader, protection_domain, CHECK_NULL);
  }
}

…. First review of resolve_instance_class_or_null doesn’t spot anything interesting at first view! Maybe
I should check carefully

So going high level….

As have been said before, on JDK 7, classForName has been replaced by ClassFinder#resolveClass

public static Class classForName(String name) throws ClassNotFoundException
Deprecated! As - of JDK version 7, replaced by ClassFinder#resolveClass(String) .

ClassFinder doesn't exist on JDK 6, so digging into JDK 7:

     * @see #resolveClass(String,ClassLoader)
     */
    public static Class&lt;?&gt; resolveClass(String name) throws ClassNotFoundException {
        return resolveClass(name, null);
    }

calls with loader == null....

    /**
     * Returns the {@code Class} object associated with
     * the class or interface with the given string name,
     * using the given class loader.
     * <p>
     * The {@code name} can denote an array class
     * (see {@link Class#getName} for details).
     * <p>
     * If the parameter {@code loader} is null,
     * the class is loaded through the default class loader.
     * <p>
     * This method can be used to obtain
     * any of the {@code Class} objects
     * representing {@code void} or primitive Java types:
     * {@code char}, {@code byte}, {@code short},
     * {@code int}, {@code long}, {@code float},
     * {@code double} and {@code boolean}.
     *
     * @param name    fully qualified name of the desired class
     * @param loader  class loader from which the class must be loaded
     * @return class object representing the desired class
     *
     * @throws ClassNotFoundException  if the class cannot be located
     *                                 by the specified class loader
     *
     * @see #findClass(String,ClassLoader)
     * @see PrimitiveTypeMap#getType(String)
     */
    public static Class&lt;?&gt; resolveClass(String name, ClassLoader loader) throws ClassNotFoundException {
        Class&lt;?&gt; type = PrimitiveTypeMap.getType(name);
        return (type == null)
                ? findClass(name, loader)
                : type;
    }


    /**
     * Returns the {@code Class} object associated with
     * the class or interface with the given string name,
     * using the given class loader.
     * <p>
     * The {@code name} can denote an array class
     * (see {@link Class#getName} for details).
     * <p>
     * If the parameter {@code loader} is null,
     * the class is loaded through the default class loader.
     *
     * @param name    fully qualified name of the desired class
     * @param loader  class loader from which the class must be loaded
     * @return class object representing the desired class
     *
     * @throws ClassNotFoundException  if the class cannot be located
     *                                 by the specified class loader
     *
     * @see #findClass(String,ClassLoader)
     * @see Class#forName(String,boolean,ClassLoader)
     */
    public static Class&lt;?&gt; findClass(String name, ClassLoader loader) throws ClassNotFoundException {
        if (loader != null) {
            try {
                return Class.forName(name, false, loader);
            } catch (ClassNotFoundException exception) {
                // use default class loader instead
            } catch (SecurityException exception) {
                // use default class loader instead
            }
        }
        return findClass(name);
    }

Will call…. so here we go…. I suppose the difference could be how
Java 7 calls to Class.forName maybe….:

    /**
     * Returns the {@code Class} object associated
     * with the class or interface with the given string name,
     * using the default class loader.
     * <p>
     * The {@code name} can denote an array class
     * (see {@link Class#getName} for details).
     *
     * @param name  fully qualified name of the desired class
     * @return class object representing the desired class
     *
     * @throws ClassNotFoundException  if the class cannot be located
     *                                 by the specified class loader
     *
     * @see Class#forName(String)
     * @see Class#forName(String,boolean,ClassLoader)
     * @see ClassLoader#getSystemClassLoader()
     * @see Thread#getContextClassLoader()
     */
    public static Class&lt;?&gt; findClass(String name) throws ClassNotFoundException {
        try {
            ClassLoader loader = Thread.currentThread().getContextClassLoader();
            if (loader == null) {
                // can be null in IE (see 6204697)
                loader = ClassLoader.getSystemClassLoader();
            }
            if (loader != null) {
                return Class.forName(name, false, loader);
            }

        } catch (ClassNotFoundException exception) {
            // use current class loader instead
        } catch (SecurityException exception) {
            // use current class loader instead
        }
        return Class.forName(name);
    }

In Java6

	at java.security.AccessControlContext.checkPermission(Unknown Source)
	at java.security.AccessController.checkPermission(Unknown Source)
	at java.lang.SecurityManager.checkPermission(Unknown Source)
	at java.lang.SecurityManager.checkPackageAccess(Unknown Source)
	at sun.plugin2.applet.Applet2SecurityManager.checkPackageAccess(Unknown Source)
	at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
	at java.lang.ClassLoader.loadClass(Unknown Source)
	at sun.plugin2.applet.Plugin2ClassLoader.loadClass0(Unknown Source)
	at sun.plugin2.applet.Plugin2ClassLoader.loadClass(Unknown Source)
	at sun.plugin2.applet.Plugin2ClassLoader.loadClass0(Unknown Source)
	at sun.plugin2.applet.Plugin2ClassLoader.loadClass(Unknown Source)
	at sun.plugin2.applet.Plugin2ClassLoader.loadClass(Unknown Source)
	at java.lang.ClassLoader.loadClass(Unknown Source)
	at java.lang.Class.forName0(Native Method)
	at java.lang.Class.forName(Unknown Source)

My feeling is…. on Java7 the sun.plugin2.applet.Plugin2ClassLoader is not
being used…… sooo…. whhich one?... maybe:

ClassLoader loader = Thread.currentThread().getContextClassLoader();
if (loader == null) {
	// can be null in IE (see 6204697)
	loader = ClassLoader.getSystemClassLoader();
}

maybe??? not sure 100% sorry, I would need debug it to see a little better…

The difference, could be, with JDK6, where the ClassFinder doesn’t exist, is which
forName would be call and ClassLoader.getCallerClassLoader() will be used…. could be???

    /**
     * Returns the {@code Class} object associated with the class or
     * interface with the given string name.  Invoking this method is
     * equivalent to:
     *
     * <blockquote>
     *  {@code Class.forName(className, true, currentLoader)}
     * </blockquote>
     *
     * where {@code currentLoader} denotes the defining class loader of
     * the current class.
     *
     * <p> For example, the following code fragment returns the
     * runtime {@code Class} descriptor for the class named
     * {@code java.lang.Thread}:
     *
     * <blockquote>
     *   {@code Class t = Class.forName("java.lang.Thread")}
     * </blockquote>
     * <p>
     * A call to {@code forName("X")} causes the class named
     * {@code X} to be initialized.
     *
     * @param      className   the fully qualified name of the desired class.
     * @return     the {@code Class} object for the class with the
     *             specified name.
     * @exception LinkageError if the linkage fails
     * @exception ExceptionInInitializerError if the initialization provoked
     *            by this method fails
     * @exception ClassNotFoundException if the class cannot be located
     */
    public static Class&lt;?&gt; forName(String className)
                throws ClassNotFoundException {
        return forName0(className, true, ClassLoader.getCallerClassLoader());
    }

Assessed Attacker Value: 5
Assessed Attacker Value: 5Assessed Attacker Value: 1

10 High

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

COMPLETE

Integrity Impact

COMPLETE

Availability Impact

COMPLETE

AV:N/AC:L/Au:N/C:C/I:C/A:C

0.975 High

EPSS

Percentile

100.0%