VirtualBox is a popular open source, cross-platform, virtualization software developed by Oracle Corporation. Earlier this year we identified an arbitrary file move vulnerability in the VirtualBox system service
service that could facilitate privilege escalation; here we’ll outline the steps used to discover and exploit this issue.
This vulnerability was also discovered by Naor Hodorov who is also credited in the Oracle Patch Advisory.
After installing VirtualBox for Windows, a single user-land service is installed (VirtualBox system service
) which runs as SYSTEM
and is configured to start on-demand:
PS C:\\tools> sc.exe qc VboxSDS
[SC] QueryServiceConfig SUCCESS
SERVICE_NAME: VboxSDS
TYPE : 10 WIN32_OWN_PROCESS
START_TYPE : 3 DEMAND_START
ERROR_CONTROL : 1 NORMAL
BINARY_PATH_NAME : "C:\\Program Files\\Oracle\\VirtualBox\\VBoxSDS.exe"
LOAD_ORDER_GROUP :
TAG : 0
DISPLAY_NAME : VirtualBox system service
DEPENDENCIES : RPCSS
SERVICE_START_NAME : LocalSystem
This service will create the directory C:\\ProgramData\\VirtualBox\\
for logging purposes.
This directory is created without specifying explicit ACLs and as such inherits permissions from the parent directory (C:\\ProgramData
) which allows users to create new files/folders:
PS C:\\tools> cacls.exe C:\\ProgramData\\VirtualBox
C:\\ProgramData\\VirtualBox NT AUTHORITY\\SYSTEM:(OI)(CI)(ID)F
BUILTIN\\Administrators:(OI)(CI)(ID)F
CREATOR OWNER:(OI)(CI)(IO)(ID)F
BUILTIN\\Users:(OI)(CI)(ID)R
BUILTIN\\Users:(CI)(ID)(special access:)
FILE_WRITE_DATA
FILE_APPEND_DATA
FILE_WRITE_EA
FILE_WRITE_ATTRIBUTES
PS C:\\tools>
When the service is started, this folder will be populated with log files, these log files will inherit the directory permissions which will prevent low privileged users from modifying/removing them and as a consequence limits abuse of directory junctions, a popular primitive used when exploiting logic access bugs:
PS C:\\tools> ls C:\\ProgramData\\VirtualBox\\
Directory: C:\\ProgramData\\VirtualBox
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 4/22/2024 9:44 AM 0 VBoxSDS.log
-a---- 4/22/2024 9:43 AM 1924 VBoxSDS.log.1
-a---- 4/12/2024 1:49 AM 1924 VBoxSDS.log.10
-a---- 4/19/2024 5:32 PM 1924 VBoxSDS.log.2
-a---- 4/18/2024 10:41 AM 1281 VBoxSDS.log.3
-a---- 4/17/2024 11:27 PM 1924 VBoxSDS.log.4
-a---- 4/17/2024 10:20 PM 665 VBoxSDS.log.5
-a---- 4/17/2024 10:20 PM 1431 VBoxSDS.log.6
-a---- 4/15/2024 11:04 PM 1925 VBoxSDS.log.7
-a---- 4/15/2024 1:30 PM 665 VBoxSDS.log.8
-a---- 4/15/2024 1:30 PM 1431 VBoxSDS.log.9
PS C:\\tools> cacls.exe C:\\ProgramData\\VirtualBox\\VBoxSDS.log
C:\\ProgramData\\VirtualBox\\VBoxSDS.log NT AUTHORITY\\SYSTEM:(ID)F
BUILTIN\\Administrators:(ID)F
BUILTIN\\Users:(ID)R
PS C:\\tools>
Analysing the service during startup shows an interesting behaviour where by the VboxSDS
service will perform file rename/move operation recursively inside the C:\\ProgramData\\VirtualBox
directory.
VboxSDS.log
will become VboxSDS.log.1
VboxSDS.log.1
will become VboxSDS.log.2
If the only file inside directory is VboxSDS.log.10
, it will be deleted:
This can be abused to both delete files in the directory and perform an arbitrary file move.
In order to clear the directory, we need to be able to start the service as a low privileged user and also the ability to stop/crash the service, as in most cases the directory will contain multiple log files.
Starting the service as a low privileged user can be achieved through COM. The VboxSDS
service registers a COM server and whenever this COM class is initiated the service is started:
PS C:\\tools> sc.exe queryex VboxSDS
SERVICE_NAME: VboxSDS
TYPE : 10 WIN32_OWN_PROCESS
STATE : 1 STOPPED
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x0
PID : 0
FLAGS :
PS C:\\tools> [Activator]::CreateInstance([type]::GetTypeFromCLSID("74AB5FFE-8726-4435-AA7E-876D705BCBA5"))
System.__ComObject
PS C:\\tools> sc.exe queryex VboxSDS
SERVICE_NAME: VboxSDS
TYPE : 10 WIN32_OWN_PROCESS
STATE : 4 RUNNING
(STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x0
PID : 11364
FLAGS :
PS C:\\tools>
The easiest way we discovered to crash the service was to prevent it from creating the VboxSDS.log
file.
This can be done in few different ways, however we believe the easiest is to create a directory named VboxSDS.log
, meaning the subsequent call to CreateFile
API will fail as it expects a file:
In order to win the race between moving and creating the VboxSDS.log
file, an opportunistic lock is created on VboxSDS.log.11
. This file does not normally exist but the service will try to delete it just before creating the VboxSDS.log
file:
With abilities to both clear the directory and start/crash the VBoxSDS
service we can start building an exploit:
VboxSDS.log.11
file and set oplock
on it,oplock
is triggered on the VboxSDS.log.11
file we create the VboxSDS.log
directory which will cause the service to crash,VboxSDS.log.9
file is created and an opportunistic lock is placed,oplock
is triggered the VboxSDS.log.9
file is deleted and the directory is turned into a junction point to the NT Object Manager directory (\\RPC Control
),VboxSDS.log.9
which points to our payload dll,VboxSDS.log.10
which points to a non-existent dll in the system32
directory (in this case wow64log.dll
),wow64log.dll
is created, the Microsoft Edge Update Service
is started and our dll is loaded in to a SYSTEM
process 🙂This blog post was written by Filip Dragovic.