mirror of
https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite.git
synced 2025-12-06 17:11:29 +00:00
Compare commits
51 Commits
codex/fix-
...
20251007-0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
be3fe91da4 | ||
|
|
b8b4a0fc14 | ||
|
|
7042a182df | ||
|
|
c83eef9cd8 | ||
|
|
e15a1f2e12 | ||
|
|
24e9c54290 | ||
|
|
bdb5c61dad | ||
|
|
ee83c23a74 | ||
|
|
7b36014699 | ||
|
|
6fe8304783 | ||
|
|
262feb9896 | ||
|
|
40cf08af85 | ||
|
|
7c9f431649 | ||
|
|
31bdb339d7 | ||
|
|
bdcebadde0 | ||
|
|
4b3f4aa19e | ||
|
|
7c7884fb72 | ||
|
|
35300e499b | ||
|
|
147de0fc88 | ||
|
|
afaf596342 | ||
|
|
215c5d074e | ||
|
|
ca383a4548 | ||
|
|
46264bf239 | ||
|
|
642c33304f | ||
|
|
54d861ab04 | ||
|
|
bbb932d6d3 | ||
|
|
626ea2d298 | ||
|
|
ed01b32a95 | ||
|
|
c314cfd23d | ||
|
|
cc5ab76991 | ||
|
|
36001d644e | ||
|
|
fdd414f4aa | ||
|
|
c3e50dbdbf | ||
|
|
41128808a6 | ||
|
|
6fd96f4bdb | ||
|
|
a745f00dd7 | ||
|
|
933e12d7f1 | ||
|
|
4061cef7e8 | ||
|
|
b66ced3c63 | ||
|
|
cde725dacc | ||
|
|
f0f829890c | ||
|
|
99c36b8562 | ||
|
|
a74c6c820f | ||
|
|
53fd4d8dc8 | ||
|
|
9b37fd4ef4 | ||
|
|
f27b1d4816 | ||
|
|
d335b9254f | ||
|
|
d5e3c2a885 | ||
|
|
4af321d138 | ||
|
|
39066f6867 | ||
|
|
859a44230d |
201
.github/workflows/PR-tests.yml
vendored
Normal file
201
.github/workflows/PR-tests.yml
vendored
Normal 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
|
||||
@@ -895,6 +895,14 @@ search:
|
||||
type: f
|
||||
search_in:
|
||||
- common
|
||||
|
||||
- name: "credentials.tfrc.json"
|
||||
value:
|
||||
type: f
|
||||
bad_regex: ".*"
|
||||
search_in:
|
||||
- common
|
||||
|
||||
|
||||
- name: Racoon
|
||||
value:
|
||||
@@ -1265,7 +1273,7 @@ search:
|
||||
type: f
|
||||
bad_regex: ".*"
|
||||
search_in:
|
||||
- common
|
||||
- common
|
||||
|
||||
- name: Cloud Credentials
|
||||
value:
|
||||
@@ -2059,6 +2067,11 @@ search:
|
||||
type: f
|
||||
search_in:
|
||||
- common
|
||||
- name: "private-keys-v1.d/*.key"
|
||||
value:
|
||||
type: f
|
||||
search_in:
|
||||
- common
|
||||
|
||||
- name: "*.gnupg"
|
||||
value:
|
||||
@@ -3941,3 +3954,24 @@ search:
|
||||
type: f
|
||||
search_in:
|
||||
- common
|
||||
|
||||
- name: Crontab-UI
|
||||
value:
|
||||
config:
|
||||
auto_check: True
|
||||
|
||||
files:
|
||||
- name: "crontab.db"
|
||||
value:
|
||||
bad_regex: "-P[[:space:]]+\\S+|--password[[:space:]]+\\S+|[Pp]ass(word)?|[Tt]oken|[Ss]ecret"
|
||||
only_bad_lines: True
|
||||
type: f
|
||||
search_in:
|
||||
- common
|
||||
|
||||
- name: "crontab-ui.service"
|
||||
value:
|
||||
just_list_file: True
|
||||
type: f
|
||||
search_in:
|
||||
- common
|
||||
|
||||
@@ -170,7 +170,7 @@ LinPEAS uses colors to indicate where does each section begin. But **it also use
|
||||
|
||||
- The  **Red** color is used for identifing suspicious configurations that could lead to privilege escalation.
|
||||
|
||||
- The  **Green** color is used for known good configurations (based on the name not on the conten!)
|
||||
- The  **Green** color is used for known good configurations (based on the name not on the content!)
|
||||
|
||||
- The  **Blue** color is used for: Users without shell & Mounted devices
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
# Title: Container - Writable bind mounts without nosuid (SUID risk)
|
||||
# ID: CT_RW_bind_mounts_nosuid
|
||||
# Author: HT Bot
|
||||
# Last Update: 17-09-2025
|
||||
# Description: Detect writable bind-mounted paths inside containers that are not mounted with nosuid.
|
||||
# If the container user is root and the mount is a host bind mount without nosuid, an attacker may
|
||||
# be able to drop a SUID binary on the shared path and execute it from the host to escalate to root
|
||||
# (classic container-to-host breakout via writable bind mount).
|
||||
# License: GNU GPL
|
||||
# Version: 1.0
|
||||
# Functions Used: containerCheck, print_2title, print_list, print_info
|
||||
# Global Variables: $inContainer
|
||||
# Initial Functions: containerCheck
|
||||
# Generated Global Variables: $CT_RW_bind_mounts_matches
|
||||
# Fat linpeas: 0
|
||||
# Small linpeas: 1
|
||||
|
||||
containerCheck
|
||||
|
||||
if [ "$inContainer" ]; then
|
||||
echo ""
|
||||
print_2title "Container - Writable bind mounts w/o nosuid (SUID persistence risk)"
|
||||
print_info "https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/docker-security/docker-breakout-privilege-escalation/index.html#writable-bind-mounts"
|
||||
|
||||
if [ -r /proc/self/mountinfo ]; then
|
||||
CT_RW_bind_mounts_matches=$(grep -E "(^| )bind( |$)" /proc/self/mountinfo 2>/dev/null | grep -E "(^|,)rw(,|$)" | grep -v "nosuid" || true)
|
||||
else
|
||||
CT_RW_bind_mounts_matches=$(mount -l 2>/dev/null | grep -E "bind" | grep -E "(^|,)rw(,|$)" | grep -v "nosuid" || true)
|
||||
fi
|
||||
|
||||
if [ -z "$CT_RW_bind_mounts_matches" ]; then
|
||||
print_list "Writable bind mounts without nosuid ............ No"
|
||||
else
|
||||
print_list "Writable bind mounts without nosuid ............ Yes" | sed -${E} "s,Yes,${SED_RED},"
|
||||
echo "$CT_RW_bind_mounts_matches" | sed -${E} "s,/proc/self/mountinfo,${SED_GREEN},"
|
||||
echo ""
|
||||
if [ "$(id -u 2>/dev/null)" = "0" ]; then
|
||||
print_list "Note"; echo ": You are root inside a container and there are writable bind mounts without nosuid." | sed -${E} "s,.*,${SED_RED},"
|
||||
echo " If the path is shared with the host and executable there, you may plant a SUID binary (e.g., copy /bin/bash and chmod 6777)"
|
||||
echo " and execute it from the host to obtain root. Ensure proper authorization before testing."
|
||||
else
|
||||
print_list "Note"; echo ": Current user is not root; if you obtain container root, these mounts may enable host escalation via SUID planting." | sed -${E} "s,.*,${SED_RED},"
|
||||
fi
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
@@ -0,0 +1,139 @@
|
||||
# Title: Processes & Cron & Services & Timers - Legacy r-commands and host-based trust
|
||||
# ID: PR_Rcommands_trust
|
||||
# Author: HT Bot
|
||||
# Last Update: 27-08-2025
|
||||
# Description: Detect legacy r-services (rsh/rlogin/rexec) exposure and dangerous host-based trust (.rhosts/hosts.equiv),
|
||||
# which can allow passwordless root via hostname/DNS manipulation.
|
||||
# License: GNU GPL
|
||||
# Version: 1.0
|
||||
# Functions Used: print_2title, print_3title, echo_not_found
|
||||
# Global Variables:
|
||||
# Initial Functions:
|
||||
# Generated Global Variables: $rfile, $perms, $owner, $g, $o, $any_rhosts, $shown, $f, $p
|
||||
# Fat linpeas: 0
|
||||
# Small linpeas: 1
|
||||
|
||||
if ! [ "$SEARCH_IN_FOLDER" ]; then
|
||||
print_2title "Legacy r-commands (rsh/rlogin/rexec) and host-based trust"
|
||||
|
||||
echo ""
|
||||
print_3title "Listening r-services (TCP 512-514)"
|
||||
if command -v ss >/dev/null 2>&1; then
|
||||
ss -ltnp 2>/dev/null | awk '$1 ~ /^LISTEN$/ && $4 ~ /:(512|513|514)$/ {print}' || echo_not_found "ss"
|
||||
elif command -v netstat >/dev/null 2>&1; then
|
||||
netstat -ltnp 2>/dev/null | awk '$6 ~ /LISTEN/ && $4 ~ /:(512|513|514)$/ {print}' || echo_not_found "netstat"
|
||||
else
|
||||
echo_not_found "ss|netstat"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
print_3title "systemd units exposing r-services"
|
||||
if command -v systemctl >/dev/null 2>&1; then
|
||||
systemctl list-unit-files 2>/dev/null | grep -E '^(rlogin|rsh|rexec)\.(socket|service)\b' || echo_not_found "rlogin|rsh|rexec units"
|
||||
systemctl list-sockets 2>/dev/null | grep -E '\b(rlogin|rsh|rexec)\.socket\b' || true
|
||||
else
|
||||
echo_not_found "systemctl"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
print_3title "inetd/xinetd configuration for r-services"
|
||||
if [ -f /etc/inetd.conf ]; then
|
||||
grep -vE '^\s*#|^\s*$' /etc/inetd.conf 2>/dev/null | grep -Ei '\b(shell|login|exec|rsh|rlogin|rexec)\b' 2>/dev/null || echo " No r-services found in /etc/inetd.conf"
|
||||
else
|
||||
echo_not_found "/etc/inetd.conf"
|
||||
fi
|
||||
if [ -d /etc/xinetd.d ]; then
|
||||
# Print enabled r-services in xinetd
|
||||
for f in /etc/xinetd.d/*; do
|
||||
[ -f "$f" ] || continue
|
||||
if grep -qiE '\b(service|disable)\b' "$f" 2>/dev/null; then
|
||||
if grep -qiE 'service\s+(rsh|rlogin|rexec|shell|login|exec)\b' "$f" 2>/dev/null; then
|
||||
# Only warn if not disabled
|
||||
if ! grep -qiE '^\s*disable\s*=\s*yes\b' "$f" 2>/dev/null; then
|
||||
echo " $(basename "$f") may enable r-services:"; grep -iE '^(\s*service|\s*disable)' "$f" 2>/dev/null | sed 's/^/ /'
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo_not_found "/etc/xinetd.d"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
print_3title "Installed r-service server packages"
|
||||
if command -v dpkg >/dev/null 2>&1; then
|
||||
dpkg -l 2>/dev/null | grep -E '\b(rsh-server|rsh-redone-server|krb5-rsh-server|inetutils-inetd|openbsd-inetd|xinetd|netkit-rsh)\b' || echo " No related packages found via dpkg"
|
||||
elif command -v rpm >/dev/null 2>&1; then
|
||||
rpm -qa 2>/dev/null | grep -Ei '\b(rsh|rlogin|rexec|xinetd)\b' || echo " No related packages found via rpm"
|
||||
else
|
||||
echo_not_found "dpkg|rpm"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
print_3title "/etc/hosts.equiv and /etc/shosts.equiv"
|
||||
for f in /etc/hosts.equiv /etc/shosts.equiv; do
|
||||
if [ -f "$f" ]; then
|
||||
perms=$(stat -c %a "$f" 2>/dev/null)
|
||||
owner=$(stat -c %U "$f" 2>/dev/null)
|
||||
echo " $f (perm $perms, owner $owner)"
|
||||
# Print non-comment lines
|
||||
awk 'NF && $0 !~ /^\s*#/ {print " " $0}' "$f" 2>/dev/null
|
||||
if grep -qEv '^\s*#|^\s*$' "$f" 2>/dev/null; then
|
||||
if grep -qE '(^|\s)\+' "$f" 2>/dev/null; then
|
||||
echo " [!] Wildcard '+' trust found"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
print_3title "Per-user .rhosts files"
|
||||
any_rhosts=false
|
||||
for rfile in /root/.rhosts /home/*/.rhosts; do
|
||||
if [ -f "$rfile" ]; then
|
||||
any_rhosts=true
|
||||
perms=$(stat -c %a "$rfile" 2>/dev/null)
|
||||
owner=$(stat -c %U "$rfile" 2>/dev/null)
|
||||
echo " $rfile (perm $perms, owner $owner)"
|
||||
awk 'NF && $0 !~ /^\s*#/ {print " " $0}' "$rfile" 2>/dev/null
|
||||
# Warn on insecure perms (group/other write)
|
||||
g=$(printf "%s" "$perms" | cut -c2)
|
||||
o=$(printf "%s" "$perms" | cut -c3)
|
||||
if [ "${g:-0}" -ge 2 ] || [ "${o:-0}" -ge 2 ]; then
|
||||
echo " [!] Insecure permissions (group/other write)"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
if ! $any_rhosts; then echo_not_found ".rhosts"; fi
|
||||
|
||||
echo ""
|
||||
print_3title "PAM rhosts authentication"
|
||||
shown=false
|
||||
for p in /etc/pam.d/rlogin /etc/pam.d/rsh; do
|
||||
if [ -f "$p" ]; then
|
||||
shown=true
|
||||
echo " $p:"
|
||||
(grep -nEi 'pam_rhosts|pam_rhosts_auth' "$p" 2>/dev/null || echo " no pam_rhosts* lines") | sed 's/^/ /'
|
||||
fi
|
||||
done
|
||||
if ! $shown; then echo_not_found "/etc/pam.d/rlogin|rsh"; fi
|
||||
|
||||
echo ""
|
||||
print_3title "SSH HostbasedAuthentication"
|
||||
if [ -f /etc/ssh/sshd_config ]; then
|
||||
if grep -qiE '^[^#]*HostbasedAuthentication\s+yes' /etc/ssh/sshd_config 2>/dev/null; then
|
||||
echo " HostbasedAuthentication yes (check /etc/shosts.equiv or ~/.shosts)"
|
||||
else
|
||||
echo " HostbasedAuthentication no or not set"
|
||||
fi
|
||||
else
|
||||
echo_not_found "/etc/ssh/sshd_config"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
print_3title "Potential DNS control indicators (local)"
|
||||
(ps -eo comm,args 2>/dev/null | grep -Ei '(^|/)(pdns|pdns_server|pdns_recursor|powerdns-admin)( |$)' | grep -Ev 'grep|bash' || echo " Not detected")
|
||||
|
||||
echo ""
|
||||
fi
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
# Title: Processes & Cron & Services & Timers - Crontab UI (root) Misconfiguration
|
||||
# ID: PR_Crontab_UI_misconfig
|
||||
# Author: HT Bot
|
||||
# Last Update: 2025-09-13
|
||||
# Description: Detect Crontab UI service and risky configurations that can lead to privesc:
|
||||
# - Root-run Crontab UI exposed on localhost
|
||||
# - Basic-Auth credentials in systemd Environment= (BASIC_AUTH_USER/PWD)
|
||||
# - Cron DB path (CRON_DB_PATH) and weak permissions / embedded secrets in jobs
|
||||
# License: GNU GPL
|
||||
# Version: 1.0
|
||||
# Functions Used: print_2title, print_info, print_list, echo_not_found
|
||||
# Global Variables: $SEARCH_IN_FOLDER, $SED_RED, $SED_RED_YELLOW, $NC
|
||||
# Initial Functions:
|
||||
# Generated Global Variables: $svc, $state, $user, $envvals, $port, $dbpath, $dbfile, $candidates, $procs, $perms, $basic_user, $basic_pwd, $uprint, $pprint, $dir, $found
|
||||
# Fat linpeas: 0
|
||||
# Small linpeas: 1
|
||||
|
||||
if ! [ "$SEARCH_IN_FOLDER" ]; then
|
||||
print_2title "Crontab UI (root) misconfiguration checks"
|
||||
print_info "https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/index.html#scheduledcron-jobs"
|
||||
|
||||
# Collect candidate services referencing crontab-ui
|
||||
candidates=""
|
||||
if command -v systemctl >/dev/null 2>&1; then
|
||||
candidates=$(systemctl list-units --type=service --all 2>/dev/null | awk '{print $1}' | grep -Ei '^crontab-ui\.service$' 2>/dev/null)
|
||||
fi
|
||||
|
||||
# Fallback: grep service files for ExecStart containing crontab-ui
|
||||
if [ -z "$candidates" ]; then
|
||||
for dir in /etc/systemd/system /lib/systemd/system; do
|
||||
[ -d "$dir" ] || continue
|
||||
found=$(grep -RIl "^Exec(Start|StartPre|StartPost)=.*crontab-ui" "$dir" 2>/dev/null | xargs -r -I{} basename {} 2>/dev/null)
|
||||
if [ -n "$found" ]; then
|
||||
candidates=$(printf "%s\n%s" "$candidates" "$found" | sort -u)
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Also flag if the binary exists or a process seems to be running
|
||||
if command -v crontab-ui >/dev/null 2>&1; then
|
||||
print_list "crontab-ui binary found at: $(command -v crontab-ui)"$NC
|
||||
else
|
||||
echo_not_found "crontab-ui"
|
||||
fi
|
||||
|
||||
procs=$(ps aux 2>/dev/null | grep -E "(crontab-ui|node .*crontab-ui)" | grep -v grep)
|
||||
if [ -n "$procs" ]; then
|
||||
print_list "Processes matching crontab-ui? ..................... "$NC
|
||||
printf "%s\n" "$procs"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# If no candidates detected, exit quietly
|
||||
if [ -z "$candidates" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Iterate candidates and extract interesting data
|
||||
printf "%s\n" "$candidates" | while read -r svc; do
|
||||
[ -n "$svc" ] || continue
|
||||
# Ensure suffix .service if missing
|
||||
case "$svc" in
|
||||
*.service) : ;;
|
||||
*) svc="$svc.service" ;;
|
||||
esac
|
||||
|
||||
state=""
|
||||
user=""
|
||||
if command -v systemctl >/dev/null 2>&1; then
|
||||
state=$(systemctl is-active "$svc" 2>/dev/null)
|
||||
user=$(systemctl show "$svc" -p User 2>/dev/null | cut -d= -f2)
|
||||
fi
|
||||
|
||||
[ -z "$state" ] && state="unknown"
|
||||
[ -z "$user" ] && user="unknown"
|
||||
|
||||
echo "Service: $svc (state: $state, User: $user)" | sed -${E} "s,root,${SED_RED},g"
|
||||
|
||||
# Read Environment from systemd (works even if file unreadable in many setups)
|
||||
envvals=$(systemctl show "$svc" -p Environment 2>/dev/null | cut -d= -f2-)
|
||||
if [ -n "$envvals" ]; then
|
||||
basic_user=$(printf "%s\n" "$envvals" | tr ' ' '\n' | grep -E '^BASIC_AUTH_USER=' | head -n1 | cut -d= -f2-)
|
||||
basic_pwd=$(printf "%s\n" "$envvals" | tr ' ' '\n' | grep -E '^BASIC_AUTH_PWD=' | head -n1 | cut -d= -f2-)
|
||||
dbpath=$(printf "%s\n" "$envvals" | tr ' ' '\n' | grep -E '^CRON_DB_PATH=' | head -n1 | cut -d= -f2-)
|
||||
port=$(printf "%s\n" "$envvals" | tr ' ' '\n' | grep -E '^PORT=' | head -n1 | cut -d= -f2-)
|
||||
|
||||
if [ -n "$basic_user" ] || [ -n "$basic_pwd" ]; then
|
||||
uprint="$basic_user"
|
||||
pprint="$basic_pwd"
|
||||
[ -n "$basic_pwd" ] && pprint="$basic_pwd"
|
||||
echo " └─ Basic-Auth credentials in Environment: user='${uprint}' pwd='${pprint}'" | sed -${E} "s,pwd='[^']*',${SED_RED_YELLOW},g"
|
||||
fi
|
||||
|
||||
if [ -n "$dbpath" ]; then
|
||||
echo " └─ CRON_DB_PATH: $dbpath"
|
||||
fi
|
||||
|
||||
# Check listener bound to localhost
|
||||
[ -z "$port" ] && port=8000
|
||||
if command -v ss >/dev/null 2>&1; then
|
||||
if ss -ltn 2>/dev/null | grep -qE "127\.0\.0\.1:${port}[[:space:]]"; then
|
||||
echo " └─ Listener detected on 127.0.0.1:${port} (likely Crontab UI)."
|
||||
fi
|
||||
else
|
||||
if netstat -tnl 2>/dev/null | grep -qE "127\.0\.0\.1:${port}[[:space:]]"; then
|
||||
echo " └─ Listener detected on 127.0.0.1:${port} (likely Crontab UI)."
|
||||
fi
|
||||
fi
|
||||
|
||||
# If we know DB path, try to read crontab.db for obvious secrets and check perms
|
||||
if [ -n "$dbpath" ] && [ -d "$dbpath" ] && [ -r "$dbpath" ]; then
|
||||
dbfile="$dbpath/crontab.db"
|
||||
if [ -f "$dbfile" ]; then
|
||||
perms=$(ls -ld "$dbpath" 2>/dev/null | awk '{print $1, $3, $4}')
|
||||
echo " └─ DB dir perms: $perms"
|
||||
if [ -w "$dbpath" ] || [ -w "$dbfile" ]; then
|
||||
echo " └─ Writable by current user -> potential job injection!" | sed -${E} "s,.*,${SED_RED},g"
|
||||
fi
|
||||
echo " └─ Inspecting $dbfile for embedded secrets in commands (zip -P / --password / pass/token/secret)..."
|
||||
grep -E "-P[[:space:]]+\S+|--password[[:space:]]+\S+|[Pp]ass(word)?|[Tt]oken|[Ss]ecret" "$dbfile" 2>/dev/null | head -n 20 | sed -${E} "s,(${SED_RED_YELLOW}),\1,g"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
echo ""
|
||||
done
|
||||
fi
|
||||
|
||||
@@ -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
|
||||
@@ -13,5 +13,5 @@
|
||||
# Small linpeas: 1
|
||||
|
||||
|
||||
sudoVB1=" \*|env_keep\W*\+=.*LD_PRELOAD|env_keep\W*\+=.*LD_LIBRARY_PATH|peass{SUDOVB1_HERE}"
|
||||
sudoVB2="peass{SUDOVB2_HERE}"
|
||||
sudoVB1=" \*|env_keep\W*\+=.*LD_PRELOAD|env_keep\W*\+=.*LD_LIBRARY_PATH|env_keep\W*\+=.*BASH_ENV|env_keep\W*\+=.* ENV|peass{SUDOVB1_HERE}"
|
||||
sudoVB2="peass{SUDOVB2_HERE}"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Title: Variables - sudovB
|
||||
# ID: sudovB
|
||||
# Author: Carlos Polop
|
||||
# Last Update: 22-08-2023
|
||||
# Last Update: 04-10-2025
|
||||
# Description: Sudo version bad regex
|
||||
# License: GNU GPL
|
||||
# Version: 1.0
|
||||
@@ -13,4 +13,4 @@
|
||||
# Small linpeas: 1
|
||||
|
||||
|
||||
sudovB="[01].[012345678].[0-9]+|1.9.[01234][^0-9]|1.9.[01234]$|1.9.5p1"
|
||||
sudovB="[01].[012345678].[0-9]+|1.9.[01234][^0-9]|1.9.[01234]$|1.9.5p1|1\.9\.[6-9]|1\.9\.1[0-7]"
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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"""
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -22,7 +22,7 @@ $url = "https://github.com/peass-ng/PEASS-ng/releases/latest/download/winPEASany
|
||||
# One liner to download and execute winPEASany from memory in a PS shell
|
||||
$wp=[System.Reflection.Assembly]::Load([byte[]](Invoke-WebRequest "$url" -UseBasicParsing | Select-Object -ExpandProperty Content)); [winPEAS.Program]::Main("")
|
||||
|
||||
# The cprevios cmd in 2 lines
|
||||
# The previous cmd in 2 lines
|
||||
$wp=[System.Reflection.Assembly]::Load([byte[]](Invoke-WebRequest "$url" -UseBasicParsing | Select-Object -ExpandProperty Content));
|
||||
[winPEAS.Program]::Main("") #Put inside the quotes the winpeas parameters you want to use
|
||||
|
||||
@@ -74,10 +74,23 @@ winpeas.exe -lolbas #Execute also additional LOLBAS search check
|
||||
|
||||
The goal of this project is to search for possible **Privilege Escalation Paths** in Windows environments.
|
||||
|
||||
New in this version:
|
||||
- Detect potential GPO abuse by flagging writable SYSVOL paths for GPOs applied to the current host and by highlighting membership in the "Group Policy Creator Owners" group.
|
||||
|
||||
|
||||
It should take only a **few seconds** to execute almost all the checks and **some seconds/minutes during the lasts checks searching for known filenames** that could contain passwords (the time depened on the number of files in your home folder). By default only **some** filenames that could contain credentials are searched, you can use the **searchall** parameter to search all the list (this could will add some minutes).
|
||||
|
||||
The tool is based on **[SeatBelt](https://github.com/GhostPack/Seatbelt)**.
|
||||
|
||||
### New (AD-aware) checks
|
||||
|
||||
- Active Directory quick checks now include:
|
||||
- gMSA readable managed passwords: enumerate msDS-GroupManagedServiceAccount objects and report those where the current user/group is allowed to retrieve the managed password (PrincipalsAllowedToRetrieveManagedPassword).
|
||||
- AD CS (ESC4) hygiene: enumerate published certificate templates and highlight templates where the current user/group has dangerous control rights (GenericAll/WriteDacl/WriteOwner/WriteProperty/ExtendedRight) that could allow template abuse (e.g., ESC4 -> ESC1).
|
||||
|
||||
These checks are lightweight, read-only, and only run when the host is domain-joined.
|
||||
|
||||
|
||||
## Where are my COLORS?!?!?!
|
||||
|
||||
The **ouput will be colored** using **ansi** colors. If you are executing `winpeas.exe` **from a Windows console**, you need to set a registry value to see the colors (and open a new CMD):
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Text.RegularExpressions" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Linq" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
<package id="System.Runtime.Numerics" version="4.3.0" targetFramework="net452" />
|
||||
<package id="System.Text.Encoding" version="4.3.0" targetFramework="net452" />
|
||||
<package id="System.Text.Encoding.Extensions" version="4.3.0" targetFramework="net452" />
|
||||
<package id="System.Text.RegularExpressions" version="4.3.0" targetFramework="net452" requireReinstallation="true" />
|
||||
<package id="System.Text.RegularExpressions" version="4.3.1" targetFramework="net48" />
|
||||
<package id="System.Threading" version="4.3.0" targetFramework="net452" />
|
||||
<package id="System.Threading.Tasks" version="4.3.0" targetFramework="net452" />
|
||||
<package id="System.Threading.Timer" version="4.3.0" targetFramework="net452" />
|
||||
|
||||
@@ -83,6 +83,10 @@
|
||||
<Reference Include="System.Runtime.InteropServices.RuntimeInformation, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Text.RegularExpressions, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<HintPath>..\packages\System.Text.RegularExpressions.4.3.1\lib\net463\System.Text.RegularExpressions.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Bcl.AsyncInterfaces" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-8.0.0.0" newVersion="8.0.0.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-9.0.0.1" newVersion="9.0.0.1" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Win32.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
@@ -156,7 +156,7 @@
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Text.Encodings.Web" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-8.0.0.0" newVersion="8.0.0.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-9.0.0.1" newVersion="9.0.0.1" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Text.RegularExpressions" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
|
||||
346
winPEAS/winPEASexe/winPEAS/Checks/ActiveDirectoryInfo.cs
Normal file
346
winPEAS/winPEASexe/winPEAS/Checks/ActiveDirectoryInfo.cs
Normal file
@@ -0,0 +1,346 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.DirectoryServices;
|
||||
using System.Security.AccessControl;
|
||||
using System.Security.Principal;
|
||||
using winPEAS.Helpers;
|
||||
using winPEAS.Helpers.Registry;
|
||||
using winPEAS.Info.FilesInfo.Certificates;
|
||||
|
||||
namespace winPEAS.Checks
|
||||
{
|
||||
// Lightweight AD-oriented checks for common escalation paths (gMSA readable password, AD CS template control)
|
||||
internal class ActiveDirectoryInfo : ISystemCheck
|
||||
{
|
||||
public void PrintInfo(bool isDebug)
|
||||
{
|
||||
Beaprint.GreatPrint("Active Directory Quick Checks");
|
||||
|
||||
new List<Action>
|
||||
{
|
||||
PrintGmsaReadableByCurrentPrincipal,
|
||||
PrintAdcsMisconfigurations
|
||||
}.ForEach(action => CheckRunner.Run(action, isDebug));
|
||||
}
|
||||
|
||||
private static HashSet<string> GetCurrentSidSet()
|
||||
{
|
||||
var sids = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
try
|
||||
{
|
||||
var id = WindowsIdentity.GetCurrent();
|
||||
sids.Add(id.User.Value);
|
||||
foreach (var g in id.Groups)
|
||||
{
|
||||
sids.Add(g.Value);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Beaprint.GrayPrint(" [!] Error obtaining current SIDs: " + ex.Message);
|
||||
}
|
||||
return sids;
|
||||
}
|
||||
|
||||
private static string GetRootDseProp(string prop)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var root = new DirectoryEntry("LDAP://RootDSE"))
|
||||
{
|
||||
return root.Properties[prop]?.Value as string;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Beaprint.GrayPrint($" [!] Error accessing RootDSE ({prop}): {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetProp(SearchResult r, string name)
|
||||
{
|
||||
return (r.Properties.Contains(name) && r.Properties[name].Count > 0)
|
||||
? r.Properties[name][0]?.ToString()
|
||||
: null;
|
||||
}
|
||||
|
||||
// Detect gMSA objects where the current principal (or one of its groups) can retrieve the managed password
|
||||
private void PrintGmsaReadableByCurrentPrincipal()
|
||||
{
|
||||
try
|
||||
{
|
||||
Beaprint.MainPrint("gMSA readable managed passwords");
|
||||
Beaprint.LinkPrint(
|
||||
"https://book.hacktricks.wiki/en/windows-hardening/active-directory-methodology/gmsa.html",
|
||||
"Look for Group Managed Service Accounts you can read (msDS-ManagedPassword)");
|
||||
|
||||
if (!Checks.IsPartOfDomain)
|
||||
{
|
||||
Beaprint.GrayPrint(" [-] Host is not domain-joined. Skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
var defaultNC = GetRootDseProp("defaultNamingContext");
|
||||
if (string.IsNullOrEmpty(defaultNC))
|
||||
{
|
||||
Beaprint.GrayPrint(" [-] Could not resolve defaultNamingContext.");
|
||||
return;
|
||||
}
|
||||
|
||||
var currentSidSet = GetCurrentSidSet();
|
||||
int total = 0, readable = 0;
|
||||
|
||||
using (var baseDe = new DirectoryEntry("LDAP://" + defaultNC))
|
||||
using (var ds = new DirectorySearcher(baseDe))
|
||||
{
|
||||
ds.PageSize = 300;
|
||||
ds.Filter = "(&(objectClass=msDS-GroupManagedServiceAccount))";
|
||||
ds.PropertiesToLoad.Add("sAMAccountName");
|
||||
ds.PropertiesToLoad.Add("distinguishedName");
|
||||
// Who can read the managed password
|
||||
ds.PropertiesToLoad.Add("PrincipalsAllowedToRetrieveManagedPassword");
|
||||
|
||||
foreach (SearchResult r in ds.FindAll())
|
||||
{
|
||||
total++;
|
||||
var name = GetProp(r, "sAMAccountName") ?? GetProp(r, "distinguishedName") ?? "<unknown>";
|
||||
var dn = GetProp(r, "distinguishedName") ?? "";
|
||||
|
||||
bool canRead = false;
|
||||
// Attribute may be absent or empty
|
||||
var allowedDns = r.Properties["principalsallowedtoretrievemanagedpassword"];
|
||||
if (allowedDns != null)
|
||||
{
|
||||
foreach (var val in allowedDns)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var de = new DirectoryEntry("LDAP://" + val.ToString()))
|
||||
{
|
||||
var sidObj = de.Properties["objectSid"]?.Value as byte[];
|
||||
if (sidObj == null) continue;
|
||||
var sid = new SecurityIdentifier(sidObj, 0).Value;
|
||||
if (currentSidSet.Contains(sid))
|
||||
{
|
||||
canRead = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { /* ignore DN resolution issues */ }
|
||||
}
|
||||
}
|
||||
|
||||
if (canRead)
|
||||
{
|
||||
readable++;
|
||||
Beaprint.BadPrint($" You can retrieve managed password for gMSA: {name} (DN: {dn})");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (readable == 0)
|
||||
{
|
||||
Beaprint.GrayPrint($" [-] No gMSA with readable managed password found (checked {total}).");
|
||||
}
|
||||
else
|
||||
{
|
||||
Beaprint.GrayPrint($" [*] Hint: If such gMSA is member of Builtin\\Remote Management Users on a target, WinRM may be allowed.");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Beaprint.PrintException(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
// Detect AD CS misconfigurations
|
||||
private void PrintAdcsMisconfigurations()
|
||||
{
|
||||
try
|
||||
{
|
||||
Beaprint.MainPrint("AD CS misconfigurations for ESC");
|
||||
Beaprint.LinkPrint("https://book.hacktricks.wiki/en/windows-hardening/active-directory-methodology/ad-certificates.html");
|
||||
|
||||
if (!Checks.IsPartOfDomain)
|
||||
{
|
||||
Beaprint.GrayPrint(" [-] Host is not domain-joined. Skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
Beaprint.InfoPrint("Check for ADCS misconfigurations in the local DC registry");
|
||||
bool IsDomainController = RegistryHelper.GetReg("HKLM", @"SYSTEM\CurrentControlSet\Services\NTDS")?.ValueCount > 0;
|
||||
if (IsDomainController)
|
||||
{
|
||||
// For StrongBinding and CertificateMapping, More details in KB014754 - Registry key information:
|
||||
// https://support.microsoft.com/en-us/topic/kb5014754-certificate-based-authentication-changes-on-windows-domain-controllers-ad2c23b0-15d8-4340-a468-4d4f3b188f16
|
||||
uint? strongBinding = RegistryHelper.GetDwordValue("HKLM", @"SYSTEM\CurrentControlSet\Services\Kdc", "StrongCertificateBindingEnforcement");
|
||||
switch (strongBinding)
|
||||
{
|
||||
case 0:
|
||||
Beaprint.BadPrint(" StrongCertificateBindingEnforcement: 0 — Weak mapping allowed, vulnerable to ESC9.");
|
||||
break;
|
||||
case 2:
|
||||
Beaprint.GoodPrint(" StrongCertificateBindingEnforcement: 2 — Prevents weak UPN/DNS mappings even if SID extension missing, not vulnerable to ESC9.");
|
||||
break;
|
||||
// 1 is default behavior now I think?
|
||||
case 1:
|
||||
default:
|
||||
Beaprint.NoColorPrint($" StrongCertificateBindingEnforcement: {strongBinding} — Allow weak mapping if SID extension missing, may be vulnerable to ESC9.");
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
uint? certMapping = RegistryHelper.GetDwordValue("HKLM", @"SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL", "CertificateMappingMethods");
|
||||
if (certMapping.HasValue && (certMapping & 0x4) != 0)
|
||||
Beaprint.BadPrint($" CertificateMappingMethods: {certMapping} — Allow UPN-based mapping, vulnerable to ESC10.");
|
||||
else if(certMapping.HasValue && ((certMapping & 0x1) != 0 || (certMapping & 0x2) != 0))
|
||||
Beaprint.NoColorPrint($" CertificateMappingMethods: {certMapping} — Allow weak Subject/Issuer certificate mapping.");
|
||||
// 0x18 (strong mapping) is default behavior if not the flags above I think?
|
||||
else
|
||||
Beaprint.GoodPrint($" CertificateMappingMethods: {certMapping} — Strong Certificate mapping enabled.");
|
||||
|
||||
// We take the Active CA, can they be several?
|
||||
string caName = RegistryHelper.GetRegValue("HKLM", $@"SYSTEM\CurrentControlSet\Services\CertSvc\Configuration", "Active");
|
||||
if (!string.IsNullOrWhiteSpace(caName))
|
||||
{
|
||||
// Obscure Source for InterfaceFlag Enum:
|
||||
// https://www.sysadmins.lv/apidocs/pki/html/T_PKI_CertificateServices_Flags_InterfaceFlagEnum.htm
|
||||
uint? interfaceFlags = RegistryHelper.GetDwordValue("HKLM", $@"SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\{caName}", "InterfaceFlags");
|
||||
if (!interfaceFlags.HasValue || (interfaceFlags & 512) == 0)
|
||||
Beaprint.BadPrint(" IF_ENFORCEENCRYPTICERTREQUEST not set in InterfaceFlags — vulnerable to ESC11.");
|
||||
else
|
||||
Beaprint.GoodPrint(" IF_ENFORCEENCRYPTICERTREQUEST set in InterfaceFlags — not vulnerable to ESC11.");
|
||||
|
||||
string policyModule = RegistryHelper.GetRegValue("HKLM", $@"SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\{caName}\PolicyModules", "Active");
|
||||
if (!string.IsNullOrWhiteSpace(policyModule))
|
||||
{
|
||||
string disableExtensionList = RegistryHelper.GetRegValue("HKLM", $@"SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\{caName}\PolicyModules\{policyModule}", "DisableExtensionList");
|
||||
// zOID_NTDS_CA_SECURITY_EXT (OID 1.3.6.1.4.1.311.25.2)
|
||||
if (disableExtensionList?.Contains("1.3.6.1.4.1.311.25.2") == true)
|
||||
Beaprint.BadPrint(" szOID_NTDS_CA_SECURITY_EXT disabled for the entire CA — vulnerable to ESC16.");
|
||||
else
|
||||
Beaprint.GoodPrint(" szOID_NTDS_CA_SECURITY_EXT not disabled for the CA — not vulnerable to ESC16.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Beaprint.GrayPrint(" [-] Policy Module not found. Skipping.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Beaprint.GrayPrint(" [-] Certificate Authority not found. Skipping.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Beaprint.GrayPrint(" [-] Host is not a domain controller. Skipping ADCS Registry check");
|
||||
}
|
||||
|
||||
// Detect AD CS certificate templates where current principal has dangerous control rights(ESC4 - style)
|
||||
Beaprint.InfoPrint("\nIf you can modify a template (WriteDacl/WriteOwner/GenericAll), you can abuse ESC4");
|
||||
var configNC = GetRootDseProp("configurationNamingContext");
|
||||
if (string.IsNullOrEmpty(configNC))
|
||||
{
|
||||
Beaprint.GrayPrint(" [-] Could not resolve configurationNamingContext.");
|
||||
return;
|
||||
}
|
||||
|
||||
var currentSidSet = GetCurrentSidSet();
|
||||
int checkedTemplates = 0;
|
||||
int vulnerable = 0;
|
||||
|
||||
var templatesDn = $"LDAP://CN=Certificate Templates,CN=Public Key Services,CN=Services,{configNC}";
|
||||
|
||||
using (var deBase = new DirectoryEntry(templatesDn))
|
||||
using (var ds = new DirectorySearcher(deBase))
|
||||
{
|
||||
ds.PageSize = 300;
|
||||
ds.Filter = "(objectClass=pKICertificateTemplate)";
|
||||
ds.PropertiesToLoad.Add("cn");
|
||||
|
||||
foreach (SearchResult r in ds.FindAll())
|
||||
{
|
||||
checkedTemplates++;
|
||||
string templateCn = GetProp(r, "cn") ?? "<unknown>";
|
||||
|
||||
// Fetch security descriptor (DACL)
|
||||
DirectoryEntry de = null;
|
||||
try
|
||||
{
|
||||
de = r.GetDirectoryEntry();
|
||||
de.Options.SecurityMasks = SecurityMasks.Dacl;
|
||||
de.RefreshCache(new[] { "ntSecurityDescriptor" });
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
de?.Dispose();
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var sd = de.ObjectSecurity; // ActiveDirectorySecurity
|
||||
var rules = sd.GetAccessRules(true, true, typeof(SecurityIdentifier));
|
||||
bool hit = false;
|
||||
var hitRights = new HashSet<string>();
|
||||
|
||||
foreach (ActiveDirectoryAccessRule rule in rules)
|
||||
{
|
||||
if (rule.AccessControlType != AccessControlType.Allow) continue;
|
||||
var sid = (rule.IdentityReference as SecurityIdentifier)?.Value;
|
||||
if (string.IsNullOrEmpty(sid)) continue;
|
||||
if (!currentSidSet.Contains(sid)) continue;
|
||||
|
||||
var rights = rule.ActiveDirectoryRights;
|
||||
bool dangerous =
|
||||
rights.HasFlag(ActiveDirectoryRights.GenericAll) ||
|
||||
rights.HasFlag(ActiveDirectoryRights.WriteDacl) ||
|
||||
rights.HasFlag(ActiveDirectoryRights.WriteOwner) ||
|
||||
rights.HasFlag(ActiveDirectoryRights.WriteProperty) ||
|
||||
rights.HasFlag(ActiveDirectoryRights.ExtendedRight);
|
||||
|
||||
if (dangerous)
|
||||
{
|
||||
hit = true;
|
||||
if (rights.HasFlag(ActiveDirectoryRights.GenericAll)) hitRights.Add("GenericAll");
|
||||
if (rights.HasFlag(ActiveDirectoryRights.WriteDacl)) hitRights.Add("WriteDacl");
|
||||
if (rights.HasFlag(ActiveDirectoryRights.WriteOwner)) hitRights.Add("WriteOwner");
|
||||
if (rights.HasFlag(ActiveDirectoryRights.WriteProperty)) hitRights.Add("WriteProperty");
|
||||
if (rights.HasFlag(ActiveDirectoryRights.ExtendedRight)) hitRights.Add("ExtendedRight");
|
||||
}
|
||||
}
|
||||
|
||||
if (hit)
|
||||
{
|
||||
vulnerable++;
|
||||
Beaprint.BadPrint($" Dangerous rights over template: {templateCn} (Rights: {string.Join(",", hitRights)})");
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignore templates we couldn't read
|
||||
}
|
||||
finally
|
||||
{
|
||||
de?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (vulnerable == 0)
|
||||
{
|
||||
Beaprint.GrayPrint($" [-] No templates with dangerous rights found (checked {checkedTemplates}).");
|
||||
}
|
||||
else
|
||||
{
|
||||
Beaprint.GrayPrint(" [*] Tip: Abuse with tools like Certipy (template write -> ESC1 -> enroll).");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Beaprint.PrintException(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -90,6 +90,7 @@ namespace winPEAS.Checks
|
||||
new SystemCheck("servicesinfo", new ServicesInfo()),
|
||||
new SystemCheck("applicationsinfo", new ApplicationsInfo()),
|
||||
new SystemCheck("networkinfo", new NetworkInfo()),
|
||||
new SystemCheck("activedirectoryinfo", new ActiveDirectoryInfo()),
|
||||
new SystemCheck("cloudinfo", new CloudInfo()),
|
||||
new SystemCheck("windowscreds", new WindowsCreds()),
|
||||
new SystemCheck("browserinfo", new BrowserInfo()),
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -84,6 +84,7 @@ namespace winPEAS.Checks
|
||||
PrintLSAInfo,
|
||||
PrintNtlmSettings,
|
||||
PrintLocalGroupPolicy,
|
||||
PrintPotentialGPOAbuse,
|
||||
AppLockerHelper.PrintAppLockerPolicy,
|
||||
PrintPrintersWMIInfo,
|
||||
PrintNamedPipes,
|
||||
@@ -1131,6 +1132,94 @@ namespace winPEAS.Checks
|
||||
}
|
||||
}
|
||||
|
||||
private static void PrintPotentialGPOAbuse()
|
||||
{
|
||||
try
|
||||
{
|
||||
Beaprint.MainPrint("Potential GPO abuse vectors (applied domain GPOs writable by current user)");
|
||||
|
||||
if (!Checks.IsPartOfDomain)
|
||||
{
|
||||
Beaprint.NoColorPrint(" Host is not joined to a domain or domain info is unavailable.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Build a friendly group list for the current user to quickly spot interesting memberships
|
||||
var currentGroups = winPEAS.Info.UserInfo.User.GetUserGroups(Checks.CurrentUserName, Checks.CurrentUserDomainName) ?? new System.Collections.Generic.List<string>();
|
||||
var hasGPCO = currentGroups.Any(g => string.Equals(g, "Group Policy Creator Owners", System.StringComparison.InvariantCultureIgnoreCase));
|
||||
|
||||
if (hasGPCO)
|
||||
{
|
||||
Beaprint.BadPrint(" [!] Current user is member of 'Group Policy Creator Owners' — can create/own new GPOs. If you can link a GPO to an OU that applies here, you can execute code as SYSTEM via scheduled task/startup script.");
|
||||
}
|
||||
|
||||
var infos = GroupPolicy.GetLocalGroupPolicyInfos();
|
||||
|
||||
bool anyFinding = false;
|
||||
foreach (var info in infos)
|
||||
{
|
||||
var fileSysPath = info.FileSysPath?.ToString();
|
||||
if (string.IsNullOrEmpty(fileSysPath))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only look at domain GPOs stored in SYSVOL
|
||||
var isSysvolPath = fileSysPath.StartsWith(@"\", System.StringComparison.InvariantCultureIgnoreCase) &&
|
||||
fileSysPath.IndexOf(@"\SysVol\", System.StringComparison.InvariantCultureIgnoreCase) >= 0 &&
|
||||
fileSysPath.IndexOf(@"\Policies\", System.StringComparison.InvariantCultureIgnoreCase) >= 0;
|
||||
|
||||
if (!isSysvolPath)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check write/equivalent permissions on common abuse locations inside the GPO
|
||||
var pathsToCheck = new System.Collections.Generic.List<string>
|
||||
{
|
||||
fileSysPath,
|
||||
System.IO.Path.Combine(fileSysPath, @"Machine\Scripts\Startup"),
|
||||
System.IO.Path.Combine(fileSysPath, @"User\Scripts\Logon"),
|
||||
System.IO.Path.Combine(fileSysPath, @"Machine\Preferences\ScheduledTasks")
|
||||
};
|
||||
|
||||
foreach (var p in pathsToCheck)
|
||||
{
|
||||
var perms = PermissionsHelper.GetPermissionsFolder(p, Checks.CurrentUserSiDs, PermissionType.WRITEABLE_OR_EQUIVALENT);
|
||||
if (perms != null && perms.Count > 0)
|
||||
{
|
||||
if (!anyFinding)
|
||||
{
|
||||
Beaprint.LinkPrint("https://book.hacktricks.wiki/en/windows-hardening/active-directory-methodology/gpo-abuse.html", "Why it matters");
|
||||
}
|
||||
anyFinding = true;
|
||||
Beaprint.BadPrint($" [!] Writable applied GPO detected");
|
||||
Beaprint.NoColorPrint($" GPO Display Name : {info.DisplayName}");
|
||||
Beaprint.NoColorPrint($" GPO Name : {info.GPOName}");
|
||||
Beaprint.NoColorPrint($" GPO Link : {info.Link}");
|
||||
Beaprint.NoColorPrint($" Path : {p}");
|
||||
foreach (var entry in perms)
|
||||
{
|
||||
Beaprint.NoColorPrint($" -> {entry}");
|
||||
}
|
||||
Beaprint.GrayPrint(" Hint: Abuse by adding an immediate Scheduled Task or Startup script to execute as SYSTEM on gpupdate.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!anyFinding && !hasGPCO)
|
||||
{
|
||||
Beaprint.NoColorPrint(" No obvious GPO abuse via writable SYSVOL paths or GPCO membership detected.");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Avoid noisy stack traces in normal runs
|
||||
Beaprint.GrayPrint($" [!] Error while checking potential GPO abuse: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void PrintPowerShellSessionSettings()
|
||||
{
|
||||
try
|
||||
|
||||
@@ -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.";
|
||||
|
||||
@@ -129,6 +129,7 @@ namespace winPEAS.Helpers
|
||||
Console.WriteLine(LCYAN + " servicesinfo" + GRAY + " Search services information" + NOCOLOR);
|
||||
Console.WriteLine(LCYAN + " applicationsinfo" + GRAY + " Search installed applications information" + NOCOLOR);
|
||||
Console.WriteLine(LCYAN + " networkinfo" + GRAY + " Search network information" + NOCOLOR);
|
||||
Console.WriteLine(LCYAN + " activedirectoryinfo" + GRAY + " Quick AD checks (gMSA readable passwords, AD CS template rights)" + NOCOLOR);
|
||||
Console.WriteLine(LCYAN + " cloudinfo" + GRAY + " Enumerate cloud information" + NOCOLOR);
|
||||
Console.WriteLine(LCYAN + " windowscreds" + GRAY + " Search windows credentials" + NOCOLOR);
|
||||
Console.WriteLine(LCYAN + " browserinfo" + GRAY + " Search browser information" + NOCOLOR);
|
||||
|
||||
@@ -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;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user