Add linpeas privilege escalation checks from: HTB: SmartHire

This commit is contained in:
HackTricks News Bot committed 2026-10-04 19:57:28 +00:00
1 parent 7cff6dc5ae
commit 80bfc568e8
1 file changed
+92 -5
@@ -1,20 +1,20 @@
# Title: Users Information - Sudo -l
# ID: UG_Sudo_l
# Author: Carlos Polop
# Last Update: 22-08-2023
# Description: Checking 'sudo -l', /etc/sudoers, and /etc/sudoers.d
# Last Update: 04-10-2026
# Description: Checking 'sudo -l', /etc/sudoers, /etc/sudoers.d, and privileged Python scripts that load code from writable paths
# License: GNU GPL
# Version: 1.0
# Version: 1.1
# Mitre: T1548.003
# Functions Used: echo_not_found, print_2title, print_info
# Global Variables:$IAMROOT, $PASSWORD, $TIMEOUT, $sudoB, $sudoG, $sudoVB1, $sudoVB2
# Initial Functions:
# Generated Global Variables: $sudo_l_output, $sudo_l_password_output, $sudo_l_cached_output, $secure_path_line
# Generated Global Variables: $sudo_l_output, $sudo_l_password_output, $sudo_l_cached_output, $secure_path_line, $sudo_python_scripts, $python_sudo_script, $python_loader_lines, $python_loader_root, $python_loader_roots, $python_loader_path_lines, $python_loader_literal, $python_loader_parent, $python_candidate_dir, $python_seen_dirs, $python_pth_file, $python_pth_imports, $python_writable_pth, $python_script_dir
# Fat linpeas: 0
# Small linpeas: 1
print_2title "Checking 'sudo -l', /etc/sudoers, and /etc/sudoers.d" "T1548.003"
print_2title "Checking 'sudo -l', sudoers files, and privileged Python paths" "T1548.003"
print_info "https://book.hacktricks.wiki/en/linux-hardening/linux-basics/linux-privilege-escalation/index.html#sudo-and-suid"
sudo_l_colorize() {
@@ -64,6 +64,93 @@ if [ "$secure_path_line" ]; then
fi
done
fi
# Correlate root-capable sudo Python commands with dynamic import/site-directory
# loading. site.addsitedir() and site.addpackage() process .pth files, whose
# "import " lines are executed by Python. A writable plugin/site directory can
# therefore turn an otherwise fixed sudo command into code execution as root.
sudo_python_scripts=$(printf "%s\n%s\n%s\n" "$sudo_l_cached_output" "$sudo_l_password_output" "$sudo_l_output" | awk '
/python[0-9.]*/ && /\((root|ALL)([[:space:]:,)]|$)/ && !/!root/ {
for (i = 1; i <= NF; i++) {
token = $i
gsub(/^["'"'']|["'"'',:]$/, "", token)
if (token ~ /^\/.*\.py$/) print token
}
}
' | sort -u)
if [ "$sudo_python_scripts" ]; then
printf "%s\n" "$sudo_python_scripts" | while IFS= read -r python_sudo_script; do
[ -f "$python_sudo_script" ] && [ -r "$python_sudo_script" ] || continue
python_loader_lines=$(grep -nE 'site\.(addsitedir|addpackage)[[:space:]]*\(|sys\.path\.(append|insert|extend)[[:space:]]*\(|(spec_from_file_location|SourceFileLoader|exec_module)[[:space:]]*\(' "$python_sudo_script" 2>/dev/null)
[ "$python_loader_lines" ] || continue
python_script_dir=$(dirname "$python_sudo_script")
python_loader_path_lines=$(grep -E 'site\.(addsitedir|addpackage)|sys\.path\.(append|insert|extend)|(_DIR|_PATH)[[:space:]]*=' "$python_sudo_script" 2>/dev/null)
python_loader_roots=$(
printf "%s\n" "$python_loader_path_lines" | grep -Eo "['\"]/[^'\"]+['\"]" 2>/dev/null | tr -d "'\""
printf "%s\n" "$python_loader_path_lines" | sed -nE "s/.*[(\/=][[:space:]]*['\"]([^'\"]+)['\"].*/\1/p" | while IFS= read -r python_loader_literal; do
case "$python_loader_literal" in
/*|*://*) ;;
*) printf "%s/%s\n" "$python_script_dir" "$python_loader_literal" ;;
esac
done
)
# Fall back to the script tree only when static path extraction is not
# possible (for example when addsitedir() receives a computed value).
[ "$python_loader_roots" ] || python_loader_roots="$python_script_dir"
python_seen_dirs="|"
printf "%s\n" "$python_loader_roots" | sort -u | while IFS= read -r python_loader_root; do
if ! [ -d "$python_loader_root" ]; then
python_loader_parent=$(dirname "$python_loader_root")
if [ -d "$python_loader_parent" ] && [ -w "$python_loader_parent" ]; then
echo "Privileged sudo Python script loads code/paths dynamically: $python_sudo_script"
printf "%s\n" "$python_loader_lines"
echo "Python loader path can be created in writable parent: $python_loader_root (parent: $python_loader_parent)" | sed -${E} "s,.*,${SED_RED_YELLOW},"
echo ""
fi
continue
fi
# A bounded traversal keeps this quick and also catches loaders that
# iterate over plugin subdirectories before calling addsitedir().
for python_candidate_dir in "$python_loader_root" "$python_loader_root"/* "$python_loader_root"/*/*; do
[ -d "$python_candidate_dir" ] || continue
python_writable_pth=""
for python_pth_file in "$python_candidate_dir"/*.pth; do
[ -f "$python_pth_file" ] && [ -w "$python_pth_file" ] && python_writable_pth=1
done
[ -w "$python_candidate_dir" ] || [ "$python_writable_pth" ] || continue
case "$python_seen_dirs" in
*"|$python_candidate_dir|"*) continue ;;
esac
python_seen_dirs="${python_seen_dirs}${python_candidate_dir}|"
echo "Privileged sudo Python script loads code/paths dynamically: $python_sudo_script"
printf "%s\n" "$python_loader_lines"
if printf "%s\n" "$python_loader_lines" | grep -qE 'site\.(addsitedir|addpackage)'; then
echo "Writable directory processed by privileged Python site loader: $python_candidate_dir (.pth import lines may execute as root)" | sed -${E} "s,.*,${SED_RED_YELLOW},"
else
echo "Writable directory near privileged Python import path: $python_candidate_dir (possible module/path hijack)" | sed -${E} "s,.*,${SED_RED_YELLOW},"
fi
ls -ld "$python_candidate_dir" 2>/dev/null
for python_pth_file in "$python_candidate_dir"/*.pth; do
[ -f "$python_pth_file" ] || continue
[ -w "$python_candidate_dir" ] || [ -w "$python_pth_file" ] || continue
echo " Python path configuration file: $python_pth_file"
python_pth_imports=$(grep -nE '^import[[:space:]]' "$python_pth_file" 2>/dev/null)
if [ "$python_pth_imports" ]; then
printf "%s\n" "$python_pth_imports" | sed -${E} "s,.*,${SED_RED_YELLOW},"
fi
done
echo ""
done
done
done
fi
(sudo_l_colorize_file /etc/sudoers) 2>/dev/null || echo_not_found "/etc/sudoers"
if ! [ "$IAMROOT" ] && [ -w '/etc/sudoers.d/' ]; then
echo "You can create a file in /etc/sudoers.d/ and escalate privileges" | sed -${E} "s,.*,${SED_RED_YELLOW},"