Active Directory’de Kullanıcı Oturumlarını İzleme: who Komutu ve Alternatifleri

Sistem yöneticiliğinde en kritik görevlerden biri, sunucularınıza kimin bağlandığını, ne zaman bağlandığını ve ne kadar süre sistemde kaldığını takip etmektir. Özellikle Active Directory ortamlarında yüzlerce veya binlerce kullanıcının oturum açıp kapattığı düşünüldüğünde, bu izleme işi ciddi bir operasyonel gereklilik haline gelir. Linux tarafında who komutu bu iş için biçilmiş kaftan olsa da, Windows Server ve Active Directory tarafında işler biraz daha karmaşık bir hal alır. Bu yazıda hem Linux’taki who komutunu hem de Windows Active Directory ortamında eşdeğer kullanıcı oturumu izleme yöntemlerini, gerçek dünya senaryolarıyla birlikte ele alacağız.

who Komutu Nedir ve Ne İşe Yarar?

who komutu, Unix/Linux sistemlerde anlık olarak sisteme giriş yapmış kullanıcıları listeleyen basit ama son derece güçlü bir araçtır. /var/run/utmp dosyasını okuyarak bu bilgileri getirir. Temel çıktısında kullanıcı adı, terminal bilgisi, oturum açma zamanı ve bağlantı kaynağı yer alır.

# Temel kullanım
who

# Örnek çıktı:
# ahmet    pts/0        2024-01-15 09:23 (192.168.1.105)
# mehmet   pts/1        2024-01-15 10:47 (10.0.0.22)
# root     tty1         2024-01-15 08:00

Bu kadar basit bir komut, aslında güvenlik ve sistem yönetimi açısından pek çok şeyi anında ortaya koyar. Kim şu an sistemde? Nereden bağlanıyorlar? Ne zamandan beri oturumları açık?

who Komutunun Parametreleri

who komutunun en sık kullanılan parametrelerini şöyle sıralayabiliriz:

  • -a: Tüm bilgileri göster, ölü processleri ve boot zamanını da dahil et
  • -b: Sistemin son başlatma zamanını göster
  • -d: Ölü processleri göster
  • -H: Başlık satırı ekle, çıktıyı daha okunabilir hale getirir
  • -l: Giriş satırlarını listele
  • -m: Sadece mevcut kullanıcıyı göster, who am i ile aynı işlev
  • -q: Kullanıcı adlarını ve toplam sayıyı kısa formatta göster
  • -r: Mevcut çalışma seviyesini (runlevel) göster
  • -s: Varsayılan kısa format, isim, satır ve zaman
  • -T: Terminal yazılabilirlik durumunu göster, + yazılabilir, - yazılamaz
  • -u: Detaylı kullanıcı listesi, idle süresini de dahil eder
# Başlık ekleyerek daha okunabilir çıktı
who -H

# Örnek çıktı:
# NAME     LINE         TIME             COMMENT
# ahmet    pts/0        2024-01-15 09:23 (192.168.1.105)
# mehmet   pts/1        2024-01-15 10:47 (10.0.0.22)

# Detaylı bilgi ile idle süresini gör
who -u -H

# Sistemin ne zaman başladığını öğren
who -b

w Komutu: who’nun Güçlü Kardeşi

w komutu, who‘nun biraz daha bilgi dolu versiyonu olarak düşünülebilir. Oturum bilgilerinin yanı sıra kullanıcıların şu an ne yaptığını, CPU kullanımını ve idle sürelerini de gösterir.

# w komutunun temel kullanımı
w

# Örnek çıktı:
# 11:32:04 up 3 days, 2:15, 3 users, load average: 0.15, 0.22, 0.18
# USER     TTY      FROM             LOGIN@   IDLE JCPU   PCPU WHAT
# ahmet    pts/0    192.168.1.105    09:23    0.00s 0.05s  0.01s w
# mehmet   pts/1    10.0.0.22        10:47   45:12  0.02s  0.02s -bash
# root     tty1     -                08:00    3:27m 0.00s  0.00s -bash

# Belirli bir kullanıcı için filtrele
w ahmet

w çıktısındaki sütunları anlayalım:

  • USER: Oturum açan kullanıcı adı
  • TTY: Terminal türü, pts sanal terminal, tty fiziksel terminal
  • FROM: Bağlantı kaynağı IP veya hostname
  • LOGIN@: Oturum açma zamanı
  • IDLE: Son aktiviteden bu yana geçen süre
  • JCPU: Terminal üzerinden çalışan tüm processlerin CPU süresi
  • PCPU: Şu an çalışan process için CPU süresi
  • WHAT: Şu an çalıştırılan komut

last Komutu: Geçmişe Bakış

Anlık durumu görmek yeterli değil çoğu zaman. “Dün gece kim sisteme girdi?” sorusunun cevabı için last komutunu kullanırız. Bu komut /var/log/wtmp dosyasını okur.

# Son oturumları listele
last

# Sadece belirli bir kullanıcının oturumlarını göster
last ahmet

# Son 10 girişi göster
last -n 10

# Başarısız giriş denemelerini göster (lastb komutu)
sudo lastb

# Son 20 başarısız giriş denemesi
sudo lastb -n 20

# Belirli bir tarihten sonraki girişleri filtrele
last -s "2024-01-01" -t "2024-01-31"

Bir güvenlik olayı yaşandığında ilk bakılacak yer genellikle last çıktısıdır. Hangi IP’den, hangi saatlerde giriş yapıldığı, oturumun ne kadar sürdüğü gibi bilgiler, bir saldırganın izini takip etmek için hayati önem taşır.

Windows Server Active Directory’de Kullanıcı Oturumu İzleme

Linux tarafı bu kadar. Asıl konumuz olan Active Directory ortamına geçelim. Windows Server’da who komutunun doğrudan bir karşılığı yoktur ama PowerShell ve çeşitli araçlarla çok daha kapsamlı oturum izleme yapabilirsiniz.

quser ve query session Komutları

Windows’un yerleşik quser ve query session komutları, Linux’taki who komutuna en yakın araçlardır.

# Yerel sunucudaki aktif oturumları listele
quser

# Uzak sunucudaki oturumları listele
quser /server:DC01

# Tüm domain controller'larda oturumları sorgula
$DCList = Get-ADDomainController -Filter * | Select-Object -ExpandProperty Name
foreach ($DC in $DCList) {
    Write-Host "=== $DC ===" -ForegroundColor Yellow
    quser /server:$DC 2>$null
}

# query session alternatif kullanım
query session /server:DC01

quser çıktısında şu bilgiler yer alır:

  • USERNAME: Oturum açan kullanıcı adı
  • SESSIONNAME: Oturum adı (console, rdp-tcp#0 gibi)
  • ID: Oturum kimlik numarası
  • STATE: Active veya Disc (disconnected) durumu
  • IDLE TIME: Kullanıcının ne kadar süredir işlem yapmadığı
  • LOGON TIME: Oturum açma zamanı

PowerShell ile Kapsamlı Oturum İzleme

Gerçek AD ortamlarında tek bir sunucuya bakmak genellikle yeterli olmaz. Tüm sunucuları veya belirli bir OU altındaki makineleri taramak gerekir.

# Active Directory'deki tüm bilgisayarlarda aktif oturumları bul
function Get-ADUserSessions {
    param(
        [string]$SearchBase = (Get-ADDomain).DistinguishedName,
        [int]$TimeoutSeconds = 5
    )
    
    $Computers = Get-ADComputer -Filter {OperatingSystem -like "*Server*"} -SearchBase $SearchBase
    $Results = @()
    
    foreach ($Computer in $Computers) {
        $ComputerName = $Computer.Name
        
        # Ping kontrolü
        if (Test-Connection -ComputerName $ComputerName -Count 1 -Quiet -TimeToLive $TimeoutSeconds) {
            try {
                $Sessions = Invoke-Command -ComputerName $ComputerName -ScriptBlock {
                    $Output = quser 2>$null
                    if ($Output) {
                        $Output | Select-Object -Skip 1 | ForEach-Object {
                            $Line = $_ -replace 's+', ' '
                            $Parts = $Line.Trim().Split(' ')
                            [PSCustomObject]@{
                                ComputerName = $env:COMPUTERNAME
                                UserName     = $Parts[0]
                                SessionName  = $Parts[1]
                                State        = $Parts[3]
                                IdleTime     = $Parts[4]
                                LogonTime    = "$($Parts[5]) $($Parts[6])"
                            }
                        }
                    }
                } -ErrorAction Stop
                
                $Results += $Sessions
            }
            catch {
                Write-Warning "$ComputerName erisilemedi: $_"
            }
        }
        else {
            Write-Verbose "$ComputerName cevap vermiyor, atlaniyor..."
        }
    }
    
    return $Results
}

# Fonksiyonu calistir
$AllSessions = Get-ADUserSessions
$AllSessions | Format-Table -AutoSize

Event Log ile Oturum Takibi

Active Directory ortamında en güvenilir yöntem Windows Event Log izlemektir. Özellikle Domain Controller’lardaki Security log’ları altın madeni gibidir.

Kritik Event ID’ler şunlardır:

  • 4624: Başarılı oturum açma
  • 4625: Başarısız oturum açma girişimi
  • 4634: Oturum kapatma
  • 4647: Kullanıcı tarafından başlatılan oturum kapatma
  • 4648: Açık credentials ile oturum açma girişimi
  • 4768: Kerberos TGT isteği (domain logon)
  • 4769: Kerberos servis bileti isteği
  • 4776: NTLM kimlik doğrulama
# Son 24 saatteki tüm başarılı domain logonları
$StartTime = (Get-Date).AddHours(-24)

$LogonEvents = Get-WinEvent -ComputerName "DC01" -FilterHashtable @{
    LogName   = 'Security'
    Id        = 4624
    StartTime = $StartTime
} | Where-Object {
    # Sadece interactive ve remote interactive logonları al
    # LogonType 2 = Interactive, 10 = RemoteInteractive (RDP)
    $_.Properties[8].Value -in @(2, 10)
} | ForEach-Object {
    [PSCustomObject]@{
        TimeCreated  = $_.TimeCreated
        UserName     = $_.Properties[5].Value
        Domain       = $_.Properties[6].Value
        LogonType    = $_.Properties[8].Value
        SourceIP     = $_.Properties[18].Value
        WorkStation  = $_.Properties[11].Value
    }
} | Where-Object { $_.UserName -notlike "*$" }  # Makine hesaplarini filtrele

$LogonEvents | Sort-Object TimeCreated -Descending | Format-Table -AutoSize

# Sonuclari CSV'ye kaydet
$LogonEvents | Export-Csv -Path "C:LogsLogonReport_$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation -Encoding UTF8

Gerçek Dünya Senaryosu 1: Mesai Dışı Giriş Tespiti

Bir finans şirketinde sysadmin olduğunuzu düşünün. Güvenlik ekibiniz mesai saatleri dışında (gece 22:00 ile sabah 07:00 arası) sunuculara yapılan RDP bağlantılarını tespit edip raporlamanızı istiyor.

# Mesai disi RDP girisleri raporu
function Get-AfterHoursLogons {
    param(
        [string]$DCName = "DC01",
        [int]$DaysBack = 7,
        [int]$BusinessStartHour = 7,
        [int]$BusinessEndHour = 22
    )
    
    $StartTime = (Get-Date).AddDays(-$DaysBack)
    
    $AfterHoursEvents = Get-WinEvent -ComputerName $DCName -FilterHashtable @{
        LogName   = 'Security'
        Id        = 4624
        StartTime = $StartTime
    } | ForEach-Object {
        $EventTime = $_.TimeCreated
        $Hour = $EventTime.Hour
        
        # Mesai disi kontrolu
        if ($Hour -lt $BusinessStartHour -or $Hour -ge $BusinessEndHour) {
            [PSCustomObject]@{
                DateTime    = $EventTime
                DayOfWeek   = $EventTime.DayOfWeek
                Hour        = $Hour
                UserName    = $_.Properties[5].Value
                Domain      = $_.Properties[6].Value
                LogonType   = $_.Properties[8].Value
                SourceIP    = $_.Properties[18].Value
            }
        }
    } | Where-Object {
        $_.UserName -notlike "*$" -and
        $_.LogonType -in @(2, 10) -and
        $_.UserName -ne "ANONYMOUS LOGON"
    }
    
    return $AfterHoursEvents
}

$Report = Get-AfterHoursLogons -DCName "DC01" -DaysBack 30
Write-Host "Mesai disi $($Report.Count) giris tespit edildi" -ForegroundColor Red
$Report | Sort-Object DateTime -Descending | Format-Table -AutoSize

# HTML rapor olustur
$Report | ConvertTo-Html -Title "Mesai Disi Giris Raporu" -PreContent "<h2>Son 30 Gun - Mesai Disi Girisler</h2>" |
    Out-File "C:ReportsAfterHoursLogons.html"

Gerçek Dünya Senaryosu 2: Kilitli Hesap Kaynağını Bulma

AD ortamında en sık karşılaşılan sorunlardan biri hesap kilitlenmesidir. Kullanıcı “hesabım kilitlendi” diye geldiğinde, kilit kaynağını bulmak birkaç dakika alabilir.

# Hesap kilitleme kaynagini bul
function Find-AccountLockoutSource {
    param(
        [Parameter(Mandatory=$true)]
        [string]$LockedUserName
    )
    
    # Domain Controller'lari bul
    $DomainControllers = Get-ADDomainController -Filter * | Select-Object -ExpandProperty HostName
    
    $LockoutEvents = @()
    
    foreach ($DC in $DomainControllers) {
        Write-Host "Sorgulanıyor: $DC" -ForegroundColor Cyan
        
        try {
            $Events = Get-WinEvent -ComputerName $DC -FilterHashtable @{
                LogName = 'Security'
                Id      = 4740  # Account Lockout event
            } -ErrorAction Stop | Where-Object {
                $_.Properties[0].Value -eq $LockedUserName
            } | ForEach-Object {
                [PSCustomObject]@{
                    DC          = $DC
                    TimeCreated = $_.TimeCreated
                    UserName    = $_.Properties[0].Value
                    CallerPC    = $_.Properties[1].Value
                }
            }
            
            $LockoutEvents += $Events
        }
        catch {
            Write-Warning "$DC uzerinde event alinirken hata: $_"
        }
    }
    
    if ($LockoutEvents.Count -gt 0) {
        Write-Host "`n$LockedUserName icin kilit kaynaklari:" -ForegroundColor Yellow
        $LockoutEvents | Sort-Object TimeCreated -Descending | Format-Table -AutoSize
    }
    else {
        Write-Host "Son 24 saatte $LockedUserName icin kilit eventi bulunamadi" -ForegroundColor Green
    }
}

# Kullanimi
Find-AccountLockoutSource -LockedUserName "ahmet.yilmaz"

Linux Oturum Logları ile Windows AD Entegrasyonu

Karma ortamlarda (Linux sunucuları AD’ye join edilmiş) hem Linux who/last çıktılarını hem de Windows Event Log’larını birleştiren kapsamlı bir izleme sistemi kurmak gerekir.

# SSSD veya Winbind ile AD'ye join edilmis Linux'ta
# AD kullanicilerinin oturum loglarini filtrele
last | grep -E "@yourdomain.com|DOMAIN\\" | head -20

# Sadece bugünkü girisleri goster
last | grep "$(date '+%a %b %e')"

# Basarısız giris denemelerini domain bazinda filtrele
sudo grep "Invalid user" /var/log/auth.log | grep -v "127.0.0.1" | 
    awk '{print $1, $2, $3, $9, $11}' | sort | uniq -c | sort -rn | head -20

# SSH ile giren AD kullanicilari icin oturum surelerini hesapla
who -a | grep pts | awk '{print $1, $3, $4, $5}'

Otomatik Oturum İzleme ve Alarm Sistemi

Sürekli manuel kontrol yapmak yerine otomatik bir alarm sistemi kurmak çok daha verimlidir.

# Zamanlanmis gorev ile oturum izleme ve email bildirimi
# Bu script Task Scheduler ile her 15 dakikada bir calisacak

$AlertConfig = @{
    SMTPServer   = "mail.sirket.com"
    From         = "[email protected]"
    To           = "[email protected]"
    MaxIdleHours = 8  # 8 saatten fazla idle oturumlar icin uyari
}

function Send-SessionAlert {
    param($SessionInfo, $AlertType)
    
    $Subject = "[$AlertType] Kullanici Oturum Uyarisi - $(Get-Date -Format 'dd.MM.yyyy HH:mm')"
    $Body = @"
Otomatik Oturum Izleme Sistemi

Uyari Tipi : $AlertType
Sunucu     : $($SessionInfo.ComputerName)
Kullanici  : $($SessionInfo.UserName)
Oturum     : $($SessionInfo.SessionName)
Durum      : $($SessionInfo.State)
Idle Sure  : $($SessionInfo.IdleTime)
Giris Zam. : $($SessionInfo.LogonTime)

Bu mesaj otomatik olarak uretilmistir.
"@
    
    Send-MailMessage -SmtpServer $AlertConfig.SMTPServer `
                     -From $AlertConfig.From `
                     -To $AlertConfig.To `
                     -Subject $Subject `
                     -Body $Body `
                     -Encoding UTF8
}

# Domain Controller'lardaki uzun sureli disconnected oturumlari bul
$AllDCs = Get-ADDomainController -Filter * | Select-Object -ExpandProperty Name

foreach ($DC in $AllDCs) {
    $Sessions = quser /server:$DC 2>$null
    if ($Sessions) {
        $Sessions | Select-Object -Skip 1 | ForEach-Object {
            if ($_ -match "Disc") {
                $IdleStr = ($_ -split 's+')[5]
                # Idle sure 8 saat ustu ise uyar
                if ($IdleStr -match "(d+)+") {
                    $IdleDays = [int]$Matches[1]
                    if ($IdleDays -ge 1) {
                        Write-Host "UYARI: $DC - Uzun sureli disconnected oturum bulundu" -ForegroundColor Red
                        # Send-SessionAlert -SessionInfo $ParsedSession -AlertType "UZUN_IDLE_OTURUM"
                    }
                }
            }
        }
    }
}

Oturum Günlüklerini Merkezi Olarak Toplama

Büyük ortamlarda her sunucuya tek tek bakmak yerine merkezi log yönetimi şarttır. Windows Event Forwarding (WEF) veya bir SIEM çözümü kullanabilirsiniz.

# Windows Event Forwarding icin abonelik olusturma
# Bu komutlar Event Collector sunucusunda calistirilir

# WEC servisini baslat
wecutil qc /q

# Subscription olustur (XML dosyasindan)
# Once subscription.xml dosyasi hazirla
$SubscriptionXML = @"
<Subscription xmlns="http://schemas.microsoft.com/2006/03/windows/events/subscription">
    <SubscriptionId>SecurityLogons</SubscriptionId>
    <SubscriptionType>SourceInitiated</SubscriptionType>
    <Description>Domain genelinde oturum eventleri toplama</Description>
    <Enabled>true</Enabled>
    <Uri>http://schemas.microsoft.com/wbem/wsman/1/windows/EventLog</Uri>
    <ConfigurationMode>MinLatency</ConfigurationMode>
    <Query>
        <![CDATA[
            <QueryList>
                <Query Id="0">
                    <Select Path="Security">
                        *[System[EventID=4624 or EventID=4625 or EventID=4634 or EventID=4740]]
                    </Select>
                </Query>
            </QueryList>
        ]]>
    </Query>
    <AllowedSourceDomainComputers>O:NSG:NSD:(A;;GA;;;DC)(A;;GA;;;NS)</AllowedSourceDomainComputers>
</Subscription>
"@

$SubscriptionXML | Out-File -FilePath "C:WEFSecurityLogons.xml" -Encoding UTF8
wecutil cs "C:WEFSecurityLogons.xml"

# Mevcut subscriptionlari listele
wecutil es

Sonuç

Kullanıcı oturumlarını izlemek, sysadmin’in hem proaktif güvenlik hem de reaktif olay müdahale süreçlerinin temel taşını oluşturur. Linux tarafında who, w ve last komutları basit ama etkili araçlar olarak öne çıkarken, Windows Active Directory ortamında quser, PowerShell cmdlet’leri ve Windows Event Log’ları birlikte kullanıldığında çok daha kapsamlı bir görünürlük sağlanır.

Özellikle dikkat edilmesi gereken noktalar şunlardır: Event ID’leri düzenli olarak takip edin ve kritik olaylar için otomatik alarm mekanizmaları kurun. Disconnected oturumları temizlemek için GPO politikaları belirleyin, aksi halde sunucu kaynaklarınız gereksiz yere tükenir. Mesai dışı girişleri ve alışılmadık kaynak IP’lerden gelen bağlantıları mutlaka raporlayın. Son olarak, log dosyalarını yeterli süre saklayın; pek çok siber güvenlik standardı en az 90 gün log tutulmasını zorunlu kılar.

Tüm bu araçları ve yöntemleri düzenli bir rutin haline getirdiğinizde, hem olası güvenlik ihlallerini önceden fark edersiniz hem de “kim ne zaman ne yaptı?” sorusuna her zaman hızlıca cevap verebilirsiniz. Bu da sizi sadece reaktif değil, proaktif bir sysadmin yapar.

Yorum yapın