25.10.2017

nmap

1 Eylül 2017 itibariyle nmap 20 yaşını dolduran proje. Her türlü çok faydalı.

Karışımızda tek bir bilgisayar (genel anlamda herhangi bir ağ cihazı olabilir, ama kısaca bilgisayar veya cihaz diyelim) var, IP adresi 192.168.1.1 olsun ve bu bilgisayarın sık kullanılan portlar üzerinden bir taramasını yapmak istiyoruz. Kullanacağımız komut:

nmap 192.168.1.1

Starting Nmap 7.31 ( https://nmap.org ) at 2017-10-24 09:05 Turkey Standard Time
Nmap scan report for 192.168.1.1
Host is up (0.027s latency).
Not shown: 997 closed ports
PORT   STATE SERVICE
22/tcp open  ssh
23/tcp open  telnet
80/tcp open  http
MAC Address: XX:YY:ZZ:WW:QQ:AA (üretici)

Nmap done: 1 IP address (1 host up) scanned in 2.16 seconds


gibi bir sonuç döner. Bir çok güzel bilgi var. 1000 tane port taramış, 997 tanesinin kapalı olduğunu, 3 tanesinin ise açık olduğunu söylüyor: 22, 23 ve 80. En altta gizlediğim MAC adresi var, yanında parantez içinde de üretici bilgisi yer alıyor. Birden fazla cihazı isim veya IP adreslerini boşlukla ayrılmış bir şekilde aynı satıra yazarak da taratabiliriz. IP aralığı vermek için 192.168.1.1-10 veya tüm oktet yerine * karakterini kullanarak 192.168.1.* veya CIDR notasyonu ile 192.168.1.1/24 de yazabiliriz.

Genel olarak taramanın iki aşaması var; ilk aşama cihaz keşfi (host discovery). Bu aşamada verilen IP aralığındaki açık ve taranabilir cihaz listesi çıkartılıyor, açık olduğuna dair hiçbir iz olmayan IP adreslerinin portlarını tarayarak vakit kaybetmemek için. İkinci aşama port taraması (port scanning). Bu aşamada da hedef bilgisayarların açık olan portlarını bulmaya çalışıyor. Sadece cihaz keşfi yapıp, port taraması yapmamak için -sn anahtarını, tam tersi durumda cihaz keşfi yapmadan doğrudan verilen tüm IP adreslerini port taramasına sokmak için -Pn anahtarını kullanabiliriz.

Cihaz Keşfi

Port taramasını tamamen atlayıp sadece ping taraması gerçekleştirmek için:

nmap -sn 192.168.1.*

Sadece belli bir aralıktaki cihazların ters DNS sorgularını yapıp toplam sayıyı almak için (bilgisayarlara hiçbir paket gönderilmeden)

nmap -sL 192.168.1.*

SYN flag set edilmiş TCP paketi ile ping yapmak için (port taramasız):

nmap -sn -PS 192.168.1.*

SYN biti 1 olan bir paket alındığında, eğer o portu dinleyen bir hizmet yoksa RST biti 1 olan bir paket ile cevap verilir. Eğer dinleyen bir hizmet varsa da hedef makine bir sonraki aşamaya geçerek SYN/ACK bitleri 1 olan bir paket ile cevar verir. Bu da yine karşıdaki cihazın açık olduğunu anlamamıza yarar.

ACK flag set edilmiş TCP paketi ile ping yapmak için (port taramasız):

nmap -sn -PA 192.168.1.*

ACK biti 1 olan bir pakette ise var olan bir TCP bağlantısında alınan veriye ait alındı cevabı gönderiliyormuş gibi yapılır. Bu cevabı alan hedef makine ise RST biti 1 olan bir paket ile cevap verir ki bu da aynı şekilde hedef makinenin açık olduğunu gösterir.

Yukarıdaki iki yöntem varsayılan olarak TCP 80 portunu kullanır. Bu durumu değiştirmek için komut satırında -p20 gibi bir port belirtebiliriz.

UDP taraması yapmak için (port taramasız):

nmap -sn -PU 192.168.1.*

varsayılan olarak UDP taramasında 40125 portu kullanılır, kullanılan bir porta denk gelmesi için. Kullanmayan bir porta UDP paketi gönderildiğinde ICMP port erişilemiyor cevabının gönderilir. Bu da karşıdaki bilgisayarın açık olduğunu gösterir. Kullanımda bir UDP portuna denk gelirsek hiçbir cevap dönülmez. Bu sebeple varsayılan olarak 40125 gibi kullanılma ihtimali az olan bir port seçilmiş.

Bir de SCTP kullanarak yukarıdaki denemenin yapılması var:

nmap -sn -SY 192.168.1.*

Denemeleri yaparken dikkat edilecek bir konu; yerel ağdaki bir hedefi tarıyorken bir de WireShark'ta gönderilen paketleri inceliyorsanız sadece ARP protokolünün kullanıldığını, ne TCP SYN ne de ACK kullanıldığını görünce şaşırabilirsiniz. Bu durum yerel ağdaki cihazların açık olduğunu ARP ile anlamanın daha kolay olmasından kaynaklanıyor. nmap bu kolay yöntemi kullanıyor. ARP'yi kapatmak için komut satırından --disable-arp-ping 'i kullanabilirsiniz, şöyle:

nmap -sn -PS 192.168.1.* --disable-arp-ping

Tam tersine, yerel ağdaki cihazları sadece ARP sorgularıyla tespit etmek istiyorsak ARP ping kullanmalıyız:

nmap -sn -PR 192.168.1.*

ARP protokolü düşük TCP stack'inde düşük seviyede çalışan bir protokoldür. İşletim sisteminin güvenlik duvarı ile "genelde" engellenmezler. Basit olarak gönderilen "Kim 192.168.1.5 adresine sahip?" sorgusuna, bu adrese sahip cihaz tarafından cevap verilir. Bunu aslında 192.168.1.5 adresine ping atıp daha sonra ARP cache'ine bakarak da bulabiliriz. Ama nmap'in bu işi işletim sisteminin algoritmalarına kıyasla, çok sayıda hedef cihaz üzerinde daha optimize bir şekilde yaptığı belirtilmiş.

Port Taraması

nmap'in -P ile başlayan anahtarları cihaz keşfi ile ilgili olanlardı. Port taraması ile ilgili olanlar ise -s ile başlar.

Yine SYN biti 1 olan bir paket ile port taraması yapmak için

nmap -sS -p80 192.168.1.1

SYN paketi gönderip gerisini getirmeden bağlantıyı sonlandırmak için işletim sistemi tarafından sunulan standart ağ rutinlerinin dışında özel paketler göndermek gerekir. Bu da root/administrator yetkisi ister çoğu durumda. Bu duruma alternatif işletim sisteminin standart rutinleri ile işi gerçekleştirmek için TCP Connect taraması tercih edilebilir.

nmap -sT -p80 192.168.1.1

SYN taraması çoğu durumda loglara girmez, dikkat uyandırmaz. Ama çok sayıda TCP Connect taraması loglara girer ve dikkat uyandırır. Dahası yavaştır ve aynı bilgiyi elde etmek için daha fazla paket gönerilmesini gerektirir. Ama mecbur kalınınca kullanılabilir.

UDP kullanan portlar üzerinden tarama yapmak için ise

nmap -sU 192.168.1.1

Cihaz keşfini atlayıp sadece 53 UDP portunu kontrol etmek istersek

nmap -Pn -sU -p53 192.168.1.1

SCTP ile port taraması yapmak için -sY kullanılablir. Şu sayfada çok faydalı bir yöntem olarak vurgulanmış.

nmap -sY 192.168.1.1

Cihaz keşfinde kullanılan ACK bitini port taramasında da kullanabiliyoruz. Ama burada durum biraz daha farklı. -sA ile TCP ACK scan yapmak mümkün. Ama bu taramayla portların tam durum bilgisini edinmek mümkün değil. Daha çok firewall kurallarını tahmin etme, stateful mu değil mi öğrenmek için kullanılabilir.

Bunun dışında TCP Null (-sN), TCP FIN (-sF) ve Xmas (-sX) taramaları var, ama kullanım alanları biraz daha kısıtlı.

Hedef bilgisayarın verdiği cevaplara göre hangi işletim sistemine sahip olduğunu tahmin edebiliriz:

nmap -O 192.168.1.1

Hedef bilgisayarın bir güvenlik duvarı ile korunup korunmadığını bulmak için

nmap -sA 192.168.1.1

Son olarak port bazında dönülen open, closed ve filtered durumlarına açıklama getireyim. Bir port açıksa ve gönderilen örneğin SYN paketine SYN veya SYN/ACK ile cevap veriyorsa port open olarak listelenir. Bağlantıya karşılık RST ile cevap veriyorsa port kapalı olarak listelenir. Gönderilen pakete hiç cevap gelmiyorsa filtered olarak görülür.

Şu sayfada verilen cheat-sheet faydalı olabilir:


Scripting Engine

smb-os-discovery

Tüm yetenekleri bunlar değil elbette. Çok faydalı bulduğum özelliklerinden biri de hazır gelen, veya genişletilebilen scriptler ile ileri seviye bazı taramalar yapabiliyor olması. Örneğin SMB protokolü üzerinde işletim sistemi ve diğer bazı özellikleri edinebileceğimiz aşağıdaki tarama çok faydalı bilgiler içeriyor. Bu bilgilerin edinilebilmesi için cihazın SMB (veya linux SAMBA) protokolünü destekliyor olması gerek.

nmap -p 445 --script smb-os-discovery 192.168.1.0/24

Nmap scan report for pc1.domain (192.168.1.1)
Host is up (0.066s latency).
PORT    STATE SERVICE
445/tcp open  microsoft-ds
MAC Address: xx:xx:xx:xx:xx:xx (Manufacturer)

Host script results:
| smb-os-discovery:
|   OS: Windows 7 Professional 7601 Service Pack 1 (Windows 7 Professional 6.1)
|   OS CPE: cpe:/o:microsoft:windows_7::sp1:professional
|   Computer name: pc1
|   NetBIOS computer name: pc1\x00
|   Domain name: domain
|   Forest name: domain
|   FQDN: pc1.domain
|_  System time: 2017-11-29T10:51:37+03:00


ssl-enum-ciphers

HTTPS üzerinden hizmet veren bir web sunucunun hangi protokolleri desteklediğini bulmak için bu da çok faydalı. SSLv1 ve SSLv2 kullanan "riskli" sunucuların tespit edilebilmesi için kullanılabilir.



nmap --script ssl-enum-ciphers -p 443 www.example.com

Starting Nmap 7.31 ( https://nmap.org ) at 2017-11-29 11:10 Turkey Standard Time
Nmap scan report for
www.example.com (192.168.1.9)
Host is up (0.00013s latency).
Other addresses for
www.example.com (not scanned):
192.168.1.9rDNS record for www.example.com: bosbdata.bosb.lc
PORT    STATE SERVICE
443/tcp open  https
| ssl-enum-ciphers:
|   SSLv3:
|     ciphers:
|       TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C
|       TLS_RSA_WITH_RC4_128_SHA (rsa 2048) - C
|       TLS_RSA_WITH_RC4_128_MD5 (rsa 2048) - C
|     compressors:
|       NULL
|     cipher preference: server
|     warnings:
|       64-bit block cipher 3DES vulnerable to SWEET32 attack
|       Broken cipher RC4 is deprecated by RFC 7465
|       CBC-mode cipher in SSLv3 (CVE-2014-3566)
|       Ciphersuite uses MD5 for message integrity
|   TLSv1.0:
|     ciphers:
|       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (secp256r1) - A
|       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (secp256r1) - A
|       TLS_DHE_RSA_WITH_AES_256_CBC_SHA (dh 1024) - A
|       TLS_DHE_RSA_WITH_AES_128_CBC_SHA (dh 1024) - A
|       TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
|       TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C
|       TLS_RSA_WITH_RC4_128_SHA (rsa 2048) - C
|       TLS_RSA_WITH_RC4_128_MD5 (rsa 2048) - C
|     compressors:
|       NULL
|     cipher preference: server
|     warnings:
|       64-bit block cipher 3DES vulnerable to SWEET32 attack
|       Broken cipher RC4 is deprecated by RFC 7465
|       Ciphersuite uses MD5 for message integrity
|       Key exchange (dh 1024) of lower strength than certificate key
|_  least strength: C
MAC Address:
xx:xx:xx:xx:xx:xx (Manufacturer)

Nmap done: 1 IP address (1 host up) scanned in 3.38 seconds


En altta yazdığı gibi en düşük güvenlik seviyesi C. Yukarıda da kırmızı ile bu güvenlik seviyesindeki protokoller var. Bunların kapatılması gerekebilir.

[1] https://nmap.org/book/man
[2] https://nmap.org/book/man-host-discovery.html
[3] https://nmap.org/book/man-port-scanning-techniques.html
[4] https://hackertarget.com/7-nmap-nse-scripts-recon/
[5] https://nmap.org/nsedoc/
[6] https://www.computerhope.com/unix/nmap.htm
[7] https://www.tecmint.com/use-nmap-script-engine-nse-scripts-in-linux/
[8] https://bencane.com/2013/02/25/10-nmap-commands-every-sysadmin-should-know/

23.10.2017

Wayland mi X mi kullanıyoruz nasıl anlarız?

Linux veya benzeri işletim sistemlerinin grafik arayüz için kullandıkları X Windowing System'in günlük ihtiyaçları karşılayamaması sebebiyle Waylan adında bir projeye başlandı. Bazı dağıtımlar hala X kullanırken bazıları Wayland'a geçiş yaptı.

Kullandığımız dağıtımın hangisini kullandığını nasıl anlarız sorusuna bulduğum yanıtlar şöyle:

1. Yöntem:
Terminalden önce mevcut oturum kimliğimizi (session ID) bulalım:

$ loginctl
    SESSION       UID    User       SEAT
          1      1000    metin      seat0

Dikkat edilecek yer, SESSION başlığının altında kalan sayı. Bizi durumumuzda 1. İkinci adımda bu sayıyı kullanarak şu satırı yazalım (küçük büyük harf duyarlı):

$ loginctl show-session 1 -p Type
Type=X11

Hala X11 kullanıyormuşuz.

2. Yöntem
$ echo $XDG_SESSION_TYPE
x11

sonuç x11 veya wayland olarak belirtilir. Benim X kullandığım çıktı.

3. Yöntem
Gnome için:

$ ps aux | grep gnome-shell

ya da KDE Plasma için

$ ps aux | grep plasma

Eğer sonuçların arasında --wayland görünüyorsa Wayland kullanıyoruz. Gnome üzerinde şöyle birşey çıkıyorsa

metin 1877 0.0 0.0  118520   976  pts/0  S+  08:09  0:00 --color=auto  gnome-shell

veya KDE plasma üzerinde

root 1071 0.0 0.1 62740 16988 ? S 16:55 0:00 /usr/lib/sddm/sddm-helper --socket /tmp/sdd
m-authf3607558-f925-4db1-b685-3431073f8948 --id 1 --start /usr/bin/startplasma-x11 --user metin


gibi birşey çıktığı için X kullanıyorum.

12.10.2017

Günlük ihtiyaçlar için Powershell

Bu yazı, standart komut satırı araçlarının Powershell eşdeğerlerini listelemeyi amaçlıyor. Aşağıda önce komut satırı çözümünü, sonrasında da Powershell eşdeğerini yazacağım.

Dosya sistemi işleri

Dosya sistemi temel komutları olan cd, dir, del, mkdir gibi komutları aynen Powershell'de de kullanabiliyoruz. Bunlar alias'lar aracılığıyla oluyor. Ama aslında arka tarafta komut satırı penceresinin iç komutlarından başka komutlar çalışıyor.

C:\> dir
PS C:\> Get-ChildItem

C:\> cd 
PS C:\> Set-Location

C:\> del
PS C:\> Remove-Item

C:\> mkdir
PS C:\> New-Item -ItemType Directory

Bunlara ek olarak örneğin tüm alt klasörlerde bulunan ve isminde fatura geçen dosyaları bulmak için

C:\> dir *fatura* /s
eşdeğeri
PS C:\> dir -Include *fatura* -Recurse

Hatta daha da fazlasını yapıp içinde fatura geçen dosyaların son 1 ayda oluşturulanlarını bulmak için ise

PS C:\> dir -Include *fatura* -Recurse | ? {$_.CreationTime -gt (Get-Date).AddMonths(-1)} | select CreationTime, LastWriteTime, Fullname

kullanılabilir. -Include anahtarı bazen garip bir şekilde istediğim gibi sonuç vermiyor. Bu durumda -Filter anahtarı faydalı olabiliyor. Tek yapılacak -Include'u silip yerine -Filter eklemek. Duruma göre tırnak içine almak gerekebilir.

En çok ihtiyaç duyduğum başka bir şey ise içinde belli bir kelime veya karakter kümesi geçen belli tipte uzantıya sahip dosyaları bulmak. Bunu klasik komut satırında şu şekilde yapıyordum:

C:\> findstr /s /i "admin" *.log

Bunun eşdeğeri de Select-String cmdlet'i. Alias'ı ise sls:

PS C:\> dir *.log -Recurse | sls -Pattern "admin"

findstr.exe alt klasörleri de kapsama alabilecek /s anahtarına sahip. Select-String (sls) cmdlet'inin böyle bir yeteneği yok ama Get-ChildItem (dir) cmdlet'inin çıktısını ona yönlendirerek bu ihtiyacı karşılayabiliyoruz. Eğer alt klasörler değil de sadece mevcut klasördeki bazı dosyalar içinde arama yapacaksak dir (Get-ChildItem) komtuna ihtiyaç yok. Doğrudan sls (Select-String) kullanabiliriz:

PS C:\> sls -Path C:\*.log -Pattern "admin" 

Select-String cmdlet'i varsayılan olarak küçük/büyük ayrımı yapmaz (case insensitive). Özellikle küçük/büyük harf ayrımı olmasını isterseniz -CaseSensitive parametresini kullanmalısınız.

Komut satırından yeni dosya oluşturmak için New-Item cmdlet'i kullanılabilir. New-Item hem dosya, hem klasör, hem de başka sağlayıcıların yeni öğelerini yaratmak için kullanılabilir. Varsayılan değeri File (dosya)dır.

PS C:\>New-Item -Path D:\klasor1 -ItemType file -Name dosya1.txt

Dosya veya klasör ismini değiştirmek için Rename-Item kullanılabilir.

PS C:\>Rename-Item -Name dosya.log -NewName dosya.txt

Ancak Path parametresi wildcard desteklemez. Bunun için toplu dosya isim değiştirme işlemlerini şunun gibi yapmak gerekir:

PS C:\>Get-ChildItem *.log | Rename-Item -NewName {$_.Name -replace ".log", ".txt"}

Linux'ta olduğu gibi New-Item cmdlet'i taşımayı deskeklemez. Yani NewName parametresi sadece dosya adı olmalıdır. Bu alanda dosya yolu verisi olamaz. Taşıma işlemleri için Move-Item kullanılmalıdır ve Path parametresi wildcard'ları destekler.

PS C:\>Move-Item -Path .\file*.txt -Destination D:\klasor1

Ağ sorun giderme

Komut satırının meşhur ping komutu harici bir komut olduğu için Powershell'de ping çalışıyor. Ama bunun yerine başka bir alternatif komut daha var.

C:\> ping 192.168.1.1                                   
                                                        
Pinging 192.168.1.1 with 32 bytes of data:              
Reply from 192.168.1.1: bytes=32 time<1ms TTL=128       
Reply from 192.168.1.1: bytes=32 time<1ms TTL=128       
Reply from 192.168.1.1: bytes=32 time<1ms TTL=128       
Reply from 192.168.1.1: bytes=32 time<1ms TTL=128       
                                                        
Ping statistics for 192.168.1.1:                        
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:          
    Minimum = 0ms, Maximum = 0ms, Average = 0ms         


PS C:\> Test-Connection -Computarname 192.168.1.1

Source    Destination   IPV4Address  IPV6Address Bytes    Time(ms)
------    -----------   -----------  ----------- -----    --------
MET8      192.168.1.1   192.168.1.1              32       0
MET8      192.168.1.1   192.168.1.1              32       0
MET8      192.168.1.1   192.168.1.1              32       0
MET8      192.168.1.1   192.168.1.1              32       0


Bu bildiğimiz ICMP ping.exe'nin karşılığı. Aynı ping.exe'de olduğu gibi varsayılan olarak 32 byte'lık paketler gönderiyor. Varsayılan olarak 1 saniye bekliyor, varsayılan olarak 4 paket gönderip duruyor. Sırasıyla bu parametreleri değiştirmek için -BufferSize, -Delay ve -Count kullanmak gerek.

Ayrıca ICMP ile değil de, TCP ile herhangi bir portu denemek istersek de

PS C:\> Test-NetConnection -ComputarName server01 -Port 21

kullanabiliriz. Bunun eşdeğeri klasik komut satırında yoktu. Bunun yerine psping veya benzer uygulamaları kullanıyorduk. tracert komutunun eşdeğeri olarak Test-NetConnection'ı -TraceRoute parametresi ile birlikte kullanabilirizi

PS C:\> Test-NetConnection -TraceRoute google.com

Bilgisayarda hangi ağ aygıtları var görmek istersek:

PS C:\> Get-NetAdapter
Name       InterfaceDescription     ifIndex Status  MacAddress         LinkSpeed
----       --------------------     ------- ------  ----------         ---------
Ethernet   Broadcom NetXtreme...          4 Up      XX-XX-XX-XX-XX-XX      1 Gbps
Wi-Fi      Intel(R) Centrino ...          3 Discon. XX-XX-XX-XX-XX-XX      0 bps
Buradan bir arayüzün IP adresini bulmak istersek (örneğin Ethernet cihazı) ifIndex sütunundaki arayüz endeksini alıp aşağıdaki komuta yazarak IP adresini öğrenebiliriz.

PS C:\> Get-NetIPAddress -InterfaceIndex 4         
IPAddress         : 192.168.1.5                    
InterfaceIndex    : 4                              
InterfaceAlias    : Ethernet                       
AddressFamily     : IPv4                           
Type              : Unicast                        
PrefixLength      : 16                             
PrefixOrigin      : Manual                         
SuffixOrigin      : Manual                         
AddressState      : Preferred                      
ValidLifetime     : Infinite ([TimeSpan]::MaxValue)
PreferredLifetime : Infinite ([TimeSpan]::MaxValue)
SkipAsSource      : False                          
PolicyStore       : ActiveStore
 
2022-08-26 Ek: netstat alternatifi olarak da Get-NetTCPConnection kullanılabilir.

PS C:\> Get-NetTCPConnection -RemotePort 443

arp -a alternatifi olarak Get-NetNeighbor kullanılabilir, hatta IPAddress alanında '*' wildcard olarak kabul edilir:

PS> Get-NetNeighbor -IPAddress 192.168*
 
route print yerine Get-NetRoute kullanılabilir, hatta belli bir ağ arayüzü için interface index verilerek çıkış daraltılabilir:
 
PS> Get-NetRoute -InterfaceIndex 2 

Ağ arayüzü ve IP adresi eşleşmesi için Get-NetIPInterface komutu faydalı olabilir, IP sürümü ve bağlantı durumu kısıtlamasıyla:

PS> Get-NetIPInterface -AddressFamily IPv4 -ConnectionState Connected

Hizmetler

Yerel bilgisayardaki hizmetlerin bir listesini almak için komut:

PS C:\> Get-Service

veya kısaca

PS C:\> gsv

yeterli. Ama hayat her zaman bu kadar kolay olmuyor. İlgilendiğimiz sadece DHCP client hizmeti ise şu şekilde bir komut ile durumunu sorgulayabiliriz:

PS C:\> gsv dhcp

Status   Name               DisplayName
------   ----               -----------
Running  Dhcp               DHCP Client

Bu hizmeti tekrar başlatmak için boru karakteri ile Get-Service cmdletinin yukarıdaki çıktısını Restart-Service cmdlet'ine yönlendirebiliriz.

PS C:\> gsv dhcp | Restart-Service

Bazen de adını tam bilmediğimiz bir hizmetin durumunu öğrenmek isteriz. Örneğin "Bit Locker Drive Encryption Service"in kısa servis adını bulmak için şunu yapabiliriz:

PS C:\> gsv | select DisplayName, Name, Status | sls "bit"

@{DisplayName=BitLocker Drive Encryption Service; Name=BDESVC; Status=Stopped}
@{DisplayName=VMware USB Arbitration Service; Name=VMUSBArbService; Status=Running}


2 tane hizmet döndü, bunların ilki bizim aradığımız (daha temiz bir çıktı için gsv | out-string -stream | sls "bit" kullanılabilir). Kırmızı ile belirttiğim kısa hizmet adının hemen devamında da Status = Stopped olarak gözüküyor. Bunu tekrar başlatmak istersek

PS C:\> Start-Service BDESVC

dememiz yeterli.

(04.01.2018 düzeltme: daha da kısa olarak aynı şeyi gsv -Disp *bit* ile de yapabiliriz)

Sadece çalışan servisleri başlatmak için kullanabileceğimiz bir parametresi yok Get-Service cmdlet'inin. Bunun yerine Get-Service'in çıktısını Where-Object cmdlet'ine yönlendirerek sadece çalışanları süzebiliriz:

PS C:\> gsv | ? {$_.Status -eq "Running"}

Eğer bu işi yerel makinede değil de uzaktaki bir makinede yapmak istiyorsak Get-Service cmdlet'ine -ComputerName parametresi ile uzak makine adını belirmek gerek.

PS C:\> gsv -Computername server01| ?{$_.Status -eq "Running"}

Windows Olayları

En sık kullanılan araçlardan biri de Windows Olaylarıdır. Örneğin sistem olay günlüğüne bakmak için şu cmdlet'i kullanabiliriz:

PS C:\> get-eventlog -LogName system

Tabi bu binlerce kayıt dönebilir. Bunun yerine en yeni 10 olaya

PS C:\> get-eventlog system -Newest 10

ya da son 1 saatte meydana gelen olaylara bakmak isteyebiliriz:

PS C:\> get-eventlog system -After (Get-Date).AddHours(-1)

Eğer belli bir Event ID'ye sahip olayları süzmek isterseniz bu noktada yine Where-Object'e başvurmak gerek.

PS C:\> Get-Eventlog -LogName system -Newest 10 | Where-Object {$_.EventID -eq 7040}

Where-Object'e başvurmadan doğrudan Get-Eventlog tarafından süzme işleminin yapılabiliyor olması güzel olurdu, ama olmamış. Bunun ne dezavantajı var? Yukarıdaki örnekte öncelikle son 10 olayı görmek istiyor, sonrasında da bu olayların içinde Event ID'si 7040 olanları seçiyoruz. Bu durumda dönen olay sayısı 10 da olabilir, 0 da olabilir. Yani Event ID'si 7040 olan son 10 olayı almak istersek bu sefer olayın sırasını değiştirmek lazım:

PS C:\> Get-EventLog -LogName system | Where-Object {$_.EventID -eq 7040} | Select-Object -First 10

Ancak bu da nispeten ilk duruma göre çok daha fazla uzun sürecek. Çünkü Get-Eventlog çalışmaya başlayınca en yeni olaylardan başlayarak olayları getirir. Belli bir ölçüt belirtilmişse o ölçüte göre (son 5 olay, son 1 saatte olan olaylar, belli bir kaynaktan gelenler vs.) göre işlem yapar. Ancak son örnekteki gibi bir ölçüt yoksa tüm olayları tarar, ve sonrasında bunların içinden süzme işlemi yapar. Bu da hem daha fazla işlemci hem de daha fazla bellek kullanımını gerektirir.

Alternatif olarak Get-EventLog cmdlet'i yerine Get-WinEvent cmdlet'i kullanılabilir. 7040 olay kimliği için son 10 olayı aşağıdaki şekilde çekebilriz:

PS C:\> Get-WinEvent -FilterHashTable @{LogName=System;ID=7040} -MaxEvents 10

Veya son 1 saat içinde gerçekleşen tüm 7040 olaylarını görmek için

PS C:\> Get-WinEvent -FilterHashTable @{LogName=System;ID=7040;StartTime=(Get-Date).AddHours(-1)}

Birden fazla ID'yi virgüllerle ayırarak yazabiliriz. StarTime gibi EndTime gibi bir son tarih-saat bilgisi de verilebilir. FilterHashTable ile kullanılabilecek bazı alanlar

Key name        Value data type        Accepts wildcard characters?
 LogName        <String[]>             Yes
 ProviderName   <String[]>             Yes
 Path           <String[]>             No
 Keywords       <Long[]>               No
 ID             <Int32[]>              No
 Level          <Int32[]>              No
 StartTime      <DateTime>             No
 EndTime        <DataTime>             No
 UserID         <SID>                  No
 Data           <String[]>             No
 *              <String[]>             No


Görüleceği gibi wildcard'lar sadece LogName ve ProviderName için kullanılabiliyor.  Keyword gibi alanlar olayın ayrıntısında anahtar kelime araması yapmak için değil. Bu alan için veri tipinin Long[] olduğuna dikkat etmek gerek. Sadece hataları listelemek için Level=2, uyarılar için Level=3 ve nihayet bilgi seviyesindeki olaylar için Information=4 kullanılabilir.

 Kayıt Defteri

Windows Kayıt defteri ile uğraşmak nispeten komut satırına göre daha kolaydır. Yolunu bildiğiniz bir kayıt defteri konumunu sanki dosya sisteminde bir konumda çalışıyormuş gibi cd (Get-ChildItem) cmdlet'iyle görebilirsiniz.

PS C:\> dir HKLM:\Software\Microsoft\Windows\CurrentVersion\Run

Üstelik de her adımda tab ile tamamlama imkanıyla.

Get-ChildItem ile gezilebilecek yerler dosya sistemi ile kayıt defterinden ibaret değil. Bu tip nesnelere PowerShell Drive deniyor. Tüm PSDrive sürücülerinin listesi için

PS C:\> Get-PSDrive
Name    Used (GB) Free (GB) Provider      Root
----    --------- --------- --------      ----
Alias                       Alias
C                           FileSystem    C:\
Cert                        Certificate   \
D                           FileSystem    D:\
Env                         Environment
Function                    Function
S                           FileSystem    \\server\paylasim
HKCU                        Registry      HKEY_CURRENT_USER
HKLM                        Registry      HKEY_LOCAL_MACHINE
WSMan                       WSMan

gibi bir sonuç elde ederiz. Bu da demektir ki örneğin alias'lar hakkında bilgi için Get-Alias ve Get-Help'in dışında doğrudan

PS C:\> cd Alias:

komutunu kullanıp dir ile tüm alias listesini alabiliriz.

Kayıt defteri konusuna gelelim. HKLM\Software\Microsoft\CurrentVersion\Run altındaki değerleri sorgulayalım:

PS C:\> cd HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\run
PS C:\> dir

Burada bazı değerler olmasına rağmen içerik gözükmedi. dir (Get-ChildItem) sadece alt anahtarları listeler. Değerleri görmek için

PS C:\> Get-ItemProperty .
Apoint      : C:\Program Files\DellTPad\Apoint.exe
PSPath      : Microsoft.PShell.Core\Registry::HKEY_LOCAL_MACHINE\...
PSParentPath: Microsoft.PShell.Core\Registry::HKEY_LOCAL_MACHINE\...
PSChildName : run
PSDrive     : HKLM
PSProvider  : Microsoft.PowerShell.Core\Registry

kullanabiliriz (ekrana sığsın diye kısalttım). Burada Run anahtarı altında yer alan değer Apoint'ti.

Yeni Registry değeri yaratmak için

PS C:\> New-Item Adobe

ve bu alt anahtarın altında kayıt defteri değerleri yaratmak için ise

PS C:\> New-ItemProperty -Path . -Name "Disable" -Type DWord -Value 1

kullanabiliriz. Aynı şekilde alt anahtarları silmek için Remove-Item, değerleri silmek için ise Remove-ItemProperty kullanılmalı.

Ortam Değişkenleri

Ortam değişkenleri de bir sistemin işleyişinde önemli yere sahip. Önceki başlıkta Get-PSDrive ile gezinmeye uygun nesneleri listelerken Env de çıkmıştı. Yani ortam değişkenlerinden PATH'i görmek için

PS C:\> cd ENV:                                                   
PS C:\> dir Path                                                  
Name                        Value                                 
----                        -----                                 
Path                        C:\ProgramData\Oracle\Java\javapath...


kullanmak mümkün. Ayrıca

PS C:\> $ENV:Path

de aynı işi yapar. Daha okunaklı bir liste için

PS C:\> ($Env:Path).Split(";")

yapabiliriz. Bu listeye örneğin C:\Scripts klasörünü eklemek istersek yapmamız gereken

$Env:Path += ";C:\Scripts"

Veya bunu tekrar silmek için

$Env:Path = $Env:Path.Replace(";C:\Script","")

yapabiliriz. Ama bu ortam değişkenini kalıcı olarak değiştirmez. Kalıcı yapmak için

[Environment]::SetEnvironmentVariable( "Path", $env:Path, [System.EnvironmentVariableTarget]::Machine )

şeklinde sistem genelinde değişiklik yapan yordam çağrılmalı.

Son olarak bazı durumlarda uyumsuz veri tiplerinin gizemini çözmek için kullanılabilecek cmdlet Get-Member'a örnek vereyim:

PS C:\> $Env:Path | Get-Member

Uzun bir liste verecek. İlk sırada yer alacak

TypeName: System.String

bizim için anahtar. Örnek bir kullanım için tüm alias'lar içinde hizmetlerin yönetimi için kaç alias yaratıldığını bulmak isteyelim.

PS C:\> dir Alias:

komutu ile  tüm alias'ları listeleyebiliriz. Ama acaba bunların kaçının içinde "service" geçiyor. Select-String (sls) cmdlet'iyle içinde service geçenleri bulmaya çalışalım:

PS C:\> dir Alias: | sls "service"

Hiçbir şey dönmedi. Neden? Çünkü adından da anlaşılacağı gibi Select-String cmdlet'i sadece string veri tipi üzerinde çalışır. Sebebi dir Alias: komutunun string veri tipi dönmemesi olabilir mi? Bakalım:

PS C:\> dir Alias: | Get-Member                                  
                                                                 
   TypeName: System.Management.Automation.AliasInfo              
                                                                 
Name                MemberType     Definition                    
----                ----------     ----------                    
Equals              Method         bool Equals(System.Object obj)
GetHashCode         Method         int GetHashCode()             
GetType             Method         type GetType()                


diye uzayan bir çıktı üretir. İlk satırda yazan

   TypeName: System.Management.Automation.AliasInfo              

bizim için önemli. Yani string veri tipi dönmemiş. Bir array döndüğü için array'in ilk elemanının tüm özelliklerini (property) yazalım:

PS C:\> (dir Alias:)[0] | fl *         
                                       
DisplayName       : % -> ForEach-Object
CommandType       : Alias              
Definition        : ForEach-Object     
ReferencedCommand : ForEach-Object     
ResolvedCommand   : ForEach-Object     


Burada çok şaşırtıcı olmayan "DisplayName" adında bir alan var. Bu alanın tipini kontrol edelim:

PS C:\> (dir Alias:)[0].DisplayName | Get-Member 
                                                 
   TypeName: System.String                       

String'i bulduk. Demek ki Select-String'in girişi bu alan olmalı.

PS C:\> (dir Alias:).DisplayName | sls "service"
                                                
gsv -> Get-Service                              
sasv -> Start-Service                           
spsv -> Stop-Service                            


Sonuçta 3 alias olduğunu gördük. İlla ki powershell saysın dersek:

PS C:\> (dir Alias:).DisplayName | sls "service" | Measure
                                                          
Count    : 3                                              
Average  :                                                
Sum      :                                                
Maximum  :                                                
Minimum  :                                                
Property :                                                

Powershell'e giriş

Windows'da komut satırının yeteneklerinin günümüz beklentilerinin altında kalmasına çözüm olarak ortaya çıkan Powershell faydalı ve kullanışlı bir framework haline geldi. .Net altyapısı üzerine inşa edilen sistem her yeni sürümde daha faydalı işlevler sunuyor

Powershell komutlarına cmdlet deniyor. Bir fiil ve ismin tire işareti ile birleşiminden oluşuyorlar. Örneğin çalışan süreçlerin listesini almak için kullanılacak komut (cmdlet):

Get-Process
Ama her seferinde bu kadar uzun komutlar girmemek için kısaltma amaçlı "alias"lar eklenmiş. Her seferinde Get-Process yazmak elbette mümkün, ama kısaltmak isterseniz

gps
veya
ps
de aynı işi yapıyor. Bu alias elbette linuxtaki eşdeğeri ps komutundan geliyor. Ama linux eşdeğerinden farklı olarak tamamen nesne yönelimli (object oriented). Tüm çalışan süreçlerin listesini değil de sadece svc ile başlayan süreçlerin listesini görmek istersek yapılacak
ps svc*
yazmak. Bunun sonucunda aşağıdaki gibi bir çıktı üretecek:

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
    844      30    19016      21172    90             232 svchost
   1005      37   112316     114080   190             396 svchost
   2163      71    72416      72612   349             412 svchost
    652      34    12444      20520   145             452 svchost
    527      19     8504      14744    82             756 svchost
    547      18     6752      10376    71             796 svchost
   1250     183    24952      28980  1309            1240 svchost
    325      19     3396       8688    54            1508 svchost
    489      38    27524      28188   116            1532 svchost
    108      10     3316       3040    42            1844 svchost
     55       6      712       1224    21            2036 svchost
    369      17     5584      10000    91            2044 svchost
     53       6      712       1280    21            2088 svchost
    100       8     1312       2224    24            2136 svchost
    165      14     4176       5092    48            2568 svchost
    145      11     2148       5920    43            5968 svchost


Buradaki sütünların açıklamaları [1] ve [2] de var.
Örneğin handle sayısı 1000'den fazla olan ve svc ile başlayan süreçleri listelemek için

ps svc* | ? {$_.Handles -gt 1000}

yazmak yeterli. Bu komutun kısaltılmış hali. Uzun uzun alias kullanmadan yazmak istersek komut şöyle olurdu:
Get-Process -Process svc* | Where-Object {$_.Handles -gt 1000}
Soru işareti (?) Where-Object cmdlet'inin bir alias'ı. Get-Process cmdlet'inin varsayılan parametresi de Process olduğu için ayrıca -Process yazmaya gerek yok. Önemli olan kısmı boru karakterinden (|) sonrası. Komut satırında olduğu gibi burada da boru karakteri bir komutun çıktısını diğer komuta giriş olarak veriyor. svc ile başlayan süreçlerlerin listesini al, Where-Object komuduna ver. O da bunları bir döngüye soksun (küme parantezleri sanal bir for döngüsü gibi), sadece Handles değeri 1000'den büyük olanları çıkış olarak üretsin. Burada $_ sanal for döngüsündeki döngü değişkeninin yerine geçiyor. Döngünün her adımında nesnenin Handles özelliğini alıp -gt ile "büyüktür" (greater than) işlemine tabi tutuyor. Sonucunda da şu çıkıyor:

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
   1008      38   114932     113968   193             396 svchost
   2226      71    75344      73328   347             412 svchost
   1245     182    24888      28940  1308            1240 svchost


Tam da istenen bu. Powershell bunun için güzel :)

Hatta bunları da Working Set değerine göre azalan şekilde sıralamak istersek yazılması gereken bir boru karakteri daha var:
ps svc* | ? {$_.Handles -gt 1000} | sort WS -Desc
Bu komutu da uzun uzadıya yazmak istersek
Get-Process -ProcessName svc* | Where-Object {$_.Handles -gt 1000} | Sort-Object -Property WS -Descending
olurdu. Tabloyu çok karmaşık bulursanız, sadece Handles ve Working Set değerlerni süreç isim ve ID'leriyle görmek isterseniz bu alanlardan sadece bazılarını select ile seçmeniz gerekir:
ps svc* | ? {$_.Handles -gt 1000} | sort WS -Desc | select Id, ProcessName, WS, Handles

Bu noktadan sonra uzunlarını yazmaya gerek yok bence.

Hala eklenebilecek şeyler var. Working Set sütununun sayısal biçimlendirmesini beğenmeyenler binlik ayraç kullanmak isteyebilir. Bu durumda
ps svc* | ? {$_.Handles -gt 1000} | sort WS -Desc | select Id, ProcessName, @{N="WorkingSet";E={"{0,13:N0}" -f $_.WS}}, Handles

yazılabilir. Sonuç şu şekilde olur:

 Id  ProcessName       WorkingSet                          Handles
 --  -----------       ----------                          -------
 396 svchost           114.790.400                           1005
 412 svchost            72.474.624                           2173
1240 svchost            29.532.160                           1245


Çıkışı buraya sığdırmak için boşlukları sildiğimi itiraf etmeliyim. Ama bunu gerek kalmadan sonuç üretmek için de Format-Table * -Autosize ekleyebilirdim. Yani:
ps svc* | ? {$_.Handles -gt 1000} | sort WS -Desc | select Id, ProcessName, @{N="WorkingSet";E={"{0,13:N0}" -f $_.WS}}, Handles | ft -AutoSize
Sonuç şöyle olurdu:

  Id ProcessName WorkingSet    Handles
  -- ----------- ----------    -------
 396 svchost       114.221.056    1005
 412 svchost        72.462.336    2173
1240 svchost        29.532.160    1247


Temiz ve güzel.

9.10.2017

Fedora'da dnf kullanımı

Fedora'da yum'ın yerini alan dnf gayet pratik. Ama özetlemek için birkaç önemli noktayı yazmak istedim, biraz da apt ile kıyaslayarak (// işaretinden sonrası Ubuntu için).

Repository'leri güncellemek
# dnf check-update  // apt update
Kurulu bütün paketleri güncellemek
# dnf update // apt upgrade
Tek bir paketi güncelleme
# dnf update firefox // apt upgrade firefox
Veya daha da öncesinde paket kurmak
# dnf install firefox // apt install firefox
Paketi kaldırmak
# dnf remove firefox // apt remove firefox
Bazen log dosyaları vs ile birlikte programın tüm artıklarından kurtulmak gerekir. Bu işin dnf'te karşılığı yok.
 # --------- // apt purge firefox (veya apt remove --purge firefox)
Kurulu paketi tekrar kurmak
# dnf reinstall firefox  //  apt reinstall firefox
Başka bir programın bağımlılığı olarak kurulmuş ama şu anda ihtiyaç duyulmayan paketleri kaldırmak için
# dnf autoremove // apt autoremove
Güncellenebilir (veya kurulu) olan paketlerin listesini almak için
# dnf list --upgrades (--installed) // apt list --upgradable (--installed)
Bir paket aramak
# dnf search (all) firefox // apt-cache search firefox
Bir paket hakkında ayrıntılı bilgi almak
# dnf info firefox // apt show firefox
Kurulu ve depolardaki sürüm hakkında bilgi almak
# dnf info firefox // apt-cache policy firefox
Geçici (cache) bilgileri temizlemek için
# dnf clean all  // apt clean
Bir dosyayı hangi paket kurdu
# dnf provides <dosya_adi> //  dpkg -S <dosya_adi> (veya apt-file search <dosya_adi>)
Veya bir paket kurulunce sisteme hangi dosyalar eklendi
# rpm -ql firefox (veya paket için rpm -qlp firefox-58.0.2-1.fc27.x86-64.rpm) //  dpkg-query -L firefox (paket için dpkg-deb -c firefox.deb, veya apt-file list firefox)
İnternet bağlantısı olmayan bir sisteme bir paketi kurabilmek için internet bağlantısı olan bir Fedora makinede gerekli indirmeleri yapıp, bunları daha sonra bağlantısı olmayan bilgisayara kurmak için download komutu kullanılabilir.
# dnf download NetworkManager
Açıkça belirtilmezse indirme konumu /var/cache/dnf olur (nasıl açıkça belirtilir, az sonra!) Ama hedef paketin bağımlılıkları varsa bunları tek tek indirmeye çalışmak zaman alıcı olabilir. Bunun için --resolve anahtarın kullanmak gerek.
# dnf download NetworkManager --resolve
Hatta bu indirilen tüm paketleri belli bir klasörde toplamak için --downloaddir anahtarı kullanılabilir.
# dnf download NetworkManager --resolve --downloaddir=/home/user/Downloads/NM
Komut geçmişini incelemek
# dnf history // # less /var/log/apt/history.log [bkz. 2]

En son dnf işlemini görmek için

# dnf history 0

en sondan bir önceki için

# dnf history -1

veya listedeki herhangi bir işlemin ID'sini kullanarak

# dnf history 13

kullanabiliriz. En sol satırda yazan ID, belli bir tarihe ait benzersiz bir belirteçtir. Bu tarihte yapılan işlerin ayrıntısını görmek için (örneğin ID'si 49 olan tarih ile ilgili) şu yazılabilir:

# dnf history info 49

Firefox'un son dnf upgrade ile yükseltilip yükseltilmediğini öğrenmek için şu komudu kullanabiliriz:

# dnf history info 0 | grep -i 'Firefox'

ID'lerde 0 en son güncelleştirmeyi, -1 ise ondan bir öncekini gösterir.

Yapılan işlemlerden herhangi birisini geri alabiliriz. Bu durumda geri alınan işleme ait kayıt history'den silinmez, ama geri alma (undo) işlemine ait yeni bir kayıt oluşturulur.

# dnf history undo 7

Bu sadece 7 numaralı dnf işleminde yapılanı geri alır. Bundan sonraki 8, 9 vs işlemlerini geri almaz. Geri almanın benzeri rollback işlemi var. Rollback'te ise belirtilen işleme kadar tüm işlemler geri alınır, sistem belirtilen işlem yapıldıktan sonraki haline geri döner. Yani

# dnf history rollback 7

dersek, 7 numaralı işlem yapıldıktan sonraki haline döneriz. 8, 9 ve diğerleri artık yapılmamış sayılır. 7'den sonraki işlemler history listesinden de silinir. Undo ve rollback işlemleri öncesinde clean komutunu kullanmamak gerek ki cache'teki dosyalarımızla işlem yapabilelim.

Repository listesini amak

# dnf repolist // # grep -Erh '^deb ' /etc/apt/sources.list*
Bunun yanı sıra bir de Fedora'ya özgü paket grupları var. Örneğin geliştiriciler için "Development and Creative Workstation" gibi. Bunların listesini almak için
# dnf grouplist
Bu grup paketlerinden birini kurmak için
# dnf groupinstall "Web Server"
Kaldırmak için ise
# dnf groupremove "Web Server"

kullanılabilir.

Fedora (Redhat) ailesinde dnf update sonrasında emin misiniz sorusunun cevabı varsayılan olarak "hayır (H)". Ubuntu'da varsayılan olarak evet.

2018-10-15 Ekleme: dnf history kullanırken farkettiğim birşey var. Yeni kurulmuş bir Fedora 28 işistasyonu için dnf history komutunu verince aldığım çıktı şöyle oluyor.


Wikipedia'da [3] ve Fedora Project Community Blog'da [4] görüldüğü gibi Fedora 28'in çıkış tarihi 01.05.2018. Yani history'nin 1 numaralı girişi için gözüken tarih 2018-04-25 aslında Fedora 28'in resmi çıkış tarihinden önce bir tarih. Sistemi kurduktan sonraki ilk açılışta dnf upgrade ile güncellediğim için 2 numaralı satırda gözüken tarih doğru olarak sistemin ilk güncellemesine ait giriş.

2022-08-05 Ekleme: dnf'i hızlandırmak için şu videoda Ermanno, /etc/dnf/dnf.conf dosyasını açarak aşağıdaki satırları eklemiş:

max_parallel_downloads=10    # varsayılan 3
fastestmirror=True           # tartışmalı

fastestmirror söylendiğine göre sadece anlık olarak sunucuların cevap süresine bakarak bir tercihte bulunuyor. Reddit'te bir gönderide bu seçeneğin en hızlı bant genişliğine sahip sunucuyu seçmediğinden ve çoğu zaman daha yavaş bir indirmeye sebep olabileceğinden bahsedilmiş.


---

[1] https://www.digitalocean.com/community/tutorials/package-management-basics-apt-yum-dnf-pkg
[2] https://askubuntu.com/questions/21657/how-do-i-show-apt-get-package-management-history-via-command-line
[3] https://en.wikipedia.org/wiki/Fedora_version_history
[4] https://communityblog.fedoraproject.org/fedora-28-release-dates-schedule/