PowerShell security issue with file access

I ran into strange behavior of PowerShell, which I consider being a security issue. I don’t know if this is expected behavior built in by Microsoft, but by using this “bug”, you can check the contents of a folder to which you don’t have access permissions. When using the Test-Path cmdlet, the command behaves a bit different than expected.

If Test-Path is used on a file which is in a folder where you don’t have access permissions to (eg. NTFS permissions are set), the command returns $false, but also throws an UnauthorizedAccessException (access denied). However, when the file actually doesn’t exist, the command will only return $false. By catching the error, you know if the file exists or not. By using a brute-force method, you can enumerate the entire contents of the directory. This way it’s possible to find out what kind of applications are installed on a machine, and possibly exploiting weakness in these applications.

Reproducing the issue

Default behavior of the Test-Path cmdlet is to return either $true or $false:

PS C:\> Test-Path C:\DoesNotExist\file.txt
False

I created a directory called “C:\Data\Temp” and added some subfolders and files. Next I removed access to the directory by modifying NTFS permissions. Checking the C:\Data\Temp path works as expected:

PS C:\> Test-Path C:\Data\Temp
True

Next I checked a file inside the directory to which I don’t have access:

PS C:\> Test-Path C:\Data\Temp\test.txt
Test-Path : Access is denied
At line:1 char:1
+ Test-Path C:\Data\Temp\test.txt
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : PermissionDenied: (C:\Data\Temp\test.txt:String) [Test-Path], UnauthorizedAccessExceptio
n
+ FullyQualifiedErrorId : ItemExistsUnauthorizedAccessError,Microsoft.PowerShell.Commands.TestPathCommand
False

The command returns an UnauthorizedAccessException, correctly reporting that I don’t have access to the folder. But when I check a file inside the directory which does not exist:

PS C:\> Test-Path C:\Data\Temp\doesnotexist.txt
False

The command just returns $false. The command should return an UnauthorizedAccessException as well in my opinion, since I don’t have access to the entire directory. Since the Test-Path command returns an error when the file exists, you can catch the error and report that the file actually does exist.

Exploiting the issue

I wrote a PowerShell function which exploits this behavior:

Function Test-File {
    Param (
        [Parameter(Mandatory=$true,Position=0)][string]$Path
    )

    try {
        $return = Test-Path -Path $Path -ErrorAction Stop
    } catch [System.UnauthorizedAccessException] {
        return $true
    }
    return $return
}

When you run the Test-File command on a file that does exist, but to which you don’t have access, the script will return $true:

PS C:\> Test-File -Path C:\Data\Temp\test.txt
True

This script can even be extended to allow a brute-force check of files in directories. This way you can enumerate the contents of a directory, even without access to it.

Limitation

This behavior is limited to the local system only. Using Test-Path on a remote system, over UNC path for example, will always return the UnauthorizedAccessException exception, even if the file doesn’t exist.

PS C:\> Test-Path \\SERVERNAME\C$\MyFile.txt
Test-Path : Access is denied
At line:1 char:1
+ Test-Path \\SERVERNAME\C$\MyFile.txt
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : PermissionDenied: (\\SERVERNAME\C$\MyFile.txt:String) [Test-Path], UnauthorizedAccessE
xception
+ FullyQualifiedErrorId : ItemExistsUnauthorizedAccessError,Microsoft.PowerShell.Commands.TestPathCommand
False

This limitation is a good thing, since it means that you can only exploit the behavior when you already have access to a machine.

I hope this article was useful for you. If you have any questions, please don’t hesitate to leave a comment or contact me over email.

Leave a Reply

Your email address will not be published. Required fields are marked *

Complete the following sum: * Time limit is exhausted. Please reload CAPTCHA.

This site uses Akismet to reduce spam. Learn how your comment data is processed.