- SSH सिर्फ remote access से आगे बढ़कर port forwarding, jump host, config files, और key management तक को साथ में संभालने वाला टूल है, और web server के उदाहरण RDP·SQL जैसी दूसरी services पर भी वैसे ही लागू होते हैं
- local·remote·dynamic port forwarding क्रमशः
-L, -R, -D से सेट होते हैं, और मुख्य फर्क यह है कि port किस तरफ खुलता है और traffic किस दिशा में बहता है
- जिन networks में direct access बंद हो, वहाँ
-J jump host और ProxyJump से कई SSH hop जोड़कर destination तक पहुँचा जा सकता है
ssh-agent और -A agent forwarding remote host पर भी local keys इस्तेमाल करने देते हैं, जो सुविधाजनक है, लेकिन agent के दुरुपयोग से जुड़ी security risk पहले समझनी चाहिए
~/.ssh/config, ssh-copy-id, ssh-keygen, और SSH console के ~?·~C को साथ इस्तेमाल करने पर बार-बार options टाइप करने की ज़रूरत कम होती है, session के दौरान forwarding जोड़ना, public key deploy करना, और key बनाना·जाँचना आसान हो जाता है
SSH port forwarding को समझने के लिए ज़रूरी आधार
- SSH port forwarding को सिर्फ diagram से समझना मुश्किल हो सकता है, इसलिए असली commands और network scenarios को साथ देखकर समझना आसान होता है
- उदाहरण web server access पर आधारित हैं, लेकिन यही तरीका RDP, SQL जैसी लगभग सभी services पर लागू किया जा सकता है
- बार-बार इस्तेमाल होने वाले options का मतलब यह है
-N: remote server पर कोई command execute नहीं करता और shell भी नहीं खोलता
-f: SSH को background में भेज देता है
root@host: tunnel बनाने वाले user और host से login करता है
local port forwarding -L
- local port forwarding local machine के port को remote server के port तक forward करता है
- उदाहरण स्थिति
internal-web.int एक web page host करता है, जिस तक सिर्फ loopback interface से पहुँचा जा सकता है
campfire.int से internal-web.int पर SSH access संभव है
- लक्ष्य है
campfire.int के local port के ज़रिए internal-web.int के web server तक पहुँचना
- इस्तेमाल की command
ssh -N -f -L 1337:127.0.0.1:80 root@internal-web.int
- option का अर्थ
-L: local forwarding निर्दिष्ट करता है
1337:127.0.0.1:80: local port 1337 को remote के 127.0.0.1:80 से bind करता है
- tunnel बनने के बाद
campfire.int पर local port 1337 को request भेजकर internal-web.int के port 80 से interact किया जा सकता है
- याद रखने की बात:
-L में local port address के बाएँ तरफ आता है
remote port forwarding -R
- remote port forwarding local पर उपलब्ध port को remote server के port के रूप में expose करता है
- उदाहरण स्थिति
internal-web.int एक web page host करता है, जिस तक सिर्फ loopback से पहुँचा जा सकता है
- firewall की वजह से
campfire.int सीधे internal-web.int तक नहीं पहुँच सकता
vuln-server.int तक campfire.int और internal-web.int दोनों से पहुँचा जा सकता है
- इस्तेमाल की command
ssh -N -f -R 3000:127.0.0.1:80 root@vuln-server.int
- option का अर्थ
-R: remote forwarding निर्दिष्ट करता है
3000:127.0.0.1:80: vuln-server.int के port 3000 को local के 127.0.0.1:80 से bind करता है
- इसके बाद
vuln-server.int:3000 पर curl request भेजने से internal-web.int के port 80 पर चल रहे internal web page तक पहुँचा जा सकता है
- याद रखने की बात:
-R में local port address के दाएँ तरफ आता है
dynamic port forwarding -D और SOCKS proxy
- dynamic port forwarding
-D option से SOCKS proxy बनाता है और traffic को SSH relay के ज़रिए भेजता है
- उदाहरण स्थिति
internal-web.int ऐसा web application host करता है, जिस तक सिर्फ internal network से पहुँचा जा सकता है
vuln-server.int उसी internal network में है और internal-web.int तक पहुँच सकता है
- लक्ष्य है
campfire.int से vuln-server.int के ज़रिए traffic को proxy करना
/etc/proxychains.conf की setting SSH command के port से मेल खानी चाहिए
socks5: proxychains को SOCKS5 इस्तेमाल करने देता है
127.0.0.1: localhost का उपयोग करता है
8080: यह SSH -D में दिए गए port से मेल खाना चाहिए
- इस्तेमाल की command
ssh -N -f -D 8080 root@vuln-server.int
- forwarding बनने के बाद
socks5 127.0.0.1 8080 सेट करने पर proxychains curl 192.168.1.185 से internal web page तक पहुँचा जा सकता है
- SOCKS के ज़रिए DNS हर environment में ठीक से काम नहीं कर सकता, इसलिए उदाहरण में hostname की जगह IP address इस्तेमाल किया गया है
- Firefox में भी manual proxy settings के ज़रिए SOCKS proxy इस्तेमाल किया जा सकता है
- path: Settings → Privacy & Security → Network Settings
- Manual proxy configuration चुनें
- “Proxy DNS when using SOCKS V5” को check करें
- SOCKS host को
127.0.0.1 और port को 8080 पर सेट करें
jump host -J
- jump host कई SSH relay से गुजरते हुए ऐसे destination तक पहुँचने देता है, जहाँ current host से direct access संभव नहीं है
- उदाहरण chain है
campfire.int → vuln-server.int → internal-web.int → dns.int
- इस्तेमाल की command
ssh -J root@vuln-server.int,root@internal-web.int root@dns.int
- कई jump targets को comma से अलग किया जाता है
agent forwarding -A
ssh-agent local machine पर ssh-add <private_key_file> से private key या ID जोड़ने देता है
- जोड़ी गई keys को
ssh-add -l से देखा जा सकता है
ssh-agent में key जोड़ने के बाद पासवर्ड फिर से डाले बिना उसी key से SSH login किया जा सकता है, इसलिए यह लोगों और service accounts दोनों के लिए उपयोगी है
-A agent forwarding login की गई remote machine पर भी local agent की keys इस्तेमाल करने देता है
- इस्तेमाल से पहले security risk समझने के लिए Zero Effort Private Key Compromise: Abusing SSH-Agent for Lateral Movement देखें
- उदाहरण command
ssh -A -J root@vuln-server.int root@internal-web.int
- यह command
vuln-server.int के रास्ते internal-web.int पर connect करते समय campfire.int के local SSH agent में मौजूद keys इस्तेमाल करने देती है
- इसके बाद
internal-web.int पर ssh root@dns.int चलाने पर private key अलग से बताने या credentials डालने की ज़रूरत नहीं होती
TTY command allocation -t
-t option remote server पर interactive command जल्दी चलाने में उपयोगी है
- उदाहरण के तौर पर
Vim या top जैसी commands, जिन्हें TTY चाहिए
- इस्तेमाल की command
ssh root@internal-web.int -t top
- इसे चलाने पर remote server पर
top command सहित एक TTY मिल जाता है
-g: local forwarding port को बाहरी hosts के लिए खोलना
-g option remote hosts को local forwarded port से connect होने देता है
- यह local port forwarding
-L जैसा है, लेकिन फर्क यह है कि इस “local” port को बाहरी machines भी इस्तेमाल कर सकती हैं
- उदाहरण स्थिति
vuln-server.int पर shell access है
- लक्ष्य है
vuln-server.int के port 2222 पर आने वाले connections को internal-web.int के port 22 तक proxy करना
- इस्तेमाल की command
ssh -N -f -g -L 2222:localhost:22 root@internal-web.int
- option का अर्थ
-g: remote hosts को local forwarded port से connect होने देता है
-L: local forwarding निर्दिष्ट करता है
vuln-server.int के port 2222 पर SSH से connect करने पर भी असली shell internal-web.int पर ही होगा
SSH console ~? और session के दौरान forwarding
- SSH console एक छिपा हुआ feature है, जिससे remote system से सीधे interact किए बिना SSH को खुद control किया जा सकता है
- shell खराब हो जाने पर या SSH session को ही control करना हो, तब यह उपयोगी है
- help console
~? से खोला जा सकता है
- उपयोगी options
~.: मौजूदा SSH session को बंद करता है
~C: SSH console खोलता है, जहाँ forwarding options जोड़े जा सकते हैं
- अगर आप पहले से सामान्य
ssh command से vuln-server.int में login हैं, तब भी ~C दबाकर -D 8080 डालने पर वही session dynamic forwarding session की तरह इस्तेमाल किया जा सकता है
- अगर
campfire.int पर /etc/proxychains.conf port 8080 के लिए configured है, तो proxychains का उपयोग ऐसे किया जा सकता है जैसे शुरुआत से ssh -D चलाया गया हो
SSH config file ~/.ssh/config
- SSH config file
~/.ssh/config में होती है और बार-बार टाइप किए जाने वाले SSH options को सहेजकर समय बचाती है
- SSH connect करते समय इस file को parse करता है, और अगर target के लिए मेल खाता
host config हो तो उसी के options इस्तेमाल करता है
- command-line arguments config file पर प्राथमिकता रखते हैं
- उदाहरण के लिए, अगर config file में
internal-web.int के लिए user root दिया गया हो, तब भी ssh graham@internal-web.int चलाने पर login की कोशिश graham के रूप में होगी
- basic config example
# 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 चलाने पर processing flow
- command-line के
internal-web.int को ~/.ssh/config के host internal-web.int से match किया जाता है
- match होने पर command-line में न दिए गए options config file से लिए जाते हैं
- match न होने पर सिर्फ command-line में दिए गए options इस्तेमाल होते हैं
अक्सर इस्तेमाल होने वाले SSH config keywords
IdentityFile /path/to/private_key
- host के लिए इस्तेमाल होने वाली private key निर्दिष्ट करता है
- यह
ssh -i जैसा ही है
ForwardAgent
ProxyJump root@internal-web.int
- traffic को proxy करने वाला server निर्दिष्ट करता है
- यह
-J option जैसा ही है
- उदाहरण में यह दिखाया गया है कि traffic उस host से गुज़रता है, क्योंकि पहले
vuln-server.int authentication माँगता है
Match
- conditions के आधार पर SSH config keywords लागू करता है
- उदाहरण में अगर
export | grep PROXYME=TRUE command का exit code 0 हो, तो Match block के नीचे वाला ProxyJump इस्तेमाल होता है
- अगर
PROXYME environment variable न हो, तो सिर्फ सामान्य host internal-web.int block इस्तेमाल होता है
export PROXYME=TRUE सेट करने के बाद वही ssh internal-web.int चलाने पर vuln-server.int authentication के बाद internal-web.int shell मिलता है
scp और कुछ SSH-आधारित utilities भी आमतौर पर SSH config इस्तेमाल कर सकती हैं
- जिन environments में यह अपने-आप न हो, वहाँ
-F ~/.ssh/config देकर इसे explicitly बताया जा सकता है
public key copy ssh-copy-id
ssh-copy-id public key को server पर जल्दी upload करने वाली एक छोटी utility है
- इस्तेमाल की command
ssh-copy-id -i internal-web root@internal-web.int
- option का अर्थ
-i internal-web: server authentication के लिए इस्तेमाल होने वाली private key का नाम निर्दिष्ट करता है
root@internal-web.int: वह server निर्दिष्ट करता है जहाँ public key upload करनी है
key generation और inspection ssh-keygen
ssh-keygen private key और public key की जोड़ी बनाने वाली utility है
- आमतौर पर
-b option से बड़ा key size निर्दिष्ट करना recommend किया जाता है
- उदाहरण environment में default key size
3072 था
- default algorithm RSA है, लेकिन
-t flag से दूसरा algorithm चुना जा सकता है
- उदाहरण:
ssh-keygen -t ecdsa -b 521
- key का fingerprint और byte size इस command से देखा जा सकता है
ssh-keygen -lf <file-name>
1 टिप्पणियां
Hacker News की टिप्पणियां
इसमें एक हैरान कर देने वाला सरल directive छूट गया है:
sshd_configमेंAuthorizedKeysCommand /usr/bin/php /etc/ssh/auth.php %uजैसा सेट करें, और script में GitHub सेhttps://github.com/{$user}.keysfetch कर लेंबेशक यह production-quality code नहीं है, लेकिन मूल बात दिखा देता है
GitHub organization/group की membership जांचने के बाद, अगर user मौजूद है और
nss-atoजैसी किसी चीज़ से mapped है, तो server login allow किया जा सकता हैलोगों को onboard/offboard करते समय सिर्फ GitHub group में add/delete करके machines का access देना या वापस लेना संभव है, जिससे झंझट कम होता है
Amazon Linux 2 और उससे नीचे में
authorized_keysfile की individual key format check करने के लिएopensslcommand line call की जाती है, लेकिन यह RSA पर hardcoded है, इसलिए OpenSSH versioned25519support करने के बावजूद Amazon Linux 2 host परed25519से authenticate नहीं किया जा सकता थाTheory में यह एक अच्छा feature¹ enable करता है, इसलिए ठीक लगता है, लेकिन practice में यह उन लोगों के लिए भी basic functionality तोड़ देता है जो वह feature इस्तेमाल नहीं करते, जिससे Amazon Linux पर भरोसा कम होता है
पहली बार जब मुझे यह problem मिली, मैं एक cloud-first DevOps colleague की machine में SSH करने की कोशिश कर रहा था, और मेरे पास direct access नहीं था, इसलिए diagnose करना मुश्किल था
वह AWS तो अच्छी तरह जानता था, लेकिन Linux कम जानता था, इसलिए उसे पता नहीं था कि कहां देखना है; उसने Amazon Linux इसलिए चुना था क्योंकि यह cloud platform owner का बनाया distro है और उसे लगा था कि यह “more compatible” होगा, लेकिन यहां “more compatible” का मतलब असल में “अधिक बेवकूफी भरे surprises” निकला
¹ https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/connect-...
“network ठीक से काम नहीं कर रहा” ही job scope है, इसलिए ऐसे शानदार features छूट जाते हैं
शायद बहुत लोगों को यह नहीं पता कि OpenSSH config parser duplicate directives को ignore करता है, और same directive में से सिर्फ पहला effective होता है
आम तौर पर config parsers या rule engines में बाद में आया directive पहले वाले को overwrite करता है, इसलिए यह काफी counterintuitive है
यह मामूली लग सकता है, लेकिन
/etc/ssh/sshd_configजैसे defaults बदलते समय लोग और software changes को file या directive block के अंत में append करने की प्रवृत्ति रखते हैं, और उम्मीद करते हैं कि वह लागू होगाSecurity companies और organizations, कई SSH bastion products भी इसमें गलती करते हैं, और CIS Benchmarks की recommendations व ज्यादातर third-party CIS audit tools भी priority को consider नहीं करते या गलत handle करते हैं
OpenSSH config directives उम्मीद के मुताबिक define हुए हैं या नहीं, यह check करने के लिए config file को खुद scan न करें;
sshd -Tयाssh -Gसे derived internal config dump करेंsudoersfile भी इसी तरह काम करती हैUser authentication/authorization software में मुझे यह तरीका बेहतर लगता है
क्योंकि
whatever.conf.ddirectory में नई file जोड़कर भी ऐसी settings बनाना आसान है जिन्हें override नहीं किया जा सकताMain config file में
whatever.conf.d/*include करने से पहले वह setting define कर दें, और उस file पर खास protection लगा देंकोई control bypass कर रहा हो ऐसा न भी हो, तब भी पूरे context को न जानने वाला junior नई file जोड़ दे या कोई package अपनी service के लिए अजीब default install कर दे, तो भी baseline setting को priority मिलती रहती है—इसलिए यह configuration management के लिए फायदेमंद है
दूसरे contexts में उल्टा behavior ज्यादा दिखने की वजह यह है कि जो चाहिए वह “baseline setting” नहीं, बल्कि सख्त अर्थ में default value होती है, जो तब इस्तेमाल होती है जब user/developer/admin ने explicitly कुछ set नहीं किया हो
AllowUsersहालांकि कल ही NixOS ने अचानक merge order बदल दिया, जिससे मेरी file का
AllowUsersदूसरी file केMatchके नीचे चला गया और lock हो गयाArticle का सबसे important और concise sentence यह है कि
-Lमें local forwarding के लिए local address के left में होता है, और-Rमें remote forwarding के लिए local port address के right में होता है—ऐसे याद रखेंशुरू से ही
-Lऔर-Rconfuse करते रहे हैं, और port instance में कौन-सा local है यह L/R के हिसाब से बदलना काफी annoying हैमैं समझता हूं कि
-Lऔर-Rintended direction, यानी initiator और responder कहां हैं, यह बदलते हैं; लेकिनport:address:portको हमेशाlocal:binding:remoteका मतलब रखने देना और-L/-Rसे यह तय कराना कि कौन-सी side receive करेगी और कौन-सी send, भी ठीक होता-Lअपने तुरंत बाद आने वाले number के local port पर listen करता है, और-Rअपने तुरंत बाद आने वाले number के remote port पर listen करता हैबाकी
host:portसिर्फ यह बताने का सामान्य format है कि connect कहां करना हैचूंकि SSH tunnel के जरिए port forwarding की जा रही है, इसलिए यह भी स्वाभाविक रूप से follows करता है कि host को receiving port वाली side से tunnel के opposite side पर contact किया जाता है
SSH में कम चर्चित लेकिन उपयोगी फीचर के रूप में connection multiplexing है
नया TCP connection बनाने और authentication प्रक्रिया फिर से करने के बजाय मौजूदा connection को reuse कराया जा सकता है
protocol में ही channel की अवधारणा होती है, और हर data frame में अलग-अलग streams को पहचानने वाला metadata जुड़ा होता है; यह feature उसी का इस्तेमाल करता है
बाद के sessions में पूरा authentication दोबारा न करना पड़े, यह बड़ा फायदा है
remote पर
tmuxवगैरह न हो और आप कई terminal windows के जरिए कई panels इस्तेमाल करते हों, तो यह खास तौर पर अच्छा है; authentication में passphrase या HSM touch जैसी कुछ सेकंड लेने वाली प्रक्रिया हो तो फर्क और ज्यादा महसूस होता है“connection persistence” setting भी है, ताकि कुछ servers के बीच आते-जाते हर बार authenticate न करना पड़े
कुल मिलाकर यह एक अच्छा-हो-तो-बढ़िया feature है, लेकिन जिंदगी बदल देने वाला नहीं
कुछ servers पर यह feature बंद होता है; और इसकी कमी तब ज्यादा महसूस होती है जब यह off हो, compared to जब यह on हो
और देखें: https://en.wikibooks.org/wiki/OpenSSH/Cookbook/Multiplexing
SSH, TLS के उलट, जो round trips घटाने के लिए optimized है, काफी chatty protocol है; यह multiplexing option लगभग अकेला exception है
ProxyJumpbastion host से गुजरते समय Ansible को इस्तेमाल करने में कहीं ज्यादा सुविधाजनक बना सकता हैअगर
~/.ssh/configमें बहुत सारे hosts हैं, तो wildcard support करने वालेIncludedirective से file को बहुत messy होने से बचाया जा सकता हैउदाहरण के लिए
~/.ssh/configमेंInclude config.d/*.confरखें, और~/.ssh/config.d/work.confयाclient1.confमेंhost,hostname,usersettings अलग-अलग रख सकते हैंHostdirective भी wildcard support करता हैउदाहरण के लिए
host *_workजोड़करhost1_workजैसे सभी work hosts के लिए common settings डाल सकते हैंIncludeकोHost/Matchdirective के अंदर रखा जा सकता हैउदाहरण के लिए
~/.ssh/configमेंHost proj1.*.corpऔरInclude ~/.ssh/proj1.confरखें, तो project-specific matches ऊपर के पास रखे जा सकते हैं और review करते समय ढेरों अलग-अलग files खंगालने की जरूरत भी कम होती हैforwarding करते समय मैं लगभग कभी
-fइस्तेमाल नहीं करताइससे यह समझना मुश्किल हो सकता है कि कौन-सी forwarding अभी भी खुली और चल रही है, और यह अपने ही पैर पर कुल्हाड़ी जैसा बन सकता है
-tएक बढ़िया trick है, और यह ऐसा feature था जिसके बारे में मुझे पता नहीं था~escape commands की list में आसानी से छूट जाने वाली अहम बात यह है कि nested sessions के अंदर भी escapes को nest किया जा सकता हैकिसी भी वजह से
-Jन इस्तेमाल कर रहे हों, तो यह उपयोगी हैlist उपयोगी चीजों से अच्छी तरह मेल खाती है, और कुछ नई बातें भी सीखने को मिलीं
-tशानदार है। मैं इसेssh -t my-dev-vps 'tmux new-session -A -s main'की तरह इस्तेमाल करता हूं, ताकि हर बार चलाने पर सीधे tmux session की पिछली जगह पर लौट जाऊंprocess list को खुद खंगालने के अलावा, अच्छा होगा अगर SSH किसी reasonable तरीके से forwarding status expose करे
AF_UNIXsupport जोड़ने वाला एक मौजूदा pull request है; अगर यह merge हो गया तो तरह-तरह की दिलचस्प forwarding संभव हो जाएगीवजह यह है कि किसी भी local process के जरिए SSH connection को proxy करना आसान हो जाएगा, और वह process remote end तक data पहुंचाने का काम अपनी तरह से handle कर सकेगा
https://github.com/openssh/openssh-portable/pull/431
AF_UNIXइस्तेमाल करने वाले-Dमें है, लेकिन सब कुछAF_UNIXके ऊपर चल सकना अच्छी बात हैकरीब 1 साल पहले से
curlशायदALL_PROXYsyntaxsocks5://localhost/pathयाsocks5hके जरिएAF_UNIXSOCKS इस्तेमाल कर सकता हैलगता है यह इसलिए जोड़ा गया क्योंकि Tor
AF_UNIXSOCKS proxy इस्तेमाल करता हैstandard Unix permissions से network access configure कर पाना अच्छा होगा, और निजी तौर पर तो TCP/IP को kernel से पूरी तरह बाहर धकेल पाना और भी बेहतर लगेगा
SSH console पहली बार देखकर मैं हैरान रह गया था
एक colleague ने
~#दिखाया था, और ऐसा लगा जैसे SEGA Genesis game में मिलने वाला secret cheat menu खोज लिया होtilde क्यों? क्योंकि
rlogin,rshने इसका इस्तेमाल किया थाrlogin,rshने tilde क्यों इस्तेमाल किया? क्योंकिcuने किया थाcuक्यों? modem या serial line होने परcuसे communication करते थे, और Hayes codes भेजने होते थे; लेकिन Hayes code की escape sequence इस्तेमाल करने पर आप modem में निकल जाते, इसलिएcuसे बाहर निकलने के लिए अलग signal चाहिए था^[क्यों नहीं? क्योंकि वह telnet का हैइसलिए अगर आपने telnet से host में connect किया और फिर
cuसे modem में connect हुए, तो telnet से बाहर निकले बिनाcuपर लौटने के लिए अलग escape syntax चाहिए थाआखिरकार यह escape syntax की अंतहीन परतों वाला ढांचा है
और असल में यह tilde नहीं, बल्कि tilde ही है
CR, tilde,.होता है; क्या मैं अब तक गलत इस्तेमाल कर रहा था?ssh-copy-idsection पहले बताता है कि command public key upload करती है, फिर अचानक private key upload करने की बात पर बदल जाता है; यह typo लगता हैसाथ ही यह command सिर्फ key upload नहीं करती, बल्कि
~/.ssh/authorized_keysमें append करती है, इसलिए यह कहीं ज्यादा उपयोगी हैअंत में,
ssh-keygensection में आजकल मैंने जो पढ़ा है उसके अनुसारecdsaकी तुलना मेंed25519को ज्यादा पसंद किया जाता है