Classic ASP/MSSQL Authentication Issue using CredSpec

274 views Asked by At

I'm currently trying to make some improvements to some old (and soon to be phased out) infrastructure in preperation for a move to .NET core. We have a small feedback form which writes into a SQL table using SQLOLEDB connection strings. These strings works fine with a username/password defined in cleartext though I am looking to move away from this method in favour of integrated authentication.

I have done a lot of work to get to where I am:

  1. Built a docker container based on IIS with ASP features installed.
  2. Running the container in a swarm on a Windows host - joined to our AD domain.
  3. Setup gMSAs in order to provide domain account access to the database.

At present, I've ran through all the steps in MS' gMSA on Windows Containers guide (https://learn.microsoft.com/en-us/virtualization/windowscontainers/manage-containers/manage-serviceaccounts). The tests check out, I'm able to run all the tests in https://learn.microsoft.com/en-us/virtualization/windowscontainers/manage-containers/gmsa-troubleshooting#check-the-container with no issues, however when I try to connect using my connection string, I receive an error in my logs showing:

2020-09-28 19:36:43 172.17.173.120 POST /Default.asp |42|80040e4d|Login_failed_for_user_'NT_AUTHORITY\ANONYMOUS_LOGON'.

This, to me, doesn't make much sense since the application pool identity is set to network and the tests check out on the container.

Now I've tried a few things like editing the web.config to have impersonate set to true/false, authentication via Windows but I'm still kind of stumped. I've set the host to be allowed to delegate any service over Kerberos.

I also tried logging in using:

docker exec -it --user "NT AUTHORITY\NETWORK SERVICE" cb4 powershell

then running:

$connectionString = 'Data Source=serverhostname.domain.local;database=databasename;Integrated Security = True;'
$sqlConnection = New-Object System.Data.SqlClient.SqlConnection $connectionString
$sqlConnection.Open()
$sqlConnection | select *

which results in a database connection with an open state.

The application pool is setup with the NetworkService identity

Get-ItemProperty IIS:\AppPools\domain.co.uk\ -Name processModel

identityType           : NetworkService
userName               :
password               :
loadUserProfile        : False
setProfileEnvironment  : True
logonType              : LogonBatch
manualGroupMembership  : False
idleTimeout            : 00:20:00
idleTimeoutAction      : Terminate
maxProcesses           : 1
shutdownTimeLimit      : 00:01:30
startupTimeLimit       : 00:01:30
pingingEnabled         : True
pingInterval           : 00:00:30
pingResponseTime       : 00:01:30
logEventOnProcessModel : IdleTimeout
PSPath                 : WebAdministration::\\413E8843BBEF\AppPools\domain.co.uk\
PSParentPath           : WebAdministration::\\413E8843BBEF\AppPools
PSChildName            : domain.co.uk\
PSDrive                : IIS
PSProvider             : WebAdministration
Attributes             : {identityType, userName, password, loadUserProfile...}
ChildElements          : {}
ElementTagName         : processModel
Methods                :
Schema                 : Microsoft.IIs.PowerShell.Framework.ConfigurationElementSchema

Any suggestions would be appreciated!

2

There are 2 answers

0
jimbo8098 On BEST ANSWER

Ok, so I figured this out and posted my findings in a public Gist:

https://gist.github.com/jimbo8098/48fa8d1cd05a61b35534aa107decb3e3

Basically, the problem was that while the application pool identity was set to Network, the site was not, it was using what appears to have been IUSR. Given this, I was not relaying the gMSA account to ASP's scripts and therefore I was unable to use integrated auth. The solution was to run:

Set-WebConfigurationProperty system.webServer/security/authentication/anonymousAuthentication -Name "userName" -Value ""; if ($?) {
Set-WebConfigurationProperty system.webServer/security/authentication/anonymousAuthentication -Name "password" -Value ""; if ($?) {
Set-WebConfigurationProperty system.webServer/security/authentication/anonymousAuthentication -Name "logonMethod" -Value 2;}}

What this did was set the username and password to blank and the logon method to network. This was perfect since it meant the application pool and site both used the expected account, the gMSA one.

A very useful way I found to get to the bottom of this was to make a test script:

<%
Set objNetwork = CreateObject("WScript.Network")
strNAME = objNetwork.computername
response.write("Value of strNAME variable: " & strNAME & "<br>")
response.write("Domain = " & objNetwork.UserDomain & "<br/>")
response.write("ComputerName = " & objNetwork.ComputerName & "<br/>")
response.write("UserName = " & objNetwork.UserName & "<br/>")
%>

Prior to the solution, this showed IUSR and was my big clue to the problem. After the solution, the UserName read app$ (where app was the name of the gMSA) with the expected Domain.

5
Bruce Zhang On

There are serveral things you need to pay attention to when connecting to the database.

  1. The identity of application pool should have a domain account.
  2. The domain account has permission to read or change in database.
  3. IIS server and sql server should in same intranet and use same domain.

More details can refer to this thread's answer.