CreateProcessAsUser with elevated privileges - windows

My service is running under local system permissions, and needs to start an application with administrator permissions in the user session.
What I got is:
WTSGetActiveConsoleSessionID()
WTSQueryUserToken for session ID
CreateProcessAsUser
The problem is I need to run the process (Step 3) as an administrator, without asking the user for the administrator's password.
On Linux systems I would simply do a "su ", but to achieve this on a Windows system?

I've finally found the solution to manage this:
public void launchProcessInUserSession(String process) throws WindowsAPIException {
final DWORD interactiveSessionId = kernel32.WTSGetActiveConsoleSessionId();
final DWORD serviceSessionId = getCurrentSessionId();
final HANDLEByReference pExecutionToken = new HANDLEByReference();
final HANDLE currentProcessToken = getCurrentProcessToken();
try {
final HANDLE interactiveUserToken = getUserToken(interactiveSessionId);
checkAPIError(advapi32.DuplicateTokenEx(currentProcessToken, WinNT.TOKEN_ALL_ACCESS, null, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
WinNT.TOKEN_TYPE.TokenPrimary, pExecutionToken));
} finally {
kernel32.CloseHandle(currentProcessToken);
}
final HANDLE executionToken = pExecutionToken.getValue();
try {
checkAPIError(advapi32.SetTokenInformation(executionToken, TOKEN_INFORMATION_CLASS.TokenSessionId, new IntByReference(interactiveSessionId.intValue()), DWORD.SIZE));
final WinBase.STARTUPINFO si = new WinBase.STARTUPINFO();
final PROCESS_INFORMATION processInfo = new WinBase.PROCESS_INFORMATION();
final int dwFlags = WinBase.DETACHED_PROCESS;
checkAPIError(advapi32.CreateProcessAsUser(executionToken, null, process, null, null, false, dwFlags, null, null, si, processInfo));
LOGGER.debug("Execution done. Process ID is {}", processInfo.dwProcessId);
} finally {
kernel32.CloseHandle(executionToken);
}
}

I need to run the process (Step 3) as administrator, without asking the user for the administrator's password.
If it were possible for a low privileged user to execute code as a privileged user, then the system's security model would be broken. If you want to execute code with administrator privileges then you need to supply appropriate credentials, at some point.
Your proposed plan of action has you calling CreateProcessAsUser passing the user token for a low privileged user. This plan, as itemized in the question, cannot succeed. Since the user token you will provide is that of the low privileged user, the process will not be able to perform administrative tasks.
You will need to provide, one way or another, credentials for a user with administrative rights.

Related

Programmatically create libraries folder under Roaming profile for new users, as first desktop login does

I'm creating some new windows users and assigning admin rights with
net UserName Password /add
net localgroup administrators UserName /add
After this point, the user is created, but it's not really loaded. As for example, the C:\Users\UserName folder hasn't been created yet.
After that, I run some processes impersonating the user by using
psexec -i -h -u UserName -p Password process.exe
After this, some additional things are loaded for the user, I can see it on C:\Users\UserName, and on the system registry, but it's still missing part of the roaming profile.
In particular, I'm looking at the folder C:\Users\TestUser\AppData\Roaming\Microsoft\Windows\libraries not being created (Note: this is true only for win10, in win7 it does get created). This folder seems to be created only when logging with the user through the desktop login.
How can I finish initializing the user so that the user is loaded the same way that logging through the desktop would do it (or at least so that C:\Users\TestUser\AppData\Roaming\Microsoft\Windows\libraries is created).
I've tried using LoadUserProfile but I haven't had any luck so far
IntPtr hUser = IntPtr.Zero;
try
{
bool result = LogonUser(
userName, null, password,
LOGON_TYPE.LOGON32_LOGON_NETWORK,
LOGON_PROVIDER.LOGON32_PROVIDER_DEFAULT,
out hUser);
if (result == false)
{
Exception ex = new System.ComponentModel.Win32Exception(
Marshal.GetLastWin32Error());
throw ex;
}
PROFILEINFO profileInfo = new PROFILEINFO();
profileInfo.dwSize = Marshal.SizeOf(profileInfo);
profileInfo.lpUserName = Environment.MachineName+ #"\" + userName;
result = LoadUserProfile(
hUser, ref profileInfo);
if (result == false)
{
Exception ex = new System.ComponentModel.Win32Exception(
Marshal.GetLastWin32Error());
throw ex;
}
}
finally
{
if (hUser != IntPtr.Zero)
{
CloseHandle(hUser);
}
}
Any solution on C#, powershell, or batch scripting would do it.

Open a JobObject created in a service from a user session process

I have a windows service that creates a JobObject that i need to keep alive as long as the machine is turned on - the goal is to manage a few user session processes that can terminate/start at any time with this JobObject. I am creating it in a service to make sure the process is running at startup, and that it can't be killed by regular users.
However, i don't seem to be able to open a handle to this JobObject from the user session, I always get an access denied (5) error, despite going as far as creating it with a NULL DACL.
I have found a somewhat related question here: Open an Event object created by my service from my application, but for me, even with the NULL DACL, when asking for a JOB_OBJECT_ASSIGN_PROCESS right, i get access denied (asking for SYNCHRONIZE works for example).
The service code:
PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(psd, TRUE, NULL, FALSE);
SECURITY_ATTRIBUTES secAttr= {0};
secAttr.nLength = sizeof(secAttr);
secAttr.bInheritHandle = false;
secAttr.lpSecurityDescriptor = psd;
hJobObject = CreateJobObject(&secAttr, SCL_JOBOBJECTNAME);
LocalFree(psd);
The user session code:
hJobObject = OpenJobObject(JOB_OBJECT_ASSIGN_PROCESS, FALSE, SCL_JOBOBJECTNAME);
if (hJobObject == NULL)
{
DWORD wError = GetLastError();
printf("Error: %d\n", wError); // this always pops 5
return 1;
}
Any ideas? As a test, i tried spawning a user session process from within the service, and assign the JobObject via the service code, and that worked,.. so i'm fairly certain its related to security settings i am missing, despite the NULL DACL.
if you create Job in service - this object by default will be have WinSystemLabelSid label SID: S-1-16-16384 - System Mandatory Level. (i just check this) so you need not only set Dacl but Sacl too. for example:
ULONG cb = MAX_SID_SIZE;
PSID LowLabelSid = (PSID)alloca(MAX_SID_SIZE);
if (CreateWellKnownSid(WinLowLabelSid, 0, LowLabelSid, &cb))
{
PACL Sacl = (PACL)alloca(cb += sizeof(ACL) + sizeof(ACE_HEADER) + sizeof(ACCESS_MASK));
InitializeAcl(Sacl, cb, ACL_REVISION);
if (AddMandatoryAce(Sacl, ACL_REVISION, 0, 0, LowLabelSid))
{
SECURITY_DESCRIPTOR sd;
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
SetSecurityDescriptorSacl(&sd, TRUE, Sacl, FALSE);
SECURITY_ATTRIBUTES sa= { sizeof(sa), &sd, FALSE };
if (HANDLE hJob = CreateJobObject(&sa, L"Global\\{58BFC6DB-BE93-4cdb-919C-4C713ACB5A32}"))
{
CloseHandle(hJob);
}
}
}

Either Negotiate or SimpleBind must be specified and they cannot be combined

i am trying to validate the credentials of a user against a active directory with a principalcontext but always get an error.
I try to connect via ssl, because it is sensitive data, but it always give me the error in the headline.
try
{
PrincipalContext pc = new PrincipalContext(ContextType.Domain, "myAwesomeDomain.com", null, ContextOptions.SecureSocketLayer, adUser, adPassword);
using (pc)
{
retVal = pc.ValidateCredentials(userID, password, ContextOptions.SecureSocketLayer);
}
}
I also tried to set DC="myAwesomeDomain,DC=COM" for the container instead of null.
The Credentials to log into the AD are correct, they are working fine with DirectoryEntry.
I have no clue how to go on.
Any idea?
Mh, it is some time since now, i found a solution back then:
try
{
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, "myAwesomeDomain.com", null, ContextOptions.SecureSocketLayer, adUser, adPassword);
{
retVal = pc.ValidateCredentials(userID, password, ContextOptions.SecureSocketLayer);
}
}
it really worked this way, i can not explain why

Spring ACL adding ACE when the current user has no permission on the ACL

Short Question: When a new user signs up on my website I need to add a read permission to a domain object. Spring ACLs does a check using the current user's permissions to see if a permission can be added. This will always fail because the user has just signed up and has no permissions on the object that they need a read permission on. Is there a way to skip the security check in certain situations?
Long question: The website I'm working on has an invite system that is done using tokens and emails. User A creates an organization and becomes the owner of that organization. User A can then invite User B to the organization by email, an email will be sent telling them to signup, etc. When User B gets the invite they sign up and the token is looked up. This token has a relation to an organization and at this point I try to give the user a ReadPermission but I get the error:
"org.springframework.security.acls.model.NotFoundException: Unable to locate a matching ACE for passed permissions and SIDs"
Is there a way around this security check?
Or
How far into Spring Security do I need to go to change this setup?
Found the answer to this when reading spring docs. You can use a Runnable and DelegatingSecurityContextExecutor to run the required call as a different user.
User newUser = getCurrentUser();
User notOriginalUser = accountsService.findUserById(someId);
SecurityContext context = SecurityContextHolder.createEmptyContext();
Authentication authentication = new UsernamePasswordAuthenticationToken(notOriginalUser, "doesnotmatter", authoritiesList);
context.setAuthentication(authentication);
SimpleAsyncTaskExecutor delegateExecutor = new SimpleAsyncTaskExecutor();
DelegatingSecurityContextExecutor executor = new DelegatingSecurityContextExecutor(delegateExecutor, context);
class PermissionRunnable implements Runnable {
String u;
Organization o;
PermissionRunnable(Organization org, String username) {
o = org;
u = username;
}
public void run() {
permissionsService.setReadableByPrincipal(o, new PrincipalSid(u));
}
}
Runnable originalRunnable = new PermissionRunnable(org, newUser.getUsername());
executor.execute(originalRunnable);

WIN7 Keyboard hook stops working in another user account?

I created my own parental control app using C# to monitor my kids activity. It logs all the keyboard input and screens in the background silently, with the only gui of taskbar icon. So far, I just let it run in my admin account and everybody share the same account and it works fine. The problem is that as kids grow up, they found a way to kill it from the task manager. So, I need to use a more sophisticated way to protect my app. I thought I could solve this problem easily by creating a separate standard account for each kid and I can setup my app to run as an admin to monitor all their activities. However, I faced a lot of issues.
The keyboard hooks seem to stop working once I switched to a different user account. Is it true? I thought it's global hook - is it just global within the user account?
The screen capturing doesn't work on another user account either. This is my code and
it failed at g.CopyFromScreen with error "the handle is invalid":
RECT rc = Win32.GetWindowRect();
using (System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(rc.Width, rc.Height))
{
using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bitmap))
{
g.CopyFromScreen(rc.Location, System.Drawing.Point.Empty, new System.Drawing.Size(rc.Width, rc.Height));
string fileName = Settings.Instance.GetImageFileName();
bitmap.Save(fileName, System.Drawing.Imaging.ImageFormat.Png);
}
}
Your help is much appreciated.
As long as the kids aren't administrators, you can run the program under their accounts and deny access to the process.
For example (tested):
static void SetAcl() {
var sd = new RawSecurityDescriptor(ControlFlags.None,
new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null),
null, null, new RawAcl(2, 0));
sd.SetFlags(ControlFlags.DiscretionaryAclPresent | ControlFlags.DiscretionaryAclDefaulted);
var rawSd = new byte[sd.BinaryLength];
sd.GetBinaryForm(rawSd, 0);
if (!NativeMethods.SetKernelObjectSecurity(Process.GetCurrentProcess().Handle, SecurityInfos.DiscretionaryAcl, rawSd))
throw new Win32Exception();
}
static class NativeMethods {
[DllImport("Advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetKernelObjectSecurity(IntPtr target, SecurityInfos info, byte[] descriptor);
}

Resources