Didier Stevens

Monday 19 July 2021

Using SeBackupPrivilege With Python

Filed under: Hacking — Didier Stevens @ 0:00

Access to files on a Windows NTFS filesystem is governed by permissions and privileges.

For permissions, it is done with a security descriptor on a file which contains a Discretionary Access Control List (DACL): these are the permissions that decide if a user has access (and which type of access) to said file. Most files don’t have their own, proper permissions: they inherit them from their parent folders.

Even administrators can be denied access to a file through DACL configuration.

But there is another mechanism that governs access to securable objects like files: privileges. A privilege is a property that a user holds. Administrators have many privileges that normal users don’t have. Like SeBackupPrivilege and SeRestorePrivilege (these are privileges necessary for backup operators).

When a user holds a privilege, it allows that user to do things that other users without that privilege are not allowed to do. For example, the SeBackupPrivilege allows a user to read any file, even if the security descriptor denies access.

But just having the SeBackupPrivilege is not enough:

1) it needs to be enabled programmatically

2) when opening a file, the intention to use the privilege must be specified

Doing this in a programming language like C is easy (for example, I programmed this into my FileScanner tool), but for Python, it’s a bit more complicated.

Part 1, enabling the privilege can be done in Python with the following code (it relies on pywin32).

import win32security
import win32api

def EnablePrivilege(privilege):
    hToken = win32security.OpenProcessToken(win32api.GetCurrentProcess(), win32security.TOKEN_ADJUST_PRIVILEGES | win32security.TOKEN_QUERY)
    win32security.AdjustTokenPrivileges(hToken, 0, [(win32security.LookupPrivilegeValue(None, privilege), win32security.SE_PRIVILEGE_ENABLED)])
    win32api.CloseHandle(hToken)

EnablePrivilege(win32security.SE_BACKUP_NAME)

Part 2, opening the file, is typically done with WIN32 API function CreateFile and passing it the FILE_FLAG_BACKUP_SEMANTICS flag with argument dwFlagsAndAttributes.

In Python, we usually access files via function open, and not via WIN32 API function CreateFile. We can do that, but I found a simpler method.

Python’s open function has no argument where we can pass flag FILE_FLAG_BACKUP_SEMANTICS, so we cannot use open.

Python also has function os.open, it returns a file descriptor that can then be used with other file descriptor operations, like read. Like open, os.open has no argument to pass flag FILE_FLAG_BACKUP_SEMANTICS. However, someone figured out it can be done indirectly by using flag 0x2000 (os.O_DIRECTORY ?) :

fd = os.open('c:\\demo\\test.txt', 0x2000)
os.read(fd, 0x10) # read 10 bytes

Here under is a demo. File c:\demo\test.txt is only accessible (full control) by a given, normal user. And not by the administrator. This instance of Python is running under the account of an elevated administrator (so that it has the SeBackupPrivilege ready to be enabled).

When attempting to open file c:\demo\test.txt with open and os.open, permission is denied.

But after enabling SeBackupPrivilege, access via os.open is granted:

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply (comments are moderated)

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

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

Blog at WordPress.com.