Skip to content

110.1 Perform security administration tasks

Weight: 3

Candidates should know how to review system configuration to ensure host security in accordance with local security policies.

Objectives

  • Audit a system to find files with the suid/sgid bit set.
  • Set or change user passwords and password aging information.
  • Being able to use nmap and netstat to discover open ports on a system.
  • Set up limits on user logins, processes and memory usage.
  • Determine which users have logged in to the system or are currently logged in.
  • Basic sudo configuration and usage.

Terms

find, passwd, fuser, lsof, nmap, chage, netstat, sudo, /etc/sudoers, su, usermod, ulimit, who, w, last

Becoming another user: su and sudo

su

su ("substitute user") switches your session to another account. It asks for the target user's password: to become root, you need root's password.

carol@debian:~$ whoami
carol
carol@debian:~$ su -
Password:
root@debian:~# whoami
root
root@debian:~# exit
logout
carol@debian:~$
Command Gives you
su - mimi a login shell as mimi, with mimi's environment
su - or su - root a login shell as root (the name is optional for root)
su root, but keeping your old environment

The - loads the target user's environment. Without it you stay in your own environment, as the prompt shows:

carol@debian:~$ su
Password:
root@debian:/home/carol#

Sharing the root password with many people is a bad security practice. That is what sudo avoids.

sudo

sudo runs one command as root (or as another user), so sudo ls runs ls as root. It has two big advantages over su:

  1. It asks for your own password, not root's. Whether you are allowed is decided by a security policy, the sudoers files /etc/sudoers and /etc/sudoers.d/*.
  2. It raises privileges for one command, instead of opening a whole root shell.
carol@debian:~$ sudo whoami
root
carol@debian:~$ sudo -u mimi whoami
mimi

sudo -u user command runs as that user; without -u it runs as root. After you type your password, sudo remembers it for 15 minutes per user and terminal. Defaults timestamp_timeout=1 in /etc/sudoers changes that to one minute.

sudo su - combines the two: sudo runs su - as root, so you get a root login shell by typing your own password.

/etc/sudoers

The sudoers file says who may run what, as whom, and on which machines:

$ sudo cat /etc/sudoers
#
# 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.
#
Defaults    env_reset
Defaults    mail_badpass
Defaults    secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

# User privilege specification
root    ALL=(ALL:ALL) ALL

# Members of the admin group may gain root privileges
%admin  ALL=(ALL) ALL

# Allow members of group sudo to execute any command
%sudo   ALL=(ALL:ALL) ALL

#includedir /etc/sudoers.d

Every rule has the same shape:

 root    ALL  =  (ALL:ALL)    ALL
   |      |         |          |
  who   hosts   as user:group  commands

So root ALL=(ALL:ALL) ALL means: root, from all hosts, as any user and any group, may run all commands. A % in front of a name means a group, so %sudo is every member of the group sudo.

You can be much more precise. To let carol check Apache's status, and nothing else:

carol   ALL=(ALL:ALL) /usr/bin/systemctl status apache2

Without having to type a password:

carol   ALL=(ALL:ALL) NOPASSWD: /usr/bin/systemctl status apache2

Two more examples of the same idea:

web     ALL=(root) /usr/bin/systemctl     # 'web' may run only this, as root
web     ALL=(root) NOPASSWD: /usr/bin/systemctl restart nginx

Only on host 192.168.1.7, and only as user mimi:

carol   192.168.1.7=(mimi) /usr/bin/systemctl status apache2
carol@debian:~$ sudo -u mimi systemctl status apache2
● apache2.service - The Apache HTTP Server
   Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: enabled)
   Active: active (running) since Tue 2020-06-09 13:12:19 CEST; 29min ago

To give a user full admin rights, the simplest way is to add them to the admin group: sudo on Debian systems, wheel on Red Hat systems. Use -a, or the user loses all other groups:

root@debian:~# usermod -aG sudo carol

Always edit with visudo

A mistake in /etc/sudoers can lock everyone out of sudo. Edit it with visudo, never directly with an editor. visudo checks the syntax before saving. It opens your default editor, which you can change with Defaults editor=/usr/bin/nano in the file, or for one run with EDITOR=/usr/bin/nano visudo.

Aliases

For bigger setups, sudoers can name groups of hosts, users and commands:

Host_Alias SERVERS = 192.168.1.7, server1, server2
User_Alias REGULAR_USERS = john, mary, alex
User_Alias PRIVILEGED_USERS = mimi
User_Alias ADMINS = carol, %sudo, PRIVILEGED_USERS, !REGULAR_USERS
Cmnd_Alias SERVICES = /usr/bin/systemctl *

ADMINS  SERVERS=SERVICES
Alias Lists
Host_Alias host names, IP addresses, networks, netgroups (+name)
User_Alias user names, groups (%group), netgroups (+name). ! excludes
Cmnd_Alias commands. * means any arguments. A directory means every file in it
Runas_Alias users to run as, also by UID

The last line reads: every user in ADMINS may run any SERVICES command on any SERVERS host.

Who is logged in: who, w and last

Command Shows
who the users logged in now
w the users logged in now, and what they are doing
last the login history, newest first, including people who have logged out
lastb the failed login attempts

who

root@debian:~# who
carol    pts/0        2020-06-06 17:16 (192.168.1.4)
mimi     pts/1        2020-06-06 17:28 (192.168.1.4)

The columns are user, terminal, login date and time, and the host they came from. Useful options:

Option Shows
-b the time of the last boot
-r the current runlevel
-H column headings

A pts terminal is a pseudo terminal, like an SSH session or a terminal window; tty is a real console. Each shell window counts as a separate login.

w

w adds a summary line and what each user is running:

root@debian:~# w
 17:56:12 up 40 min,  2 users,  load average: 0.04, 0.12, 0.09
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
carol    pts/0    192.168.1.4      17:16    1.00s  0.15s  0.05s sshd: carol [priv]
mimi     pts/1    192.168.1.4      17:28   15:08   0.05s  0.05s -bash

The top line is the time, how long the system has been up, the number of users, and the load average over 1, 5 and 15 minutes (as in uptime).

Column Is
IDLE how long since the user last typed something
JCPU CPU time used by all processes on that terminal
PCPU CPU time used by the current process
WHAT the command running now

w mimi and who both accept a user name.

last

who and w show only people logged in now. last shows the history, read from /var/log/wtmp:

root@debian:~# last
carol    pts/0        192.168.1.4      Sat Jun  6 14:25   still logged in
reboot   system boot  4.19.0-9-amd64   Sat Jun  6 14:24   still running
mimi     pts/0        192.168.1.4      Sat Jun  6 12:07 - 14:24  (02:16)
reboot   system boot  4.19.0-9-amd64   Sat Jun  6 12:07 - 14:24  (02:17)
(...)
wtmp begins Sun May 31 14:14:58 2020

mimi logged in at 12:07 and out at 14:24, a session of 2 hours 16 minutes. The reboot lines show each boot, with the kernel version and how long the system ran. last carol shows one user only. Failed logins are kept in /var/log/btmp; read them with lastb, or last -f /var/log/btmp.

Passwords and password aging

passwd -S shows the status of an account:

carol@debian:~$ passwd -S
carol P 12/07/2019 0 99999 7 -1
Field Here Means
1 carol the user name
2 P the password state: P usable password, L locked, NP no password
3 12/07/2019 the date of the last change
4 0 minimum days between changes. 0 means any time
5 99999 maximum days the password is valid. 99999 means it never expires
6 7 days of warning before it expires
7 -1 inactive days after expiry before the account is locked. -1 means no limit

Root uses passwd for basic account control:

Command Does
passwd carol set carol's password
passwd -l carol lock the password
passwd -u carol unlock it
passwd -e carol expire it: carol must choose a new one at next login
passwd -d carol delete the password

Here root locks carol's password, carol then cannot change it, and root unlocks it:

root@debian:~# passwd -l carol
passwd: password expiry information changed.
root@debian:~# su - carol
carol@debian:~$ passwd -S
carol L 05/31/2020 0 99999 7 -1
carol@debian:~$ passwd
Changing password for carol.
Current password:
passwd: Authentication token manipulation error
passwd: password unchanged
carol@debian:~$ exit
logout
root@debian:~# passwd -u carol
passwd: password expiry information changed.

usermod -L carol and usermod -U carol lock and unlock too, and usermod -f 3 carol sets 3 inactive days after the password expires.

chage

chage ("change age") is the main tool for aging. Anyone can list their own settings with -l; changing them needs root:

carol@debian:~$ chage -l carol
Last password change                               : Aug 06, 2019
Password expires                                   : never
Password inactive                                  : never
Account expires                                    : never
Minimum number of days between password change     : 0
Maximum number of days between password change     : 99999
Number of days of warning before password expires  : 7

With only a user name, root gets an interactive prompt for each value:

root@debian:~# chage carol
Changing the aging information for carol
Enter the new value, or press ENTER for the default

        Minimum Password Age [0]:
        Maximum Password Age [99999]:
        Last Password Change (YYYY-MM-DD) [2020-06-01]:
        Password Expiration Warning [7]:
        Password Inactive [-1]:
        Account Expiration Date (YYYY-MM-DD) [-1]:
Option Long form Example Sets
-m --mindays chage -m 5 carol minimum days between changes (0 = any time)
-M --maxdays chage -M 30 carol maximum days the password is valid (99999 = never expires)
-d --lastday chage -d 0 carol the last change date. 0 forces a new password at next login
-W --warndays chage -W 7 carol days of warning before expiry
-I --inactive chage -I 10 carol inactive days after expiry before the account is locked (same as usermod -f)
-E --expiredate chage -E 2050-12-13 carol the date the account is locked

Finding SUID and SGID files

Besides read, write and execute, files can carry special permission bits:

Bit Number Shown as Effect
SUID 4000 s in the owner's execute place the program runs with the rights of the file's owner
SGID 2000 s in the group's execute place on a file: runs with the rights of the file's group. On a directory: new files inherit the directory's group

A lowercase s means the execute bit is also set. An uppercase S means it is not.

passwd is the classic SUID program. It must write to /etc/shadow, which only root may change, even when a normal user runs it. The SUID bit makes it run as its owner, root:

carol@debian:~$ ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 63736 Jul 27  2018 /usr/bin/passwd

Setting SGID on a directory, by adding 2 in front of the normal mode:

carol@debian:~$ ls -ld shared_directory
drwxr-xr-x 2 carol carol 4096 May 30 23:55 shared_directory
carol@debian:~$ sudo chmod 2755 shared_directory/
carol@debian:~$ ls -ld shared_directory
drwxr-sr-x 2 carol carol 4096 May 30 23:55 shared_directory

Why audit them? An SUID root program gives root's rights to whoever runs it. Imagine an attacker who got root once and set SUID on a copy of vi under an innocent name: from then on any user could edit any file as root. So check now and then which SUID and SGID files exist, and that each one should be there. An unexpected suid binary, especially a shell or editor, is a red flag.

find -perm searches by permission. The prefix in front of the value changes the meaning:

Form Finds files with
-perm 4000 exactly this mode (SUID and nothing else)
-perm -4000 at least these bits (SUID, plus any other permissions)
-perm /6000 any of these bits (SUID or SGID)

The value can be numeric or symbolic: -perm -u+s is the same as -perm -4000, and -perm -g+s the same as -perm -2000.

carol@debian:~$ sudo find /usr/bin -perm -4000
/usr/bin/umount
/usr/bin/newgrp
/usr/bin/gpasswd
/usr/bin/chfn
/usr/bin/mount
/usr/bin/passwd
/usr/bin/chsh
/usr/bin/sudo
/usr/bin/su
carol@debian:~$ sudo find /usr/bin -perm /6000
/usr/bin/dotlock.mailutils
/usr/bin/umount
/usr/bin/newgrp
/usr/bin/wall
/usr/bin/ssh-agent
/usr/bin/chage
(...)
/usr/bin/crontab
/usr/bin/su

To audit the whole system, search from /:

$ sudo find / -perm -u+s

Limiting resources: ulimit

ulimit limits the resources a user's shell and its programs may use. Each limit has two values:

  • the soft limit (-S), the one in force. A user may raise it, up to the hard limit.
  • the hard limit (-H), the ceiling. Only root can raise it. Users can only lower it.

ulimit -a shows all soft limits (-Ha the hard ones):

$ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 47457
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 47457
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

Some of the resources:

Option Limits
-f the size of files the shell and its children may write
-u the number of processes for one user
-t CPU time per process, in seconds
-v virtual memory
-m resident memory (RSS, the part in RAM)
-l memory that may be locked
-n open files
-b socket buffer size

Reading a limit: give -S or -H and the resource. Without either, you get the soft value:

carol@debian:~$ ulimit -u
10000
carol@debian:~$ ulimit -Su
10000
carol@debian:~$ ulimit -Hu
15672

Setting a limit: without -S or -H, both are set. The value can be a number, or soft, hard or unlimited:

root@debian:~# ulimit -f 500
root@debian:~# ulimit -Sf
500
root@debian:~# ulimit -Hf
500
root@debian:~# ulimit -Sf 200
root@debian:~# ulimit -Sf
200
root@debian:~# ulimit -Hf
500

ulimit -t 1 would limit every process in this shell to one second of CPU time; a process that uses more is killed. CPU time is not clock time: time firefox shows how much CPU a program really used.

ulimit is a Bash builtin, so it has no man page of its own (see man bash), and its changes last only for the current shell.

/etc/security/limits.conf

For limits that last, and for limits on other users, use /etc/security/limits.conf. It protects a machine from a runaway process or a fork bomb. Each line is:

<domain>   <type>   <item>   <value>
Field Can be
domain a user name, @group, * for everyone (group and * limits do not apply to root)
type soft, hard, or - for both
item what to limit, see below
value the limit

Common items: nproc (number of processes), maxlogins (simultaneous logins for this user), maxsyslogins (logins on the whole system), fsize (file size), nofile (open files), cpu (CPU time in minutes), as (address space), core (core file size), priority, nice.

#<domain>      <type>  <item>         <value>
*               soft    core            0
root            hard    core            100000
@student        hard    nproc           20
@faculty        soft    nproc           20
@faculty        hard    nproc           50
ftp             hard    nproc           0
@student        -       maxlogins       4

So every student may run at most 20 processes and log in at most 4 times at once.

Finding open ports

Every open port is a door into the machine, and malware often opens one so an attacker can talk to it. Check your open ports regularly. Four tools do it: lsof, fuser, netstat and nmap.

lsof

lsof ("list open files") lists every open file, and on Linux network connections are files too. -i shows the network ones:

root@debian:~# lsof -i
COMMAND   PID     USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
dhclient  357     root    7u  IPv4  13493      0t0  UDP *:bootpc
sshd      389     root    3u  IPv4  13689      0t0  TCP *:ssh (LISTEN)
sshd      389     root    4u  IPv6  13700      0t0  TCP *:ssh (LISTEN)
apache2   399     root    3u  IPv6  13826      0t0  TCP *:http (LISTEN)
apache2   401 www-data    3u  IPv6  13826      0t0  TCP *:http (LISTEN)
sshd      557     root    3u  IPv4  14701      0t0  TCP 192.168.1.7:ssh->192.168.1.4:60510 (ESTABLISHED)
sshd      569    carol    3u  IPv4  14701      0t0  TCP 192.168.1.7:ssh->192.168.1.4:60510 (ESTABLISHED)

You see the program, PID, user, and whether each socket is listening or connected. Here SSH and Apache listen, bootpc is the DHCP client, and there is one SSH connection. Filters:

Command Shows
lsof -i all network files
lsof -i4, lsof -i6 IPv4 only, IPv6 only
lsof -i :22 port 22 only
lsof -i@192.168.1.7 connections of that address
lsof -i@192.168.1.7:22,80 that address, ports 22 and 80 (ranges with -)

fuser

fuser ("file user") shows which processes use a file, and how. With -v (verbose) you get a table:

root@debian:~# fuser -v .
                     USER        PID ACCESS COMMAND
/root:               root        580 ..c.. bash

The ACCESS letters: c current directory, e executable being run, f open file, F open file for writing, r root directory, m mmap'ed file or shared library.

With -n you name a network port and protocol, which answers "who is using port 80?":

root@debian:~# fuser -vn tcp 80
                     USER        PID ACCESS COMMAND
80/tcp:              root        402 F.... apache2
                     www-data    404 F.... apache2
                     www-data    405 F.... apache2

The short form fuser 22/tcp -v works too. fuser -k 80/tcp kills the processes using that port.

netstat

netstat prints network statistics. With no options it lists active connections and Unix sockets, which is long, so pipe it to less. The useful options:

Option Shows
-l listening sockets only
-t TCP
-u UDP
-a all, listening and connected
-n numbers instead of names (22 instead of ssh)
-e extra information: the user and inode
-p the program using each socket
carol@debian:~$ netstat -lt
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 0.0.0.0:ssh             0.0.0.0:*               LISTEN
tcp        0      0 localhost:smtp          0.0.0.0:*               LISTEN
tcp6       0      0 [::]:http               [::]:*                  LISTEN
tcp6       0      0 [::]:ssh                [::]:*                  LISTEN
carol@debian:~$ netstat -uten
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       User   Inode
tcp        0      0 192.168.1.7:22          192.168.1.4:39144       ESTABLISHED 0      15103

Without -l you see the established connections; with -n, ssh became 22. A popular combination is netstat -tuna: TCP and UDP, all sockets, numeric:

$ netstat -tuna
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN
tcp        0      0 192.168.1.35:49574      173.194.122.231:443     ESTABLISHED
udp        0      0 0.0.0.0:5353            0.0.0.0:*

LISTEN lines are servers waiting for connections. ESTABLISHED lines are open connections. 0.0.0.0 means any address: the web server on port 80 accepts connections from anywhere, while the database on 3306 listens only on 127.0.0.1, the machine itself. ss (109.3) does the same job with the same options.

nmap

nmap (network mapper) is a port scanner: it tests a machine from the outside, the way an attacker would. By default it checks 1000 ports:

root@debian:~# nmap localhost
Starting Nmap 7.70 ( https://nmap.org ) at 2020-06-04 19:29 CEST
Nmap scan report for localhost (127.0.0.1)
Host is up (0.0000040s latency).
Other addresses for localhost (not scanned): ::1
Not shown: 998 closed ports
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Nmap done: 1 IP address (1 host up) scanned in 1.58 seconds
You scan Example
several hosts nmap localhost 192.168.1.7
a range of hosts nmap 192.168.1.3-20
a whole subnet nmap 192.168.1.* or nmap 192.168.1.0/24
a subnet but one host nmap 192.168.1.0/24 --exclude 192.168.1.7
one port nmap -p 22 localhost or nmap -p ssh localhost
several ports nmap -p ssh,80 localhost
a range of ports nmap -p 22-80 localhost
all 65535 ports nmap -p- localhost
the 100 most common ports, fast nmap -F localhost
with more detail nmap -v (or -vv)
root@debian:~# nmap -p 22-80 localhost
(...)
Not shown: 57 closed ports
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Another machine might show more, for example a database and a proxy:

# nmap localhost
PORT     STATE SERVICE
80/tcp   open  http
3306/tcp open  mysql
9050/tcp open  tor-socks

Comparing nmap (outside view) with netstat/ss (inside view) shows whether a service is exposed more widely than intended. Only scan machines you are allowed to.

More examples

The same commands once more, with other names and values, as a quick reference:

$ whoami
nagato
$ su -
Password:            # root's password
# whoami
root
$ w            # logged-in users and what each is running, plus load average
$ who          # logged-in users and their login time
$ last         # login history from /var/log/wtmp (most recent first)
$ last -f /var/log/btmp     # failed login attempts; watch for guessing
$ passwd              # change my own (asks for the current one)
# passwd nagato       # root sets another user's, no old password needed
$ passwd -S nagato    # status
nagato P 2023-09-14 0 99999 7 -1
# passwd -l nagato    # lock
# passwd -u nagato    # unlock
# passwd -e nagato    # expire now, forcing a change at next login
# chage -l nagato     # list current aging
# chage nagato        # interactive, prompts for each field
# chage -M 90 -m 7 -W 3 nagato # max 90 days, min 7, warn 3 days ahead
$ ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 63K Nov 23 2022 /usr/bin/passwd
# find / -perm -4000 -type f 2>/dev/null    # suid files (-u+s is the symbolic form)
/usr/bin/passwd
/usr/bin/sudo
# find / -perm -2000 -type f 2>/dev/null    # sgid files (-g+s)
# find / -perm /6000 -type f 2>/dev/null    # suid OR sgid (4000 + 2000)
$ ulimit -a          # all current limits
$ ulimit -u          # max user processes
$ ulimit -t 1        # cap CPU time at 1 second; a longer process is killed
$ ulimit -Sn 2048    # -S soft / -H hard pick which limit (here the soft open-files cap)
# /etc/security/limits.conf
@students  hard  nproc      20     # the students group: at most 20 processes
*          hard  nofile     8192   # everyone: at most 8192 open files
nagato     -     maxlogins  4      # nagato: at most 4 simultaneous logins
$ netstat -tuna
Proto Local Address        Foreign Address      State
tcp   0.0.0.0:80           0.0.0.0:*            LISTEN
tcp   127.0.0.1:3306       0.0.0.0:*            LISTEN
tcp   192.168.1.35:49574   173.194.122.231:443 ESTABLISHED
# lsof -i
COMMAND  PID  USER   NODE NAME
nginx  11095  root   TCP *:http (LISTEN)
# fuser 22/tcp -v
                USER  PID ACCESS COMMAND
22/tcp:         root    1 F....  systemd
# fuser -k 80/tcp       # -k: kill whatever is using this port

Summary

I review a host along several lines. I prefer sudo over su, because it grants rights per command and is logged. su switches to another user and needs that user's password, with su - loading their environment; sudo runs single commands as root with my own password, as allowed by /etc/sudoers and /etc/sudoers.d/. A sudoers rule reads who hosts=(user:group) commands, % marks a group, NOPASSWD: skips the password, and aliases (User_Alias, Host_Alias, Cmnd_Alias) name lists. I always edit it with visudo, and give full rights by adding a user to the sudo (or wheel) group with usermod -aG.

who and w show who is logged in now, w adding idle time and the running command, while last reads the login history from /var/log/wtmp, and lastb (or last -f /var/log/btmp) the failed attempts. passwd -S shows a password's state (P, L or NP) and aging, and as root I lock, unlock, expire or delete passwords with -l, -u, -e and -d, and change accounts with usermod. chage -l lists aging, and chage -M, -m, -W, -I, -E and -d 0 change it.

SUID (4000) makes a program run as its owner and SGID (2000) as its group, so I hunt dangerous permissions with find / -perm -4000 (or -u+s), -perm -2000 (or -g+s) or -perm /6000 for either. ulimit caps resources now: it sets soft and hard limits for the current shell, and users can only lower hard limits; permanent per-user or per-group limits such as nproc and maxlogins go in /etc/security/limits.conf.

I check exposure two ways. From inside, I use lsof -i (with :port or @address), fuser -vn tcp 80 to see which process holds a port, and netstat with -l, -t, -u, -n, -e and -p (or -tuna), or ss. From the network, nmap scans hosts, ranges and subnets, with -p choosing ports and -F a fast scan.