When a named pipe client connects to a server and writes some data, the server can call ImpersonateNamedPipeClient() to impersonate the client. (The server does need to read the data before calling ImpersonateNamedPipeClient()).
As we can see at this link, this can lead to a privilege escalation security vulnerability.
Is possible to prevent/disable/deny this impersonation, so that a client can connect to the named pipe but not allow the server to impersonate?
Note 1: I know that the client needs to write on the named pipe first. But in some cases, the client will need to write first, so I need to prevent this security flaw.
Note 2: A solution that applies to Windows XP and above is appreciated.
When calling CreateFile() to open the client end of the named pipe, pass SECURITY_IDENTIFICATION in the dwFlagsAndAttributes parameter. This allows the server to identify the user and to determine the client's privileges, but prevents the server from impersonating the client's security context.
You can use SECURITY_ANONYMOUS instead if you also want to prevent the server from identifying the user.
Note that the server can still successfully call ImpersonateNamedPipeClient() but any attempt to make use of the impersonation token will be restricted by the specified impersonation level. For example, if the server attempts to open a file while impersonating the client at identification or anonymous level, the operation will fail.
For more information, see the Impersonation Levels page on MSDN.
It should also be noted that as of Windows XP service pack 2, the server cannot impersonate the client unless it holds the SeImpersonatePrivilege privilege. (See ImpersonateNamedPipeClient on MSDN.) In the default configuration, only system services and administrators have this privilege. This effectively mitigates many (though not all) of the risks described in the article you link to.
Related
Is it impossible to access the mapped network drive( mapped in user session) from service after impersonating the current user by using ImpersonateLoggedOnUser Windows API?
Yes, this is impossible. Drive mappings are only established during an interactive logon. The ImpersonateLoggedOnUser function does not impersonate the user's entire logon session, just their security context. This is only one of the many things that cannot be done using impersonation.
I suppose you might be able to do this by duplicating the user's login token (obtained from one of their interactive processes), and then using that to call the CreateProcessAsUser function. You would then launch a process that would work with the mapped network drive(s). I'm not absolutely certain that this will work, as I've never done it, but it seems theoretically possible.
Of course, it begs the question of why you need to follow such a circuitous route. It would be eminently more sensible to just run your code in the user's interactive process to begin with, as a standard Windows application.
This is not something that a service is designed to do. Services do not support mapped network drives. If you want to access a network resource from within a service, you should just use the UNC path.
I am looking forward for an example for using a user defined control code in services. I want to send a user defined command to my windows service. At this command windows service will create a named-pipe for client process, and client will establish a connection with this named-pipe by CreateFile function. My custom control sometimes works well but later it shows error for invalidation.
So how can I establish information exchange between a service and various clients?
SERVICE_USER_DEFINED_CONTROL is rarely used. When it is used, it is generally to prompt the service to re-read its configuration file. (On unix SIGHUP is generally used for the same purpose).
In your case the correct answer is to simply create the named pipe on startup and keep listening, and wait for someone to connect if they ever do.
The following method is a DCOM server method. The COM client and server is running in different WinXP machines. The COM client calls RegisterClient method to register callback interface. The problem is QueryInterface method fails with error code E_ACCESSDENIED. What could be the reason for the issue?
STDMETHODIMP CGEMExtension::RegisterClient(IUnknown** ppGEMExtensionEvents, int* nClientId, int* nResult)
{
HRESULT hRes = (*ppGEMExtensionEvents)->QueryInterface(IID_IGEMExtension,(void**)&pUnknown);
return hRes;
}
When you get an E_ACCESSDENIED, it means you have a permissions problem (don't waist your time on firewalls or registrations - the former will raise errors telling you the service is not available, and the latter will tell you the class is not registered or so). COM relies on Windows permissions, so this is what you should focus on.
In your case, if I understand the case correctly, the server actually calls the client, in order to get the right interface. For that, the user running the server should have the right permissions on the client side. A few suggestions:
As daramarak suggests, have the server and the client use the same domain user, or the same local user with the same password.
On the client, set this setting to "classic".
Give the server's user, if known to the client, additional permissions using DCOMCNFG.
This might be because the correct permissions is wrong on the other computer. Simplest way to check this is to turn on logging with secpol (Local Policies, Audit policy, turn on logging of logon events and object access) then you can see if you are trying to access the other machine.
If you are just testing then I would suggest to use the setting "run as interactive user" on the com object in component services and make sure that you have the same user with the same password on both machines. Then you must be running as the common user on the client machine. Spesifically setting the user to the common user is also possible.
As a general advice to debugging DCOM connectivity: Turn off all firewalls and such to make sure that the connection is working, then turn on security measures one by one, making sure that you leave the correct ports open and that the correct users have the correct permissions.
I give you my experience even if it may not apply directly to your specific case.
On Windows 7 at 64bit I have an exe compiled with x64 and a dll compiled at 32 bit.
A COM object lives inside the dll.
The exe (launched by the "normal" user) creates the COM object (on the same computer) asking for IUnknown and the creation is successful. Then the exe asks for a different interface through QueryInterface and it fails with E_ACCESSDENIED.
If I launch the exe "as administrator" then the QueryInterface will return with S_OK.
I did not investigate further, I suspect there is some policy about the 32 bit - 64 bit interaction.
I wish to use named pipes in my app. Server would be NT service and client is user space app.
I presume that there could be a problem if someone could create application client that lock pipe(or something) and my server stop receive messages.
I wish to add that client should always send messages and server receive them. If someone disturb that process there be a problem.
I need advice how to secure named pipes
Here are some things to consider in terms of implementing "secured" named pipes.
Named pipes in Windows OS are placed in a special path \\.\pipe\ to which every user (including guest) has access.
A named pipe can have multiple instances that share the same name;
Each instance connects exactly one pipe server and one pipe client.
New pipe clients connected to the pipe servers in round-robin order.
The creator of the first instance decides the maximum number of instances as well as specifies the security descriptors.
This includes an access control list (DACL) to control all the instances.
The default descriptor grants read access to everyone and full access only to the creator user and the administrators.
If a named pipe does not exist, any user can create the first instance and set DACL of all pipe instances.
If it exists, only users with FILE_CREATE_PIPE_INSTANCE permission can create new instances.
Take advantage of FILE_FLAG_FIRST_PIPE_INSTANCE flag for your server to ensure that it is creating the first instance.
Credits: Man-in-the-Machine (MitMa) attacks on ill-secured inter process communications, which explains the harm of not securing many IPC methods including named pipes.
AFAIK, multiple different client processes can all open the named pipe and write to the single reader process. This would certainly hold true on Unix, so it probably does on Windows too.
That means that a single process cannot stop other processes writing to the server - though a misbehaved process might overwhelm the server with its messages. There is no easy protection against an over-enthusiastic client.
Are there any alternatives to LogonUser and for impersonating given account in order to access network resources? I'm looking for the method of impersonation which would let me connect to machine in foreign domains (or, workgroup machines for the same matter).
For initial data I have: machine name, username (or domain\username), cleartext password.
I know there's a way to establish connection using WNetAddConnection to a \\machinename\ipc$, then most network functions will run in a context of that account, however win2008 added another twist and some functions still use the account, that thread is running under.
I'm also aware, that there's some way to get an impersonation token using SSPI. Have anyone experimented with those tokens, are they good for accessing shares, SCM, remote registry and stuff? Is is what WNetAddConnection is using?
EDIT: To clarify, the reason I cannot use LogonUser is because I need to impersonate user in a non-trusted domain or workgroup
EDIT2: Another clarification: the item I'm trying to implement is similar to psexec, e.g.:
program should not modify host or active directory configuration (e.g.: create temporary local users, etc). Moreover assumption cannot be made that it is running on DC or not
there can be no assumptions made about which software is pre-installed on the remote host, only condition given is that windows file sharing is enabled on target
Account/password is known to be working on target, but target machine may be in local domain, foreign domain, not in domain at all.
EDIT3: I would really love to hear more about SSPI InitializeSecurityContext / AcquireCredentialsHandle option. Is there anybody who has been working with this API extensively? Is it possible to use the tokens returned with impersonation, so that a thread can access network shares and copy files, etc? Can someone post a working code snippet?
EDIT4: Thanks to Marsh Ray, problem got resolved. If anyone is looking to see the proof-of-concept code, it is here
If you're wanting to "access network resources" outside of your forest, do that with WNetAddConnection2/3 as you mentioned, or use the standard RPC APIs with RPC_ C__ AUTHN__ GSS__ NEGOTIATE and and explicit credentials structure.
Normally, "impersonation" is something that happens on the server side. The server side will be able to impersonate the connection as the account you're connecting as.
But the key is this: impersonation only makes sense for impersonating an account the server can access in his local SAM/domain/forest directory. If the client and server are in different forests, they clearly can't agree on the SID of an account for an impersonation token (except for the case of well-known SIDs like Administrator which serve mainly to confuse this kind of thing), and that seems necessary to check against DACLs etc.
Perhaps what you want is to call LogonUserEx with the LOGON32__ LOGON__ NEW__ CREDENTIALS flag. This should succeed (even in a different forest - it doesn't actually authenticate the credentials you give it) giving you a token with the username/password you specified. You may have to use DuplicateToken to turn this into an impersonation token. Then you can use SetThreadToken to replace the token on your thread.
IMHO this isn't really "impersonation", you're just using the credentials outright, but it allows you to access network resources transparently as the arbitrary username/password you supply.
Edit: Oh yeah, be aware that there is no protection against man-in-the-middle on this type of connection. The client especially cannot strongly authenticate the server (short of heroics like IPSEC), so in theory you can't trust anything the server tells you.
The theory goes that you pass the credentials as a SEC_WINNT_AUTH_IDENTITY structure to the AcquireCredentialsHandle function that creates the handle used in InitializeSecurityContext. I never tried this on foreign domains though and I don't know if it works.
Doing this directly and reliably via the Windows API seems next to impossible, plus Windows does so much work behind the scenes to make network access "just work". Plus the impersonation side of things only works for the single thread that called the APIs.
But... you can run a whole program under a different user... such as when you run a service.
So you could edit the registry in your main program to run various services under different security tokens and use IPC/Sockets to communicate with those processes from your main application. ie. a whole bunch (or restarting and reconfiguring the same process) of helper processes running under the different user(s) which your main app abuses.
I realize this is a hack but it seems viable ;)
You could open a command line, map the drive using the plaintext username and password. Then disconnect the drive:
net use m: \\machinename\share password /user:username
... do stuff ...
net use m: /delete
http://technet.microsoft.com/en-us/library/cc756153(WS.10).aspx