From aef2b84f33ecce4e0cdcdd1bf1048692bc4c24b6 Mon Sep 17 00:00:00 2001 From: Carlos Polop Date: Mon, 29 Jun 2026 13:50:25 +0200 Subject: [PATCH] Add opt-in online package vulnerability lookup --- .../PackageKit_Pack2TheRoot.sh | 2 +- .../linpeas_parts/functions/checkDirtyFrag.sh | 2 +- .../functions/check_external_hostname.sh | 134 +++++++++++++++++- .../functions/check_tcp_443_bin.sh | 12 +- .../linpeas_base/0_variables_base.sh | 9 +- 5 files changed, 142 insertions(+), 17 deletions(-) diff --git a/linPEAS/builder/linpeas_parts/7_software_information/PackageKit_Pack2TheRoot.sh b/linPEAS/builder/linpeas_parts/7_software_information/PackageKit_Pack2TheRoot.sh index 1359b6d..7d6475c 100644 --- a/linPEAS/builder/linpeas_parts/7_software_information/PackageKit_Pack2TheRoot.sh +++ b/linPEAS/builder/linpeas_parts/7_software_information/PackageKit_Pack2TheRoot.sh @@ -20,7 +20,7 @@ # Functions Used: print_2title, print_3title, print_info, echo_not_found # Global Variables: # Initial Functions: -# Generated Global Variables: $pk_full, $pk_version, $pk_pkg_manager, $pk_distro_id, $pk_distro_codename, $pk_fixed_version, $pk_fixed_label, $pk_min_vuln, $pk_max_vuln, $pk_lower, $pk_higher, $pk_vulnerable, $pk_ioc_count +# Generated Global Variables: $pk_full, $pk_version, $pk_pkg_manager, $pk_distro_id, $pk_distro_codename, $pk_fixed_version, $pk_fixed_label, $pk_min_vuln, $pk_max_vuln, $pk_lower, $pk_higher, $pk_vulnerable, $pk_ioc_count, $VERSION_CODENAME, $Version # Fat linpeas: 0 # Small linpeas: 1 diff --git a/linPEAS/builder/linpeas_parts/functions/checkDirtyFrag.sh b/linPEAS/builder/linpeas_parts/functions/checkDirtyFrag.sh index 6a69d97..b517d4c 100644 --- a/linPEAS/builder/linpeas_parts/functions/checkDirtyFrag.sh +++ b/linPEAS/builder/linpeas_parts/functions/checkDirtyFrag.sh @@ -10,7 +10,7 @@ # Functions Used: # Global Variables: $E, $SED_GREEN, $SED_YELLOW, $SED_RED_YELLOW # Initial Functions: -# Generated Global Variables: $DF43_KERNEL_OS, $DF43_KERNEL_RELEASE, $DF43_KERNEL_VERSION, $DF43_KBUILD, $DF43_VERSION_KNOWN, $DF43_ESP_AFFECTED, $DF43_RXRPC_AFFECTED, $DF43_ESP_MODS, $DF43_RXRPC_MODS, $DF43_LOADED_ESP, $DF43_LOADED_RXRPC, $DF43_AUTO_ESP, $DF43_AUTO_RXRPC, $DF43_MODDEP, $DF43_MOD, $DF43_BUILTIN_ESP, $DF43_BUILTIN_RXRPC, $DF43_KCFG, $DF43_KCAT, $DF43_C, $DF43_MITIG_ESP, $DF43_MITIG_RXRPC, $DF43_USERNS_OFF, $DF43_CAP_NET_ADMIN, $DF43_CAPEFF, $DF43_CAPLO, $DF43_OLDBUILD, $DF43_BDATE, $DF43_BE, $DF43_FE, $DF43_ESP_REACH, $DF43_RXRPC_REACH, $DF43_RC +# Generated Global Variables: $DF43_KERNEL_OS, $DF43_KERNEL_RELEASE, $DF43_KERNEL_VERSION, $DF43_KBUILD, $DF43_VERSION_KNOWN, $DF43_ESP_AFFECTED, $DF43_RXRPC_AFFECTED, $DF43_ESP_MODS, $DF43_RXRPC_MODS, $DF43_LOADED_ESP, $DF43_LOADED_RXRPC, $DF43_AUTO_ESP, $DF43_AUTO_RXRPC, $DF43_MODDEP, $DF43_MOD, $DF43_BUILTIN_ESP, $DF43_BUILTIN_RXRPC, $DF43_KCFG, $DF43_KCAT, $DF43_C, $DF43_MITIG_ESP, $DF43_MITIG_RXRPC, $DF43_USERNS_OFF, $DF43_CAP_NET_ADMIN, $DF43_CAPEFF, $DF43_CAPLO, $DF43_OLDBUILD, $DF43_BDATE, $DF43_BE, $DF43_FE, $DF43_ESP_REACH, $DF43_RXRPC_REACH, $DF43_RC, $DF43_CURVER, $DF43_REQVER, $DF43_OP, $DF43_CMP # Fat linpeas: 0 # Small linpeas: 1 diff --git a/linPEAS/builder/linpeas_parts/functions/check_external_hostname.sh b/linPEAS/builder/linpeas_parts/functions/check_external_hostname.sh index b0af3d6..760d313 100644 --- a/linPEAS/builder/linpeas_parts/functions/check_external_hostname.sh +++ b/linPEAS/builder/linpeas_parts/functions/check_external_hostname.sh @@ -6,20 +6,146 @@ # License: GNU GPL # Version: 1.0 # Functions Used: -# Global Variables: +# Global Variables: $VERSION, $ONLINE_VULN_CHECKS # Initial Functions: -# Generated Global Variables: $$INTERNET_SEARCH_TIMEOUT +# Generated Global Variables: $$INTERNET_SEARCH_TIMEOUT, $HACKTRICKS_HOST_CHECKER_URL, $HACKTRICKS_PACKAGE_LIMIT, $_os_id, $_os_version_id, $_os_version_major, $_ecosystem, $_pkg_name, $_pkg_line, $_pkg_version, $_limit, $_os_name, $_os_codename, $_hostname, $_hacktricks_host_checker_url, $_hacktricks_payload, $source, $binary, $Version # Fat linpeas: 0 # Small linpeas: 1 +linpeas_json_escape(){ + printf "%s" "$1" | sed 's/\\/\\\\/g; s/"/\\"/g; s/ / /g' +} + +linpeas_os_release_field(){ + [ -r /etc/os-release ] || return + awk -F= -v key="$1" ' + $1 == key { + value=$0 + sub(/^[^=]*=/, "", value) + gsub(/^"/, "", value) + gsub(/"$/, "", value) + print value + exit + } + ' /etc/os-release 2>/dev/null +} + +linpeas_os_package_ecosystem(){ + _os_id="$(linpeas_os_release_field ID)" + _os_version_id="$(linpeas_os_release_field VERSION_ID)" + _os_version_major="$(printf "%s" "$_os_version_id" | cut -d. -f1)" + + case "$_os_id" in + debian) [ "$_os_version_major" ] && printf "Debian:%s" "$_os_version_major" ;; + ubuntu) [ "$_os_version_id" ] && printf "Ubuntu:%s" "$_os_version_id" ;; + alpine) [ "$_os_version_id" ] && printf "Alpine:v%s" "$_os_version_id" ;; + fedora) [ "$_os_version_id" ] && printf "Fedora:%s" "$_os_version_id" ;; + amzn) [ "$_os_version_id" ] && printf "Amazon Linux:%s" "$_os_version_id" ;; + rhel) [ "$_os_version_major" ] && printf "Red Hat:%s" "$_os_version_major" ;; + centos) [ "$_os_version_major" ] && printf "CentOS:%s" "$_os_version_major" ;; + rocky) [ "$_os_version_major" ] && printf "Rocky Linux:%s" "$_os_version_major" ;; + almalinux) [ "$_os_version_major" ] && printf "AlmaLinux:%s" "$_os_version_major" ;; + esac +} + +linpeas_print_package_json_lines(){ + _ecosystem="$(linpeas_os_package_ecosystem)" + + if command -v dpkg-query >/dev/null 2>&1; then + dpkg-query -W -f='${source:Package}\t${source:Version}\t${binary:Package}\t${Version}\n' 2>/dev/null | awk -F '\t' -v ecosystem="$_ecosystem" ' + function esc(s) { gsub(/\\/,"\\\\",s); gsub(/"/,"\\\"",s); gsub(/\r/," ",s); return s } + { + name=$1; version=$2 + if (name == "" || name == "-") { name=$3; version=$4 } + if (version == "" || version == "-") { version=$4 } + sub(/^src:/, "", name) + if (name == "" || version == "") next + key=name "|" version + if (seen[key]++) next + printf "{\"name\":\"%s\",\"version\":\"%s\",\"ecosystem\":\"%s\",\"manager\":\"dpkg\"}\n", esc(name), esc(version), esc(ecosystem) + }' + elif command -v rpm >/dev/null 2>&1; then + rpm -qa --qf '%{NAME}\t%{VERSION}-%{RELEASE}\n' 2>/dev/null | awk -F '\t' -v ecosystem="$_ecosystem" ' + function esc(s) { gsub(/\\/,"\\\\",s); gsub(/"/,"\\\"",s); gsub(/\r/," ",s); return s } + $1 != "" && $2 != "" { + key=$1 "|" $2 + if (seen[key]++) next + printf "{\"name\":\"%s\",\"version\":\"%s\",\"ecosystem\":\"%s\",\"manager\":\"rpm\"}\n", esc($1), esc($2), esc(ecosystem) + }' + elif command -v apk >/dev/null 2>&1; then + apk info 2>/dev/null | while IFS= read -r _pkg_name; do + [ "$_pkg_name" ] || continue + _pkg_line="$(apk info -e -v "$_pkg_name" 2>/dev/null | head -n 1)" + _pkg_version="$(printf "%s" "$_pkg_line" | awk -v n="$_pkg_name" 'index($0, n "-") == 1 { print substr($0, length(n) + 2); exit }')" + [ "$_pkg_version" ] || continue + printf '{"name":"%s","version":"%s","ecosystem":"%s","manager":"apk"}\n' \ + "$(linpeas_json_escape "$_pkg_name")" "$(linpeas_json_escape "$_pkg_version")" "$(linpeas_json_escape "$_ecosystem")" + done + elif command -v pacman >/dev/null 2>&1; then + pacman -Q 2>/dev/null | awk -v ecosystem="$_ecosystem" ' + function esc(s) { gsub(/\\/,"\\\\",s); gsub(/"/,"\\\"",s); gsub(/\r/," ",s); return s } + $1 != "" && $2 != "" { + key=$1 "|" $2 + if (seen[key]++) next + printf "{\"name\":\"%s\",\"version\":\"%s\",\"ecosystem\":\"%s\",\"manager\":\"pacman\"}\n", esc($1), esc($2), esc(ecosystem) + }' + fi +} + +linpeas_packages_json(){ + _limit="${HACKTRICKS_PACKAGE_LIMIT:-300}" + linpeas_print_package_json_lines | awk -v max="$_limit" ' + BEGIN { first=1; printf "[" } + NF { + if (count >= max) next + if (!first) printf "," + printf "%s", $0 + first=0 + count++ + } + END { printf "]" }' +} + +linpeas_os_json(){ + _os_id="$(linpeas_os_release_field ID)" + _os_name="$(linpeas_os_release_field PRETTY_NAME)" + _os_version_id="$(linpeas_os_release_field VERSION_ID)" + _os_codename="$(linpeas_os_release_field VERSION_CODENAME)" + printf '{"id":"%s","name":"%s","version_id":"%s","codename":"%s","kernel":{"release":"%s","version":"%s","arch":"%s"}}' \ + "$(linpeas_json_escape "$_os_id")" \ + "$(linpeas_json_escape "$_os_name")" \ + "$(linpeas_json_escape "$_os_version_id")" \ + "$(linpeas_json_escape "$_os_codename")" \ + "$(linpeas_json_escape "$(uname -r 2>/dev/null)")" \ + "$(linpeas_json_escape "$(uname -v 2>/dev/null)")" \ + "$(linpeas_json_escape "$(uname -m 2>/dev/null)")" +} + +linpeas_host_checker_payload(){ + _hostname="$(hostname 2>/dev/null)" + if [ "$ONLINE_VULN_CHECKS" ]; then + printf '{"hostname":"%s","source":"linpeas","version":"%s","online_package_check":true,"os":%s,"packages":%s}' \ + "$(linpeas_json_escape "$_hostname")" \ + "$(linpeas_json_escape "$VERSION")" \ + "$(linpeas_os_json)" \ + "$(linpeas_packages_json)" + else + printf '{"hostname":"%s","source":"linpeas","version":"%s"}' \ + "$(linpeas_json_escape "$_hostname")" \ + "$(linpeas_json_escape "$VERSION")" + fi +} + check_external_hostname(){ INTERNET_SEARCH_TIMEOUT=15 + _hacktricks_host_checker_url="${HACKTRICKS_HOST_CHECKER_URL:-https://tools.hacktricks.wiki/api/host-checker}" + _hacktricks_payload="$(linpeas_host_checker_payload)" # wget or curl? if command -v curl >/dev/null 2>&1; then - curl "https://tools.hacktricks.wiki/api/host-checker" -H "User-Agent: linpeas" -d "{\"hostname\":\"$(hostname)\"}" -H "Content-Type: application/json" --max-time "$INTERNET_SEARCH_TIMEOUT" + curl -s "$_hacktricks_host_checker_url" -H "User-Agent: linpeas" --data-binary "$_hacktricks_payload" -H "Content-Type: application/json" --max-time "$INTERNET_SEARCH_TIMEOUT" elif command -v wget >/dev/null 2>&1; then - wget -q -O - "https://tools.hacktricks.wiki/api/host-checker" --header "User-Agent: linpeas" --post-data "{\"hostname\":\"$(hostname)\"}" -H "Content-Type: application/json" --timeout "$INTERNET_SEARCH_TIMEOUT" + wget -q -O - "$_hacktricks_host_checker_url" --header "User-Agent: linpeas" --header "Content-Type: application/json" --post-data "$_hacktricks_payload" --timeout "$INTERNET_SEARCH_TIMEOUT" else echo "wget or curl not found" fi diff --git a/linPEAS/builder/linpeas_parts/functions/check_tcp_443_bin.sh b/linPEAS/builder/linpeas_parts/functions/check_tcp_443_bin.sh index 8d5a0f1..9fcfbe9 100644 --- a/linPEAS/builder/linpeas_parts/functions/check_tcp_443_bin.sh +++ b/linPEAS/builder/linpeas_parts/functions/check_tcp_443_bin.sh @@ -8,19 +8,17 @@ # Functions Used: # Global Variables: # Initial Functions: -# Generated Global Variables: $url_lambda, $TIMEOUT_INTERNET_SECONDS_443_BIN +# Generated Global Variables: $url_443, $TIMEOUT_INTERNET_SECONDS_443_BIN # Fat linpeas: 0 # Small linpeas: 1 check_tcp_443_bin () { local TIMEOUT_INTERNET_SECONDS_443_BIN=$1 - local url_lambda="https://tools.hacktricks.wiki/api/host-checker" + local url_443="https://1.1.1.1" if command -v curl >/dev/null 2>&1; then - if curl -s --connect-timeout $TIMEOUT_INTERNET_SECONDS_443_BIN "$url_lambda" \ - -H "User-Agent: linpeas" -H "Content-Type: application/json" \ - -d "{\"hostname\":\"$(hostname)\"}" >/dev/null 2>&1 + if curl -s -k --connect-timeout "$TIMEOUT_INTERNET_SECONDS_443_BIN" "$url_443" >/dev/null 2>&1 then echo "Port 443 is accessible with curl" return 0 # ✅ success @@ -30,9 +28,7 @@ check_tcp_443_bin () { fi elif command -v wget >/dev/null 2>&1; then - if wget -q --timeout=$TIMEOUT_INTERNET_SECONDS_443_BIN -O - "$url_lambda" \ - --header "User-Agent: linpeas" -H "Content-Type: application/json" \ - --post-data "{\"hostname\":\"$(hostname)\"}" >/dev/null 2>&1 + if wget -q --no-check-certificate --timeout="$TIMEOUT_INTERNET_SECONDS_443_BIN" -O - "$url_443" >/dev/null 2>&1 then echo "Port 443 is accessible with wget" return 0 diff --git a/linPEAS/builder/linpeas_parts/linpeas_base/0_variables_base.sh b/linPEAS/builder/linpeas_parts/linpeas_base/0_variables_base.sh index 6009b3a..5e50c9f 100644 --- a/linPEAS/builder/linpeas_parts/linpeas_base/0_variables_base.sh +++ b/linPEAS/builder/linpeas_parts/linpeas_base/0_variables_base.sh @@ -8,7 +8,7 @@ # Functions Used: # Global Variables: # Initial Functions: -# Generated Global Variables: $VERSION, $ADVISORY, $IAMROOT, $MAXPATH_FIND_W, $C, $RED, $SED_RED, $GREEN, $SED_GREEN, $YELLOW, $SED_YELLOW, $RED_YELLOW, $SED_RED_YELLOW, $BLUE, $SED_BLUE, $ITALIC_BLUE, $LIGHT_MAGENTA, $SED_LIGHT_MAGENTA, $LIGHT_CYAN, $SED_LIGHT_CYAN, $LG, $SED_LG, $DG, $SED_DG, $NC, $UNDERLINED, $ITALIC, $MACPEAS, $FAST, $SUPERFAST, $DISCOVERY, $PORTS, $QUIET, $CHECKS, $MITRE_FILTER, $SEARCH_IN_FOLDER, $ROOT_FOLDER, $WAIT, $PASSWORD, $NOCOLOR, $DEBUG, $AUTO_NETWORK_SCAN, $EXTRA_CHECKS, $REGEXES, $PORT_FORWARD, $E, $PING, $FPING, $DISCOVER_BAN_BAD, $DISCOVER_BAN_GOOD, $SCAN_BAN_GOOD, $NMAP_GOOD, $SCRIPTNAME, $FOUND_BASH, $FOUND_NC, $HOMESEARCH, $GREPHOMESEARCH, $SCAN_BAN_BAD, $HOME, $THREADS, $opt, $HELP, $USER, $TOTAL_T1_TIME, $END_T1_TIME, $START_T1_TIME, $title, $title_len, $max_title_len, $rest_len, $CONT_THREADS, $wgroups, $SEDOVERFLOW, $Wfolders, $Wfolder, $grp, $END_T2_TIME, $TOTAL_T2_TIME, $START_T2_TIME, $_mitre_tag, $_mitre_filter, $_mitre_base, $_mitre_tags_left, $_mitre_filters_left +# Generated Global Variables: $VERSION, $ADVISORY, $IAMROOT, $MAXPATH_FIND_W, $C, $RED, $SED_RED, $GREEN, $SED_GREEN, $YELLOW, $SED_YELLOW, $RED_YELLOW, $SED_RED_YELLOW, $BLUE, $SED_BLUE, $ITALIC_BLUE, $LIGHT_MAGENTA, $SED_LIGHT_MAGENTA, $LIGHT_CYAN, $SED_LIGHT_CYAN, $LG, $SED_LG, $DG, $SED_DG, $NC, $UNDERLINED, $ITALIC, $MACPEAS, $FAST, $SUPERFAST, $DISCOVERY, $PORTS, $QUIET, $CHECKS, $MITRE_FILTER, $SEARCH_IN_FOLDER, $ROOT_FOLDER, $WAIT, $PASSWORD, $NOCOLOR, $DEBUG, $AUTO_NETWORK_SCAN, $EXTRA_CHECKS, $REGEXES, $PORT_FORWARD, $NOT_CHECK_EXTERNAL_HOSTNAME, $ONLINE_VULN_CHECKS, $E, $PING, $FPING, $DISCOVER_BAN_BAD, $DISCOVER_BAN_GOOD, $SCAN_BAN_GOOD, $NMAP_GOOD, $SCRIPTNAME, $FOUND_BASH, $FOUND_NC, $HOMESEARCH, $GREPHOMESEARCH, $SCAN_BAN_BAD, $HOME, $THREADS, $opt, $HELP, $USER, $TOTAL_T1_TIME, $END_T1_TIME, $START_T1_TIME, $title, $title_len, $max_title_len, $rest_len, $CONT_THREADS, $wgroups, $SEDOVERFLOW, $Wfolders, $Wfolder, $grp, $END_T2_TIME, $TOTAL_T2_TIME, $START_T2_TIME, $_mitre_tag, $_mitre_filter, $_mitre_base, $_mitre_tags_left, $_mitre_filters_left # Fat linpeas: 0 # Small linpeas: 1 @@ -85,6 +85,7 @@ EXTRA_CHECKS="" REGEXES="" PORT_FORWARD="" NOT_CHECK_EXTERNAL_HOSTNAME="" +ONLINE_VULN_CHECKS="" THREADS="$( ( (grep -c processor /proc/cpuinfo 2>/dev/null) || ( (command -v lscpu >/dev/null 2>&1) && (lscpu | grep '^CPU(s):' | awk '{print $2}')) || echo -n 2) | tr -d "\n")" [ "$THREADS" -eq "$THREADS" ] 2>/dev/null && : || THREADS="2" #If THREADS is not a number, put number 2 [ "$THREADS" -lt 1 ] 2>/dev/null && THREADS="2" #If THREADS is 0 or negative, put number 2 (avoids division-by-zero in eval_bckgrd) @@ -97,6 +98,7 @@ ${NC}This tool enum and search possible misconfigurations$DG (known vulns, user, ${YELLOW} -s${BLUE} Stealth & faster (don't check some time consuming checks) ${YELLOW} -e${BLUE} Perform extra enumeration ${YELLOW} -r${BLUE} Enable Regexes (this can take from some mins to hours) + ${YELLOW} -V${BLUE} Send package/kernel inventory to HackTricks for online vulnerability lookup ${YELLOW} -P${BLUE} Indicate a password that will be used to run 'sudo -l' and to bruteforce other users accounts via 'su' ${YELLOW} -n${BLUE} Do not check hostname & IP in known malicious lists and leaks ${YELLOW} -D${BLUE} Debug mode @@ -123,10 +125,10 @@ ${NC}This tool enum and search possible misconfigurations$DG (known vulns, user, ${YELLOW} -N${BLUE} Do not use colours ${YELLOW} -z ${BLUE} Set number of threads for background checks (default: auto-detected CPU count, fallback: 2; must be >= 1)$NC" -while getopts ":h?asd:p:i:P:qo:T:LMwNDterf:F:z:" opt; do +while getopts ":h?asd:p:i:P:qo:T:LMwNDterVf:F:z:" opt; do case "$opt" in h|\?) printf "%s\n\n" "$HELP$NC"; exit 0;; - a) FAST="";EXTRA_CHECKS="1";; + a) FAST="";EXTRA_CHECKS="1";ONLINE_VULN_CHECKS="1";; s) SUPERFAST=1;; d) DISCOVERY=$OPTARG;; p) PORTS=$OPTARG;; @@ -144,6 +146,7 @@ while getopts ":h?asd:p:i:P:qo:T:LMwNDterf:F:z:" opt; do t) AUTO_NETWORK_SCAN="1";; e) EXTRA_CHECKS="1";; r) REGEXES="1";; + V) ONLINE_VULN_CHECKS="1";; f) SEARCH_IN_FOLDER=$OPTARG; if ! [ "$(echo -n $SEARCH_IN_FOLDER | tail -c 1)" = "/" ]; then #Make sure firmware folder ends with "/" SEARCH_IN_FOLDER="${SEARCH_IN_FOLDER}/";