The next part of my DNS protection and identification series – this time focusing on DGA (Domain Generation Algorithm).
DGAs are used to evade traditional IOCs such as static domains and IP addresses. How does it work? It’s quite simple: a compromised host continuously generates domain names and sends DNS queries. If one of those domains resolves successfully, the infected machine attempts to communicate with the C2 server.

What about protection mechanisms? Let’s check them out.
I created two PowerShell scripts to simulate DGA behavior:
- DGA.ps – generates completely random domain names, each 12 characters long.
# Parameters
$BaseDomain = "com" # Base domain to append
$Seed = 12345 # Seed for random number generator
$DomainCount = 50 # Number of domains to generate (limited to 50)
$DomainLength = 8 # Length of the generated subdomain
# Function to initialize a random generator with a seed
function Initialize-Random {
param([int]$Seed)
$Global:Random = New-Object System.Random $Seed
}
# Function to generate a random string of a specified length
function Generate-RandomString {
param([int]$Length)
$Chars = "abcdefghijklmnopqrstuvwxyz0123456789"
$CharsArray = $Chars.ToCharArray()
$String = ""
for ($i = 0; $i -lt $Length; $i++) {
$String += $CharsArray[$Random.Next(0, $CharsArray.Length)]
}
return $String
}
# Function to generate domains using a DGA
function Generate-DGA {
param([int]$Count, [int]$Length, [string]$BaseDomain)
$Domains = @()
for ($i = 1; $i -le $Count; $i++) {
$RandomString = Generate-RandomString -Length $Length
$Domains += "$RandomString.$BaseDomain"
}
return $Domains
}
# Function to send DNS queries for the generated domains
function Query-DNS {
param([string[]]$Domains)
foreach ($Domain in $Domains) {
Write-Host "Querying DNS for $Domain" -ForegroundColor Cyan
try {
Resolve-DnsName -Name $Domain -Type A -ErrorAction SilentlyContinue
} catch {
# Do nothing, just query
}
}
}
# Initialize the random generator with the seed
Initialize-Random -Seed $Seed
# Generate domains
Write-Host "Generating up to $DomainCount domains using DGA..." -ForegroundColor Yellow
$GeneratedDomains = Generate-DGA -Count $DomainCount -Length $DomainLength -BaseDomain $BaseDomain
# Display the generated domains
$GeneratedDomains | ForEach-Object { Write-Host $_ -ForegroundColor Green }
# Query DNS for each generated domain
Query-DNS -Domains $GeneratedDomains
- DGA_dictionary.ps – generates domains using random combinations of dictionary words, making them resemble more typical websites.
# Configuration
$WordList = @(
"alpha", "secure", "cloud", "data", "stream", "net", "sys", "core",
"dark", "wolf", "intel", "pulse", "zero", "black", "zone"
)
$TLDList = @("xyz", "top", "tk", "online", "info", "click", "site")
$DomainCount = 50 # Total domains to generate
$DomainLength = 2 # Number of dictionary words to combine
# Initialize random number generator (not seeded = more random each time)
$Random = [System.Random]::new()
# Generate one dictionary-based domain
function Generate-DictionaryDomain {
param ([array]$Words, [int]$WordCount, [string[]]$TLDs)
$domainParts = @()
for ($i = 0; $i -lt $WordCount; $i++) {
$word = $Words[$Random.Next(0, $Words.Length)]
$domainParts += $word
}
$tld = $TLDs[$Random.Next(0, $TLDs.Length)]
$subdomain = ($domainParts -join "") + "." + $tld
return $subdomain.ToLower()
}
# Generate list of random DGA domains
function Generate-DGA-Domains {
param([int]$Count, [array]$Words, [int]$WordCount, [string[]]$TLDs)
$domains = @()
for ($i = 0; $i -lt $Count; $i++) {
$d = Generate-DictionaryDomain -Words $Words -WordCount $WordCount -TLDs $TLDs
$domains += $d
}
return $domains
}
# Query each domain via DNS
function Query-DNS {
param([string[]]$Domains)
foreach ($domain in $Domains) {
Write-Host "Querying DNS for $domain" -ForegroundColor Cyan
try {
Resolve-DnsName -Name $domain -Type A -ErrorAction SilentlyContinue | Out-Null
} catch {
# Silent fail — this is expected for non-existent domains
}
}
}
# === MAIN ===
Write-Host "Generating $DomainCount random dictionary-based DGA domains..." -ForegroundColor Yellow
$GeneratedDomains = Generate-DGA-Domains -Count $DomainCount -Words $WordList -WordCount $DomainLength -TLDs $TLDList
# Print generated domains
$GeneratedDomains | ForEach-Object { Write-Host $_ -ForegroundColor Green }
# Perform DNS requests
Query-DNS -Domains $GeneratedDomainsp
Umbrella
Umbrella’s behavior remained the same as in previous infiltration and exfiltration tests: it simply categorized the domains as Uncategorized and did nothing further.
FortiGate
FortiGate assigned categories to the generated domains, regardless of which script was used. No advanced detection or DGA-specific behavior was observed.
Palo Alto
Using the first script, Palo Alto correctly identified the traffic as DGA-generated domains. With the second script, some domains were flagged as spyware, while others (especially those using dictionary-based words) were treated as legitimate – which is actually the correct behavior.
Interestingly, when I reduced the generated domain length from 12 to 8 characters, Palo no longer identified them as malicious – probably to avoid false positives.
Conclusion
FortiGate and Umbrella offer no real protection against DGA techniques. They simply categorize domains using static lists, without deeper inspection. Palo Alto is the only solution that attempted to intelligently identify DGA behavior – although even then, it has limitations depending on domain structure and length.