Project Update

This commit is contained in:
2022-12-05 10:09:01 +01:00
parent a86fff1b36
commit 80abe85b85
11 changed files with 2722 additions and 1573 deletions

311
lse.sh
View File

@@ -1,15 +1,15 @@
#!/bin/sh
# shellcheck disable=1003,1091,2006,2016,2034,2039
# vim: set ts=2 sw=2 sts=2 et:
# shellcheck disable=1003,1091,2006,2016,2034,2039,3043
# vim: set ts=2 sw=2 sts=2 fdm=marker fmr=#(,#) et:
# Author: Diego Blanco <diego.blanco@treitos.com>
# GitHub: https://github.com/diego-treitos/linux-smart-enumeration
#
lse_version="3.10"
lse_version="4.10nw"
#( Colors
##( Colors
#
# fg
#( fg
red='\e[31m'
lred='\e[91m'
green='\e[32m'
@@ -26,8 +26,8 @@ grey='\e[90m'
lgrey='\e[37m'
white='\e[97m'
black='\e[30m'
#
# bg
##)
#( bg
b_red='\e[41m'
b_lred='\e[101m'
b_green='\e[42m'
@@ -44,8 +44,8 @@ b_grey='\e[100m'
b_lgrey='\e[47m'
b_white='\e[107m'
b_black='\e[40m'
#
# special
##)
#( special
reset='\e[0;0m'
bold='\e[01m'
italic='\e[03m'
@@ -59,13 +59,13 @@ underline_off='\e[24m'
inverse_off='\e[27m'
conceil_off='\e[28m'
crossedout_off='\e[29m'
##)
#)
#( Globals
##( Globals
#
# user
lse_user_id="$UID"
[ -z "$lse_user_id" ] && lse_user_id="`id -u`"
lse_user_id="`id -u`"
lse_user="$USER"
[ -z "$lse_user" ] && lse_user="`id -nu`"
lse_pass=""
@@ -77,7 +77,8 @@ lse_arch="`uname -m`"
lse_linux="`uname -r`"
lse_hostname="`hostname`"
lse_distro=`command -v lsb_release >/dev/null 2>&1 && lsb_release -d | sed 's/Description:\s*//' 2>/dev/null`
[ -z "$lse_distro" ] && lse_distro="`(source /etc/os-release && echo "$PRETTY_NAME")2>/dev/null`"
[ -z "$lse_distro" ] && lse_distro="`(. /etc/os-release && echo "$PRETTY_NAME")2>/dev/null`"
lse_distro_codename="" # retrieved below with lse_get_distro_codename
# lse
lse_passed_tests=""
@@ -85,11 +86,12 @@ lse_executed_tests=""
lse_DEBUG=false
lse_procmon_data=`mktemp`
lse_procmon_lock=`mktemp`
lse_cve_tmp=''
# printf
printf "%s" "$reset" | grep -q '\\' && alias printf="env printf"
# internal data
#( internal data
lse_common_setuid="
/bin/fusermount
/bin/mount
@@ -176,12 +178,14 @@ lse_common_setuid="
/usr/sbin/usernetctl
/usr/sbin/uuidd
"
#regex rules for common setuid
#)
#( regex rules for common setuid
lse_common_setuid="$lse_common_setuid
/snap/core.*
/var/tmp/mkinitramfs.*
"
#critical writable files
#)
#( critical writable files
lse_critical_writable="
/etc/apache2/apache2.conf
/etc/apache2/httpd.conf
@@ -235,8 +239,13 @@ lse_critical_writable_dirs="
/root
"
#)
#( CVE list (populated by the lse packager)
lse_cve_list="
" #CVElistMARKER
#)
#)
#( Options
##( Options
lse_color=true
lse_alt_color=false
lse_interactive=true
@@ -247,16 +256,16 @@ lse_find_opts='-path /proc -prune -o -path /sys -prune -o -path /dev -prune -o'
lse_grep_opts='--color=always'
#)
#( Lib
cecho() {
##( Lib
cecho() { #(
if $lse_color; then
printf "%b" "$@"
else
# If color is disabled we remove it
printf "%b" "$@" | sed 's/\x1B\[[0-9;]\+[A-Za-z]//g'
fi
}
lse_recolor() {
} #)
lse_recolor() { #(
o_white="$white"
o_lyellow="$lyellow"
o_grey="$grey"
@@ -270,11 +279,11 @@ lse_recolor() {
lred="$red"
lgreen="$b_lgreen$black"
lcyan="$cyan"
}
lse_error() {
} #)
lse_error() { #(
cecho "${red}ERROR: ${reset}$*\n" >&2
}
lse_exclude_paths() {
} #)
lse_exclude_paths() { #(
local IFS="
"
for p in `printf "%s" "$1" | tr ',' '\n'`; do
@@ -282,8 +291,8 @@ lse_exclude_paths() {
p="${p%%/}"
lse_find_opts="$lse_find_opts -path ${p} -prune -o"
done
}
lse_set_level() {
} #)
lse_set_level() { #(
case "$1" in
0|1|2)
lse_level=$(($1))
@@ -293,8 +302,8 @@ lse_set_level() {
exit 1
;;
esac
}
lse_help() {
} #)
lse_help() { #(
echo "Use: $0 [options]"
echo
echo " OPTIONS"
@@ -319,6 +328,7 @@ lse_help() {
echo " pro: Processes related tests."
echo " sof: Software related tests."
echo " ctn: Container (docker, lxc) related tests."
echo " cve: CVE related tests."
echo " Specific tests can be used with their IDs (i.e.: usr020,sud)"
echo " -e PATHS Comma separated list of paths to exclude. This allows you"
echo " to do faster scans at the cost of completeness"
@@ -326,8 +336,8 @@ lse_help() {
echo " processes. A value of 0 will disable any watch (default: 60)"
echo " -S Serve the lse.sh script in this host so it can be retrieved"
echo " from a remote host."
}
lse_ask() {
} #)
lse_ask() { #(
local question="$1"
# We use stderr to print the question
cecho "${white}${question}: ${reset}" >&2
@@ -341,24 +351,24 @@ lse_ask() {
return 1
;;
esac
}
lse_request_information() {
} #)
lse_request_information() { #(
if $lse_interactive; then
cecho "${grey}---\n"
[ -z "$lse_user" ] && lse_user=`lse_ask "Could not find current user name. Current user?"`
lse_pass=`lse_ask "If you know the current user password, write it here to check sudo privileges"`
cecho "${grey}---\n"
fi
}
lse_test_passed() {
} #)
lse_test_passed() { #(
# Checks if a test passed by ID
local id="$1"
for i in $lse_passed_tests; do
[ "$i" = "$id" ] && return 0
done
return 1
}
lse_test() {
} #)
lse_test() { #(
# Test id
local id="$1"
# Minimum level required for this test to show its output
@@ -394,8 +404,8 @@ lse_test() {
# Print name and line
cecho "${white}[${l}${white}] ${grey}${id}${white} $name${grey}"
for i in $(seq $((${#name}+4)) 67); do
echo -n "."
for i in $(seq $((${#id}+${#name}+10)) 79); do
printf "."
done
# Check dependencies
@@ -445,8 +455,8 @@ lse_test() {
fi
return 0
fi
}
lse_show_info() {
} #)
lse_show_info() { #(
echo
cecho "${lcyan} LSE Version:${reset} $lse_version\n"
echo
@@ -470,12 +480,14 @@ lse_show_info() {
fi
cecho "${lblue}Architecture:${reset} $lse_arch\n"
echo
}
lse_serve() {
cecho "${green}=====================(${yellow} Current Output Verbosity Level: ${cyan}$lse_level ${green})======================${reset}"
echo
} #)
lse_serve() { #(
# get port
which nc >/dev/null || lse_error "Could not find 'nc' netcat binary."
local_ips="`ip a | grep -Eo 'inet ([0-9]{1,3}\.){3}[0-9]{1,3}' | cut -d' ' -f2`"
local_ips="`ip a | grep -Eo "inet ([0-9]{1,3}\.){3}[0-9]{1,3}" | cut -d' ' -f2`"
# Get a valid and non used port
port=`od -An -N2 -i /dev/random|grep -Eo '[0-9]+'`
@@ -506,8 +518,8 @@ lse_serve() {
done
# try nc with '-N' (openbsd), then ncat and then use '-q0' (traditional)
nc -l -N -p "$port" < "$0" >/dev/null 2>/dev/null || nc -l --send-only -p "$port" < "$0" >/dev/null 2>/dev/null || nc -l -q0 -p "$port" < "$0" >/dev/null
}
lse_header() {
} #)
lse_header() { #(
local id="$1"
shift
local title="$*"
@@ -530,8 +542,8 @@ lse_header() {
done
text="$text(${green} $title ${magenta})====="
cecho "$text${reset}\n"
}
lse_exit() {
} #)
lse_exit() { #(
local ec=1
local text="\n${magenta}=================================="
[ "$1" ] && ec=$1
@@ -539,18 +551,32 @@ lse_exit() {
cecho "$text${reset}\n"
rm -f "$lse_procmon_data"
rm -f "$lse_procmon_lock"
rm -f "$lse_cve_tmp"
exit "$ec"
}
lse_procmon() {
} #)
lse_procmon() { #(
# monitor processes
#NOTE: The first number will be the number of occurrences of a process due to
# uniq -c
local ps_args
local ps_busybox
if ps -V 2>&1 | grep -iq busybox; then
ps_args='-o pid,user,args'
ps_busybox=true
else
ps_args="-ewwwo start_time,pid,user:50,args"
ps_busybox=false
fi
while [ -f "$lse_procmon_lock" ]; do
ps -ewwwo start_time,pid,user:50,args
if $ps_busybox; then
ps $ps_args | sed 's/^\([0-9]*\)/? \1 /g'
else
ps $ps_args
fi
sleep 0.001
done | grep -v 'ewwwo start_time,pid,user:50,args' | sed 's/^ *//g' | tr -s '[:space:]' | grep -v "^START" | grep -Ev '[^ ]+ [^ ]+ [^ ]+ \[' | sort -Mr | uniq -c | sed 's/^ *//g' > "$lse_procmon_data"
}
lse_proc_print() {
done | grep -Ev "(pid,user|$lse_user *sed s/)" | sed 's/^ *//g' | tr -s '[:space:]' | grep -Ev "PID *USER *COMMAND" | grep -Ev '[^ ]+ [^ ]+ [^ ]+ \[' | sort -Mr | uniq -c | sed 's/^ *//g' > "$lse_procmon_data"
} #)
lse_proc_print() { #(
# Pretty prints output from lse_procmom received via stdin
if $lse_color; then
printf "${green}%s %8s %8s %s\n" "START" "PID" "USER" "COMMAND"
@@ -574,7 +600,57 @@ lse_proc_print() {
printf "%s %8s %8s %s\n" "$p_time" "$p_pid" "$p_user" "$p_args"
fi
done
}
} #)
lse_get_distro_codename() { #(
# Get the distribution name
#
# ubuntu, debian, centos, redhat, opsuse, fedora, rocky
local distro="${grey}unknown${reset}"
if type lsb_release >/dev/null 2>&1; then
distro=`lsb_release -is`
elif [ -f /etc/os-release ]; then
distro=`grep -E '^ID=' /etc/os-release | cut -f2 -d=`
echo "$distro" | grep -qi opensuse && distro=opsuse
elif [ -f /etc/redhat-release ]; then
grep -qi "centos" /etc/redhat-release && distro=centos
grep -qi "fedora" /etc/redhat-release && distro=fedora
grep -qi "red hat" /etc/redhat-release && distro=redhat
grep -qi "rocky" /etc/redhat-release && distro=rocky
fi
printf '%s' "$distro" | tr '[:upper:]' '[:lower:]' | tr -d \"\'
} #)
lse_is_version_bigger() { #(
# check if version v1 is bigger than v2
local v1="$1"; local v2="$2" ; local vc
[ "$v1" = "$v2" ] && return 1 # equal is not bigger
vc="`printf "%s\n%s\n" "$v1" "$v2" | sort -rV | head -n1`"
[ "$v1" = "$vc" ] && return 0
return 1
} #)
lse_get_pkg_version() { #(
# get package version depending on distro
# returns 2 if distro is unknown
# returns 1 if package is not installed (or doesn't exist)
# returns 0 on success, and prints out the package version
pkg_name="$1"
case "$lse_distro_codename" in
debian|ubuntu)
pkg_version=`dpkg -l "$pkg_name" 2>/dev/null | grep -E '^ii' | tr -s ' ' | cut -d' ' -f3`
;;
centos|redhat|fedora|opsuse|rocky|amzn)
pkg_version=`rpm -q "$pkg_name" 2>/dev/null`
pkg_version="${pkg_version##"$pkg_name"-}"
pkg_version=`echo "$pkg_version" | sed -E 's/\.(aarch64|armv7hl|i686|noarch|ppc64le|s390x|x86_64)$//'`
;;
*)
return 2
;;
esac
[ -z "$pkg_version" ] && return 1
printf "%s" "$pkg_version"
return 0
} #)
#)
#)
########################################################################( TESTS
@@ -638,7 +714,7 @@ lse_run_tests_users() {
'for ep in $lse_exec_paths; do [ "$ep" = "." ] && grep -ER "^ *PATH=.*" /etc/ 2> /dev/null | tr -d \"\'"'"' | grep -E "[=:]\.([:[:space:]]|\$)";done' \
"usr070"
}
#)
#########################################################################( sudo
lse_run_tests_sudo() {
@@ -688,7 +764,7 @@ lse_run_tests_sudo() {
"Do we know if any other users used sudo?" \
'for uh in $(cut -d: -f1,6 /etc/passwd); do [ -f "${uh##*:}/.sudo_as_admin_successful" ] && echo "${uh%%:*}"; done'
}
#)
##################################################################( file system
lse_run_tests_filesystem() {
@@ -851,7 +927,7 @@ lse_run_tests_filesystem() {
"Dump fstab file" \
'cat /etc/fstab'
}
#)
#######################################################################( system
lse_run_tests_system() {
@@ -907,7 +983,7 @@ lse_run_tests_system() {
"System password policies in /etc/login.defs" \
'grep "^PASS_MAX_DAYS\|^PASS_MIN_DAYS\|^PASS_WARN_AGE\|^ENCRYPT_METHOD" /etc/login.defs'
}
#)
#####################################################################( security
lse_run_tests_security() {
@@ -953,7 +1029,7 @@ lse_run_tests_security() {
"Can we read the auditd log?" \
'al=/var/log/audit/audit.log; test -r "$al" && echo "tail $al:" && echo && tail "$al"'
}
#)
##############################################################( recurrent tasks
lse_run_tests_recurrent_tasks() {
@@ -1021,7 +1097,7 @@ lse_run_tests_recurrent_tasks() {
"Systemd timers" \
'systemctl list-timers --all'
}
#)
######################################################################( network
lse_run_tests_network() {
@@ -1072,7 +1148,7 @@ lse_run_tests_network() {
"Listening UDP" \
'netstat -unlp || ss -unlp'
}
#)
#####################################################################( services
lse_run_tests_services() {
@@ -1167,7 +1243,7 @@ lse_run_tests_services() {
"Systemd config files permissions" \
'ls -lthR /lib/systemd/ /etc/systemd/'
}
#)
#####################################################################( software
lse_run_tests_software() {
@@ -1310,7 +1386,7 @@ lse_run_tests_software() {
'screen -v'
}
#)
###################################################################( containers
lse_run_tests_containers() {
@@ -1341,7 +1417,7 @@ lse_run_tests_containers() {
"Is the user a member of any lxc/lxd group?" \
'groups | grep $lse_grep_opts "lxc\|lxd"'
}
#)
####################################################################( processes
lse_run_tests_processes() {
@@ -1398,49 +1474,84 @@ lse_run_tests_processes() {
'printf "%s\n" "$lse_proc_bin" | xargs ls -l' \
"pro001"
}
#)
#########################################################################( CVEs
lse_run_tests_cves() {
lse_header "cve" "CVEs"
if [ "${#lse_cve_list}" = 1 ]; then
if [ -z "$lse_selection" ] || printf "%s" "$lse_selection" | grep -iq 'cve'; then
printf "%s\n%s\n%s" \
" In order to test for CVEs, download lse.sh from the GitHub releases page." \
" Alternatively, build lse_cve.sh using tools/package_cvs_into_lse.sh from the" \
" repository."
fi
else
for lse_cve in $lse_cve_list; do
eval "$(printf '%s' "$lse_cve" | base64 -d | gunzip -c)"
lse_test "$lse_cve_id" "$lse_cve_level" \
"$lse_cve_description" \
"lse_cve_test"
done
fi
}
#)
#
##)
#( Main
while getopts "hcCil:e:p:s:S" option; do
case "${option}" in
c) lse_color=false; lse_grep_opts='--color=never';;
C) lse_alt_color=true;;
e) lse_exclude_paths "${OPTARG}";;
i) lse_interactive=false;;
l) lse_set_level "${OPTARG}";;
s) lse_selection="`printf \"%s\" \"${OPTARG}\"|sed 's/,/ /g'`";;
p) lse_proc_time="${OPTARG}";;
S) lse_serve; exit $?;;
h) lse_help; exit 0;;
*) lse_help; exit 1;;
esac
done
main() {
while getopts "hcCil:e:p:s:S" option; do
case "${option}" in
c) lse_color=false; lse_grep_opts='--color=never';;
C) lse_alt_color=true;;
e) lse_exclude_paths "${OPTARG}";;
i) lse_interactive=false;;
l) lse_set_level "${OPTARG}";;
s) lse_selection="`printf \"%s\" \"${OPTARG}\"|sed 's/,/ /g'`";;
p) lse_proc_time="${OPTARG}";;
S) lse_serve; exit $?;;
h) lse_help; exit 0;;
*) lse_help; exit 1;;
esac
done
#trap to exec on SIGINT
trap "lse_exit 1" 2
#trap to exec on SIGINT
trap "lse_exit 1" 2
# use alternative color scheme
$lse_alt_color && lse_recolor
# use alternative color scheme
$lse_alt_color && lse_recolor
lse_request_information
lse_show_info
PATH="$PATH:/sbin:/usr/sbin" #fix path just in case
lse_request_information
lse_show_info
PATH="$PATH:/sbin:/usr/sbin" #fix path just in case
lse_distro_codename=`lse_get_distro_codename`
lse_procmon &
(sleep "$lse_proc_time"; rm -f "$lse_procmon_lock") &
lse_procmon &
(sleep "$lse_proc_time"; rm -f "$lse_procmon_lock") &
lse_run_tests_users
lse_run_tests_sudo
lse_run_tests_filesystem
lse_run_tests_system
lse_run_tests_security
lse_run_tests_recurrent_tasks
lse_run_tests_network
lse_run_tests_services
lse_run_tests_software
lse_run_tests_containers
lse_run_tests_processes
## NO WAR
lse_header "nowar" "humanity"
lse_test "nowar0" "0" \
'Should we question autocrats and their "military operations"?' \
'cecho " $black$b_blue NO $reset\n $black$b_yellow WAR $reset"'
lse_exit 0
lse_run_tests_users
lse_run_tests_sudo
lse_run_tests_filesystem
lse_run_tests_system
lse_run_tests_security
lse_run_tests_recurrent_tasks
lse_run_tests_network
lse_run_tests_services
lse_run_tests_software
lse_run_tests_containers
lse_run_tests_processes
lse_run_tests_cves
lse_exit 0
}
[ ! "$lse_NO_EXEC" ] && main "$@"
#)