Tuesday, August 8, 2017

Windows Exploitation Tricks: Arbitrary Directory Creation to Arbitrary File Read

Posted by James Forshaw, Project Zero

For cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 past couple of months I’ve been presenting my “Introduction to Windows Logical Privilege Escalation Workshop” at a few conferences. The restriction of a 2 hour slot fails to do cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 topic justice and some interesting tips and tricks I would like to present have to be cut out. So as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 likelihood of a full training course any time soon is pretty low, I thought I’d put togecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r an irregular series of blog posts which detail small, self contained exploitation tricks which you can put to use if you find similar security vulnerabilities in Windows.

In this post I’m going to give a technique to go from an arbitrary directory creation vulnerability to arbitrary file read. Arbitrary direction creation vulnerabilities do exist - for example, here’s one that was in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Linux subsystem - but it’s not always obvious how you’d exploit such a bug in contrast to arbitrary file creation where a DLL is dropped somewhere. You could abuse DLL Redirection support where you create a directory calling program.exe.local to do DLL planting but that’s not always reliable as you’ll only be able to redirect DLLs not in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same directory (such as System32) and only ones which would normally go via Side-by-Side DLL loading.

For this blog we’ll use my example driver from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Workshop which already contains a vulnerable directory creation bug, and we’ll write a Powershell script to exploit it using my NtObjectManager module. The technique I’m going to describe isn’t a vulnerability, but it’s something you can use if you have a separate directory creation bug.

Quick Background on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Vulnerability Class

When dealing with files from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Win32 API you’ve got two functions, CreateFile and CreateDirectory. It would make sense that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s a separation between cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 two operations. However at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Native API level cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s only ZwCreateFile, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 way cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel separates files and directories is by passing eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r FILE_DIRECTORY_FILE or FILE_NON_DIRECTORY_FILE to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 CreateOptions parameter when calling ZwCreateFile. Why cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system call is for creating a file and yet cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 flags are named as if Directories are cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 main file type I’ve no idea.

A very simple vulnerable example you might see in a kernel driver looks like cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 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,
                     &obj_attr, &io_status,
                     NULL, FILE_ATTRIBUTE_NORMAL,
                    FILE_SHARE_READ | FILE_SHARE_DELETE,
                    FILE_OPEN_IF, FILE_DIRECTORY_FILE, NULL, 0);
}

There’s three important things to note about this code that determines whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r it’s a vulnerable directory creation vulnerability. Firstly it’s passing FILE_DIRECTORY_FILE to CreateOptions which means it’s going to create a directory. Second it’s passing as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Disposition parameter FILE_OPEN_IF. This means cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 directory will be created if it doesn’t exist, or opened if it does. And thirdly, and perhaps most importantly, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 driver is calling a Zw function, which means that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 call to create cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 directory will default to running with kernel permissions which disables all access checks. The way to guard against this would be to pass cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OBJ_FORCE_ACCESS_CHECK attribute flag in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OBJECT_ATTRIBUTES, however we can see with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 flags passed to InitializeObjectAttributes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 flag is not being set in this case.

Just from this snippet of code we don’t know where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 destination path is coming from, it could be from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 user or it could be fixed. As long as this code is running in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 context of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current process (or is impersonating your user account) it doesn’t really matter. Why is running in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current user’s context so important? It ensures that when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 directory is created cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 owner of that resource is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current user which means you can modify cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Security Descriptor to give you full access to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 directory. In many cases even this isn’t necessary as many of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system directories have a CREATOR OWNER access control entry which ensures that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 owner gets full access immediately.

Creating an Arbitrary Directory

If you want to follow along you’ll need to setup a Windows 10 VM (doesn’t matter if it’s 32 or 64 bit) and follow cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 details in setup.txt from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 zip file containing my Workshop driver. Then you’ll need to install cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 NtObjectManager Powershell Module. It’s available on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Powershell Gallery, which is an online module repository so follow cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 details cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re.
Assuming that’s all done, let’s get to work. First let’s look how we can call cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerable code in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 driver. The driver exposes a Device Object to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 user with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 name \Device\WorkshopDriver (we can see cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 setup in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 source code). All “vulnerabilities” are cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n exercised by sending Device IO Control requests to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 device object. The code for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IO Control handling is in device_control.c and we’re specifically interested in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 dispatch. The code ControlCreateDir is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 one we’re looking for, it takes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 input data from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 user and uses that as an unchecked UNICODE_STRING to pass to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code to create cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 directory. If we look up cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code to create cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IOCTL number we find ControlCreateDir is 2, so let’s use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following PS code to create an arbitrary directory.

Import-Module NtObjectManager

# Get an IOCTL for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 workshop driver.
function Get-DriverIoCtl {
   Param([int]$ControlCode)
   [NtApiDotNet.NtIoControlCode]::new("Unknown",`
       0x800 -bor $ControlCode, "Buffered", "Any")
}

function New-Directory {
 Param([string]$Filename)
 # Open cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 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 function first opens cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 device object, converts cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 path to a native NT format as an array of bytes and calls cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DeviceIoControl function on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 device. We could just pass an integer value for control code but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 NT API libraries I wrote have an NtIoControlCode type to pack up cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 values for you. Let’s try it and see if it works to create cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 directory c:\windows\abc.

create_new_dir.PNG

It works and we’ve successfully created cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 arbitrary directory. Just to check we use Get-Acl to get cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Security Descriptor of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 directory and we can see that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 owner is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ‘user’ account which means we can get full access to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 directory.
Now cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 problem is what to do with this ability? There’s no doubt some system service which might look up in a list of directories for an executable to run or a configuration file to parse. But it’d be nice not to rely on something like that. As cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 title suggested instead we’ll convert this into an arbitrary file read, how might do we go about doing that?

Mount Point Abuse

If you’ve watched my talk on Abusing Windows Symbolic Links you’ll know how NTFS mount points (or sometimes Junctions) work. The $REPARSE_POINT NTFS attribute is stored with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Directory which cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 NTFS driver reads when opening a directory. The attribute contains an alternative native NT object manager path to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 destination of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 symbolic link which is passed back to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IO manager to continue processing. This allows cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Mount Point to work between different volumes, but it does have one interesting consequence. Specifically cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 path doesn’t have to actually to point to anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r directory, what if we give it a path to a file?

If you use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Win32 APIs it will fail and if you use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 NT apis directly you’ll find you end up in a weird paradox. If you try and open cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mount point as a file cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 error will say it’s a directory, and if you instead try to open as a directory it will tell you it’s really a file. Turns out if you don’t specify eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r FILE_DIRECTORY_FILE or FILE_NON_DIRECTORY_FILE cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 NTFS driver will pass its checks and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mount point can actually redirect to a file.

Paradox.png
Perhaps we can find some system service which will open our file without any of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se flags (if you pass FILE_FLAG_BACKUP_SEMANTICS to CreateFile this will also remove all flags) and ideally get cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 service to read and return cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 file data?

National Language Support

Windows supports many different languages, and in order to support non-unicode encodings still supports Code Pages. A lot is exposed through cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 National Language Support (NLS) libraries, and you’d assume that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 libraries run entirely in user mode but if you look at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel you’ll find a few system calls here and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re to support NLS. The one of most interest to this blog is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 NtGetNlsSectionPtr system call. This system call maps code page files from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 System32 directory into a process’ memory where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 libraries can access cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code page data. It’s not entirely clear why it needs to be in kernel mode, perhaps it’s just to make cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 sections shareable between all processes on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same machine. Let’s look at a simplified version of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code, it’s not a very big function:

NTSTATUS NtGetNlsSectionPtr(DWORD NlsType,
                           DWORD CodePage,
                           PVOID *SectionPointer,
                           PULONG SectionSize) {
 UNICODE_STRING section_name;
 OBJECT_ATTRIBUTES section_obj_attr;
 HANDLE section_handle;
 RtlpInitNlsSectionName(NlsType, CodePage, &section_name);
 InitializeObjectAttributes(&section_obj_attr,
                            &section_name,
                            OBJ_KERNEL_HANDLE |
                            OBJ_OPENIF |
                            OBJ_CASE_INSENSITIVE |
                            OBJ_PERMANENT);
    
 // Open section under \NLS directory.
 if (!NT_SUCCESS(ZwOpenSection(&section_handle,
                        SECTION_MAP_READ,
                        &section_obj_attr))) {
   // If no section cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n open cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 corresponding file and create section.
   UNICODE_STRING file_name;
   OBJECT_ATTRIBUTES obj_attr;
   HANDLE file_handle;

   RtlpInitNlsFileName(NlsType,
                       CodePage,
                       &file_name);
   InitializeObjectAttributes(&obj_attr,
                              &file_name,
                              OBJ_KERNEL_HANDLE |
                              OBJ_CASE_INSENSITIVE);
   ZwOpenFile(&file_handle, SYNCHRONIZE,
              &obj_attr, FILE_SHARE_READ, 0);
   ZwCreateSection(&section_handle, FILE_MAP_READ,
                   &section_obj_attr, NULL,
                   PROTECT_READ_ONLY, MEM_COMMIT, file_handle);
   ZwClose(file_handle);
 }

 // Map section into memory and return pointer.
 NTSTATUS status = MmMapViewOfSection(
                     section_handle,
                     SectionPointer,
                     SectionSize);
 ZwClose(section_handle);
 return status;
}

The first thing to note here is it tries to open a named section object under cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 \NLS directory using a name generated from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 CodePage parameter. To get an idea what that name looks like we’ll just list that directory:

nls_dir.PNG

The named sections are of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 form NlsSectionCP where NUM is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 number of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code page to map. You’ll also notice cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s a section for a normalization data set. Which file gets mapped depends on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first NlsType parameter, we don’t care about normalization for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 moment. If cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 section object isn’t found cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code builds a file path to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code page file, opens it with ZwOpenFile and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n calls ZwCreateSection to create a read-only named section object. Finally cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 section is mapped into memory and returned to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 caller.

There’s two important things to note here, first cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OBJ_FORCE_ACCESS_CHECK flag is not being set for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 open call. This means cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 call will open any file even if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 caller doesn’t have access to it. And most importantly cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 final parameter of ZwOpenFile is 0, this means neicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r FILE_DIRECTORY_FILE or FILE_NON_DIRECTORY_FILE is being set. Not setting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se flags will result in our desired condition, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 open call will follow cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mount point redirection to a file and not generate an error. What is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 file path set to? We can just disassemble RtlpInitNlsFileName to find out:

void RtlpInitNlsFileName(DWORD NlsType,
                        DWORD CodePage,
                        PUNICODE_STRING String) {
 if (NlsType == NLS_CODEPAGE) {
    RtlStringCchPrintfW(String,
             L"\\SystemRoot\\System32\\c_%.3d.nls", CodePage);
 } else {
    // Get normalization path from registry.
    // NOTE about how this is arbitrary registry write to file.
 }
}

The file is of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 form c_.nls under cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 System32 directory. Note that it uses cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 special symbolic link \SystemRoot which points to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Windows directory using a device path format. This prevents this code from being abused by redirecting drive letters and making it an actual vulnerability. Also note that if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 normalization path is requested cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 information is read out from a machine registry key, so if you have an arbitrary registry value writing vulnerability you might be able to exploit this system call to get anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r arbitrary read, but that’s for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 interested reader to investigate.

I think it’s clear now what we have to do, create a directory in System32 with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 name c_.nls, set its reparse data to point to an arbitrary file cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 NLS system call to open and map cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 file. Choosing a code page number is easy, 1337 is unused. But what file should we read? A common file to read is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SAM registry hive which contains logon information for local users. However access to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SAM file is usually blocked as it’s not sharable and even just opening for read access as an administrator will fail with a sharing violation. There’s of course a number of ways you can get around this, you can use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 registry backup functions (but that needs admin rights) or we can pull an old copy of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SAM from a Volume Shadow Copy (which isn’t on by default on Windows 10). So perhaps let’s forget about… no wait we’re in luck.

File sharing on Windows files depends on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 access being requested. For example if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 caller requests Read access but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 file is not shared for read access cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n it fails. However it’s possible to open a file for certain non-content rights, such as reading cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 security descriptor or synchronizing on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 file object, rights which are not considered when checking cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 existing file sharing settings. If you look back at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code for NtGetNlsSectionPtr you’ll notice cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 only access right being requested for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 file is SYNCHRONIZE and so will always allow cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 file to be opened even if locked with no sharing access.

But how can that work? Doesn’t ZwCreateSection need a readable file handle to do cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 read-only file mapping. Yes and no. Windows file objects do not really care whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r a file is readable or writable. Access rights are associated with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handle created when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 file is opened. When you call ZwCreateSection from user-mode cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 call eventually tries to convert cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handle to a pointer to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 file object. For that to occur cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 caller must specify what access rights need to be on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handle for it to succeed, for a read-only mapping cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel requests cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handle has Read Data access. However just as with access checking with files if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel calls ZwCreateSection access checking is disabled including when converting a file handle to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 file object pointer. This results in ZwCreateSection succeeding even though cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 file handle only has SYNCHRONIZE access. Which means we can open any file on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system regardless of it’s sharing mode and that includes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SAM file.

So let’s put cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 final touches to this, we create cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 directory \SystemRoot\System32\c_1337.nls and convert it to a mount point which redirects to \SystemRoot\System32\config\SAM. Then we call NtGetNlsSectionPtr requesting code page 1337, which creates cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 section and returns us a pointer to it. Finally we just copy out cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mapped file memory into a new file and we’re done.

$dir = "\SystemRoot\system32\c_1337.nls"
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 =
    [NtApiDotNet.NtLocale]::GetNlsSectionPtr("CodePage", 1337)) {
 Use-NtObject($output = [IO.File]::OpenWrite("sam.bin")) {
   $map.GetStream().CopyTo($output)
   Write-Host "Copied file"
 }
}

Loading cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 created file in a hex editor shows we did indeed steal cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SAM file.

sam.PNG

For completeness we’ll clean up our mess. We can just delete cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 directory by opening cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 directory file with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Delete On Close flag and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n closing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 file (making sure to open it as a reparse point ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rwise you’ll try and open cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SAM again). For cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 section as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object was created in our security context (just like cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 directory) and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re was no explicit security descriptor cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n we can open it for DELETE access and call ZwMakeTemporaryObject to remove cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 permanent reference count set by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original creator with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OBJ_PERMANENT flag.

Use-NtObject($sect = Get-NtSection \nls\NlsSectionCP1337 `
                   -Access Delete) {
 # Delete permanent object.
 $sect.MakeTemporary()
}

Wrap-Up

What I’ve described in this blog post is not a vulnerability, although certainly cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code doesn’t seem to follow best practice. It’s a system call which hasn’t changed since at least Windows 7 so if you find yourself with an arbitrary directory creation vulnerability you should be able to use this trick to read any file on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system regardless of whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r it’s already open or shared. I’ve put cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 final script on GITHUB at this link if you want cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 final version to get a better understanding of how it works.

It’s worth keeping a log of any unusual behaviours when you’re reverse engineering a product in case it becomes useful as I did in this case. Many times I’ve found code which isn’t itself a vulnerability but have has some useful properties which allow you to build out exploitation chains.

No comments:

Post a Comment