Skip to content

Linux Networking and Security Fundamentals-Day2

Here's the lab material for day 2 of the Linux Networking & Security Fundamentals webinar.

Note

My main IP network is either: 10.0.2.0/24 or 10.0.42.0/16, depending on the lab being used for the day.

I run a Debian server and client, Fedora server and client, Ubuntu server, and some mystery Linux distributions. (Really, it's whatever I have available at the time!)

See this link for more information on how to set up your lab to follow along.

Disclaimer & Warning Link Here


Part I: Security 101

This is the foundation of the day's concepts, but there is only one lab. The core concepts of this section are listed below. Descriptions for these concepts can be found in the Security+ Cert Guide.

  • Nothing is ever 100% secure
  • Defense in Depth
  • Principle of Least Privilege
  • Always be Watching

Lab 1-1

Using the dig command to check a website

  • Run the comand dig -x 67.205.11.189 (or other IP address defined by the instructor). What do you find?

  • Ping that same IP address and view the results there as well.

Part II: Working with Services

Services are the underlying programs that make applications work. For example, without the httpd service, we wouldn't be able to use the Apache web server. Services are important for two reasons:

  1. They make the system available to legitimate users.
  2. They increase the attack surface, and in so doing, make the system available to illegitmate users too.

So, we have to split our brain. One side needs to think about availability and the other needs to consider security. This is the constant balance that we must maintain in the tech world.

Lab 2-1

Reducing the Attack Surface

This lab shows how to stop and disable a service, and check the open ports of a system. The lab is run on a Debian client system.

  • Stop the networking service

    systemctl stop networking

    Then check its status with systemctl status networking

  • Disable the service

    systemctl disable networking

    Then check its status again.

    Note

    The service can be stopped and disabled with one command:

    systemctl --now disable networking

  • Start and enable the networking service

    systemctl --now enable networking

  • Check for open ports being used by services

    ss -tulnw

    Example results:

    user@deb52:~$ ss -tulnw
    Netid         State           Recv-Q          Send-Q                    Local Address:Port                    Peer Address:Port         
    icmp6         UNCONN          0               0                                     *:58                                 *:*            
    udp           UNCONN          0               0                         192.168.122.1:53                           0.0.0.0:*            
    udp           UNCONN          0               0                        0.0.0.0%virbr0:67                           0.0.0.0:*            
    udp           UNCONN          0               0                               0.0.0.0:44050                        0.0.0.0:*            
    udp           UNCONN          8448            0                         192.168.122.1:5353                         0.0.0.0:*            
    udp           UNCONN          8448            0                             10.0.2.52:5353                         0.0.0.0:*            
    udp           UNCONN          0               0                               0.0.0.0:5353                         0.0.0.0:*            
    udp           UNCONN          0               0                               0.0.0.0:5353                         0.0.0.0:*            
    udp           UNCONN          0               0                               0.0.0.0:56590                        0.0.0.0:*            
    udp           UNCONN          0               0                                  [::]:45721                           [::]:*            
    udp           UNCONN          0               0                                  [::]:5353                            [::]:*            
    tcp           LISTEN          0               100                           127.0.0.1:20959                        0.0.0.0:*            
    tcp           LISTEN          0               100                           127.0.0.1:20000                        0.0.0.0:*            
    tcp           LISTEN          0               100                             0.0.0.0:4000                         0.0.0.0:*            
    tcp           LISTEN          0               100                           127.0.0.1:12001                        0.0.0.0:*            
    tcp           LISTEN          0               100                           127.0.0.1:12002                        0.0.0.0:*            
    tcp           LISTEN          0               100                           127.0.0.1:25001                        0.0.0.0:*            
    tcp           LISTEN          0               80                            127.0.0.1:3306                         0.0.0.0:*            
    tcp           LISTEN          0               100                           127.0.0.1:26002                        0.0.0.0:*            
    tcp           LISTEN          0               32                        192.168.122.1:53                           0.0.0.0:*            
    tcp           LISTEN          0               9                               0.0.0.0:21                           0.0.0.0:*            
    tcp           LISTEN          0               128                             0.0.0.0:22                           0.0.0.0:*            
    tcp           LISTEN          0               128                           127.0.0.1:7001                         0.0.0.0:*            
    tcp           LISTEN          0               100                                [::]:4000                            [::]:*            
    tcp           LISTEN          0               128                                   *:80                                 *:*            
    tcp           LISTEN          0               9                                  [::]:21                              [::]:*            
    tcp           LISTEN          0               128                                [::]:22                              [::]:*            
    tcp           LISTEN          0               128                               [::1]:7001                            [::]:*    
    

    Scroll over to see the open ports. You can see that the DHCP client (port 67), DNS (port 53), SSH (port 22), and several others are opened. Those are ports that aare opened on the inbound side. Every open port is a potential vulnerability. Normally, a client such as this would have no legitimate reason to have port 22 open (amoong other ports). We could close that port by stopping and disabling the service with one command.

    Don't do this on your system (so you don't lose SSH) but here is an example:

    systemctl --now disable ssh

    You can use curly braces {} to stop and disable multiple services at the same time. For example:

    systemctl --now disable {service1,service2}

Lab 2-2

Cause a Degraded System - and fix it!

This lab demonstrates how one failed service or program will cause a "degraded system". The lab is run on a Debian client.

  • Cause a service to fail.

    Here we'll type an error into the SSH server configuration file. When we attempt to restart SSH, it will fail. That will then cause the system to become degraded.

    1. Open the sshd_config file. It is located in /etc/ssh.
    2. Locate the line that says #Port 22, and modify it to read Port22----$%^
    3. Restart the SSH server service: systemctl restart sshd. You should see the failure. For example:
    root@deb52:/etc/ssh# systemctl restart sshd
    Job for ssh.service failed because the control process exited with error code.
    See "systemctl status ssh.service" and "journalctl -xe" for details.
    
  • Start troubleshooting

    Now, run the command systemctl status and the second line should read "State: degraded". Unfortunately, this command does not show what has failed, or how. But you can find any failed services by issuing the command: systemctl --failed. This should result in the following:

    root@deb52:/etc/ssh# systemctl --failed
      UNIT        LOAD   ACTIVE SUB    DESCRIPTION                
    ‚óŹ ssh.service loaded failed failed OpenBSD Secure Shell server
    
    LOAD   = Reflects whether the unit definition was properly loaded.
    ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
    SUB    = The low-level unit activation state, values depend on unit type.
    
    1 loaded units listed. Pass --all to see loaded but inactive units, too.
    To show all installed unit files use 'systemctl list-unit-files'.
    

    We can see that the ssh service has failed. We can check the ssh and sshd servicese individually with the systemctl or journalctl commands. Examples:

    systemctl status ssh and systemctl status sshd

    journalctl -u ssh and journalctl -u sshd

    If systemctl doesn't go back in time far enough in the logs, then journalctl is the tool to use. By issuing the command journalctl -u ssh we can see why and where the actual error occurred:

    Apr 07 16:48:15 deb52 sshd[5193]: /etc/ssh/sshd_config line 13: Badly formatted port number.
    

    It tells us exactly where to look to analyze the problem more: the sshd_config file on line 13. That is exactly what we messed up in the first place!

    Note

    You could have also run the journalctl -xe command (as the Linux error message stated) but that will give you a ton of information that you would need to sift through. Using the -u option with the particular service name will usually save you time. And you can put that extra time in a bottle for later use if you wish.

  • Fix the problem and verify full functionality

    Access the SSH configuration file:

    vim /etc/ssh-sshd_config

    Change the line that we modified earlier back to the original: #Port 22

    Restart the service:

    systemctl restart sshd

    Check the system with a systemctl status. At this point, it should once again say that the State is "running" in green. And all is well in Linux Land.

Part III: Updates & Upgrades

One of the most important ways to keep a system secure it to update it. Linux distributions such as Debian, Ubuntu, Red Hat, and most others continually release security updates. These are essential to the operating system's well-being. But not only that, updates to individual programs are important as well. For instance, programs that use SSH and SSL, or work as web servers, and so on. These should be updated ASAP, as long as updates are performed within your organization's guidelines (policies and procedures).

Different Linux distributions use different package managers, and so, updating will vary from one distro to the next. Here's a quick breakdown of some of the command line-based package managers used by Linux systems:

  • Debian Linux (and derivatives): apt
  • Red Hat (and derivatives): dnf
  • SuSE (and derivatives): zypper
  • Arch (and derivatives): pacman

We'll focus on the Advanced Package Tool (APT) that is used by Debian and Ubuntu (and many others).

The apt tool can be used to: check for updates, install individual updates, install all updates, upgrade to a new version of the OS, install individual programs, and more. It is a powerful tool and should be used accordingly - with caution.

Lab 3-1

Using apt

In this lab we will show: how to update all programs at once; update individual programs; install individual programs; and cleanup the system when done.

  • Update all programs

    Warning

    The following procedure will update the entire system to the latest point release and will update any existing programs that have updates available. Use with caution!

    At a Debian client system type the following command:

    apt update && apt upgrade -y
    

    Note

    You will need root or sudo access to accomplish this.

    This command does the following:

    1. Checks for updates based on the "sources.list" file.
    2. Downloads and installs all updates

    It does this automatically without any other user intervention. While this is okay for a client system (usually), we might need to use more caution when working with servers.

  • Update a server

    Here we will update a Debian server, but we will do so in a more step-by-step fashion.

    First, let's run apt update by itself so that the system will search for updates.

    Next, lets view what those updates are:

    apt list --upgradeable

    Example on Debian Server

    Here's an example of the two previous commands:

    root@deb51:~# apt update
    Hit:1 http://deb.debian.org/debian buster InRelease
    Get:2 http://security.debian.org/debian-security buster/updates InRelease [65.4 kB]
    Get:3 http://deb.debian.org/debian buster-updates InRelease [51.9 kB]
    Get:4 http://security.debian.org/debian-security buster/updates/main Sources [180 kB]
    Get:5 http://security.debian.org/debian-security buster/updates/main amd64 Packages [271 kB]
    Get:6 http://security.debian.org/debian-security buster/updates/main Translation-en [145 kB]
    Fetched 714 kB in 0s (1,469 kB/s)                              
    Reading package lists... Done
    Building dependency tree       
    Reading state information... Done
    1 package can be upgraded. Run 'apt list --upgradable' to see it.
    root@deb51:~# apt list --upgradeable
    Listing... Done
    libopenjp2-7/stable 2.3.0-2+deb10u2 amd64 [upgradable from: 2.3.0-2+deb10u1]
    N: There is 1 additional version. Please use the '-a' switch to see it
    

    In the example, we see that the file libopenjp2-7 can be upgraded (slightly). That file is part of a package called OpenJPEG which deals with JPEG compression. This could be considered to be bloat (unnecessary software) on a server, especially if we are working in the command line only with no desktop environment (which you normally should be if working on Debian server).

    Note

    This is just an example. Your server will have different information based on what is installed, and when you run the commands!

    In this example, we have a several options. We could:

    • Do nothing. This is, in fact, a common option.

    • Update the individual file (which is done with the apt install command)

      apt install libopenjp2-7

    • Update the whole system (which would only update that file anyway in this case)

      apt upgrade

    • Or, choose to remove the file or JPEG compression altogether in an effort to remove bloat. For example:

      apt remove libopenjp2-7

    If we choose one of the second or third options, the file gets updated, and a subsequent execution of apt update will result in a message telling us that "all packages are up to date". If we choose the last option, the file and other dependent files are removed, and a subsequent apt update will, again, show that all packages are up to date.
    - Update another package that was previously installed

    For example, update the OpenSSH pacakge:

    apt install openssh-server

    That updates the SSH server on the system (if an update is available).

  • Clean up!

    This is fairly easy. First, delete extra files in the /var directory with this command:

    apt clean

    Next, remove any unused or unnecessary packages:

    apt autoremove

    This will most likely remove a lot of unused pacakges. When it is finished, run an apt udpate to make sure that there are no additional updates that are required.

Lastly, you should know how to update the OS from one point release to the next and from one version to the next.

  • To update the point release, first check the current version and point release. Here's an example in Debian:

    root@deb51:~# cat /etc/debian_version 
    10.9
    

    The file "debian_version" simply tells us the version and release. But it is important because it shows that point release number, whereas commands such as hostnamectl will only show the main version number.

    apt update && apt upgrade will normally update the system to the latest point release (for example, from 10.8 to 10.9). it will also install any and all security updates (which is what we are really interested in).

  • To update from one version to another, the command apt full-upgrade can be used. But use caution, this is a major upgrade, and as such, it could cause system instability based on your hardware and software. It is best to run this on a test system first and document the results carefully.

That's it for this lab - and for this section!

Part IV: Firewalls

A firewalls is essentially a set of rules that can permit or deny traffic to a particular location. they can be hardware-based or software-based. Another commonly used name for a firewall is a packet filter.

In the following two labs we will work on UFW and firewalld.

UFW

UFW is the Uncomplicated FireWall. It was developed by Ubuntu and works on Ubuntu and Debian-based systems. We'll run the UFW lab on a Debian server.

Lab 4-1

Working with UFW

The Uncomplicated FireWall (developed by Ubuntu), is designed for Ubuntu and works well on Debian. It is not designed for Red Hat and its derivatives. This is a front-end firewall utility that interfaces with the iptables back-end tool and ultimately, the iptables (or nftables) themselves.

In this lab we'll show how to install UFW, enable the UFW service, enable the UFW firewall itself, and create and remove some rules - testing as we go. I'll be testing on a Debian server, but an Ubuntu server would work just as well.

Warning

You will need to work locally at the virtual machine for this lab. This is because once enabled, the firewall will shutdown subsequent SSH connections.

  • Setup UFW

    To begin, we'll install and enable UFW. On Ubuntu it should already be installed. However, other distributions, such as Debian, will need to install it.

    apt install ufw

    After that we need to make sure the service is enabled and started.

    systemctl status ufw

    If it is not enabled and started, do so:

    systemctl --now enable ufw

    Now, turn on the firewall itself.

    ufw enable

    That's it, UFW is enabled and running. Let's take a look at the main configuration file for UFW:

    vim /etc/default/ufw

    Note the default global rules. All inbound and forwarded connections are being dropped, while any outbound connections are allowed. Here's an example of that on the Debian system:

    # Set the default input policy to ACCEPT, DROP, or REJECT. Please note that if
    # you change this you will most likely want to adjust your rules.
    DEFAULT_INPUT_POLICY="DROP"
    
    # Set the default output policy to ACCEPT, DROP, or REJECT. Please note that if
    # you change this you will most likely want to adjust your rules.
    DEFAULT_OUTPUT_POLICY="ACCEPT"
    
    # Set the default forward policy to ACCEPT, DROP or REJECT.  Please note that
    # if you change this you will most likely want to adjust your rules
    DEFAULT_FORWARD_POLICY="DROP"
    

    Note

    For the actual rules configuration file go to /etc/ufw/ and access user.rules to start.

  • Create inbound rules

    Now that we enabled the firewall, we can't connect to the server anymore! If you were to test it from a client, SSH connections would fail. But most of the time, you will want to run a firewall - but with exceptions. One exception is SSH. Let's enable inbound ssh with the following command:

    ufw allow 22/tcp

    or

    ufw allow ssh

    Now, lets show the rule:

    ufw show added

    This should show that the UFW rule has been added to allow inbound SSH. Now, attempt to SSH into the server from a client system. It should work.

    Note

    To view the access log, go to /var/log/ufw.log

    In some firewalling scenarios you might need to deny a service. Let's deny SSH now with the following command:

    ufw deny ssh

    Enter the ufw status command to verify that it is working. You will note that the "SSH allow" rule is gone. The deny rule now takes precedence as shown below:

    root@deb51:~# ufw status
    Status: active
    
    To                         Action      From
    --                         ------      ----
    22/tcp                     DENY        Anywhere                  
    22/tcp (v6)                DENY        Anywhere (v6)   
    
  • Delete a rule (and more!)

    It could be that you want to allow SSH over IPv4, but not over IPv6. UFW creates separate rules for both IP systems (by default) unless you specify otherwise. In this case, we have both set to deny. We could delete the IPv4, and afterward create a rule that allows IPv4 SSH access.

    But first, we delete the SSH IP4 rule. The easiest way to do this is to delete the rule number. to find out the rule numbers, issue the following command:

    ufw status numbered

    You should see the rule numbers on the left, for example:

    root@deb51:~# ufw status numbered
    Status: active
    
         To                         Action      From
         --                         ------      ----
    [ 1] 22/tcp                     DENY IN     Anywhere                  
    [ 2] 22/tcp (v6)                DENY IN     Anywhere (v6)   
    

    So the rule we wnat to delete is Rule #1. Do this with the following command:

    ufw delete 1

    That's it. Check it again with ufw status and it should be gone. Now create an allow rule for SSH over IPv4 only. And check it:

    root@deb51:~# ufw allow proto tcp to 0.0.0.0/0 port 22
    Rule added
    root@deb51:~# ufw status numbered
    Status: active
    
         To                         Action      From
         --                         ------      ----
    [ 1] 22/tcp                     ALLOW IN    Anywhere                  
    [ 2] 22/tcp (v6)                DENY IN     Anywhere (v6)    
    

    Now we can see that SSH over IPv4 is allowed, but SSH over IPv6 is not. Great work!

    Note

    That was just one example of many. And the networking options are vast. You will need to tweak your rules based on your network configuration and needs.

    Note

    If you find that you don't need IPv6, you can simply disable it globally. Go to:

    /etc/default/ufw

    and change IPV6=YES to IPV6=NO. Then reload the service: ufw reload. Alternatively, you could restart the UFW service: systemctl restart ufw or ufw disable and ufw enable.

  • Disable UFW, delete the rules, and disable the UFW service

    Careful with the following command. It removes the rules and resets the firewall to a disabled state!

    ufw reset

    Then, stop and disable the service to bring the system back to its original state before we began the lab.

    systemctl --now disable ufw

Note

For more information about UFW:

Help file: ufw --help

MAN page: man ufw

Basic usage: https://help.ubuntu.com/community/UFW More advanced usage and configs: https://wiki.ubuntu.com/UncomplicatedFirewall

firewalld

firewalld is a front-end firewalling utility developed by Red Hat. So it's designed for Fedora, RHEL, CentOS, and other Red Hat derivatives, and is installed on them by default. It acts as an easier to use front-end for the netfilter framework via the nftables userspace utility - which essentially is the nft command.

Note

This utility is recommended for workstations. While it is often used on servers, it is recommended to use nftables (and the nft utility) on servers and for firewalling entire networks.

firewalld can be installed on Debian and Ubuntu, but it is not designed for them and therefore might not work quite as expected.

For the following lab we'll work with a Fedora server.

Lab 4-2

Working with firewalld

Warning

You will need to work locally at the virtual machine for this lab. This is because once enabled, the firewall will shutdown subsequent SSH connections.

  • Check if the service is running:

    systemctl status firewalld

    If not started and enabled, do it now:

    systemctl --now enable firewalld

  • Show the current zone

    Zones are entities that hold different configurations. For example, block and deny are more secure built-in zones, whereas public is a bit less secure (and commonly found as a default).

    Almost all firewalld commands start with firewall-cmd. To show the current zone, issue the following command:

    firewall-cmd --get-active-zones

    Here's an example of the output on the Fedora server:

    [root@fed-server ~]# firewall-cmd --get-active-zones
    FedoraServer
      interfaces: enp1s0
    

    Here we can see that the current active zone that the firewall is using is called FedoraServer. This is the default option, and is fairly limited. It is very similar to the public zone (which is used by CentOS for example by default).

    We also see that the network interface (enp1s0) is making use of that zone type.

    You can also issue the following command to get more information about the active zone:

    firewall-cmd --list-all

    Here is the results from our Fedora Server:

    [root@fed-server ~]# firewall-cmd --list-all
    FedoraServer (active)
      target: default
      icmp-block-inversion: no
      interfaces: enp1s0
      sources: 
      services: cockpit dhcpv6-client ssh
      ports: 
      protocols: 
      masquerade: no
      forward-ports: 
      source-ports: 
      icmp-blocks: 
      rich rules: 
    

    You can see the services that are running, and that is essentially what we are limited to. So we can ping the server, SSH into it, use the cockpit service to control it remotely from a web browser, and the server can seek to obtain an IP address from a DHCP server. We can't do much of anything else though. However, even this will not be secure enough for many environments.

    You try it!

    Try now to ping and SSH into the Fedora server. You should be able to.

    Note

    There are many types of built-in zones. To see a list of them, type the following command:

    firewall-cmd --get-zones

    To see in-depth information about all zones, type the following:

    firewall-cmd --list-all-zones

    You can also create your own zones if you wish.

  • Change the active zone from FedoraServer to block

    Let's make the system more secure by changing the default active zone. Issue the following command:

    firewall-cmd --zone=block --change-interface=enp1s0 --permanent

    Note

    You will have to change the name of your interface from enp1s0 to whatever your network interface name is. If you are not sure than issue either the ip a command or the nmcli command. Be sure to use the Linux name of the network interface, and not the NetworkManager name.

    This command changes the active zone. Check it with:

    firewall-cmd --get-active-zones

    Your interface should now be part of the block zone, making it more secure. Once again, you can list more information, but this time we have to add the zone name. Use the following command:

    firewall-cmd --zone=block --list-all

    You should see output similar to the following:

    [root@fed-server ~]# firewall-cmd --zone=block --list-all
    block (active)
      target: %%REJECT%%
      icmp-block-inversion: no
      interfaces: enp1s0
      sources: 
      services: 
      ports: 
      protocols: 
      masquerade: no
      forward-ports: 
      source-ports: 
      icmp-blocks: 
      rich rules: 
    

    Note that there are no services listed. So this zone type is more secure because it allows nothing to come through, including ping or SSH which we could accmplish earlier. You can view this further by typing the following command:

    firewall-cmd --zone=block --list-ports

    That command should show nothing because no ports are open right now, which in turn is because no services are currently allowed.

    You try it!

    Go ahead and attempt to ping the Fedora server from a remote system and SSH into it. You should not be able to do so now.

    Now try scanning the server with nmap. If you don't have nmap installed, you can easily install it (apt install nmap or dnf install nmap`, etc...)

    Here I scan the Fedora server (10.0.2.54) from a Fedora client. As you can see below, the results show that everything is filtered, and effectively no ports are open.

    [root@fed-client ~]# nmap -Pn 10.0.2.54
    Starting Nmap 7.80 ( https://nmap.org ) at 2021-04-09 13:51 EDT
    Nmap scan report for 10.0.2.54
    Host is up (0.00039s latency).
    All 1000 scanned ports on 10.0.2.54 are filtered
    MAC Address: 52:54:00:B5:29:89 (QEMU virtual NIC)
    
    Nmap done: 1 IP address (1 host up) scanned in 5.37 seconds
    
  • Add a rule to allow SSH

    Most of the time, we desire access to a server via SSH. So let's add a rule that allows it.

    firewall-cmd --zone=block --add-port=22/tcp --perm

    We have to specify the zone we are dealing with (block). The --add-port option has the ability to be configured by port number (22/tcp) or by name (ssh). We also added the --permanent option in abbreviated form (--perm) so that the port will remain open if the system is rebooted.

    Now we have to reload the firewall for the change to take effect.

    firewall-cmd --reload

    Now we can check our work with the following commands:

    firewall-cmd --zone=block --list-ports

    firewall-cmd --zone=block --list-all

    Here are the results of the second option:

    [root@fed-server ~]# firewall-cmd --zone=block --list-all
    block (active)
      target: %%REJECT%%
      icmp-block-inversion: no
      interfaces: enp1s0
      sources: 
      services: 
      ports: 22/tcp
      protocols: 
      masquerade: no
      forward-ports: 
      source-ports: 
      icmp-blocks: 
      rich rules: 
    

    You can see that for the "block" zone, the only port that is listed is port 22. If we had run the command with the --add-port=ssh option, that would show up under services. Whether you do this by service name or by port is up to you but it might be dictated by organizational policy as well. Historically I prefer to do it by port number.

    You try it!

    Now you should be able to SSH into the server, but not ping the server.

    Note

    A subsequent nmap scan from the client: nmap -Pn 10.0.2.54 should show that everything is filtered except for the SSH port.

  • Remove the SSH rule

    To remove the SSH rule, issue the following command:

    firewall-cmd --zone=block --remove-port=22/tcp --perm

    Then, reload the firewall:

    firewall-cmd --reload

    Check your work:

    firewall-cmd --zone=block --list-ports

    It should show that no ports are opened once again.

  • Change the active zone back to the original.

    Issue the following command:

    firewall-cmd --zone=FedoraServer --change-interface=enp1s0 --per

    Note

    Your original zone name might be different. For example, if you are working on CentOS, it is probably named public.

    Your interface name may be different as well.

    Also, we have abbreviated --permanent even further to --per.

    Verify the active zone:

    firewall-cmd --get-active-zones

  • Open multiple ports at once

    Now we have our original active zone. But it doesn't allow for things like HTTP, DNS, and so on. If we want those, we have to create a rule to open those ports. For example, if we wanted to run a FreeIPA server, we would need to open several ports. We could do it in the following manner:

    firewall-cmd --add-port={80,443,389,636,88,464}/tcp --per
    

    That will open up the ports associated with HTTP, HTTPS, LDAP, Secure LDAP, and two Kerberos-based ports.

    Reload the firewall and the check your work:

    firewall-cmd --reload

    firewall-cmd --list-ports

  • Close multiple ports at once

    firewall-cmd --add-port={80,443,389,636,88,464}/tcp --per
    

    Reload the firewall, and check your work. Everything should be back to the original firewall settings.

  • Stop the firewall service and scan the system

    Stop and disable the firewall service with the following command:

    systemctl --now disable firewalld

    Now scan it from a remote client:

    nmap 10.0.2.54

    Change the IP address as necessary for your server. Here are example results:

    [root@fed-client ~]# nmap 10.0.2.54
    Starting Nmap 7.80 ( https://nmap.org ) at 2021-04-09 14:19 EDT
    Nmap scan report for 10.0.2.54
    Host is up (0.00015s latency).
    Not shown: 998 closed ports
    PORT     STATE SERVICE
    22/tcp   open  ssh
    9090/tcp open  zeus-admin
    MAC Address: 52:54:00:B5:29:89 (QEMU virtual NIC)
    
    Nmap done: 1 IP address (1 host up) scanned in 0.24 seconds
    

    We didn't need the -Pn option this time because the Fedora server is not firewalled at all. You'll also note that the scan only took 0.24 seconds. It shows us that the SSH and zeus-admin (cockpit) ports are open. When you do this type of work, you get to see why firewalls are so important.

    Note

    There is a graphical version of the firewall-cmd command structure. It is called firewall-config, and it can be installed to a Fedora client with the dnf install firewall-config command.

    Success

    That's it for this lab. Great work!

Part V: User Security

In Linux you have the root user and everyone else, known as standard users. The root user has complete control over the system. Standard users can have varying levels of power depending on what you assign.

When logged in and using a terminal a standard user will see the $ at the end of the prompt, as shown here:

user@deb51:~$

However, the root user login prompt will show the # sign:

root@deb51:~#

Warning

Though we use the root account a lot in these labs, it is important to limit root usage in the field, and instead set up a standard user account as an administrator of the system. More on that later in this lab guide.

You try it!

Go ahead and log in to your system as a regular account now. Then, login as the root account by typing su - and the password of the root user. Notice the difference between the two types of accounts.

Lab 5-1

Working with passwords

In this lab we'll create a new account and attempt to assign a new password to the account. In so doing, we will see some of the basic password rules that are applied to user accounts by the operating system. This is shown on a Debian server.

  • Create a new account

    As root, create a new account named sysadmin.

    adduser sysadmin

    Assign the password test to the account and confirm it. You can fill out the rest of the automated form if you wish or just press enter to bypass them. Here's an example of what it looks like on a Debian server:

    root@deb51:~# adduser sysadmin
    Adding user `sysadmin' ...
    Adding new group `sysadmin' (1001) ...
    Adding new user `sysadmin' (1001) with group `sysadmin' ...
    Creating home directory `/home/sysadmin' ...
    Copying files from `/etc/skel' ...
    New password: 
    Retype new password: 
    passwd: password updated successfully
    Changing the user information for sysadmin
    Enter the new value, or press ENTER for the default
        Full Name []: Bob User
        Room Number []: 8
        Work Phone []: 5551212
        Home Phone []: 5551212
        Other []: test user
    Is the information correct? [Y/n] y
    root@deb51:~# 
    
  • Login as the new sysadmin account

    You can either logout of root and then login as sysadmin, or you can type:

    su - sysadmin which will start a new login shell for that account.

  • Attempt to change the password:

    Type passwd to change the sysadmin account password. You will be prompted for the current password.

    Now enter the following new password: test1 and confirm it.

    The system should respond by saying that you must choose a longer password. That's because Debian's default password policy for minimum length is 6 characters.

  • Attempt to change the password again:

    Type passwd again. This time, try the password test12. Although it meets the minimum requirements, it will fail again. The system will tell you that "Bad: new and old password are too similar". That's because the new password has the same characters as the old password.

  • Attempt to change the password a third time:

    Type passwd once again. This time, try the password hello123. This should work.

    Note

    Is hello123 a secure password? Not really, by today's standards. At the bare minimum, passwords should be 8-10 characters, with a higher level of complexity. Length is very important. While the password in question is 8 characters, it just scrapes by in today's insecure world. It only uses lowercase letters and its only 8 characters. A more secure system would require passwords that are 16 characters minimum and use uppercase letters, lowercase letters, numbers, and special characters.

    For more informatin about password security, see the NIST SP 800-63B Digital Identity Guidelines document at this link: https://pages.nist.gov/800-63-3/sp800-63b.html

    Tip

    Need a quick way to generate a password in Linux? If you have openSSL installed it's easy:

    openssl rand -base64 24

    This will generate a 24 character password for you. However, I recommend using a local password vault, such as KeePass.

  • Remove the sysadmin account

    We have an account with a weak password that we really don't need. As a sysadmin, always remember to clean up after your work. In this case, we'll remove the sysadmin account and any associated home directories.

    Logout of the sysadmin account and login as root. If you previously used the su - sysadmin command to login as sysadmin, you can simply type logout, or exit and you will be returned to the root shell. Otherwise, make sure you are logged in as root.

    Delete the sysadmin account:

    deluser sysadmin

    Then, delete the home directories for sysadmin:

    rm -r /home/sysadmin

    Check it with the following command:

    ls /home

    You should not see a sysadmin directory there any longer. An example of the entire removal process is shown below:

    sysadmin@deb51:~$ exit
    logout
    root@deb51:~# deluser sysadmin
    Removing user `sysadmin' ...
    Warning: group `sysadmin' has no more members.
    Done.
    root@deb51:~# rm -r /home/sysadmin
    root@deb51:~# ls /home
    user
    root@deb51:~# 
    

Great job, that concludes this lab!

Lab 5-2

su, sudo, and sudoers

This lab demonstrates how to work with the su, su -, and sudo commands. It also shows how to make a user an administrator of the system.

su is short for substitute user. If you ever need to login as a different user, the su command facilitates this. So for example, su sysadmin or su - sysadmin will login to the sysadmin account. One difference between the two is that su leaves you in the current directory that you were working in. su - puts you in the home directory of the user you are logging in as.

sudo has multiple meanings. First, sudo is a program that runs on Linux systems which associates permissions with users and groups. sudo is also a group that a user can be added to in Debian/Ubuntu and similar systems. By default, once added to the sudo group, the user becomes an administrator. Finally, sudo is a command. When it precedes another command it allows the command to be run as an administrator. For example, apt update requires sudo rights. So for a typical user who acts as an admin to do an update, that user must type sudo apt update. Any command that requires administrative privileges needs to be preceeded by sudo. The only case where this is not true is if you are logged in as root.

Users who have been given administrative privileges are known as a sudoers. That name is also the name of the sudo permissions file.

Let's demonstrate all this now. Once again, this is demonstrated on a Debian server currently logged in as root.

  • Use su to access another account

    Type su sysadmin. When you do so, it logs in as sysadmin, with no password required because you were already logged in as root. It leaves you in the same directory. Example:

    root@deb51:~# su sysadmin
    sysadmin@deb51:/root$ ls
    ls: cannot open directory '.': Permission denied
    sysadmin@deb51:/root$ 
    

    Note that we are logged in as sysadmin, but it placed us in the /root directory. That is the working directory for the root account. With su sysadmin we didn't actually open a new login shell. And we are restricted. If we type ls we will get a permission denied message because the sysadmin account cannot do anything in the root directory.

    Type logout or exit to logout of the sysadmin account and return to root.

  • Use su - to access that same account

    Now type su - sysadmin. Typing ls works (though there is no content). Now type pwd. When you do so you will find that the default directory is /home/sysadmin as shown below.

    root@deb51:~# su - sysadmin
    sysadmin@deb51:~$ ls
    sysadmin@deb51:~$ pwd
    /home/sysadmin
    sysadmin@deb51:~$ 
    

    This does actually create a new login shell. This is generally the preferred method, though not always.

    Logout of sysadmin and back to root.

    Note

    To login as root, use su or su -. The name "root" is not necessary.

  • Install sudo

    Many Linux distributions already have sudo installed. You can easily find out by typing sudo. If not installed, it will tell you the command is not recognized. Debian (running as a server) does not have sudo installed by default. To install it, as root, type the following:

    apt install sudo

  • Attempt to use sudo

    Login as sysadmin: su - sysadmin

    Type apt update. It won't work, because the sysadmin account would need to use the sudo command first.

    Type sudo apt update. It still won't work because the sysadmin account is not yet an actual administrator. It has not been added to the sudo group.

    Example below:

    root@deb51:~# su - sysadmin
    sysadmin@deb51:~$ apt update
    Reading package lists... Done
    E: Could not open lock file /var/lib/apt/lists/lock - open (13: Permission denied)
    E: Unable to lock directory /var/lib/apt/lists/
    W: Problem unlinking the file /var/cache/apt/pkgcache.bin - RemoveCaches (13: Permission denied)
    W: Problem unlinking the file /var/cache/apt/srcpkgcache.bin - RemoveCaches (13: Permission denied)
    sysadmin@deb51:~$ sudo apt update
    sudo: unable to resolve host deb51: No address associated with hostname
    
    We trust you have received the usual lecture from the local System
    Administrator. It usually boils down to these three things:
    
        #1) Respect the privacy of others.
        #2) Think before you type.
        #3) With great power comes great responsibility.
    
    [sudo] password for sysadmin: 
    sysadmin is not in the sudoers file.  This incident will be reported.
    

    Logout of sysadmin and back into root.

  • Add the sysadmin account to sudo and test

    So, as it stands, the sysadmin account is an admin in name only - not in actual privilege. We have to add that privilege. We do that by making sysadmin a sudoer. You could also phrase that as: adding sysadmin to the sudo group. This group was created automatically when we installed the sudo program.

    Issue the following command:

    usermod -aG sudo sysadmin

    That modifies the sysadmin account, and adds it to the sudo group. Now, it should have administrative privileges.

    Login as sysadmin again:

    su - sysadmin

    And attempt to update the system:

    sudo apt update

    The first time you use the sudo command, the system should request the user's password. Type it. The command should now work and the program will tell us how many packages can be updated. That's it, sysadmin now has administrative privileges. But only as long as the command sudo precedes the administrative command.

  • View the sudoers file

    The sudoers file is where we can specify privileges for groups and individual users. It is located at /etc/sudoers. However, the recommended way to modify the file is to use the visudo command. But this command will require administrative access, so as sysadmin, we would have to add sudo before the command. To do this, simply type:

    sudo visudo

    Example of visudo on a Debian Server

    #
    # This file MUST be edited with the 'visudo' command as root.
    #
    # Please consider adding local content in /etc/sudoers.d/ instead of
    # directly modifying this file.
    #
    # See the man page for details on how to write a sudoers file.
    #
    Defaults    env_reset
    Defaults    mail_badpass
    Defaults    secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
    
    # Host alias specification
    
    # User alias specification
    
    # Cmnd alias specification
    
    # User privilege specification
    root    ALL=(ALL:ALL) ALL
    
    # Allow members of group sudo to execute any command
    %sudo   ALL=(ALL:ALL) ALL
    
    # See sudoers(5) for more information on "#include" directives:
    
    #includedir /etc/sudoers.d
    

    Looking toward the bottom of the file, you will note that the root account has ALL permissions. So does the sudo group (referenced as %sudo). But this can be changed. The sudo group can be limited, or new groups can be created with their own permissions. Individual accounts can also be assigned particular permissions to the system.

    Note

    In Fedora/RHEL/CentOS systems, the %wheel group takes the place of %sudo. This applies to the sudoers file and if you want to apply administrative permissions to a user account. So for example:

    usermod -aG wheel sysadmin

    Tip

    By default sudo asks for the password of the user. It won't ask again for 5 minutes. To increase this timeout, add the following line to the sudoers file:

    Defaults:sysadmin timestamp_timeout=30

    That changes the timeout to 30 minutes for sysadmin. Modify it as you wish, but it is not suggested to modify it to 0 (which is infinite).

    This is just a primer. There is plenty more to users, groups, permissions, sudo, and so on. But this is the core of what is happening on a Debian or Ubuntu system. It's one of the more complicated concepts in the Linux operating system. If you can understand this, then you can understand just about anything in Linux.

Users and Passwords Part II

The default password settings are weak in most distributions of Linux. To secure the system, the settings should be modified. But first, let's do some analysis of a Debian server. Log in as root. First we'll look at the list of user accounts. This can be found in the /etc/passwd file. Even though the name is "passwd", it doesn't store passwords. View it now:

cat /etc/passwd

You should see a list of user accounts and system accounts. The root account is in the beginning of the list. Newly created accounts are at the end. For example, the line item that has the sysadmin account will look similar to this:

sysadmin:x:1001:1001:,,,:/home/sysadmin:/bin/bash

This shows us that the username is sysadmin. "x" is an older setting, it used to show the password location but is not used anymore. 1001 shows us the User ID and the Group ID. Then we see the home directory and the shell being used (which is bash). So keep in mind that the passwd file does not actually show password information. It only shows user account information.

To see password-based information, we use the /etc/shadow file. View it now:

cat /etc/shadow

This also shows a list of accounts, but now we get password-based information. For example:

sysadmin:$6$uIxm1E1ZzM1i6wR9$nafysqSgqg6rJNE2IlPGK4tPgMWBSIcpFuqhKtPWRZKYyrBs1m2bUSt/PGDfZWDPCkisK7rhk1Qg2Lpjcpxdp/:18729:0:99999:7:::

Note

You can also view the type of hash algorithm being used by accessing the /etc/pam.d/common-password file. Look for the line similar to this:

password    [success=1 default=ignore]  pam_unix.so obscure sha512

This shows once again that we are using SHA512.

Lab 5-3

Working with Password Settings

In this lab we'll show how to change the default password settings and criteria on a Debian server as root.

  • Use chage to change password settings

    Type the following command:

    chage sysadmin

    This command allows us to change the age requirements for a password as shown below:

    root@deb51:~# chage sysadmin
    Changing the aging information for sysadmin
    Enter the new value, or press ENTER for the default
    
        Minimum Password Age [0]: 0
        Maximum Password Age [99999]: 365
        Last Password Change (YYYY-MM-DD) [2021-04-12]: 
        Password Expiration Warning [7]: 
        Password Inactive [-1]: 
        Account Expiration Date (YYYY-MM-DD) [-1]: 2021-12-31
    root@deb51:~# 
    

    Here the maximum password age was changed from 99999 days to 365 days. Also, there is an account expiration date at the end of the year 2021. After December 31, 2021, the user account sysadmin will not be able to login. The other settings were not modified.

    Tip

    While this is a good command to know, it is not used quite as often today. It has a lot of additional options which can be useful though. For example, to set a user's password to expire (make it a zero-day password) you can issue the following command:

    chage -d 0 sysadmin

    This will require the sysadmin account to change its password on next login.

  • Modify password minimum length and criteria

    In Debian and Ubuntu you can change the minimum password length and other criteria in /etc/pam.d/common-password. Open the file now:

    vim /etc/pam.d/common-password

    Find the line that we located earlier:

    password    [success=1 default=ignore]  pam_unix.so obscure sha512
    

    To change the minimum password length, add minlen=12 to the end of that line so that it looks like this:

    password    [success=1 default=ignore]  pam_unix.so obscure sha512 minlen=12
    

    Now, instead of a 6 character password minimum, Debian will require 12 character passwords from users. Increase the number as you see fit, or based on organizational policies!

    You can also add criteria such as requiring uppercase letters and special characters. First, on Debian and Ubuntu, password quality has to be installed.

    apt install libpam-pwquality

    Once done, the common-password file should now show a new line above the previous line that we modified that says "pam_pwquality.so".

    Now you can have additional options to the new line ending in "pam_pwquality.so":

    • To require uppercase letters: ucredit=1

    • To require lowercase letters: dcredit=1

    • To require special (or other) characters: ocredit=1

    • To require that a certain amount of password criteria be included: minclass=2

    • To specifically require a particular amount of characters, use the minus sign. For example, ocredit=-1. Note the -1 instead of a 1.

    Here's an example of a configuration that requires 12 characters, a minimum of 1 uppercase, 1 lowercase, and 2 special characters.

    # here are the per-package modules (the "Primary" block)
    password    requisite           pam_pwquality.so retry=3 ucredit=1 dcredit=1 ocredit=-2 minclass=3
    password    [success=1 default=ignore]  pam_unix.so obscure use_authtok try_first_pass sha512 minlen=12
    

    Warning

    Be sure to test this with a standard user account, and not the root account! It's easy to forget a password!

    Note

    This portion of the lab will work differently on Fedora/RHEL/CentOS systems. There you use the Authselect tool.

  • Change the password expiration globally

    Previously, we changed the password expiration for a single user account with the chage file. Now, let's change it for all users.

    As root, open the /etc/login.defs file:

    vim /etc/login.defs

    Search for the line that says PASS_MAX_DAYS. Modify it as you see fit. Example below:

    # Password aging controls:
    #
    #   PASS_MAX_DAYS   Maximum number of days a password may be used.
    #   PASS_MIN_DAYS   Minimum number of days allowed between password changes.
    #   PASS_WARN_AGE   Number of days warning given before a password expires.
    #
    PASS_MAX_DAYS   365
    PASS_MIN_DAYS   0
    PASS_WARN_AGE   7
    

    I thought that 274 years was a little too long. So here the PASS_MAX_DAYS setting was changed from 99999 days to 365 days. But this only applies to new accounts.

That wraps up this lab, and Part V of this lab guide.

Part VI: Securing SSH

SSH is a heavily used tool. However, it is vulnerable (like everything else). This section describes how to secure an SSH server.

Remember that a typical SSH connection is performed from one computer to another. For example, if computerA wanted to SSH into computerB then the user at computerA would type:

ssh user@computerB

If the user at computerA knows the password of the user account at computerb, then access will be granted. However, while passwords offer some security, it's more secure to use cryptographic keys.

Lab 6-1

Creating and Distributing SSH Keys

In this lab we'll build an SSH key on a Debian client (as a typical user), distribute it to a Debian server, and then SSH into that server from the client using the key we just made.

To SSH into a system using a key, you actually need to create a key pair. The first key is called a private key and it resides at the computer where the key pair is built. The second key is called a public key, and it resides at the SSH server, meaning the remote computer that will be connected to.

When you attempt to SSH into the remote system, that system presents its public key. If it matches the private key stored at the local computer, then the connection is allowed. If it doesn't match (for example, a rogue or malicious system) then the connection will be denied.

  • Create an RSA-based key pair

    To create an SSH key pair, login to the client as a typical user, and type the following:

    ssh-keygen

    When it prompts you, press enter to save the key pair to the default location. It's also highly recommended to select and confirm a complex passphrase to protect the keypair. The process will be very similar to the following:

    user@deb52:~$ ssh-keygen
    Generating public/private rsa key pair.
    Enter file in which to save the key (/home/user/.ssh/id_rsa): 
    Enter passphrase (empty for no passphrase): 
    Enter same passphrase again: 
    Your identification has been saved in /home/user/.ssh/id_rsa.
    Your public key has been saved in /home/user/.ssh/id_rsa.pub.
    The key fingerprint is:
    SHA256:amG7G71T2CxDiruTOhO+1niqtV7X6Zer9B3BGjpWKTQ user@deb52
    The key's randomart image is:
    +---[RSA 2048]----+
    |                 |
    |                 |
    |        E        |
    |       ... o     |
    |     .ooS++ o    |
    |  . ...*+=+o .   |
    | ..+.o* O+...    |
    | .*o*o *.+o. .   |
    |.+*B.oo.++o..    |
    +----[SHA256]-----+
    user@deb52:~$ 
    

    Danger

    Pressing enter for a blank passphrase is insecure. For added security, use a passphrase. The more length and complexity the better. This protects the key pair that you have created. Think about it: If someone was to gain access to your computer (internally or externally), and more importantly to your user account, then that person could potentially gain access to all the systems that you would normally access via SSH.

    Note

    When you do use a passphrase fo the SSH key pair, you will be required to type it the first time you connect to a remote host using the SSH key. Subsequent attempts during a single login session will not require it unless you are doing double SSH: meaning if you are SSH'd into the client, and then are SSH'ing from there into another system. However, all of this is configurable at the system where the keys were created in the /etc/ssh/ssh_config file. Just be careful of how loose you are with security!

  • View the SSH key pair

    The key pair is saved in a hidden directory. Type ls -a to see it. The directory name is .ssh. Access that directory: cd .ssh. Then type ls to view the contents. The procedure should be similar to the following:

    user@deb52:~$ ls -a
    .              .bash_logout           .cache   Documents         .gnupg         .local    Music           Pictures  .qt             .ssh       .viminfo
    ..             .bash-powerline-ng.sh  .config  Downloads         .ICEauthority  .mono     .nmcli-history  .profile  .recently-used  Templates  .wget-hsts
    .bash_history  .bashrc                Desktop  .fancy-prompt.sh  .lesshst       .mozilla  .nx             Public    script.sh       Videos     .Xauthority
    user@deb52:~$ cd .ssh
    user@deb52:~/.ssh$ ls
    id_rsa  id_rsa.pub  known_hosts
    user@deb52:~/.ssh$ 
    

    You can see three files inside of .ssh: id_rsa (which is the private key), id_rsa.pub (which is the public key to be copied to remote hosts), and known_hosts, which contains the list of known hosts that you have connected to in the past.

    Tip

    You can make bigger keys if your organization requires it. A typical RSA-based SSH key is 2048-bit. Let's say you needed 3072-bit. You could type the following:

    ssh-keygen -b 3072

    Remember to use different names/directories when creating subsequent keys.

  • Copy the public key to a remote host

    Now that our key pair is created, we can copy the public key of our key pair to a remote host. In this lab the key will be copied to a Debian server, making use of the user account that exists there.

    ssh-copy-id user@10.0.2.51

    You will be required to type the password of the user account at the remote computer, but otherwise, that's it. You don't have to specify a directory, it will copy it to the default .ssh directory in the user accounts home directory. Just make sure that the results show that 1 key was added. Example:

    user@deb52:~/.ssh$ ssh-copy-id user@10.0.2.51
    /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/user/.ssh/id_rsa.pub"
    /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
    /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
    user@10.0.2.51's password: 
    
    Number of key(s) added: 1
    

    Now try logging into the machine, with: "ssh 'user@10.0.2.51'" and check to make sure that only the key(s) you wanted were added.

  • SSH into the remote host

    Now, we can SSH into the remote host to take control of it.

    ssh user@10.0.2.51

    The command is the same as normal. For the first time, the local system will require that we enter the SSH key passphrase (if we set one). Example:

    user@deb52:~$ ssh user@10.0.2.51
    Enter passphrase for key '/home/user/.ssh/id_rsa': 
    Linux deb51 4.19.0-16-amd64 #1 SMP Debian 4.19.181-1 (2021-03-19) x86_64
    
    The programs included with the Debian GNU/Linux system are free software;
    the exact distribution terms for each program are described in the
    individual files in /usr/share/doc/*/copyright.
    
    Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
    permitted by applicable law.
    Last login: Mon Apr 12 17:49:33 2021 from 10.0.2.52
    user@deb51:~$ 
    

    As you can see, we are using a system deb52 and SSH'd into a remote server deb51.

    That's it. Now we are logged in using SSH keys. This way, we don't have to send a user's password over the network, and instead rely on the much more secure SSH key process.

Lab 6-2

Securing the SSH Server

Using SSH by itself is much more secure than older alternatives such as Telnet. But SSH has its own set of vulnerabilities. This section demonstrates how to make SSH more secure than it already is. In this lab we'll increase the SSH security of a Debian server in several ways. The bulk of these are configurations that are done in the /etc/ssh/sshd_config file.

  1. Change the SSH inbound port

    An SSH server uses port 22 inbound by default. This is well-known. However, many port scans that are peformed by would be invaders only scan for the first 1000 ports of a system. If we change the port to something less known that is above the first 1000 ports, then it can increase the security of the server.

    On the Debian server, open the sshd_config file:

    vim /etc/ssh/sshd_config

    Find the line that indicates the port number. It should be near the beginning of the file. By default it is commented out, but it will say #Port 22.

    As an example, we'll change it to port 2222. So change the line that reads #Port 22 to:

    Port 2222

    Here's an example of the first 15 lines of the file:

    #   $OpenBSD: sshd_config,v 1.103 2018/04/09 20:41:22 tj Exp $
    
    # This is the sshd server system-wide configuration file.  See
    # sshd_config(5) for more information.
    
    # This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin
    
    # The strategy used for options in the default sshd_config shipped with
    # OpenSSH is to specify options with their default value where
    # possible, but leave them commented.  Uncommented options override the
    # default value.
    
    Port 2222
    #AddressFamily any
    #ListenAddress 0.0.0.0
    #ListenAddress ::
    

    Save and close the file.

    Then, restart the sshd service:

    systemctl restart sshd

    Now, on the Debian client, attempt to ssh into the server using the new port:

    ssh user@10.0.2.51 -p 2222

    The -p option specifies the port to use. You should see results similar to the following:

    user@deb52:~$ ssh user@10.0.2.51 -p 2222
    Enter passphrase for key '/home/user/.ssh/id_rsa': 
    Linux deb51 4.19.0-16-amd64 #1 SMP Debian 4.19.181-1 (2021-03-19) x86_64
    
    The programs included with the Debian GNU/Linux system are free software;
    the exact distribution terms for each program are described in the
    individual files in /usr/share/doc/*/copyright.
    
    Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
    permitted by applicable law.
    Last login: Mon Apr 12 17:52:58 2021 from 10.0.2.52
    user@deb51:~$ 
    

    After successfully connecting, log back out.

  2. Disable password-based SSH

    Although our client will now connect to the server with a key instead of a password, the server can still be accessed by other systems and other users via password. We can disable password-based SSH altogether on the server.

    As root on the Debian server, open /etc/ssh/sshd_config again and find the line that says:

    #PasswordAuthentication yes

    and uncomment it and change it to:

    PasswordAuthentication no

    Save and exit the file. This will disallow password-based authentication to that SSH server across the board.

  3. Restrict access by creating an exclusive group

    Don't just allow anyone to connect! By creating an exclusive group, we specify and organize the users that are allowed to connect.

    Create a new group. For example:

    addgroup ssh-allowed

    Now, add the user account to the new group:

    adduser user ssh-allowed

    Verify the existence of "user" within the "ssh-allowed" group:

    groups user

    Open the SSH Server config file once again:

    vim /etc/ssh/sshd_config

    and add the group to the end of the config file:

    AllowGroups ssh-allowed

    Tip

    You could also echo that line to the file without opening it:

    echo "AllowGroups ssh-allowed" >> /etc/ssh/sshd_config

    Just be sure to append the file with a double >> . This applies to any lines that we add to config files, but for these labs I want you to open and get to know the configuration files.

    Now, test the SSH connection to the server with the user account. It should work.

    Warning

    Don't forget that we changed the port to 2222!

    Next, remove the user acount from the ssh-allowed group.

    deluser user ssh-allowed

    Now attempt to SSH in again. It should fail, as all other accounts that are not members of "ssh-allowed" will fail.

  4. Disable root login altogether

    While root cannot login to an openSSH server via password by default, the root account can still connect via a key. We take that ability away by modifying the following line in the sshd_config file:

    PermitRootLogin prohibit-password

    to:

    PermitRootLogin no

  5. Lower the maximum amount of authentication attempts

    When a user connects to an SSH server with a password, the user get's 5 attempts to type the correct password. (The actual number listed is 6.) We can lower thisnumber to 4, which effectively allows the user 3 attempts. So, three strikes and you're out!

    Find the line: MaxAuthTries and change it from 6 to 4.

There is plenty more that you can do. Some things to consider include:

  • Lowering the login grace time
  • Configure SSH timeouts (so that sessions don't last forever)
  • Proper key management

And much more.

Info

For more information about SSH guidelines, see this NIST document:

https://nvlpubs.nist.gov/nistpubs/ir/2015/nist.ir.7966.pdf

Summary

Think of how many hackers attempt to get into servers that allow inbound SSH connections. There are literally millions, not to mention bots. So... you could argue that there can't be enough protection for an SSH server.

So some fundamental ways to increase the security of the SSH server are to: use a different and less known port; disable password-based SSH; restrict SSH access by user and group; disable root login; reduce the maximum authentication attempts; and set up SSH timeouts.

Another concept mentioned is key management. Security companies find thousands (if not millions) of floater keys on corporate networks all the time. That's because there often is no proper key management (SSH certificate authority, or other solution) and it results in SSH key sprawl - where the admins literally don't know where many of the keys are.

Most of these concepts don't just apply to SSH servers, they apply to just about any "server" or mover of information. It could be a switch, router, PC, and of course, your actual traditional servers.

And these security techniques only scratch the surface of what can be accomplished. Always be looking to improve on the security of your servers.


That's it for the lab guide for Day 2! Hope you enjoyed it.