Bear with me, as I have a somehow tricky setup in a custom AWS EC2 AMI based on Windows Server 2012.
I orchestrate a machine using CloudFormation. Once the machine is up and provisioned through the UserData part of the provisioning script, I need to launch a daemon on the machine. I do so using PowerShell from a remote machine:
Invoke-Command \
-ComputerName '<IP>' \
-Credential $cred \
-ScriptBlock { \
$res = C:\bootstrap.ps1 C:\daemonlauncher.ps1;
Start-Sleep -Seconds 5;
return $res;
};
The contents of bootstrap.ps1
are:
Invoke-WmiMethod -Class "Win32_Process" -Name "Create" -ArgumentList "powershell -File $($args[0])";
And the contents of daemonlauncher.ps1
are simple:
# Some PATH environment setup...
Start-Process -FilePath daemon.exe -ArgumentList 8080;
This way, I end up having a daemon.exe
instance running on port 8080. For now, what happened is:
Invoke-Command
executes in the remote machinebootstrap.ps1
.bootstrap.ps1
creates a new instance of PowerShell, passing to itdaemonlauncher.ps1
.daemonlauncher.ps1
starts thedaemon.exe
process and exits. The daemon remains running.
Now, the tricky part. daemon.exe
is used to launch a second process, let's call it server.exe
. Now, server.exe
listens on an SSL port using a self-signed certificate. However, it fails to load the self-signed certificate, although it is able to create it. server.exe
is written in C#, and the error it throws is (check the access denied part):
Error importing certificate 'c:\server\ssl-certificate.pfx': Access denied
However, if instead of using Invoke-Command
from a remote computer to execute bootstrap.ps1
(step 1) I do so directly from within the target computer, the server.exe
process can load the certificate with no issues at all.
C:\bootstrap.ps1 C:\daemonlauncher.ps1
Examining the Security tab of daemon.exe
with ProcessExplorer, I can see that the Privileges are different depending on how I launched it:
- Launching using
Invoke-Command
from the remote machine:- All privileges are
Enabled
- All privileges are
- Launching
bootstrap.ps1
manually from the target machine:- All privileges are
Disabled
except for:- SeChangeNotifyPrivilege > Default Enabled
- SeCreateGlobalPrivilege > Default Enabled
- SeDebugPrivilege > Enabled
- SeImpersonatePrivilege > Default Enabled
- All privileges are
I'm at a loss here. Any help will be much appreciated.
Further information
After messing with Process Explorer / Process Monitor I could get this additional info:
When started from the remote machine (using Invoke-Command
), daemon.exe
has the correct user ({MACHINE-NAME}\Administrator
) and correct SID
under the Security tab.
Checking with Process Monitor, I can see that server.exe
tries to access %APPDATA%\Microsoft\Crypto\RSA\{SID}
, but it doesn't try to create any file inside it (I think the CREATE FILE on ed0352f...
with NAME NOT FOUND result is just the process trying to read it).
12:01:42.0687133 PM server.exe 1228 CreateFile C:\Users\Administrator\AppData\Roaming\Microsoft\Crypto NAME COLLISION Desired Access: Read Data/List Directory, Synchronize, Disposition: Create, Options: Directory, Synchronous IO Non-Alert, Attributes: S, ShareMode: Read, Write, AllocationSize: 0
12:01:42.0687908 PM server.exe 1228 CreateFile C:\Users\Administrator\AppData\Roaming\Microsoft\Crypto\RSA NAME COLLISION Desired Access: Read Data/List Directory, Synchronize, Disposition: Create, Options: Directory, Synchronous IO Non-Alert, Attributes: S, ShareMode: Read, Write, AllocationSize: 0
12:01:42.0689283 PM server.exe 1228 CreateFile C:\Users\Administrator\AppData\Roaming\Microsoft\Crypto\RSA\S-1-5-21-928426534-1735938674-1186316988-500 NAME COLLISION Desired Access: Read Data/List Directory, Synchronize, Disposition: Create, Options: Directory, Synchronous IO Non-Alert, Attributes: S, ShareMode: Read, Write, AllocationSize: 0
12:01:42.0691444 PM server.exe 1228 CreateFile C:\Users\Administrator\AppData\Roaming\Microsoft\Crypto\RSA\S-1-5-21-928426534-1735938674-1186316988-500\ed0352ff16ca244170b661836cbecde9_63d47ad1-1696-4af6-bfda-1963bc1d25d0 NAME NOT FOUND Desired Access: Generic Read, Disposition: Open, Options: Sequential Access, Synchronous IO Non-Alert, Non-Directory File, Attributes: n/a, ShareMode: Read, AllocationSize: n/a
12:01:42.0692365 PM server.exe 1228 CreateFile C:\Users\Administrator\AppData\Roaming\Microsoft\Crypto\RSA\S-1-5-21-928426534-1735938674-1186316988-500 SUCCESS Desired Access: Read Data/List Directory, Synchronize, Disposition: Open, Options: Directory, Synchronous IO Non-Alert, Attributes: n/a, ShareMode: Read, Write, Delete, AllocationSize: n/a, OpenResult: Opened
12:01:42.0692590 PM server.exe 1228 QueryDirectory C:\Users\Administrator\AppData\Roaming\Microsoft\Crypto\RSA\S-1-5-21-928426534-1735938674-1186316988-500\ed0352ff16ca244170b661836cbecde9_* NO SUCH FILE Filter: ed0352ff16ca244170b661836cbecde9_*
12:01:42.0692752 PM server.exe 1228 CloseFile C:\Users\Administrator\AppData\Roaming\Microsoft\Crypto\RSA\S-1-5-21-928426534-1735938674-1186316988-500 SUCCESS
When I execute the following line from the remote computer I get that the Administrator
user profile is loaded (property Loaded
is True
). Worth noting everything I'm running is with -Credential
for Administrator
:
Invoke-Command \
-ComputerName '<IP>' \
-Credential $cred` \
-ScriptBlock {
Get-WmiObject -Class "Win32_UserProfile";
};
Then, once I run at least once the daemon.exe
from the target machine (just running step 2 from above directly on the target machine), server.exe
DOES CREATE a file under %APPDATA%\Microsoft\Crypto\RSA\{SID}
and writes to it (9a470a...
in this example):
12:06:39.3433354 PM server.exe 3420 CreateFile C:\Users\Administrator\AppData\Roaming\Microsoft\Crypto NAME COLLISION Desired Access: Read Data/List Directory, Synchronize, Disposition: Create, Options: Directory, Synchronous IO Non-Alert, Open For Backup, Attributes: S, ShareMode: Read, Write, AllocationSize: 0
12:06:39.3434039 PM server.exe 3420 CreateFile C:\Users\Administrator\AppData\Roaming\Microsoft\Crypto\RSA NAME COLLISION Desired Access: Read Data/List Directory, Synchronize, Disposition: Create, Options: Directory, Synchronous IO Non-Alert, Open For Backup, Attributes: S, ShareMode: Read, Write, AllocationSize: 0
12:06:39.3434697 PM server.exe 3420 CreateFile C:\Users\Administrator\AppData\Roaming\Microsoft\Crypto\RSA\S-1-5-21-928426534-1735938674-1186316988-500 NAME COLLISION Desired Access: Read Data/List Directory, Synchronize, Disposition: Create, Options: Directory, Synchronous IO Non-Alert, Open For Backup, Attributes: S, ShareMode: Read, Write, AllocationSize: 0
12:06:39.3435435 PM server.exe 3420 CreateFile C:\Users\Administrator\AppData\Roaming\Microsoft\Crypto\RSA\S-1-5-21-928426534-1735938674-1186316988-500\9a470a37b16b84cf43ed29a419dfbb0b_63d47ad1-1696-4af6-bfda-1963bc1d25d0 SUCCESS Desired Access: Generic Write, Read Attributes, Disposition: OpenIf, Options: Sequential Access, Synchronous IO Non-Alert, Non-Directory File, Attributes: S, ShareMode: None, AllocationSize: 0, OpenResult: Created
12:06:39.3436466 PM server.exe 3420 WriteFile C:\Users\Administrator\AppData\Roaming\Microsoft\Crypto\RSA\S-1-5-21-928426534-1735938674-1186316988-500\9a470a37b16b84cf43ed29a419dfbb0b_63d47ad1-1696-4af6-bfda-1963bc1d25d0 SUCCESS Offset: 0, Length: 79, Priority: Normal
12:06:39.3436929 PM server.exe 3420 CloseFile C:\Users\Administrator\AppData\Roaming\Microsoft\Crypto\RSA\S-1-5-21-928426534-1735938674-1186316988-500\9a470a37b16b84cf43ed29a419dfbb0b_63d47ad1-1696-4af6-bfda-1963bc1d25d0 SUCCESS
Once I have run the program locally once, if I execute all from the beginning from the remote computer server.exe
can correctly load the certificate until a machine restart. Then we are back at the beginning of the issue.
Every time it creates a different file under ...\Crypto\RSA\S-1-5-21...\
.