I am learning Python security (Windows API) and particularly trying to start up notepad.exe as a restricted user using the CreateRestrictedToken API. Currently when I execute the script, notepad.exe starts up with the DISABLE_MAX_PRIVILEGE (0x1) as expected.
In addition to DISABLE_MAX_PRIVILEGE (0x1), I would like to disable some SIDs, such as Administrators (S-1-5-32-544), Authenticated Users (S-1-5-11), and Console Logon (S-1-2-1). I have attempted to disable the Administrators SID; however, it fails with the following error:
TypeError: 'PySID' object has no attribute '__getitem__'
There seems to be a structure in the SID_AND_ATTRIBUTES, but I'm not quite sure how to put it together.
My Python build is x64 version 2.7.4.
import win32process
import win32job
import time
import win32event
import win32security
import win32api
from random import randint
ph = win32process.GetCurrentProcess()
th = win32security.OpenProcessToken(ph,win32security.TOKEN_ALL_ACCESS)
admins = win32security.ConvertStringSidToSid("S-1-5-32-544")[0]
token = win32security.CreateRestrictedToken(th, 1, admins, None, None)
startup = win32process.STARTUPINFO()
(hProcess, hThread, processId, threadId) = win32process.CreateProcessAsUser(token, "C:\\Windows\\Notepad.exe", None, None, None, True, win32process.CREATE_BREAKAWAY_FROM_JOB, None, None, startup)
The SidsToDisable parameter of PyWin32's CreateRestrictedToken takes a PySID_AND_ATTRIBUTES. This is a sequence of (PySID, Attributes) tuples. The attributes are ignored in this case, so use 0. For example:
import os
import win32process
import win32security
token = win32security.OpenProcessToken(win32process.GetCurrentProcess(),
win32security.TOKEN_ALL_ACCESS)
disabled_sids = [(win32security.CreateWellKnownSid(sidt), 0)
for sidt in [win32security.WinBuiltinAdministratorsSid,
win32security.WinAuthenticatedUserSid]]
# WinConsoleLogonSid (81) requires Windows 8.
# Use the string SID instead.
disabled_sids.append(
(win32security.ConvertStringSidToSid("S-1-2-1"), 0))
token_r = win32security.CreateRestrictedToken(
token, win32security.DISABLE_MAX_PRIVILEGE,
disabled_sids, None, None)
notepad_path = os.path.join(os.environ['SystemRoot'], 'notepad.exe')
startup = win32process.STARTUPINFO()
(hProcess, hThread,
processId, threadId) = win32process.CreateProcessAsUser(
token_r, notepad_path, None, None, None,
True, win32process.CREATE_BREAKAWAY_FROM_JOB, None, None, startup)
Related
All I need to do is create a program that lists all running services on my Windows machine. I have tried a number of methods including psutil to no avail. I have since tried to simplify it by just trying to execute the "net stat" command. It works, but the output is garbled. Is there anyway to save this to a text file nice and neat? Also, I'd like to append the word 'Running' next to each line. When I try to add that I get the following error:
File "./Python37/test3.py", line 3, in
print(str(result.stdout + 'running'))
TypeError: can't concat str to bytes
Here is my code so far:
import subprocess
result = subprocess.run(['net', 'start'], stdout=subprocess.PIPE)
print(str(result.stdout + 'running'))
Use EnumServicesStatus API like this :
import win32con
import win32service
def ListServices():
resume = 0
accessSCM = win32con.GENERIC_READ
accessSrv = win32service.SC_MANAGER_ALL_ACCESS
#Open Service Control Manager
hscm = win32service.OpenSCManager(None, None, accessSCM)
#Enumerate Service Control Manager DB
typeFilter = win32service.SERVICE_WIN32
stateFilter = win32service.SERVICE_STATE_ALL
statuses = win32service.EnumServicesStatus(hscm, typeFilter, stateFilter)
for (short_name, desc, status) in statuses:
print(short_name, desc, status)
ListServices();
win32service and win32con is part of pywin32 opensource project which you can download the lastest version here
.
From psutil 4.2.0 onwards you can list and query the windows services using following APIs.
psutil.win_service_iter()
Usage:
>>> import psutil
>>>
>>> list(psutil.win_service_iter())
[<WindowsService(name='AeLookupSvc', display_name='Application Experience') at 38850096>,
<WindowsService(name='ALG', display_name='Application Layer Gateway Service') at 38850128>,
<WindowsService(name='APNMCP', display_name='Ask Update Service') at 38850160>,
<WindowsService(name='AppIDSvc', display_name='Application Identity') at 38850192>,
...]
psutil.win_service_get(name) - To get a windows service by name
Usage:
>>> import psutil
>>> s = psutil.win_service_get('alg')
>>> s.as_dict()
{'binpath': 'C:\\Windows\\System32\\alg.exe',
'description': 'Provides support for 3rd party protocol plug-ins for Internet Connection Sharing',
'display_name': 'Application Layer Gateway Service',
'name': 'alg',
'pid': None,
'start_type': 'manual',
'status': 'stopped',
'username': 'NT AUTHORITY\\LocalService'}
I'm trying to map a remote path on Windows 10 for serveral hours but i don't get it to work. At first i tried it with WNetAddConnection2 but no matter what credentials or flags i use, when I type net use the mapped drive has always the status not available.
Manually i can map drives without problems, I only have problems when i map the drive programmatically.
import win32wnet
import win32netcon
nr = win32wnet.NETRESOURCE()
nr.dwScope = win32netcon.RESOURCE_GLOBALNET
nr.dwType = win32netcon.RESOURCETYPE_DISK
nr.dwUsage = win32netcon.RESOURCEUSAGE_CONNECTABLE
nr.lpLocalName = 'Z:'
nr.lpRemoteName = '\\\\192.168.178.46\\Test'
win32wnet.WNetAddConnection2(nr, None, None, 25)
The 25 is a flag set of interactive and prompt. I don't get any errors and the drive is listed when i type net use, but the status is always not available and the drive is not visible under workstation.
After that I tried NetUseAdd:
import win32net
win32net.NetUseAdd(None, 3, {'remote': r'\\192.168.178.46\Test',
'local': 'Z:', 'username': 'Admin', 'password': '123',
'status': 0, 'flags': 1, 'asg_type': 0})
It runs successfully but net use doesn't list anything and no mapped drives are visible under workstation.
A solution without subprocess would be nice. Can someone help please?
EDIT: Now i understand why it doesn't work. The app is running in admin context and I'm current logged in as non-admin. This behaviour is expalined here: https://superuser.com/questions/495370/why-isnt-a-mapped-drive-available-under-an-elevated-cmd-prompt-but-is-under-a-r
Is it possible to run the app as admin but the WNetAddConnection2 method as current user??
EDIT 2: Following the instructions from eryksun i came up with this:
import ctypes
from win32security import TOKEN_IMPERSONATE, TOKEN_ALL_ACCESS
from win32process import GetWindowThreadProcessId
from win32api import OpenProcess
from win32security import OpenProcessToken
from win32security import ImpersonateLoggedOnUser
from win32security import RevertToSelf
user32 = ctypes.WinDLL('user32', use_last_error=True);
user32.GetShellWindow.restype = ctypes.c_void_p
handle = user32.GetShellWindow()
threadId, processId = GetWindowThreadProcessId(handle)
handle_op = OpenProcess(TOKEN_ALL_ACCESS, True, processId)
handle_opt = OpenProcessToken(handle_op, TOKEN_IMPERSONATE)
ImpersonateLoggedOnUser(handle_opt) # throws access denied error
SOLUTION:
import ctypes
from win32process import GetWindowThreadProcessId
from win32api import OpenProcess
from win32security import OpenProcessToken, ImpersonateLoggedOnUser, RevertToSelf, TOKEN_QUERY, TOKEN_DUPLICATE
from win32con import PROCESS_QUERY_INFORMATION
user32 = ctypes.WinDLL('user32', use_last_error=True);
user32.GetShellWindow.restype = ctypes.c_void_p
handle = user32.GetShellWindow()
threadId, processId = GetWindowThreadProcessId(handle)
handle_op = OpenProcess(PROCESS_QUERY_INFORMATION, False, processId)
handle_opt = OpenProcessToken(handle_op, TOKEN_QUERY | TOKEN_DUPLICATE)
ImpersonateLoggedOnUser(handle_opt)
try:
nr = win32wnet.NETRESOURCE()
nr.dwScope = win32netcon.RESOURCE_GLOBALNET
nr.dwType = DISK
nr.dwUsage = win32netcon.RESOURCEUSAGE_CONNECTABLE
nr.lpLocalName = 'Z:'
nr.lpRemoteName = '\\\\192.168.178.46\\Test'
win32wnet.WNetAddConnection3(None, nr, None, None, 25)
except:
print("Unexpected error...")
RevertToSelf()
win32wnet.WNetAddConnection2(win32netcon.RESOURCETYPE_DISK, drive,
networkPath, None, user, password)
Drive is the local drive you want to map the network drive to, e.g. X:\
For networkpath add \\ in the beginning of the path, e.g. \\\\networkpath02 if you can access the path with \\networkpath02 in explorer.
I'm trying to create a shortcut through python that will launch a file in another program with an argument. E.g:
"C:\file.exe" "C:\folder\file.ext" argument
The code I've tried messing with:
from win32com.client import Dispatch
import os
shell = Dispatch("WScript.Shell")
shortcut = shell.CreateShortCut(path)
shortcut.Targetpath = r'"C:\file.exe" "C:\folder\file.ext"'
shortcut.Arguments = argument
shortcut.WorkingDirectory = "C:\" #or "C:\folder\file.ext" in this case?
shortcut.save()
But i get an error thrown my way:
AttributeError: Property '<unknown>.Targetpath' can not be set.
I've tried different formats of the string and google doesn't seem to know the solution to this problem
from comtypes.client import CreateObject
from comtypes.gen import IWshRuntimeLibrary
shell = CreateObject("WScript.Shell")
shortcut = shell.CreateShortCut(path).QueryInterface(IWshRuntimeLibrary.IWshShortcut)
shortcut.TargetPath = "C:\file.exe"
args = ["C:\folder\file.ext", argument]
shortcut.Arguments = " ".join(args)
shortcut.Save()
Reference
Here is how to do it on Python 3.6 (the second import of #wombatonfire s solution is not found any more).
First i did pip install comtypes, then:
import comtypes
from comtypes.client import CreateObject
from comtypes.persist import IPersistFile
from comtypes.shelllink import ShellLink
# Create a link
s = CreateObject(ShellLink)
s.SetPath('C:\\myfile.txt')
# s.SetArguments('arg1 arg2 arg3')
# s.SetWorkingDirectory('C:\\')
# s.SetIconLocation('path\\to\\.exe\\or\\.ico\\file', 1)
# s.SetDescription('bla bla bla')
# s.Hotkey=1601
# s.ShowCMD=1
p = s.QueryInterface(IPersistFile)
p.Save("C:\\link to myfile.lnk", True)
# Read information from a link
s = CreateObject(ShellLink)
p = s.QueryInterface(IPersistFile)
p.Load("C:\\link to myfile.lnk", True)
print(s.GetPath())
# print(s.GetArguments())
# print(s.GetWorkingDirectory())
# print(s.GetIconLocation())
# print(s.GetDescription())
# print(s.Hotkey)
# print(s.ShowCmd)
see site-packages/comtypes/shelllink.py for more info.
I want to save the registry key "Run" using _winreg in Python.
This is my code:
import _winreg
key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, r'Software\Microsoft\Windows\CurrentVersion\Run')
_winreg.SaveKey(key, "C:\key.reg")
When executing, I get a Windows error message: "A required privilege is not held by the client"
Can anyone see what is wrong?
Modify your code as below. It works fine if it is Run as Administrator. I have tested it on Win7 64 bit
import os, sys
import _winreg
import win32api
import win32security
#
# You need to have SeBackupPrivilege enabled for this to work
#
priv_flags = win32security.TOKEN_ADJUST_PRIVILEGES | win32security.TOKEN_QUERY
hToken = win32security.OpenProcessToken (win32api.GetCurrentProcess (), priv_flags)
privilege_id = win32security.LookupPrivilegeValue (None, "SeBackupPrivilege")
win32security.AdjustTokenPrivileges (hToken, 0, [(privilege_id, win32security.SE_PRIVILEGE_ENABLED)])
key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, r'Software\Microsoft\Windows\CurrentVersion\Run')
filepath = r'C:\key.reg'
if os.path.exists (filepath):
os.unlink (filepath)
_winreg.SaveKey (key, filepath)
Note: if win32api & win32security are missing, install them from here
Reference: Here
I'm trying to register the Firefox browser to run on Windows. According to the documentation for Webbrowser, "If the environment variable BROWSER exists, it is interpreted to override the platform default list of browsers, as a os.pathsep-separated list of browsers to try in order". I have the following:
import os
import webbrowser
from subprocess import call
os.environ["BROWSER"] = "C:\\FirefoxPortable\\FirefoxPortable.exe"
webbrowser.open('http://google.com')
This still opens iexplorer ( the default browser ).
Also:
>>> webbrowser._browsers
{'windows-default': [<class 'webbrowser.WindowsDefault'>, None], 'c:\\program files\\internet explorer\\iexplore.exe': [None, <webbrowser.BackgroundBrowser object at 0x04A18F90>]}
>>> webbrowser._tryorder
['windows-default', 'C:\\Program Files\\Internet Explorer\\IEXPLORE.EXE']
How Can I use Firefox here?
Source:
# OK, now that we know what the default preference orders for each
# platform are, allow user to override them with the BROWSER variable.
if "BROWSER" in os.environ:
_userchoices = os.environ["BROWSER"].split(os.pathsep)
_userchoices.reverse()
# Treat choices in same way as if passed into get() but do register
# and prepend to _tryorder
for cmdline in _userchoices:
if cmdline != '':
cmd = _synthesize(cmdline, -1)
if cmd[1] is None:
register(cmdline, None, GenericBrowser(cmdline), -1)
cmdline = None # to make del work if _userchoices was empty
del cmdline
del _userchoices
# what to do if _tryorder is now empty?
Tried your example and got the same result: Was opening in IE, not in Firefox. Reason is, that at import time of webbrowser, the BROWSER environment variable is not yet set. By simply reordering:
import os
# put it **before** importing webbroser
os.environ["BROWSER"] = "C:\\FirefoxPortable\\FirefoxPortable.exe"
import webbrowser
# from subprocess import call
webbrowser.open('http://google.com')
it works now. I figured that by trying to set the environment variable on the command line. Note: It did not work having the path in quotes
set BROWSER=C:\FirefoxPortable\FirefoxPortable.exe
did work,
set BROWSER="C:\FirefoxPortable\FirefoxPortable.exe"
did not. Sorry for the late answer, but the diagnostics with
>>> webbrowser._browsers
>>> webbrowser._tryorder
had been very helpful, thanks.
Try the following code:
webbrowser.register('firefox', None, webbrowser.GenericBrowser('C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe'))
a=webbrowser.get('firefox')
a.open("www.google.com")