Not even getting to the airtight hatchway: Planting files in world-writable directories
A security vulnerability report came in declaring that the finder had discovered an elevation of privilege vulnerability. They explained that they identified a world-writable directory and that an attacker can exploit the directory by creating or deleting a file, or could perform arbitrary execution from that directory.
Their proof-of-concept copied a file into the world-writable directory and confirmed that it was there and could be read. They also copied an executable into the world-writable directory, and then executed it.
So, yeah, that’s what happens when you have write permission in a directory. You can copy files into the directory, and that includes copying executables. But so what?
There had yet to be any demonstrated elevation of privilege. The user who copied the files into the directory is the same use that read them out or executed them.
Now, if the system automatically executed programs in that directory as some other user, say because the world-writable directory is on the default
PATH, or because it’s a directory like the global Startup Folder, then you’d have something. You placed an executable in a place that will execute as another user.
But so far, all you did was load a trap. You didn’t do anything to spring the trap.
In order to spring the trap, you need to trick somebody into going into that world-writable directory and running your program. That requires the victim to take some significant nondefault actions, and you’ll have to convince them to click on multiple things. At this point, what you have is a social engineering attack, not a security vulnerability.
After all, you don’t have to look around for world-writable directories. You can always make your own!
mkdir %USERPROFILE%\trap icacls %USERPROFILE%\trap /grant users:RW
Bingo, you just created a world-writable directory, just like the big boys.
Go ahead, copy your favorite malware into that directory. You haven’t achieved any elevation of privilege. The files are there, but you still have to trick somebody into launching them, and that’s where the real work begins.
Bonus chatter: This is a fertile ground for bogus security vulnerability reports. Most such reports claim elevation of privilege, but their “proof of concept” document doesn’t show any actual elevation of privilege. Many of them don’t even show any code execution! They title their report something like “Arbitrary file creation could potentially perform arbitrary execution,” but nowhere in the report is any realization of this potential ever demonstrated.
Any program can be potentially executed. I plug in a USB drive with an executable on it. Oh no, I have potential arbitrary execution!
That’s not the hard part. The hard part is getting it executed.
That sort of reminded me of a long time ago, certain networking product enforced strict user quotas (hey, hard drives back then were *expensive*) but the shared, network-mounted /tmp folder was visible to everyone logged-in.
So, an interesting trick was, if you saw a file under /tmp which belonged to someone else, and you moved the file into your own home folder (which was not shared with anyone else), the owner of the file didn’t change, just where it was stored. So the quota consumed was still that of the other user. Next, all you had to do was to truncate the file to zero (but not delete!) and then write your own content into it, and boom! instant quota extension, as you now had a useful file under a folder you controlled, but consuming someone else’s disk quota.
Good old times …
I suppose this was before the invention of the sticky bit?
%SystemRoot%\Temp is such a prominent world-writable directory, and it happens to be the systems TMP and TEMP directory, especially used by processes running under the “NT AUTHORITY\SYSTEM” account. And there are PLENTY of defective programs, foremost executable (bah!) installers/self-extractors, which extract executables into the processes TEMP directory and run them there. Do I need to say that almost all of them are vulnerable to CAPEC-471? Now combine them: deploy such crapware via any tool that runs under the local system account.
See you next year, at spring break!
Incorrect. You need user account to read/write temp. There is no entry for “Everyone”.
First THINK, then post:: everyone needs a user account to log on. Also ask Raymond what he meant with “world-writable”.
I think %SystemRoot%\Temp is NOT world-writable in Vista or later versions of Windows. (Just checked the ACL and yes, “Users” group do not have write access)
And user process create temp files in %USER_PROFILE%\AppData\Local\Temp .
Unfortunately it is.
The ACL for the directory gives members of the users group create file and create directory rights. This means that a user is able to create files and directories, and as the creator/owner of the file/directory, the user will get full rights.
This is the Windows 10 ACLs too.
I just checked I can’t even get in the folder to view the files (blocked by UAC consent).
And try to list files there with “dir” shows nothing. (It should at least contain some log files with names beginning with “dd_” because I have Visual Studio installed there.)
On my Windows 10 system, %SystemRoot%\Temp is owned by NT AUTHORITY\SYSTEM and has the following ACE in its ACL:
plus some other ACEs that don’t apply to BUILTIN/Users. Because of the (WD)(AD) permissions, I’m able to create new files and subdirectories successfully, but without (RC) and (RD), I’m unable to view the owner of the directory or list the directory contents without elevating to an Administrator. I don’t think the (X) permission has any effect on the Temp directory itself (correct me if I’m wrong), but it’d be inherited by any child files created within that directory to allow those files to be executed.
Correct except for the conclusion about the full rights.
There are 2 ACL entries which apply here:
1) (A;CI;0x00100026;;;BU) allows member of BUILTIN\Users to create files and directories, plus to traverse and synchronize; it’s inheritable to (sub)directories, so this permission propagates, and allows users to create files/subdirectories in subdirectories created by other users.
2) (A;OICIIO;FA;;;CO) allows full access to all files and (sub)directories for their creator/owner
@Adam Rosenfield: what CACLS.exe and ICACLS.exe show as X is WD in SDDL. It means execute permission for files, and traverse directory for directories. It would have effect on the directory for user accounts without the “traverse directory” privilege, but it is NOT inherited to files!
No, I am correct including the conclusion about the full rights.
I never stated that the user would get full rights on the entire TEMP directory, I stated that the user would get full rights on any file or directory created by the user as the creator/owner. This is easy to check.
Full rights on a directory through creator owner.
Full rights on a file through creator owner. So my conclusion is spot on.
You’re right that it’s not inherited to files—there’s (CI) for container inherit but no (OI) for object inherit, so it would only inherit into subdirectories but not regular files. I didn’t realize there was a separate access right for “traverse directory”, which is apparently not the same thing as the right to “list directory”.
I found https://docs.microsoft.com/en-us/windows/win32/fileio/file-access-rights-constants to be a useful resource in decoding these flags, which confirms that access right 0x20 is FILE_EXECUTE for ordinary files (the (X) in icacls’s output) and FILE_TRAVERSE for directories. It also contains this interesting remark:
> By default, users are assigned the BYPASS_TRAVERSE_CHECKING privilege, which ignores the FILE_TRAVERSE access right. See the remarks in File Security and Access Rights for more information.
It would be nice if the icacls documentation included descriptions of exactly which access right flags are meant by all of the tokens that it outputs and inputs. As we saw in Raymond’s article from November 18, the (D) flag is quite deceptive!
You did NOT mention the 2nd ACE here, so your conclusion missed the reason for the “full access”.
If there were no (explicit) ACE for “creator/owner”, the owner gets no immediate “full access”; but since the owner has (implicit) WDAC, s/he can add an ACE with “full access” later.
JFTR: where did you read that I stated you wrote something about “full access” for the TEMP directory? DON’T TRY TO PULL A STRAWMAN!
I didn’t need to mention the second ACE. Right back in my first post I wrote:
“and as the creator/owner of the file/directory, the user will get full rights.”
This had one MAJOR implication, the creator/owner of the file can always get full rights of any file they own. Now read that statement, does it say that the directory ACL will give them the rights? Does it say that the rights will be on the file immediately? No, all it says is that as the creator/owner of a file you have full rights.
Does this say that the user would or wouldn’t have to use the creator/owner rights to get that full access? No, but the fact that I mentioned creator/owner rights means that you can’t rule out the use of those rights to get full access.
So yes, this implication was there all along. So my conclusion was always correct.
If you have been reading this blog for a long time then you should be familiar with this concept. For example in 2008 Raymond blogged about the SeDebugPrivilege which effectively gives you system rights. It doesn’t immediately give you system privileges but they effectively have them. So no, my conclusion didn’t miss any conditions for the user getting full access, it assumed that the extra step would implicitly be taken to give them the final rights on the directory.
You still don’t get it, and even come up with yet another wrong statement: “This had one MAJOR implication, the creator/owner of the file can always get full rights of any file they own.”
NO, the creator/owner can NOT always get full access!
Proof/demo: add the ACE (D;IOOICI;WD;;;CO) to an arbitrary directory, and just for this demo also another ACE which does NOT allow full access, for example (D;IOOICI;WP;;;WD)
Now create a file or subdirectory there and try to change its ACL into full access.
Ok… and done.
1) Disable inheritance.
2) Remove the deny ACEs.
3) Full access obtained.
Why would you think that setting a deny for the WRITE_DAC would trump the implicit allowing of WRITE_DAC that the owner of the object would get?
When the Windows documentation states:
“An object’s owner implicitly has WRITE_DAC access to the object. This means that the owner can modify the object’s discretionary access control list (DACL), and thus, can control access to the object.”
There is no “unless the owner is denied the WRITE_DAC right”. Windows will not even check the ACL if the operation being taken is updating the DACL and the SID in the token matches the SID of the owner of the object.
SetNamedSecurityInfo is just as firm on this. It quite clearly states:
“The caller must have WRITE_DAC access to the object or be the owner of the object.”
So the Windows documentation states that your proof/demo is incorrect and in all situations the owner of the object is always able to modify the DACL.
I was going to edit my other post to include this information, but unfortunately it is still awaiting moderation.
There is an even more explicit bit of documentation that explicitly states that denying WRITE_DAC is ignored by ownership’s implied WRITE_DAC.
The Ownership of Objects section on the Access Control Overview states:
“No matter what permissions are set on an object, the owner of the object can always change the permissions.”
This also links to a page which states:
“The owner can always change permissions on an object, even when the owner is denied all access to the object.”
So if you are able to show your demo working in real life, where you deny the owner of the file the WRITE_DAC right and this blocks them from updating the DACL, then I would suggest you submit that as a bug report.
The owner of an object (almost) always has implicit WRITE_DAC and READ_CONTROL permissions. I was unable to replicate your experiment, even when adding an ACE for Deny full rights to Everyone and deleting all other ACEs—as the owner of an object, I was still able to remove that Deny ACE and add back Allow rights for myself to regain full control due to the implicit WRITE_DAC permission.
However, I found that there’s an interesting S-1-3-4 Owner Rights SID, where which causes the system to ignore the implicit WRITE_DAC and READ_CONTROL permissions. Adding “icacls foo /deny “owner rights:(F)” to a file with an empty ACL resulted in a file that I could no longer access or take control of, even though I was the owner. Not even when elevating to an Administrator.
To regain control of the file, I used takeown in an Administrator command prompt, which is able to succeed due to the SeTakeOwnership privilege. In doing so, this apparently removed the “OWNER RIGHTS:(N)” rule and replaced it with “OWNER RIGHTS:(IO)(N)”, so I could once again utilize the implicit WRITE_DAC permission and regain full control. When changing the file owner through Windows Explorer instead (again after elevating to Administrator), the same thing happened.
From both procmon and a Debugger, takeown makes a call to SetFileSecurityW() with the SecurityInformation parameter equal to only the OWNER_SECURITY_INFORMATION parameter. It’s not changing the DACL anywhere at all, yet immediately after SetFileSecurityW() returns, the DACL has been modified with the “OWNER RIGHTS” ACE changed. Therefore, I conclude that this is an undocumented(?) behavior of the Windows object security model to allow the owner to regain full control of the object in this weird edge case.
Unfortunately I wrote the wrong security principal CO alias S-1-3-0 here; the correct security principal for the proof/demo is but OW alias S-1-3-4.
Cf https://support.microsoft.com/en-us/help/914392/best-practices-and-guidance-for-writers-of-service-discretionary-acces for the “translation”
| Description: A group that represents the current owner of the object.
| When an ACE that carries this SID is applied to an object, the system ignores the
| implicit READ_CONTROL and WRITE_DAC permissions for the object owner.
Thanks to Adam Rosenfield for finding my stupid mistake as well as providing the proof that ownership does indeed NOT imply full access rights!
“For example in 2008 Raymond blogged about the SeDebugPrivilege which effectively gives you system rights. It doesn’t immediately give you system privileges but they effectively have them. So no, my conclusion didn’t miss any conditions for the user getting full access, it assumed that the extra step would implicitly be taken to give them the final rights on the directory.”
Take a view from the other side: why was the (according to you superfluous) ACE which gives CO IMMEDIATE full access added to %SystemRoot%\Temp? And how could this feature make it into Vista and later versions?
As a regular reader of Raymond’s blog you should know that every feature starts with -100 points!
>Any program can be potentially executed. I plug in a USB drive with an executable on it. Oh no, I have potential arbitrary execution!
>That’s not the hard part. The hard part is getting it executed.
How soon have you forgotten the USB drive autorun debacle.