2.02.2023

Powershell betiklerini elektronik olarak imzalamak

Müthiş bir koruma yöntemi olmasa da powershell'de varsayılan olarak betiklerin çalıştırılmalarını engelleyen bir politika var. Yani yeni bir Windows bilgisayar aldınız/kurdunuz. Varsayılan olarak powershell terminalinden sadece komutlar girebilirsiniz. ps1 uzantılı betik dosyalarını çalıştırmanız engellenir. Eğer bu engeli kaldırmak isterseniz Set-ExecutionPolicy ile çalıştırma politikanızı değiştirmelisiniz. Şu çalıştırma seviyeleri vardır:

AllSigned: Tüm betikler imzalı olsun.

ByPass: Yasakları takma

RemoteSigned: Sadece download edilmiş betiklerin imzalı olmalarını bekle. Yerel oluşturulmuş betiklerin imzalı olmasını bekleme (bir dosyanın nasıl download edilmiş olduğunu anlarız? ZoneIdentifier ile).

Restricted: Tüm betikleri engelle.

Default: Varsayılan olarak iş istasyonları için restircted, sunucular için remotesigned.

Undefined: Politika tanımlı değil, default uygulanır. Niye ayrıca buna ihtiyaç duyulmuş, bilmiyorum.

Unrestircted: Patron çıldırdı, herşey serbest!

Amacımız Execution Policy'yi AllSigned yapabilmek için tüm scriptleri imzalamak için gereken adımları özetlemek. Önce bir sertifikaya ihtiyacımız var. Sertifka edinmenin pek çok yolu var. Bir sertifika hizmeti veren firmadan para ile almak bir yöntem. Yerel ağımızda bize bu hizmeti verecek bir sunucu (CA, certificate authority) varsa oradan da edinebiliriz. Bunların hiçbiri yoksa, sadece deneme amaçlı kullanılması önerilen "kendi kendine imzalanmış" bir sertifika da oluşturabiliriz. Sonuçta Windows Sertifika Deposu'nda bulunan ve kod imzalamak amacıyla üretilmiş (bu zorunlu) bir sertifikamız olsun. Buna bir PSDrive olan cert: sürücüsünden şu şekilde erişip bir değişkene atayabilriz (bu konumda:

PS> $sertifika = (Get-ChildItem cert:\CurrentUser\My -CodeSigningCert)[0]

Bu konumda birden fazla varsa ilkini seçer. Eğer illa "kendi kendine imzalanmış" sertifikamız olsun diyorsak

PS> New-SelfSignedCertificate -Subject "CodeSigning" -CertStoreLocation cert:\CurrentUser\My -Type CodeSigningCert -NotAfter (Get-Date).AddYears(5) -Keylength 4096 -Friendlyname PowershellSignature

Burada gözüken adımız "CodeSigning" olacak, sertifika cert:\CurrentUser\My (yani geçerli kullanıcının kişisel sertifikalar bölümünde) saklanacak, sertifikanın tipi CodeSigninCert olacak, 5 yıl geçerliliğe sahip olacak, anahtar uzunluğu 4096 bit olacak ve ismi PowershellSignature olacak. Eğer bunu kullancaksak ve geçerli kullanıcının kişisel sertifikalarında başka sertifika yoksa bunu bir değişkene atamak için yapacağımız şu olacaktır:

PS> $sertifika = Get-ChildItem cert:\CurrentUser\My -CodeSigningCert

Sonra Set-AuthenticodeSignature cmdlet'ini kullanarak ps1 uzantılı dosyamızı imzalayalım:

PS>  Set-AuthenticodeSignature -Filepath C:\scripts\sample.ps1 -Certificate $sertifika

İmzalanan powershell dosyasının sonuna yorum için kullanılan "#" karakteri ile başlayan 47 satırlık bir hash bölümü eklenecek. Bu hash, dosyamızın imzası olacaktır. İmzalandıktan sonra dosyada bir değişiklik olursa dosyayı tekrar imzalamamız gerekecektir.

Set-AuthenticodeSignature'ı çalıştırdıktan sonra Status kısmında UnknownError görürsek bu, işlemi yapmak için yükseltilmiş ayrıcalıklara ihtiyacımız olduğunu gösterir. Muhtemelen normal kullanıcı haklarımızla CurrentUser değil de LocalMachine altından bir sertifika okumuşuzdur. Normal yetkilerimizle işlem yapmak için sertifikayı CurrentUser altına koymak daha pratik bir yol.

Normal şartlar altında bir sertifikaya güvenebilmek için o sertifikayı imzalayan (bize veren) kurumun kök sertifikasına da güvenmemiz gerek. Yani o da bizim sertifika depomuzda olmalı. "kendinden imzalı" sertifikalar için böyle birşey olmadığından sertifika zincirlerinde bir güvensizlik sarı bir ünlem veya kırmızı çarpı ile kendini belli edebilir. Bu durumun kolay çözümü "kendinden imzalı" sertifikamızın bir koyasını da "Güvenilir Kök Sertifika Yetkilileri" (Trusted Root Certification Authorities) koymaktır.

Son olarak execution policy'mizi AllSigned yapabiliriz, ama bunu yapmak için yine yükseltilmiş ayrıcalıklara (yönetici yetkilerine) ihtiyacımız olacak:

PS> Set-ExecutionPolicy AllSigned

Betiği her değiştirdiğimizde bu sürece tekrar katlanmamak için bu işi bir de yapacak bir betik yazabiliriz (hata denetimini atladım). İmzalanacak dosyayı -filename parametresi ile belirtmek gerek. Bu dosyayı oluşturduktan sonra çalıştırabilmek için yukarıdaki satırları bir kez daha kullanarak bunu da imzalamamız gerek.

function imzala {
    param(
        [string]$filename 
    )

    $s = Get-ChildItem cert:\CurrentUser\My -CodeSigningCert
    Set-AuthenticodeSignature -Filepath $filename -Certificate $s
}

1.02.2023

Powershell ile bilgisayarlar arasında dosya aktarımı

Eğer bir etki alanına üye iki bilgisayar söz konusuysa

PS> Copy-Item \\pc1\paylasim\dosya1 -Destination \\pc2\ortak

şeklinde dosya aktarımı yapılabilir. ama daha karmaşık bir durum olduğunu varsayalım. Bu iki bilgisayar da etki alanının üyesi olmasın. İki bilgisayar için de bir powershell uzak oturumu başlatmış olduğumuzu varsayalım

PS> $oturum1 = New-PSSession -Computername pc1 -Credential (Get-Credential "pc1\user1")

PS> $oturum2 = New-PSSession -Computername pc2 -Credential (Get-Credential "pc2\user2")

Maalesef, iki oturum arasında bir seferde dosya aktarabilmek için şöyle bir şansımız yok:

PS> Copy-Item C:\klasor1\dosya1.txt -Destination C:\klasor2 -FromSession $oturum1 -ToSession $oturum2

Bunu yapmayı denersek powershell bize FromSession ve ToSession parametrelerinin aynı anda kullanılamayacağını söyler. Bunun yerine kopyalamak istediğimiz dosyayı önce kendi bilgisayarımıza aktarabilir, daha sonra pc2'ye aktarabiliriz:

PS> Copy-Item C:\klasor1\dosya1.txt -Destination D:\depo -FromSession $oturum1

PS> Copy-Item D:\depo\dosya1.txt -Destination C:\klasor2 -ToSession $oturum2

Ya da pc1'deki oturuma girip, $oturum2 nesnesini bu bilgisayarda oluşturup, hedef dosyayı doğrudan pc2'ye aktarabiliriz. Burada sorun pc1'deki oturumda get-credential gibi bir cmdlet'i çağırmak olurdu. Bu durumda da iki seçeneğimiz var. Birincisi credential nesnesini kendi makinemizde oluşturup, bunu $using ile pc1'e göndermek:

PS> $cred2 = Get-Credential "PC2\user2"

PS> Enter-PSSession -Session $oturum1

[pc1] PS> $oturum_pc2 = New-PSSession -Computer pc2 -Credential $using:cred2

[pc1] PS> Copy-Item C:\klasor1\dosya1.txt -Destination C:\klasor2 -ToSession $oturum_pc2

İkinci seçeneğimizde ise credentials nesnesi yerine pc1 üzerindeki oturumda şifreyi açıkça yazmak:

PS> Enter-PSSession -Session $oturum1

[pc1] PS> $kullanici = "PC2\user2"

[pc1] PS> $parola = ConvertTo-SecureString -String "parolamiz" -AsPlainText -Force

[pc1] PS> $cred2 = New-Object -TypeName System.Management.Automation.PSCredential -Argumentlist $kullanici, $parola

[pc1] PS> $oturum_pc2 = New-PSSession -Computername pc2 -Credential $cred2

[pc1] PS> Copy-Item C:\klasor1\dosya1.txt -Destination C:\klasor2 -ToSession $oturum_pc2

En az güvenli olan yöntem, sanıyorum en sondaki oldu, çünkü parolayı açık açık girmek zorunda kaldık.

31.01.2023

Etki alanında olmayan makinelere powershell ile uzaktan bağlanmak

Kısacası PSRemoting. Uzun konu. Ama pratik olarak etki alanında (domain) olmayan makinelerin birbirlerine nasıl uzaktan bağlanacaklarına hızlıca bakalım.

İki makine de workgroup modunda. Bağlantıyı başlatarak karşı tarafta bağlanacak makineye "kaynak", kendisine bağlanılmasını bekleyecek makineye de "hedef" diyelim.

Bu ikisinin de güvenlik duvarları açık olabilir. Kaynak makinenin dışarı çıkışının engellenmediğini varsayarak bu tarafta yapılacak birşey yok. Ama hedef makine dinleme modunda olduğundan bu makinede uygun portlar açacak ayarların yapılması gerekecek. Ayrıca hedef makinede bu bağlantıyı bekleyecek (dinleyecek) bir yapı da olmalı. Bu da WinRM hizmeti. Varsayılan olarak yeni sistemlerde bu kapalı geliyor. Bunun da açılması gerekecek. Birkaç küçük ayrıntı daha var. Şükür ki bunları otomatik yapan bir cmdlet var. Hedef makinede sadece şunu yazmak yeterli:

PS> Enable-PSRemoting

Eğer bunu yazınca ağ profilimiz ile ilgili şikayet ediyorsa Public profildeyiz demektir. İki seçeneğimiz var; ya -SkipNetworkProfileCheck parametresini kullanarak tekrar deneyebiliriz ya da ağ profilimizi değiştirmeliyiz. Bence ikincisi daya iyi bir seçenek. Değiştirmek için

PS> Set-NetConnectionProfile -NetworkCategory Private

Hedef makine ile işimiz bitti. Şimdi sıra kaynak makinede. Powershell ile bağlanırken kullanıcı adı ve şifre bilgileri karşı makineye gönderileceğinden karşıdaki makinenin gerçekten güvenilir olup olmadığından emin olmamız istenir. Bu sebeple rastgele makinelere bağlanmayı denerken kullanıcı adı ve şifre bilgilerini göndermememiz için güvenilir bilgisayarlar listesi oluşturulmuş. Sadece bu listedeki bilgisayarlara bağlanabiliriz. Bu liste de WSMan sürücüsünde localhost\Client\TrustedHosts gibi bir adrestedir. Mevcut içeriğini görüntülemek için

PS> Get-Item WSMan:\localhost\Client\TrustedHosts

kullanabiliriz. Hedef makinemizin adının da "hedef" olduğunu varsayarsak bu dosyaya bu bilgisayarın ismini girmemiz gerek. Şöyle bir komut kullanabiliriz:

PS> Set-Item WSMan:\localhost\Client\TrustedHosts -Value "hedef"

Bu komut TrustedHosts'un içeriğini değiştirir. Birden fazla ekleme yapmak için -Concatenate parametresi kullanılabilir. Bir de "sunucu" adında bir makine daha ekleyelim:

PS> Set-Item WSMan:\localhost\Client\TrustedHosts -Value "hedef" -Concatenate

Bu aşamada artık bağlanabiliriz:

PS> Enter-PSSession -Computername hedef -Credential (Get-Credential "hedef\kullanici")

Burada sorun varsa belki hedef makinedeki güvenlik duvarını tekrar kontrol etmek isteyebiliriz.

PS> Get-NetFirewallRule "WINRM-HTTP-In-TCP*"

Bu komut sonucunda 2 kural dönecektir. İkisi de 5985/TCP portunu etkinleştiren kuraldır ama özelliklerini aşağıaki gibi kıyaslayayım:

Kural ismi
Ağ profiliKapsamPort/ProtokolPrivate Profilde
WINRM-HTTP-In-TCPPublic
Yerel alt ağ
5985/TCPDevre dışı
WINRM-HTTP-In-TCP-NoScopeDomain ve Private
-yok-5985/TCPEtkin

Bu tabloda vurgulamak istediğim, isminde NoScope geçen Domain ve Private profilleri için oluşturulmuş bir kural. Bizim profilimiz de Private olduğu için burada etkinleştirilmiş duruma olmalı. Diğer kuralda ise kapsam (scope) belirtilmiştir, sadece yerel alt ağ. Eğer olur da public profili etkinleştirirsek bizim kontrol etmemiz gereken kural bu olacak.

Buna alternatif olarak hedef makine SSH sunucusu varsa ssh ile de bağlanmak mümkün. O yazımda yazmadığım şekilde Windows makineye ssh yüklemek için (bugün için beta) artık winget de kullanabiliriz:

PS> winget install "OpenSSH Beta"

4.01.2023

Komut satırından sıkıştırma ve açma

 Eskiden sadece tar vardı. Bir klasörü tar ile sıkıştırmak için

$ tar -czvf compressed.tar.gz /home/user/dir1

Burada

    -c : Create (oluştur)

    -z :  zip (sıkıştır)

    -v : verbose (dosya ayrıntılarını görüntüle)

    -f : Filename (sıkıştırılmış dosya adını belirt)

Birden fazla klasör boşluk bırakarak ard arda yazılabilir.

Hariç tutulmak istenen klasör veya dosyalar (* wildcard karakteri kullanılarak) --exclude parametresiyle verilebilir.

$ tar -czvf compressed.tar.gz /home/usr/dir1 --exclude=/home/user/dosya1.txt --exclude=*.mp4 --exclude /home/user/Download

Bu örneklerdeki -z parametresi gzip sıkıştırma yöntemini kullanıyordu. Yeni bir sıkıştırma yöntemi olan bzip2'yi kullanmak (daha fazla sıkıştırma oranı için) -z'yi -j ile değiştirmek gerek. Örneğin

$ tar -cjvf compressed.tar.bzip2 /home/user/dir1

Sıkıştırılmış dosyayı açmak (ayıklamak/çıkarmak) için ise -c anahtarını -x (eXtract) ile değiştirmek gerek:

$ tar -xzvf compressed.tar.gz

Bu komut mevcut klasörün içine çıkartır. Başka bir klasöre çıkartmak için -C (büyük C) anahtarı kullanılır:

$ tar -xzvf compressed.tar.gz -C /tmp

tar komutundan başka bir de zip komutu var. Bu komut ile tek bir dosyayı sıkıştırma yapmak için

$ zip compressed.zip /home/user/file1.txt

bir klasörü, altındaki tüm içerik ile birlikte sıkıştırmak için ise

$zip -r -q -9 compressed.zip /home/user/Documents/

kullanılabilir. Burada

    -r : Recurse (alt klasörleri de dahil et)

    -q : Quiet (sıkıştırılan her içeriği yazma)

    -9 : En yüksek sıkıştırma oranını kullan (-0 en düşük, -9 en yüksek sıkıştırma oranı)

Sıkıştırılan dosyaya bir parola vermek için -e anahtarı kullanılabilir. Bu anahtardan sonra parola sorulur.

zip ile sıkıştırılmış dosyaları açmak için ise unzip komutunu kullanmak gerek:

    $ unzip compressed.zip

Burada kullanılabilecek bazı anahtarlar şöyle:

    -q : Quiet (ayrıntıları yazma)

    -d <klasör> : çıkarılacak konumu belirt

    -P <parola> : Büyük 'P' harfi ile parola korumalı dosya için parola belirt (DİKKAT: Komut geçmişinde görüntülenecek!)

    -x <*>    : eXlude (hariç tut)

    -l : Çıkarmadan sadece zip dosyasının içeriğindeki dosyaları görüntüle

Bazı bonus komutlar şöyle:

$ zipcloak compressed.zip    # varolan bir dosyayı parola korumalı yap

$ zipdetail compressed.zip  # sıkıştırılmış dosya ayrıntılarını görüntüle

$ zipinfo compressed.zip  # sıkıştırılmış dosya ayrıntılarını görüntüle

$ zipgrep kelime compressed.zip # sıkışmış dosyaların içeriğinde anahtar kelime araması yap

$ zipsplit -n 1024000 compressed.zip # sıkıştırılmış dosyayı 102400 byte (1 MB) bölümlere böl

Son zamanlarda daha da fazla sıkıştırma oranı veren 7zip de kullanılabilir. Windows için yüklenen 7-zip paketinde de 7z komutu aynı işlemleri yapabilir. Bir klasörü 7zip ile sıkıştırmak için:

$ 7z a compressed.7z /home/user/log_file

çıkartmak için de

$ 7z e compressed.7z -o /home/user/

Tabi Windows'da powershell ile gelen Compress-Archive ve Expand-Archive komutları da kullanılabilir:

PS> Compress-Archive -Path log_file -DestinationPath compressed.zip

Açmak için de

PS> Expand-Archive -Path D:\archive\compressed.zip -DestinationPath C:\Users\fethi\

kullanılabilir.

28.12.2022

bind-chroot veya named-chroot

Bind DNS sunucusu kurmak için normal şartlar altında bind paketine ihtiyacımız var. Debian/Ubuntu için /etc/bind/ altındaki yapılandırmaları tamamlayıp zone dosyalarını da uygun yere (örneğin /etc/bind/zones) [Fedora/CentOS için ise /etc/named.conf dosyasını yapılandırıp /var/named/ altına zone dosyalarımızı] ekledikten sonra named-checkconf ve named-checkzone (bind-utils paketi ile gelen) ile yapılandırmaları kontrol edip named hizmetini başlattıktan sonra DNS sunucumuz hazır. Çalıştığından emin olmak için host, dig ve nslookup kullanabiliriz.

Ama her an internete bağlı bir DNS sunucusunun güvenliği ile ilgili endişe edenler için farklı bir seçenek daha var; bind-chroot. DNS hizmetini veren sürecin yetkilerini kısıtlayarak dosya sistemindeki erişimini bir chroot ortamı ile kısıtlamaya yarayan özel bir yapılandırma.

Fedora üzerinden işlem yaptığımızı varsayarsak öncelikle sisteme bind-chroot'u kurmamız gerek.

$ sudo dnf install bind-chroot bind-utils

bind'ı kurduktan sonra sistemdeki bütün isimleri named olacak. Alan adlarımızı chroot olmayan bind içinde çalışır hale getirdikten sonra öncelikle bu hizmeti durdurup devre dışı bırakalım.

$ sudo systemctl stop named

$ sudo systemctl disable named

Bu aşamada hem named hem de named-chroot hizmetleri devre dışı olmalı. Şimdi chroot ortamımızı hazırlayalım (bu adım öncesinde /var/named/chroot/ altında sadece named pki klasörleri olmalı).

$ /usr/libexec/setup-named-chroot.sh /var/named/chroot/ on

Bu adımdan sonra /etc/named.conf dosyasına /var/named/chroot/etc/named.conf yolundan, /var/named/forward.zone dosyasına ise /var/named/chroot/var/named/forward.zone yolundan erişeceğiz.

Bundan sonra named-chroot hizmetini başlatıp etkinleştirebiliriz.

$ sudo systemctl start named-chroot

$ sudo systemctl enable named-chroot

Güvenlik duvarımız etkindi. DNS için yeni kural ekleyep ayarları uygulayalım:

$ sudo firewall-cmd --permanent --add-service=dns

$ sudo firewall-cmd --reload

İşlem tamam.

---

Linux Bind kurulumu

9.12.2022

Powershell ile Windows'da IPv6'yı devre dışı bırakmak

Grafik arayüzden yapmak da bir yöntem ama Powershell varken Powershell'den yapmak lazım.

Bilgisayardaki ağ adaptörleri ile ilişkilendirilen birkaç "bileşen" var, aşağıdaki resimde görülebileceği gibi.

Grafik arayüz yöntemi ile yukarıdaki "İnternet Protokolü Sürüm 6 (TCP/IPv6)" öğesinin solundaki seçimi kaldırmak yeterli. Bunu powershell ile yapmak için önce Get-NetAdapterBinding cmdlet'ini kullanabiliriz. Bunun sonucunda bilgisayardaki tüm ağ adaptörleri (kablolu, kablosuz, sanal, Docker, VPN vs.)  ile ilişkilendirilen bütün bileşenlerin listesi gelir. Bunların içinden sadece konumuz ile ilgili olarak IPv6'ları görmek için -ComponentID argumanı ile birlikte ms_tcpip6 kimliğini kullanmalıyız.

PS> Get-NetAdapterBinding -ComponentID ms_tcpip6

Bunun sonucunda da bütün ağ adaptörlerinin IPv6 eşleştirmesi gelir. Amacımız bütün ağ adaptörlerinin IPv6 bileşeni ilişkisini kesmekse doğrudan bu komutun çıktısını Disable-NetAdapterBinding cmdlet'ine gönderebiliriz.

PS> Get-NetAdapterBinding -ComponentID ms_tcpip6 | Disable-NetAdapterBinding

Ama amacımız sadece, örneğin kablolu bağlantının (diyelim ki Ethernet) ilişkisini kesmek ise 

PS> Get-NetAdapterBinding -ComponentID ms_tcpip6 -Name Ethernet | Disable-NetAdapterBinding

kullanabiliriz. Daha kısa olsun, diye Get-NetAdapterBinding'i atlayıp direk bağlantıyı kesen cmdlet olan Disable-NetAdapterBinding'i de kullanabiliriz.

PS>Disable-NetAdapterBinding -ComponentID ms_tcpip6 -Name Ethernet

ama önce Get-NetAdapterBinding kullanmak işlemi hangi adaptör ve bileşenler üzerinde yaptığımızdan emin olmamızı sağlar.

2023-01-13 Ek: Farkettim ki ağ arayüzündeki ilişkileri kaldırmak IPv6'yı tamamen devre dışı bırakmıyormuş. Tamamen devre dışı bırakmak için şurada (Microsoft Exchange CSSRhoderic Milne blog) yazıldığı gibi HKLM\System\CurrentControlSet\Services\Tcpipv6\Parameters altına DWord olarak DisabledComponents değerini oluşturmak ve değerini Hex olarak FF (veya onluk düzende 255) vermek gerek.

26.11.2022

fedora-repos-archive

Bilgisayarımda bir sorun var. dnf update ile yaptığım güncellemelerin bazılarında işlem yarıda kalıyor, oturum kapanıyor ve kaldığı yerden devam ettiremiyorum. dnf history undo ve dnf history rollback kullanmayı denedim ama DNF <paket-adi> bulunamadı gibi bir hata verdi.

Şu adreste buldum ki fedora-repos-archive deposunu etkinleştirince bu hatalardan kurtulabiliyorum.

Önce fedora-repos-archive'i kuralım:

# sudo dnf install fedora-repos-archive

arkasından

# sudo dnf history undo 17

gibi bir işlemle 17. işlemi geri alabilir, ya da 

# sudo dnf history rollback 16

gibi bir işlemle sorunlu işlem olan 17'den önceki duruma dönebiliriz. Ama --allowerasing veya --skip-broken anahtarlarını kullanmak da gerekebilir.

İşimiz bittikten sonra /etc/yum.repos.d/fedora-updates-archive.repo dosyasındaki

enabled=1

satırını

enabled=0

olarak değiştirmek, bundan sonra dnf update sırasında fedora-repos-archive'i atlayarak güncelleme işlemlerini hızlandıracaktır.