Kurumsal ağlarda DNS, genellikle güvenlik açısından en çok göz ardı edilen bileşenlerden biridir. Oysa DNS filtreleme, kötü amaçlı yazılımların komuta-kontrol sunucularıyla iletişimini kesmekten tutun da kullanıcıların zararlı sitelere erişimini engellemeye kadar kritik bir savunma katmanı oluşturur. Windows Server üzerinde DNS filtrelemeyi doğru yapılandırmak, hem maliyetsiz hem de son derece etkili bir güvenlik önlemi olarak öne çıkar. Bu yazıda adım adım gerçek dünya senaryolarıyla Windows Server DNS filtrelemeyi ele alacağız.
DNS Filtreleme Neden Bu Kadar Önemli?
Düşün bir dakika: Bir kullanıcı farkında olmadan kimlik avı bağlantısına tıkladığında ilk ne olur? Tarayıcı, söz konusu domain için DNS sorgusu gönderir. Eğer bu noktada bir filtreleme mekanizman varsa, zararlı domain hiçbir zaman IP adresine çözümlenmez ve bağlantı kurulmadan tehdit bertaraf edilir.
Windows Server DNS’in built-in özellikleri birçok kurum için yeterli koruma sağlayabilir. Response Policy Zone (RPZ) desteği olmasa da PowerShell, DNS Manager politikaları ve üçüncü taraf entegrasyonlarıyla güçlü bir filtreleme altyapısı kurabilirsin.
Temel filtreleme senaryoları:
- Bilinen zararlı domainlerin engellenmesi (malware, phishing, C2 sunucuları)
- Kategoriye göre içerik filtrelemesi (sosyal medya, kumar, yetişkin içerik)
- DNS tünelleme saldırılarının tespiti ve engellenmesi
- Split-horizon DNS ile iç/dış kaynak ayrımı
- Çalışan saatlerine göre dinamik filtreleme
Ortamın Hazırlanması
Önce mevcut DNS yapını kontrol edelim. Windows Server 2016 ve üzeri sürümler, DNS politikaları açısından çok daha yetenekli geldi. Hangi sürümde olduğunu kontrol et:
Get-WindowsFeature -Name DNS
$PSVersionTable.PSVersion
(Get-WmiObject Win32_OperatingSystem).Caption
DNS Server rolü yüklü değilse şu komutla kur:
Install-WindowsFeature -Name DNS -IncludeManagementTools -IncludeAllSubFeature
Import-Module DNSServer
Sonra mevcut DNS zone’larını ve yapılandırmayı görelim:
Get-DnsServer
Get-DnsServerZone
Get-DnsServerForwarder
Get-DnsServerCache
Bu çıktılar sana başlangıç noktasını verecek. Özellikle forwarder ayarlarına dikkat et. Çoğu kurumda forwarder olarak ISP’nin DNS adresleri girilmiş olur ki bu güvenlik açısından hiç ideal değildir.
DNS Politikası ile Temel Filtreleme
Windows Server 2016 ile birlikte gelen DNS Politikaları, belirli istemci gruplarına, saatlere veya sorgulara göre farklı yanıtlar döndürmeni sağlar. Bu, filtrelemenin temelidir.
Engellenecek Domain Listesi Oluşturma
Önce engellenecek domainleri tutacak bir yapı kur. Ben genellikle bir TXT dosyasından besleyen bir PowerShell scripti tercih ediyorum:
# Engellenecek domainleri dosyadan oku ve DNS zone olarak ekle
$blockedDomains = Get-Content "C:DNSblocked_domains.txt"
$dnsServer = $env:COMPUTERNAME
foreach ($domain in $blockedDomains) {
$domain = $domain.Trim()
if ($domain -and -not $domain.StartsWith("#")) {
try {
# Zone yoksa oluştur
if (-not (Get-DnsServerZone -Name $domain -ErrorAction SilentlyContinue)) {
Add-DnsServerPrimaryZone -Name $domain -ZoneFile "$domain.dns" -DynamicUpdate None
Write-Host "Zone eklendi: $domain" -ForegroundColor Green
}
# SOA ve NS kayıtları otomatik eklenir, A kaydı ekle (sinkhole IP)
Add-DnsServerResourceRecordA -ZoneName $domain -Name "@" -IPv4Address "0.0.0.0" -ErrorAction SilentlyContinue
Add-DnsServerResourceRecordA -ZoneName $domain -Name "*" -IPv4Address "0.0.0.0" -ErrorAction SilentlyContinue
} catch {
Write-Warning "Hata - $domain : $($_.Exception.Message)"
}
}
}
Yukarıdaki script, zararlı domainler için local zone oluşturur ve bunları 0.0.0.0 adresine yönlendirir. Bu yönteme DNS Sinkhole denir. Wildcard A kaydı (*) sayesinde sub.zararlısite.com gibi alt domainler de engellenir.
Sinkhole IP Seçimi
0.0.0.0 yerine kendi ağında bir “uyarı sayfası” sunucusu kurabilirsin. Böylece kullanıcı engellenen siteye erişmeye çalıştığında boş bir sayfa yerine anlamlı bir uyarı mesajı görür:
# Uyarı sunucusu IP'si (kendi ortamında değiştir)
$sinkholeIP = "192.168.1.250"
# Mevcut zone'ların sinkhole IP'sini güncelle
$zones = Get-DnsServerZone | Where-Object {$_.ZoneFile -like "*.dns" -and $_.ZoneName -notlike "*.in-addr.arpa"}
foreach ($zone in $zones) {
$records = Get-DnsServerResourceRecord -ZoneName $zone.ZoneName -RRType A -ErrorAction SilentlyContinue
foreach ($record in $records) {
if ($record.RecordData.IPv4Address.IPAddressToString -eq "0.0.0.0") {
$newRecord = $record.Clone()
$newRecord.RecordData.IPv4Address = [System.Net.IPAddress]::Parse($sinkholeIP)
Set-DnsServerResourceRecord -ZoneName $zone.ZoneName -OldInputObject $record -NewInputObject $newRecord
}
}
}
Write-Host "Sinkhole IP guncellendi: $sinkholeIP"
DNS Politikalarıyla Gelişmiş Filtreleme
DNS politikaları, kural tabanlı çok daha esnek bir yapı sunar. Örneğin mesai saatleri dışında sosyal medya erişimini engellemek istiyorsun diyelim:
# Mesai saati dışı (18:00-08:00) sosyal medya engeli için politika
# Önce istemci subnet'i tanımla
Add-DnsServerClientSubnet -Name "InternalUsers" -IPv4Subnet "192.168.0.0/16"
# Zaman dilimi tanımla (mesai saatleri)
Add-DnsServerQueryResolutionPolicy `
-Name "BlockSocialAfterHours" `
-Action DENY `
-ClientSubnet "EQ,InternalUsers" `
-TimeOfDay "EQ,18:00-08:00" `
-QName "EQ,*.facebook.com,*.twitter.com,*.instagram.com,*.tiktok.com" `
-ProcessingOrder 1 `
-PassThru
Politikanın aktif olduğunu doğrula:
Get-DnsServerQueryResolutionPolicy | Format-List Name, Action, ProcessingOrder, IsEnabled
Otomatik Blocklist Güncelleme Sistemi
Manuel liste yönetimi uzun vadede sürdürülemez. Ücretsiz tehdit istihbaratı kaynaklarından otomatik güncelleme yapan bir sistem kur:
# Tehdit istihbaratı kaynaklarından blocklist güncelleme scripti
# C:DNSUpdate-BlockList.ps1
param(
[string]$BlockListPath = "C:DNSblocked_domains.txt",
[string]$LogPath = "C:DNSLogsupdate_$(Get-Date -Format 'yyyyMMdd').log"
)
# Log dizini oluştur
if (-not (Test-Path (Split-Path $LogPath))) {
New-Item -ItemType Directory -Path (Split-Path $LogPath) -Force | Out-Null
}
function Write-Log {
param([string]$Message)
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
"$timestamp - $Message" | Tee-Object -FilePath $LogPath -Append
}
# Ücretsiz blocklist kaynakları
$sources = @(
@{
Name = "Malware Domain List"
URL = "https://www.malwaredomainlist.com/hostslist/hosts.txt"
Parser = {
param($content)
$content -split "`n" | Where-Object {$_ -match "^0.0.0.0s+"} |
ForEach-Object {($_ -split "s+")[1]} |
Where-Object {$_ -and $_ -ne "0.0.0.0"}
}
},
@{
Name = "StevenBlack Hosts"
URL = "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts"
Parser = {
param($content)
$content -split "`n" | Where-Object {$_ -match "^0.0.0.0s+" -and $_ -notmatch "localhost"} |
ForEach-Object {($_ -split "s+")[1]} |
Where-Object {$_ -and $_ -ne "0.0.0.0"}
}
}
)
$allDomains = @()
foreach ($source in $sources) {
try {
Write-Log "Indiriliyor: $($source.Name)"
$content = Invoke-WebRequest -Uri $source.URL -TimeoutSec 60 -UseBasicParsing | Select-Object -ExpandProperty Content
$domains = & $source.Parser $content
$allDomains += $domains
Write-Log "$($source.Name): $($domains.Count) domain bulundu"
} catch {
Write-Log "HATA - $($source.Name): $($_.Exception.Message)"
}
}
# Tekrar edenleri temizle ve sırala
$uniqueDomains = $allDomains | Sort-Object -Unique
Write-Log "Toplam benzersiz domain: $($uniqueDomains.Count)"
# Dosyaya yaz
$uniqueDomains | Set-Content $BlockListPath -Encoding UTF8
Write-Log "Blocklist guncellendi: $BlockListPath"
Bu scripti Task Scheduler’a ekle:
# Scheduled Task olustur (her gece 02:00'de calistir)
$action = New-ScheduledTaskAction `
-Execute "PowerShell.exe" `
-Argument "-NonInteractive -ExecutionPolicy Bypass -File C:DNSUpdate-BlockList.ps1"
$trigger = New-ScheduledTaskTrigger -Daily -At "02:00"
$settings = New-ScheduledTaskSettingsSet `
-ExecutionTimeLimit (New-TimeSpan -Hours 1) `
-RestartCount 3 `
-RestartInterval (New-TimeSpan -Minutes 10)
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -RunLevel Highest
Register-ScheduledTask `
-TaskName "DNS-BlockList-Update" `
-Action $action `
-Trigger $trigger `
-Settings $settings `
-Principal $principal `
-Description "DNS blocklist guncelleme gorevi"
Write-Host "Scheduled task olusturuldu."
DNS Tünelleme Tespiti
DNS tünelleme, saldırganların güvenlik duvarlarını atlatmak için DNS protokolünü veri kanalı olarak kullandığı gelişmiş bir tekniktir. Bunu tespit etmek için DNS sorgu loglarını analiz etmen gerekir.
Önce debug logging’i etkinleştir:
# DNS debug logging aktif et
Set-DnsServerDiagnostics `
-All $true `
-LogFilePath "C:WindowsSystem32dnsdns_debug.log" `
-MaxMBFileSize 500
# Sadece kritik loglar istiyorsan (performans için tercih edilir)
Set-DnsServerDiagnostics `
-Queries $true `
-Answers $true `
-SendPackets $true `
-ReceivePackets $true `
-LogFilePath "C:DNSLogsdns_queries.log" `
-MaxMBFileSize 200
Şüpheli DNS aktivitesini analiz eden bir script:
# DNS tünelleme tespiti - anormal sorgu analizi
# C:DNSDetect-DNSTunnel.ps1
$logPath = "C:DNSLogsdns_queries.log"
$threshold_queryLength = 50 # 50 karakterden uzun subdomain sorgular
$threshold_queryCount = 100 # Dakikada 100'den fazla sorgu
$reportPath = "C:DNSReportstunnel_suspects_$(Get-Date -Format 'yyyyMMdd_HHmm').txt"
Write-Host "DNS tünelleme analizi basliyor..."
# Windows Event Log'dan DNS sorgularini oku (DNS debug log yerine Event Log kullaniyorsan)
$dnsEvents = Get-WinEvent -LogName "Microsoft-Windows-DNS-Server/Audit" -MaxEvents 10000 -ErrorAction SilentlyContinue
$suspiciousPatterns = @()
foreach ($event in $dnsEvents) {
$message = $event.Message
# Uzun subdomain tespiti (DNS tünelleme genellikle cok uzun subdomain kullanir)
if ($message -match "QNAME:s+(S+)") {
$queryName = $matches[1]
$parts = $queryName.Split(".")
foreach ($part in $parts) {
if ($part.Length -gt $threshold_queryLength) {
$suspiciousPatterns += [PSCustomObject]@{
Time = $event.TimeCreated
Type = "Uzun Subdomain"
Query = $queryName
SubdomainLength = $part.Length
Detail = "Subdomain $($part.Length) karakter uzunlugunda"
}
}
}
# Base64 benzeri karakter yogunlugu kontrolu
if ($queryName -match "^[a-zA-Z0-9+/]{20,}") {
$suspiciousPatterns += [PSCustomObject]@{
Time = $event.TimeCreated
Type = "Base64 Benzeri Sorgu"
Query = $queryName
SubdomainLength = $queryName.Length
Detail = "Base64 kodlu icerik suptesi"
}
}
}
}
if ($suspiciousPatterns.Count -gt 0) {
Write-Warning "$($suspiciousPatterns.Count) suphueli DNS aktivitesi tespit edildi!"
$suspiciousPatterns | Export-Csv $reportPath -NoTypeInformation -Encoding UTF8
Write-Host "Rapor kaydedildi: $reportPath"
# Email bildirimi gonder (SMTP ayarlarini degistir)
# Send-MailMessage -To "[email protected]" -Subject "DNS Tunel Suphesi" -Body ($suspiciousPatterns | Out-String)
} else {
Write-Host "Anormal aktivite tespit edilmedi." -ForegroundColor Green
}
Harici DNS Sunucularını Engelleme
Kullanıcıların DNS filtrelemeni bypass etmek için 8.8.8.8 gibi harici DNS sunucularını kullanmasını Windows Firewall ile engelle:
# Harici DNS sorgularini engelle (sadece kendi DNS sunucunu kullanmalarini zorla)
# Port 53 UDP ve TCP - kendi DNS sunucularin disindaki tum IP'lere blok
$internalDNSServers = @("192.168.1.10", "192.168.1.11") # Kendi DNS IP'lerini gir
# Outbound DNS'i engelle
New-NetFirewallRule `
-DisplayName "Block External DNS UDP" `
-Direction Outbound `
-Protocol UDP `
-RemotePort 53 `
-RemoteAddress "Any" `
-Action Block `
-Profile Any `
-Enabled True
New-NetFirewallRule `
-DisplayName "Block External DNS TCP" `
-Direction Outbound `
-Protocol TCP `
-RemotePort 53 `
-RemoteAddress "Any" `
-Action Block `
-Profile Any `
-Enabled True
# Kendi DNS sunucularindan DNS'e izin ver (istisnalar)
foreach ($dnsIP in $internalDNSServers) {
New-NetFirewallRule `
-DisplayName "Allow Internal DNS UDP - $dnsIP" `
-Direction Outbound `
-Protocol UDP `
-RemotePort 53 `
-RemoteAddress $dnsIP `
-Action Allow `
-Profile Any `
-Enabled True
New-NetFirewallRule `
-DisplayName "Allow Internal DNS TCP - $dnsIP" `
-Direction Outbound `
-Protocol TCP `
-RemotePort 53 `
-RemoteAddress $dnsIP `
-Action Allow `
-Profile Any `
-Enabled True
}
Write-Host "Firewall kurallari olusturuldu. Sadece internal DNS kullanilabilir."
DNS over HTTPS (DoH) ile Bypass’ı Engelleme
Modern tarayıcılar DNS over HTTPS kullanarak DNS filtrelemeni tamamen atlayabilir. Windows’ta Group Policy ile bunu engelle:
# Registry uzerinden DoH'u devre disi birak (Windows 11 ve Server 2022 icin)
$regPath = "HKLM:SYSTEMCurrentControlSetServicesDnscacheParameters"
# DoH'u devre disi birak
Set-ItemProperty -Path $regPath -Name "EnableAutoDoh" -Value 0 -Type DWord
# Chrome'un dahili DoH'unu engellemek icin Group Policy Registry ayarlari
$chromePoliciesPath = "HKLM:SOFTWAREPoliciesGoogleChrome"
if (-not (Test-Path $chromePoliciesPath)) {
New-Item -Path $chromePoliciesPath -Force | Out-Null
}
Set-ItemProperty -Path $chromePoliciesPath -Name "DnsOverHttpsMode" -Value "off" -Type String
# Firefox icin
$firefoxPoliciesPath = "HKLM:SOFTWAREPoliciesMozillaFirefox"
if (-not (Test-Path $firefoxPoliciesPath)) {
New-Item -Path $firefoxPoliciesPath -Force | Out-Null
}
Set-ItemProperty -Path $firefoxPoliciesPath -Name "DNSOverHTTPS" -Value 0 -Type DWord
Write-Host "DoH politikalari uygulandı. Degisikliklerin etkili olmasi icin tarayiciyi yeniden baslatiniz."
DNS Önbellek Zehirlenmesine Karşı Önlemler
DNS cache poisoning, saldırganların DNS yanıtlarını tahrif ederek kullanıcıları sahte sitelere yönlendirdiği klasik bir saldırıdır. Windows Server DNS buna karşı bazı built-in korumalar sunar:
# DNSSEC dogrulama aktif et
Set-DnsServerRecursion `
-Enable $true `
-SecureResponse $true `
-AdditionalTimeout 4 `
-RetryInterval 3 `
-Timeout 8
# Önbellek kirlenmesine karsi koruma
Set-DnsServerCache `
-MaxTTL 1.00:00:00 `
-MaxNegativeTtl 0:15:00 `
-PollutionProtect $true `
-LockingPercent 100 `
-StoreEmptyAuthenticationResponse $true
# Randomized kaynak port (Kaminsky saldirilarini engeller)
# Bu Windows DNS Server'da varsayilan olarak aktif, dogrulamayi yap:
Get-DnsServerSetting | Select-Object SocketPoolSize, SocketPoolExcludedPortRanges
# Socket pool boyutunu artir (varsayilan 2500, artirmak guvenlik saglar)
Set-DnsServerSetting -SocketPoolSize 10000
Monitoring ve Raporlama
Yaptığın tüm bu yapılandırmanın işe yarayıp yaramadığını görmek için monitoring kritik. Event ID’leri ile DNS aktivitesini izle:
# DNS sorgu istatistikleri ve en cok engellenen domainleri raporla
# C:DNSReportsGenerate-DNSReport.ps1
$reportDate = Get-Date -Format "yyyy-MM-dd"
$reportPath = "C:DNSReportsDNS_Report_$reportDate.html"
# DNS sunucu istatistikleri
$stats = Get-DnsServerStatistics
$zoneCount = (Get-DnsServerZone).Count
$blockedZones = (Get-DnsServerZone | Where-Object {$_.ZoneFile -like "*.dns"}).Count
# HTML rapor olustur
$html = @"
<!DOCTYPE html>
<html>
<head><title>DNS Guvenlik Raporu - $reportDate</title>
<style>body{font-family:Arial;margin:20px} h2{color:#333} .stat{background:#f0f0f0;padding:10px;margin:5px}</style>
</head>
<body>
<h2>DNS Guvenlik Raporu - $reportDate</h2>
<div class='stat'><b>Toplam Zone Sayisi:</b> $zoneCount</div>
<div class='stat'><b>Engellenen Domain Zone:</b> $blockedZones</div>
<div class='stat'><b>Toplam Sorgu:</b> $($stats.Query.TotalQueries)</div>
<div class='stat'><b>Recursive Sorgu:</b> $($stats.Query.TotalQueriesRecursed)</div>
<div class='stat'><b>Baskari Sorgu:</b> $($stats.Query.TotalReferrals)</div>
</body>
</html>
"@
$html | Out-File $reportPath -Encoding UTF8
Write-Host "Rapor olusturuldu: $reportPath"
# Onemli Event ID'leri kontrol et
$criticalEvents = Get-WinEvent -FilterHashtable @{
LogName = 'DNS Server'
Level = 1,2,3 # Critical, Error, Warning
StartTime = (Get-Date).AddHours(-24)
} -ErrorAction SilentlyContinue
if ($criticalEvents) {
Write-Warning "Son 24 saatte $($criticalEvents.Count) kritik DNS eventi tespit edildi!"
$criticalEvents | Select-Object TimeCreated, Id, Message | Format-Table -AutoSize
}
Gerçek Dünya Senaryosu: Fidye Yazılımı C2 Engellemesi
2022 yılında bir müşterimde yaşanan vakayı anlatayım. Çalışanlardan biri sahte bir fatura ekine tıkladı. Endpoint antivirus’u ilk yükleyiciyi yakalamadı. Ancak DNS filtreleme sistemi, zararlı yazılımın komuta-kontrol sunucusuna bağlanma girişimini anında kesti.
Olayın ardından geriye dönük log analizinde şunu gördük: Zararlı yazılım, update.microsoftsecurity-cdn.net ve telemetry.windowsupdate-cdn.net gibi meşru görünen ama tehdit istihbaratı listelerinde yer alan domainlere sorgu atmaya çalışmış. DNS sinkhole sayesinde bu sorgular 0.0.0.0‘a yönlendirilmiş ve C2 iletişimi hiç kurulamamış.
Bu vakadan çıkan en önemli ders şu: Threatfeed’leri güncel tut, wildcard engellemesini ihmal etme ve DNS loglarını düzenli izle.
Sonuç
Windows Server’da DNS filtreleme, katmanlı güvenlik mimarisinin vazgeçilmez bir parçasıdır. Anlattığımız yöntemleri özetleyecek olursak:
- DNS Sinkhole ile zararlı domainleri hiçbir IP’ye çözümlenmeden engelle
- DNS Politikaları ile zaman ve istemci bazlı dinamik kurallar uygula
- Otomatik blocklist güncellemesi ile tehdit istihbaratını her gece sisteme entegre et
- DNS tünelleme tespiti için uzun ve anormal sorguları analiz et
- Firewall kuralları ile harici DNS bypass girişimlerini kes
- DoH kısıtlaması ile tarayıcı bazlı filtreleme atlatma girişimlerini önle
- DNS önbellek koruma ayarlarıyla cache poisoning saldırılarına karşı önlem al
Bu yapılandırmaları bir kez kurulsun ve unutulsun olarak bakma. DNS tehdit ortamı sürekli değişiyor. Aylık blocklist doğrulaması, haftalık log analizi ve her güvenlik olayının ardından kural gözden geçirmesi rutin haline gelmeli.
Son olarak şunu söylemeliyim: DNS filtreleme tek başına yeterli değil. Ama doğru yapılandırıldığında, saldırı zincirinin en kritik halkalarından birini koparıyor. Ve bu, fidye yazılımı, APT ya da basit phishing fark etmeksizin seni ciddi anlamda koruyor.