Özet
Bu rapor, TryHackMe'nin Basic Pentesting odasında kay
kullanıcısının SSH private key'ini kırma ve kullanma sürecinde karşılaştığım,
saatler süren bir takılmanın kök nedenini ve çözümünü belgeliyor. Sorun CTF'in
kendisiyle değil, güncel Kali Linux'ta gelen OpenSSL 3.0.13'ün
eski tip şifreli PEM key'leri okuyamamasıyla ilgili, iyi bilinen bir uyumluluk
sorunuydu.
Key'in Kırılması ve Sorunun Tespiti
Key'in passphrase'inin kırılması:
ssh2john kay_id_rsa > forjohn.txt
john forjohn.txt --wordlist=/usr/share/wordlists/rockyou.txt
john --show forjohn.txt
Sonuç: passphrase doğru şekilde bulundu ve topluluktaki diğer write-up'larla birebir örtüşüyordu.
Not: Bu aşamada bir kullanım hatası da yapmıştım — john
yanlışlıkla forjohn.txt yerine ham kay_id_rsa dosyasına
karşı çalıştırılmış, bu da alakasız bir hash formatının yanlışlıkla algılanmasına
ve boşa zaman harcanmasına yol açmıştı. Doğru komut her zaman ssh2john'un
ürettiği hash dosyası üzerinde çalıştırılmalı.
Asıl sorun: Doğru passphrase bulunmasına rağmen hem
ssh -i kay_id_rsa kay@<target>
hem de
openssl rsa -in kay_id_rsa -out kay_id_rsa_new
ssh-keygen -p -f kay_id_rsa_new -N "" -m PEM
komutları şu hatayı veriyordu:
error in libcrypto: unsupported
Could not find private key from kay_id_rsa
...DECODER routines:OSSL_DECODER_from_bio:unsupported...
Input structure: EncryptedPrivateKeyInfo
Kök Nedenin Teşhisi
Key'in Proc-Type: 4,ENCRYPTED / DEK-Info: AES-128-CBC
başlıklı "traditional" (PKCS#1) şifreli PEM formatında olduğunu belirledim. Bu format:
- MD5 tabanlı, tek turlu bir anahtar türetme algoritması (
EVP_BytesToKey) kullanır, - OpenSSL'in eski (pre-3.0) API'sine göre tasarlanmıştır,
- OpenSSL 3.0'ın yeni provider / STORE / DECODER mimarisiyle bazı build'lerde düzgün işlenemiyor.
-provider legacy -provider default eklemek de sorunu çözmedi, çünkü
asıl problem eksik bir şifreleme algoritması değil, decoder'ın bu PEM yapısını
hiç tanıyamamasıydı (No supported data to decode).
Manuel Çözüm
openssl'in yüksek seviyeli komutlarını (openssl rsa,
openssl pkey, ssh-keygen) tamamen atlayıp, düşük
seviyeli openssl enc ile ham AES-128-CBC şifre çözme işlemini elle
yaptım:
DEK-Infosatırından IV'yi çıkardım.- Salt = IV'nin ilk 8 baytı.
- Anahtarı klasik
EVP_BytesToKeyalgoritmasıyla (MD5(passphrase + salt)) Python ile elle türettim. openssl enc -d -aes-128-cbc -K <key> -iv <iv> -nopadile ham DER verisini elde ettim.- PKCS#7 padding'i kaldırıp, veriyi base64'e çevirip düz (şifresiz) bir PEM dosyası olarak yeniden sardım.
openssl rsa -in ... -check -noout→RSA key ok— doğrulandı.- Bu şifresiz key ile
ssh -isorunsuz çalıştı.
Neden Bu Sorun Oluşuyor?
Klasik ("traditional") şifreli PEM formatı şuna benzer:
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,<16-byte-IV-hex>
<base64 ciphertext>
-----END RSA PRIVATE KEY-----
Bu format PKCS#8 değildir; şifreleme PEM header seviyesinde tanımlanır ve
anahtar türetimi için tek turlu MD5 kullanılır. OpenSSL 3.0 ile gelen yeni
mimaride key okuma işlemleri artık eski PEM_read_bio_PrivateKey
yerine OSSL_DECODER_from_bio / OSSL_STORE
API'lerinden geçiyor ve MD5 tabanlı eski KDF algoritması bazı yapılandırmalarda
legacy provider'a taşınmış durumda (FIPS uyumluluğu için — MD5 FIPS'te devre
dışı). Bazı OpenSSL 3.0.x/3.1.x sürümlerinde decoder'a selection
parametresi doğru geçirilmediğinde key ya hiç tanınmıyor ya da bozuk veri
üretiliyor — bu, OpenSSL'in kendi geliştiricileri tarafından da resmi olarak
kabul edilip yamanmış bir bug.
Doğrulama
Sorunun gerçekliğini kanıtlamak için aynı key üzerinde şu denemeleri sırayla yaptım ve hepsi başarısız oldu:
openssl rsa -in key.pem -passin pass:beeswax -out out.pem
openssl pkey -in key.pem -passin pass:beeswax -out out.pem
openssl rsa -provider legacy -provider default -in key.pem -passin pass:beeswax -out out.pem
openssl rsa -inform PEM -in key.pem -passin pass:beeswax -out out.pem -traditional
Buna karşılık, düşük seviye openssl enc ile manuel AES-CBC çözme +
elle yeniden PEM sarma işlemi sorunsuz çalıştı ve openssl rsa -check -noout
çıktısı RSA key ok oldu. Bu, sorunun key'in kendisinde değil, OpenSSL'in
yüksek seviye decoder katmanında olduğunu doğruladı.
Sonuç ve Öneriler
CTF cevapları doğruydu ve değişmemişti; sorun makinede veya odada değil, saldırgan makinesindeki (Kali) güncel OpenSSL sürümündeydi. Bu, 2023-2024 sonrası güncellenen Kali/Debian sistemlerinde giderek daha sık karşılaşılan bir sorun çünkü eski CTF makineleri hâlâ 2016-2018 döneminin OpenSSH/OpenSSL varsayılanlarıyla key üretiyor.
Gelecekte hızlı çözüm için: openssl rsa/ssh-keygen
"unsupported"/"Could not read private key" hatası verirse önce
-provider legacy -provider default -passin pass:... dene; işe
yaramazsa doğrudan manuel openssl enc + Python KDF yöntemine geç —
bu yöntem OpenSSL sürümünden bağımsız her zaman çalışır çünkü yüksek seviye
decoder katmanını tamamen by-pass eder.
Tam Script
# 1) IV'yi key dosyasından çek (DEK-Info satırındaki hex kısmı)
IV=$(grep DEK-Info kay_id_rsa | cut -d',' -f2)
# 2) Şifreli veriyi (base64 body) çıkar ve decode et
tail -n +4 kay_id_rsa | head -n -1 | base64 -d > payload.bin
# 3) AES key'i türet (passphrase, salt=IV'nin ilk 8 baytı)
KEY=$(python3 -c "
import hashlib, binascii
iv = binascii.unhexlify('$IV')
salt = iv[:8]
d = d_i = b''
while len(d) < 16:
d_i = hashlib.md5(d_i + b'beeswax' + salt).digest()
d += d_i
print(d[:16].hex())
")
# 4) Ham AES-CBC deşifreleme (bozuk yüksek-seviye decoder'ı atlıyoruz)
openssl enc -d -aes-128-cbc -in payload.bin -out decrypted.der -K $KEY -iv $IV -nopad
# 5) PKCS7 padding'i kaldır ve yeniden PEM'e sar
python3 -c "
import base64
data = open('decrypted.der','rb').read()
der = data[:-data[-1]]
pem = '-----BEGIN RSA PRIVATE KEY-----\n' + base64.encodebytes(der).decode() + '-----END RSA PRIVATE KEY-----\n'
open('kay_id_rsa_final','w').write(pem)
"
chmod 600 kay_id_rsa_final
# 6) Doğrula
openssl rsa -in kay_id_rsa_final -check -noout
Resmi / Topluluk Kaynakları
- OpenSSL Resmi Dokümantasyonu — PEM_read_bio_PrivateKey — github.com/openssl/openssl
- GitHub Discussion — openssl/openssl #23044 — github.com/openssl/openssl/discussions/23044
- GitHub Issue — openssl/openssl #14566 — github.com/openssl/openssl/issues/14566
- GitHub PR — openssl/openssl #21519 (Decoder key export fixes) — github.com/openssl/openssl/pull/21519
- GitLab — libssh-mirror MR #30 — gitlab.com/libssh/libssh-mirror
- GitHub Issue — pyca/cryptography #8563 — github.com/pyca/cryptography/issues/8563