2.06.2021

Windows Server + OpenSSH

Windows Server 2019 varsayılan olarak OpenSSH Client kurulu geliyor. Yönetici ayrıcalıklarıyla açılmış bir Powershell konsolunda şu komut ile kontrol edebiliriz:

PS> Get-WindowsCapability -Online -Name 'OpenSSH*'

Buna ilave olarak OpenSSH Server kurulumunu da bir özellik gibi kurabiliriz:

PS> Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0

Kurulduktan sonra sshd hizmetini hemen başlatmak için

PS> Start-Service sshd

kullanabiliriz. Ama Windows Firewall etkinse önce bir kuralımızın olup olmadığını kontrol etmemiz iyi olabilir:

PS> Get-NetFirewallRule -Name *ssh*

Eğer bir kural yoksa yenisini yaratmak için

PS> New-NetFirewallRule -Name SSHSpec -DisplayName SSHSpec -Profile any
     -Protocol TCP
     -LocalPort 1022
     -Direction Inbound
     -Action Allow

Uzaktan bağlandığımızda varsayılan olarak cmd shell gelir. Bunu powershell ile değiştirmek için

PS>   New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH"
      -Name DefaultShell
      -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
      -PropertyType String
      -Force

İleri seviye ayarlar sshd_config dosyasında, bu dosya da $env:ProgramData konumunda. Bu dosyadaki birkaç parametreyi hatırlayalım:

DenyUsers : Bağlanması engellenmek istenen kullanıcılar

AllowUsers : SSH sunucunun hedef kitlesi

PermitRootLogin : Windows Server için anlamsız

PermitEmptyPasswords : Boş parolalar geçerli mi değil mi

PasswordAuthentication : Parola ile bağlanmak mümkün mü, yoksa sadece RSA anahtarıyla mı

Eğer bir anahtar çifti yaratmak istiyorsak ssh-keygen ile yapabiliriz. Bu adımdan sonra id_rsa ve id_rsa.pub adında iki dosya oluşacak. pub uzantılı genel (public) anahtarımız. Bunu sunucuda bırakacağız. id_rsa ise bizim özel anahtarımız. Paylaşmamamız ve yanımızda taşımamız gerekiyor.

Öncelikle sunucu tarafında authorized_keys dosyasını oluşturalım.

PS> copy id_rsa.pub authorized_keys

Bu dosyanın yetkileri önemli. Sadece SYSTEM ve bizim kullanıcımızın tam yetkileri olmalı, başka yetki olmamalı. Bu amaçla icacls aracını kullanarak önce yetkilerin devralınmasını engelleyelim, daha sonra da administrators grubunu yetkiler listesinden çıkaralım.

PS> icacls authorized_keys /inheritance:r

PS> icacls authorized_keys /remove:g BUILTIN\Administrators

Yine şu sayfada sshd_config dosyasındaki aşağıdaki satırların başına # işareti konularak etkisizleştirilmesi önerilmiş.

# Match Group administrators
#   AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys

sshd_config dosyasında yapılan değişikliklerden sonra sshd hizmetinin yeniden başlatılması gerek.

PS> Restart-Service sshd

Uzaktan bağlanabilmemiz için bir adım kaldı, o da id_rsa anahtarımızı yerel bilgisayara aktarmak. scp ile uzaktan kopyalayabiliriz.

PS> scp administrator@192.168.x.x:/Users/administrator/.ssh/id_rsa C:\Users\username

Ancak bu dosyanın da yetkileri ile ilgili kesin kurallar var. Benzer şekilde sadece SYSTEM ve kendi kullanıcımız yetkili olmalı.

PS> icacls .\id_rsa /inheritance:r

PS> icacls .\id_rsa /grant username:F

PS> icacls .\id_rsa /grant SYSTEM:F

Bundan sonra artık ssh bağlantısı mümkün.

PS> ssh administrator@192.168.x.x -i .ssh/id_rsa

Hala aşağıdaki gibi hata alıyorsanız

Permission denied (publickey,keyboard-interactive)

sondan bir önceki adımda # işaretiyle etkisizleştirmeniz gereken satırı atlamamış olabilirsiniz. Ya da alternatif olarak sshd_config dosyasında geçen

#StrictModes yes

satırını

StrictModes no

olarak değiştirmek önerilmiş.

27.04.2021

İnternetten indirilen bir dosyanın engelini kaldırma

Alternate data streams (ADS) konusunu daha önce yazmıştım. İnternetten indirilen bir dosya üzerinde bir "Zone.Identifier" ADS akışı olur.


Yukarıdaki diyaloğun altındaki "Engellemeyi Kaldır" kutusu işaretlenmeden zip dosyası açılırsa açılan her dosya için Zone.Identifier akışı oluşur. Bu Windows ayıklama arayüzü kullanıldığında geçerlidir. Diğer dosya sıkıştırma uygulamaları için durum farklı olabilir. Örneğin 7zip, çıkartılan (veya ayıklanan, her neyse) dosyalar için Zone.Identifier akışını korumaz. Ayrıca bu akışa sahip bir dosya çalıştırılırken de kaynağına güvenip güvenmediğimize dair emin misiniz sorusu görüntülenir.

Neyse, çevirideki anlam karmaşasından sıyrılıp konuya dönelim. Zip dosyasına sağ tıklayıp engellemeyi kaldırabiliriz. Ama amacımız bunu komut satırından, powershell ile yapmak.

Önce akışı görelim:

PS> Get-Item -Path Sysinternals* -Streams *

Bu şekilde bulunduğumuz klasörde sysinternals ile başlayan tüm dosyaların ADS verilerini görüntülemiş oluruz. Belli bir dosyanın belli bir akışına (ADS'sine) ulaşmak için daha net olarak

PS> Get-Item SysinternalsSuite.zip -Streams Zone.Identifier

kullanabiliriz. Zone.Identifier akışını bulduk. Bir de içeriğini görüntüleyelim.

PS> Get-Content SysinternalsSuite.zip:Zone.Identifier

[ZoneTransfer]
ZoneId=3
ReferrerUrl=https://docs.microsoft.com/tr-tr/sysinternals/downloads/sysinternals-suite
HostUrl=https://download.sysinternals.com/files/SysinternalsSuite.zip

Bunu silmek için de

PS> Remove-Item SysinternalsSuite.zip:Zone.Identifier

kullanabiliriz. Bunlar tek seçenek değil, başka yollar da var. ADS akışından kurtulduktan sonra powershell ile dosyaları çıkartmak (ayıklamak, genişletmek) için de şöyle bir yol olabilir:

PS> Expand-Archive .\SysinternalsSuite.zip -DestinationPath D:\Tools\ -Force

Burada -Force parametresi o klasörde var olan eski sürümlerin üzerine yazmayı etkinleştirmek için.

16.03.2021

Get-WinEvent ve Logon Type

Uzak masaüstü bağlantılarını eventlog'dan süzmek için garip filtereler kullandım durdum. Ta ki şunu bulana kadar:

Get-WinEvent -FilterHashTable @{LogName="Security";Id=4624} | Where-Object {$_.properties[8].value -eq 10}

Buradaki properties olarak geçen 27 öğelik EventProperty nesnesi, her olay için ayrıntılar sekmesinde çıkan parametrize edilmiş olay özellikleri. Bunu aslında log parser zamanlarından biliyordum, ama nedense bu alanların powershell'den de erişebileceğini hiç düşünmemiştim.

Her durumda Logon Type=10 kaydı düşülmüyor. Sunucunun ekranı kilitlenmişse sadece Logon Type=7 (muhtemelen bir Logon Type=3 sonrasında) kaydı olabiliyor.

15.03.2021

Sysmon

Sysinternals araçlarının fanatiğiyim. Hepsi güzel, ama özellikle Process Monitor, Process Explorer, Autoruns gibi araçların hayranıyım. Bir süredir Sysmon'un varlığından ve işlevlerinden haberdardım ama çok yakınlaşma fırsatım olmamıştı. Aslında yakınlaşınca anladım ki Sysmon hakkında hiçbir şey bilmiyormuşum. Channel9'daki Defrag Tools programındaki konuşmalar falan konuya sadece giriş seviyesinde değinmiş.

İşin özünde Sysmon da Process Monitor benzeri bir araç. Ama bir grafik arayüzü yok. Grafik arayüz olmayınca da onun yerine geçecek filtreleme işlerini başka bir şekilde yapmamız gerekiyor. Bu şekil de burada XML oluyor.

Şu anda web sayfalarında 13.01 sürümü var. Yani ilk çıktığından bu yana çok yol almış. Yolun çoğu XML yapısı ile ilgili alınmış. Sanıyorum ilk çıktığında bugüne kıyasla çok ilkel bir XML yapısı varmış. Zamanla çok değişmiş. Şu anda XML schemaversion 4.5. Bu neleri değiştirmiş, varsayılan olarak VEYA olan filtre 4.22 ile VE olmuş, yeni XML elemanları eklenmiş vs.

Çalıştırıp yakalamaya başlaması için

sysmon -i

komutunu vermek gerekiyor. Bu şekilde varsayılan ayarlarla çalışmaya başlıyor. Yakaladığı olayları Event Viewer'da Application and Service Logs altında Microsoft-Windows-Sysmon/Operational'a yazıyor. -i anahtarı ile çalıştırıldığı anda kendini %SystemRoot% klasörünün altına kopyalayıp bir servis olarak çalışmaya başlıyor. Bu şekilde bilgisayarı tekrar başlattığımızda da çalışmaya devam ediyor. Faaliyetlerini durdurmak için kaldırmak gerekiyor ki bu da

sysmon -u

ile oluyor. Bir kez kurulduktan sonra varsayılan ayarlarla olayları yakalamaya başlıyor demiştik. Yapılandırmayı değiştirmek için bir XML dosyası oluşturarak -c anahtarı ile bu dosyanın yerini göstermek gerekiyor.

sysmon -c ornek.xml

Buraya kadarki konular zaten her yerde yazılan kısım. Bir örnek üzerinden gidelim. Bir sunucumuz var; bu sunucunun üzerinde IIS çalışıyor. C:\inetpub\wwroot\aspnet_client klasörü altında oluşturulan .aspx dosyalarının hangi süreç tarafından oluşturulduğunu bilmek ve bundan haberdar olmak istiyoruz. Aynı zamanda %ProgramData% ve %SystemRoot%\Temp klasörlerinin altında oluşturulabilecek *.7z, *.zip ve *.rar dosyalarına ait olayları takip etmek istioruz. Aslında bunun mantığını kurala dökmek kolay. Bir pseudo code ile:

(Path = C:\inetpub\wwwroot\aspnet_client VE Extension=*.aspx) VEYA ((PATH=%PROGRAMDATA% VEYA PATH=%SystemRoot%\temp) VE (Extension=.7z VEYA Extension=.zip VEYA Extension=.rar))

demek kolay. Ama bunu XML'e dökmek nispeten zor. Tüm süreci nasıl anlatırım bilemiyorum, ama nihayetinde şunları söyleyebilirim. Birden fazla mantık grupları için RuleGroup'lar oluşturmak gerek. Aynı olaya ait ikisi de include veya ikisi de exlude olan RuleGroup'lar geçerli değil. Ayrıca schemaversion 4.22'den sonra EventFiltering elemanı içindeki öğelerin varsayılan mantık operatörü VE. Bunu değiştirmek için groupRelation attribute'larını kullanıyoruz. İkisi de include olan RuleGroup'lardan kaçınmak için birini exclude yapmam gerekti. Bunu da path'ten yana kullandım. Hariç tutulabilecek path'leri toplayıp bir exlude RuleGroup'u oluşturdum. Sonuçta elimde şöyle bir XML dosyası oldu:

<Sysmon schemaversion="4.5">
  <HashAlgorithms>sha256</HashAlgorithms>
  <CheckRevocation/> <!-- Check loaded drivers, log if their code-signing certificate has been revoked, in case malware stole one to sign a kernel driver -->

  <EventFiltering>

    <RuleGroup name="Extension" groupRelation="or">
      <FileCreate onmatch="include">
        <TargetFilename condition="end with">.7z</TargetFilename>
        <TargetFilename condition="end with">.zip</TargetFilename>
        <TargetFilename condition="end with">.rar</TargetFilename>
        <TargetFilename condition="end with">.aspx</TargetFilename>
        <TargetFilename condition="end with">.asp</TargetFilename>
      </FileCreate>
    </RuleGroup>

    <RuleGroup name="Path" groupRelation="or">
      <FileCreate onmatch="exclude">
        <TargetFilename condition="begin with">C:\PerfLogs</TargetFilename>
        <TargetFilename condition="begin with">C:\Program Files (x86)</TargetFilename>
        <TargetFilename condition="begin with">C:\Program Files</TargetFilename>
        <TargetFilename condition="begin with">C:\Scripts</TargetFilename>
        <TargetFilename condition="begin with">C:\inetpub\temp</TargetFilename>
        <TargetFilename condition="begin with">C:\inetpub\logs</TargetFilename>
        <TargetFilename condition="begin with">C:\inetpub\history</TargetFilename>
        <TargetFilename condition="begin with">C:\inetpub\custerr</TargetFilename>
      </FileCreate>
    </RuleGroup>

    <RuleGroup name="ProcStart" groupRelation="or">
      <ProcessCreate onmatch="include">
        <Image condition="end with">cmd.exe</Image>
        <Image condition="end with">powershell.exe</Image>
        <Image condition="end with">iexplore.exe</Image>
      </ProcessCreate>
    </RuleGroup>

    <RuleGroup name="ProcStartExclude" groupRelation="or">
      <ProcessCreate onmatch="exclude">
        <CommandLine condition="contains">...</CommandLine>
      </ProcessCreate>
    </RuleGroup>

    <RuleGroup name="ProcEnd" groupRelation="or">
      <ProcessTerminate onmatch="include"/>
    </RuleGroup>

    <RuleGroup name="NetConnct" groupRelation="or">
      <NetworkConnect onmatch="include">
        <DestinationHostname condition="end with">github.com</DestinationHostname>
        <DestinationHostname condition="end with">githubusercontent.com</DestinationHostname>
      </NetworkConnect>
    </RuleGroup>

  </EventFiltering>

</Sysmon>

Arada başka öğeler de var. Örneğin cmd.exe, powershell.exe ve iexplore.exe süreçlerinin başlaması da takip ediliyor. Süreç başlaması işlemlerinin takibinde bazı hariç tutmalar için "..." ile olası bir durumu da ekledim. Ayrıca github.com ve githubusercontent.com'a girişleri de takip ettim. Bunun dışındaki süreç başlamalarını ve sonlanmalarını hariç tuttum.Şablon olarak şu kaynaktaki xml dosyası üzerinden gittim.

27.02.2021

Youtube'u nasıl engellerim

Gördüğüm kadarıyla herkesin hedefi bu. Evde çocuk var, tableti var, ve eline tablet geçen çocuk Youtube'u bırakmıyor. Ebeveynler de nasıl engellerim diye düşünüyorlar.

Kolay bir yol buldum. Bir Raspberry PI ve PI-Hole ile istenen cihaz üzerinde istenen engelleme (sadece Youtube değil, başka adresler de engellenebilir) yapılabiliyor. Raspberry PI nasıl edinilir, üzerine bir işletim sistemi nasıl kurulur ve PI-Hole nasıl çalışır hale getirilir, bu adımları atlıyorum.

PI-Hole kurulduktan (modem üzerinde DNS yönlendirmeleri, DHCP işleri vs bittikten) sonra pi-hole'a http://pi.hole gibi bir adresten ulaşabiliyor olmalısınız. Ulaşamıyorsanız cihazlarınızın gizli DNS (private DNS) kullanmadığından emin olun. http://pi.hole adresi üzerinden pi-hole'a ulaştıktan (ve kurulum sırasında verilen şifre ile oturum açtıktan) sonra sol üstte yer alan üç çizgili butondan menüyü genişletin (masaüstü bir bilgisayardan giriyorsanız menü solda açık gelir).

Menüde "Group Management" altından Groups'u seçin. Buraya YoutubeYok gibi bir isimle yeni bir grup yaratın. Varsayılan "Default" grubunuzla birlikte 2 grubunuz olacak. Daha sonra yine menüden "Group Management"in altındaki Clients'i seçin. Buraya kısıtlamanın uygulanacağı cihazın MAC adresin girerek sağındaki grup adını bir önceki adımda yarattığımız YoutubeYok (veya ne verdiyseniz ona) ayarlayın. Bu şekilde sadece kısıtlamaların uygulanacağı cihazı bir grubun üyesi yaptık. Başka cihazların da bu kısıtlamaya maruz kalmasını istiyorsanız onları da eklemelisiniz.

Nihayet son aşamada menüden "Group Management" altından Domains'i seçin. Bu sayfaya yasaklanmasını istediğiniz youtube adreslerini yazın. Sadece youtube.com yetmeyebilir, wildcard kullanarak googlevideo.com, googleapis.com ve google.com gibi adresleri de eklemeniz gerekebilir.

Bu adımdan sonra yasaklamalar devreye girmiş olacak. Kaydettikten hemen sonra devam eden bir akış varsa Youtube hemen kesilmeyecektir. Sistem DNS sorgularını "yanlış cevaplandırma" mantığına dayandığı için malum cihaz(lar)ın üzerinde zaten çözülmüş sorguların süresi geçene kadar (tahminen birkaç dakika) herşey normal çalışmaya devam edecektir.

Bu elbette bu işi yapmanın tek yolu değil, ama Raspberry PI uygun fiyatlı bir cihaz. pi-hole da tek seçenek olmayabilir, pfSense gibi çözümler de uygulanabilir, ama bu çok daha kolay bir yöntem gibi geldi bana.

25.02.2021

Powershell ile sayma

Varsayalım ki şöyle bir hedefimiz var; bugün uygulama olay günlüğü (Application Event Log) içinde kaydı düşülen olayların ID'lerine göre hangisinin kaç kez olduğunu bulmak istiyoruz.

Get-WinEvent -FilterHashTable @{LogName="Application";StartTime="2021-02-25 00:00"} |
Group-Object -Property ID -NoElement |
Sort-Object -Property Count -Descending

Bunu bir de Log Parser ile yapmak istedim:

SELECT EventID,
COUNT(EventID) As IdCount
FROM Application
WHERE (TimeGenerated>TO_TIMESTAMP('2021-02-25 00:00:00','yyyy-MM-dd HH:mm:ss'))
GROUP BY EventID
ORDER BY IdCount DESC

Aralarındaki benzerik hoşuma gitti.

23.02.2021

IP adresinden coğrafi konum öğrenme

Sysmon Tools'un sayfasını incelerken basit bir IP adresini coğrafi konuma çeviren servisi öğrendim, hoşuma gitti. Ücretsiz sürüm ayda 10.000 sorguya kadar izin veriyor. Bu sebeple Powershell ile kullanma yoluna gittim.

Herşeyden önce ipstack.com üzerinde ücretsiz bir hesap açıp API access key'ine sahip olmak gerekiyor.

Varsayalım ki elimde $IPAdresi adında bir değişen var ve içeriğinde coğrafi konumunu sorgulamak istediğim bir IP adresi var.

Sorguları göndermek için $IPAdresi değişkenini kullanarak şöyle bir URI oluşturuyoruz.

$uri  = "http://api.ipstack.com/" + $IPAdresi + "?access_key=xxxx-xxx-xxx-xxx"

Daha sonra bu adrese bir Invoke-WebRequest ile istek gönderdim ve sonucu $wr değişkenine kaydettim.

$wr = Invoke-WebRequest -uri $uri -UseBasicParsing

IPStack.com'un cevabı bir JSON nesnesi. Bunu dönüştürebilmek için de şu satırı kullandım:

$json = $wr.content | ConvertFrom-Json

Bu adımdan sonra $json nesnesinin şu alt alanları döndü ki çok işime yaradı.

continent_code: 2 harfli kıta kodu (AF: Afrika, AS: Asya, EU: Avrupa, NA: Kuzey Amerika, OC: Okyanusya, SA: Güney Amerika, AN: Antarktika)

continent_name: Yukarıdakinin tam hali, kıta adı

country_code: 2 harfli ülke kodu (tam liste için Wikipedia sayfasına bakın)

country_name: Yukarıdakinin tam hali, ülke adı

region_code: Bölge kodu. Amerika için eyalet kodları, Türkiye için plaka numaraları.

region_name: Bölge ismi. Amerika için eyalet ismi, Türkiye için şehir ismi.

city: Şehir. Türkye için yukarıdaki ile aynı.

Ayrıntılar için şu sayfaya bakılabilir.

Sonradan aklıma geldi, ama Invoke-WebRequest | ConvertFrom-Json kullanmak yerine tek seferde Invoke-RestMethod kullanılabilir. İkisi de Powershell 3.0 ile gelmiş.