Selamlar, bu yazımda IIS Configuration Değişikliklerini Splunk ile İzlemeyi ele alacağız. Şimdiden keyifli okumalar. 🙂 Bu çalışmanın amacı, IIS sunucularındaki ana konfigürasyon dosyası olan applicationHost.config üzerinde oluşabilecek yetkili veya yetkisiz değişiklikleri en geç beş dakika içinde tespit etmektir. Çözüm yalnızca hash değişikliğini görmekle kalmaz; eklenen ve silinen satırları JSON event içerisine ekler, değişiklik anındaki dosyanın snapshot’ını alır ve olayı Splunk üzerinde alarm üretilebilecek hale getirir.

  • Dosyanın SHA-256 hash değeri baseline ile karşılaştırılır.
  • Yeni değişiklikte added_lines ve removed_lines alanları oluşturulur.
  • Her yeni hash için zaman damgalı snapshot alınır.
  • Aynı hash için tekrar CHANGED eventi üretilmez.
  • UNCHANGED durumları Splunk’a gönderilmez.
  • Aynı UF app’i standalone ve cluster yapılarda kullanılabilir.

2. Çözümün Çalışma Mantığı

applicationHost.config
        ↓
PowerShell script hash hesaplar
        ↓
Baseline hash ile karşılaştırır
        ↓
Aynı ise: çıktı üretmeden sonlanır
Farklı ise: duplicate state kontrolü yapılır
        ↓
Yeni hash ise:
– Snapshot alınır
– Eklenen/silinen satırlar çıkarılır
– JSON event stdout’a yazılır
        ↓
Splunk Universal Forwarder
        ↓
index=iis_config_integrity
        ↓
Alarm / inceleme / geri dönüş

Baseline, snapshot, log ve state dosyaları Splunk app dizininde değil, C:\ProgramData\IISConfigMonitor altında tutulur. Böylece Deployment Server app’i yeniden dağıttığında çalışma verileri korunur.

3. Windows IIS Sunucusunda Universal Forwarder App’i

Standalone POC’de app doğrudan Windows Universal Forwarder’ın etc\apps dizinine konulur. Üretim ortamında aynı app Deployment Server üzerindeki deployment-apps dizininden IIS sunucularına dağıtılır.

3.1 App klasörü nerede oluşturulacak?

Sunucu: Windows IIS sunucusu

Bileşen: Splunk Universal Forwarder

App adı: TA-iis-config-integrity

Tam yol: C:\Program Files\SplunkUniversalForwarder\etc\apps\TA-iis-config-integrity

C:\Program Files\SplunkUniversalForwarder\etc\apps\TA-iis-config-integrity\

TA-iis-config-integrity
├── bin
│   ├── iis_config_integrity.ps1
│   └── run_iis_config_integrity.cmd
└── local
    ├── inputs.conf
    └── app.conf

Klasörleri oluşturma komutları:

$UFHome = “C:\Program Files\SplunkUniversalForwarder”
$AppRoot = “$UFHome\etc\apps\TA-iis-config-integrity”

New-Item “$AppRoot\bin” -ItemType Directory -Force | Out-Null
New-Item “$AppRoot\local” -ItemType Directory -Force | Out-Null

3.2 PowerShell scripti nereye konulacak?

Dosya adı: iis_config_integrity.ps1

Tam yol: C:\Program Files\SplunkUniversalForwarder\etc\apps\TA-iis-config-integrity\bin\iis_config_integrity.ps1

C:\Program Files\SplunkUniversalForwarder\etc\apps\TA-iis-config-integrity\bin\iis_config_integrity.ps1

Aşağıdaki script bin dizinine iis_config_integrity.ps1 adıyla kaydedilir. İzlenen dosya, scriptin başındaki ConfigPath değişkenidir. applicationHost.config dışında farklı bir web.config izlenecekse bu değişken veya ileride merkezi path listesi genişletilebilir.

[CmdletBinding()]
param()

$ErrorActionPreference = “Stop”

# AYARLAR
$ConfigPath = “$env:windir\System32\inetsrv\config\applicationHost.config”
$MonitorRoot = “C:\ProgramData\IISConfigMonitor”

$BaselineDirectory = Join-Path $MonitorRoot “baseline”
$SnapshotDirectory = Join-Path $MonitorRoot “snapshots”
$LogDirectory = Join-Path $MonitorRoot “logs”
$StateDirectory = Join-Path $MonitorRoot “state”

$BaselinePath = Join-Path $BaselineDirectory “applicationHost.config”
$HashPath = Join-Path $BaselineDirectory “applicationHost.config.sha256”
$LogPath = Join-Path $LogDirectory “iis_config_integrity.json”
$LastAlertedHashPath = Join-Path $StateDirectory “last_alerted_hash.txt”

function Write-IntegrityLog {
    param(
        [Parameter(Mandatory)]
        [hashtable]$Data,
        [switch]$SendToSplunk
    )

    $Data.timestamp = (Get-Date).ToString(“o”)
    $Data.host = $env:COMPUTERNAME
    $Json = $Data | ConvertTo-Json -Compress -Depth 10

    Add-Content -Path $LogPath -Value $Json -Encoding UTF8

    if ($SendToSplunk) {
        Write-Output $Json
    }
}

function Get-CleanFileContent {
    param(
        [Parameter(Mandatory)]
        [string]$Path
    )

    return @(
        Get-Content -Path $Path -ErrorAction Stop |
        ForEach-Object { [string]$_ }
    )
}

# Runtime klasörleri
foreach ($Directory in @(
    $BaselineDirectory,
    $SnapshotDirectory,
    $LogDirectory,
    $StateDirectory
)) {
    if (-not (Test-Path $Directory -PathType Container)) {
        New-Item -Path $Directory -ItemType Directory -Force | Out-Null
    }
}

# Config dosyası var mı?
if (-not (Test-Path $ConfigPath -PathType Leaf)) {
    Write-IntegrityLog -SendToSplunk -Data @{
        event_type = “iis_config_integrity”
        status = “FILE_NOT_FOUND”
        severity = “critical”
        file_path = $ConfigPath
        message = “IIS configuration file could not be found.”
    }
    return
}

# XML geçerli mi?
try {
    [xml]$CurrentXml = Get-Content -Path $ConfigPath -Raw -ErrorAction Stop
}
catch {
    Write-IntegrityLog -SendToSplunk -Data @{
        event_type = “iis_config_integrity”
        status = “INVALID_XML”
        severity = “critical”
        file_path = $ConfigPath
        message = $_.Exception.Message
    }
    return
}

# Güncel hash
try {
    $CurrentHash = (
        Get-FileHash -Path $ConfigPath -Algorithm SHA256 -ErrorAction Stop
    ).Hash
}
catch {
    Write-IntegrityLog -SendToSplunk -Data @{
        event_type = “iis_config_integrity”
        status = “HASH_ERROR”
        severity = “critical”
        file_path = $ConfigPath
        message = $_.Exception.Message
    }
    return
}

# İlk baseline
if (
    -not (Test-Path $BaselinePath -PathType Leaf) -or
    -not (Test-Path $HashPath -PathType Leaf)
) {
    try {
        Copy-Item -Path $ConfigPath -Destination $BaselinePath -Force
        $CurrentHash | Set-Content -Path $HashPath -Encoding ASCII
    }
    catch {
        Write-IntegrityLog -SendToSplunk -Data @{
            event_type = “iis_config_integrity”
            status = “BASELINE_CREATE_ERROR”
            severity = “critical”
            file_path = $ConfigPath
            message = $_.Exception.Message
        }
        return
    }

    Write-IntegrityLog -SendToSplunk -Data @{
        event_type = “iis_config_integrity”
        status = “BASELINE_CREATED”
        severity = “informational”
        file_path = $ConfigPath
        hash_algorithm = “SHA256”
        current_hash = $CurrentHash
    }
    return
}

# Baseline hash
try {
    $BaselineHash = (
        Get-Content -Path $HashPath -Raw -ErrorAction Stop
    ).Trim()
}
catch {
    Write-IntegrityLog -SendToSplunk -Data @{
        event_type = “iis_config_integrity”
        status = “BASELINE_READ_ERROR”
        severity = “critical”
        file_path = $ConfigPath
        message = $_.Exception.Message
    }
    return
}

# Değişiklik yok
if ($CurrentHash -eq $BaselineHash) {
    if (Test-Path $LastAlertedHashPath -PathType Leaf) {
        Remove-Item $LastAlertedHashPath -Force -ErrorAction SilentlyContinue
    }
    return
}

# Duplicate kontrolü
if (Test-Path $LastAlertedHashPath -PathType Leaf) {
    $LastAlertedHash = (
        Get-Content -Path $LastAlertedHashPath -Raw `
            -ErrorAction SilentlyContinue
    ).Trim()

    if ($CurrentHash -eq $LastAlertedHash) {
        return
    }
}

# Snapshot
$DetectionTime = Get-Date -Format “yyyyMMdd_HHmmss_fff”
$SnapshotPath = Join-Path `
    $SnapshotDirectory `
    “applicationHost_$DetectionTime.config”

try {
    Copy-Item -Path $ConfigPath -Destination $SnapshotPath -Force
}
catch {
    Write-IntegrityLog -SendToSplunk -Data @{
        event_type = “iis_config_integrity”
        status = “SNAPSHOT_ERROR”
        severity = “critical”
        file_path = $ConfigPath
        baseline_hash = $BaselineHash
        current_hash = $CurrentHash
        message = $_.Exception.Message
    }
    return
}

# Satır karşılaştırması
try {
    $BaselineContent = Get-CleanFileContent -Path $BaselinePath
    $CurrentContent = Get-CleanFileContent -Path $ConfigPath

    $Differences = @(
        Compare-Object `
            -ReferenceObject $BaselineContent `
            -DifferenceObject $CurrentContent `
            -SyncWindow 3
    )
}
catch {
    Write-IntegrityLog -SendToSplunk -Data @{
        event_type = “iis_config_integrity”
        status = “COMPARE_ERROR”
        severity = “critical”
        file_path = $ConfigPath
        baseline_hash = $BaselineHash
        current_hash = $CurrentHash
        snapshot_path = $SnapshotPath
        message = $_.Exception.Message
    }
    return
}

$AddedLines = @(
    $Differences |
    Where-Object { $_.SideIndicator -eq “=>” } |
    ForEach-Object { [string]$_.InputObject }
)

$RemovedLines = @(
    $Differences |
    Where-Object { $_.SideIndicator -eq “<=” } |
    ForEach-Object { [string]$_.InputObject }
)

# CHANGED eventi
Write-IntegrityLog -SendToSplunk -Data @{
    event_type = “iis_config_integrity”
    status = “CHANGED”
    severity = “high”
    file_path = $ConfigPath
    hash_algorithm = “SHA256”
    baseline_hash = $BaselineHash
    current_hash = $CurrentHash
    snapshot_path = $SnapshotPath
    added_line_count = $AddedLines.Count
    removed_line_count = $RemovedLines.Count
    added_lines = $AddedLines
    removed_lines = $RemovedLines
}

# Aynı hash tekrar gönderilmesin
$CurrentHash |
Set-Content -Path $LastAlertedHashPath -Encoding ASCII -Force

return

3.3 CMD wrapper nereye konulacak?

Dosya adı: run_iis_config_integrity.cmd

Tam yol: C:\Program Files\SplunkUniversalForwarder\etc\apps\TA-iis-config-integrity\bin\run_iis_config_integrity.cmd

C:\Program Files\SplunkUniversalForwarder\etc\apps\TA-iis-config-integrity\bin\run_iis_config_integrity.cmd

Universal Forwarder, CMD wrapper’ı scripted input olarak çalıştırır. Wrapper, PowerShell scriptini NoProfile, NonInteractive ve ExecutionPolicy Bypass parametreleriyle çağırır.

@echo off
powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -File “%~dp0iis_config_integrity.ps1”
exit /b %ERRORLEVEL%

3.4 inputs.conf nereye konulacak?

Tam yol: C:\Program Files\SplunkUniversalForwarder\etc\apps\TA-iis-config-integrity\local\inputs.conf

C:\Program Files\SplunkUniversalForwarder\etc\apps\TA-iis-config-integrity\local\inputs.conf

Bu stanza wrapper’ı 300 saniyede bir çalıştırır. İlk POC’de 60 saniye kullanılıp test tamamlandıktan sonra 300 saniyeye çekilebilir.

[script://.\bin\run_iis_config_integrity.cmd]
interval = 300
sourcetype = iis:config:integrity
index = iis_config_integrity
disabled = 0

3.5 app.conf nereye konulacak?

Tam yol: C:\Program Files\SplunkUniversalForwarder\etc\apps\TA-iis-config-integrity\local\app.conf

C:\Program Files\SplunkUniversalForwarder\etc\apps\TA-iis-config-integrity\local\app.conf

[install]
is_configured = 1
state = enabled

[ui]
is_visible = 0

[launcher]
author = Furkan KILINC
description = IIS configuration integrity monitoring
version = 1.0.0

[package]
id = TA-iis-config-integrity

3.6 UF app doğrulaması

$UFHome = “C:\Program Files\SplunkUniversalForwarder”

Test-Path “$UFHome\etc\apps\TA-iis-config-integrity\bin\iis_config_integrity.ps1”
Test-Path “$UFHome\etc\apps\TA-iis-config-integrity\bin\run_iis_config_integrity.cmd”

& “$UFHome\bin\splunk.exe” btool inputs list –debug |
Select-String “run_iis_config_integrity|iis_config_integrity|interval|disabled”

Restart-Service SplunkForwarder

Beklenen btool çıktısı:

[script://.\bin\run_iis_config_integrity.cmd]
disabled = 0
index = iis_config_integrity
interval = 300
sourcetype = iis:config:integrity




4. Standalone Splunk Sunucusunda Yapılacaklar

Standalone yapıda index ve parsing ayarları aynı Splunk Enterprise sunucusunda tutulur. POC ortamında Linux standalone Splunk kullanılmıştır.

4.1 Index tanımı

iis_config_integrity adında index tanımlanır

4.2 props.conf nereye konulacak?

Tam yol: /opt/splunk/etc/apps/TA-iis-config-integrity-receiver/local/props.conf

/opt/splunk/etc/apps/TA-iis-config-integrity-receiver/local/props.conf

[iis:config:integrity]
SHOULD_LINEMERGE = false
LINE_BREAKER = ([\r\n]+)
TRUNCATE = 0
KV_MODE = json
TIME_PREFIX = “timestamp”\s*:\s*”
TIME_FORMAT = %Y-%m-%dT%H:%M:%S.%7N%:z
MAX_TIMESTAMP_LOOKAHEAD = 40

KV_MODE=json search-time alan çıkarımı sağlar. Aynı sourcetype üzerinde INDEXED_EXTRACTIONS=json da tanımlanırsa alanlar iki kez görülebilir; bu nedenle tek yöntem kullanılmalıdır.

4.3 Standalone doğrulama

/opt/splunk/bin/splunk btool indexes list iis_config_integrity –debug
/opt/splunk/bin/splunk btool props list iis:config:integrity –debug
/opt/splunk/bin/splunk restart


Standalone Splunk üzerinde arama yapmadan önce IIS test sunucusunda kontrollü bir konfigürasyon değişikliği oluşturulmalıdır. Test sırasında applicationHost.config dosyasının elle düzenlenmesi yerine IIS’in desteklenen AppCmd aracı kullanılacaktır.

4.3.1 Mevcut konfigürasyonu baseline olarak kaydetme

Bu komutlar Windows IIS test sunucusunda, Administrator PowerShell üzerinden çalıştırılır.

$ConfigPath = "$env:windir\System32\inetsrv\config\applicationHost.config"
$BaselinePath = "C:\ProgramData\IISConfigMonitor\baseline\applicationHost.config"
$HashPath = "C:\ProgramData\IISConfigMonitor\baseline\applicationHost.config.sha256"
$StatePath = "C:\ProgramData\IISConfigMonitor\state\last_alerted_hash.txt"

Copy-Item `
    -Path $ConfigPath `
    -Destination $BaselinePath `
    -Force

(
    Get-FileHash `
        -Path $ConfigPath `
        -Algorithm SHA256
).Hash |
    Set-Content `
        -Path $HashPath `
        -Encoding ASCII

Remove-Item `
    -Path $StatePath `
    -Force `
    -ErrorAction SilentlyContinue

Bu işlem:

  • Mevcut applicationHost.config dosyasını onaylı baseline olarak kaydeder.
  • Baseline’a ait SHA-256 hash değerini günceller.
  • Önceki testten kalan duplicate state dosyasını temizler.

Baseline ile aktif dosyanın aynı olduğunu doğrulamak için:

$CurrentHash = (
    Get-FileHash `
        -Path $ConfigPath `
        -Algorithm SHA256
).Hash

$BaselineHash = (
    Get-Content `
        -Path $HashPath `
        -Raw
).Trim()

[PSCustomObject]@{
    CurrentHash  = $CurrentHash
    BaselineHash = $BaselineHash
    Match        = $CurrentHash -eq $BaselineHash
}

Beklenen sonuç:

Match : True

4.3.2 Değişiklik yok durumunun kontrol edilmesi

Universal Forwarder servisi yeniden başlatılır:

Restart-Service SplunkForwarder

Script, inputs.conf içindeki interval değerine göre çalışacaktır. Baseline ile aktif dosya aynı olduğu için Splunk’a CHANGED eventi gönderilmemelidir.

Kontrol sorgusu:

index=iis_config_integrity
sourcetype="iis:config:integrity"
earliest=-10m
| table _time host status current_hash added_line_count removed_line_count
| sort - _time


Bu aşamada yeni bir CHANGED sonucu oluşmaması beklenir. Script UNCHANGED olaylarını stdout üzerinden göndermediği için gereksiz lisans tüketimi oluşmaz.

4.3.3 Kontrollü IIS değişikliği oluşturma

Test amacıyla yeni bir application pool oluşturulur:

$AppCmd = "$env:windir\System32\inetsrv\appcmd.exe"

& $AppCmd add apppool /name:"FurkanIntegrityTest"

Beklenen çıktı:

APPPOOL object "FurkanIntegrityTest" added

Application pool’un oluştuğunu doğrulamak için:

& $AppCmd list apppool "FurkanIntegrityTest"

Bu işlem applicationHost.config dosyasına aşağıdakine benzer bir satır ekler:

<add name="FurkanIntegrityTest" />

Hash değerinin değiştiğini hemen doğrulayabiliriz:

$CurrentHash = (
    Get-FileHash `
        -Path $ConfigPath `
        -Algorithm SHA256
).Hash

$BaselineHash = (
    Get-Content `
        -Path $HashPath `
        -Raw
).Trim()

[PSCustomObject]@{
    CurrentHash  = $CurrentHash
    BaselineHash = $BaselineHash
    Changed      = $CurrentHash -ne $BaselineHash
}

Beklenen sonuç:

Changed : True

4.3.4 Scripted input çalışmasının beklenmesi

inputs.conf içerisinde:

interval = 300

tanımlıysa en fazla beş dakika beklenir.

Test sırasında beklemek istenmiyorsa geçici olarak interval = 60 yapılabilir. Değişiklik sonrası Universal Forwarder restart edilmelidir:

Restart-Service SplunkForwarder

4.3.5 Splunk üzerinde CHANGED olayının doğrulanması

Standalone Splunk üzerinde aşağıdaki sorgu çalıştırılır:

index=iis_config_integrity
sourcetype=”iis:config:integrity”
earliest=-10m
| table _time host source status severity
baseline_hash current_hash
added_line_count removed_line_count
added_lines removed_lines snapshot_path
| sort – _time


4.3.6 Duplicate event kontrolü

İlk event geldikten sonra bir kontrol periyodu daha beklenir. Aynı config hash’i için yeniden event oluşmamalıdır.

index=iis_config_integrity
sourcetype=”iis:config:integrity”
earliest=-15m
| stats
count
earliest(_time) as first_seen
latest(_time) as last_seen
by host current_hash status
| convert ctime(first_seen) ctime(last_seen)

Bu sonuç last_alerted_hash.txt state mekanizmasının çalıştığını ve aynı değişikliğin her beş dakikada tekrar indexlenmediğini gösterir.

4.3.7 Silinen satır testinin yapılması

Önce test application pool mevcutken config baseline olarak kaydedilir:

Copy-Item `
    -Path $ConfigPath `
    -Destination $BaselinePath `
    -Force

(
    Get-FileHash `
        -Path $ConfigPath `
        -Algorithm SHA256
).Hash |
    Set-Content `
        -Path $HashPath `
        -Encoding ASCII

Remove-Item `
    -Path $StatePath `
    -Force `
    -ErrorAction SilentlyContinue

Ardından application pool silinir:

& $AppCmd delete apppool "FurkanIntegrityTest"

Beklenen çıktı:

APPPOOL object "FurkanIntegrityTest" deleted

Scriptin çalışması beklendikten sonra şu sorgu çalıştırılır:

index=iis_config_integrity
sourcetype="iis:config:integrity"
earliest=-10m
| table _time host status severity
    added_line_count removed_line_count
    added_lines removed_lines snapshot_path
| sort - _time

Beklenen sonuç:

status             : CHANGED
added_line_count   : 0
removed_line_count : 1
removed_lines      : <add name="FurkanIntegrityTest" />

5. Cluster Mimarisinde Yapılacaklar

Cluster yapıda konfigürasyonlar görevlerine göre ayrılır. Universal Forwarder app’i Deployment Server’da, index tanımı Cluster Manager’da, search-time parsing ve alarm ise SHC Deployer’da tutulur.

KatmanAppİçerikHedef
Deployment ServerTA-iis-config-integrityPS1, CMD, inputs.confIIS UF sunucuları
Cluster ManagerTA-iis-config-integrity-indexersindexes.confIndexer peers
SHC DeployerTA-iis-config-integrity-searchprops.confSHC üyeleri

5.1 Deployment Server app’i nereye konulacak?

Sunucu: Deployment Server

Tam app yolu: /opt/splunk/etc/deployment-apps/TA-iis-config-integrity

/opt/splunk/etc/deployment-apps/TA-iis-config-integrity/

TA-iis-config-integrity
├── bin/
│   ├── iis_config_integrity.ps1
│   └── run_iis_config_integrity.cmd
└── local/
    ├── inputs.conf
    └── app.conf

Standalone POC’de çalışan app, aynı içerikle deployment-apps altına taşınır. App yalnızca IIS hostlarını kapsayan ayrı bir server class üzerinden dağıtılmalıdır.

Önerilen server class: SC_IIS_Config_Integrity

5.2 Cluster Manager index tanımı

Cluster master üzerinde oluşturulan indexes.conf tanımı bundle ile indexer peer’lara dağıtılır.

5.3 SHC Deployer Search App’i

SHC Deployer üzerinde yalnızca JSON alanlarının Search Head Cluster üyelerinde çıkarılması için bir search app oluşturulur.

App yolu:

/opt/splunk/etc/shcluster/apps/TA-iis-config-integrity-search/

Klasör yapısı:

TA-iis-config-integrity-search

├── default

│   ├── app.conf

│   └── props.conf

└── metadata

    └── default.meta

props.conf

Dosya yolu:

/opt/splunk/etc/shcluster/apps/TA-iis-config-integrity-search/default/props.conf

İçeriği:

[iis:config:integrity]

KV_MODE = json

Bu tanım sayesinde aşağıdaki JSON alanları Search Head üzerinde kullanılabilir:

status

severity

current_hash

baseline_hash

added_line_count

removed_line_count

added_lines

removed_lines

snapshot_path

app.conf

Dosya yolu:

/opt/splunk/etc/shcluster/apps/TA-iis-config-integrity-search/default/app.conf

İçeriği:

[install]

is_configured = 1

state = enabled

[ui]

is_visible = 0

[package]

id = TA-iis-config-integrity-search

default.meta

Dosya yolu:

/opt/splunk/etc/shcluster/apps/TA-iis-config-integrity-search/metadata/default.meta

İçeriği:

[]

access = read : [ * ], write : [ admin ]

export = system

SHC bundle dağıtımı

/opt/splunk/bin/splunk apply shcluster-bundle \

-target https://<SHC_MEMBER_IP>:8089 \

-auth admin

Dağıtım sonrasında JSON alanları Search Head Cluster üyelerinde kullanılabilir hale gelir.

Alarm ise Search Head arayüzünden manuel oluşturulur

index=iis_config_integrity sourcetype=”iis:config:integrity”
status IN (
“CHANGED”,
“FILE_NOT_FOUND”,
“INVALID_XML”,
“HASH_ERROR”,
“BASELINE_CREATE_ERROR”,
“BASELINE_READ_ERROR”,
“SNAPSHOT_ERROR”,
“COMPARE_ERROR”
)
| eval change_summary=case(
status=”CHANGED” AND added_line_count>0 AND removed_line_count>0,
“IIS config içerisinde ekleme ve silme tespit edildi”,
status=”CHANGED” AND added_line_count>0,
“IIS config içerisine yeni tanım eklendi”,
status=”CHANGED” AND removed_line_count>0,
“IIS config içerisinden tanım silindi”,
status=”FILE_NOT_FOUND”,
“IIS config dosyası bulunamadı”,
status=”INVALID_XML”,
“IIS config XML formatı geçersiz”,
status=”HASH_ERROR”,
“IIS config hash hesaplama hatası oluştu”,
status=”BASELINE_CREATE_ERROR”,
“IIS config baseline oluşturulamadı”,
status=”BASELINE_READ_ERROR”,
“IIS config baseline okunamadı”,
status=”SNAPSHOT_ERROR”,
“IIS config snapshot alınamadı”,
status=”COMPARE_ERROR”,
“IIS config karşılaştırma hatası oluştu”,
true(),
“IIS config integrity kontrol hatası”
)
| table _time host status severity change_summary file_path
baseline_hash current_hash
added_line_count removed_line_count
added_lines removed_lines
snapshot_path message
| sort – _time

6. Uçtan Uca Test Senaryosu

  1. Mevcut config’i baseline haline getirin.

$ConfigPath = “$env:windir\System32\inetsrv\config\applicationHost.config”
$BaselinePath = “C:\ProgramData\IISConfigMonitor\baseline\applicationHost.config”
$HashPath = “C:\ProgramData\IISConfigMonitor\baseline\applicationHost.config.sha256”

Copy-Item $ConfigPath $BaselinePath -Force
(Get-FileHash $ConfigPath -Algorithm SHA256).Hash |
Set-Content $HashPath -Encoding ASCII

2.Test application pool oluşturun.

$AppCmd = “$env:windir\System32\inetsrv\appcmd.exe”
& $AppCmd add apppool /name:”FurkanIntegrityTest”

3.En fazla beş dakika bekleyin.

4.Splunk üzerinde CHANGED eventini kontrol edin.

index=iis_config_integrity sourcetype=”iis:config:integrity”
| table _time host status severity added_line_count removed_line_count
    added_lines removed_lines current_hash snapshot_path
| sort – _time

5.Aynı hash için duplicate oluşmadığını kontrol edin.

index=iis_config_integrity sourcetype=”iis:config:integrity”
| stats count earliest(_time) as first_seen latest(_time) as last_seen
    by host current_hash status
| convert ctime(first_seen) ctime(last_seen)

Beklenen sonuç: aynı current_hash için count=1.

7. Disk Kullanımını Kontrol Altında Tutma

  • Hash baseline ile aynıysa UNCHANGED eventi gönderilmez.
  • Aynı current_hash daha önce gönderildiyse yeni CHANGED eventi oluşturulmaz.
  • PowerShell debug ve Write-Host çıktıları kaldırılmıştır.
  • JSON içerisinde yalnızca gerekli alanlar bulunur.
  • Snapshot içeriği Splunk’a gönderilmez; yalnızca snapshot_path alanı gönderilir.
  • Baseline, snapshot ve state klasörleri monitor input ile izlenmez.

30 günden eski snapshotları temizleme örneği:

Get-ChildItem “C:\ProgramData\IISConfigMonitor\snapshots” -File |
Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-30) } |
Remove-Item -Force

8. Meşru Değişiklik Sonrası Baseline Güncelleme

Script değişikliği otomatik olarak baseline kabul etmez. Meşru değişiklik operasyon ekibi tarafından kontrol edildikten sonra aşağıdaki işlem uygulanabilir.

$ConfigPath = “$env:windir\System32\inetsrv\config\applicationHost.config”
$BaselinePath = “C:\ProgramData\IISConfigMonitor\baseline\applicationHost.config”
$HashPath = “C:\ProgramData\IISConfigMonitor\baseline\applicationHost.config.sha256”
$StatePath = “C:\ProgramData\IISConfigMonitor\state\last_alerted_hash.txt”

Copy-Item $ConfigPath $BaselinePath -Force

(Get-FileHash $ConfigPath -Algorithm SHA256).Hash |
Set-Content $HashPath -Encoding ASCII

Remove-Item $StatePath -Force -ErrorAction SilentlyContinue

Üretim ortamında baseline güncellemesi change ticket numarasıyla ilişkilendirilmeli ve tercihen ayrı bir audit event olarak Splunk’a gönderilmelidir.

9. Sonuç

Bu yapı IIS applicationHost.config dosyasını hash ve içerik seviyesinde takip eder. Yeni değişiklikte eklenen ve silinen satırlar Splunk’a gönderilir, snapshot alınır ve aynı hash için tekrar event oluşması engellenir. Standalone POC’de doğrulanan UF app’i üretim ortamında Deployment Server’dan dağıtılabilir; index Cluster Manager, parsing ve alarm ise SHC Deployer üzerinden yönetilebilir.

Share this content:

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Explore More

ARP SPOOFING VE MAN IN THE MIDDLE ATTACK NEDİR?

Herkese selam! Bu yazımda ele aldığım konu ise ARP Spoofıng ve Man In the Mıddle Attack Nedir, Keyifli Okumalar 😊 Öncelikle ARP nedir buna değinelim 😊 ARP NEDİR ? ARP(Adress

Splunk ile Firewall External Feed İçin Otomatik IP Listesi Üretme

Selamlar, bu yazımda Splunk alarm çıktılarından firewall external feed için kullanılabilecek IP listesinin nasıl otomatik üretilebileceğini ele alacağız. Şimdiden keyifli okumalar. SOC operasyonlarında Splunk üzerinde yazılan alarmlar sonucunda şüpheli IP

SYSMON NEDİR?

Herkese selam! Bu yazımda ele aldığım konu SYSMON Nedir , Keyifli Okumalar.  🙂 Sistem üzerinde gerçekleştirilen olaylara ait ön tanımlı olarak kayıt edilmeyen olayları ağımızdaki gelişmiş tehditleri tespit etmemize yardımcı