------------------------------------------------------------------------------- See also "usage/ssh_howto.txt" And for using SSH public keys with pass-phrase protection see And Kimmo Suominen's Guide... http://kimmo.suominen.com/docs/ssh/ ------------------------------------------------------------------------------- SSH versions (protocols and implementation) First there are two protocols v1 and v2 The first is insecure and is NOT used anymore, anywhere. (Just as: telnet, rsh, and non-anoymous ftp; is should not be used) The other distiction is Commercial SSH and OpenSSH which are just different implementations and slight option differences, with the biggest difference being how keys are stored on disk and in homes. (see below) SunSSH v3 is basied on OpenSSH, but with some slight differences in command line options. Caution is needed for advanced scripts. ------------------------------------------------------------------------------- Ssh Public Private Key Generation and Conversion SSH Version 1 Run the command, press return for all questions ssh-keygen To allow this account to access another account without a password append the file ".ssh/identity.pub" into ".ssh/authorized_keys" on the account you which access. These keys are opsolete and only the version 2 DSA keys are now needed. OpenSSH Three keys should be generated for maximum interoperatibility. ssh-keygen -t rsa1 ssh-keygen -t rsa ssh-keygen -t dsa Then for remote account access append the files ".ssh/id*.pub" into ".ssh/authorized_keys" on the remote account. Which key is used depends on the particular setup of the SSH daemond on both systems. NOTE: under open ssh you can also place authorized keys into the ".ssh/authorized_keys2" file as well. I use the normal file for authorization access from my primary accounts, while I use the second file as a local autorization file bettwen hosts in a cluster, which is NOT distributed from my primary hosts. All OpenSSH stuff is saved into ".ssh" in your home. Commercial SSH2 The commerical SSH2 keys are generated as above, but are stored in the ".ssh2" sub-directory and used differently (extra level of indirection). * ssh-keygen is used to generate the public and private key files EG it generates files: id_dsa_1024_a id_dsa_1024_a.pub Rename to match host: id_dsa_kraken id_dsa_kraken.pub * .ssh2/identification then specifies the private key files, that identify this account to other accounts. EG: IdKey id_dsa_kraken * .ssh2/authorization contains lines identify public key files in the ".ssh2" sub-directory which are allowed access. EG: Key id_dsa_kobold.pub All SSH2 stuff is saved into ".ssh2" in your home. As such OpenSSH and SSH2 configuration can happilly co-exist. OpenSSH and SSH2 key conversion To convert a OpenSSH public key to SSH2 (using OpenSSH) ssh-keygen -e -f ~/.ssh/id_dsa.pub > ~/.ssh2/id_dsa_`uname -n`.pub To convert SSH2 public key to OpenSSH authorized keys (using OpenSSH) ssh-keygen -i -f ~/.ssh2/id_dsa_`uname -n`.pub >> ~/.ssh2/authorized_keys Now you can then add that file name to the ".ssh2/authorization" file and copy both to the machine you want to login to without a password. echo "Key id_dsa_`uname -n`.pub" >> .ssh2/authorization NOTE: the base64 encoded key block does NOT care where the key is broken by newlines or spaces, so you can format it almost anyway you like, if the newlines are permitted by that file. The comment and subject fields seem to be freeform to identify which public key the file contains. ------------------------------------------------------------------------------- Ssh options on the command line... Due to problems with some programs (like rsync, see "rsync.hints", in this directory), most ssh programs will alow you to specify a "=" instead of a space between option and its argument. (Only openssh-2.1 does not seem to allow this which caused some problems). As such in scripts you can use... ssh -f -x -o BatchMode=yes {remote_command} Which turns off any password interaction with user (abort instead) The -f means to background the command and -x ensures an X window connection is also not setup. ------------------------------------------------------------------------------- Copying a file with a ':' in its name The following will fail as their is no host named "t" scp t:t remote: To fix you must have a '/' somewhere before the colon, in which case ssh will consider it a filename. EG: use any of the following... scp ./t:t remote: scp /path/to/file/t:t remote: =============================================================================== Special Techniques and Methods... ------------------------------------------------------------------------------- SSH Path and environment Check what path is used on the remote server and that their is no other junk... ssh remote.domain 'echo $PATH' or the rest of the envionment ssh remote.domain env You can override the initial ssh path my adding it to ".ssh/environment" on the remote server, but this only works if "PermitUserEnvironment" is set to true in the "/etc/ssh/sshd_config" file. echo "PATH=$PATH" >>~/.ssh/environment If this is not posible you can try something like... ssh remote.domain /bin/sh -c 'export PATH=$PATH_FROM_PROFILE; cmd' And debug with... ssh localhost 'pstree -p $$' ssh localhost /bin/sh -c 'pstree -p $$' ... and so on ... Note that better way of setting the environment is to use the shell and not the ssh, or the remote command. The t/csh will read the ".cshrc" file which can abort early for non-interactive commands. The bash shell will read ".bashrc" file (only time it does so), for non-interactive shells. ------------------------------------------------------------------------------- Ssh Server, Limit what commands will work... In the ".ssh/authorized_keys" file you can define a key as command="/path/to/some/command args..." ssh-dss ... Ensure it remains all on one line. This will force ssh to only execute the command that was given, and NOT the command actually requested by the client. Example commands... /usr/bin/cvs server only allow cvs upload/download /usr/bin/ssh user@host always forward user to another host The 'command' can be a special script that looks at the user requested command saved by SSH into the environment variable SSH_ORIGINAL_COMMAND, and then determines the appropriate course of action. For example, see my "ssh_restricted" script that restricts commands to specific directory of pre-defined commands. However the SSH_ORIGINAL_COMMAND envvar losses all the original quoting and escaping of the command and arguments. This means that any escaped or quoted white space, and other special shell characters, will loose there normal interpretation, unless the user provides further escaped quoting of the arguments. In other words do not just execute the provided command but parse it to ensure that things are what you want to allow the user to run. Examples of use. * Limit remote commands to specific ones * Parse rsync requests for `funny business and/or source requests * Log what commands are being requested for remote execution. ------------------------------------------------------------------------------- Ssh Server, Limit to specific scripts in a sub-directory Install script 'restricted_ssh' script /home/anthony/store/scripts/net_connect/restricted_ssh In authorised Keys add command="/path/to/secure/home/restricted_ssh" ssh-dss ... Make sure it remains all on one line. Only remove accounts with this addition will be resctricted. Edit script appropriate for logging. Create "ssh_scripts" sub-directory and add links or scripts the remote use is allowed to run... For example... ln -s /bin/date ssh_scripts ln -s /bin/hostname ssh_scripts Ensure that scripts do not provide access to a shell, and require no arguments Note 'ls' is a built-in command, provided by the "restricted_ssh" script. Test from remote users account... ssh secure-server FAIL no login shell ssh secure-server ls List scripts available ssh secure-server date return date on secure server ssh secure-server hostname return hostname of secure server ssh secure-server date %F FAIL arguments not allowed ssh secure-server ps FAIL no such script ssh secure-server /bin/ps FAIL path characters used ssh secure-server 'date;ps' FAIL illegal charcater (only alphanum) ------------------------------------------------------------------------------- Limit ssh to sftp logins only Add the following (with appropriate group) to "sshd_config" and restart the service. AllowTcpForwarding no Subsystem sftp internal-sftp #/usr/lib/openssh/sftp-server ForceCommand internal-sftp Match group {your_group-here} ChrootDirectory /home/%u ------------------------------------------------------------------------------- Keeping ssh keys on USB key only. Limiting access to a server to ssh pubic keys only is in many ways far more secure than using passwords. Some secure servers only allow ssh-key login and disable user password logins completely for improved security. This was an artical on how you can store local password protected keys on a USB key to provide remote access to a server and via that a separate root ssh key access. NOTE: It talks about using this as a two factor authentication (password for key and the key itself). However the server only sees the key, not the password so it is actually only really a single factor security. From Linux Journal Tighter SSH Security with Two-Factor Authentication http://www.linuxjournal.com/article/8957 By only allowing SSH public key logins which much be stored en encrypted form, will provide increased security without the use of static passwords on the remote machine. User authentication... Prepare a USB stick that holds your encrypted SSH public keys, each public key in a separate file that us named appropriatally for access to a specific machine. You can then login to the remote host using the -i option to specify your encrypted identity file. ssh -i /media/usbdisk/key-rsa-bob@machine2 bob@machine2 Only you with the decrypting password for that key can use them, and they are only stored on a USB stick. (ASIDE: this is not really two factor as one in 'local' not on the server). Root Authentication... For root, you do not want to allow remote root access, so first set the ssh deamon to also look at the localhost loopback interface then only allow root via the loopback interface only. To make this work you would use ssh-add to add the key for root to the ssh-agent (typically already running), and then you can ssh to root on the remote machine you have already logged in on. EG in sshd_config you have something like PermitRootLogin yes AllowUsers bob@* AllowUsers root@127.0.0.1 and restart. Example get root on remote machine... First the user on his current machine does setup root access (5 min limited time access) ssh-add -t 300 /media/usbdisk/key-rsa-root@machine2 then login (as above) ssh -A -i /media/usbdisk/key-rsa-bob@machine2 Then on the remote machine... See that we have access to the roots key ssh-add -l and become root (or run a command as root) ssh root@localhost Note that the roots private key never leaves the users USB key or the machine he is currently using. No one can get root on the remote machine without that USB setup. Now that you can two-factor auth login to root you can lock down its normal password access, and even lockdown su and sudo access The ssh-agent on users machine however should also be locked down using -c so that the user on the original machine must confirm the remote machines use. This is protection against a lurker that has already cracked the remote machne and he wants to hijack root keys to other machines. An alternative is a seperate ssh-agent for each machine and set the enviroment variable SSH_AUTH_SOCK appropriatally before connecting to the remote machine. Of course that should get wrappered into a script "tfssh" tfssh [username@]host [keydir] Download from ftp://ftp.linuxjournal.com/pub/lj/listings/issue152/8957.tgz Saved in ~/store/scripts/net_connect/two_factor_ssh ------------------------------------------------------------------------------- Encrypted links (for any service) ssh -L X:destination:Y firewall This will create a local port X which forwards connections and data to the machine "firewall", and then on to port Y on "destination". A client program (application) can then connect to "localhost:X" to contact the server at "destination:Y". The server program on "destination:Y" however will see the traffic from your client program coming from the machine "firewall", even though client is not actually running on that machine. In other words it sets up a link between the local machine and the one on "firewall" such that "localhost:X" delivers to "destination:Y" via that firewall host. Communications links... ssh -L X:destination:Y firewall "client prog" -normal tcp-> "localhost:X" "localhost" ====ssh encrypted====> "firewall" "firewall" -normal tcp-> "destination:Y" (server program) For a example of this see http://www.uk.research.att.com/vnc/sshvnc.html Add a -C (+C in ssh2) to compress the link as well as encrypt it. A extra -N option means no remote command or login is needed, just the link. NOTE: by default the "X" port is only linked to the loopback interface. This means only client programs on the local machine can use it. If you like client programs on another machine on your network to use port "X" on the initial machine, then also add the option "-o GatewayPorts=yes" or -g. Note: that as long as "localhost" and "firewall" has SSH, then either client or sever application, can be running on a window machine, not just UNIX, or linux! Also note that the links between the client and server applications and the SSH link ports are NOT encrypted, so should be kept local, or at least on the same subnet. The -R option is the same as -l except that the client / server positions are swicthed. EG: X is the port on the remote machine clients connect to while destination and Y is where the local machine transfers connections. Communications links... ssh -R X:destination:Y firewall "client prog" -normal_tcp-> "firewall:X" "firewall" ====ssh encrypted====> "localhost" "localhost" -normal-> "destination:Y" (server program) if the client connecting to the remote system is not local, then you must do add "0.0.0.0" to the command, so it binds to ALL network ports. ssh -L 0.0.0.0:X:destination:Y firewall ------------------------------------------------------------------------------- Using a SSH 'hold_command' With the above socks proxy, or port forwarding I usally like to have the ssh command run a 'holding program on the remote server. This command holds the port, to ensure it does not unexpectantally close. One command I use is... exec xlogo -name proxy -g 20x20-5+5 -fg red -bg navy \ -xrm 'proxy*baseTranslations: #override : quit()' I also sometimes use the color reversal, to denote the reverse direction... exec xlogo -name proxy -g 20x20-30+5 -fg blue -bg firebrick \ -xrm 'proxy*baseTranslations: #override : quit()' The 'xlogo' program is an X windows command that should exist on any machine with X windows capability (all UNIX machines). This means the command will automatically exit and die, closing the remote connections, when you log out of your machine. The special 'resource option' or -xrm is designed to let you close the connection by just pressing the mouse button on that small window. This is no longer needed, as you can now use a -N flag to specify that no command is needed on the remote host. ------------------------------------------------------------------------------ SSH to one machine via a intermedite firewall host -- As of OpenSSH 5.4 you can use... host internal HostName internal.firewalled.domain ProxyCommand ssh -qax -W %h:%p firewall.domain Usage... 1/ add the following to your ".ssh/config" on your external machine. replacing {...} parts as appropriate. Host jumpbox User {jumpbox_username} HostName jumpbox.itc.griffith.edu.au Host internal User {internal_username} HostName {internal}.itc.griffith.edu.au ProxyCommand ssh -W %h:%p jumpbox 2/ make sure you can login to firewall using a public key from your extrnal machine (home) Note: you can also use ".ssh/authorized_keys2" to hold public key authorizations, as a 'local only' authorization (for distributed accounts). Now if you type ssh jumpbox you will login to firewall But if you type ssh internal you will login to the internal machine It is slow to set up the double link, but will work. 3/ Optionally set the 'external' accounts public key in your 'internal' account. You do not need a public key from firewall, as the proxy setup ("ssh -W") makes a 'port' connection, from firewall to the 'internal' ssh port. As such it is the external host that needs public keys on both firewall and your 'internal' host for password-less ssh connections. This connection is a port forward, but it isn't a SSH daemon port forward. The "ssh -W" option is in many ways like using "netcat" to do the port forward. however "netcat" may not be installed on "firewall". 4/ If making multiple connections I suggest adding this to at least the 'internal' setup. ControlMaster auto ControlPath /tmp/ssh-anthony/%r@%h:%p This causes new connections to share any link you still have open, thus makes secondary connections faster. -- Before that you use 'nc' to set up the connection Add the following to your local ".ssh/config" host host1 host2 ProxyCommand ssh -qax firewall nc %h 22 You of cause need to be able to login to the firewall host and access the other machine from that machine. Note port 22 is the SSH server port, so the above forwards the connection via the firewall host to the destination hosts SSH port. EG: to connect to either "host1" or "host2" use the command given to go via a firewall host. The "nc" is the netcat command, which will not understand the other features, which the "-qax" argument will turnoff. -- Alternative use "chainssh" shell script to do this. http://chainssh.sourceforge.net/ See also http://sshmenu.sourceforge.net/articles/transparent-mulithop.html --?-- Simularly the following will always open a forwarded port whenever a connection is made to a particular host... host firewall LocalForward 8080 webserver:80 EG: connect the port localhost:8080 to webserver:80 via the sshd on firewall ------------------------------------------------------------------------------- Socks Proxy via a firewall host. ssh -X -n -o BatchMode=yes -D 8080 firewall "cmd" & The command is some command to hold the connection open, when it ends the socks connection will also end. A good command is... exec xlogo -name proxy -g 20x20-5+5 -fg firebrick -bg navy \ -xrm 'proxy*baseTranslations: #override : quit()' This runs a small Xlogo that will just quit when the mouse button is pressed, or your X terminal session ends, thus closing the connection automatically. You can now point your web cliient and other network utilities to port 8080 on the local machine to socks connect via your firewall host to anywhere. For example... curl -v --socks5 localhost:8080 -m 30 -L http://www.aol.com.au/ | wc Unfortunatally you can not set environemnt variables to define a default socks proxy server (see next). You must tell each application what it is. ------------------------------------------------------------------------------- Web Proxy via firewall and another open web proxy server (old method) If you can find a open web proxy you have access to say proxy_ip:3128 This you can do this... ssh -X -n -o BatchMode=yes -L 4444:proxy_ip:3128 firewall "cmd" Where the "cmd" is a connection holder as per the socks proxy above. curl --proxy localhost:4444 -m 30 http://www.aol.com.au/ | wc You can no define environment variables like... # for lynx HTTP_PROXY = "http://localhost:4444/" NO_PROXY = ".list.of.local,.domains,.not.to.proxy" # for curl http_proxy = "$HTTP_PROXY" no_proxy = "$NO_PROXY" and it test with... curl -m 30 http://www.aol.com.au/ | wc and/or set the proxy setting of your web browser, and browse/download This is harder to setup (and find an open proxy on the web) but has the advantage that only connections from the firewall is to that web proxy. This makes it much more difficult for system adminastrators of the firewall to figure out what sites you are looking at and downloading from. ------------------------------------------------------------------------------- SSH Bit Torrent via a Public Host Bit torrent needs an outgoing Socks Proxy, but also a Incomming remote port. The SSH daemon on remote machine must allow TcpForwarding and GatewayPorts. ssh -X -n -o BatchMode=yes -D 4001 \ -R 0.0.0.0:13481:localhost:13481 \ $remote_server "$hold_command" & This lets azurus use 13481 as its incomming port and 4001 on the localhost as the socks v5 proxy port. Configure Azureus... In Configuraton Wizard set Advanced options Under Preferences (Options) -> Connection: Set Incoming TCP listen port to 13481 Under Preferences (Options) -> Connection -> Proxy Options Check: Enable proxying of tracker communications Check: I have a SOCKS proxy Set: Host to 127.0.0.1 Set: Port to 4001 Check: Enable proxying of peer communications Check: Inform tracker of limitation Set: SOCKS version to V5 Check: Use same proxy settings for tracker and peer communications proxy Under Preferences (Options) -> Transfer: Check: Allow multiple connections from the same IP Now restart Azureus ------------------------------------------------------------------------------- SSH to a Dynamic (roaming) IP Address. If the machine you are trying to ssh to changes IP address, the following options allow you to select the right host key seperately to the actual address you attempt to SSH to. ssh -o CheckIP=no -o StrictHostKeyChecking=no -o HostKeyAlias={machine_name} {Current_IP_of_machine} This is usfull if you want to SSH back to a machine, which dialed onto the network via a PPP modem or dynamic ADSL connection. Eg ssh back to where you logged in using info in "$SSH_CLIENT" or "$SSH_CONNECTION" environment variable. ------------------------------------------------------------------------------- SSH security notes and ideas. Turn off port forward on machines with multi users See http://www.semicomplete.com/articles/ssh-security/ Basically because of -N ssh does not need a working shell to use port forwarding, and thus using a shell like /bin/false will not disable a user from using a port forward. If port forwarding is needed, then consider including a valid 'shell test' in the PAM login system. that probably should be added in any case. Use a white list of acceptable IP's The problem is that you can't login from a random terminal when you need to. You may also have too many users to control access in this way. Only allow public key access. No passwords allowed, period. For random remote logins have putty and your private ssh key on a USB stick. NB: using the private key on public machines may not be a very good idea. Spot and deny SSH dictionary attacks... "denyHosts"... Adds 'deny' lines to the '/etc/hosts.deny" file when it sees an attacks in the /var/log/secure file. A script to do the same thing locally is simple too, so you can DIY it. "sshdfilter", runs sshd with a -e filter to add iptable denys in real time rather than after the fact, often before a password has even been requested. It is highly configurable, and removed old entries according to various rules. However it is not avaialble as a yum package (yet) http://www.csc.liv.ac.uk/~greg/sshdfilter/ "sshd_sentry" (may not be released), after five failed attempts the IP address is blocked for 24 hours. The problem is it leaves you vulnerable to a DoS attack from competitors, It does not just block SSH ports but also denies web bot access for google and yahoo search engines too. Limit logins to specific usernames. Dictionary attackers will give up as they don't really know your allowed user list. Change the sshd port on the external router... EG port forward 7xxx on the router to 22 on your internal machine Note do not use port 2222. Everyone uses that and script kiddies will catch on to this, and scan for that port too. Not at time of writing though. One Time, or limited time Passwords. Do you have an SMS-enabled cell phone? For an operating systems class project this spring I wrote a simple PAM module what would look up the user's cell phone number then send an eight-digit random number to the user's cell phone, which the user has to type in at the login prompt. I used this module to secure the outward-facing sshd (on port 7xxx), blocking port 22 at the firewall so I could continue to ssh around my home network without spending $0.15 every time I rebooted my laptop. As long as your phone has a signal, you have effective token-based authentication. -------------------------------------------------------------------------------