'how to obtain SeDebugPrivilege in Python?

How does one obtain SeDebugPrivilege in Python? I believe both the Ctypes api and PyWin32 are both individually capable of doing it, i don't care which API is used. I found this broken code in the wild, it's probably pretty close

import win32api
import win32con
import win32security
#
def get_extra_privs():
    # Try to give ourselves some extra privs (only works if we're admin):
    # SeBackupPrivilege   - so we can read anything
    # SeDebugPrivilege    - so we can find out about other processes (otherwise OpenProcess will fail for some)
    # SeSecurityPrivilege - ??? what does this do?
    
    # Problem: Vista+ support "Protected" processes, e.g. audiodg.exe.  We can't see info about these.
    # Interesting post on why Protected Process aren't really secure anyway: http://www.alex-ionescu.com/?p=34
    
    th = win32security.OpenProcessToken(win32api.GetCurrentProcess(), win32con.TOKEN_ADJUST_PRIVILEGES | win32con.TOKEN_QUERY)
    TokenPrivileges = 1
    privs = win32security.GetTokenInformation(th, TokenPrivileges)
    newprivs = []
    for privtuple in privs:
        if privtuple[0] == win32security.LookupPrivilegeValue(remote_server, "SeBackupPrivilege") or privtuple[0] == win32security.LookupPrivilegeValue(remote_server, "SeDebugPrivilege") or privtuple[0] == win32security.LookupPrivilegeValue(remote_server, "SeSecurityPrivilege"):
            print ("Added privilege " + str(privtuple[0]))
            # privtuple[1] = 2 # tuples are immutable.  WHY?!
            newprivs.append((privtuple[0], 2)) # SE_PRIVILEGE_ENABLED
        else:
            newprivs.append((privtuple[0], privtuple[1]))
                
    # Adjust privs
    privs = tuple(newprivs)
    str(win32security.AdjustTokenPrivileges(th, False , privs)) 

but it crashes with

  File "C:\cygwin64\home\hans\tibia\pybot\pybot.py", line 11, in init
    processStuff.get_extra_privs()
  File "C:\cygwin64\home\hans\tibia\pybot\processStuff.py", line 20, in get_extra_privs
    if privtuple[0] == win32security.LookupPrivilegeValue(remote_server, "SeBackupPrivilege") or privtuple[0] == win32security.LookupPrivilegeValue(remote_server
, "SeDebugPrivilege") or privtuple[0] == win32security.LookupPrivilegeValue(remote_server, "SeSecurityPrivilege"):
TypeError: 'PySID' object is not subscriptable


Solution 1:[1]

Problems:

codee00.py:

#!/usr/bin/env python

import sys

import win32api as wapi
import win32con as wcon
import win32security as wsec


PRIV_NAMES = (
    wsec.SE_BACKUP_NAME,
    wsec.SE_DEBUG_NAME,
    wsec.SE_SECURITY_NAME,
)


def enable_privs(remote_server=None, priv_names=PRIV_NAMES):
    priv_ids = sorted(wsec.LookupPrivilegeValue(remote_server, e) for e in priv_names)
    print("Privileges to be enabled IDs:", priv_ids)
    tok = wsec.OpenProcessToken(wapi.GetCurrentProcess(), wcon.TOKEN_ADJUST_PRIVILEGES | wcon.TOKEN_QUERY)
    proc_privs = wsec.GetTokenInformation(tok, wsec.TokenPrivileges)
    print("Existing process privileges:", proc_privs)
    new_proc_privs = []
    need_change = False
    for proc_priv in proc_privs:
        if proc_priv[0] in priv_ids:
            print("Checking privilege " + str(proc_priv[0]))
            if proc_priv[1] != wcon.SE_PRIVILEGE_ENABLED:
                need_change = True
            new_proc_privs.append((proc_priv[0], wcon.SE_PRIVILEGE_ENABLED))
        else:
            new_proc_privs.append(proc_priv)
    print("New process privileges:", new_proc_privs)
    if need_change:
        modif_privs = wsec.AdjustTokenPrivileges(tok, False, new_proc_privs)
        res = wapi.GetLastError()
        print("Changed privileges:", modif_privs)  # Changed ones
        if res != 0:
            print("Error (partial) setting privileges:", res)
    else:
        print("Already set")
    #wsec.GetTokenInformation(tok, wsec.TokenPrivileges)  # To compare with proc_privs
    wapi.CloseHandle(tok)


def main(*argv):
    enable_privs()


if __name__ == "__main__":
    print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
                                                   64 if sys.maxsize > 0x100000000 else 32, sys.platform))
    rc = main(*sys.argv[1:])
    print("\nDone.")
    sys.exit(rc)

Output:

[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q072193556]> "e:\Work\Dev\VEnvs\py_pc064_03.09_test0\Scripts\python.exe" code00.py
Python 3.9.9 (tags/v3.9.9:ccb0e6a, Nov 15 2021, 18:08:50) [MSC v.1929 64 bit (AMD64)] 064bit on win32

Privileges to be added IDs: [17, 20, 8]
Existing process privileges: ((2, 0), (3, 0), (4, 0), (5, 0), (7, 0), (8, 2), (9, 0), (10, 0), (11, 0), (12, 0), (13, 0), (14, 0), (15, 0), (16, 0), (17, 0), (18, 0), (19, 0), (20, 0), (21, 0), (22, 0), (23, 3), (24, 0), (25, 0), (26, 0), (28, 0), (29, 3), (30, 3), (31, 0), (32, 0), (33, 0), (34, 0), (35, 0), (36, 0))
Checking privilege 8
Checking privilege 17
Checking privilege 20
New process privileges: [(2, 0), (3, 0), (4, 0), (5, 0), (7, 0), (8, 2), (9, 0), (10, 0), (11, 0), (12, 0), (13, 0), (14, 0), (15, 0), (16, 0), (17, 2), (18, 0), (19, 0), (20, 2), (21, 0), (22, 0), (23, 3), (24, 0), (25, 0), (26, 0), (28, 0), (29, 3), (30, 3), (31, 0), (32, 0), (33, 0), (34, 0), (35, 0), (36, 0)]
Changed privileges: ((17, 0), (20, 0))

Done

[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q072193556]> :: Attempt running as non Administrator user
[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q072193556]> runas /user:test "cmd /k e:\Work\Dev\VEnvs\py_pc064_03.09_test0\Scripts\python.exe %CD%\code00.py"
Enter the password for test:
Attempting to start cmd /k e:\Work\Dev\VEnvs\py_pc064_03.09_test0\Scripts\python.exe e:\Work\Dev\StackOverflow\q072193556\code00.py as user "CFATI-5510-0\test" ...

And the newly launched terminal:

Python 3.9.9 (tags/v3.9.9:ccb0e6a, Nov 15 2021, 18:08:50) [MSC v.1929 64 bit (AMD64)] 064bit on win32

Privileges to be enabled IDs: [8, 17, 20]
Existing process privileges: ((19, 0), (23, 3), (25, 0), (33, 0), (34, 0))
New process privileges: [(19, 0), (23, 3), (25, 0), (33, 0), (34, 0)]
Already set

Done.

As for the final goal (adding extra new privileges - which is not clearly stated in the question):

  • It can't be done, which makes perfect sense, as one non privileged process being able to grant itself (administrative) privileges, would beat the purpose of the whole Windows security (privileges and rights) mechanism

    • Even if one would try adding new privilege entries to the existing list (which automatically implies that current code has design flaws), AdjustTokenPrivileges would (silently) fail with ERROR_NOT_ALL_ASSIGNED (1300). Check [MS.Docs]: Changing Privileges in a Token for more details

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1