I was recently investigating a potential malware incident flagged by our EDR, and the endpoint team needed to quickly determine if the host had been communicating with known bad domains or IPs. While our SIEM had the alert, the granular session data we needed was in Zscaler. I wanted to document the multi-step process I used, which combines the Zscaler Admin Portal log search with their APIs for automation, as I believe this is a common compliance (SOX, HIPAA) and operational need. The goal was to isolate the host's traffic over a critical 24-hour window and identify any callbacks.
First, I needed to establish a baseline of the host's activity. In the Zscaler Admin Portal, under **Administration > Logs**, I used the **Advanced Search** in the **Web Logs** section. The key is to filter by the internal source IP of the suspected host. Your query will look something like this:
```
Source IP = 10.50.75.102
```
Set your time window appropriately—I used 24 hours prior to the alert. The initial results are overwhelming, so you need to refine. I typically add a few exclusion filters right away to reduce noise from internal traffic and common benign services:
* Exclude `Destination IP` in `10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16`
* Exclude `URL Category` in `Business Systems, Computer and Internet Info, Content Servers`
* Sort by **Transactions** descending to see the highest-volume external domains.
This manual review can identify obvious suspicious patterns, but for a thorough investigation, you need to pull all this data for deeper analysis. Manually exporting gigabytes of logs is impractical. This is where Zscaler's APIs become essential.
I switched to using the `GET /loggrep` API endpoint via PowerShell. This allows you to programmatically retrieve logs matching your criteria. You first need to authenticate via the `POST /authenticate` API to obtain a session cookie. Below is a condensed version of the script I used to gather the data. Note that you must use your admin credentials and API base URL (e.g., ` https://admin.zscaler.net/api/v1`).
```powershell
$baseUrl = "https://admin.zscaler.net/api/v1"
$creds = @{
"username" = "admin_user"
"password" = "admin_password"
} | ConvertTo-Json
# Authenticate
$auth = Invoke-RestMethod -Uri "$baseUrl/authenticate" -Method Post -Body $creds -ContentType "application/json" -SessionVariable websession
# Build loggrep query for the suspect host IP, excluding internal ranges.
$queryParams = @{
"query" = "srcip=10.50.75.102 AND dstip!=10.0.0.0/8 AND dstip!=172.16.0.0/12 AND dstip!=192.168.0.0/16"
"from" = "2024-10-26T00:00:00"
"to" = "2024-10-27T00:00:00"
"type" = "web"
}
$logData = Invoke-RestMethod -Uri "$baseUrl/loggrep" -Method Get -Body $queryParams -WebSession $websession -ContentType "application/json"
$logData.results | Export-Csv -Path "Zscaler_Host_Traffic.csv" -NoTypeInformation
```
Once you have the CSV file, the real analysis begins. I load it into a tool like Splunk or even Excel/PowerBI for aggregation. The critical fields are:
* `dsthost` (Destination Host): Look for anomalous, newly seen, or algorithmically-generated domain names.
* `urlclass` (URL Category): Pay close attention to categories like `Malware`, `Phishing`, `Command and Control`, or newly created custom categories.
* `threatclass` (Threat Class): Any entries here are immediate red flags.
* `responsecode` (Response Code): A high volume of `Response Code = 0` can indicate blocked connections to suspicious sites.
The final step is cross-referencing. I take the list of unique external `dsthost` and `dstip` values from the Zscaler logs and run them against our internal threat intelligence feeds and OSINT sources like VirusTotal or AlienVault OTX. Any matches, especially to recent IOCs, provide the evidence needed to justify isolating the host. This entire process, from initial log search to actionable IOC list, can be templated and automated for future incidents, which is a huge win for audit and compliance reporting, as it creates a clear, repeatable investigation trail.
Logs don't lie.
> Exclude `Destination IP
Sorry, can I ask a quick clarification? When you say exclude destination IPs to cut down noise, are you referring to your internal network ranges, or are there specific external IPs you always filter out first? I'm trying to build a standard filter list for our team.
Usually internal ranges. I start with our RFC 1918 subnets, then exclude major SaaS provider IPs our company uses - things like Office 365 front doors or AWS S3 endpoints that every host talks to constantly. That alone strips out 70% of the log entries.
But you can't just blindly exclude all external IPs. The whole point is to find the malicious external call, so your filter list needs to be built from your own known-good infrastructure and trusted services, not a generic list you found online.
Your CRM is lying to you.