23.06.2025

SysineternalsSuite paketinin boyutu

Sysinternals'ın Microsoft'tan önce de var olduğunu hatırlayan ve geliştirdiği araçları kullanan biri olarak Process Explorer, Process Monitor ve benzeri (o zamanlar isimler farklıydı, birleşmemiş tekil araçlar vardı) araçların güncel sürümlerini takip ediyorum. Paketlerin tümüne ihtiyaç duyanlar için "Suite" adı verilen bir zip dosyası yayınlanıyor sitede (indirme bağlantıları hala https://www.sysinternals.com/ sistesine yönleniyor). Her aracın yeni sürümü ile birlikte Suite de güncelleniyor.

Bu sysinternals suite paketlerinin boyutları, her bir aracın yeni sürümlerinin çıkışıyla birlikte yavaş bir artış eğilimindeydi. Artışın hızı hakkında bir fikir vermek amacıyla boyut geçtiğimiz dönemde şöyle gerçekleşti:

TarihBoyut
22 Kasım 202351.803 KB
27 Ağustos 202451.656 KB
28 Şubat 202551.813 KB
20 Haziran 2025170.127 KB

Görüldüğü gibi son indirmede boyut 52 MB seviyesinden 170 MB seviyesine çıkmış. Ne tür yeni araçlar pakete eklenmiş ya da mevcut araçlara ne tür yeni özellikler kazandırılmış olabilir diye bakmak için hemen 170 MB'lık paketin zip dosyasını bir yere genişlettim ama ciddi farklar göremedim. Ayrıntılı olarak incelemek için bir önceki paket ile en yeni paketin içeriklerini karşılaştırmak istedim. Basit bir içerik taramasında gördüm ki 28 Şubat'taki sürüm ile 20 Haziran'daki sürüm arasında tek fark RDCMan.exe aracıyla ilgili. Dosyanın 2.93.1431 sürümli 1.858 KB boyutundaki eski sürümünün yerine 3.1.0 sürümlü 67.050 KB boyutundaki sürümünün gelmiş. Buna ilave olarak bir de x86 sistemler için aynı sürüm numarasına sahip 62.232 KB boyutundaki RDCMan-x86.exe pakete eklenmiş.

Bütün fark bundan.

19.06.2025

Powershell ile IIS günlük dosyalarını incelemek

Bazı rutin işleri otomatik hale getirmek, betiklerin içinde kullanmak vs gibi amaçlarla metin dosyalarını bir metin düzenleyici veya Excel gibi programlarla incelemek yerine, Linux'tan gelen bir adet olarak, komut satırı (ya da powershell) ile incelemek gibi bir alışkanlık edinmiştim.

IIS günlük dosyası üzerinden gidelim. Bu dosyaların başında (ya da hizmet yeniden başlatıldığında)

#Software: Microsoft Internet Information Services 10.0
#Version: 1.0
#Date: 2024-06-19 00:00:02
#Fields: date time s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) cs(Referer) sc-status sc-substatus sc-win32-status time-taken

gibi satırlar yer alır. Bu satırları görmezden gelerek altındaki verilere odaklanmak istiyorum. Bu dosyanın adı u_ex250619.log gibi u_ex ile başlayan, yıl (iki haneli), ay ve gün sırasıyla tarih verisi içeren ve log uzatılı bir şey olacak.

cat ./u_ex250619.log | sls "^(?!#)"

ikinci bölüm, # karakteri ile başlamayan satırları göster demek.

Alışkanlık olduğu üzere bu adımdan sonra ConvertFrom-String cmdlet'ini kullanarak bu log dosyasındaki verileri sütunlara ayırmaya çalıştım. Bu arada sütun isimleri olarak üstte verdiğim "#" ile başlayan satırların en altındaki Fields: kelimesinden sonra gelen alan adlarını kullanabilirim. Bu alan adlarından tire "-" karakterini çıkararak şöyle bir alan adları değişkeni oluşturdum:

$alan_adlari = @('date','time','sip','csmethod','csuristem','csuriquery','sport','csusername','cip','UserAgent','Referer','scstatus','scsubstatus','scwin32status','timetaken')

Şimdi bunları kullanarak, alan ayracı olarak da boşluk karakterini belirterek verileri alalım:

cat ./u_ex250619.log | sls "^(?!#)" | ConvertFrom-String -Delimiter " " -PropertyNames $alan_adlari

Bu işlem, benim örneğimde 100MB'lık bir IIS log dosyası için onlarca dakika sürdü. Nasıl hızlandırabilirim diye düşünürken ConvertFrom-String cmdlet'inden şüphelenerek yerine ConvertFrom-Csv'yi kullanmayı düşündüm. Sonuçta IIS günlük dosyaları da boşluk karakter ile ayrılmış değerlerden oluşuyor.

cat ./u_ex250619.log | sls "^(?!#)" | ConvertFrom-Csv -Delimiter " " -Header $alan_adlari

Bu cmdlet'in de -Delimiter parametresi var, ama -PropertyNames yerine -Header kullanmak gerekecek. 

Bu şekilde verileri okuyabilmek sadece 1 dakika sürdü.

Bu aşamadan sonra örneğin bu log dosyasında en çok istekte bulunan 5 IP adresini tespit etmek için aşağıdaki gibi bir yöntem kullanılabilir.

cat ./u_ex250619.log | sls "^(?!#)" | 
    ConvertFrom-Csv -Delimiter " " -Header $alan_adlari | select cip | 
         Group-Object -Property cip -NoElement |
            Sort-Object -Property Count -Desc | 
                select -First 5 

Burada cip, $alan_adlari değişkeninde belirttiğimiz client-ip'nin kısaltması. Sunucumuzda en çok talep gören sayfayı (csuristem) görmek, var olmayan sayfalara (scstatus -eq 404) kimin en çok erişmeye çalıştığını görmek için yukarıdaki betik özelleştirilebilir.

17.06.2025

MRT - malicious software removal tool

Windows sunuculara güncelleştirme gelmiş. Aralarında MRT güncellemesi de var.

Bu, gözüktüğü gibi 5.134 sürüme ait bir güncelleştirme. Peki mevcut sürümümüz kaç? Bunu görmek için farklı yöntemler var. Birincisi sysinternals aracı olan sigcheck ile mrt.exe dosyasının sürüm bilgisine bakmak.

sigcheck64 C:\Windows\system32\mrt.exe

Bunun sonucunda da mevcut sürümümün 5.132 olduğunu gördüm.

Buna alternatif Get-Item ile dosya sürümü sorgulanabilir.

(Get-Item C:\Windows\System32\mrt.exe).VersionInfo.ProductVersion

Daha farklı bir yöntem ile Windows\debug klasörü altındaki mrt.log dosyasına bakılabilir.

cat C:\Windows\debug\mrt.log | sls "Removal Tool v" -Context 0,1 | select -last 1 

Nihai yöntem de mrt.exe doyasını çalıştırarak pencere başlığındaki sürüm numarasına bakmak.

Bunu sadece İngilizce yerelleştirmesi olan sistemlerde mi yapabiliyoruz, yoksa sadece sunucularda mı bilemiyorum ama Windows 11 Türkçe yerelleştirmeye sahip bilgisayarımda bu şekilde sürüm numarası gelmedi.

Her türlü sürüm eski. Hemen güncelleştirmek lazım.

Windows güvenliği ile ilgili bir de Güvenlik Zekası Güncelleştirme (Security Intelligence) sürümü önemli. Onu sorgulamak için de

(Get-MpComputerStatus).AntivirusSignatureVersion

kullanılabilir. 

16.06.2025

Linux'ta find komutu

Dosya aramak. Bitmez tükenmez bir ihtiyaç. Bütün işlevlerin de yıllar önce tasarlanmış bir find komutunun yetenekleri ile hala yapılabiliyor olması ilginç.

En çok kullandığım işlev, en son değişiklik tarihine göre dosya aramak; muhtemelen kısmi dosya ismi ile birlikte. Son 1 gün içinde değişen dosyaları bulmak için

find . -type f -iname '*.txt' -mtime 1

Burada en sondaki rakamın yanında artı veya eksi olmadığından tam 1 gün önce (1 ile 2 arasındakileri; yani 24 saat ve 48 saat önce değişenleri) değişenleri bul demek. 1 günden önce değişenler demek için

find . -type f -iname '*.txt' -mtime +1

Bir günden daha önce (24 saatten daha kısa süre önce) değişenleri bul demek için ise

find . -type f -iname '*.txt' -mtime -1

demek gerek.

Son 10 dakika içinde değişen (oluşan) dosyaları görmek için

find . -type f -mmin -10

Son 10 dakika ile 30 dakika arasında değişen dosyaları görmek için

find . -type f -mmin +10 -mmin -30 

Daha net bir tarih ve saat bilgisi için -newermt parametresi kullanılabilir. Örneğin 1 Ocak 2024'ten sonra değişen txt uzantılı dosyalar için

find . -type f -newermt '2024-01-01'
find . -type f -newermt 'Jan 1 2024'
find . -type f -newermt '2024-01-01 01:25 PM'

gibi komutlar kullanılabilir. En sondaki örnek diğerleri ile eşdeğer değil, saat farkı ile farklı sonuçlar üretir, sadece ISO tarih biçimindeki saat bilgisini göstermek için verdim.

Bu parametre daha esnek kullanıma da sahip. Örneğin

find . -type f -newermt 'yesterday'
find . -type f -newermt '2 weeks ago'
find . -type f -newermt '6 hours ago'

Hatta belli bir tarih aralığı için ünlem "!" işareti aralık sonu belirlenebilir. Örneğin 1 Ocak 2024 ile 31 Nisan 2024 arasını belirtmek için

find . -type f -newermt "2024-01-01" ! -newermt "2024-04-31"

Bir dosyanın oluşturulmasından daha sonra oluşturulmuş (düzenlenmiş) dosyaları bulmak da mümkün. Örnek dosyamız /home/metin/referans_dosya olsun. 

find . -type f -newer /home/metin/referans_dosya

Tüm tarih verileri sistemin yerel saatine göre yapılıyor.

Başka bir kriter de dosya boyutu. Genelde ihtiyacım olan belli bir boyutun üzerinde olan dosyalar. 2 GB'tan büyük ISO dosyaları için

find . -type f -iname '*.iso' -size +2G

Tam tersi, 2 GB'tan küçük iso dosyaları için ise, tahmin edilebileceği gibi boyut belirten 2'nin yanındaki artı '+' işaretini eksiye '-' çevirerek

find . -type f -iname '*.iso' -size -2G

find komutu sonrasında dosyanın ls ile gösterilen ayrıntılarını görmek istiyorsak iki seçenek var. -exec kullanmak, ya da find'in kendi -ls parametresini kullanmak. İki örnek

find . -type f -newermt 'yesterday' -exec ls -l {} \;
find . -type f -newermt 'yesterday' -ls

İlk örneğin sonundaki \; işareti ls komutunu bulunan her dosya için ayrı ayrı çalıştır demek. Her birini toplayıp tek seferde ls çalıştırmak için bunun yerine \+ kullanmak gerek.

İkinci örnekteki -ls parametresi, normal ls komutunun çıktısına göre 2 fazla sütun veri üretir. İlk sütun bulunan dosyanın dosya sistemindeki inode numarası. İkinci sütun ise bu dosyanın dosya sisteminde kaç blok kapladığını gösterir (sistemimizde bir blok kaç byte diye bakmak istersek sudo tune2fs -l /dev/sda). Aslında ls -li komutu ile de bu sütunlara ulaşmak mümkün.

Sadece bulunduğumuz klasördeki dosyalarla ilgileniyorsak ve en son değiştirilenleri bulmak istiyorsak

ls -ltR

Bu şekilde değiştirilme zamanlarına (-t) göre sıralar. En son değiştirilenlerin en altta yer alması için (-R) kullanılır, yoksa en son değişenler en üstte yer alır. Sadece son değişen 10 tane ile ilgileniyorsak

ls -lt | head

kullanabiliriz. Dosya boyutuna göre sıralamak için -S kullanılabilir. Bu da varsayılan olarak büyükten küçüğe sıralar. En büyük 5 dosyayı listelemek için

ls -lS | head -5

---

https://www.cyberciti.biz/faq/linux-unix-osxfind-files-by-date/

12.06.2025

Powershell betiklerinde günlük tutma

Düzenli olarak çalışan bir betik ile ilgili günlük tutmak faydalı oluyor. Günlüğün ilk başında yyyy-aa-gg ss:dd:nn biçiminde bir tarih alanı olmalı, sonrasında da günlük kaydına sebep olan olayla ilgili bilgiler yer almalı. İlk bulduğum yöntem şuydu:

$suan = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$log = "D:\log.txt"
... 
Add-Content -Path $log -Value "$suan beklenmeyen hata"

Sonra her seferinde tarih değişkeni ile uğraşmamak için fonksiyon oluşturmak istedim.

function gunluk {
    param (
        [string]$mesaj
    )
    $suan = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $log = D:\log.txt
    Add-Content -Path $log -Value "$suan - $mesaj"
}
...
gunluk "beklenen hata"

Bu gayet pratik bir yöntem oldu, benim için. Sonrasında yürütme işlecini (&) keşfettim.

$log = "D:\log.txt"
$suan=Get-Date -Format "yyyy-MM-dd HH:mm:ss"; 
$gunluk = {param($mesaj);Add-Content -Path $log -Value "$suan - $mesaj"}
...
& $gunluk "baska bir hata daha"

Fonksiyonu çağırmak mı daha etkilidir, yoksa bir değişkenin içeriğini çalıştırmak mı, bilemedim ama bu da güzel.

Duruma göre, $suan değişkeni de bloğun içine alınabilir.

30.05.2025

Linux güvenlik duvarı ve logları

Debian sunucu üzerinde ufw güvenlik duvarını etkinleştirmiş, 

sudo ufw enable

bazı hizmetler için port açma kuralları oluşturmuştum.

sudo ufw allow to <hizmet|port>

Ara sıra güvenlik kayıtlarını incelemek için

sudo journalctl -u <hizmet> --since "1 week ago"

gibi bir komut ile son 1 hafta içinde gerçekleşen olaylara ait kayıtları inceliyordum. Şüpheli/ısrarcı bir IP adresinden gelen istekler ile ilgili engelleme kuralları koyuyordum.

sudo ufw deny from 192.168.5.0/24 to any

Normalde /var/log/ufw.log dosyasında engellenen IP adreslerine ait kayıtlarının olması gerekir.

sudo tail /var/log/ufw.log

Bir süre sonra farkettim ki ufw ile önce istediğim hizmeti etkinleştirip altında da ufw deny komutu ile eklediğim IP engellemeleri aslında engellenmiyor. Bunun sebebi de genel olarak güvenlik duvarı kuralları içinde işlemin üstteki kuraldan başlaması ve aşağıya doğru inmesi. Trafiğe uyan bir kural bulunduktan sonra alttaki diğer kurallar işletilmiyor. Yani üstte hizmete izin veren bir kural varsa attaki engellemeler çalışmıyor. Bunun için engelleme kurallarını izin verme kurallarının üstüne koymaya başladım, aşağıdaki gibi

sudo ufw insert 1 deny from 192.168.5.0/24 to any

Bunun sonucunda da /var/log/ufw.log dosyasına artık kayıtlar düşmemeye başladı. Acaba engellemeler çalışmıyor mu diye düşündüm ama

sudo iptables -L ufw-user-input -v -n

komutuyla baktığımda ilgili engelleme kurallarının yanıdaki sayaçların arttığını gördüm. Yani engelleme kuralları çalışıyor ama log kayıtları oluşmuyordu. Arka planda iptables altyapısını kullanan ufw, izin, engelleme ve log işlemleri için karmaşık bir kural yapısına sahip. insert ile üst sıraya eklediğim kurallar log yapısını bozuyor. Buna çözüm olarak önce ufw-user-input zincirine iptables komutu ile yeni LOG kuralı eklemeyi (her IP için ayrı kural) denedim.

sudo iptables -I ufw-user-input 1 -s 192.168.5.0/24 -j LOG --log-prefix "[UFW BLOCK] "

Ama her yeni IP adresi engelleme kurallı eklediğimde ufw, iptables kurallarını sıfırlayıp kuralları tekrar baştan yazdığı için log kuralım da siliniyordu. Bu duruma çözüm olarak LOG kurallarını ufw-user-input zincirine değil de ufw-before-input zincirine eklemeyi, ekleme işlemini de /etc/ufw/before.rules dosyası aracılığıyla yapmayı buldum. Bu şekilde kuralları değiştirdiğimde eski LOG silinmiyor. before.rules dosyasında *filter anahtar kelimesi ile başlayan ve # End required lines ile biten bölümden hemen sonra

-A ufw-before-input -s 192.168.5.0/24 -j LOG --log-prefix "[UFW BLOCK] " --log-level 4

ekliyorum. Bunu da engellediğim her IP adresi için ayrı ayrı yapıyorum.

iptables altyapısı aslında /var/log/ufw.log gibi bir dosyaya log yazmıyor. ufw nasıl oluyor da buraya yazabiliyor, merak ettim. Loglar aslında

/var/log/syslog
/var/log/messages
/var/log/kern.log

yazılıyor. Bu loglar üzerinden de

grep "UFW BLOCK" /var/log/kern.log

gibi sorgular ile ufw engellemeleri görülebiliyor. Bunların ufw.log dosyasında da görünmesini sağlayan ise rsyslog sistemi. /etc/rsyslog.d/20-ufw.conf dosyasında aşağıdaki gibi bir satır var.

:msg,contains,"[UFW " /var/log/ufw.log

Bu satır sayesinde syslog kayıtlarında içinde "[UFW " geçen logların /var/log/ufw.log dosyasına yönlendirilmesi sağlanmış.

Dahası, bir süredir iptables altyapısı yerine nftables'ın kullanıldığı farkettim.

sudo iptables -V

komutu sonucunda parantez içinde nf_tables yazıyorsa evet, iptables yerine nftables kullanıyoruz demek. Bunun yerine parantez içinde legacy yazıyor veya olabilir ya da parantez içinde bir ifade olmayabilir. Bu, iptables olduğunun göstergesi. Bir süre daha uyumluluk modunda iptables komutları ile çalışabiliriz. Ama bu uyumluluk modu uzun sürmeyecek. Sistemde nftables'ın izlerini aramak için önce kurulu paketlerin içinde nftables arayabilirim. Debian tabanlı sistemlerde

dpkg -l | grep -E "(iptables|nftables|ufw)"
veya Fedora türevlerinde
rpm -qa | grep -E "(iptables|nftables|firewalld)"

Yüklü modüllerde nf_tables olup olmadığına bakabilirim

lsmod | grep nf_tables

systemd birimlerine bakabilirim

systemctl list-units --type=service | grep -E "(iptables|nftables|firewall)">

Son olarak nftables kullanan bir sistemde

nft list ruleset

ile json formatında bir çıktı kural kümesini gösterir. Diğer bazı kontroller:

update-alternatives --display iptables
ls -l /etc/alternatives/iptables


6.05.2025

Forticlient SSL tam sürüm edinme

Forticlient SSL uygulaması için Fortinet sayfasından çevrim içi sürümü indirdikten (sadece VPN indirmeye dikkat!) ForticlientInstaller.exe'yi çalıştırıp asıl kurulum dosyasının güncel halini internetten indirmesini beklemek gerek.


Her seferinde bu indirmeyi beklememek ve bir çevrim dışı kurulum dosyaya sahip olmak için şu Reddit gönderisinde aşağıdaki gibi bir yöntem önerilmiş. Tam aşağıdaki ekran görüntülendiğinde

Başlat>Çalıştır'a %Temp% yazarak bilgisayarınızın geçici dosyalar klasörüne gidip, burada kurulum için indirilmiş ve az sonra silinecek olan "FortiClientVPN.exe" dosyasını bulabiliriz. Bu yazının amacı bu dosyayı daha sonra kullanmak üzere başka bir konuma kopyalamak üzerine. 4 MB'lık çevrim içi dosyaya kıyasla çevrim dışı dosya 200 MB'ın üstünde. Evet, lisans anlaşmasını kabul etmeden kuruluma devam etmiyor.