diff --git a/docs/pingcastle/4.0/enterpriseagentdeployment.md b/docs/pingcastle/4.0/enterpriseagentdeployment.md index 3a53e17f50..6a811636f6 100644 --- a/docs/pingcastle/4.0/enterpriseagentdeployment.md +++ b/docs/pingcastle/4.0/enterpriseagentdeployment.md @@ -3,7 +3,7 @@ sidebar_label: Agent deployment --- # Agent Deployment for PingCastle Enterprise -`PingCastleSchedulerService` handles scheduled scanning for domains it can reach directly. Use agent deployment instead when a security or network boundary prevents that — for example, an isolated or air-gapped domain, or a domain separated from the PingCastle Enterprise server by a firewall the scheduler can't cross. In these cases, run `PingCastle.exe` locally on a server that has access to the target domain, and have it push results directly to PingCastle Enterprise over the API. +`PingCastleSchedulerService` handles scheduled scanning for domains it can reach directly. Use agent deployment instead when a security or network boundary prevents that — for example, an isolated or air-gapped domain, or a domain that sits behind a firewall the scheduler can't cross. In these cases, run `PingCastle.exe` locally on a server that has access to the target domain, and have it push results directly to PingCastle Enterprise over the API. ## Program version @@ -31,9 +31,11 @@ PingCastle.exe --healthcheck --server --level Full --api-endpoint If the server requires TLS 1.2, install the TLS 1.2 client package on the system running the audit. +For details on calling the API directly (including through Swagger or PowerShell), see [Using the Swagger API for PingCastle Enterprise](enterpriseapiswagger.md). + ## Automatic Forest Exploration Setup -For large environments, you can simplify scan configuration by using automatic forest exploration. PingCastle then discovers and scans all domains within a forest automatically, using a wildcard in the `--server` parameter. +For large environments, you can simplify scan configuration with automatic forest exploration. When you use a wildcard in the `--server` parameter, PingCastle discovers and scans all domains within a forest automatically. ### Manual Execution diff --git a/docs/pingcastle/4.0/enterpriseapiswagger.md b/docs/pingcastle/4.0/enterpriseapiswagger.md new file mode 100644 index 0000000000..87d8f02fe3 --- /dev/null +++ b/docs/pingcastle/4.0/enterpriseapiswagger.md @@ -0,0 +1,295 @@ +--- +sidebar_label: Swagger API +--- +# Using the Swagger API for PingCastle Enterprise + +PingCastle Enterprise exposes a Swagger UI for calling its REST API directly. Use it to explore available endpoints, authenticate, and test calls before automating them from a script. + +## Prerequisites + +### Enable anonymous authentication in IIS + +The Swagger UI loads without requiring a logged-in user, but IIS must allow anonymous access to the site (or at least to the `/swagger` path) for the page to render. + +If anonymous authentication is disabled, IIS shows a Windows credential popup before the page loads. That popup comes from IIS requesting a Windows identity, not from the API's own login. + +To enable anonymous authentication: + +1. Open **IIS Manager** on the server hosting PingCastle Enterprise. +2. In the left pane, expand **Sites** and select the PingCastle Enterprise site. + + ![IIS Manager with PingCastleEnterprise site selected and Authentication icon visible](kb/0-images/iis-manager-site-selection.png) + +3. Double-click **Authentication** in the center pane. + + ![Authentication settings showing Anonymous Authentication disabled and Windows Authentication enabled](kb/0-images/iis-authentication-settings.png) + +4. Right-click **Anonymous Authentication** and select **Enable**. + + ![Context menu for enabling Anonymous Authentication in IIS](kb/0-images/iis-anonymous-authentication-enable.png) + +:::tip +Changes to IIS authentication settings take effect immediately. You don't need to restart IIS. +::: + +### Gather your base URL and API key + +You need: + +- The base URL of your PingCastle Enterprise server, for example `https://pingcastle.contoso.com`. +- An Agent API key. Create or copy one from **Configuration** > **Agents**. + + :::tip + For full access to Swagger endpoints, set the agent's authorization level to **Perform Admin Actions**, **Read & Write all Enterprise data**, or **Read all Enterprise data**, depending on which calls you need to make. + ::: + + ![Configuration menu with Agents option highlighted](kb/0-images/pingcastle-configuration-agents-menu.png) + + ![Agents page showing API keys, authorization types, and owner](kb/0-images/pingcastle-api-keys-table.png) + +## Open Swagger + +1. In a browser, go to `https:///swagger`. +2. If IIS anonymous authentication is disabled, a Windows credential popup appears first. Enter valid domain credentials, or fix the IIS setting so the popup doesn't appear for every visitor. +3. The Swagger UI loads and lists all API controllers (for example, `Agent`, `Domains`, `Users`) as collapsible sections. + +## Authenticate in Swagger + +The API uses a two-step authentication flow: log in with an Agent API key to get a JSON Web Token (JWT) bearer token, then apply that token so Swagger sends it on every subsequent call. + +### Call Login + +1. On the Swagger page, scroll to the **Agent** section and expand **`POST /api/Agent/Login`**. +2. Click **Try it out**. +3. In the request body editor, replace the template values: + + ```json + { + "apikey": "string", + "location": "string" + } + ``` + +4. Set `apikey` to your Agent API key. +5. Set `location` to any identifying label for where the call originates, such as your hostname. +6. Click **Execute**. +7. In the **Response body**, copy the value after the word `Bearer` (without the surrounding quotes): + + ``` + Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... + ``` + +### Apply the token + +1. Scroll to the top of the Swagger page and click the green **Authorize** button (padlock icon). +2. In the dialog, paste the token into the **Value** field under the `Bearer` security scheme. + + :::note + The field expects the token without the `Bearer ` prefix. If pasting the full `Bearer ` string returns a 401 error, remove the leading `Bearer ` and retry with just the token. + ::: + +3. Click **Authorize**, then **Close**. + +All subsequent **Try it out** calls in Swagger now include this token in the `Authorization` header automatically. + +### Token expiry + +The token is valid for one hour. After that, calls return `401 Unauthorized`. Repeat the login and authorization steps to get a fresh token. + +## Troubleshoot 401 errors and credential popups + +Two different authentication failures can occur, and each points to a different cause: + +- A **Windows credential popup before the page loads** means IIS anonymous authentication is disabled. See [Enable anonymous authentication in IIS](#enable-anonymous-authentication-in-iis). +- An **HTTP 401 response from an API call inside Swagger** means the bearer token is missing, expired, or the API key lacks the required authorization level. Confirm the padlock icon shows as authorized, re-run **Login** for a fresh token, and check the agent's status and authorization level on the **Agents** screen. + +For a full walkthrough of the 401/IIS root cause, see [Scheduler or Agent Deployment Returns 401 Unauthorized Error](kb/scheduler-or-agent-deployment-returns-401-unauthorized-error.md). + +## Use browser dev tools to inspect requests + +Browser developer tools show the raw request and response when Swagger's own display doesn't provide enough detail. + +1. Press **F12** (or right-click and select **Inspect**) to open developer tools. +2. Click the **Network** tab, and tick **Preserve log** if the request needs to survive a page navigation. +3. Perform the action in Swagger, such as clicking **Execute** on an endpoint. +4. Find the corresponding request in the list — its name matches the API path, for example `Login`. +5. Click the request row and check: + - **Headers** — confirm the `Authorization` header is present and starts with `Bearer ` for authenticated calls. + - **Payload** or **Request** — confirm the JSON body Swagger sent matches what you entered. + - **Response** — read the raw response body, which often contains a more specific error message than the Swagger UI renders, such as `"Agent not found"` or `"Location not provided"`. + - **Status** — note the HTTP status code: `400` (bad request or invalid input), `401` (authentication problem), `403` (not authorized), or `500` (server error). +6. Check the **Console** tab for JavaScript errors if the Swagger page itself behaves unexpectedly, such as the **Authorize** dialog not opening. + +## Call the API from PowerShell + +The following helper functions wrap the same login flow and let you call any API endpoint without using the browser. + +### Core functions + +```powershell +Function Invoke-PcApi { + [CmdletBinding()] + param ( + [parameter(Mandatory = $true, Position = 0)] + [System.String]$Uri, + [parameter(Mandatory = $false)] + [hashtable]$Headers = @{}, + [parameter(Mandatory = $false)] + [System.String]$Method = "Get", + [parameter(Mandatory = $false)] + [System.String]$ContentType, + [parameter(Mandatory = $false)] + [System.String]$Body, + [parameter(Mandatory = $false)] + [hashtable]$AdditionalParameters = @{} + ) + + $RequestParameters = @{ + "Uri" = $Global:PingCastle_URL + "/" + $Uri.TrimStart("/"); + "Headers" = @{"Authorization" = "$($Global:PingCastle_JWT)" } + $Headers; + "Method" = $Method + } + + if ($ContentType) { + $RequestParameters["ContentType"] = $ContentType + } + + if ($Body) { + $RequestParameters["Body"] = $Body + } + + if ($AdditionalParameters) { + $RestrictedParams = @("Uri", "Headers", "Method", "ContentType", "Body") + foreach ($Parameter in $RestrictedParams) { + if ($AdditionalParameters.ContainsKey($Parameter)) { + Throw "AdditionalParameters cannot contain the parameter $($Parameter), use -$($Parameter) instead." + } + } + } + + Write-Verbose $RequestParameters.URI + Try { + return Invoke-RestMethod @RequestParameters @AdditionalParameters -ErrorAction Stop + } + catch { + throw $($_.Exception.Message) + } +} + +function Connect-PCServer { + param ( + [Parameter(Mandatory = $False)] + [ValidateNotNull()] + [string]$Server = "localhost", + [Parameter(Mandatory = $True)] + [string]$ApiKey = "", + [switch]$UseHTTP, + [string]$Location = "$($ENV:COMPUTERNAME)", + [string]$Port + ) + + # Construct the URL + if ($UseHTTP) { + $Protocol = "http" + } + else { + $Protocol = "https" + } + + $Base_URL = "$Protocol`://$Server" + + if ($Port) { + $Base_URL = "$BASE_URL`:$Port" + } + + $Login_URL = "$BASE_URL/api/Agent/Login" + + # Build Login Body + $Obj = New-Object -TypeName PSObject + $Obj | Add-Member -MemberType NoteProperty -Name "apikey" -Value $ApiKey + $Obj | Add-Member -MemberType NoteProperty -Name "location" -Value $Location + + $Body_Json = $Obj | ConvertTo-Json + + # Send the POST request + $response = Invoke-WebRequest -UseBasicParsing -Uri $Login_URL ` + -Method "POST" ` + -ContentType "application/json-patch+json" ` + -Body $Body_Json + + # Output new variables for base url and JWT + $Global:PingCastle_URL = $Base_URL + $GLobal:PingCastle_JWT = $response.Content + + # Extract and return the JWT token + return $response.Content +} +``` + +### Example: connect and list domains + +```powershell +Function Get-PCDomain { + [CmdletBinding(DefaultParameterSetName = "All")] + param ( + [Parameter(ParameterSetName = "Single")] + [String] + $id, + [switch]$Raw, + # Domain Name + [Parameter(Mandatory = $True, ParameterSetName = "SingleName")] + [string] + $Name + ) + # Create empty params + $Params = @{} + + If ($PSCmdlet.ParameterSetName -eq "All" -or $PSCmdlet.ParameterSetName -eq "SingleName") { + $Params.Add("Uri", "/api/domains") + } + else { + $Params.Add("Uri", "/api/domains/$id") + } + + $Response = Invoke-PcApi @Params + + # Filter the output as no API for single name only ID. + If ($PSCmdlet.ParameterSetName -eq "SingleName") { + $Response = $Response | Where-Object { $_.name -eq $Name } + } + + If ($Raw) { + $Response + } + else { + $Response | Select-Object Id, Name + } +} +``` + +Usage: + +```powershell +# Connect - needs your Agent API key from the Agents screen +Connect-PCServer -Server "pingcastle.contoso.com" -ApiKey "your-agent-api-key-here" + +# List all domains +Get-PCDomain + +# Get a single domain by name +Get-PCDomain -Name "contoso.com" + +# Call any other endpoint directly +Invoke-PcApi -Uri "/api/domains" -Method Get +``` + +### Troubleshoot PowerShell calls + +- A **401** response from `Invoke-WebRequest` or `Invoke-RestMethod` means the same things as [Troubleshoot 401 errors and credential popups](#troubleshoot-401-errors-and-credential-popups): confirm the API key is enabled and the token (`$Global:PingCastle_JWT`) hasn't expired (one-hour lifetime). Call `Connect-PCServer` again to refresh it. +- If the server uses a self-signed or otherwise untrusted certificate, `Invoke-WebRequest` and `Invoke-RestMethod` fail with a certificate trust error. Resolve this by trusting the certificate — don't disable certificate validation. +- Use `-Verbose` on `Invoke-PcApi` to print the exact URL it calls. + +## Related links + +- [Scheduler or Agent Deployment Returns 401 Unauthorized Error](kb/scheduler-or-agent-deployment-returns-401-unauthorized-error.md) +- [Agent Deployment for PingCastle Enterprise](enterpriseagentdeployment.md) diff --git a/docs/pingcastle/4.0/index.md b/docs/pingcastle/4.0/index.md index 146e260569..62f37a1aa8 100644 --- a/docs/pingcastle/4.0/index.md +++ b/docs/pingcastle/4.0/index.md @@ -6,11 +6,11 @@ sidebar_label: User guide ## About PingCastle -PingCastle is a security assessment and auditing tool for CISOs, Security Auditors, and IT Professionals working with Active Directory and Entra ID. +PingCastle is a security assessment and auditing tool for Chief Information Security Officers (CISOs), Security Auditors, and IT Professionals working with Active Directory and Entra ID. -Netwrix offers various products to help protect your network infrastructure. PingCastle focuses specifically on assessment. It collects comprehensive information from your Active Directory and Entra ID environments, analyzes this data for security risks and misconfigurations, and generates detailed reports with actionable findings. +Netwrix offers various products to help protect your network infrastructure. PingCastle focuses on assessment. It collects comprehensive information from your Active Directory and Entra ID environments, analyzes this data for security risks and misconfigurations, and generates detailed reports with actionable findings. -These reports help you identify and prioritize security issues that need remediation, giving you clear visibility into your security posture and enabling data-driven decisions to improve your environment's security. +These reports help you identify and prioritize security issues that need remediation, giving you clear visibility into your security posture and a basis for data-driven improvements. ## License @@ -193,8 +193,8 @@ PingCastle.exe --healthcheck --server mydomain.com When a healthcheck scan completes, PingCastle generates two files: -- **HTML Report**: Designed for human review, containing visualizations, detailed findings, and remediation guidance -- **XML Report**: Machine-readable format used for consolidation of multiple reports, automation, and integration with other tools +- **HTML Report**: Format for human review, containing visualizations, detailed findings, and remediation guidance +- **XML Report**: Machine-readable format for consolidation of multiple reports, automation, and integration with other tools ### Risk Scoring @@ -270,7 +270,7 @@ PingCastle.exe --hc-conso This consolidates all available XML reports and generates summary reports with trust relationship maps. You can combine XML reports generated from multiple locations to create a comprehensive view of your infrastructure. :::note -PingCastle performs consolidation automatically when using `--server *` for automatic domain discovery. +PingCastle performs consolidation automatically when you use `--server *` for automatic domain discovery. ::: **Output Files** @@ -283,7 +283,7 @@ Consolidation generates three HTML files: ### Option 3: Quick Domain Cartography -For a fast network map without full healthcheck scores (under 5 minutes), use the cartography mode. +For a fast network map (under 5 minutes) without full healthcheck scores, use the cartography mode. **Interactive Mode**: Select "carto" from the menu. @@ -322,7 +322,7 @@ The simplified map presents a cleaner, hierarchical view where each domain appea **File**: `xxx_hilbert_map.html` -The Hilbert map provides a visual representation of network IP address space using fractal functions to compress IP addresses into a 2D visualization. Each square represents a network, so you can identify unused address space or overlapping networks. +The Hilbert map visualizes network IP address space, using fractal functions to compress IP addresses into a 2D view. Each square represents a network, so you can identify unused address space or overlapping networks. **Report Layout**: - **Network Overview**: High-level view of all networks @@ -487,7 +487,7 @@ For authenticated SMTP, provide values for `UserName` and `Password`. For TLS/SS | `--sendXmlTo ` | Send only the XML report. Accepts comma-separated email addresses | | `--sendHtmlTo ` | Send only the HTML report. Accepts comma-separated email addresses | | `--sendAllTo ` | Send both HTML and XML reports. Accepts comma-separated email addresses | -| `--notifyMail ` | Send notification when reports are received | +| `--notifyMail ` | Send a notification when reports arrive | | `--smtplogin ` | Specify SMTP username via command line (overrides config) | | `--smtppass ` | Specify SMTP password via command line (overrides config) | | `--smtptls` | Enable TLS/SSL for SMTP (for ports other than 465 and 587) | @@ -507,7 +507,7 @@ PingCastle can send reports in XML format (encrypted or not) to an API endpoint ![https://www.pingcastle.com/wp/wp-content/uploads/2018/09/pingcastle-swagger.webp](/images/pingcastle/basicuser/image26.webp) -For custom integrations, the API specification is available in Swagger format via the [Swagger Editor](https://editor.swagger.io/?url=https://gist.githubusercontent.com/vletoux/c6c565c8af07b4df5df65ed01ffeb917/raw/fca7a288050b7b17ba6024f2a23ef8c4d46fd813/pingcastle-swagger.json) or as a [direct download](https://gist.githubusercontent.com/vletoux/c6c565c8af07b4df5df65ed01ffeb917/raw/fca7a288050b7b17ba6024f2a23ef8c4d46fd813/pingcastle-swagger.json). +For custom integrations, the API specification is available in Swagger format via the [Swagger Editor](https://editor.swagger.io/?url=https://gist.githubusercontent.com/vletoux/c6c565c8af07b4df5df65ed01ffeb917/raw/fca7a288050b7b17ba6024f2a23ef8c4d46fd813/pingcastle-swagger.json) or as a [direct download](https://gist.githubusercontent.com/vletoux/c6c565c8af07b4df5df65ed01ffeb917/raw/fca7a288050b7b17ba6024f2a23ef8c4d46fd813/pingcastle-swagger.json). If you're using PingCastle Enterprise, see [Using the Swagger API for PingCastle Enterprise](enterpriseapiswagger.md) for a full walkthrough of authenticating and calling the API. ## Scanners @@ -528,19 +528,19 @@ Scanning large numbers of workstations may trigger security alerts. | **computerversion** | Get the version of computers to detect obsolete operating systems | `PingCastle.exe --scanner computerversion --server ` | | **foreignusers** | Enumerate users in denied domains (e.g., bastions) via trusts using MS-LSAT | `PingCastle.exe --scanner foreignusers --foreigndomain --server domain controller` | | **kerberoschecksumhotfix** | Check MS14-068 vulnerability by analyzing KB3011780 installation status | `PingCastle.exe --scanner kerberoschecksumhotfix --server ` | -| **laps_bitlocker** | Check if LAPS and/or BitLocker has been enabled for domain computers | `PingCastle.exe --scanner laps_bitlocker --server ` | +| **laps_bitlocker** | Check whether domain computers have LAPS and/or BitLocker enabled | `PingCastle.exe --scanner laps_bitlocker --server ` | | **localadmin** | Enumerate local administrators on computers | `PingCastle.exe --scanner localadmin --server ` | | **nullsession** | Check if null sessions are enabled and provide examples | `PingCastle.exe --scanner nullsession --server ` | | **nullsession-trust** | Dump domain trusts via null session if possible | `PingCastle.exe --scanner nullsession-trust --server ` | | **oxidbindings** | List all IPs via OXID Resolver (DCOM) to find admin networks. No auth required | `PingCastle.exe --scanner oxidbindings --server ` | | **remote** | Check if remote desktop solutions are installed | `PingCastle.exe --scanner remote --server ` | -| **share** | List all shares and determine if accessible by anyone | `PingCastle.exe --scanner share --server ` | +| **share** | List all shares and determine whether anyone can access them | `PingCastle.exe --scanner share --server ` | | **smb** | Scan for SMB versions available and check if SMB signing is active | `PingCastle.exe --scanner smb --server ` | | **smb3querynetwork** | List all IPs and interface speeds using SMB3 (auth required) | `PingCastle.exe --scanner smb3querynetwork --server ` | | **smbhotfix** | Check MS17-010 (EternalBlue/WannaCry) vulnerability status | `PingCastle.exe --scanner smbhotfix --server ` | | **spooler** | Check if the spooler service is remotely active (exploitable with unconstrained delegation) | `PingCastle.exe --scanner spooler --server ` | | **startup** | Get last startup date to determine if patches have been applied (Legacy) | `PingCastle.exe --scanner startup --server ` | -| **zerologon** | Test for ZeroLogon vulnerability (must be run from inside the domain). *Note: This only performs the check and has no destructive actions* | `PingCastle.exe --scanner zerologon --server ` | +| **zerologon** | Test for ZeroLogon vulnerability (run this from inside the domain). *Note: This only performs the check and has no destructive actions* | `PingCastle.exe --scanner zerologon --server ` | ### Scanner Options @@ -674,7 +674,7 @@ The file size has grown significantly across recent versions due to enhanced cap - **Version 3.4** - Approx 20MB - Includes Microsoft Graph API DLLs for Entra ID integration - **Version 3.5** - Approx 250MB - Includes Microsoft Graph API DLLs plus embedded ASP.NET 8 Runtime -The version 3.5 size increase is due to the migration from .NET Framework 4.7.2 to ASP.NET 8 with native packaging. This change eliminates the need for custom packaging tools (Fody Costura) and allows PingCastle to run without requiring users to install ASP.NET 8 prerequisites on their systems, providing a better deployment experience. +The version 3.5 size increase is due to the migration from .NET Framework 4.7.2 to ASP.NET 8 with native packaging. This change eliminates the need for custom packaging tools (Fody Costura) and lets PingCastle run without users installing ASP.NET 8 prerequisites on their systems. ### pingcastle.exe.config File Location @@ -686,7 +686,7 @@ This migration happened in version 3.5 and applies only if you're upgrading from 1. **Run PingCastleAutoUpdater.exe** to download the update 2. **Verify the version** of PingCastle.exe matches the expected version -3. **Check the readme files** added or updated by the update +3. **Check the readme files** the update adds or changes 4. **Run PingCastleAutoUpdater.exe a second time** to trigger automatic migration During migration: @@ -700,7 +700,7 @@ Visually review the migrated settings in `appsettings.console.json` to ensure th ### PingCastle AntiVirus Detections -Attackers have used PingCastle as a reconnaissance tool in some high-profile attacks, leading some AntiVirus and EDR products to flag it as malicious. +Attackers have used PingCastle as a reconnaissance tool in some high-profile attacks, leading some AntiVirus and Endpoint Detection and Response (EDR) products to flag it as malicious. **Recommended Action**: Whitelist PingCastle.exe on the specific systems and users your organization authorizes for security assessments. Normal end users shouldn't be running PingCastle. @@ -740,9 +740,9 @@ Netwrix is actively working to reduce false positive detections: ## List of open source software used -PingCastle uses a set of open source components to perform its job. +PingCastle relies on a set of open source components. -The list of components used by PingCastle, but not limited to, is: +These components include, among others: - [Bootstrap](https://getbootstrap.com/) licensed under the [MIT license](https://tldrlegal.com/license/mit-license) diff --git a/sidebars/pingcastle/4.0.js b/sidebars/pingcastle/4.0.js index 22f2acf7d1..c1261215f5 100644 --- a/sidebars/pingcastle/4.0.js +++ b/sidebars/pingcastle/4.0.js @@ -71,6 +71,7 @@ module.exports = { label: 'User Guide', items: [ 'enterpriseuser', + 'enterpriseapiswagger', 'enterpriseuser-dashboard', 'enterpriseuser-infrastructure', 'enterpriseuser-entities',