ssh

Updated: October 15, 2024

Secure Shell is used to login to remote machines. It can also be used for executing commands on a remote machine.


Table of Contents

Syntax

ssh [-46AaCfGgKkMNnqsTtVvXxYy] [-B bind_interface] [-b bind_address] [-c cipher_spec] 
    [-D [bind_address:]port] [-E log_file] [-e escape_char] [-F configfile] [-I pkcs11]
    [-i identity_file] [-J destination] [-L address] [-l login_name] [-m mac_spec] [-O ctl_cmd] 
    [-o option] [-p port] [-Q query_option] [-R address] [-S ctl_path] [-W host:port]
    [-w local_tun[:remote_tun]] destination [command]

Escape Characters

~.      # Disconnect.
~^Z     # Background ssh.
~#      # List forwarded connections.
~&      # Background ssh at logout when waiting for forwarded connection / X11 sessions to terminate.
~?      # Display a list of escape characters.
~B      # Send a BREAK to the remote system (only useful if the peer supports it).
~C      # Open command line.  Currently this allows the addition of port forwardings using the -L, -R 
        # and -D options (see above).  It also allows the cancellation of existing port-forwardings 
        # with -KL[bind_address:]port for local, -KR[bind_address:]port for remote and 
        # -KD[bind_address:]port fordynamic port-forwardings.  !command allows the user to
        # execute a local command if the PermitLocalCommand option is enabled in ssh_config(5).  
        # Basic help is available, using the -h option.
~R      # Request rekeying of the connection (only useful if the peer supports it).
~V      # Decrease the verbosity (LogLevel) when errors are being written to stderr.
~v      # Increase the verbosity (LogLevel) when errors are being written to stderr.

Working with keys

First check to see if a key already exists. (may want to remove it)

for key in ~/.ssh/id_*; do ssh-keygen -l -f "${key}"; done | uniq

If there is a key we want to keep, we should check that it has been added to ssh-agent.

ssh-add -l

If there is no key, let’s make one!

# generate a key w/hostname as comment. All ed25519 are 256 bits
ssh-keygen -t ed25519 -C "$(hostname)"                    # key would be called id_ed25519
ssh-keygen -t ed25519 -C "$(hostname)" -f "$(hostname)"   # key would be called hostname

# May also need to set user permissions over .ssh folder
chown -R megacron:megacron ~/.ssh
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_*
chmod 644 ~/.ssh/id_*.pub
chmod 644 ~/.ssh/authorized_keys
chmod 644 ~/.ssh/known_hosts
chmod 644 ~/.ssh/config

# this will start server
eval "$(ssh-agent -s)"

# add the private key to the ssh agent
ssh-add ~/.ssh/id_ed25519

# generate/change a passphrase
ssh-keygen -f ~/.ssh/id_ed2519 -p

# update password encoding on old key
ssh-keygen -o -f ~/.ssh/id_ed25519
  -f    # private key filename
  -o    # use newer safer password encoding
  -c    # change comment
  -C    # set comment text
  -b    # set size (bytes)
  -p    # change passphrase
  -t    # type of key, like ed25519
  
# test if ssh key added correctly for gitlab
ssh -T git@gitlab.com
# if test fails run to see error:
ssh -vvvT git@gitlab.com

# To specify to use a certain key to access remote server
ssh -i ~/.ssh/id_ed25519 megacron@10.0.18.18

# enable the server
sudo systemctl start sshd
sudo systemctl enable sshd

SSH-ADD

eval "$(ssh-agent -s)"          # make sure ssh agent is running
ssh-add -d ~/.ssh/id_ed25519    # remove specific identity from ssh agent 
ssh-add -D                      # remove all identities from ssh agent

Create a Config File

~/.ssh/config (client)

Host *
  AddKeysToAgent yes
  UseKeychain yes
  IdentitiesOnly yes
  IdentityFile ~/.ssh/id_ed25519
  IdentityFile ~/.ssh/id_rsa    # keep any old key files if you want

# Set a specific key to a name 
Host pi3
  HostName 192.168.0.12
  Port 4321
  User drax
  IdentitiesOnly yes
  IdentityFile ~/.ssh/id_ed25519

Setup Bastion Server

~/.ssh/config

Host 138.197.177.13 # IP of bastion server
  User root
  StrictHostKeyChecking no
  UserKnownHostsFile /dev/null
  LogLevel ERROR
  ServerAliveInterval 60
  IdentityFile ~/.ssh/id_ed2519

Host 192.168.69.*
  ProxyCommand ssh 138.197.177.13 -W %h:%p
  StrictHostKeyChecking no
  UserKnownHostsFile /dev/null
  LogLevel ERROR
  ServerAliveInterval 60

to connect to synology through a jump server

ssh -L localhost:5001:user.synology.me:5001 jump

Setup SSHD Config File

/etc/ssh/sshd_config (server)

Port 4321    # change the port to match ~/.ssh/config of client.

Once ssh config file is updated, add the private key to the ssh agent

ssh-add -K ~/.ssh/id_ed25519

When saved you can then ssh to target host with

ssh pi3

Moving Keys to Remote Server

Ideally should use:

# creates necessary folders and permissions as well!
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@host

Copy the .pub key is placed on as many computers to grant access to the server.
There are 2 ways to do this on command line:
* Pipe the file though SSH using normal login of connecting computer.
* Secure copy the file using SSH. Either one will use password. After that, no password will be needed.

# Move pub key to remote server authorized_keys file:
scp ~/.ssh/id_rsa.pub megacron@10.0.18.18:.ssh/authorized_keys

# Copies the contents of the id_rsa.pub file to your clipboard
pbcopy < ~/.ssh/id_ed25519.pub              # OSX
cat ~/.ssh/id_rsa.pub | clip                # windows
xclip -sel clip < ~/.ssh/id_ed25519.pub     # linux

cat ~/.ssh/id_ed25519.pub | ssh user@remotehost 'cat >> ~/.ssh/authorized_keys'   # appends key
scp ~/.ssh/id_ed25519.pub pi@10.0.18.18:.ssh/authorized_keys                      # overwrites existing keys
sudo chmod 600 authorized_keys  # change mod u=rw

Git Shell for SSH

If you want to restrict access to a git server you can set it up with a git shell instead of a sh like zsh, csh, zsh and the like. This starts with editing /etc/passwd bottom line. git:x:1000:1000::/home/git:/bin/sh Change:

/bin/sh to /usr/bin/git-shell

A custom message can be made if users try to use ssh. run: git help shell

SERVER HARDENING

Perform hardening only after passwordless ssh key if fully working.
Set idle timeout interval, don’t allow empty password, turn off x11forwarding, limit max authentication attempts.

sudo vim /etc/ssh/sshd_config 
# Add time for a timeout:
ClientAliveInterval 300
# Remove empty password by uncommenting:
PermitEmptyPasswords no
# Make sure x11forwarding is off
X11Forwarding no
# Lower auth tries
MaxAuthTries 3

# restart sshd server
sudo systemctl restart sshd   # pacman, macOS
sudo service ssh restart      # apt
sudo vim /etc/services
# after finished edit
sudo launchctl unload /System/Library/LaunchDaemons/ssh.plist
sudo launchctl load -w /System/Library/LaunchDaemons/ssh.plist

X11

REALLY GOTTA LOOK INTO THIS!!  options -nf
ALSO
-S ControlPath && ControlMaster && ControlPersist

Send commands to other machines w/o logging in:

ssh USER@SERVER_IP "ls /etc"  # pulls list from etc on other machine to yours.

ssh -t USER@SERVER_IP "sudo COMMAND"  # use -t if sudo needs to be used.

POPULAR USES

# install and run an apache server.  Check to see if running by going to http://loacalhost:80
ssh -R 8080:localhost:80 user@192.168.10.20     # creates a remote of the service on local machine to extend to another server for clients to access.  So the clients can connect from a cloud on the remote server on port 8080 which then forwards through firewall by ssh tunnel to port 80 of the apache server running locally, while the clients only know they are connecting to 8080.

# create a loopback connection to get past firewall by first connecting locally to machine then going to internet. (tcp forward)
ssh -L 5901:localhost:5901 ardwolf@rrs5204q6n.hak5.org   # for instance when using VNCVIEWER as a remote desktop application.  This is mapping the 5901 port on the remote VNC server to the 5901 port on local machine.

need to configure VNC server to then only listen on lo  (local)

then to connect ssh >> VNC all you need to put in for the command is:
  vncviewer localhost:1

# create a dynamic connection
ssh -D 8080   # go to *.  Allow to go anywhere.  Where -L mapped to another specific port, -D does not map any specific relationship.

Quids shows some very basic setup.

Install SSH SERVER & give Authorization.

This is the Debian/Ubuntu version of sshd.

sudo apt-get install openssh-server
sudo chmod 700 .ssh   # change mod u=rwx
sudo service ssh status

Then edit sshd_config to your liking and check local networking. (Default PORT 22).

sudo vim /etc/ssh/sshd_config    # edit conf file
ssh localhost   # get localhost name
allowUsers billy@192.168.0.17

PORTS

ssh -p 4321 user@192.168.10.12   # creates shell env on remote computer on local network.

REMOTING FROM ANOTHER NETWORK (Public Access)

For our example lets say the following variables:


In order to gain access from outside the port needs to be forwarded by the router where the machine running sshd we want access to is located. Forward port 4321 Internal & External to 192.168.9.12
Now we can use following command to ssh to that machine from anywhere on the internet.

ssh -p 4321 drax@123.123.123.123

DELETE OR REPLACE OLD KEYS

Edit ~/.ssh/known_hosts with your favourite text editor and remove the line containing the old key. It is also possible to not do this manually using the following command:

	ssh-keygen -R <strong>computer_name_or_ip</strong>

PER REPOSITORY KEYS If you want different keys depending on the repository you are working on, you can issue the following command while inside your repository.

git config core.sshCommand "ssh -o IdentitiesOnly=yes -i ~/.ssh/id_somePrivateKey -F /dev/null"