Compare commits

...

34 Commits

Author SHA1 Message Date
HackTricks News Bot
f46172fab2 Add linpeas privilege escalation checks from: HTB Zero: .htaccess ErrorDocument LFI → credential reuse → root via apache2ctl-f 2025-08-27 16:42:57 +02:00
SirBroccoli
cc5ab76991 Merge pull request #486 from soobinrho/fix-typo-on-color-explanations
docs: fix typo (conten -> content)
2025-08-27 12:12:28 +02:00
carlospolop
36001d644e Merge branch 'master' of github.com:peass-ng/PEASS-ng 2025-08-25 11:18:18 +02:00
carlospolop
fdd414f4aa new workflow 2025-08-25 11:18:16 +02:00
Soobin Rho
c3e50dbdbf docs: fix typo (conten -> content) 2025-08-08 17:56:41 -05:00
SirBroccoli
41128808a6 Merge pull request #483 from securitytime/patch-1
Update Beaprint.cs
2025-07-01 16:23:13 +02:00
carlospolop
6fd96f4bdb f 2025-07-01 12:12:01 +02:00
carlospolop
a745f00dd7 fix 2025-07-01 11:10:21 +02:00
securitytime
933e12d7f1 Update Beaprint.cs
A space character is missing here:
"... educational purposes only.Any misuse of this software  ..."
2025-06-28 09:12:40 +02:00
SirBroccoli
4061cef7e8 Merge pull request #476 from peass-ng/codex/fix-url-reference-in-linpeasbuilder.py
Fix url variable reference in linpeasBuilder
2025-06-25 01:59:43 +02:00
SirBroccoli
b66ced3c63 Merge pull request #475 from peass-ng/codex/find-and-fix-a-bug
Fix parser global state reuse
2025-06-25 01:59:03 +02:00
SirBroccoli
cde725dacc Merge pull request #477 from peass-ng/codex/update-docstring-and-fix-typo
Fix docstring and comment in linpeasBuilder
2025-06-25 01:57:58 +02:00
SirBroccoli
f0f829890c Merge pull request #479 from peass-ng/codex/replace--parth--with--path--in-argparse
Fix typo in linpeas builder arg help
2025-06-25 01:57:11 +02:00
SirBroccoli
99c36b8562 Merge pull request #480 from Signum21/master
Fixed multiple bugs in Vulnerable Leaked Handlers
2025-06-25 01:56:58 +02:00
SirBroccoli
a74c6c820f Merge pull request #482 from Aarav-Juneja/builder-exclude-fix
Fix exclude modules on linPEASS
2025-06-25 01:55:48 +02:00
SirBroccoli
53fd4d8dc8 Merge pull request #481 from ertaku12/master
Added a privilege escalation vulnerability for MySQL 4.x/5.x versions.
2025-06-25 01:55:25 +02:00
Aarav Juneja
9b37fd4ef4 Fix exclude modules on linPEASS 2025-06-24 13:05:10 -07:00
John Doe
f27b1d4816 Added a privilege escalation vulnerability for MySQL 4.x/5.x versions. 2025-06-23 22:37:44 +03:00
Signum21
d335b9254f Fixed multiple bugs in Vulnerable Leaked Handlers 2025-06-15 20:59:20 +02:00
SirBroccoli
d5e3c2a885 Fix typo in linpeas builder output argument 2025-06-06 00:38:05 +02:00
SirBroccoli
4af321d138 Fix docstring and comment typo 2025-06-06 00:01:29 +02:00
SirBroccoli
4e556fd594 Fix variable reference when parsing URLs 2025-06-06 00:01:17 +02:00
SirBroccoli
39066f6867 Fix leftover debug code and reset state in parser 2025-06-06 00:00:39 +02:00
SirBroccoli
c3a93a57fe Merge pull request #473 from Signum21/master
Fix IdentityNotMappedException in Vulnerable Leaked Handlers
2025-05-31 22:36:49 +02:00
Signum21
f62d9fc550 Fix System.Security.Principal.IdentityNotMappedException in Vulnerable Leaked Handlers 2025-05-31 04:56:14 +02:00
SirBroccoli
11e9b8dde6 Merge pull request #472 from Jack-Vaughn/NoEnvVars-Update
Add 4 noisy environment variables to NoEnvVars.sh
2025-05-26 23:57:40 +02:00
Jack Vaughn
b9a9ad5ddf Add 4 noisy and useless environment variables to NoEnvVars.sh
These variables (^PATH=|^INVOCATION_ID=|^WATCHDOG_PID=|^LISTEN_PID=) frequently appear across processes 
on busy systems (10+ each on tested system) and produce a large volume of irrelevant output
2025-05-25 21:32:51 -04:00
carlospolop
88f08a405e l 2025-05-26 02:55:07 +02:00
SirBroccoli
322792c4ec Merge pull request #471 from Jack-Vaughn/environ-check
Add module to check for sensitive environment variables via /proc/*/environ
2025-05-26 02:33:43 +02:00
Jack
c150e63b52 This module scans /proc/*/environ for potentially sensitive environment variables on Linux systems.
It targets common keywords like token, password, secret, AWS, API, etc.

Uses 'tr' instead of 'strings' to improve compatibility in minimal environments like containers.

The check is skipped entirely on MacPEAS.
2025-05-25 12:55:34 -04:00
carlospolop
7b8dcfbe8d f 2025-05-25 08:17:07 +02:00
carlospolop
aac3667247 f l 2025-05-25 08:15:48 +02:00
carlospolop
64ab193d25 f linpeas 2025-05-25 07:05:48 +02:00
carlospolop
aab8241ede f 2025-05-25 02:21:39 +02:00
23 changed files with 562 additions and 91 deletions

201
.github/workflows/PR-tests.yml vendored Normal file
View File

@@ -0,0 +1,201 @@
name: PR-tests
on:
pull_request:
branches:
- master
- main
paths-ignore:
- '.github/**'
jobs:
Build_and_test_winpeas_pr:
runs-on: windows-latest
# environment variables
env:
Solution_Path: 'winPEAS\winPEASexe\winPEAS.sln'
Configuration: 'Release'
steps:
# checkout
- name: Checkout
uses: actions/checkout@master
with:
ref: ${{ github.head_ref }}
- name: Download regexes
run: |
powershell.exe -ExecutionPolicy Bypass -File build_lists/download_regexes.ps1
# Add MSBuild to the PATH
- name: Setup MSBuild.exe
uses: microsoft/setup-msbuild@v1.0.2
# Setup NuGet
- name: Setup NuGet.exe
uses: nuget/setup-nuget@v1
# Restore the packages for testing
- name: Restore the application
run: nuget restore $env:Solution_Path
# build
- name: run MSBuild
run: msbuild $env:Solution_Path
# Build all versions
- name: Build all versions
run: |
echo "build x64"
msbuild -m $env:Solution_Path /t:Rebuild /p:Configuration=$env:Configuration /p:Platform="x64"
echo "build x86"
msbuild -m $env:Solution_Path /t:Rebuild /p:Configuration=$env:Configuration /p:Platform="x86"
echo "build Any CPU"
msbuild -m $env:Solution_Path /t:Rebuild /p:Configuration=$env:Configuration /p:Platform="Any CPU"
- name: Execute winPEAS -h
shell: pwsh
run: |
$Configuration = "Release"
$exePath = "winPEAS/winPEASexe/winPEAS/bin/$Configuration/winPEAS.exe"
if (Test-Path $exePath) {
& $exePath -h
} else {
Write-Error "winPEAS.exe not found at $exePath"
}
- name: Execute winPEAS cloudinfo
shell: pwsh
run: |
$Configuration = "Release"
$exePath = "winPEAS/winPEASexe/winPEAS/bin/$Configuration/winPEAS.exe"
if (Test-Path $exePath) {
& $exePath cloudinfo
} else {
Write-Error "winPEAS.exe not found at $exePath"
}
- name: Execute winPEAS systeminfo
shell: pwsh
run: |
$Configuration = "Release"
$exePath = "winPEAS/winPEASexe/winPEAS/bin/$Configuration/winPEAS.exe"
if (Test-Path $exePath) {
& $exePath systeminfo
} else {
Write-Error "winPEAS.exe not found at $exePath"
}
- name: Execute winPEAS networkinfo
shell: pwsh
run: |
$Configuration = "Release"
$exePath = "winPEAS/winPEASexe/winPEAS/bin/$Configuration/winPEAS.exe"
if (Test-Path $exePath) {
& $exePath networkinfo
} else {
Write-Error "winPEAS.exe not found at $exePath"
}
Build_and_test_linpeas_pr:
runs-on: ubuntu-latest
steps:
# Download repo
- uses: actions/checkout@v2
with:
ref: ${{ github.head_ref }}
# Setup go
- uses: actions/setup-go@v2
with:
go-version: 1.17.0-rc1
stable: false
- run: go version
# Build linpeas
- name: Build linpeas
run: |
python3 -m pip install PyYAML
cd linPEAS
python3 -m builder.linpeas_builder --all --output linpeas_fat.sh
python3 -m builder.linpeas_builder --all-no-fat --output linpeas.sh
python3 -m builder.linpeas_builder --small --output linpeas_small.sh
# Run linpeas help as quick test
- name: Run linpeas help
run: linPEAS/linpeas_fat.sh -h && linPEAS/linpeas.sh -h && linPEAS/linpeas_small.sh -h
# Run linpeas as a test
- name: Run linpeas system_information
run: linPEAS/linpeas_fat.sh -o system_information -a
- name: Run linpeas container
run: linPEAS/linpeas_fat.sh -o container -a
- name: Run linpeas cloud
run: linPEAS/linpeas_fat.sh -o cloud -a
- name: Run linpeas procs_crons_timers_srvcs_sockets
run: linPEAS/linpeas_fat.sh -o procs_crons_timers_srvcs_sockets -a
- name: Run linpeas network_information
run: linPEAS/linpeas_fat.sh -o network_information -t -a
- name: Run linpeas users_information
run: linPEAS/linpeas_fat.sh -o users_information -a
- name: Run linpeas software_information
run: linPEAS/linpeas_fat.sh -o software_information -a
- name: Run linpeas interesting_perms_files
run: linPEAS/linpeas_fat.sh -o interesting_perms_files -a
- name: Run linpeas interesting_files
run: linPEAS/linpeas_fat.sh -o interesting_files -a
Build_and_test_macpeas_pr:
runs-on: macos-latest
steps:
# Download repo
- uses: actions/checkout@v2
with:
ref: ${{ github.head_ref }}
# Build linpeas (macpeas)
- name: Build macpeas
run: |
python3 -m pip install PyYAML --break-system-packages
python3 -m pip install requests --break-system-packages
cd linPEAS
python3 -m builder.linpeas_builder --all --output linpeas_fat.sh
# Run linpeas help as quick test
- name: Run macpeas help
run: linPEAS/linpeas_fat.sh -h
# Run macpeas parts to test it
- name: Run macpeas system_information
run: linPEAS/linpeas_fat.sh -o system_information -a
- name: Run macpeas container
run: linPEAS/linpeas_fat.sh -o container -a
- name: Run macpeas cloud
run: linPEAS/linpeas_fat.sh -o cloud -a
- name: Run macpeas procs_crons_timers_srvcs_sockets
run: linPEAS/linpeas_fat.sh -o procs_crons_timers_srvcs_sockets -a
- name: Run macpeas network_information
run: linPEAS/linpeas_fat.sh -o network_information -t -a
- name: Run macpeas users_information
run: linPEAS/linpeas_fat.sh -o users_information -a
- name: Run macpeas software_information
run: linPEAS/linpeas_fat.sh -o software_information -a

View File

@@ -96,7 +96,7 @@ bash /path/to/linpeas.sh -f /path/to/folder
The goal of this script is to search for possible **Privilege Escalation Paths** (tested in Debian, CentOS, FreeBSD, OpenBSD and MacOS).
This script doesn't have any dependency.
This script doesn't have any dependency. It also detects unsafe patterns in privileged cron/systemd scripts that read process command lines (pgrep/ps), transform them into a command string, and execute it (for example, apache2ctl -t built from pgrep -lfa output), which can lead to root code execution.
It uses **/bin/sh** syntax, so can run in anything supporting `sh` (and the binaries and parameters used).
@@ -170,7 +170,7 @@ LinPEAS uses colors to indicate where does each section begin. But **it also use
- The ![](https://placehold.it/15/b32400/000000?text=+) **Red** color is used for identifing suspicious configurations that could lead to privilege escalation.
- The ![](https://placehold.it/15/66ff33/000000?text=+) **Green** color is used for known good configurations (based on the name not on the conten!)
- The ![](https://placehold.it/15/66ff33/000000?text=+) **Green** color is used for known good configurations (based on the name not on the content!)
- The ![](https://placehold.it/15/0066ff/000000?text=+) **Blue** color is used for: Users without shell & Mounted devices

View File

@@ -33,7 +33,7 @@ if __name__ == "__main__":
parser.add_argument('--small', action='store_true', help='Build small version of linpeas.')
parser.add_argument('--include', type=str, help='Build linpeas only with the modules indicated you can indicate section names or module IDs).')
parser.add_argument('--exclude', type=str, help='Exclude the given modules (you can indicate section names or module IDs).')
parser.add_argument('--output', required=True, type=str, help='Parth to write the final linpeas file to.')
parser.add_argument('--output', required=True, type=str, help='Path to write the final linpeas file to.')
args = parser.parse_args()
all_modules = args.all

View File

@@ -26,7 +26,7 @@
# License: GNU GPL
# Version: 1.0
# Functions Used: echo_not_found, print_2title, print_info
# Global Variables:
# Global Variables: $NoEnvVars, $EnvVarsRed
# Initial Functions:
# Generated Global Variables:
# Fat linpeas: 0
@@ -35,5 +35,5 @@
print_2title "Environment"
print_info "Any private information inside environment variables?"
(env || printenv || set) 2>/dev/null | grep -v "RELEVANT*|FIND*|^VERSION=|dbuslistG|mygroups|ldsoconfdG|pwd_inside_history|kernelDCW_Ubuntu_Precise|kernelDCW_Ubuntu_Trusty|kernelDCW_Ubuntu_Xenial|kernelDCW_Rhel|^sudovB=|^rootcommon=|^mounted=|^mountG=|^notmounted=|^mountpermsB=|^mountpermsG=|^kernelB=|^C=|^RED=|^GREEN=|^Y=|^B=|^NC=|TIMEOUT=|groupsB=|groupsVB=|knw_grps=|sidG|sidB=|sidVB=|sidVB2=|sudoB=|sudoG=|sudoVB=|timersG=|capsB=|notExtensions=|Wfolders=|writeB=|writeVB=|_usrs=|compiler=|LS_COLORS=|pathshG=|notBackup=|processesDump|processesB|commonrootdirs|USEFUL_SOFTWARE|PSTORAGE_" | sed -${E} "s,[pP][aA][sS][sS][wW]|[aA][pP][iI][kK][eE][yY]|[aA][pP][iI][_][kK][eE][yY]|KRB5CCNAME,${SED_RED},g" || echo_not_found "env || set"
(env || printenv || set) 2>/dev/null | grep -Eiv "$NoEnvVars" | sed -${E} "s,$EnvVarsRed,${SED_RED},g" || echo_not_found "env || set"
echo ""

View File

@@ -0,0 +1,121 @@
# Title: Processes & Cron & Services & Timers - Unsafe pgrep/ps → command execution
# ID: PR_Unsafe_processlist_cmd_exec
# Author: HT Bot
# Last Update: 2025-08-27
# Description: Detect privileged cron/systemd scripts that read process command lines (pgrep/ps),
# transform them into a command string and execute it (e.g., cmd var / eval). This
# catches patterns like the apache2ctl -t injection from pgrep -lfa found in HTB Zero.
# License: GNU GPL
# Version: 1.0
# Functions Used: print_2title, print_info
# Global Variables: $SEARCH_IN_FOLDER
# Initial Functions:
# Generated Global Variables: $candfile, $line, $file, $svc, $user, $exec, $pgrep_lines, $ps_lines, $exec_lines, $hint, $pattern_dollar
# Fat linpeas: 0
# Small linpeas: 1
if ! [ "$SEARCH_IN_FOLDER" ]; then
print_2title "Unsafe process-list command execution in privileged jobs"
print_info "Looks for root cron/systemd scripts that build commands from pgrep/ps output and execute them (e.g., pgrep -lfa → var 'cmd' → exec/eval). If found, try forging a matching process argv to get code run as root."
candfile=$(mktemp 2>/dev/null || echo "/tmp/linpeas.candidates.$$")
# 1) Collect candidates from cron
for f in /etc/crontab /etc/anacrontab /var/spool/cron/crontabs/root; do
[ -r "$f" ] && cat "$f" 2>/dev/null | grep -vE '^[[:space:]]*#' | awk '{print $0}' || true
done |
while IFS= read -r line || [ -n "$line" ]; do
case "$line" in
""|\#*) continue ;;
esac
# Extract absolute paths from the line
echo "$line" | grep -oE '/[A-Za-z0-9_./-]+' 2>/dev/null | while IFS= read -r file; do
[ -e "$file" ] && printf '%s\n' "$file" >>"$candfile"
# Expand run-parts directories
if echo "$line" | grep -qE '\brun-parts\b' && [ -d "$file" ]; then
ls -1 "$file" 2>/dev/null | while IFS= read -r x; do
[ -f "$file/$x" ] && printf '%s\n' "$file/$x" >>"$candfile"
done
fi
done
done
# Include files inside cron directories
for d in /etc/cron.d /etc/cron.daily /etc/cron.hourly /etc/cron.weekly /etc/cron.monthly; do
[ -d "$d" ] || continue
find "$d" -maxdepth 1 -type f -readable 2>/dev/null >>"$candfile"
done
# 2) Collect candidates from systemd (services running as root)
if command -v systemctl >/dev/null 2>&1; then
systemctl list-units --type=service --all 2>/dev/null | awk '{print $1}' | grep -E '\.service$' | while IFS= read -r svc; do
user=$(systemctl show "$svc" -p User 2>/dev/null | cut -d= -f2)
# Default user is root when empty; consider both empty and 'root'
if [ -z "$user" ] || [ "$user" = "root" ]; then
exec=$(systemctl show "$svc" -p ExecStart 2>/dev/null | cut -d= -f2-)
# Extract absolute paths referenced in ExecStart
printf '%s' "$exec" | grep -oE '/[A-Za-z0-9_./-]+' 2>/dev/null | while IFS= read -r file; do
[ -e "$file" ] && printf '%s\n' "$file" >>"$candfile"
done
fi
done
fi
# De-duplicate and trim to a reasonable number
if [ -s "$candfile" ]; then
sort -u "$candfile" | head -n 150 | while IFS= read -r file; do
# Only plain text, readable files <= 500KB
[ -r "$file" ] || continue
[ -f "$file" ] || continue
# Skip obvious binaries
case "$(head -c 4 "$file" 2>/dev/null | od -An -t x1 | tr -d ' \n')" in
7f454c46|cafebabe|feedface|feedfacf) continue;;
esac
[ $(wc -c <"$file" 2>/dev/null) -le 512000 ] || continue
# Look for pgrep/ps grabbing command lines
pgrep_lines=$(grep -nE '\bpgrep\b[^\n]*\-(f|\-\-full)' "$file" 2>/dev/null)
ps_lines=$(grep -nE '\bps\b[^\n]*\-o[[:space:]]*(pid,(cmd|args)|command)|\bps\b[^\n]*\-ef' "$file" 2>/dev/null)
[ -z "$pgrep_lines$ps_lines" ] && continue
# Look for building a command string and executing it
exec_lines=""
# variable execution via a variable named "cmd"
pattern_dollar="\$"
if grep -nE '^[[:space:]]*cmd *=.*' "$file" 2>/dev/null | grep -q '.'; then
exec_lines=$(grep -nE "(^|[;&|][[:space:]]*)${pattern_dollar}cmd(\b|[[:space:]])" "$file" 2>/dev/null)
fi
# eval/bash -c patterns
exec_lines=${exec_lines}
exec_lines=$(printf '%s\n' "$exec_lines"; grep -nE '\beval\b[[:space:]]+"?\$?[A-Za-z_][A-Za-z0-9_]*' "$file" 2>/dev/null)
exec_lines=$(printf '%s\n' "$exec_lines"; grep -nE '\b(bash|sh)\b[[:space:]]+\-c[[:space:]]+"?\$?[A-Za-z_][A-Za-z0-9_]*' "$file" 2>/dev/null)
[ -z "$exec_lines" ] && continue
echo "[!] Potentially vulnerable privileged script: $file"
[ -n "$pgrep_lines" ] && echo "$pgrep_lines" | sed 's/^/ pgrep: /'
[ -n "$ps_lines" ] && echo "$ps_lines" | sed 's/^/ ps: /'
echo "$exec_lines" | sed 's/^/ exec: /'
# Extra hint if apache2ctl -t appears
if grep -qE 'apache2ctl' "$file" 2>/dev/null && grep -qE '\-t(\b|[[:space:]])' "$file" 2>/dev/null; then
hint=" hint: script references 'apache2ctl -t' — try forging argv via a fake process name to load attacker-controlled config (e.g., -d/-f)."
echo "$hint"
fi
echo
done
fi
rm -f "$candfile" 2>/dev/null
else
# Folder mode: best-effort regex scan within the provided directory (bounded)
print_2title "Unsafe process-list command execution (folder scan)"
print_info "Searching for scripts that read pgrep/ps output and execute a constructed command."
find "${SEARCH_IN_FOLDER}" -type f -maxdepth 5 -size -512k 2>/dev/null \
| xargs -I{} sh -c 'grep -qE "\\bpgrep\\b.*-(f|--full)|\\bps\\b.*-o[[:space:]]*(pid,(cmd|args)|command)|\\bps\\b.*-ef" "{}" 2>/dev/null && \
grep -qE "(^|[;&|][[:space:]]*)\(\$[cC][mM][dD])(\\b|[[:space:]])|\\beval\\b|\\b(bash|sh)\\b[[:space:]]+-c" "{}" 2>/dev/null && echo "[!] Potential match: {}"' \
| head -n 50
echo
fi

View File

@@ -8,7 +8,7 @@
# Functions Used: check_dns, check_icmp, check_tcp_443, check_tcp_443_bin, check_tcp_80, print_2title, check_external_hostname
# Global Variables:
# Initial Functions:
# Generated Global Variables: $pid4, $pid2, $pid1, $pid3, $pid5, $NOT_CHECK_EXTERNAL_HOSTNAME, $TIMEOUT_INTERNET_SECONDS
# Generated Global Variables: $pid4, $pid2, $pid1, $pid3, $$tcp443_bin_status, $NOT_CHECK_EXTERNAL_HOSTNAME, $TIMEOUT_INTERNET_SECONDS
# Fat linpeas: 0
# Small linpeas: 0
@@ -19,24 +19,30 @@ print_2title "Internet Access?"
TIMEOUT_INTERNET_SECONDS=5
if [ "$SUPERFAST" ]; then
TIMEOUT_INTERNET_SECONDS=2
TIMEOUT_INTERNET_SECONDS=2.5
fi
# Run all checks in background
check_tcp_80 2>/dev/null & pid1=$!
check_tcp_443 2>/dev/null & pid2=$!
check_tcp_443_bin 2>/dev/null & pid3=$!
check_icmp 2>/dev/null & pid4=$!
check_dns 2>/dev/null & pid5=$!
check_tcp_80 "$TIMEOUT_INTERNET_SECONDS" 2>/dev/null & pid1=$!
check_tcp_443 "$TIMEOUT_INTERNET_SECONDS" 2>/dev/null & pid2=$!
check_icmp "$TIMEOUT_INTERNET_SECONDS" 2>/dev/null & pid3=$!
check_dns "$TIMEOUT_INTERNET_SECONDS" 2>/dev/null & pid4=$!
# Kill all after 10 seconds
(sleep $TIMEOUT_INTERNET_SECONDS && kill -9 $pid1 $pid2 $pid3 $pid4 $pid5 2>/dev/null) &
(sleep $(( $TIMEOUT_INTERNET_SECONDS + 1 )) && kill -9 $pid1 $pid2 $pid3 $pid4 2>/dev/null) &
check_tcp_443_bin $TIMEOUT_INTERNET_SECONDS 2>/dev/null
tcp443_bin_status=$?
wait $pid1 $pid2 $pid3 $pid4 2>/dev/null
# Wait for all to finish
wait $pid1 $pid2 $pid3 $pid4 $pid5 2>/dev/null
wait 2>/dev/null
if ! [ "$SUPERFAST" ] && ! [ "$NOT_CHECK_EXTERNAL_HOSTNAME" ]; then
if [ "$tcp443_bin_status" -eq 0 ] && \
[ -z "$SUPERFAST" ] && [ -z "$NOT_CHECK_EXTERNAL_HOSTNAME" ]; then
echo ""
print_2title "Is hostname malicious or leaked?"
print_info "This will check the public IP and hostname in known malicious lists and leaks to find any relevant information about the host."

View File

@@ -8,7 +8,7 @@
# Functions Used: print_2title
# Global Variables: $DEBUG, $knw_usrs, $nosh_usrs, $sh_usrs, $DEBUG, $USER, $STRINGS
# Initial Functions:
# Generated Global Variables: $mysqluser, $mysqlexec, $mysqlconnect, $mysqlconnectnopass
# Generated Global Variables: $mysqluser, $mysqlexec, $mysqlconnect, $mysqlconnectnopass, $mysqluser, $version_output, $major_version, $version, $process_info
# Fat linpeas: 0
# Small linpeas: 1
@@ -102,4 +102,42 @@ if [ "$(command -v mysql || echo -n '')" ] || [ "$(command -v mysqladmin || echo
else echo_no
fi
echo ""
fi
### This section checks if MySQL (mysqld) is running as root and if its version is 4.x or 5.x to refer a known local privilege escalation exploit! ###
# Find the mysqld process
process_info=$(ps aux | grep '[m]ysqld' | head -n1)
if [ -z "$process_info" ]; then
echo "MySQL process not found." | sed -${E} "s,.*,${SED_GREEN},"
else
# Extract the process user
mysqluser=$(echo "$process_info" | awk '{print $1}')
# Get the MySQL version string
version_output=$(mysqld --version 2>&1)
# Extract the version number (expects format like X.Y.Z)
version=$(echo "$version_output" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1)
if [ -z "$version" ]; then
echo "Unable to determine MySQL version." | sed -${E} "s,.*,${SED_GREEN},"
else
# Extract the major version number (X from X.Y.Z)
major_version=$(echo "$version" | cut -d. -f1)
# Check if MySQL is running as root and if the version is either 4.x or 5.x
if [ "$mysqluser" = "root" ] && { [ "$major_version" -eq 4 ] || [ "$major_version" -eq 5 ]; }; then
echo "MySQL is running as root with version $version. This is a potential local privilege escalation vulnerability!" | sed -${E} "s,.*,${SED_RED},"
echo "\tRefer to: https://www.exploit-db.com/exploits/1518" | sed -${E} "s,.*,${SED_YELLOW},"
echo "\tRefer to: https://medium.com/r3d-buck3t/privilege-escalation-with-mysql-user-defined-functions-996ef7d5ceaf" | sed -${E} "s,.*,${SED_YELLOW},"
else
echo "MySQL is running as user '$mysqluser' with version $version." | sed -${E} "s,.*,${SED_GREEN},"
fi
### ------------------------------------------------------------------------------------------------------------------------------------------------ ###
fi
fi

View File

@@ -0,0 +1,22 @@
# Title: Interesting Files - Interesting Environment Variables
# ID: IF_Interesting_environment_variables
# Author: Jack Vaughn
# Last Update: 25-05-2025
# Description: Searching possible sensitive environment variables inside of /proc/*/environ
# License: GNU GPL
# Version: 1.0
# Functions Used: print_2title
# Global Variables: $MACPEAS, $NoEnvVars, $EnvVarsRed
# Initial Functions:
# Generated Global Variables:
# Fat linpeas: 0
# Small linpeas: 1
if [ -z "$MACPEAS" ]; then
print_2title "Checking all env variables in /proc/*/environ removing duplicates and filtering out useless env vars"
cat /proc/[0-9]*/environ 2>/dev/null | \
tr '\0' '\n' | \
grep -Eiv "$NoEnvVars" | \
sort -u | \
sed -${E} "s,$EnvVarsRed,${SED_RED},g"
fi

View File

@@ -8,25 +8,19 @@
# Functions Used:
# Global Variables:
# Initial Functions:
# Generated Global Variables: $pid, $pids
# Generated Global Variables: $TIMEOUT_INTERNET_SECONDS_DNS, $local_pid
# Fat linpeas: 0
# Small linpeas: 1
check_dns(){
local TIMEOUT_INTERNET_SECONDS_DNS=$1
if ! [ -f "/bin/bash" ]; then
echo " /bin/bash not found"
return
fi
/bin/bash -c '
for ip in 1.1.1.1 8.8.8.8 ; do
(( echo cfc9 0100 0001 0000 0000 0000 0a64 7563 6b64 7563 6b67 6f03 636f 6d00 0001 0001 | xxd -p -r >&3; dd bs=9000 count=1 <&3 2>/dev/null | xxd ) 3>/dev/udp/$ip/53 && echo "DNS available" && exit 0) &
pids+=($!)
done
for pid in ${pids[@]}; do
wait $pid && exit 0
done
echo "DNS not available"
' 2>/dev/null | grep "available" || echo "DNS not available"
# example.com
(bash -c '((( echo cfc9 0100 0001 0000 0000 0000 0a64 7563 6b64 7563 6b67 6f03 636f 6d00 0001 0001 | xxd -p -r >&3; dd bs=9000 count=1 <&3 2>/dev/null | xxd ) 3>/dev/udp/1.1.1.1/53 && echo "DNS accessible") | grep "accessible" && exit 0 ) 2>/dev/null || echo "DNS is not accessible"') & local_pid=$!
sleep $TIMEOUT_INTERNET_SECONDS_DNS && kill -9 $local_pid 2>/dev/null && echo "DNS is not accessible"
}

View File

@@ -8,11 +8,20 @@
# Functions Used:
# Global Variables:
# Initial Functions:
# Generated Global Variables:
# Generated Global Variables: $TIMEOUT_INTERNET_SECONDS_ICMP, $local_pid
# Fat linpeas: 0
# Small linpeas: 1
check_icmp(){
(ping -c 1 1.1.1.1 | grep -E "1 received|1 packets received" && echo "Ping is available" || echo "Ping is not available" 2>/dev/null) | grep -i "available"
local TIMEOUT_INTERNET_SECONDS_ICMP=$1
if ! [ "$(command -v ping 2>/dev/null || echo -n '')" ]; then
echo " ping not found"
return
fi
# example.com
((ping -c 1 1.1.1.1 2>/dev/null | grep -Ei "1 received|1 packets received" && echo "ICMP is accessible" || echo "ICMP is not accessible" 2>/dev/null) | grep "accessible" && exit 0 ) 2>/dev/null || echo "ICMP is not accessible" & local_pid=$!
sleep $TIMEOUT_INTERNET_SECONDS_ICMP && kill -9 $local_pid 2>/dev/null && echo "ICMP is not accessible"
}

View File

@@ -8,30 +8,21 @@
# Functions Used:
# Global Variables:
# Initial Functions:
# Generated Global Variables: $pid, $pids
# Generated Global Variables: $local_pid, $TIMEOUT_INTERNET_SECONDS_443
# Fat linpeas: 0
# Small linpeas: 1
check_tcp_443(){
local TIMEOUT_INTERNET_SECONDS_443=$1
if ! [ -f "/bin/bash" ]; then
echo " /bin/bash not found"
return
fi
/bin/bash -c '
for ip in 1.1.1.1 8.8.8.8; do
(echo >/dev/tcp/$ip/443 && echo "Port 443 is accessible" && exit 0) &
pids+=($!)
done
for pid in ${pids[@]}; do
wait $pid && exit 0
done
echo "Port 80 is not accessible"
' 2>/dev/null | grep "accessible" || echo "Port 80 is not accessible"
# example.com
(bash -c '(echo >/dev/tcp/104.18.74.230/443 2>/dev/null && echo "Port 443 is accessible" && exit 0) 2>/dev/null || echo "Port 443 is not accessible"') & local_pid=$!
sleep $TIMEOUT_INTERNET_SECONDS_443 && kill -9 $local_pid 2>/dev/null && echo "Port 443 is not accessible"
}

View File

@@ -8,16 +8,39 @@
# Functions Used:
# Global Variables:
# Initial Functions:
# Generated Global Variables:
# Generated Global Variables: $url_lambda, $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://2e6ppt7izvuv66qmx2r3et2ufi0mxwqs.lambda-url.us-east-1.on.aws/"
check_tcp_443_bin(){
if command -v curl >/dev/null 2>&1; then
curl -s "https://2e6ppt7izvuv66qmx2r3et2ufi0mxwqs.lambda-url.us-east-1.on.aws/" -H "User-Agent: linpeas" -H "Content-Type: application/json" >/dev/null 2>&1 && echo "Port 443 is accessible with curl" || echo "Port 443 is not accessible with curl"
if curl -s --connect-timeout $TIMEOUT_INTERNET_SECONDS_443_BIN "$url_lambda" \
-H "User-Agent: linpeas" -H "Content-Type: application/json" >/dev/null 2>&1
then
echo "Port 443 is accessible with curl"
return 0 # ✅ success
else
echo "Port 443 is not accessible with curl"
return 1
fi
elif command -v wget >/dev/null 2>&1; then
wget -q -O - "https://2e6ppt7izvuv66qmx2r3et2ufi0mxwqs.lambda-url.us-east-1.on.aws/" --header "User-Agent: linpeas" -H "Content-Type: application/json" >/dev/null 2>&1 && echo "Port 443 is accessible with wget" || echo "Port 443 is not accessible with wget"
if wget -q --timeout=$TIMEOUT_INTERNET_SECONDS_443_BIN -O - "$url_lambda" \
--header "User-Agent: linpeas" -H "Content-Type: application/json" >/dev/null 2>&1
then
echo "Port 443 is accessible with wget"
return 0
else
echo "Port 443 is not accessible with wget"
return 1
fi
else
echo "Neither curl nor wget available"
return 1
fi
}
}

View File

@@ -8,25 +8,21 @@
# Functions Used:
# Global Variables:
# Initial Functions:
# Generated Global Variables: $pid, $pids
# Generated Global Variables: $local_pid, $TIMEOUT_INTERNET_SECONDS_80
# Fat linpeas: 0
# Small linpeas: 1
check_tcp_80(){
local TIMEOUT_INTERNET_SECONDS_80=$1
if ! [ -f "/bin/bash" ]; then
echo " /bin/bash not found"
return
fi
/bin/bash -c '
for ip in 1.1.1.1 8.8.8.8; do
(echo >/dev/tcp/$ip/80 && echo "Port 80 is accessible" && exit 0) &
pids+=($!)
done
for pid in ${pids[@]}; do
wait $pid && exit 0
done
echo "Port 80 is not accessible"
' 2>/dev/null | grep "accessible"
# example.com
(bash -c '(echo >/dev/tcp/104.18.74.230/80 2>/dev/null && echo "Port 80 is accessible" && exit 0) 2>/dev/null || echo "Port 80 is not accessible"') & local_pid=$!
sleep $TIMEOUT_INTERNET_SECONDS_80 && kill -9 $local_pid 2>/dev/null && echo "Port 80 is not accessible"
}

View File

@@ -0,0 +1,18 @@
# Title: Variables - EnvVarsRed
# ID: EnvVarsRed
# Author: Carlos Polop
# Last Update: 26-05-2025
# Description: Useless env vars
# License: GNU GPL
# Version: 1.0
# Functions Used:
# Global Variables:
# Initial Functions:
# Generated Global Variables: $EnvVarsRed
# Fat linpeas: 0
# Small linpeas: 1
EnvVarsRed="[pP][aA][sS][sS][wW]|[aA][pP][iI][kK][eE][yY]|[aA][pP][iI][_][kK][eE][yY]|KRB5CCNAME|[aA][pP][iI][_][kK][eE][yY]|[aA][wW][sS]|[aA][zZ][uU][rR][eE]|[gG][cC][pP]|[aA][pP][iI]|[sS][eE][cC][rR][eE][tT]|[sS][qQ][lL]|[dD][aA][tT][aA][bB][aA][sS][eE]|[tT][oO][kK][eE][nN]"

View File

@@ -0,0 +1,16 @@
# Title: Variables - NoEnvVars
# ID: NoEnvVars
# Author: Carlos Polop
# Last Update: 26-05-2025
# Description: Useless env vars
# License: GNU GPL
# Version: 1.0
# Functions Used:
# Global Variables:
# Initial Functions:
# Generated Global Variables: $NoEnvVars
# Fat linpeas: 0
# Small linpeas: 1
NoEnvVars="LESS_TERMCAP|JOURNAL_STREAM|XDG_SESSION|DBUS_SESSION|systemd\/sessions|systemd_exec|MEMORY_PRESSURE_WATCH|RELEVANT*|FIND*|^VERSION=|dbuslistG|mygroups|ldsoconfdG|pwd_inside_history|kernelDCW_Ubuntu_Precise|kernelDCW_Ubuntu_Trusty|kernelDCW_Ubuntu_Xenial|kernelDCW_Rhel|^sudovB=|^rootcommon=|^mounted=|^mountG=|^notmounted=|^mountpermsB=|^mountpermsG=|^kernelB=|^C=|^RED=|^GREEN=|^Y=|^B=|^NC=|TIMEOUT=|groupsB=|groupsVB=|knw_grps=|sidG|sidB=|sidVB=|sidVB2=|sudoB=|sudoG=|sudoVB=|timersG=|capsB=|notExtensions=|Wfolders=|writeB=|writeVB=|_usrs=|compiler=|LS_COLORS=|pathshG=|notBackup=|processesDump|processesB|commonrootdirs|USEFUL_SOFTWARE|PSTORAGE_|^PATH=|^INVOCATION_ID=|^WATCHDOG_PID=|^LISTEN_PID="

View File

@@ -292,9 +292,12 @@ class LinpeasBaseBuilder:
all_module_paths += self.enumerate_directory(LINPEAS_PARTS["variables"])
for module in LINPEAS_PARTS["modules"]:
exclude = False
for ex_module in exclude_modules:
if ex_module in module["folder_path"] or ex_module in [module["name"], module["name_check"]]:
continue
exclude = True
break
if exclude: continue
all_module_paths += self.enumerate_directory(module["folder_path"])
for module in all_module_paths:

View File

@@ -97,7 +97,7 @@ class LinpeasBuilder:
for orig_url in urls:
tar_gz_bin_name = ""
if ",,," in orig_url:
tar_gz_bin_name = url.split(",,,")[1]
tar_gz_bin_name = orig_url.split(",,,")[1]
url = orig_url.split(",,,")[0]
else:
url = orig_url
@@ -402,9 +402,9 @@ class LinpeasBuilder:
def __replace_mark(self, mark: str, find_calls: list, join_char: str):
"""Substitude the markup with the actual code"""
self.linpeas_sh = self.linpeas_sh.replace(mark, join_char.join(find_calls)) #New line char is't needed
"""Substitute the markup with the actual code"""
self.linpeas_sh = self.linpeas_sh.replace(mark, join_char.join(find_calls)) #New line char isn't needed
def write_linpeas(self, path):
"""Write on disk the final linpeas"""

View File

@@ -106,8 +106,6 @@ def parse_line(line: str):
global FINAL_JSON, C_SECTION, C_MAIN_SECTION, C_2_SECTION, C_3_SECTION
if "Cron jobs" in line:
a=1
if is_section(line, TITLE1_PATTERN):
title = parse_title(line)
@@ -145,17 +143,26 @@ def parse_line(line: str):
def parse_peass(outputpath: str, jsonpath: str = ""):
global OUTPUT_PATH, JSON_PATH
global OUTPUT_PATH, JSON_PATH, FINAL_JSON, C_SECTION, C_MAIN_SECTION, C_2_SECTION, C_3_SECTION
OUTPUT_PATH = outputpath
JSON_PATH = jsonpath
for line in open(OUTPUT_PATH, 'r', encoding="utf8").readlines():
line = line.strip()
if not line or not clean_colors(line): #Remove empty lines or lines just with colors hex
continue
# Reset globals to avoid data leaking between executions
FINAL_JSON = {}
C_SECTION = FINAL_JSON
C_MAIN_SECTION = FINAL_JSON
C_2_SECTION = FINAL_JSON
C_3_SECTION = FINAL_JSON
parse_line(line)
with open(OUTPUT_PATH, 'r', encoding="utf8") as f:
for line in f.readlines():
line = line.strip()
# Remove empty lines or lines containing only color codes
if not line or not clean_colors(line):
continue
parse_line(line)
if JSON_PATH:
with open(JSON_PATH, "w") as f:

View File

@@ -512,7 +512,7 @@ namespace winPEAS.Checks
}
else if (!string.IsNullOrEmpty(resolutionInfo.Error))
{
Beaprint.BadPrint($" {resolutionInfo.Error}");
Beaprint.PrintException($" {resolutionInfo.Error}");
}
}
catch (Exception ex)

View File

@@ -102,17 +102,15 @@ namespace winPEAS.Checks
{
vulnHandlers = ProcessesInfo.GetVulnHandlers(progress);
}
Dictionary<string, string> colors = new Dictionary<string, string>();
colors[Checks.CurrentUserName] = Beaprint.ansi_color_bad;
colors[HandlesHelper.elevatedProcess] = Beaprint.ansi_color_bad;
foreach (Dictionary<string, string> handler in vulnHandlers)
{
Dictionary<string, string> colors = new Dictionary<string, string>()
{
{ Checks.CurrentUserName, Beaprint.ansi_color_bad },
{ handler["Reason"], Beaprint.ansi_color_bad },
};
Beaprint.DictPrint(vulnHandlers, colors, true);
colors[handler["Reason"]] = Beaprint.ansi_color_bad;
}
Beaprint.DictPrint(vulnHandlers, colors, true);
}
catch (Exception ex)
{

View File

@@ -31,7 +31,7 @@ namespace winPEAS.Helpers
public static string ansi_current_user = MAGENTA;
private static string Advisory =
"winpeas should be used for authorized penetration testing and/or educational purposes only." +
"winpeas should be used for authorized penetration testing and/or educational purposes only. " +
"Any misuse of this software will not be the responsibility of the author or of any other collaborator. " +
"Use it at your own devices and/or with the device owner's permission.";
@@ -81,7 +81,7 @@ namespace winPEAS.Helpers
/---------------------------------------------------------------------------------\
| {1}Do you like PEASS?{0} |
|---------------------------------------------------------------------------------|
| {3}Learn Cloud Hacking{0} : {2}training.hacktricks.xyz {0} |
| {3}Learn Cloud Hacking{0} : {2}training.hacktricks.xyz {0} |
| {3}Follow on Twitter{0} : {2}@hacktricks_live{0} |
| {3}Respect on HTB{0} : {2}SirBroccoli {0} |
|---------------------------------------------------------------------------------|

View File

@@ -12,6 +12,7 @@ namespace winPEAS.Helpers
private const int CNST_SYSTEM_EXTENDED_HANDLE_INFORMATION = 64;
public const uint STATUS_INFO_LENGTH_MISMATCH = 0xC0000004;
public const int DUPLICATE_SAME_ACCESS = 0x2;
public const string elevatedProcess = "Access denied, process is probably elevated";
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct FILE_NAME_INFO
@@ -171,7 +172,7 @@ namespace winPEAS.Helpers
// Hex perms from https://docs.microsoft.com/en-us/windows/win32/procthread/process-security-and-access-rights and https://github.com/buffer/maltracer/blob/master/defines.py
//PROCESS_ALL_ACCESS
if ((h.GrantedAccess & 0x001F0FFF) == h.GrantedAccess)
if ((h.GrantedAccess & 0x001F0FFF) == h.GrantedAccess || (h.GrantedAccess & 0x1FFFFF) == h.GrantedAccess)
{
vulnHandler.isVuln = true;
vulnHandler.reason = "PROCESS_ALL_ACCESS";
@@ -454,6 +455,8 @@ namespace winPEAS.Helpers
}
catch
{
data["name"] = elevatedProcess;
data["sid"] = elevatedProcess;
return data;
}
finally
@@ -469,12 +472,32 @@ namespace winPEAS.Helpers
public static PT_RELEVANT_INFO getProcInfoById(int pid)
{
PT_RELEVANT_INFO pri = new PT_RELEVANT_INFO();
Process proc;
Process proc = Process.GetProcessById(pid);
try
{
proc = Process.GetProcessById(pid);
}
catch
{
pri.pid = pid;
pri.name = "Error, process may not exist";
pri.userName = "Error, process may not exist";
pri.userSid = "Error, process may not exist";
pri.imagePath = "Error, process may not exist";
return pri;
}
Dictionary<string, string> user = GetProcU(proc);
StringBuilder fileName = new StringBuilder(2000);
Native.Psapi.GetProcessImageFileName(proc.Handle, fileName, 2000);
try
{
Native.Psapi.GetProcessImageFileName(proc.Handle, fileName, 2000);
}
catch
{
fileName = new StringBuilder(elevatedProcess);
}
pri.pid = pid;
pri.name = proc.ProcessName;

View File

@@ -195,11 +195,11 @@ namespace winPEAS.Info.ProcessInfo
continue;
List<string> permsFile = PermissionsHelper.GetPermissionsFile(sFilePath, Checks.Checks.CurrentUserSiDs, PermissionType.WRITEABLE_OR_EQUIVALENT);
IdentityReference sid = null;
try
{
System.Security.AccessControl.FileSecurity fs = System.IO.File.GetAccessControl(sFilePath);
IdentityReference sid = fs.GetOwner(typeof(SecurityIdentifier));
string ownerName = sid.Translate(typeof(NTAccount)).ToString();
sid = fs.GetOwner(typeof(SecurityIdentifier));
// If current user already have permissions over that file or the proc belongs to the owner of the file,
// handler not interesting to elevate privs
@@ -207,6 +207,8 @@ namespace winPEAS.Info.ProcessInfo
continue;
to_add["File Path"] = sFilePath;
string ownerName = sid.Translate(typeof(NTAccount)).ToString();
to_add["File Owner"] = ownerName;
}
catch (System.IO.FileNotFoundException)
@@ -218,7 +220,10 @@ namespace winPEAS.Info.ProcessInfo
{
continue;
}
catch (System.Security.Principal.IdentityNotMappedException)
{
to_add["File Owner"] = sid.ToString();
}
}
else if (typeName == "key")