![]() |
Tip: Run process in system account (sc.exe) |
Post Reply
|
Page 123 4> |
| Author | ||||
Matts_User_Name
Senior Member
Joined: 10 August 2006 Location: USA Status: Offline Points: 687 |
Post Options
Thanks(0)
Quote Reply
Topic: Tip: Run process in system account (sc.exe)Posted: 03 November 2008 at 6:29pm |
|||
|
I have recently been doing some research on windows services, and have been working on some command line parsing, so while experimenting I thought of a nice little trick to run a process in the System account (And have the window be displayed) without using PsExec -sid Involves: 1. sc.exe - Manages windows service 2. net.exe - start windows service 3. cmd.exe - Runs the application Command (Copy and paste in command prompt or the run dialog) - This will run calc.exe
A path with quotes: The \" = a quote (quotes would be needed for paths with spaces, but this is just an example) Note: Copy and paste this one into cmd.exe or a batch(.bat) file, because the run dialog will not translate the \" escape chars.
So how does it work? 1. The & symbol tells cmd.exe to parse treat the text that follows as if it were a new line in a batch file (It basically is a new line delimiter which allows multiple commands to be combined into 1 line) To break it down:
2. Variables:
3. How it works:
This is just a useful trick I thought I would share. Feedback is welcome. Feel free to give it a shot and copy & paste that command in the run dialog. (Check the process's account either using TaskMgr or PE :P) I wonder if in vista this makes UAC mad, haha. -Matt Update: To make this work on paths with spaces, the start command needs to be changed from start calc to start "" calc. The other way works but as soon as you give start a path with spaces in it, it will not properly work, and I forgot about that until now. The other day I finally solved that nagging problem by using start /? and studying its commands. Apparently start's first parameter is the CreateProcess's WindowTitle parameter, inwhich if you specify a path like "C:\Documents and Settings\app.exe" a console windows will open with the title C:\Documents. To Fix this we must specify start "" "C:\Documents and Settings\app.exe" (Yes start requires quotes be supplied for paths with spaces) The problem is the 2 quotes within those quotes for binPath is not playing nice with cmd.exe. Usually you can use the ^ symbol to have cmd print in that special character but for some reason it is not working. I will try to figure this out later, perhaps by setting a variable or something. Update 2: (11-30-08) To use quotes in the path, I wasn't thinking straight and you can use the C-language escape sequence \" Ex: binPath= "cmd /c start \"\" \"calc\"" Which will translate to having an image path of: cmd /c start "" "calc" Enjoy! -Matt Edited by Matts_User_Name - 18 June 2009 at 9:26am |
||||
![]() |
||||
molotov
Moderator Group
Joined: 04 October 2006 Status: Offline Points: 17506 |
Post Options
Thanks(0)
Quote Reply
Posted: 03 November 2008 at 6:38pm |
|||
|
Good explanation!
Sounds similar to the technique discussed here: New Elevation PowerToys for Windows Vista (Also, note that interactive services on Vista are deprecated...) Edited by molotov - 03 November 2008 at 6:38pm |
||||
|
Daily affirmation:
net helpmsg 4006 |
||||
![]() |
||||
Matts_User_Name
Senior Member
Joined: 10 August 2006 Location: USA Status: Offline Points: 687 |
Post Options
Thanks(0)
Quote Reply
Posted: 03 November 2008 at 7:12pm |
|||
|
Thank you. I felt like I needed to get that out of my head so I remembered it (Usually when I write something out it sticks in better) Ah yes I have been working with similar things. An application in VB6 that I created to run an application as a different user and in a different desktop. I initially created it because of this RAT tool used to help others with comp problems called Radmin. It uses this "Telnet" which it opens cmd.exe on their side and waits for commands. The problem was that fact that I needed to change the desktop, if I wanted to run an application and display it to the user while not specifically controlling their mouse. The WinStation was not WinSta0, so I implemented some code I saw a while back that worked on impersonation. An Amazing feature. Its called UR (UserRun) Basically it works on various concepts like CreateProcessAsUser, Thread impersonation, Token DACL modification, Process username searching, ShellExecute with App/File & CmdLine parsing. A work of art I am creating =] I currently somewhat consider it a little more powerful than PsExec. Works great, but I am trying to make it perfect, haha. Maybe if I get some time to clean up the code Ill post it here. |
||||
![]() |
||||
doug_axtell
Newbie
Joined: 21 January 2009 Location: United States Status: Offline Points: 3 |
Post Options
Thanks(0)
Quote Reply
Posted: 21 January 2009 at 9:37pm |
|||
|
I work for a software shop writing test automation.
I've written a service in C# whose goal it is to (a) listen for TCP messages from our build automation host indicating that a new build has been published to QA, and then to (b) launch a local program that will install the new build and run a "build acceptance" test against it. The build cceptance test is GUI-driven - it uses the Ranorex library to exercise the GUI of the new build. Unfortunately my service is not functional at this point because when it launches the subordinate process (a C# console app), that process runs in the service's session, and not on the interactive window station and desktop. For better or worse, build acceptance test must be run on the interactive desktop in order to function properly. I've been looking online to find a solution, and I found a candidate at http://social.msdn.microsoft.com/forums/en-US/windowssecurity/thread/31bfa13d-982b-4b1a-bff3-2761ade5214f/. See the second message in the thread from contributer "efratian". I've implemented that approach in my C# service, but when I start the service and send it the appropriate message via TCP, it fails in CreateProcessAsUser(). The error code is 267 and the text for that error is "The directory name is invalid." I've verified through other experiments that the executable path being provided to CreateProcessAsUser() is correct. I'm therefore left to wonder: Do I have security/access privilege problem to solve in order to get CreateProcessAsUser() to succeed in my scenario? Please reply with any insights or suggestions. |
||||
![]() |
||||
Matts_User_Name
Senior Member
Joined: 10 August 2006 Location: USA Status: Offline Points: 687 |
Post Options
Thanks(0)
Quote Reply
Posted: 22 January 2009 at 12:27am |
|||
|
Hey there. I did receive your PM/Email, and yes you probably should have created a different thread and referred to this one, but no worries, this works too. Hmm okay so the problem is CreateProcessAsUser is returning ERROR_DIRECTORY. I did a lot of research on windows security back in May 08 so hopefully I can still help. If I recall correctly, that typically is not the error that is spit out if its a permissions issue, but just to be sure, you need to do the following. CreateProcessAsUser MUST have The Token-Specific permission called: TOKEN_ASSIGN_PRIMARY It ALSO MUST have a process token privilege SE_ASSIGNPRIMARYTOKEN_NAME ("SeAssignPrimaryToken") (This permission does not have to be enabled, since CPAU is actually kind enough to do that for us, as long as it exists in our token). In most situations "SeAssignPrimaryToken" is only given to processes running under the system account so therefore we would need to implement a fix. The only way to add a removed privilege to a process's token is by modifying a kernel data structure (_EPROCESS). This is known as DKOM, but is much easier said than done. The other solution is to re-run our app in a different security context (user account) or have another process do the dirty work for us (such as a service) Here are possible solutions: 1. Use thread impersonation (This means we can magically change the security context of a thread inside our process to run in the security context of another process (Ex: Winlogon) This by far is my favorite method! Just note: To use ImpersonateLoggedOnUser, the token which we open, we must be able to have the TOKEN_DUPLICATE Token-Specific access right in order for it to work. Luckily this never really is a problem (Ex: If we want to impersonate Winlogon's token.) Just ensure that you have SeDebugPrivilege enable. This can be quickly done by calling RtlAdjustPrivilege(20, 1, 0, 0) in ntdll or the other method in kernel32.dll using AdjustTokenPrivileges 2. Create a service and have it run applications in our Desktop. 3. Create a DLL to inject(map) into some other process, in which it would execute CreateProcess call(s) in its DllMain But like I said, I am not sure if the issue you are having is permissions, yet the only other thing I can think of which would cause this is the CreateProcess behavior with its CommandLine parameter: It requires that it is in a variable, and not be passed as a literal string (which is constant). For some reason, it internally modifes and then changes back to normal this param, and that means if you pass it something like "cmd.exe" instead of some var like sApp, then it will fail for sure. Also ensure you are passing StartupInfo and Process_Information properly (pass by reference, meaning pointers to them) Note: SI and PI dont require any setup EXCEPT: SI's 1st member "cb" MUST be given a size. The last thing I can think of is that you either declared CreateProcess (Or CreateProcessAsUser) improperly in C# (I am assuming it is like VB and isn't magically imported by headers like in C/C++) or that you not giving it a null string for the App Path, and possibly instead giving it a 0? (On a side note not related to your problem, remember the close the hThread and hProcess in PI after you get your CP call working to avoid a handle leak if they are being constantly called) I somehow doubt I helped solved your problem (but hopefully you found this of some value once you get CP bulletproof) I would try looking around google for: CreateProcess ERROR_DIRECTORY I found this, but looking over it, it doesn't seem too helpful http://social.technet.microsoft.com/Forums/en-US/vcgeneral/thread/bab4fc1d-e26b-4b4c-bf10-494199012f8d If this is of any value here is a function I made in VB a while back which allows me to run a process as any specified user (As long as I am logged on as admin) Note: This is just the function, not the whole source :P I guess if anyone really is interested in the source you can PM me.
Maybe this will help you or anyone else reading this. (Even though it is in VB6) Even though I do not know C#, I am starting to learn C++ so I might be able to figure out the similar syntax and provide any suggestions to where I think the problem might be in. Perhaps you could post the declare and the call to CreateProces/CreateProcessAsUser. Also, thinking about it now, have you ever tried CreateProcess in a C# app, and if so were the results the same or did it work? Edited by Matts_User_Name - 22 January 2009 at 12:36am |
||||
![]() |
||||
doug_axtell
Newbie
Joined: 21 January 2009 Location: United States Status: Offline Points: 3 |
Post Options
Thanks(0)
Quote Reply
Posted: 22 January 2009 at 1:22am |
|||
|
Thanks for the thought-provoking feedback. Let me address your suggestions/questions one-by-one.
My C# service is running as LocalSystem. Doesn't that mean that it will have the SE_ASSIGNPRIMARYTOKEN_NAME (although 'disabled') privilege? (It does according to http://msdn.microsoft.com/en-us/library/ms684190(VS.85).aspx.) I'm more concerned about TOKEN_ASSIGN_PRIMARY. How can I give my C# service this permission? 1- You recommend use of ImpersonateLoggedOnUser. 2- "Create a service and have it run applications in our Desktop." 3- DLL injection... *- In "Topic: Default process DACL and newly created objects" you recommend us of GetKernelObjectSecurity() and related calls. I've experimented with a form of (1): I tried the C# WindowsIdentity.Impersonate(). I've tried to impersonate with the token handle that comes out of WTSQueryUserToken(), and it doesn't seem to make any difference. Perhaps I ought to try to impersonate based on the token handle that comes out of DuplicateTokenEx()... What do you think? With regard to (2), I'm not sure what your suggesting. Would you clarify? With regard to (3), I'll keep that in mind but I'd like to try other options first. With regard to (*), which I threw in for kicks, is that cited post of yours even relevant? Leaving the permission, privilege discussion for a moment to return to the ERROR_DIRECTORY discussion, I do have some juicy info for you. In my call to CreateProcessAsUser(), when I pass string variables to lpApplicationName and lpCommandLine, I get the 267 error even though I believe the string values to be sound/correct. However, when I pass C#'s string.Empty as lpApplicationName, and I put the exe path and args into lpCommandLine, I get error 3, which is "the system cannot find the path specified". I am setting si.cb = Marshal.SizeOf(si); Lastly I have a relevant, but more general question. I'm currently working with code that make the following sequence of calls: WTSGetActiveConsoleSessionId() WTSQueryUserToken() DuplicateTokenEx() WindowsIdentity.Impersonate() CreateProcessAsUser() (Note the blending of C# and Win32 API.) ... and you seem to think that this will work as long as I get the details right. Under what circumstances would I need to employ this longer sequence? - LogonUser - LoadUserProfile - CreateEnvironmentBlock - SetTokenInformation(TokenSessionId, WTSGetActiveConsoleSessionId()) - OpenWindowStation("winsta0") - OpenDesktop("default") - AddAceToWindowStation - AddAceToDesktop - ImpersonateLoggenOnUser - CreateProcessAsUser - cleanup Thanks a ton! |
||||
![]() |
||||
wj32
Senior Member
Joined: 16 January 2009 Location: Australia Status: Offline Points: 1016 |
Post Options
Thanks(0)
Quote Reply
Posted: 22 January 2009 at 2:01am |
|||
|
Here's what you need to do in order to run a program as SYSTEM:
1. LogonUser with NT AUTHORITY\SYSTEM 2. NtSetInformationToken - set the session ID of the token to whatever you need it to be 3. CreateProcessAsUser while setting Desktop in the ProcessInformation struct to Default\WinSta0 That's it, except for the fact that LogonUser requires TcbPrivilege and CreateProcessAsUser requires AssignPrimaryTokenPrivilege. That means you'll have to run the program as a service first. SYSTEM has both these privileges, but only TcbPrivilege is enabled by default. That means you'll have to enable AssignPrimaryTokenPrivilege. You only need to change the DACLs of the Window Station and Desktop if you're running the program as something other than SYSTEM - SYSTEM should have full rights to them already. Edited by wj32 - 22 January 2009 at 2:10am |
||||
![]() |
||||
wj32
Senior Member
Joined: 16 January 2009 Location: Australia Status: Offline Points: 1016 |
Post Options
Thanks(0)
Quote Reply
Posted: 22 January 2009 at 2:33am |
|||
Tokens can have privileges. Privileges can be enabled permanently (or "enabled by default"), enabled, or disabled. In order for a specific function like CreateProcessAsUser or LogonUser to work, you must have the required privilege enabled. The problem is, normal user accounts do not even have the privileges - you can't enable or disable them because they simply don't exist for normal user accounts' tokens. SYSTEM tokens, by default, have SeAssignPrimaryToken and SeTcbPrivilege while normal tokens do not. SYSTEM tokens have SeTcbPrivilege enabled by default (permanently enabled) while SeAssignPrimaryToken is disabled (you can enable it though). Through AdjustTokenPrivileges, you can enable a disabled privilege, disable an enabled privilege (you can't disable a privilege that's enabled by default though), or remove any privilege permanently. You can't add privileges to a token, so removing a privilege cannot be reverted. I think Matts_User_Name called having-a-privilege a permission while having it enabled a privilege. |
||||
![]() |
||||
Matts_User_Name
Senior Member
Joined: 10 August 2006 Location: USA Status: Offline Points: 687 |
Post Options
Thanks(0)
Quote Reply
Posted: 22 January 2009 at 6:18pm |
|||
|
Isn't LogonUser for the SYSTEM account a little overkill when it is already logged on (Processes like winlogon.exe are running under its account and security context)? I would assume Thread Impersonation would possibly be best instead of logging on the user. Indeed normal (administrator) account do not have the SeAssignPrimaryToken and SeTcbPrivilege meaning all process tokens will have these removed, although we can readd them into our token of 1 thread in our process by use of impersonation.
Hmm, I am not sure about that one. In my experience (Running in an Administrator account on XP) using ATP you can modify (Disable, Enable, Remove) any privilege held in a process' token (Meaning those that are "Enabled by Default" --> Meaning the process started with this Privilege enabled) Also, I am not sure where I ment to imply that having a privilege is a permission and having it enabled is a privilege but I ment: 1. To have a privilege: The privilege is contained inside our process token. We can Disable, Enable, or remove it. 2. To have a privilege enabled: We are able to take advantage of its powers (Ex: Once SeDebugPrivilege is enabled, it allows us to bypass all permission checking when opening processes and threads) Tokens are process-specific while Permissions are object-specific (meaning processes, tokens, threads, files etc) @doug With method 2 or 3: You can have the Service or Injected dll call CreateProcess and specify the specific Window Station and Desktop (Ex: Default is WinSta0\Desktop) for which to run the process in. (When started it will then inherit all the token privileges from the calling process) Ill try to post some code on that when I get home (at school now, arg!) Edited by Matts_User_Name - 22 January 2009 at 6:21pm |
||||
![]() |
||||
wj32
Senior Member
Joined: 16 January 2009 Location: Australia Status: Offline Points: 1016 |
Post Options
Thanks(0)
Quote Reply
Posted: 22 January 2009 at 10:22pm |
|||
Yes, you could steal the token of an existing process, but I find that harder to program than just calling LogonUser...
I've tried doing that. You can only remove enabled-by-default privileges. You can't enable or disable them.
Oops. Didn't read that properly! |
||||
![]() |
||||
Post Reply
|
Page 123 4> |
|
Tweet
|
| Forum Jump | Forum Permissions ![]() You cannot post new topics in this forum You cannot reply to topics in this forum You cannot delete your posts in this forum You cannot edit your posts in this forum You cannot create polls in this forum You cannot vote in polls in this forum |