- SSH adalah alat yang mencakup lebih dari sekadar akses jarak jauh: port forwarding, jump host, file konfigurasi, hingga manajemen kunci, dan contoh server web di sini bisa langsung diterapkan juga ke layanan lain seperti RDP dan SQL
- Port forwarding lokal, jarak jauh, dan dinamis masing-masing menggunakan
-L, -R, dan -D, dengan perbedaan utama pada sisi mana port dibuka dan ke mana trafik mengalir
- Pada jaringan yang memblokir akses langsung, jump host
-J dan ProxyJump dapat merangkai beberapa perantara SSH untuk mencapai tujuan
ssh-agent dan agent forwarding -A memungkinkan penggunaan kunci lokal juga di host jarak jauh, tetapi risiko keamanan akibat penyalahgunaan agent harus dipahami terlebih dahulu
- Dengan memakai
~/.ssh/config, ssh-copy-id, ssh-keygen, serta konsol SSH ~? dan ~C bersama-sama, kita bisa mengurangi input opsi berulang, menambah forwarding saat sesi berjalan, mempermudah distribusi kunci publik, serta pembuatan dan pemeriksaan kunci
Prasyarat untuk memahami SSH port forwarding
- Alur SSH port forwarding sulit dipahami hanya dari diagram, sehingga lebih mudah dimengerti bila melihat perintah nyata beserta skenario jaringannya
- Contoh menggunakan akses ke server web, tetapi cara yang sama juga berlaku untuk hampir semua layanan seperti RDP, SQL, dan lainnya
- Opsi yang sering dipakai berulang memiliki arti berikut
-N: tidak menjalankan perintah di server jarak jauh dan juga tidak membuka shell
-f: menjalankan SSH di background
root@host: login ke pengguna dan host yang akan dipakai untuk membuat tunnel
Local port forwarding -L
- Local port forwarding meneruskan port pada mesin lokal ke port pada server jarak jauh
- Contoh situasi
internal-web.int meng-host halaman web yang hanya dapat diakses dari interface loopback
campfire.int dapat mengakses internal-web.int melalui SSH
- Ingin mengakses server web di
internal-web.int melalui port lokal milik campfire.int
- Perintah yang digunakan
ssh -N -f -L 1337:127.0.0.1:80 root@internal-web.int
- Penjelasan opsi
-L: menentukan local forwarding
1337:127.0.0.1:80: mengikat port lokal 1337 ke 127.0.0.1:80 di sisi jarak jauh
- Setelah tunnel dibuat, kita bisa mengirim permintaan ke port lokal
1337 dari campfire.int untuk berinteraksi dengan port 80 milik internal-web.int
- Hal yang perlu diingat adalah pada
-L, port lokal berada di sisi kiri alamat
Remote port forwarding -R
- Remote port forwarding mengekspos port yang dapat diakses dari lokal ke port pada server jarak jauh
- Contoh situasi
internal-web.int meng-host halaman web yang hanya bisa diakses melalui loopback
campfire.int tidak bisa langsung mengakses internal-web.int karena firewall
vuln-server.int dapat diakses dari campfire.int maupun internal-web.int
- Perintah yang digunakan
ssh -N -f -R 3000:127.0.0.1:80 root@vuln-server.int
- Penjelasan opsi
-R: menentukan remote forwarding
3000:127.0.0.1:80: mengikat port 3000 di vuln-server.int ke 127.0.0.1:80 di lokal
- Setelah itu, jika mengirim permintaan
curl ke vuln-server.int:3000, kita dapat mengakses halaman web internal yang berjalan di port 80 milik internal-web.int
- Hal yang perlu diingat adalah pada
-R, port lokal berada di sisi kanan alamat
Dynamic port forwarding -D dan proxy SOCKS
- Dynamic port forwarding membuat proxy SOCKS dengan opsi
-D dan mengirim trafik melalui perantara SSH
- Contoh situasi
internal-web.int meng-host aplikasi web yang hanya dapat diakses dari jaringan internal
vuln-server.int berada di jaringan internal yang sama dan dapat mengakses internal-web.int
- Ingin mem-proxy trafik dari
campfire.int melalui vuln-server.int
- Konfigurasi
/etc/proxychains.conf harus sesuai dengan port pada perintah SSH
socks5: membuat proxychains menggunakan SOCKS5
127.0.0.1: menggunakan localhost
8080: harus sama dengan port yang ditentukan pada SSH -D
- Perintah yang digunakan
ssh -N -f -D 8080 root@vuln-server.int
- Setelah forwarding dibuat, jika
socks5 127.0.0.1 8080 dikonfigurasi, kita bisa mengakses halaman web internal dengan proxychains curl 192.168.1.185
- DNS melalui SOCKS kadang tidak berjalan baik tergantung lingkungan, sehingga pada contoh digunakan alamat IP alih-alih nama host
- Di Firefox juga bisa memakai proxy SOCKS lewat konfigurasi proxy manual
- Jalur: Settings → Privacy & Security → Network Settings
- Pilih Manual proxy configuration
- Centang “Proxy DNS when using SOCKS V5”
- Atur SOCKS host ke
127.0.0.1 dan port ke 8080
Jump host -J
- Jump host memungkinkan koneksi ke tujuan yang tidak bisa diakses langsung dari host saat ini dengan melewati beberapa perantara SSH
- Rantai contoh adalah
campfire.int → vuln-server.int → internal-web.int → dns.int
- Perintah yang digunakan
ssh -J root@vuln-server.int,root@internal-web.int root@dns.int
- Beberapa target lompatan dipisahkan dengan koma
Agent forwarding -A
ssh-agent memungkinkan penambahan private key atau ID di mesin lokal dengan ssh-add <private_key_file>
- Kunci yang ditambahkan bisa dilihat dengan
ssh-add -l
- Dengan menambahkan kunci ke
ssh-agent, kita bisa melakukan koneksi SSH menggunakan kunci tersebut tanpa perlu memasukkan kata sandi lagi, sehingga berguna baik untuk manusia maupun akun layanan
- Agent forwarding
-A memungkinkan penggunaan kunci dari agent lokal juga di mesin jarak jauh yang kita masuki
- Untuk memeriksa risiko keamanannya sebelum digunakan, lihat Zero Effort Private Key Compromise: Abusing SSH-Agent for Lateral Movement
- Contoh perintah
ssh -A -J root@vuln-server.int root@internal-web.int
- Perintah ini terhubung ke
internal-web.int melalui vuln-server.int sambil memungkinkan penggunaan kunci yang ada di SSH agent lokal campfire.int
- Setelah itu, saat menjalankan
ssh root@dns.int dari internal-web.int, kita bisa terhubung tanpa menentukan private key atau memasukkan kredensial
Alokasi perintah TTY -t
- Opsi
-t berguna untuk cepat menjalankan perintah yang memerlukan interaksi di server jarak jauh
- Contohnya adalah perintah yang membutuhkan TTY seperti
Vim atau top
- Perintah yang digunakan
ssh root@internal-web.int -t top
- Saat dijalankan, kita akan mendapat TTY di server jarak jauh beserta perintah
top
Membuat host eksternal juga bisa terhubung ke port local forwarding dengan -g
- Opsi
-g memungkinkan host jarak jauh terhubung ke port yang di-forward secara lokal
- Mirip dengan local port forwarding
-L, tetapi bedanya mesin eksternal juga bisa memakai port “lokal” tersebut
- Contoh situasi
- Ada akses shell ke
vuln-server.int
- Ingin mem-proxy koneksi yang masuk ke port
2222 di vuln-server.int ke port 22 di internal-web.int
- Perintah yang digunakan
ssh -N -f -g -L 2222:localhost:22 root@internal-web.int
- Penjelasan opsi
-g: memungkinkan host jarak jauh terhubung ke port local forwarding
-L: menentukan local forwarding
- Meski terhubung via SSH ke port
2222 di vuln-server.int, shell yang sebenarnya akan berada di internal-web.int
Konsol SSH ~? dan forwarding di tengah sesi
- Konsol SSH adalah fitur tersembunyi yang memungkinkan kita mengontrol SSH itu sendiri tanpa berinteraksi langsung dengan sistem jarak jauh
- Fitur ini berguna saat shell rusak atau ketika kita perlu mengendalikan sesi SSH itu sendiri
- Konsol bantuan dapat dibuka dengan
~?
- Opsi yang berguna
~.: menutup sesi SSH saat ini
~C: membuka konsol SSH untuk menambahkan opsi forwarding
- Bahkan setelah sudah terhubung ke
vuln-server.int dengan perintah ssh biasa, kita bisa menekan ~C lalu memasukkan -D 8080 agar sesi tersebut dipakai seperti sesi dynamic forwarding
- Jika
/etc/proxychains.conf di campfire.int disetel memakai port 8080, maka proxychains bisa digunakan seolah-olah sesi dimulai sejak awal dengan ssh -D
File konfigurasi SSH ~/.ssh/config
- File konfigurasi SSH berada di
~/.ssh/config dan memungkinkan kita menyimpan opsi SSH yang sering diketik ulang untuk menghemat waktu
- Saat melakukan koneksi SSH, file ini diparse, dan bila ada pengaturan
host yang cocok dengan target koneksi, opsi tersebut akan digunakan
- Argumen command line memiliki prioritas lebih tinggi daripada file konfigurasi
- Misalnya, walaupun file konfigurasi menetapkan pengguna
root untuk internal-web.int, menjalankan ssh graham@internal-web.int akan mencoba login sebagai graham
- Contoh konfigurasi dasar
# 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
- Alur pemrosesan saat menjalankan
ssh internal-web.int
- Mencocokkan
internal-web.int pada command line dengan host internal-web.int di ~/.ssh/config
- Jika cocok, mengambil opsi yang tidak ditentukan di command line dari file konfigurasi
- Jika tidak cocok, hanya menggunakan opsi yang didefinisikan di command line
Kata kunci SSH config yang sering dipakai
IdentityFile /path/to/private_key
- Menentukan private key yang akan dipakai untuk host
- Fungsinya sama dengan
ssh -i
ForwardAgent
ProxyJump root@internal-web.int
- Menentukan server yang akan dipakai untuk mem-proxy trafik
- Fungsinya sama dengan opsi
-J
- Dalam contoh, ini menunjukkan bahwa trafik melewati host tersebut karena autentikasi
vuln-server.int diminta lebih dulu
Match
- Menerapkan kata kunci SSH config berdasarkan kondisi tertentu
- Dalam contoh, jika exit code dari perintah
export | grep PROXYME=TRUE adalah 0, maka ProxyJump di bawah blok Match akan digunakan
- Jika variabel lingkungan
PROXYME tidak ada, hanya blok host internal-web.int biasa yang akan digunakan
- Setelah mengatur
export PROXYME=TRUE, menjalankan ssh internal-web.int yang sama akan melewati autentikasi vuln-server.int lalu memberikan shell internal-web.int
scp dan beberapa utilitas berbasis SSH lainnya biasanya juga dapat memakai SSH config
- Di lingkungan yang tidak memakainya secara otomatis, bisa dinyatakan eksplisit dengan
-F ~/.ssh/config
Menyalin public key ssh-copy-id
ssh-copy-id adalah utilitas kecil untuk cepat mengunggah public key ke server
- Perintah yang digunakan
ssh-copy-id -i internal-web root@internal-web.int
- Penjelasan opsi
-i internal-web: menentukan nama private key yang dipakai untuk autentikasi ke server
root@internal-web.int: menentukan server tujuan upload public key
Membuat dan memeriksa kunci dengan ssh-keygen
ssh-keygen adalah utilitas untuk membuat pasangan private key dan public key
- Umumnya disarankan menggunakan opsi
-b untuk menentukan ukuran kunci yang lebih besar
- Ukuran kunci default pada lingkungan contoh adalah
3072
- Algoritme default adalah RSA, tetapi algoritme lain dapat ditentukan dengan flag
-t
- Contoh:
ssh-keygen -t ecdsa -b 521
- Fingerprint dan ukuran byte kunci bisa diperiksa dengan perintah berikut
ssh-keygen -lf <file-name>
1 komentar
Komentar Hacker News
Ada satu direktif yang sangat sederhana tetapi terlewat di sini: atur di
sshd_configsepertiAuthorizedKeysCommand /usr/bin/php /etc/ssh/auth.php %u, lalu di skrip ambilhttps://github.com/{$user}.keysdari GitHubTentu ini bukan kode berkualitas produksi, tetapi menunjukkan intinya
Setelah memeriksa apakah pengguna merupakan anggota organisasi/grup GitHub, jika pengguna itu ada dan dipetakan dengan sesuatu seperti
nss-ato, login ke server bisa diizinkanSaat onboarding/offboarding orang, akses ke mesin bisa diberikan atau dicabut cukup dengan menambahkan/menghapus mereka dari grup GitHub, sehingga kerepotannya berkurang
Di Amazon Linux 2 ke bawah, ia memanggil command line
openssluntuk memeriksa format tiap kunci di fileauthorized_keys, tetapi karena di-hardcode ke RSA, meskipun versi OpenSSH mendukunged25519, autentikasi denganed25519ke host Amazon Linux 2 tidak bisa dilakukanSecara teori ini bagus karena memungkinkan fitur keren¹, tetapi dalam praktiknya, bagi orang yang tidak memakai fitur itu pun fungsi dasar menjadi rusak, sehingga membuat Amazon Linux terasa kurang dapat dipercaya
Saat pertama kali mengalami masalah ini, saya sedang mencoba SSH ke mesin milik rekan DevOps yang cloud-first, dan karena saya tidak bisa mengaksesnya langsung, diagnosisnya sulit
Ia sangat paham AWS tetapi kurang paham Linux, sehingga tidak tahu harus melihat ke mana; ia memilih Amazon Linux karena itu distro buatan pemilik platform cloud dan mengira akan “lebih kompatibel”, tetapi di sini “lebih kompatibel” sebenarnya berarti “lebih banyak kejutan bodoh”
¹ https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/connect-...
Karena cakupan kerja saya adalah “jaringan tidak berfungsi dengan benar”, fitur-fitur keren seperti ini jadi terlewat
Sepertinya banyak orang tidak tahu bahwa parser konfigurasi OpenSSH mengabaikan direktif duplikat, dan dari direktif yang sama hanya yang pertama yang berlaku
Pada parser konfigurasi atau rule engine biasanya direktif yang muncul belakangan menimpa yang sebelumnya, jadi ini cukup berlawanan dengan intuisi
Ini mungkin terlihat sepele, tetapi saat mengubah nilai default seperti
/etc/ssh/sshd_config, manusia maupun perangkat lunak cenderung menambahkan perubahan di akhir file atau blok direktif, dan berharap perubahan itu diterapkanPerusahaan atau organisasi keamanan, berbagai produk bastion SSH, juga sering salah soal ini; rekomendasi CIS Benchmarks dan sebagian besar alat audit CIS pihak ketiga juga tidak mempertimbangkan prioritas atau menanganinya dengan keliru
Untuk memastikan direktif konfigurasi OpenSSH didefinisikan sesuai harapan, jangan menelusuri file konfigurasi secara langsung; dump konfigurasi internal yang dihasilkan dengan
sshd -Tataussh -Gsudoersjuga bekerja dengan cara yang samaUntuk perangkat lunak autentikasi/otorisasi pengguna, saya menganggap cara ini memang diinginkan
Sebab ini memudahkan membuat pengaturan yang tidak bisa ditimpa hanya dengan menambahkan file baru ke direktori
whatever.conf.dCukup definisikan pengaturan tersebut di file konfigurasi utama sebelum memuat
whatever.conf.d/*, lalu beri perlindungan khusus pada file ituBahkan jika bukan situasi seseorang mencoba melewati kontrol, ini menguntungkan untuk manajemen konfigurasi, karena pengaturan dasar tetap punya prioritas meskipun pegawai baru yang tidak tahu konteks penuh menambahkan file baru, atau suatu paket memasang default aneh untuk layanannya sendiri
Alasan perilaku sebaliknya lebih sering terlihat dalam konteks lain adalah karena yang diinginkan bukan “pengaturan dasar”, melainkan default dalam arti ketat: nilai yang dipakai ketika pengguna/pengembang/admin tidak menetapkannya secara eksplisit
AllowUsersNamun kemarin NixOS tiba-tiba mengubah urutan penggabungan, sehingga
AllowUsersdi file saya turun ke bawahMatchdi file lain dan terkunciPenjelasan dalam artikel bahwa pada
-Luntuk forwarding lokal, lokal berada di sisi kiri alamat, sedangkan pada-Runtuk forwarding jarak jauh, port lokal berada di sisi kanan alamat, adalah kalimat paling penting dan ringkasSejak awal saya bingung dengan
-Ldan-R, dan cukup merepotkan bahwa instance port mana yang lokal berubah tergantung L/RSaya paham bahwa
-Ldan-Rmengubah arah yang dimaksud, yaitu di mana pihak pemulai dan pihak penanggap berada, tetapi rasanya tidak masalah juga jikaport:address:portselalu berartilocal:binding:remote, lalu-L/-Rmenentukan sisi mana yang menerima dan sisi mana yang mengirim-Lmendengarkan pada port lokal yang nomornya muncul tepat setelahnya, sedangkan-Rmendengarkan pada port jarak jauh yang nomornya muncul tepat setelahnyaSisa
host:porthanyalah format umum yang memberi tahu ke mana harus terhubungKarena ini melakukan port forwarding melalui tunnel SSH, secara alami host tersebut dihubungi dari sisi yang berlawanan dengan port penerima di dalam tunnel
Salah satu fitur SSH yang kurang dikenal tetapi berguna adalah connection multiplexing
Alih-alih membuat koneksi TCP baru dan menjalani prosedur autentikasi lagi, kita bisa membuatnya menggunakan kembali koneksi yang sudah ada
Protokolnya sendiri memiliki konsep channel, dan setiap frame data diberi metadata untuk membedakan stream yang berbeda; fitur ini memanfaatkan hal itu
Keuntungan besarnya adalah sesi berikutnya tidak perlu mengulang autentikasi penuh
Ini terutama bagus jika di remote tidak ada
tmuxdan kita memakai beberapa panel lewat beberapa jendela terminal, dan akan makin terasa jika autentikasi melibatkan prosedur yang memakan beberapa detik seperti passphrase atau sentuhan HSMAda juga pengaturan “connection persistence”, sehingga tidak perlu autentikasi ulang setiap kali berpindah di antara beberapa server
Secara keseluruhan, saya melihatnya sebagai fitur yang menyenangkan untuk ada, tetapi bukan sesuatu yang sampai mengubah hidup
Di sebagian server fitur ini dimatikan, dan ketidakhadirannya lebih terasa saat dimatikan daripada saat dinyalakan
Lihat selengkapnya: https://en.wikibooks.org/wiki/OpenSSH/Cookbook/Multiplexing
Tidak seperti TLS yang dioptimalkan untuk mengurangi jumlah round-trip, SSH adalah protokol yang cukup cerewet, dan opsi multiplexing ini hampir satu-satunya pengecualian
ProxyJump, ini bisa membuat Ansible jauh lebih nyaman dipakaiJika ada banyak host di
~/.ssh/config, direktifIncludeyang mendukung wildcard bisa mencegah file menjadi terlalu berantakanMisalnya, di
~/.ssh/configkita bisa menaruhInclude config.d/*.conf, lalu memisahkan pengaturanhost,hostname, danusermasing-masing ke~/.ssh/config.d/work.confatauclient1.confHostjuga mendukung wildcardMisalnya, kita bisa menambahkan
host *_workdan memasukkan pengaturan umum untuk semua host kerja sepertihost1_workIncludebisa diletakkan di dalam direktifHost/MatchMisalnya, jika menaruh
Host proj1.*.corpdanInclude ~/.ssh/proj1.confdi~/.ssh/config, pencocokan per proyek bisa ditempatkan dekat bagian atas, dan saat meninjau konfigurasi kita tidak perlu membongkar begitu banyak file terpisahSaat melakukan forwarding, saya hampir tidak pernah memakai
-fIni bisa menjadi senjata makan tuan karena membuat sulit mengetahui forwarding mana yang masih terbuka dan sedang berjalan
-tadalah trik yang keren, dan ini fitur yang sebelumnya tidak saya ketahuiHal penting yang mudah terlewat dari daftar perintah escape
~adalah bahwa escape juga bisa dinesting di dalam sesi yang nestedIni berguna ketika, karena alasan apa pun, kita tidak memakai
-JDaftarnya cocok dengan hal-hal yang berguna, dan ada beberapa hal tambahan yang juga saya pelajari
-titu luar biasa. Saya memakainya sepertissh -t my-dev-vps 'tmux new-session -A -s main', sehingga setiap kali dijalankan saya langsung kembali ke posisi terakhir di sesi tmuxAkan bagus jika SSH bisa mengekspor status forwarding dengan cara yang masuk akal, bukan harus mengorek sendiri daftar proses
Saat ini ada pull request untuk menambahkan dukungan
AF_UNIX, dan jika ini masuk, berbagai forwarding menarik akan menjadi mungkinSebab, akan menjadi mudah mem-proxy koneksi SSH melalui proses lokal sembarang, dan proses itu bisa menangani sendiri bagaimana data diteruskan sampai ke ujung remote
https://github.com/openssh/openssh-portable/pull/431
-Dyang memakaiAF_UNIX, tetapi bagus juga jika semuanya bisa berjalan di atasAF_UNIXSepertinya sejak sekitar setahun lalu
curlbisa memakai SOCKSAF_UNIXlewat sintaksALL_PROXYsocks5://localhost/pathatausocks5hTampaknya ini ditambahkan karena Tor memakai proxy SOCKS
AF_UNIXAkan bagus jika akses jaringan bisa diatur dengan permission Unix standar, dan secara pribadi akan lebih bagus lagi jika TCP/IP bisa disingkirkan sepenuhnya dari kernel
Saya terkejut saat pertama kali melihat konsol SSH
Seorang kolega menunjukkan
~#, dan rasanya seperti menemukan menu cheat rahasia yang mungkin muncul di game SEGA GenesisMengapa tilde? Karena
rlogindanrshmemakainyaMengapa
rlogindanrshmemakai tilde? KarenacumemakainyaMengapa
cu? Jika ada modem atau jalur serial, kita berkomunikasi dengancu, dan perlu mengirim kode Hayes; tetapi jika memakai escape sequence kode Hayes, kita akan masuk ke modem, jadi diperlukan sinyal terpisah untuk keluar kecuMengapa bukan
^[? Karena itu milik telnetJadi jika kita terhubung ke host lewat telnet lalu menyambung ke modem dengan
cu, kita membutuhkan sintaks escape terpisah untuk kembali kecutanpa keluar ke telnetPada akhirnya ini adalah struktur escape syntax yang menumpuk tanpa henti
Dan sebenarnya bukan tilde, melainkan tilde
CR, tilde, lalu., apakah selama ini saya memakainya dengan salah?Bagian
ssh-copy-idawalnya menjelaskan bahwa perintah itu mengunggah public key, lalu tiba-tiba berubah menjadi mengunggah private key, jadi tampaknya itu typoSelain itu, perintah ini bukan sekadar mengunggah key, melainkan menambahkannya ke
~/.ssh/authorized_keys, sehingga jauh lebih bergunaTerakhir, pada bagian
ssh-keygen, dari materi yang saya baca belakangan inied25519lebih disukai daripadaecdsa