Attacking Cortex XDR from an unprivileged user perspective

In late 2023, we launched a new form of service where multiple customers could co-fund research time on a given product they are all using. The goal of the Co-funded research is to find vulnerabilities and possible weaknesses within the product that could impact not only our customers’ security, but anyone using the product. The discovered vulnerabilities are then reported to the editor of the solution and temporary mitigation options or IOCs are provided to the customers’ who funded the research.

In this context, we put some effort into the analysis of Cortex XDR and identified some interesting findings.

This blog post details two vulnerabilities (CVE-2024-5907 and CVE-2024-9469) that have now been fixed by Palo Alto and which could at the time be exploited by a low privileged user.

This research on Cortex XDR was performed by Florian Audon (@Nodauf) and Romain Melchiorre (@PMa1n).

CVE-2024-5907 Cortex XDR Agent: Local Privilege Escalation (PE) Vulnerability

CVE-2024-5907 – A privilege escalation (PE) vulnerability in the Palo Alto Networks Cortex XDR agent on Windows devices enables a local user to execute programs with elevated privileges. However, execution does require the local user to successfully exploit a race condition, which makes this vulnerability difficult to exploit.

When a user has unprivileged access to a laptop protected by Cortex XDR, they have the ability to request that the Cortex service (cyserver.exe) generates support logs that can then be used by administrators to troubleshoot potential issues caused by the agent.

Any user can trigger support file generations

When triggered, Cortex’s UI sends an RPC requests to the cyserver process that will start the generation of support files. As a result, the file generation is performed as NT AUTHORITY\SYSTEM.

The support file generation is performed in multiple steps and temporary files are created by Cortex during the process. Users can retrieve a lot of valuable information about the collected data in Cyvera’s log files stored in C:\ProgramData\Cyvera\Logs\tsf_collector_<date><time>.txt:

2023-10-19 17:56:35,233 [__main__] [INFO] Log file: C:\ProgramData\Cyvera\Logs\tsf_collector_19-10-
23T17_56_35.txt
2023-10-19 17:56:35,233 [__main__] [INFO] Collecting TSF data into
C:\Windows\Temp\tmp3088hxbaaa\collected_19-10-23T17_56_35
[...]

Thanks to this log file, we observed that a temporary folder was created in C:\Windows\Temp. Moreover, after multiple generations, we discovered that the name of the folder was not random. Indeed the folder is named following the pattern tmp<pid_of_cyserver><id> and can reliably be deduced from previous support file generations. Thus, the id is composed by 6 letters and is “incremented” (following the lexicographical order) between each log generation.

Additionally, this temporary folder was created with no special ACLs. As a result, it inherits them from C:\Windows\Temp which grants every user with write access.

Finally, using Process Monitor, we observed that every file in the folder is deleted recursively. More interestingly, if a user had written files in the folder during the support file generation process, they would also be deleted by Cyserver.

Therefore, using a junction (a NTFS soft link), it is possible to exploit this behaviour to force Cyserver to delete arbitrary folders. To illustrate the issue, we created a junction in the legitimate log folder. During the test, the file tree looked like this:

  • C:\Windows\Temp\tmp3148zfaaaa\collected_18-10-23T12_16_00\ (legitimate folder)
  • C:\Windows\Temp\tmp3148zfaaaa\MyFolder (junction folder pointing to C:\Users\rme\AppData\Local\Temp\2f1ab345-2630-4123-a058-ebb0d7fdb7dc)

At the end of the process, Cyserver deleted all the files including those stored in the target of the junction, which confirmed the vulnerability:

Cyserver follows the junction and deletes files in it

In order to perform a privilege escalation, one could combine the vulnerability with a well known local privilege escalation technique exploiting the Windows Installer service.

Cyserver can be tricked into deleting the C:\Config.msi folder

Nevertheless, it should be noted that as the proof of concept relies on the combination of two race conditions, the result was not consistent and multiple attempts were required to successfully perform the privilege escalation.

CVE-2024-9469 Cortex XDR Agent: Local Windows User Can Disable the Agent

CVE-2024-9469 – A problem with a detection mechanism in the Palo Alto Networks Cortex XDR agent on Windows devices enables a user with non-administrative Windows privileges to disable the agent. This issue may be leveraged by malware to disable the Cortex XDR agent and then to perform malicious activity.

During our research we looked at the Adaptive Policy module which is defined using multiple python scripts. Among them, the file auto_disable_parser.py was particularly interesting as the script is described by Palo Alto’s developers as follows:

The presser is intended to disable the agent’s protection if the agent’s resource consumption exceeds the thresholds. The order of actions is first turn off the event collection and if that does not help turn off all protection, the order is also correct in the opposite direction (resource consumption back to normal).

In the script, we can find how the check on the CPU usage is performed:

def is_cpu_high(component):
    """ Calculate whether traps CPU consumption is high."""
    #..snip..
    trapsd_machine_avg_cpu  component["EDR"]["PerformanceStatisticsFilter"]["trapsd_machine_avg_cpu"]
    trapsd_avg_cpu = component["EDR"]["PerformanceStatisticsFilter"]["trapsd_avg_cpu"]
    #..snip..
    if trapsd_machine_avg_cpu > adaptive_policy_settings.auto_disable_max_trapsd_machine_avg_cpu \
       and trapsd_avg_cpu > adaptive_policy_settings.auto_disable_max_trapsd_avg_cpu:
        logger.warning(f"Traps CPU usage exceeded the critical utilization:\n"
                       f" max trapsd_machine_avg_cpu = {adaptive_policy_settings.auto_disable_max_trapsd_machine_avg_cpu}%\n"
                       f" trapsd_machine_avg_cpu = {trapsd_machine_avg_cpu}%\n"
                       f" max trapsd_avg_cpu = {adaptive_policy_settings.auto_disable_max_trapsd_avg_cpu}% \n"
                       f" trapsd_avg_cpu {trapsd_avg_cpu}%")
        return True
    return False

In the same vein, the following function is used to identify excessive memory usage:

def is_high_memory(component):
    """ Calculate whether traps memory consumption is high."""
    #..snip..
    trapsd_memory_private_usage = component["EDR"]["PerformanceStatisticsFilter"]["trapsd_memory_private_usage" ]
    #..snip..
    if trapsd_memory_private_usage > adaptive_policy_settings.auto_disable_max_trapsd_memory_private_usage_bytes:
        logger.warning(f"Traps memory usage exceeded the critical utilization:\n"
        f" max trapsd_memory_private_usage = {adaptive_policy_settings.auto_disable_max_trapsd_memory_private_usage_bytes} \n"
        f" trapsd_memory_private_usage = {trapsd_memory_private_usage}")
        return True
    return False

In another script named adaptive_policy_settings.py, the default threshold values are defined:

auto_disable_suex_ttl = timedelta(hours=1).total_seconds()
auto_disable_max_trapsd_machine_avg_cpu = 50
auto_disable_max_trapsd_memory_private_usage_bytes = 2147483648 # 2Gb
auto_disable_max_trapsd_avg_cpu = 150 

Finally, using Cytool, we found that, by default, these value are checked every 900 seconds:

.\cytool.exe adaptive_policy query
Enter supervisor password:
Interval (seconds): 900
[..snip..]

To sum up, when a high consumption is detected, the event collector is first deactivated, and, if the consumption threshold is exceeded once again during a one-hour time window, the agent is totally disabled.

Therefore, we had to find a way to either force cyserver.exe to consume a lot of CPU or a lot of memory. During our research we focused on the CPU use. While there could be other ways to force high CPU / memory use, we found two methods that allowed us to temporarily disable the agent.

The first one is to continuously check for updates and generate support log files using the GUI.

The second is to continuously send junk data to the named pipes used in the inter-process communication of Cortex (\\.\pipe\support.[32 _hexadecimal_characters], \\.\pipe\python.[32 _hexadecimal_characters]) and to the P2P service. This contributed to raise the CPU usage.

The agent is disabled and any binary can be executed.

Moreover, no incident or alerts were generated in the cloud console. Indeed, the only place where it could be observed that the agent is being disabled by Adaptive Policy is through the status of the agent in the console.

Status of the agent in the web console.

Timeline

  • 13/02/2024 – Vulnerabilities were reported to Palo Alto
  • 15/02/2024 – Palo Alto PSIRT acknowledged the review of the reported issues
  • 21/02/2024 – Palo Alto asked additional information about exploitation details
  • 29/02/2024 – Palo Alto asked additional information about exploitation details
  • 01/03/2024 – Additional proof of concept code was provided to Palo Alto to help them fix the reported issues
  • 12/06/2024 – Palo Alto published an advisory regarding CVE-2024-5907
  • 09/10/2024 – Palo Alto published an advisory regarding CVE-2024-9469

Conclusion

While these are not the only issues discovered during our research, they illustrate the use of combining resources to produce more impactful results which end up being beneficial for all.