- SSH, uzaktan erişimin ötesinde port yönlendirme, jump host, yapılandırma dosyaları ve anahtar yönetimini birlikte ele alan bir araçtır; web sunucusu örneği RDP·SQL gibi diğer servislere de aynen uygulanabilir
- Yerel·uzak·dinamik port yönlendirme sırasıyla
-L, -R, -D ile yapılandırılır; temel fark, portun hangi tarafta açıldığı ve trafiğin nereye aktığıdır
- Doğrudan erişimin engellendiği ağlarda
-J jump host ve ProxyJump ile birden fazla SSH geçiş noktası birbirine bağlanarak hedefe ulaşılabilir
ssh-agent ve -A agent forwarding, uzak host üzerinde de yerel anahtarların kullanılmasını sağlayarak kolaylık sunar; ancak önce agent’ın kötüye kullanılmasından doğan güvenlik riskleri kontrol edilmelidir
~/.ssh/config, ssh-copy-id, ssh-keygen, SSH konsolu ~?·~C birlikte kullanıldığında tekrarlayan seçenekleri yazma ihtiyacı azalır; oturum sırasında yönlendirme eklemek, açık anahtar dağıtmak ve anahtar oluşturup denetlemek kolaylaşır
SSH port yönlendirmesini anlamak için ön kabuller
- SSH port yönlendirmede akışı yalnızca diyagramlarla kavramak zor olduğundan, gerçek komutları ve ağ senaryolarını birlikte görmek anlamayı kolaylaştırır
- Örnekler web sunucusuna erişim üzerinden verilmiştir, ancak aynı yöntem RDP, SQL vb. neredeyse tüm servislere uygulanabilir
- Tekrar tekrar kullanılan seçeneklerin anlamı şöyledir
-N: Uzak sunucuda komut çalıştırmaz ve shell de açmaz
-f: SSH’yi arka plana gönderir
root@host: Tüneli oluşturacak kullanıcı ve host ile oturum açar
Yerel port yönlendirme -L
- Yerel port yönlendirme, yerel makinenin portunu uzak sunucunun portuna aktarır
- Örnek durum
internal-web.int, yalnızca loopback arayüzünden erişilebilen bir web sayfası barındırır
campfire.int üzerinden internal-web.int’e SSH erişimi mümkündür
campfire.int’in yerel portu üzerinden internal-web.int’in web sunucusuna erişilmek istenir
- Kullanılacak komut
ssh -N -f -L 1337:127.0.0.1:80 root@internal-web.int
- Seçeneklerin açıklaması
-L: Yerel yönlendirmeyi belirtir
1337:127.0.0.1:80: Yerel port 1337’yi uzaktaki 127.0.0.1:80 adresine bağlar
- Tünel oluşturulduktan sonra
campfire.int üzerinde yerel port 1337’ye istek göndererek internal-web.int’in port 80’iyle etkileşime geçilebilir
- Hatırlanması gereken nokta,
-L için yerel portun adresin sol tarafında yer aldığıdır
Uzak port yönlendirme -R
- Uzak port yönlendirme, yerelden erişilebilen bir portu uzak sunucunun portu olarak dışa açar
- Örnek durum
internal-web.int, yalnızca loopback üzerinden erişilebilen bir web sayfası barındırır
campfire.int, güvenlik duvarı nedeniyle internal-web.int’e doğrudan erişemez
vuln-server.int, hem campfire.int hem de internal-web.int tarafından erişilebilir durumdadır
- Kullanılacak komut
ssh -N -f -R 3000:127.0.0.1:80 root@vuln-server.int
- Seçeneklerin açıklaması
-R: Uzak yönlendirmeyi belirtir
3000:127.0.0.1:80: vuln-server.int üzerindeki port 3000’i yereldeki 127.0.0.1:80 adresine bağlar
- Daha sonra
vuln-server.int:3000 adresine curl isteği gönderildiğinde, internal-web.int üzerinde port 80’de çalışan dahili web sayfasına erişilebilir
- Hatırlanması gereken nokta,
-R için yerel portun adresin sağ tarafında yer aldığıdır
Dinamik port yönlendirme -D ve SOCKS proxy
- Dinamik port yönlendirme,
-D seçeneğiyle bir SOCKS proxy oluşturur ve trafiği SSH geçiş noktası üzerinden gönderir
- Örnek durum
internal-web.int, yalnızca dahili ağdan erişilebilen bir web uygulaması barındırır
vuln-server.int, aynı dahili ağdadır ve internal-web.int’e erişebilir
campfire.int üzerinden trafiğin vuln-server.int aracılığıyla proxy’lenmesi istenir
/etc/proxychains.conf ayarı, SSH komutundaki portla eşleşmelidir
socks5: proxychains’in SOCKS5 kullanmasını sağlar
127.0.0.1: localhost’u kullanır
8080: SSH -D için belirtilen portla aynı olmalıdır
- Kullanılacak komut
ssh -N -f -D 8080 root@vuln-server.int
- Yönlendirme oluşturulduktan sonra
socks5 127.0.0.1 8080 ayarlanırsa proxychains curl 192.168.1.185 ile dahili web sayfasına erişilebilir
- SOCKS üzerinden DNS, ortama bağlı olarak düzgün çalışmayabileceği için örnekte host adı yerine IP adresi kullanılmıştır
- Firefox’ta da manuel proxy ayarıyla SOCKS proxy kullanılabilir
- Yol: Settings → Privacy & Security → Network Settings
- Manual proxy configuration seçilir
- “Proxy DNS when using SOCKS V5” işaretlenir
- SOCKS host
127.0.0.1, port 8080 olarak ayarlanır
Jump host -J
- Jump host, mevcut host’tan doğrudan erişilemeyen bir hedefe birden fazla SSH geçiş noktası üzerinden bağlanmayı sağlar
- Örnek zincir
campfire.int → vuln-server.int → internal-web.int → dns.int şeklindedir
- Kullanılacak komut
ssh -J root@vuln-server.int,root@internal-web.int root@dns.int
- Birden fazla jump hedefi virgül ile ayrılır
Agent forwarding -A
ssh-agent, yerel makinede ssh-add <private_key_file> ile özel anahtar veya ID eklenmesini sağlar
- Eklenen anahtarlar
ssh-add -l ile kontrol edilebilir
ssh-agent’a anahtar eklendiğinde, parolayı tekrar girmeden ilgili anahtarla SSH bağlantısı kurulabilir; bu hem kişiler hem de servis hesapları için kullanışlıdır
-A agent forwarding, bağlanılan uzak makinede de yerel agent’taki anahtarların kullanılmasını sağlar
- Kullanmadan önce güvenlik risklerini kontrol etmek için Zero Effort Private Key Compromise: Abusing SSH-Agent for Lateral Movement incelenmelidir
- Örnek komut
ssh -A -J root@vuln-server.int root@internal-web.int
- Bu komut,
vuln-server.int üzerinden internal-web.int’e bağlanırken yerel campfire.int üzerindeki SSH agent’ta bulunan anahtarların kullanılmasını sağlar
- Ardından
internal-web.int üzerinde ssh root@dns.int çalıştırıldığında özel anahtar belirtmeden veya kimlik bilgisi girmeden bağlantı kurulabilir
TTY komut atama -t
-t seçeneği, uzak sunucuda etkileşim gerektiren komutları hızlıca çalıştırmak için kullanışlıdır
- Örnekler,
Vim veya top gibi TTY gerektiren komutlardır
- Kullanılacak komut
ssh root@internal-web.int -t top
- Çalıştırıldığında uzak sunucuda
top komutunu içeren bir TTY alınır
Harici host’ların da yerel yönlendirme portuna bağlanmasını sağlayan -g
-g seçeneği, uzak host’ların yerel olarak yönlendirilmiş porta bağlanabilmesini sağlar
- Yerel port yönlendirme
-L ile benzerdir; farkı, harici makinelerin de söz konusu “yerel” portu kullanabilmesidir
- Örnek durum
vuln-server.int üzerinde shell erişimi vardır
vuln-server.int’in port 2222’sine gelen bağlantılar internal-web.int’in port 22’sine proxy’lenmek istenir
- Kullanılacak komut
ssh -N -f -g -L 2222:localhost:22 root@internal-web.int
- Seçeneklerin açıklaması
-g: Uzak host’ların yerel yönlendirme portuna bağlanmasına izin verir
-L: Yerel yönlendirmeyi belirtir
vuln-server.int üzerindeki port 2222’ye SSH ile bağlanılmış olsa bile gerçek shell internal-web.int üzerinde olur
SSH konsolu ~? ve oturum sırasında yönlendirme
- SSH konsolu, uzak sistemle doğrudan etkileşime girmeden SSH’nin kendisini kontrol etmeyi sağlayan gizli bir özelliktir
- Shell bozulduğunda veya SSH oturumunun kendisini kontrol etmek gerektiğinde kullanışlıdır
- Yardım konsolu
~? ile açılabilir
- Kullanışlı seçenekler
~.: Mevcut SSH oturumunu sonlandırır
~C: SSH konsolunu açarak yönlendirme seçenekleri eklenmesini sağlar
- Zaten normal bir
ssh komutuyla vuln-server.int’e bağlıyken de ~C tuşlanıp -D 8080 girilirse, bu oturum dinamik yönlendirme oturumu gibi kullanılabilir
campfire.int üzerinde /etc/proxychains.conf port 8080’i kullanacak şekilde ayarlıysa, baştan ssh -D ile başlatılmış gibi proxychains’ten yararlanılabilir
SSH yapılandırma dosyası ~/.ssh/config
- SSH yapılandırma dosyası
~/.ssh/config konumundadır ve tekrar tekrar girilen SSH seçeneklerini kaydederek zaman kazandırır
- SSH bağlantısı sırasında bu dosya ayrıştırılır; bağlantı hedefine uygun bir
host ayarı varsa ilgili seçenekler kullanılır
- Komut satırı argümanları yapılandırma dosyasından önceliklidir
- Örneğin yapılandırma dosyasında
internal-web.int kullanıcısı root olarak belirtilmiş olsa bile ssh graham@internal-web.int çalıştırılırsa graham olarak oturum açılmaya çalışılır
- Temel yapılandırma örneği
# You can put comments with a `#` at the beginning of the line only.
host internal-web.int
User root
IdentityFile /home/smores/ssh_agent/internal-web-no-pw
Port 2222
ssh internal-web.int çalıştırıldığında işlem akışı
- Komut satırındaki
internal-web.int ile ~/.ssh/config içindeki host internal-web.int eşleştirilir
- Eşleşirse komut satırında belirtilmeyen seçenekler yapılandırma dosyasından alınır
- Eşleşmezse yalnızca komut satırında tanımlanan seçenekler kullanılır
Sık kullanılan SSH config anahtar sözcükleri
IdentityFile /path/to/private_key
- Host için kullanılacak özel anahtarı belirtir
ssh -i ile aynı görevi görür
ForwardAgent
ProxyJump root@internal-web.int
- Trafiğin proxy’leneceği sunucuyu belirtir
-J seçeneğiyle aynı görevi görür
- Örnekte önce
vuln-server.int kimlik doğrulaması istenerek trafiğin bu host üzerinden geçtiği gösterilir
Match
- Koşula göre SSH config anahtar sözcüklerini uygular
- Örnekte
export | grep PROXYME=TRUE komutunun çıkış kodu 0 ise Match bloğu altındaki ProxyJump kullanılır
PROXYME ortam değişkeni yoksa yalnızca normal host internal-web.int bloğu kullanılır
export PROXYME=TRUE ayarlandıktan sonra aynı ssh internal-web.int çalıştırılırsa önce vuln-server.int kimlik doğrulamasından geçilir, ardından internal-web.int shell’i alınır
scp ve bazı SSH tabanlı yardımcı araçlar da genellikle SSH config kullanabilir
- Otomatik kullanmadığı ortamlarda
-F ~/.ssh/config ile açıkça belirtilebilir
Açık anahtar kopyalama ssh-copy-id
ssh-copy-id, açık anahtarı sunucuya hızlıca yükleyen küçük bir yardımcı araçtır
- Kullanılacak komut
ssh-copy-id -i internal-web root@internal-web.int
- Seçeneklerin açıklaması
-i internal-web: Sunucu kimlik doğrulamasında kullanılacak özel anahtar adını belirtir
root@internal-web.int: Açık anahtarın yükleneceği sunucuyu belirtir
Anahtar oluşturma ve denetleme ssh-keygen
ssh-keygen, özel anahtar·açık anahtar çifti oluşturan bir yardımcı araçtır
-b seçeneğiyle daha büyük anahtar boyutu belirtmek genellikle önerilir
- Örnek ortamda varsayılan anahtar boyutu
3072 idi
- Varsayılan algoritma RSA’dır, ancak
-t bayrağıyla farklı bir algoritma belirtilebilir
- Örnek:
ssh-keygen -t ecdsa -b 521
- Anahtarın parmak izi ve bayt boyutu şu komutla kontrol edilebilir
ssh-keygen -lf <file-name>
1 yorum
Hacker News yorumları
Burada şaşırtıcı derecede basit bir yönerge eksik:
sshd_configiçindeAuthorizedKeysCommand /usr/bin/php /etc/ssh/auth.php %ugibi ayarlayıp, betikte GitHub’dakihttps://github.com/{$user}.keysadresini almak yeterliElbette production kalitesinde kod değil, ama ana fikri gösteriyor
GitHub organizasyonu/grubu üyeliğini kontrol ettikten sonra kullanıcı mevcutsa ve
nss-atogibi bir şeyle eşlenmişse sunucuya girişe izin verebilirsinizİnsanları onboard/offboard ederken yalnızca GitHub grubuna ekleyip/çıkarmakla makine erişimini vermek veya geri almak mümkün olduğundan zahmeti azaltır
Amazon Linux 2 ve öncesinde,
authorized_keysdosyasındaki tek tek anahtar biçimlerini kontrol etmek içinopensslkomut satırını çağırıyor; RSA’ya hardcode edildiği için OpenSSH sürümüed25519desteklese bile Amazon Linux 2 host’larındaed25519ile kimlik doğrulaması yapılamıyorduTeoride hoş bir özelliği¹ mümkün kıldığı için güzel, ama pratikte o özelliği kullanmayanların bile temel işlevini bozarak Amazon Linux’a daha az güven duymama neden oluyor
Bu sorunla ilk karşılaştığımda, cloud-first bir DevOps meslektaşımın sahip olduğu bir makineye SSH ile bağlanmaya çalışıyordum; doğrudan müdahale edemediğim için teşhis etmesi zordu
O AWS’yi iyi biliyor ama Linux’u daha az biliyor, bu yüzden nereye bakacağını bilmiyordu; bulut platformu sahibinin yaptığı dağıtım olduğu için “daha uyumlu” olacağını düşünerek Amazon Linux’u seçmişti, ama burada “daha uyumlu” aslında “daha çok aptalca surprise” anlamına geliyordu
¹ https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/connect-...
“Ağ düzgün çalışmıyor” iş kapsamım olduğu için böyle harika özellikleri kaçırıyorum
OpenSSH yapılandırma ayrıştırıcısının yinelenen yönergeleri yok saydığını ve aynı yönergelerden yalnızca ilk olanın etkili olduğunu pek çok kişi bilmiyor olabilir
Genelde yapılandırma ayrıştırıcılarında veya kural motorlarında daha sonra gelen yönerge öncekinin üzerine yazar; bu yüzden oldukça sezgiye aykırı
Önemsiz görünebilir, ama
/etc/ssh/sshd_configgibi varsayılanları değiştirirken insanlar ve yazılımlar değişiklikleri dosyanın ya da yönerge bloğunun sonuna ekleme eğilimindedir ve bunun uygulanmasını beklerGüvenlik şirketleri ve kuruluşlar, çeşitli SSH bastion ürünleri de bunda hata yapıyor; CIS Benchmarks önerileri ve üçüncü taraf CIS denetim araçlarının çoğu da önceliği dikkate almıyor ya da yanlış ele alıyor
OpenSSH yapılandırma yönergelerinin beklendiği gibi tanımlanıp tanımlanmadığını kontrol etmek için yapılandırma dosyasını doğrudan taramak yerine
sshd -Tveyassh -Gile türetilmiş iç yapılandırmayı dump etmelisinizsudoersdosyası da aynı şekilde çalışırKullanıcı kimlik doğrulama/yetkilendirme yazılımında bu yaklaşımın tercih edilir olduğunu düşünüyorum
Çünkü
whatever.conf.ddizinine yeni bir dosya eklenerek override edilemeyen ayarlar oluşturmayı kolaylaştırırAna yapılandırma dosyasında
whatever.conf.d/*yüklenmeden önce ilgili ayarı tanımlayıp o dosyaya özel koruma uygulamak yeterlidirBirinin kontrolü aşmaya çalıştığı bir durum olmasa bile, tüm bağlamı bilmeyen yeni biri yeni bir dosya eklediğinde ya da bir paket kendi servisi için garip varsayılanlar kurduğunda temel ayarın önceliğini koruması açısından yapılandırma yönetimi için avantajlıdır
Başka bağlamlarda ters davranışı daha sık görmemizin nedeni, istenenin “temel ayar” değil, kullanıcı/geliştirici/yönetici açıkça ayarlamadığında kullanılan katı anlamdaki varsayılan değer olmasıdır
AllowUsersböyleAncak daha dün NixOS aniden birleştirme sırasını değiştirince benim dosyamdaki
AllowUsersbaşka bir dosyadakiMatchbloğunun altına inip kilitlenmiştiYazıdaki en önemli ve özlü cümle,
-Liçin yerel yönlendirmede local’in adresin solunda,-Riçin uzak yönlendirmede yerel portun adresin sağında olduğunu hatırlatan açıklamaEn başından beri
-Lile-Rkafamı karıştırıyordu; hangi port örneğinin yerel olduğu L/R’ye göre değişmesi epey can sıkıcı-Lve-R’nin niyet yönünü, yani başlatan ve yanıtlayanın nerede olduğunu değiştirdiğini anlıyorum; amaport:address:porther zamanlocal:binding:remoteanlamına gelse ve-L/-Rhangi tarafın dinleyen, hangi tarafın gönderen olduğunu belirlese de fena olmazdı-L’nin hemen ardından gelen numaradaki yerel portta dinlediğini,-R’nin ise hemen ardından gelen numaradaki uzak portta dinlediğini hatırlamak en kolayıGeri kalan
host:port, nereye bağlanılacağını söyleyen sıradan biçimden ibaretSSH tüneli üzerinden port yönlendirme yaptığınız için, host’un dinleyen portun bulunduğu tarafın tünelin karşı ucundan erişildiği de doğal olarak buradan çıkar
SSH’de daha az bilinen ama kullanışlı bir özellik olarak bağlantı çoğullama vardır
Yeni bir TCP bağlantısı kurup kimlik doğrulama sürecinden yeniden geçmek yerine mevcut bağlantıyı yeniden kullanacak şekilde ayarlanabilir
Protokolün kendisinde kanal kavramı vardır; her veri çerçevesine farklı akışları ayırt eden metadata eklenir ve bu özellik de bunu kullanır
Sonraki oturumlarda tam kimlik doğrulamayı tekrar yapmamak büyük bir avantajdır
Uzak tarafta
tmuxvb. yoksa ve birden fazla terminal penceresiyle birden fazla panel kullanıyorsanız özellikle iyidir; kimlik doğrulamada parola ifadesi ya da HSM’e dokunma gibi birkaç saniye süren adımlar varsa etkisi daha da hissedilir“Bağlantıyı sürdürme” ayarı da vardır; böylece birkaç sunucu arasında gidip gelirken her seferinde kimlik doğrulamak gerekmez
Genel olarak bulunması iyi olan ama hayat değiştirecek düzeyde olmayan bir özellik olarak görüyorum
Bazı sunucularda bu özellik kapalıdır; varlığı açıkken değil, yokluğu kapalıyken daha çok hissedilir
Devamı: https://en.wikibooks.org/wiki/OpenSSH/Cookbook/Multiplexing
SSH, gidiş-dönüş sayısını azaltacak şekilde optimize edilmiş TLS’in aksine oldukça geveze bir protokoldür; bu çoğullama seçeneği neredeyse tek istisnadır
ProxyJumpbastion host üzerinden geçerken Ansible kullanımını çok daha rahat hale getirebilir~/.ssh/configiçinde çok sayıda host varsa wildcard destekleyenIncludeyönergesiyle dosyanın fazla dağınık hale gelmesini önleyebilirsinizÖrneğin
~/.ssh/configiçineInclude config.d/*.confkoyup,~/.ssh/config.d/work.confveyaclient1.confiçindehost,hostname,userayarlarını ayrı ayrı tutabilirsinizHostyönergesi de wildcard desteklerÖrneğin
host *_workekleyiphost1_workgibi tüm iş host’ları için ortak ayarları koyabilirsinizInclude’uHost/Matchyönergelerinin içine koyabilirsinizÖrneğin
~/.ssh/configiçineHost proj1.*.corpveInclude ~/.ssh/proj1.confkoyarsanız, proje bazlı eşleşmeleri üst tarafa yakın tutabilir ve gözden geçirirken çok sayıda ayrı dosyada arama yapma ihtiyacını azaltabilirsinizForwarding yaparken neredeyse hiç
-fkullanmamHangi forwarding’in hâlâ açık ve çalışır durumda olduğunu anlamayı zorlaştırıp kendi ayağına sıkmak haline gelebilir
-thoş bir numara ve bilmediğim bir özellikti~escape komutları listesinde gözden kaçması kolay önemli bir nokta, iç içe oturumlarda da escape’i iç içe kullanabilmenizdirHerhangi bir nedenle
-Jkullanmadığınızda işe yararListe kullanışlı şeylerle iyi örtüşüyor; ayrıca öğrendiğim birkaç şey daha oldu
-tharika. Benssh -t my-dev-vps 'tmux new-session -A -s main'şeklinde kullanıyorum; her çalıştırdığımda tmux oturumundaki önceki konumuma doğrudan dönüyorumSüreç listesini elle kurcalamak dışında, SSH’in forwarding durumunu makul bir şekilde dışa vermesi iyi olurdu
AF_UNIXdesteği ekleyen mevcut bir pull request var; bu girerse her türden ilginç forwarding mümkün hale gelecekÇünkü SSH bağlantısını rastgele bir yerel süreç üzerinden proxy’lemek kolaylaşacak ve bu süreç veriyi uzak uca iletme işini istediği gibi yönetebilecek
https://github.com/openssh/openssh-portable/pull/431
AF_UNIXkullanan-D, ama her şeyinAF_UNIXüzerinde çalışabilir hale gelmesi güzelYaklaşık 1 yıl öncesinden beri
curl,ALL_PROXYsözdizimisocks5://localhost/pathveyasocks5hüzerindenAF_UNIXSOCKS kullanabiliyor gibi görünüyorTor
AF_UNIXSOCKS proxy kullandığı için eklenmiş gibi duruyorAğ erişimini standart Unix izinleriyle ayarlayabilmek güzel olurdu; kişisel olarak TCP/IP’yi çekirdekten tamamen dışarı atabilmek daha da iyi olurdu
SSH konsolunu ilk gördüğümde şok olmuştum
Bir iş arkadaşım
~#göstermişti; SEGA Genesis oyunundan çıkacak türden gizli bir hile menüsü bulmuşum gibi hissetmiştimNeden tilde? Çünkü
rlogin,rshbunu kullanıyorduPeki
rlogin,rshneden tilde kullanıyordu? ÇünkücukullanıyorduNeden
cu? Bir modeminiz veya seri hattınız varsacuile haberleşirdiniz ve Hayes kodları göndermeniz gerekirdi; Hayes kodunun kaçış dizisini kullanırsanız modeme çıkmış olacağınız içincudan çıkmak üzere ayrı bir sinyale ihtiyaç vardıNeden
^[değil? Çünkü o telnet içindirBu yüzden telnet ile bir host’a bağlanıp ardından
cuile modeme bağlandıysanız, telnet’ten çıkmadancuya dönmek için ayrı bir kaçış sözdizimine ihtiyaç vardıSonuçta kaçış sözdizimlerinin sonsuza dek üst üste yığıldığı bir yapı
Ve aslında tilde değil, tilde’dir
CR, tilde,.olduğunu sanıyordum; bunca zamandır yanlış mı kullanıyordum?ssh-copy-idbölümü, komutun public key’i yüklediğini anlatırken birden private key’i yüklediğini söylemeye dönüyor; yazım hatası gibi görünüyorAyrıca bu komut yalnızca anahtarı yüklemekle kalmaz,
~/.ssh/authorized_keysdosyasına ekler; bu yüzden çok daha kullanışlıdırSon olarak
ssh-keygenbölümünde, bugünlerde okuduğum kaynaklara göreecdsayerineed25519tercih ediliyor