Pergunta

I have an application in .Net that does various admin/config for other applications. I need to be able to stop and start the app pool. I've achieved this, but only if I run the app pool as local system (which is generally accepted as a bad idea).

Initially I started appcmd.exe with Process.Start (using appropriate ProcessStartInfo object), but this eventually lead me to an Exit Code of -1073741502, further research suggests that I need to debug using the windows SDK as it has something to do with an assembly not loading, so I found what seems like a simpler solution in the Microsoft.Web.Administration namespace:

I use the below code, but it seems to require the AppPool running it has an identity of local system (otherwise I get System.UnauthorizedAccessException) - is there a way to start/stop with a less privileged account (I would prefer using Application Identity) - although temporarily elevating permissions is also acceptable.

    Dim serverManager As New ServerManager()
    Dim applicationPoolCollection As ApplicationPoolCollection = serverManager.ApplicationPools

    For Each applicationPool As ApplicationPool In applicationPoolCollection

        If applicationPool.Name = appPoolName Then
            applicationPool.Stop()
            applicationPool.Start()
        End If

    Next

I've set a custom account as the Identity, but I can't work out what the minimum ACL for that user needs to be. As a test, I added the user to the local administrators group, but still get System.UnauthorizedAccessException - this suggests I need to configure a particular permission for the user, but I'm unsure what this is or how to do it. Can anyone help?

Problem is explained here also

Foi útil?

Solução 2

Using @CarlosAg answer, the following solution works:

  1. Create a new User and put them in the Administrators Group

  2. Create a web service to run the restart code, put it in it's own application pool running as a user you created (configure appropriate app pool properties, e.g. queue length etc)

    a. Put below code in your web method (or begin_reqest) to prevent it from being called externally (I think there are other ways to do this in IIS as well, but this was the quickest method I found)

    b. Add additional authentication to web service code as you see fit (we have a Single sign on service I can use).

  3. Reference this service from the web site which is running in an app pool under ApplicationIdentity

This works.

Code:

     If Not HttpContext.Current.Request.IsLocal Then
         Const msg As String = "Only local requests are allowed"
         log4net.LogManager.GetLogger(GetType(Global_asax)).Fatal(msg)
         Throw New Exception(msg)
     End If

Outras dicas

The only way you can do that is if the account that is used to run the code (using Microsoft.Web.Administration) has the right permissions to do "runtime operations" in IIS, and by default that only includes Administrators and SYSTEM, and as you correctly point out in general exposing that level of permission from the Web is a bad idea.

What you probably should do instead is create an Application Pool or some other way to run with high-privileges but that is secured to be only accessible locally (for example using IP and Domain restrictions) and that uses an additional level of authorization checks (for example only allow to be called from the Application) and that is constrained to run the minimum code as possible and the minimum surface required, for example only recycle the pool that belongs to the user, etc. That way if your web application is compromised the damage would be much more constrained.

Now, for the curious… The following is "unsupported" so please don’t use but just providing it for informational purposes.
The API that we use in ServerManager to read configuration is known as AHADMIN and you can “hack enough to read configuration”, for example if you ACL things like:

Cd C:\Windows\System32\inetsrv\config  
icacls . /grant yourUser:(R)  
icacls redirection.config /grant yourUser:(R)  
icacls applicationHost.config /grant yourUser:(R)  

You will be able to read configuration from that point on with that user. Know that at this point encrypted properties will still fail to read since the encryption keys are also protected separately and you probably should never change the ACLs there, but everything else will be readable (except runtime properties like State, etc). You should NEVER allow write access to non-privileged accounts since that would very easily allow for elevation of privileges (for example they could create an Application Pool that runs as SYSTEM and link it to random directory where now they can run code as SYSTEM).

Now, going back to runtime state, for that we use an API we refer to as RSCA (Runtime status and control API) and that in itself is also protected to be only run as SYSTEM or administrators, and although you might find a way to hack that, it is a bad idea to change that as well. but long story short this is not supported and you might easily cause issues to the system.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top