mirror of
https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite.git
synced 2026-02-14 08:36:38 +00:00
Compare commits
243 Commits
20250531-a
...
test/chack
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6d79e9c46b | ||
|
|
99111a2844 | ||
|
|
231dc93ebe | ||
|
|
f7f4695b5d | ||
|
|
a0d3cf3372 | ||
|
|
c10f03955d | ||
|
|
c3a942fdba | ||
|
|
db0adb7e33 | ||
|
|
7ca05693ef | ||
|
|
0ec20d2512 | ||
|
|
3e2af030d4 | ||
|
|
ec746e73e3 | ||
|
|
6a1d1efe95 | ||
|
|
cf3565d7e0 | ||
|
|
386ef0642a | ||
|
|
0680509774 | ||
|
|
3b0a8fd616 | ||
|
|
62ef61af0f | ||
|
|
b6c4474c27 | ||
|
|
4650d6b8ad | ||
|
|
354e3b81fb | ||
|
|
2848feda9b | ||
|
|
0bec3535dc | ||
|
|
2b1ab21f66 | ||
|
|
a8c5967d21 | ||
|
|
1e68040be3 | ||
|
|
143a20f17e | ||
|
|
de542f05a4 | ||
|
|
a10675d58f | ||
|
|
5c110bd4f8 | ||
|
|
c1bf38a8ab | ||
|
|
04c0b8aab3 | ||
|
|
a6c0491438 | ||
|
|
fce28d2b81 | ||
|
|
fcc78b919a | ||
|
|
29d350fa79 | ||
|
|
1473fedcbf | ||
|
|
f8f4250b81 | ||
|
|
1fb419fa0c | ||
|
|
651dc9cd7d | ||
|
|
0808fb7f1b | ||
|
|
c332fab519 | ||
|
|
577dcc9964 | ||
|
|
b591f3d524 | ||
|
|
b3ac8c6d22 | ||
|
|
83580fcd8a | ||
|
|
ab3a5899de | ||
|
|
0fac664048 | ||
|
|
db30e3bd7d | ||
|
|
7ad87a85e6 | ||
|
|
b24694f00b | ||
|
|
e777c81eba | ||
|
|
21a86bc365 | ||
|
|
ac7cb9c73c | ||
|
|
d054715fbd | ||
|
|
b4c1043a93 | ||
|
|
1b8706aac6 | ||
|
|
3371be7bd6 | ||
|
|
2344f5b106 | ||
|
|
485f91d46c | ||
|
|
018e8866e6 | ||
|
|
d707317278 | ||
|
|
f4ef371afc | ||
|
|
61f6282b5f | ||
|
|
a363541d77 | ||
|
|
6fc41c9a23 | ||
|
|
170a4b2c70 | ||
|
|
710709834a | ||
|
|
21b2bac892 | ||
|
|
5fdb99b38e | ||
|
|
787bc8fa8a | ||
|
|
c5401bd33d | ||
|
|
bd18d96837 | ||
|
|
ede5960b7c | ||
|
|
c54f483648 | ||
|
|
e533bf3ba5 | ||
|
|
66c3d4e342 | ||
|
|
917f88b76c | ||
|
|
21a967acb5 | ||
|
|
4155093e56 | ||
|
|
be1b0cdbd0 | ||
|
|
89a55bde9b | ||
|
|
4308caddf1 | ||
|
|
54fc62d29b | ||
|
|
9216b31b10 | ||
|
|
9d8a14d2ec | ||
|
|
9c49dfd2bb | ||
|
|
9acc2ef61d | ||
|
|
e7663381f2 | ||
|
|
ce5bd84575 | ||
|
|
c447ca993d | ||
|
|
a1aa60faf8 | ||
|
|
e81c436d80 | ||
|
|
f4883f814e | ||
|
|
4a7fb83165 | ||
|
|
ff13e8bebb | ||
|
|
e80425aa3d | ||
|
|
dc5ae45cc3 | ||
|
|
ff21b3dcb9 | ||
|
|
2f44379713 | ||
|
|
2c6cbfa43d | ||
|
|
8ae2667800 | ||
|
|
43a7684621 | ||
|
|
182c8974fd | ||
|
|
7b4a83d51d | ||
|
|
8aa05e13a4 | ||
|
|
4559fd09ea | ||
|
|
4f8a3b3f25 | ||
|
|
0ed7a39a7d | ||
|
|
974cfe028f | ||
|
|
f627e80a1b | ||
|
|
a83d33d409 | ||
|
|
1cdd473d79 | ||
|
|
0e29450869 | ||
|
|
efe9c1625f | ||
|
|
4255330728 | ||
|
|
8f928f8c5d | ||
|
|
0e8959a6db | ||
|
|
ea787df91c | ||
|
|
c14f9aeb30 | ||
|
|
a86dedb553 | ||
|
|
7e4743d9be | ||
|
|
14aa117a0e | ||
|
|
7016e5a0b4 | ||
|
|
2046d18e5d | ||
|
|
7a5aa8dcae | ||
|
|
34d0f18aad | ||
|
|
b66eebcc3d | ||
|
|
49644a9813 | ||
|
|
35eb4f5be7 | ||
|
|
13656ba172 | ||
|
|
8c043b6164 | ||
|
|
aca58f36b9 | ||
|
|
dc7ce70104 | ||
|
|
a5114ef5dd | ||
|
|
ff41d5b0e7 | ||
|
|
fa58c6688b | ||
|
|
2f9115f97d | ||
|
|
3aa04a53fc | ||
|
|
373ed3cce2 | ||
|
|
8eec7cf7f9 | ||
|
|
79d53de4cf | ||
|
|
3a89398e39 | ||
|
|
1d4b748cbc | ||
|
|
69371f825e | ||
|
|
72dbd9ef28 | ||
|
|
32e9bf657a | ||
|
|
d6bd661460 | ||
|
|
ed6263a4b3 | ||
|
|
93bb3e1a64 | ||
|
|
bf9d474cd3 | ||
|
|
f856f0b588 | ||
|
|
9d35195c56 | ||
|
|
4abbf37cc0 | ||
|
|
e77867b2d3 | ||
|
|
be72fecfa8 | ||
|
|
0e52c2feea | ||
|
|
1039cc2eff | ||
|
|
3268701ed6 | ||
|
|
488d388830 | ||
|
|
85aa98a841 | ||
|
|
10b087febf | ||
|
|
b4a1382e8a | ||
|
|
877b9b81ce | ||
|
|
74521345f6 | ||
|
|
0277e447f0 | ||
|
|
b09bd92116 | ||
|
|
8f017f98d3 | ||
|
|
17cfc6c56e | ||
|
|
6100bfaceb | ||
|
|
9123910f9d | ||
|
|
7e0f678f33 | ||
|
|
b7b7aebf1c | ||
|
|
595e021864 | ||
|
|
6c75f10fae | ||
|
|
94e84dec91 | ||
|
|
ac80ce3a9a | ||
|
|
313fe6bef5 | ||
|
|
4dad7599e6 | ||
|
|
b188ac34b6 | ||
|
|
e99e64cddf | ||
|
|
dd220af544 | ||
|
|
11c0d14561 | ||
|
|
49db1df468 | ||
|
|
80318c5005 | ||
|
|
7af6c33d39 | ||
|
|
336c53a163 | ||
|
|
6877f39193 | ||
|
|
d75525ebbc | ||
|
|
29d8132d93 | ||
|
|
c16c5de36f | ||
|
|
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 | ||
|
|
4e556fd594 | ||
|
|
39066f6867 | ||
|
|
859a44230d |
18
.github/chack-agent/pr-merge-schema.json
vendored
Normal file
18
.github/chack-agent/pr-merge-schema.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"decision": {
|
||||
"type": "string",
|
||||
"enum": ["merge", "comment"]
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"confidence": {
|
||||
"type": "string",
|
||||
"enum": ["low", "medium", "high"]
|
||||
}
|
||||
},
|
||||
"required": ["decision", "message", "confidence"]
|
||||
}
|
||||
26
.github/workflows/CI-PR_from_dev.yml
vendored
26
.github/workflows/CI-PR_from_dev.yml
vendored
@@ -1,26 +0,0 @@
|
||||
name: CI-PR_from_dev
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- winpeas_dev
|
||||
- linpeas_dev
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
create_pull_request:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
# checkout
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# PR
|
||||
- name: Pull Request
|
||||
uses: repo-sync/pull-request@v2
|
||||
with:
|
||||
destination_branch: "master"
|
||||
github_token: ${{ secrets.PULL_REQUEST_TOKEN }}
|
||||
|
||||
35
.github/workflows/CI-master_tests.yml
vendored
35
.github/workflows/CI-master_tests.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
||||
steps:
|
||||
# checkout
|
||||
- name: Checkout
|
||||
uses: actions/checkout@master
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ github.head_ref }}
|
||||
|
||||
@@ -36,11 +36,11 @@ jobs:
|
||||
|
||||
# Add MSBuild to the PATH: https://github.com/microsoft/setup-msbuild
|
||||
- name: Setup MSBuild.exe
|
||||
uses: microsoft/setup-msbuild@v1.0.2
|
||||
uses: microsoft/setup-msbuild@v2
|
||||
|
||||
# Setup NuGet
|
||||
- name: Setup NuGet.exe
|
||||
uses: nuget/setup-nuget@v1
|
||||
uses: nuget/setup-nuget@v2
|
||||
|
||||
# Restore the packages for testing
|
||||
- name: Restore the application
|
||||
@@ -48,23 +48,23 @@ jobs:
|
||||
|
||||
# build
|
||||
- name: run MSBuild
|
||||
run: msbuild $env:Solution_Path
|
||||
run: msbuild $env:Solution_Path /p:Configuration=$env:Configuration /p:UseSharedCompilation=false
|
||||
|
||||
# Execute all unit tests in the solution
|
||||
#- name: Execute unit tests
|
||||
# run: dotnet test $env:Solution_Path
|
||||
- name: Execute unit tests
|
||||
run: dotnet test $env:Solution_Path --configuration $env:Configuration
|
||||
|
||||
# Build & update all versions
|
||||
- name: Build all versions
|
||||
run: |
|
||||
echo "build x64"
|
||||
msbuild -m $env:Solution_Path /t:Rebuild /p:Configuration=$env:Configuration /p:Platform="x64"
|
||||
msbuild -m $env:Solution_Path /t:Rebuild /p:Configuration=$env:Configuration /p:Platform="x64" /p:UseSharedCompilation=false
|
||||
|
||||
echo "build x86"
|
||||
msbuild -m $env:Solution_Path /t:Rebuild /p:Configuration=$env:Configuration /p:Platform="x86"
|
||||
msbuild -m $env:Solution_Path /t:Rebuild /p:Configuration=$env:Configuration /p:Platform="x86" /p:UseSharedCompilation=false
|
||||
|
||||
echo "build Any CPU"
|
||||
msbuild -m $env:Solution_Path /t:Rebuild /p:Configuration=$env:Configuration /p:Platform="Any CPU"
|
||||
msbuild -m $env:Solution_Path /t:Rebuild /p:Configuration=$env:Configuration /p:Platform="Any CPU" /p:UseSharedCompilation=false
|
||||
|
||||
- name: Execute winPEAS -h
|
||||
shell: pwsh
|
||||
@@ -212,15 +212,15 @@ jobs:
|
||||
|
||||
steps:
|
||||
# Download repo
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ github.head_ref }}
|
||||
|
||||
# Setup go
|
||||
- uses: actions/setup-go@v2
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: 1.17.0-rc1
|
||||
stable: false
|
||||
go-version: '1.23'
|
||||
cache: false
|
||||
- run: go version
|
||||
|
||||
# Build linpeas
|
||||
@@ -231,6 +231,9 @@ jobs:
|
||||
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
|
||||
|
||||
- name: Run linPEAS builder tests
|
||||
run: python3 -m unittest discover -s linPEAS/tests -p "test_*.py"
|
||||
|
||||
# Build linpeas binaries
|
||||
- name: Build linpeas binaries
|
||||
@@ -363,7 +366,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
# Download repo
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
# Build linpeas
|
||||
- name: Build macpeas
|
||||
@@ -470,11 +473,11 @@ jobs:
|
||||
|
||||
- name: Get current date
|
||||
id: date
|
||||
run: echo "::set-output name=date::$(date +'%Y%m%d')"
|
||||
run: echo "date=$(date +'%Y%m%d')" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Generate random
|
||||
id: random_n
|
||||
run: echo "::set-output name=some_rand::$(openssl rand -hex 4)"
|
||||
run: echo "some_rand=$(openssl rand -hex 4)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
# Create the release
|
||||
- name: Create Release
|
||||
|
||||
213
.github/workflows/PR-tests.yml
vendored
Normal file
213
.github/workflows/PR-tests.yml
vendored
Normal file
@@ -0,0 +1,213 @@
|
||||
name: PR-tests
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
paths-ignore:
|
||||
- '.github/**'
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
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@v5
|
||||
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@v2
|
||||
|
||||
# Setup NuGet
|
||||
- name: Setup NuGet.exe
|
||||
uses: nuget/setup-nuget@v2
|
||||
|
||||
# Restore the packages for testing
|
||||
- name: Restore the application
|
||||
run: nuget restore $env:Solution_Path
|
||||
|
||||
# build
|
||||
- name: run MSBuild
|
||||
run: msbuild $env:Solution_Path /p:Configuration=$env:Configuration /p:UseSharedCompilation=false
|
||||
|
||||
# Execute unit tests in the solution
|
||||
- name: Execute unit tests
|
||||
run: dotnet test $env:Solution_Path --configuration $env:Configuration
|
||||
|
||||
# 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" /p:UseSharedCompilation=false
|
||||
|
||||
echo "build x86"
|
||||
msbuild -m $env:Solution_Path /t:Rebuild /p:Configuration=$env:Configuration /p:Platform="x86" /p:UseSharedCompilation=false
|
||||
|
||||
echo "build Any CPU"
|
||||
msbuild -m $env:Solution_Path /t:Rebuild /p:Configuration=$env:Configuration /p:Platform="Any CPU" /p:UseSharedCompilation=false
|
||||
|
||||
- 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@v5
|
||||
with:
|
||||
ref: ${{ github.head_ref }}
|
||||
|
||||
# Setup go
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '1.23'
|
||||
cache: 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
|
||||
|
||||
- name: Run linPEAS builder tests
|
||||
run: python3 -m unittest discover -s linPEAS/tests -p "test_*.py"
|
||||
|
||||
# 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
|
||||
if: ${{ false }}
|
||||
run: linPEAS/linpeas_fat.sh -o interesting_perms_files -a
|
||||
|
||||
- name: Run linpeas interesting_files
|
||||
if: ${{ false }}
|
||||
run: linPEAS/linpeas_fat.sh -o interesting_files -a
|
||||
|
||||
Build_and_test_macpeas_pr:
|
||||
runs-on: macos-latest
|
||||
|
||||
steps:
|
||||
# Download repo
|
||||
- uses: actions/checkout@v5
|
||||
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
|
||||
if: ${{ false }}
|
||||
run: linPEAS/linpeas_fat.sh -o software_information -a
|
||||
208
.github/workflows/chack-agent-pr-triage.yml
vendored
Normal file
208
.github/workflows/chack-agent-pr-triage.yml
vendored
Normal file
@@ -0,0 +1,208 @@
|
||||
name: Chack-Agent PR Triage
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["PR-tests"]
|
||||
types: [completed]
|
||||
|
||||
jobs:
|
||||
chack_agent_triage:
|
||||
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
env:
|
||||
CHACK_LOGS_HTTP_URL: ${{ secrets.CHACK_LOGS_HTTP_URL }}
|
||||
outputs:
|
||||
should_run: ${{ steps.gate.outputs.should_run }}
|
||||
pr_number: ${{ steps.gate.outputs.pr_number }}
|
||||
pr_title: ${{ steps.gate.outputs.pr_title }}
|
||||
pr_body: ${{ steps.gate.outputs.pr_body }}
|
||||
base_ref: ${{ steps.gate.outputs.base_ref }}
|
||||
head_ref: ${{ steps.gate.outputs.head_ref }}
|
||||
base_sha: ${{ steps.gate.outputs.base_sha }}
|
||||
head_sha: ${{ steps.gate.outputs.head_sha }}
|
||||
decision: ${{ steps.parse.outputs.decision }}
|
||||
message: ${{ steps.parse.outputs.message }}
|
||||
|
||||
steps:
|
||||
- name: Resolve PR context
|
||||
id: gate
|
||||
env:
|
||||
PR_NUMBER: ${{ github.event.workflow_run.pull_requests[0].number }}
|
||||
HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
|
||||
GH_REPO: ${{ github.repository }}
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
pr_number="${PR_NUMBER}"
|
||||
if [ -z "$pr_number" ] && [ -n "$HEAD_BRANCH" ]; then
|
||||
pr_number="$(gh pr list --state open --head "$HEAD_BRANCH" --json number --jq '.[0].number')"
|
||||
fi
|
||||
if [ -z "$pr_number" ]; then
|
||||
echo "No pull request found for this workflow_run; skipping."
|
||||
echo "should_run=false" >> "$GITHUB_OUTPUT"
|
||||
echo "pr_number=" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
author="$(gh pr view "$pr_number" --json author --jq .author.login)"
|
||||
if [ "$author" != "carlospolop" ]; then
|
||||
echo "PR author is $author; skipping."
|
||||
echo "should_run=false" >> "$GITHUB_OUTPUT"
|
||||
echo "pr_number=$pr_number" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
pr_title="$(gh pr view "$pr_number" --json title --jq .title)"
|
||||
pr_body="$(gh pr view "$pr_number" --json body --jq .body)"
|
||||
base_ref="$(gh pr view "$pr_number" --json baseRefName --jq .baseRefName)"
|
||||
head_ref="$(gh pr view "$pr_number" --json headRefName --jq .headRefName)"
|
||||
base_sha="$(gh pr view "$pr_number" --json baseRefOid --jq .baseRefOid)"
|
||||
head_sha="$(gh pr view "$pr_number" --json headRefOid --jq .headRefOid)"
|
||||
|
||||
echo "should_run=true" >> "$GITHUB_OUTPUT"
|
||||
echo "pr_number=$pr_number" >> "$GITHUB_OUTPUT"
|
||||
echo "pr_title<<EOF" >> "$GITHUB_OUTPUT"
|
||||
echo "$pr_title" >> "$GITHUB_OUTPUT"
|
||||
echo "EOF" >> "$GITHUB_OUTPUT"
|
||||
echo "pr_body<<EOF" >> "$GITHUB_OUTPUT"
|
||||
echo "$pr_body" >> "$GITHUB_OUTPUT"
|
||||
echo "EOF" >> "$GITHUB_OUTPUT"
|
||||
echo "base_ref=$base_ref" >> "$GITHUB_OUTPUT"
|
||||
echo "head_ref=$head_ref" >> "$GITHUB_OUTPUT"
|
||||
echo "base_sha=$base_sha" >> "$GITHUB_OUTPUT"
|
||||
echo "head_sha=$head_sha" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Checkout PR merge ref
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
ref: refs/pull/${{ steps.gate.outputs.pr_number }}/merge
|
||||
if: ${{ steps.gate.outputs.should_run == 'true' }}
|
||||
|
||||
- name: Pre-fetch base and head refs
|
||||
if: ${{ steps.gate.outputs.should_run == 'true' }}
|
||||
run: |
|
||||
git fetch --no-tags origin \
|
||||
${{ steps.gate.outputs.base_ref }} \
|
||||
+refs/pull/${{ steps.gate.outputs.pr_number }}/head
|
||||
|
||||
- name: Set up Node.js for Codex
|
||||
if: ${{ steps.gate.outputs.should_run == 'true' }}
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: "20"
|
||||
|
||||
- name: Install Codex CLI
|
||||
if: ${{ steps.gate.outputs.should_run == 'true' }}
|
||||
run: |
|
||||
npm install -g @openai/codex
|
||||
codex --version
|
||||
|
||||
- name: Run Chack Agent
|
||||
id: run_chack
|
||||
if: ${{ steps.gate.outputs.should_run == 'true' }}
|
||||
uses: carlospolop/chack-agent@master
|
||||
with:
|
||||
provider: codex
|
||||
model_primary: CHEAP_BUT_QUALITY
|
||||
main_action: peass-ng
|
||||
sub_action: Chack-Agent PR Triage
|
||||
system_prompt: |
|
||||
You are Chack Agent, an elite PR reviewer for PEASS-ng.
|
||||
Be conservative: merge only if changes are simple, safe, and valuable accoding to the uers give guidelines.
|
||||
If in doubt, comment with clear questions or concerns.
|
||||
Remember taht you are an autonomouts agent, use the exec tool to run the needed commands to list, read, analyze, modify, test...
|
||||
tools_config_json: "{\"exec_enabled\": true}"
|
||||
session_config_json: "{\"long_term_memory_enabled\": false}"
|
||||
agent_config_json: "{\"self_critique_enabled\": false, \"require_task_steps_manager_init_first\": true}"
|
||||
output_schema_file: .github/chack-agent/pr-merge-schema.json
|
||||
user_prompt: |
|
||||
You are reviewing PR #${{ steps.gate.outputs.pr_number }} for ${{ github.repository }}.
|
||||
|
||||
Decide whether to merge or comment. Merge only if all of the following are true:
|
||||
- Changes are simple and safe (no DoS, no long operations, no backdoors).
|
||||
- Changes follow common PEASS syntax and style without breaking anything and add useful checks or value.
|
||||
- Changes simplify code or add new useful checks without breaking anything.
|
||||
|
||||
If you don't have any doubts, and all the previous conditions are met, decide to merge.
|
||||
If you have serious doubts, choose "comment" and include your doubts or questions.
|
||||
If you decide to merge, include a short rationale.
|
||||
|
||||
Pull request title and body:
|
||||
----
|
||||
${{ steps.gate.outputs.pr_title }}
|
||||
${{ steps.gate.outputs.pr_body }}
|
||||
|
||||
Review ONLY the changes introduced by the PR:
|
||||
git log --oneline ${{ steps.gate.outputs.base_sha }}...${{ steps.gate.outputs.head_sha }}
|
||||
|
||||
Output JSON only, following the provided schema:
|
||||
.github/chack-agent/pr-merge-schema.json
|
||||
openai_api_key: ${{ secrets.OPENAI_API_KEY }}
|
||||
|
||||
- name: Parse Chack Agent decision
|
||||
id: parse
|
||||
if: ${{ steps.gate.outputs.should_run == 'true' }}
|
||||
env:
|
||||
CHACK_MESSAGE: ${{ steps.run_chack.outputs.final-message }}
|
||||
run: |
|
||||
python3 - <<'PY'
|
||||
import json
|
||||
import os
|
||||
|
||||
raw = (os.environ.get('CHACK_MESSAGE', '') or '').strip()
|
||||
decision = 'comment'
|
||||
message = 'Chack Agent did not provide details.'
|
||||
try:
|
||||
data = json.loads(raw or '{}')
|
||||
if isinstance(data, dict):
|
||||
decision = data.get('decision', 'comment')
|
||||
message = data.get('message', '').strip() or message
|
||||
else:
|
||||
message = raw or message
|
||||
except Exception:
|
||||
message = raw or message
|
||||
with open(os.environ['GITHUB_OUTPUT'], 'a') as handle:
|
||||
handle.write(f"decision={decision}\n")
|
||||
handle.write("message<<EOF\n")
|
||||
handle.write(message + "\n")
|
||||
handle.write("EOF\n")
|
||||
PY
|
||||
|
||||
merge_or_comment:
|
||||
runs-on: ubuntu-latest
|
||||
needs: chack_agent_triage
|
||||
if: ${{ github.event.workflow_run.conclusion == 'success' && needs.chack_agent_triage.outputs.should_run == 'true' && needs.chack_agent_triage.outputs.decision != '' }}
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Merge PR when approved
|
||||
if: ${{ needs.chack_agent_triage.outputs.decision == 'merge' }}
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
PR_NUMBER: ${{ needs.chack_agent_triage.outputs.pr_number }}
|
||||
run: |
|
||||
gh api \
|
||||
-X PUT \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
/repos/${{ github.repository }}/pulls/${PR_NUMBER}/merge \
|
||||
-f merge_method=squash \
|
||||
-f commit_title="Auto-merge PR #${PR_NUMBER} (Chack Agent)"
|
||||
|
||||
- name: Comment with doubts
|
||||
if: ${{ needs.chack_agent_triage.outputs.decision == 'comment' }}
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
PR_NUMBER: ${{ needs.chack_agent_triage.outputs.pr_number }}
|
||||
CHACK_MESSAGE: ${{ needs.chack_agent_triage.outputs.message }}
|
||||
with:
|
||||
github-token: ${{ github.token }}
|
||||
script: |
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: Number(process.env.PR_NUMBER),
|
||||
body: process.env.CHACK_MESSAGE,
|
||||
});
|
||||
195
.github/workflows/ci-master-failure-chack-agent-pr.yml
vendored
Normal file
195
.github/workflows/ci-master-failure-chack-agent-pr.yml
vendored
Normal file
@@ -0,0 +1,195 @@
|
||||
name: CI-master Failure Chack-Agent PR
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["CI-master_test"]
|
||||
types: [completed]
|
||||
|
||||
jobs:
|
||||
chack_agent_fix_master_failure:
|
||||
if: >
|
||||
${{ github.event.workflow_run.conclusion == 'failure' &&
|
||||
github.event.workflow_run.head_branch == 'master' &&
|
||||
!startsWith(github.event.workflow_run.head_commit.message, 'Fix CI-master failures for run #') }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
issues: write
|
||||
actions: read
|
||||
env:
|
||||
TARGET_BRANCH: master
|
||||
FIX_BRANCH: chack-agent/ci-master-fix-${{ github.event.workflow_run.id }}
|
||||
CHACK_LOGS_HTTP_URL: ${{ secrets.CHACK_LOGS_HTTP_URL }}
|
||||
steps:
|
||||
- name: Checkout failing commit
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
ref: ${{ github.event.workflow_run.head_sha }}
|
||||
fetch-depth: 0
|
||||
persist-credentials: true
|
||||
token: ${{ secrets.CHACK_AGENT_FIXER_TOKEN || github.token }}
|
||||
|
||||
- name: Configure git author
|
||||
run: |
|
||||
git config user.name "chack-agent"
|
||||
git config user.email "chack-agent@users.noreply.github.com"
|
||||
|
||||
- name: Create fix branch
|
||||
run: git checkout -b "$FIX_BRANCH"
|
||||
|
||||
- name: Fetch failure summary and failed-step logs
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
RUN_ID: ${{ github.event.workflow_run.id }}
|
||||
run: |
|
||||
failed_logs_file="$(pwd)/chack_failed_steps_logs.txt"
|
||||
if gh run view "$RUN_ID" --repo "${{ github.repository }}" --log-failed > "$failed_logs_file"; then
|
||||
if [ ! -s "$failed_logs_file" ]; then
|
||||
echo "No failed step logs were returned by gh run view --log-failed." > "$failed_logs_file"
|
||||
fi
|
||||
else
|
||||
echo "Failed to download failed step logs with gh run view --log-failed." > "$failed_logs_file"
|
||||
fi
|
||||
echo "FAILED_LOGS_PATH=$failed_logs_file" >> "$GITHUB_ENV"
|
||||
|
||||
gh api -H "Accept: application/vnd.github+json" \
|
||||
/repos/${{ github.repository }}/actions/runs/$RUN_ID/jobs \
|
||||
--paginate > /tmp/jobs.json
|
||||
python3 - <<'PY'
|
||||
import json
|
||||
|
||||
data = json.load(open('/tmp/jobs.json'))
|
||||
lines = []
|
||||
for job in data.get('jobs', []):
|
||||
if job.get('conclusion') == 'failure':
|
||||
lines.append(f"Job: {job.get('name')} (id {job.get('id')})")
|
||||
lines.append(f"URL: {job.get('html_url')}")
|
||||
for step in job.get('steps', []):
|
||||
if step.get('conclusion') == 'failure':
|
||||
lines.append(f" Step: {step.get('name')}")
|
||||
lines.append("")
|
||||
|
||||
summary = "\n".join(lines).strip() or "No failing job details found."
|
||||
with open('chack_failure_summary.txt', 'w') as handle:
|
||||
handle.write(summary)
|
||||
PY
|
||||
|
||||
- name: Create Chack Agent prompt
|
||||
env:
|
||||
RUN_URL: ${{ github.event.workflow_run.html_url }}
|
||||
HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
|
||||
run: |
|
||||
{
|
||||
echo "You are fixing a failing CI-master_test run in ${{ github.repository }}."
|
||||
echo "The failing workflow run is: ${RUN_URL}"
|
||||
echo "The failing commit SHA is: ${HEAD_SHA}"
|
||||
echo "The target branch for the final PR is: ${TARGET_BRANCH}"
|
||||
echo ""
|
||||
echo "Failure summary:"
|
||||
cat chack_failure_summary.txt
|
||||
echo ""
|
||||
echo "Failed-step logs file absolute path (local runner): ${FAILED_LOGS_PATH}"
|
||||
echo "Read that file to inspect the exact failing logs."
|
||||
echo ""
|
||||
echo "Please identify the cause, apply an easy, simple and minimal fix, and update files accordingly."
|
||||
echo "Run any fast checks you can locally (no network)."
|
||||
echo "Leave the repo in a state ready to commit; changes will be committed and pushed automatically."
|
||||
} > chack_prompt.txt
|
||||
|
||||
- name: Set up Node.js for Codex
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: "20"
|
||||
|
||||
- name: Install Codex CLI
|
||||
run: |
|
||||
npm install -g @openai/codex
|
||||
codex --version
|
||||
|
||||
- name: Run Chack Agent
|
||||
id: run_chack
|
||||
uses: carlospolop/chack-agent@master
|
||||
with:
|
||||
provider: codex
|
||||
model_primary: CHEAP_BUT_QUALITY
|
||||
main_action: peass-ng
|
||||
sub_action: CI-master Failure Chack-Agent PR
|
||||
system_prompt: |
|
||||
Diagnose the failing gh actions workflow, propose the minimal and effective safe fix, and implement it.
|
||||
Run only fast, local checks (no network). Leave the repo ready to commit.
|
||||
prompt_file: chack_prompt.txt
|
||||
tools_config_json: "{\"exec_enabled\": true}"
|
||||
session_config_json: "{\"long_term_memory_enabled\": false}"
|
||||
agent_config_json: "{\"self_critique_enabled\": false, \"require_task_steps_manager_init_first\": true}"
|
||||
openai_api_key: ${{ secrets.OPENAI_API_KEY }}
|
||||
|
||||
- name: Commit and push fix branch if changed
|
||||
id: push_fix
|
||||
run: |
|
||||
if git diff --quiet; then
|
||||
echo "No changes to commit."
|
||||
echo "pushed=false" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
rm -f chack_failure_summary.txt chack_prompt.txt chack_failed_steps_logs.txt
|
||||
git add -A
|
||||
# Avoid workflow-file pushes with token scopes that cannot write workflows.
|
||||
git reset -- .github/workflows || true
|
||||
git checkout -- .github/workflows || true
|
||||
git clean -fdx -- .github/workflows || true
|
||||
git reset -- chack_failure_summary.txt chack_prompt.txt chack_failed_steps_logs.txt
|
||||
if git diff --cached --name-only | grep -q '^.github/workflows/'; then
|
||||
echo "Workflow-file changes are still staged; skipping push without workflows permission."
|
||||
echo "pushed=false" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
if git diff --cached --quiet; then
|
||||
echo "No committable changes left after filtering."
|
||||
echo "pushed=false" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
git commit -m "Fix CI-master failures for run #${{ github.event.workflow_run.id }}"
|
||||
if ! git push origin HEAD:"$FIX_BRANCH"; then
|
||||
echo "Push failed (likely token workflow permission limits); skipping PR creation."
|
||||
echo "pushed=false" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
echo "pushed=true" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Create PR to master
|
||||
if: ${{ steps.push_fix.outputs.pushed == 'true' }}
|
||||
id: create_pr
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.CHACK_AGENT_FIXER_TOKEN || github.token }}
|
||||
RUN_URL: ${{ github.event.workflow_run.html_url }}
|
||||
run: |
|
||||
pr_url=$(gh pr create \
|
||||
--title "Fix CI-master_test failure (run #${{ github.event.workflow_run.id }})" \
|
||||
--body "Automated Chack Agent fix for failing CI-master_test run: ${RUN_URL}" \
|
||||
--base "$TARGET_BRANCH" \
|
||||
--head "$FIX_BRANCH")
|
||||
echo "url=$pr_url" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Comment on created PR with Chack Agent result
|
||||
if: ${{ steps.push_fix.outputs.pushed == 'true' && steps.run_chack.outputs.final-message != '' }}
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
PR_URL: ${{ steps.create_pr.outputs.url }}
|
||||
CHACK_MESSAGE: ${{ steps.run_chack.outputs.final-message }}
|
||||
with:
|
||||
github-token: ${{ github.token }}
|
||||
script: |
|
||||
const prUrl = process.env.PR_URL;
|
||||
const match = prUrl.match(/\/pull\/(\d+)$/);
|
||||
if (!match) {
|
||||
core.info(`Could not parse PR number from URL: ${prUrl}`);
|
||||
return;
|
||||
}
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: Number(match[1]),
|
||||
body: process.env.CHACK_MESSAGE,
|
||||
});
|
||||
244
.github/workflows/pr-failure-chack-agent-dispatch.yml
vendored
Normal file
244
.github/workflows/pr-failure-chack-agent-dispatch.yml
vendored
Normal file
@@ -0,0 +1,244 @@
|
||||
name: PR Failure Chack-Agent Dispatch
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["PR-tests"]
|
||||
types: [completed]
|
||||
|
||||
jobs:
|
||||
resolve_pr_context:
|
||||
if: >
|
||||
${{ github.event.workflow_run.conclusion == 'failure' &&
|
||||
!startsWith(github.event.workflow_run.head_commit.message || '', 'Fix CI failures for PR #') }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: read
|
||||
issues: read
|
||||
outputs:
|
||||
number: ${{ steps.pr_context.outputs.number }}
|
||||
author: ${{ steps.pr_context.outputs.author }}
|
||||
head_repo: ${{ steps.pr_context.outputs.head_repo }}
|
||||
head_branch: ${{ steps.pr_context.outputs.head_branch }}
|
||||
should_run: ${{ steps.pr_context.outputs.should_run }}
|
||||
steps:
|
||||
- name: Resolve PR context
|
||||
id: pr_context
|
||||
env:
|
||||
PR_NUMBER: ${{ github.event.workflow_run.pull_requests[0].number }}
|
||||
HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
if [ -z "$PR_NUMBER" ] && [ -n "$HEAD_BRANCH" ]; then
|
||||
PR_NUMBER="$(gh pr list --state open --head "$HEAD_BRANCH" --json number --jq '.[0].number')"
|
||||
fi
|
||||
if [ -z "$PR_NUMBER" ]; then
|
||||
echo "No pull request found for workflow_run; skipping."
|
||||
{
|
||||
echo "number="
|
||||
echo "author="
|
||||
echo "head_repo="
|
||||
echo "head_branch=${HEAD_BRANCH}"
|
||||
echo "should_run=false"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
pr_author=$(gh api -H "Accept: application/vnd.github+json" \
|
||||
/repos/${{ github.repository }}/pulls/${PR_NUMBER} \
|
||||
--jq '.user.login')
|
||||
pr_head_repo=$(gh api -H "Accept: application/vnd.github+json" \
|
||||
/repos/${{ github.repository }}/pulls/${PR_NUMBER} \
|
||||
--jq '.head.repo.full_name')
|
||||
pr_head_branch=$(gh api -H "Accept: application/vnd.github+json" \
|
||||
/repos/${{ github.repository }}/pulls/${PR_NUMBER} \
|
||||
--jq '.head.ref')
|
||||
pr_labels=$(gh api -H "Accept: application/vnd.github+json" \
|
||||
/repos/${{ github.repository }}/issues/${PR_NUMBER} \
|
||||
--jq '.labels[].name')
|
||||
if echo "$pr_labels" | grep -q "^chack-agent-fix-attempted$"; then
|
||||
echo "chack-agent fix already attempted for PR #${PR_NUMBER}; skipping."
|
||||
should_run=false
|
||||
else
|
||||
should_run=true
|
||||
fi
|
||||
{
|
||||
echo "number=${PR_NUMBER}"
|
||||
echo "author=${pr_author}"
|
||||
echo "head_repo=${pr_head_repo}"
|
||||
echo "head_branch=${pr_head_branch}"
|
||||
echo "should_run=${should_run}"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
chack_agent_on_failure:
|
||||
needs: resolve_pr_context
|
||||
if: ${{ needs.resolve_pr_context.outputs.author == 'carlospolop' && needs.resolve_pr_context.outputs.should_run == 'true' }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
issues: write
|
||||
actions: write
|
||||
env:
|
||||
CHACK_LOGS_HTTP_URL: ${{ secrets.CHACK_LOGS_HTTP_URL }}
|
||||
steps:
|
||||
- name: Comment on PR with failure info
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
PR_NUMBER: ${{ needs.resolve_pr_context.outputs.number }}
|
||||
RUN_URL: ${{ github.event.workflow_run.html_url }}
|
||||
WORKFLOW_NAME: ${{ github.event.workflow_run.name }}
|
||||
with:
|
||||
github-token: ${{ github.token }}
|
||||
script: |
|
||||
const prNumber = Number(process.env.PR_NUMBER);
|
||||
const body = `PR #${prNumber} had a failing workflow "${process.env.WORKFLOW_NAME}".\n\nRun: ${process.env.RUN_URL}\n\nLaunching Chack Agent to attempt a fix.`;
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: prNumber,
|
||||
body,
|
||||
});
|
||||
|
||||
- name: Mark fix attempt
|
||||
env:
|
||||
PR_NUMBER: ${{ needs.resolve_pr_context.outputs.number }}
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
gh api -X POST -H "Accept: application/vnd.github+json" \
|
||||
/repos/${{ github.repository }}/issues/${PR_NUMBER}/labels \
|
||||
-f labels[]=chack-agent-fix-attempted
|
||||
|
||||
- name: Checkout PR head
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
repository: ${{ needs.resolve_pr_context.outputs.head_repo }}
|
||||
ref: ${{ github.event.workflow_run.head_sha }}
|
||||
fetch-depth: 0
|
||||
persist-credentials: true
|
||||
token: ${{ secrets.CHACK_AGENT_FIXER_TOKEN || github.token }}
|
||||
|
||||
- name: Configure git author
|
||||
run: |
|
||||
git config user.name "chack-agent"
|
||||
git config user.email "chack-agent@users.noreply.github.com"
|
||||
|
||||
- name: Fetch failure summary
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
RUN_ID: ${{ github.event.workflow_run.id }}
|
||||
run: |
|
||||
gh api -H "Accept: application/vnd.github+json" \
|
||||
/repos/${{ github.repository }}/actions/runs/$RUN_ID/jobs \
|
||||
--paginate > /tmp/jobs.json
|
||||
python3 - <<'PY'
|
||||
import json
|
||||
|
||||
data = json.load(open('/tmp/jobs.json'))
|
||||
lines = []
|
||||
for job in data.get('jobs', []):
|
||||
if job.get('conclusion') == 'failure':
|
||||
lines.append(f"Job: {job.get('name')} (id {job.get('id')})")
|
||||
lines.append(f"URL: {job.get('html_url')}")
|
||||
for step in job.get('steps', []):
|
||||
if step.get('conclusion') == 'failure':
|
||||
lines.append(f" Step: {step.get('name')}")
|
||||
lines.append("")
|
||||
|
||||
summary = "\n".join(lines).strip() or "No failing job details found."
|
||||
with open('chack_failure_summary.txt', 'w') as handle:
|
||||
handle.write(summary)
|
||||
PY
|
||||
|
||||
- name: Create Chack Agent prompt
|
||||
env:
|
||||
PR_NUMBER: ${{ needs.resolve_pr_context.outputs.number }}
|
||||
RUN_URL: ${{ github.event.workflow_run.html_url }}
|
||||
HEAD_BRANCH: ${{ needs.resolve_pr_context.outputs.head_branch }}
|
||||
run: |
|
||||
{
|
||||
echo "You are fixing CI failures for PR #${PR_NUMBER} in ${{ github.repository }}."
|
||||
echo "The failing workflow run is: ${RUN_URL}"
|
||||
echo "The PR branch is: ${HEAD_BRANCH}"
|
||||
echo ""
|
||||
echo "Failure summary:"
|
||||
cat chack_failure_summary.txt
|
||||
echo ""
|
||||
echo "Please identify the cause, apply a easy, simple and minimal fix, and update files accordingly."
|
||||
echo "Run any fast checks you can locally (no network)."
|
||||
echo "Leave the repo in a state ready to commit as when you finish, it'll be automatically committed and pushed."
|
||||
} > chack_prompt.txt
|
||||
|
||||
- name: Set up Node.js for Codex
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: "20"
|
||||
|
||||
- name: Install Codex CLI
|
||||
run: |
|
||||
npm install -g @openai/codex
|
||||
codex --version
|
||||
|
||||
- name: Run Chack Agent
|
||||
id: run_chack
|
||||
uses: carlospolop/chack-agent@master
|
||||
with:
|
||||
provider: codex
|
||||
model_primary: CHEAP_BUT_QUALITY
|
||||
main_action: peass-ng
|
||||
sub_action: PR Failure Chack-Agent Dispatch
|
||||
system_prompt: |
|
||||
You are Chack Agent, an elite CI-fix engineer.
|
||||
Diagnose the failing workflow, propose the minimal safe fix, and implement it.
|
||||
Run only fast, local checks (no network). Leave the repo ready to commit.
|
||||
prompt_file: chack_prompt.txt
|
||||
tools_config_json: "{\"exec_enabled\": true}"
|
||||
session_config_json: "{\"long_term_memory_enabled\": false}"
|
||||
agent_config_json: "{\"self_critique_enabled\": false, \"require_task_steps_manager_init_first\": true}"
|
||||
openai_api_key: ${{ secrets.OPENAI_API_KEY }}
|
||||
|
||||
- name: Commit and push if changed
|
||||
env:
|
||||
TARGET_BRANCH: ${{ needs.resolve_pr_context.outputs.head_branch }}
|
||||
PR_NUMBER: ${{ needs.resolve_pr_context.outputs.number }}
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
if git diff --quiet; then
|
||||
echo "No changes to commit."
|
||||
exit 0
|
||||
fi
|
||||
rm -f chack_failure_summary.txt chack_prompt.txt
|
||||
git add -A
|
||||
# Avoid workflow-file pushes with token scopes that cannot write workflows.
|
||||
git reset -- .github/workflows || true
|
||||
git checkout -- .github/workflows || true
|
||||
git clean -fdx -- .github/workflows || true
|
||||
git reset -- chack_failure_summary.txt chack_prompt.txt
|
||||
if git diff --cached --name-only | grep -q '^.github/workflows/'; then
|
||||
echo "Workflow-file changes are still staged; skipping push without workflows permission."
|
||||
exit 0
|
||||
fi
|
||||
if git diff --cached --quiet; then
|
||||
echo "No committable changes left after filtering."
|
||||
exit 0
|
||||
fi
|
||||
git commit -m "Fix CI failures for PR #${PR_NUMBER}"
|
||||
if ! git push origin HEAD:${TARGET_BRANCH}; then
|
||||
echo "Push failed (likely token workflow permission limits); leaving run successful without push."
|
||||
exit 0
|
||||
fi
|
||||
gh workflow run PR-tests.yml --ref "${TARGET_BRANCH}"
|
||||
|
||||
- name: Comment with Chack Agent result
|
||||
if: ${{ steps.run_chack.outputs.final-message != '' }}
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
PR_NUMBER: ${{ needs.resolve_pr_context.outputs.number }}
|
||||
CHACK_MESSAGE: ${{ steps.run_chack.outputs.final-message }}
|
||||
with:
|
||||
github-token: ${{ github.token }}
|
||||
script: |
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: Number(process.env.PR_NUMBER),
|
||||
body: process.env.CHACK_MESSAGE,
|
||||
});
|
||||
3
README.md
Executable file → Normal file
3
README.md
Executable file → Normal file
@@ -28,7 +28,7 @@ Check the **[parsers](./parsers/)** directory to **transform PEASS outputs to JS
|
||||
|
||||
If you are a **PEASS & Hacktricks enthusiast**, you can get your hands now on **our [custom swag](https://peass.creator-spring.com/) and show how much you like our projects!**
|
||||
|
||||
You can also, join the 💬 [Discord group](https://discord.gg/hRep4RUj7f) or the [telegram group](https://t.me/peass) to learn about latest news in cybersecurity and meet other cybersecurity enthusiasts, or follow me on Twitter 🐦 [@hacktricks_live](https://twitter.com/hacktricks_live).
|
||||
You can also, join the 💬 [Discord group](https://discord.gg/hRep4RUj7f) or the [telegram group](https://t.me/peass) to learn about the latest news in cybersecurity and meet other cybersecurity enthusiasts, or follow me on Twitter 🐦 [@hacktricks_live](https://twitter.com/hacktricks_live).
|
||||
|
||||
## Let's improve PEASS together
|
||||
|
||||
@@ -37,4 +37,3 @@ If you want to **add something** and have **any cool idea** related to this proj
|
||||
## Advisory
|
||||
|
||||
All the scripts/binaries of the PEAS suite 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 machines and/or with the owner's permission.
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -813,6 +813,12 @@ search:
|
||||
bad_regex: "auth|accessfile=|secret=|user"
|
||||
remove_regex: "^#|^@"
|
||||
type: f
|
||||
- name: "*"
|
||||
value:
|
||||
bad_regex: "nullok|nullok_secure|pam_permit\\.so|pam_rootok\\.so|pam_exec\\.so|pam_unix\\.so.*(nullok|remember=0)|sufficient\\s+pam_unix\\.so"
|
||||
only_bad_lines: True
|
||||
remove_regex: "^#|^@"
|
||||
type: f
|
||||
type: d
|
||||
search_in:
|
||||
- ${ROOT_FOLDER}etc
|
||||
@@ -895,6 +901,14 @@ search:
|
||||
type: f
|
||||
search_in:
|
||||
- common
|
||||
|
||||
- name: "credentials.tfrc.json"
|
||||
value:
|
||||
type: f
|
||||
bad_regex: ".*"
|
||||
search_in:
|
||||
- common
|
||||
|
||||
|
||||
- name: Racoon
|
||||
value:
|
||||
@@ -1227,12 +1241,20 @@ search:
|
||||
auto_check: False
|
||||
|
||||
files:
|
||||
- name: "agent*"
|
||||
- name: "agent.*"
|
||||
value:
|
||||
type: f
|
||||
remove_path: ".dll"
|
||||
search_in:
|
||||
- ${ROOT_FOLDER}tmp
|
||||
- ${ROOT_FOLDER}run
|
||||
|
||||
- name: "ssh-agent.sock"
|
||||
value:
|
||||
type: f
|
||||
search_in:
|
||||
- ${ROOT_FOLDER}tmp
|
||||
- ${ROOT_FOLDER}run
|
||||
|
||||
- name: SSH_CONFIG
|
||||
value:
|
||||
@@ -1265,7 +1287,7 @@ search:
|
||||
type: f
|
||||
bad_regex: ".*"
|
||||
search_in:
|
||||
- common
|
||||
- common
|
||||
|
||||
- name: Cloud Credentials
|
||||
value:
|
||||
@@ -1697,7 +1719,7 @@ search:
|
||||
auto_check: True
|
||||
exec:
|
||||
- '( redis-server --version || echo_not_found "redis-server") 2>/dev/null'
|
||||
- if [ "`redis-cli INFO 2>/dev/null`" ] && ! [ "`redis-cli INFO 2>/dev/null | grep -i NOAUTH`" ]; then echo "Redis isn't password protected" | sed -${E} "s,.*,${SED_RED},"; fi
|
||||
- redis_info="$(if [ "$TIMEOUT" ]; then $TIMEOUT 2 redis-cli INFO 2>/dev/null; else redis-cli INFO 2>/dev/null; fi)"; if [ "$redis_info" ] && ! echo "$redis_info" | grep -i NOAUTH; then echo "Redis isn't password protected" | sed -${E} "s,.*,${SED_RED},"; fi
|
||||
|
||||
files:
|
||||
- name: "redis.conf"
|
||||
@@ -2060,6 +2082,50 @@ search:
|
||||
search_in:
|
||||
- common
|
||||
|
||||
- name: "*.asc"
|
||||
value:
|
||||
type: f
|
||||
remove_path: "/usr/share/|/usr/lib/|/lib/|/man/"
|
||||
search_in:
|
||||
- common
|
||||
|
||||
- name: "secring.gpg"
|
||||
value:
|
||||
type: f
|
||||
search_in:
|
||||
- common
|
||||
|
||||
- name: "pubring.kbx"
|
||||
value:
|
||||
type: f
|
||||
search_in:
|
||||
- common
|
||||
|
||||
- name: "trustdb.gpg"
|
||||
value:
|
||||
type: f
|
||||
search_in:
|
||||
- common
|
||||
|
||||
- name: "gpg-agent.conf"
|
||||
value:
|
||||
type: f
|
||||
search_in:
|
||||
- common
|
||||
|
||||
- name: "secret.asc"
|
||||
value:
|
||||
type: f
|
||||
just_list_file: True
|
||||
search_in:
|
||||
- common
|
||||
|
||||
- name: "private-keys-v1.d/*.key"
|
||||
value:
|
||||
type: f
|
||||
search_in:
|
||||
- common
|
||||
|
||||
- name: "*.gnupg"
|
||||
value:
|
||||
type: f
|
||||
@@ -2831,6 +2897,85 @@ search:
|
||||
remove_path: "example"
|
||||
search_in:
|
||||
- common
|
||||
|
||||
- name: Proxy_Config
|
||||
value:
|
||||
config:
|
||||
auto_check: True
|
||||
|
||||
files:
|
||||
- name: "environment"
|
||||
value:
|
||||
bad_regex: "(http|https|ftp|all)_proxy|no_proxy"
|
||||
only_bad_lines: True
|
||||
remove_empty_lines: True
|
||||
remove_regex: '^#'
|
||||
type: f
|
||||
check_extra_path: "^/etc/environment$"
|
||||
search_in:
|
||||
- common
|
||||
|
||||
- name: "apt.conf"
|
||||
value:
|
||||
bad_regex: "Acquire::http::Proxy|Acquire::https::Proxy|proxy"
|
||||
only_bad_lines: True
|
||||
remove_empty_lines: True
|
||||
remove_regex: '^#'
|
||||
type: f
|
||||
search_in:
|
||||
- common
|
||||
|
||||
- name: "apt.conf.d"
|
||||
value:
|
||||
type: d
|
||||
files:
|
||||
- name: "*"
|
||||
value:
|
||||
bad_regex: "Acquire::http::Proxy|Acquire::https::Proxy|proxy"
|
||||
only_bad_lines: True
|
||||
remove_empty_lines: True
|
||||
remove_regex: '^#'
|
||||
type: f
|
||||
search_in:
|
||||
- common
|
||||
|
||||
- name: Sniffing_Artifacts
|
||||
value:
|
||||
config:
|
||||
auto_check: True
|
||||
|
||||
files:
|
||||
- name: "*.pcap"
|
||||
value:
|
||||
just_list_file: True
|
||||
type: f
|
||||
search_in:
|
||||
- common
|
||||
|
||||
- name: "*.pcapng"
|
||||
value:
|
||||
just_list_file: True
|
||||
type: f
|
||||
search_in:
|
||||
- common
|
||||
|
||||
- name: "keys.log"
|
||||
value:
|
||||
bad_regex: "CLIENT_RANDOM|SERVER_HANDSHAKE_TRAFFIC_SECRET|CLIENT_HANDSHAKE_TRAFFIC_SECRET|EXPORTER_SECRET|RESUMPTION_MASTER_SECRET"
|
||||
only_bad_lines: True
|
||||
remove_empty_lines: True
|
||||
type: f
|
||||
search_in:
|
||||
- common
|
||||
|
||||
- name: "sslkeylog.log"
|
||||
value:
|
||||
bad_regex: "CLIENT_RANDOM|SERVER_HANDSHAKE_TRAFFIC_SECRET|CLIENT_HANDSHAKE_TRAFFIC_SECRET|EXPORTER_SECRET|RESUMPTION_MASTER_SECRET"
|
||||
only_bad_lines: True
|
||||
remove_empty_lines: True
|
||||
type: f
|
||||
search_in:
|
||||
- common
|
||||
|
||||
- name: Msmtprc
|
||||
value:
|
||||
@@ -3339,7 +3484,7 @@ search:
|
||||
|
||||
- name: "credentials.xml"
|
||||
value:
|
||||
bad_regex: "secret.*|password.*"
|
||||
bad_regex: "secret.*|password.*|token.*|SecretKey.*|credentialId.*"
|
||||
remove_empty_lines: True
|
||||
type: f
|
||||
search_in:
|
||||
@@ -3347,7 +3492,7 @@ search:
|
||||
|
||||
- name: "config.xml"
|
||||
value:
|
||||
bad_regex: "secret.*|password.*"
|
||||
bad_regex: "secret.*|password.*|token.*|SecretKey.*|credentialId.*"
|
||||
only_bad_lines: True
|
||||
type: f
|
||||
search_in:
|
||||
@@ -3533,7 +3678,7 @@ search:
|
||||
|
||||
- name: "RDCMan.settings"
|
||||
value:
|
||||
just_list_file: True
|
||||
bad_regex: "credentialsProfiles|password|encryptedPassword"
|
||||
type: f
|
||||
search_in:
|
||||
- common
|
||||
@@ -3935,9 +4080,37 @@ search:
|
||||
search_in:
|
||||
- common
|
||||
|
||||
- name: "*.maintenance*"
|
||||
value:
|
||||
just_list_file: True
|
||||
type: f
|
||||
search_in:
|
||||
- common
|
||||
|
||||
- name: "*.key"
|
||||
value:
|
||||
just_list_file: True
|
||||
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
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
Check the **Local Linux Privilege Escalation checklist** from **[book.hacktricks.wiki](https://book.hacktricks.wiki/en/linux-hardening/linux-privilege-escalation-checklist.html)**.
|
||||
|
||||
> **Dec 2025 update:** linpeas now inspects Linux kernels for CVE-2025-38352 (POSIX CPU timers race) by combining CONFIG_POSIX_CPU_TIMERS_TASK_WORK state with kernel build information, so you immediately know if publicly available PoCs might succeed.
|
||||
|
||||
[](https://asciinema.org/a/309566)
|
||||
|
||||
## MacPEAS
|
||||
@@ -98,10 +100,17 @@ The goal of this script is to search for possible **Privilege Escalation Paths**
|
||||
|
||||
This script doesn't have any dependency.
|
||||
|
||||
### Recent updates
|
||||
|
||||
- **Dec 2025**: Added detection for sudo configurations that expose restic's `--password-command` helper, a common privilege escalation vector observed in real environments.
|
||||
|
||||
It uses **/bin/sh** syntax, so can run in anything supporting `sh` (and the binaries and parameters used).
|
||||
|
||||
By default, **linpeas won't write anything to disk and won't try to login as any other user using `su`**.
|
||||
|
||||
LinPEAS keeps expanding vendor-specific coverage; as of 29-Nov-2025 it warns when IGEL OS appliances still ship the SUID `setup`/`date` helpers that allow NetworkManager/systemd configuration hijacking (Metasploit module `linux/local/igel_network_priv_esc`).
|
||||
|
||||
|
||||
By default linpeas takes around **4 mins** to complete, but It could take from **5 to 10 minutes** to execute all the checks using **-a** parameter *(Recommended option for CTFs)*:
|
||||
- From less than 1 min to 2 mins to make almost all the checks
|
||||
- Almost 1 min to search for possible passwords inside all the accesible files of the system
|
||||
@@ -170,7 +179,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
|
||||
@@ -51,5 +51,5 @@ if __name__ == "__main__":
|
||||
print("You must specify one of the following options: --all, --all-no-fat, --small or --include")
|
||||
parser.print_help()
|
||||
exit(1)
|
||||
|
||||
|
||||
main(all_modules, all_no_fat_modules, no_network_scanning, small, include_modules, exclude_modules, output)
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
# Title: System Information - Linux Exploit Suggester
|
||||
# ID: SY_Linux_exploit_suggester
|
||||
# Author: Carlos Polop
|
||||
# Last Update: 07-03-2024
|
||||
# Description: Execute Linux Exploit Suggester to identify potential kernel exploits:
|
||||
# - Automated kernel vulnerability detection
|
||||
# - Common vulnerable scenarios:
|
||||
# * Known kernel vulnerabilities
|
||||
# * Unpatched kernel versions
|
||||
# * Missing security patches
|
||||
# - Exploitation methods:
|
||||
# * Kernel exploit execution: Use suggested exploits
|
||||
# * Common attack vectors:
|
||||
# - Kernel memory corruption
|
||||
# - Race conditions
|
||||
# - Use-after-free
|
||||
# - Integer overflow
|
||||
# * Exploit techniques:
|
||||
# - Kernel memory manipulation
|
||||
# - Privilege escalation
|
||||
# - Root access acquisition
|
||||
# - System compromise
|
||||
# License: GNU GPL
|
||||
# Version: 1.0
|
||||
# Functions Used: print_2title, print_info
|
||||
# Global Variables: $MACPEAS
|
||||
# Initial Functions:
|
||||
# Generated Global Variables: $les_b64
|
||||
# Fat linpeas: 0
|
||||
# Small linpeas: 1
|
||||
|
||||
|
||||
if [ "$(command -v bash 2>/dev/null || echo -n '')" ] && ! [ "$MACPEAS" ]; then
|
||||
print_2title "Executing Linux Exploit Suggester"
|
||||
print_info "https://github.com/mzet-/linux-exploit-suggester"
|
||||
les_b64="peass{https://raw.githubusercontent.com/mzet-/linux-exploit-suggester/master/linux-exploit-suggester.sh}"
|
||||
echo $les_b64 | base64 -d | bash | sed "s,$(printf '\033')\\[[0-9;]*[a-zA-Z],,g" | grep -i "\[CVE" -A 10 | grep -Ev "^\-\-$" | sed -${E} "s/\[(CVE-[0-9]+-[0-9]+,?)+\].*/${SED_RED}/g"
|
||||
echo ""
|
||||
fi
|
||||
@@ -1,41 +0,0 @@
|
||||
# Title: System Information - Linux Exploit Suggester 2
|
||||
# ID: SY_Linux_exploit_suggester_2
|
||||
# Author: Carlos Polop
|
||||
# Last Update: 07-03-2024
|
||||
# Description: Execute Linux Exploit Suggester 2 (Perl version) to identify potential kernel exploits:
|
||||
# - Alternative kernel vulnerability detection
|
||||
# - Perl-based exploit suggestions
|
||||
# - Common vulnerable scenarios:
|
||||
# * Known kernel vulnerabilities
|
||||
# * Unpatched kernel versions
|
||||
# * Missing security patches
|
||||
# * Alternative exploit paths
|
||||
# - Exploitation methods:
|
||||
# * Kernel exploit execution: Use suggested exploits
|
||||
# * Common attack vectors:
|
||||
# - Kernel memory corruption
|
||||
# - Race conditions
|
||||
# - Use-after-free
|
||||
# - Integer overflow
|
||||
# * Exploit techniques:
|
||||
# - Kernel memory manipulation
|
||||
# - Privilege escalation
|
||||
# - Root access acquisition
|
||||
# - System compromise
|
||||
# License: GNU GPL
|
||||
# Version: 1.0
|
||||
# Functions Used: print_2title, print_info
|
||||
# Global Variables:
|
||||
# Initial Functions:
|
||||
# Generated Global Variables: $les2_b64
|
||||
# Fat linpeas: 1
|
||||
# Small linpeas: 0
|
||||
|
||||
|
||||
if [ "$(command -v perl 2>/dev/null || echo -n '')" ] && ! [ "$MACPEAS" ]; then
|
||||
print_2title "Executing Linux Exploit Suggester 2"
|
||||
print_info "https://github.com/jondonas/linux-exploit-suggester-2"
|
||||
les2_b64="peass{https://raw.githubusercontent.com/jondonas/linux-exploit-suggester-2/master/linux-exploit-suggester-2.pl}"
|
||||
echo $les2_b64 | base64 -d | perl 2>/dev/null | sed "s,$(printf '\033')\\[[0-9;]*[a-zA-Z],,g" | grep -iE "CVE" -B 1 -A 10 | grep -Ev "^\-\-$" | sed -${E} "s,CVE-[0-9]+-[0-9]+,${SED_RED},g"
|
||||
echo ""
|
||||
fi
|
||||
@@ -30,10 +30,9 @@
|
||||
# Fat linpeas: 0
|
||||
# Small linpeas: 0
|
||||
|
||||
if apt list --installed 2>/dev/null | grep -q 'polkit.*0\.105-26' || \
|
||||
yum list installed 2>/dev/null | grep -q 'polkit.*\(0\.117-2\|0\.115-6\)' || \
|
||||
rpm -qa 2>/dev/null | grep -q 'polkit.*\(0\.117-2\|0\.115-6\)'; then
|
||||
if apt list --installed 2>/dev/null | grep -E 'polkit.*0\.105-26' | grep -qEv 'ubuntu1\.[1-9]' || \
|
||||
yum list installed 2>/dev/null | grep -qE 'polkit.*\(0\.117-2\|0\.115-6\|0\.11[3-9]\)' || \
|
||||
rpm -qa 2>/dev/null | grep -qE 'polkit.*\(0\.117-2\|0\.115-6\|0\.11[3-9]\)'; then
|
||||
echo "Vulnerable to CVE-2021-3560" | sed -${E} "s,.*,${SED_RED_YELLOW},"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
|
||||
@@ -30,11 +30,33 @@
|
||||
# Functions Used: echo_not_found, print_2title, print_list, warn_exec
|
||||
# Global Variables:
|
||||
# Initial Functions:
|
||||
# Generated Global Variables: $ASLR, $hypervisorflag, $detectedvirt
|
||||
# Generated Global Variables: $ASLR, $hypervisorflag, $detectedvirt, $unpriv_userns_clone, $perf_event_paranoid, $mmap_min_addr, $ptrace_scope, $dmesg_restrict, $kptr_restrict, $unpriv_bpf_disabled, $protected_symlinks, $protected_hardlinks, $label, $sysctl_path, $sysctl_var, $zero_color, $nonzero_color, $sysctl_value
|
||||
# Fat linpeas: 0
|
||||
# Small linpeas: 0
|
||||
|
||||
|
||||
print_sysctl_eq_zero() {
|
||||
local label="$1"
|
||||
local sysctl_path="$2"
|
||||
local sysctl_var="$3"
|
||||
local zero_color="$4"
|
||||
local nonzero_color="$5"
|
||||
local sysctl_value
|
||||
|
||||
print_list "$label" "$NC"
|
||||
sysctl_value=$(cat "$sysctl_path" 2>/dev/null)
|
||||
eval "$sysctl_var=\$sysctl_value"
|
||||
if [ -z "$sysctl_value" ]; then
|
||||
echo_not_found "$sysctl_path"
|
||||
else
|
||||
if [ "$sysctl_value" -eq 0 ]; then
|
||||
echo "0" | sed -${E} "s,0,${zero_color},"
|
||||
else
|
||||
echo "$sysctl_value" | sed -${E} "s,.*,${nonzero_color},g"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
#-- SY) AppArmor
|
||||
print_2title "Protections"
|
||||
print_list "AppArmor enabled? .............. "$NC
|
||||
@@ -80,10 +102,54 @@ print_list "Seccomp enabled? ............... "$NC
|
||||
print_list "User namespace? ................ "$NC
|
||||
if [ "$(cat /proc/self/uid_map 2>/dev/null)" ]; then echo "enabled" | sed "s,enabled,${SED_GREEN},"; else echo "disabled" | sed "s,disabled,${SED_RED},"; fi
|
||||
|
||||
#-- SY) Unprivileged user namespaces
|
||||
print_sysctl_eq_zero "unpriv_userns_clone? ........... " "/proc/sys/kernel/unprivileged_userns_clone" "unpriv_userns_clone" "$SED_GREEN" "$SED_RED"
|
||||
|
||||
#-- SY) Unprivileged eBPF
|
||||
print_sysctl_eq_zero "unpriv_bpf_disabled? ........... " "/proc/sys/kernel/unprivileged_bpf_disabled" "unpriv_bpf_disabled" "$SED_RED" "$SED_GREEN"
|
||||
|
||||
#-- SY) cgroup2
|
||||
print_list "Cgroup2 enabled? ............... "$NC
|
||||
([ "$(grep cgroup2 /proc/filesystems 2>/dev/null)" ] && echo "enabled" || echo "disabled") | sed "s,disabled,${SED_RED}," | sed "s,enabled,${SED_GREEN},"
|
||||
|
||||
#-- SY) Kernel hardening sysctls
|
||||
print_sysctl_eq_zero "kptr_restrict? ................. " "/proc/sys/kernel/kptr_restrict" "kptr_restrict" "$SED_RED" "$SED_GREEN"
|
||||
|
||||
print_sysctl_eq_zero "dmesg_restrict? ................ " "/proc/sys/kernel/dmesg_restrict" "dmesg_restrict" "$SED_RED" "$SED_GREEN"
|
||||
|
||||
print_sysctl_eq_zero "ptrace_scope? .................. " "/proc/sys/kernel/yama/ptrace_scope" "ptrace_scope" "$SED_RED" "$SED_GREEN"
|
||||
|
||||
print_sysctl_eq_zero "protected_symlinks? ............ " "/proc/sys/fs/protected_symlinks" "protected_symlinks" "$SED_RED" "$SED_GREEN"
|
||||
|
||||
print_sysctl_eq_zero "protected_hardlinks? ........... " "/proc/sys/fs/protected_hardlinks" "protected_hardlinks" "$SED_RED" "$SED_GREEN"
|
||||
|
||||
print_list "perf_event_paranoid? ........... "$NC
|
||||
perf_event_paranoid=$(cat /proc/sys/kernel/perf_event_paranoid 2>/dev/null)
|
||||
if [ -z "$perf_event_paranoid" ]; then
|
||||
echo_not_found "/proc/sys/kernel/perf_event_paranoid"
|
||||
else
|
||||
if [ "$perf_event_paranoid" -le 1 ]; then echo "$perf_event_paranoid" | sed -${E} "s,.*,${SED_RED},g"; else echo "$perf_event_paranoid" | sed -${E} "s,.*,${SED_GREEN},g"; fi
|
||||
fi
|
||||
|
||||
print_sysctl_eq_zero "mmap_min_addr? ................. " "/proc/sys/vm/mmap_min_addr" "mmap_min_addr" "$SED_RED" "$SED_GREEN"
|
||||
|
||||
print_list "lockdown mode? ................. "$NC
|
||||
if [ -f "/sys/kernel/security/lockdown" ]; then
|
||||
cat /sys/kernel/security/lockdown 2>/dev/null | sed -${E} "s,none,${SED_RED},g; s,integrity|confidentiality,${SED_GREEN},g"
|
||||
else
|
||||
echo_not_found "/sys/kernel/security/lockdown"
|
||||
fi
|
||||
|
||||
#-- SY) Kernel hardening config flags
|
||||
print_list "Kernel hardening flags? ........ "$NC
|
||||
if [ -f "/boot/config-$(uname -r)" ]; then
|
||||
grep -E 'CONFIG_RANDOMIZE_BASE|CONFIG_STACKPROTECTOR|CONFIG_SLAB_FREELIST_|CONFIG_KASAN' /boot/config-$(uname -r) 2>/dev/null
|
||||
elif [ -f "/proc/config.gz" ]; then
|
||||
zcat /proc/config.gz 2>/dev/null | grep -E 'CONFIG_RANDOMIZE_BASE|CONFIG_STACKPROTECTOR|CONFIG_SLAB_FREELIST_|CONFIG_KASAN'
|
||||
else
|
||||
echo_not_found "kernel config"
|
||||
fi
|
||||
|
||||
#-- SY) Gatekeeper
|
||||
if [ "$MACPEAS" ]; then
|
||||
print_list "Gatekeeper enabled? .......... "$NC
|
||||
@@ -136,4 +202,4 @@ else
|
||||
if [ "$hypervisorflag" ]; then printf $RED"Yes"$NC; else printf $GREEN"No"$NC; fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
@@ -58,5 +58,23 @@ else
|
||||
echo_not_found "/proc/sys/kernel/modules_disabled"
|
||||
fi
|
||||
|
||||
# Check for module signature enforcement
|
||||
print_3title "Module signature enforcement? "
|
||||
if [ -f "/proc/sys/kernel/module_sig_enforce" ]; then
|
||||
if [ "$(cat /proc/sys/kernel/module_sig_enforce)" = "1" ]; then
|
||||
echo "Enforced" | sed -${E} "s,.*,${SED_GREEN},g"
|
||||
else
|
||||
echo "Not enforced" | sed -${E} "s,.*,${SED_RED},g"
|
||||
fi
|
||||
elif [ -f "/sys/module/module/parameters/sig_enforce" ]; then
|
||||
if [ "$(cat /sys/module/module/parameters/sig_enforce)" = "Y" ]; then
|
||||
echo "Enforced" | sed -${E} "s,.*,${SED_GREEN},g"
|
||||
else
|
||||
echo "Not enforced" | sed -${E} "s,.*,${SED_RED},g"
|
||||
fi
|
||||
else
|
||||
echo_not_found "module_sig_enforce"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
echo ""
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
# Title: System Information - CVE_2025_38236
|
||||
# ID: SY_CVE_2025_38236
|
||||
# Author: HT Bot
|
||||
# Last Update: 17-12-2025
|
||||
# Description: Detect Linux kernels exposed to CVE-2025-38236 (AF_UNIX MSG_OOB UAF) that allow local privilege escalation:
|
||||
# - Vulnerable scope:
|
||||
# * Linux kernels 6.9+ before commit 32ca245464e1479bfea8592b9db227fdc1641705
|
||||
# * AF_UNIX stream sockets with MSG_OOB enabled (CONFIG_AF_UNIX_OOB or implicit support)
|
||||
# - Exploitation summary:
|
||||
# * send/recv MSG_OOB pattern leaves zero-length SKBs in the receive queue
|
||||
# * manage_oob() skips cleanup, freeing the OOB SKB while u->oob_skb still points to it
|
||||
# * Subsequent recv(MSG_OOB) dereferences the dangling pointer → kernel UAF → LPE
|
||||
# - Mitigations:
|
||||
# * Update to a kernel that includes commit 32ca245464e1479bfea8592b9db227fdc1641705 (or newer)
|
||||
# * Disable CONFIG_AF_UNIX_OOB or block MSG_OOB in sandboxed processes
|
||||
# * Backport vendor fixes or follow Chrome's MSG_OOB filtering approach
|
||||
# License: GNU GPL
|
||||
# Version: 1.0
|
||||
# Functions Used: print_2title, print_info
|
||||
# Global Variables: $MACPEAS, $SED_RED_YELLOW, $SED_GREEN, $E
|
||||
# Initial Functions:
|
||||
# Generated Global Variables: $cve38236_kernel_release, $cve38236_kernel_version, $cve38236_oob_line, $cve38236_unix_line, $cve38236_oob_status, $CVE38236_CONFIG_SOURCE, $cve38236_conf_file, $cve38236_config_key, $cve38236_release, $cve38236_cfg, $cve38236_config_line
|
||||
# Fat linpeas: 0
|
||||
# Small linpeas: 1
|
||||
|
||||
_cve38236_version_to_number() {
|
||||
if [ -z "$1" ]; then
|
||||
printf '0\n'
|
||||
return
|
||||
fi
|
||||
echo "$1" | awk -F. '{
|
||||
major=$1+0
|
||||
if (NF>=2) minor=$2+0; else minor=0
|
||||
if (NF>=3) patch=$3+0; else patch=0
|
||||
printf "%d\n", (major*1000000)+(minor*1000)+patch
|
||||
}'
|
||||
}
|
||||
|
||||
_cve38236_version_ge() {
|
||||
local v1 v2
|
||||
v1=$(_cve38236_version_to_number "$1")
|
||||
v2=$(_cve38236_version_to_number "$2")
|
||||
[ "$v1" -ge "$v2" ]
|
||||
}
|
||||
|
||||
_cve38236_cat_config_file() {
|
||||
local cve38236_conf_file="$1"
|
||||
if [ -z "$cve38236_conf_file" ] || ! [ -r "$cve38236_conf_file" ]; then
|
||||
return 1
|
||||
fi
|
||||
if printf '%s' "$cve38236_conf_file" | grep -q '\\.gz$'; then
|
||||
if command -v zcat >/dev/null 2>&1; then
|
||||
zcat "$cve38236_conf_file" 2>/dev/null
|
||||
elif command -v gzip >/dev/null 2>&1; then
|
||||
gzip -dc "$cve38236_conf_file" 2>/dev/null
|
||||
else
|
||||
cat "$cve38236_conf_file" 2>/dev/null
|
||||
fi
|
||||
else
|
||||
cat "$cve38236_conf_file" 2>/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
_cve38236_read_config_line() {
|
||||
local cve38236_config_key="$1"
|
||||
local cve38236_release cve38236_config_line cve38236_cfg
|
||||
cve38236_release="$(uname -r 2>/dev/null)"
|
||||
for cve38236_cfg in /proc/config.gz \
|
||||
"/boot/config-${cve38236_release}" \
|
||||
"/usr/lib/modules/${cve38236_release}/build/.config" \
|
||||
"/lib/modules/${cve38236_release}/build/.config"; do
|
||||
if [ -r "$cve38236_cfg" ]; then
|
||||
cve38236_config_line=$(_cve38236_cat_config_file "$cve38236_cfg" | grep -E "^(${cve38236_config_key}=|# ${cve38236_config_key} is not set)" | head -n1)
|
||||
if [ -n "$cve38236_config_line" ]; then
|
||||
CVE38236_CONFIG_SOURCE="$cve38236_cfg"
|
||||
printf '%s\n' "$cve38236_config_line"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
|
||||
if [ ! "$MACPEAS" ]; then
|
||||
cve38236_kernel_release="$(uname -r 2>/dev/null)"
|
||||
cve38236_kernel_version="$(printf '%s' "$cve38236_kernel_release" | sed 's/[^0-9.].*//')"
|
||||
|
||||
if [ -n "$cve38236_kernel_version" ] && _cve38236_version_ge "$cve38236_kernel_version" "6.9.0"; then
|
||||
print_2title "CVE-2025-38236 - AF_UNIX MSG_OOB UAF"
|
||||
|
||||
cve38236_oob_line=$(_cve38236_read_config_line "CONFIG_AF_UNIX_OOB")
|
||||
cve38236_oob_status="unknown"
|
||||
|
||||
if printf '%s' "$cve38236_oob_line" | grep -q '=y\|=m'; then
|
||||
cve38236_oob_status="enabled"
|
||||
elif printf '%s' "$cve38236_oob_line" | grep -q 'not set'; then
|
||||
cve38236_oob_status="disabled"
|
||||
fi
|
||||
|
||||
if [ "$cve38236_oob_status" = "unknown" ]; then
|
||||
cve38236_unix_line=$(_cve38236_read_config_line "CONFIG_UNIX")
|
||||
if printf '%s' "$cve38236_unix_line" | grep -q 'not set'; then
|
||||
cve38236_oob_status="disabled"
|
||||
elif printf '%s' "$cve38236_unix_line" | grep -q '=y\|=m'; then
|
||||
cve38236_oob_status="enabled"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$cve38236_oob_status" = "disabled" ]; then
|
||||
printf 'Kernel %s >= 6.9 but MSG_OOB support is disabled (%s).\n' "$cve38236_kernel_release" "${cve38236_oob_line:-CONFIG_AF_UNIX disabled}" | sed -${E} "s,.*,${SED_GREEN},"
|
||||
print_info "CVE-2025-38236 requires AF_UNIX MSG_OOB; disabling CONFIG_AF_UNIX_OOB/CONFIG_UNIX mitigates it."
|
||||
else
|
||||
printf 'Kernel %s (parsed %s) may be vulnerable to CVE-2025-38236 - AF_UNIX MSG_OOB UAF.\n' "$cve38236_kernel_release" "$cve38236_kernel_version" | sed -${E} "s,.*,${SED_RED_YELLOW},"
|
||||
[ -n "$cve38236_oob_line" ] && print_info "Config hint: $cve38236_oob_line"
|
||||
if [ "$cve38236_oob_status" = "unknown" ]; then
|
||||
print_info "Could not read CONFIG_AF_UNIX_OOB directly; AF_UNIX appears enabled, so assume MSG_OOB reachable."
|
||||
fi
|
||||
print_info "Exploit chain: crafted MSG_OOB send/recv frees the OOB SKB while u->oob_skb still points to it, enabling kernel UAF → arbitrary read/write primitives (Project Zero 2025/08)."
|
||||
print_info "Mitigations: update to a kernel containing commit 32ca245464e1479bfea8592b9db227fdc1641705, disable CONFIG_AF_UNIX_OOB, or filter MSG_OOB in sandbox policies."
|
||||
print_info "Heuristic detection: based solely on uname -r and kernel config; vendor kernels with backported fixes should be verified manually."
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
|
||||
fi
|
||||
@@ -0,0 +1,183 @@
|
||||
# Title: System Information - CVE_2025_38352
|
||||
# ID: SY_CVE_2025_38352
|
||||
# Author: HT Bot
|
||||
# Last Update: 22-12-2025
|
||||
# Description: Detect Linux kernels that may still be vulnerable to CVE-2025-38352 (race-condition UAF in POSIX CPU timers)
|
||||
# - Highlights kernels built without CONFIG_POSIX_CPU_TIMERS_TASK_WORK
|
||||
# - Flags 6.12.x builds older than the fix commit f90fff1e152dedf52b932240ebbd670d83330eca (first shipped in 6.12.34)
|
||||
# - Provides quick risk scoring so operators can decide whether to attempt the publicly available PoC
|
||||
# - Core requirements for exploitation:
|
||||
# * CONFIG_POSIX_CPU_TIMERS_TASK_WORK disabled (common on 32-bit Android / custom kernels)
|
||||
# * Lack of the upstream exit_state guard in run_posix_cpu_timers()
|
||||
# License: GNU GPL
|
||||
# Version: 1.0
|
||||
# Functions Used: echo_not_found, print_2title, print_list
|
||||
# Global Variables: $E, $SED_GREEN, $SED_RED, $SED_RED_YELLOW, $SED_YELLOW
|
||||
# Initial Functions:
|
||||
# Generated Global Variables: $cve38352_kernel_release, $cve38352_kernel_version_cmp, $cve38352_symbol, $cve38352_task_work_state, $cve38352_config_status, $cve38352_config_source, $cve38352_config_candidates, $cve38352_cfg, $cve38352_line, $cve38352_patch_state, $cve38352_patch_label, $cve38352_fix_tag, $cve38352_last_vuln_tag, $cve38352_risk_msg, $cve38352_risk_color, $cve38352_task_line, $cve38352_patch_line, $cve38352_risk_line
|
||||
# Fat linpeas: 0
|
||||
# Small linpeas: 1
|
||||
|
||||
cve38352_version_lt(){
|
||||
awk -v v1="$1" -v v2="$2" '
|
||||
function cleannum(val) {
|
||||
gsub(/[^0-9].*/, "", val)
|
||||
if (val == "") {
|
||||
val = 0
|
||||
}
|
||||
return val + 0
|
||||
}
|
||||
BEGIN {
|
||||
n = split(v1, a, ".")
|
||||
m = split(v2, b, ".")
|
||||
max = (n > m ? n : m)
|
||||
for (i = 1; i <= max; i++) {
|
||||
av = (i <= n ? cleannum(a[i]) : 0)
|
||||
bv = (i <= m ? cleannum(b[i]) : 0)
|
||||
if (av < bv) {
|
||||
exit 0
|
||||
}
|
||||
if (av > bv) {
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
exit 1
|
||||
}'
|
||||
}
|
||||
|
||||
cve38352_sanitize_version(){
|
||||
printf "%s" "$1" | tr '-' '.' | sed 's/[^0-9.].*$//' | sed 's/\.\./\./g' | sed 's/^\.//' | sed 's/\.$//'
|
||||
}
|
||||
|
||||
print_2title "CVE-2025-38352 - POSIX CPU timers race"
|
||||
|
||||
cve38352_kernel_release=$(uname -r 2>/dev/null)
|
||||
if [ -z "$cve38352_kernel_release" ]; then
|
||||
echo_not_found "uname -r"
|
||||
echo ""
|
||||
else
|
||||
|
||||
cve38352_kernel_version_cmp=$(cve38352_sanitize_version "$cve38352_kernel_release")
|
||||
if [ -z "$cve38352_kernel_version_cmp" ]; then
|
||||
cve38352_kernel_version_cmp="unknown"
|
||||
fi
|
||||
|
||||
cve38352_symbol="CONFIG_POSIX_CPU_TIMERS_TASK_WORK"
|
||||
cve38352_task_work_state="unknown"
|
||||
cve38352_config_status="Unknown ($cve38352_symbol not found)"
|
||||
cve38352_config_source=""
|
||||
|
||||
cve38352_config_candidates="/boot/config-$cve38352_kernel_release /proc/config.gz /lib/modules/$cve38352_kernel_release/build/.config /usr/lib/modules/$cve38352_kernel_release/build/.config /usr/src/linux/.config"
|
||||
for cve38352_cfg in $cve38352_config_candidates; do
|
||||
[ -r "$cve38352_cfg" ] || continue
|
||||
if printf "%s" "$cve38352_cfg" | grep -q '\\.gz$'; then
|
||||
cve38352_line=$(gzip -dc "$cve38352_cfg" 2>/dev/null | grep -E "^(# )?$cve38352_symbol" | head -n1)
|
||||
else
|
||||
cve38352_line=$(grep -E "^(# )?$cve38352_symbol" "$cve38352_cfg" 2>/dev/null | head -n1)
|
||||
fi
|
||||
[ -z "$cve38352_line" ] && continue
|
||||
cve38352_config_source="$cve38352_cfg"
|
||||
case "$cve38352_line" in
|
||||
"$cve38352_symbol=y")
|
||||
cve38352_task_work_state="enabled"
|
||||
cve38352_config_status="Enabled (y)"
|
||||
;;
|
||||
"$cve38352_symbol=m")
|
||||
cve38352_task_work_state="enabled"
|
||||
cve38352_config_status="Built as module (m)"
|
||||
;;
|
||||
"$cve38352_symbol=n")
|
||||
cve38352_task_work_state="disabled"
|
||||
cve38352_config_status="Disabled (n)"
|
||||
;;
|
||||
"# $cve38352_symbol is not set")
|
||||
cve38352_task_work_state="disabled"
|
||||
cve38352_config_status="Not set"
|
||||
;;
|
||||
*)
|
||||
cve38352_config_status="Found: $cve38352_line"
|
||||
;;
|
||||
esac
|
||||
break
|
||||
done
|
||||
|
||||
cve38352_patch_state="unknown_branch"
|
||||
cve38352_patch_label="Unable to determine kernel train"
|
||||
cve38352_fix_tag="6.12.34"
|
||||
cve38352_last_vuln_tag="6.12.33"
|
||||
case "$cve38352_kernel_version_cmp" in
|
||||
6.12|6.12.*)
|
||||
if cve38352_version_lt "$cve38352_kernel_version_cmp" "$cve38352_fix_tag"; then
|
||||
cve38352_patch_state="pre_fix"
|
||||
cve38352_patch_label="6.12.x build < $cve38352_fix_tag (last known vulnerable LTS: $cve38352_last_vuln_tag)"
|
||||
else
|
||||
cve38352_patch_state="post_fix"
|
||||
cve38352_patch_label="6.12.x build >= $cve38352_fix_tag (should include fix f90fff1e152d)"
|
||||
fi
|
||||
;;
|
||||
unknown)
|
||||
cve38352_patch_label="Kernel version string could not be parsed"
|
||||
;;
|
||||
*)
|
||||
cve38352_patch_label="Kernel train $cve38352_kernel_version_cmp (verify commit f90fff1e152dedf52b932240ebbd670d83330eca manually)"
|
||||
;;
|
||||
esac
|
||||
|
||||
cve38352_risk_msg="Unknown - missing configuration data"
|
||||
cve38352_risk_color=""
|
||||
if [ "$cve38352_task_work_state" = "enabled" ]; then
|
||||
cve38352_risk_msg="Low - CONFIG_POSIX_CPU_TIMERS_TASK_WORK is enabled"
|
||||
cve38352_risk_color="green"
|
||||
elif [ "$cve38352_task_work_state" = "disabled" ]; then
|
||||
if [ "$cve38352_patch_state" = "pre_fix" ]; then
|
||||
cve38352_risk_msg="High - task_work disabled & kernel predates fix f90fff1e152d"
|
||||
cve38352_risk_color="red"
|
||||
else
|
||||
cve38352_risk_msg="Review - task_work disabled, ensure fix f90fff1e152d is backported"
|
||||
cve38352_risk_color="yellow"
|
||||
fi
|
||||
fi
|
||||
|
||||
print_list "Kernel release ............... $cve38352_kernel_release\n"
|
||||
print_list "Comparable version ........... $cve38352_kernel_version_cmp\n"
|
||||
|
||||
cve38352_task_line="Task_work config ............. $cve38352_config_status"
|
||||
if [ -n "$cve38352_config_source" ]; then
|
||||
cve38352_task_line="$cve38352_task_line (from $cve38352_config_source)"
|
||||
fi
|
||||
cve38352_task_line="$cve38352_task_line\n"
|
||||
if [ "$cve38352_task_work_state" = "disabled" ]; then
|
||||
print_list "$cve38352_task_line" | sed -${E} "s,.*,${SED_RED},"
|
||||
elif [ "$cve38352_task_work_state" = "enabled" ]; then
|
||||
print_list "$cve38352_task_line" | sed -${E} "s,.*,${SED_GREEN},"
|
||||
else
|
||||
print_list "$cve38352_task_line"
|
||||
fi
|
||||
|
||||
cve38352_patch_line="Patch status ................. $cve38352_patch_label\n"
|
||||
if [ "$cve38352_patch_state" = "pre_fix" ]; then
|
||||
print_list "$cve38352_patch_line" | sed -${E} "s,.*,${SED_RED_YELLOW},"
|
||||
elif [ "$cve38352_patch_state" = "post_fix" ]; then
|
||||
print_list "$cve38352_patch_line" | sed -${E} "s,.*,${SED_GREEN},"
|
||||
else
|
||||
print_list "$cve38352_patch_line" | sed -${E} "s,.*,${SED_YELLOW},"
|
||||
fi
|
||||
|
||||
cve38352_risk_line="CVE-2025-38352 risk .......... $cve38352_risk_msg\n"
|
||||
case "$cve38352_risk_color" in
|
||||
red)
|
||||
print_list "$cve38352_risk_line" | sed -${E} "s,.*,${SED_RED_YELLOW},"
|
||||
;;
|
||||
green)
|
||||
print_list "$cve38352_risk_line" | sed -${E} "s,.*,${SED_GREEN},"
|
||||
;;
|
||||
yellow)
|
||||
print_list "$cve38352_risk_line" | sed -${E} "s,.*,${SED_YELLOW},"
|
||||
;;
|
||||
*)
|
||||
print_list "$cve38352_risk_line"
|
||||
;;
|
||||
esac
|
||||
|
||||
echo ""
|
||||
fi
|
||||
@@ -4,6 +4,7 @@
|
||||
# Last Update: 07-03-2024
|
||||
# Description: Check for additional disk information and system resources relevant to privilege escalation:
|
||||
# - Disk utilization
|
||||
# - Inode usage
|
||||
# - System resources
|
||||
# - Storage statistics
|
||||
# - Common vulnerable scenarios:
|
||||
@@ -44,4 +45,8 @@ if [ "$EXTRA_CHECKS" ] || [ "$DEBUG" ]; then
|
||||
(df -h || lsblk) 2>/dev/null || echo_not_found "df and lsblk"
|
||||
warn_exec free 2>/dev/null
|
||||
echo ""
|
||||
fi
|
||||
|
||||
print_2title "Inode usage"
|
||||
warn_exec df -i 2>/dev/null
|
||||
echo ""
|
||||
fi
|
||||
|
||||
@@ -36,6 +36,14 @@ print_2title "Container details"
|
||||
|
||||
print_list "Is this a container? ...........$NC $containerType"
|
||||
|
||||
if [ -e "/proc/vz" ] && ! [ -e "/proc/bc" ]; then
|
||||
print_list "Container Runtime ..............$NC OpenVZ"
|
||||
fi
|
||||
|
||||
if [ -f "/run/systemd/container" ]; then
|
||||
print_list "Systemd Container ..............$NC $(cat /run/systemd/container)"
|
||||
fi
|
||||
|
||||
# Get container runtime info
|
||||
if [ "$(command -v docker || echo -n '')" ]; then
|
||||
print_list "Docker version ...............$NC "
|
||||
|
||||
@@ -37,10 +37,10 @@
|
||||
# - Container escape tool execution
|
||||
# License: GNU GPL
|
||||
# Version: 1.0
|
||||
# Functions Used: checkContainerExploits, checkProcSysBreakouts, containerCheck, print_2title, print_3title, print_info, print_list, warn_exec
|
||||
# Functions Used: checkContainerExploits, checkProcSysBreakouts, containerCheck, enumerateDockerSockets, print_2title, print_3title, print_info, print_list, warn_exec
|
||||
# Global Variables: $binfmt_misc_breakout, $containercapsB, $containerType, $core_pattern_breakout, $dev_mounted, $efi_efivars_writable, $efi_vars_writable, $GREP_IGNORE_MOUNTS, $inContainer, $kallsyms_readable, $kcore_readable, $kmem_readable, $kmem_writable, $kmsg_readable, $mem_readable, $mem_writable, $modprobe_present, $mountinfo_readable, $panic_on_oom_dos, $panic_sys_fs_dos, $proc_configgz_readable, $proc_mounted, $run_unshare, $release_agent_breakout1, $release_agent_breakout2, $release_agent_breakout3, $sched_debug_readable, $security_present, $security_writable, $sysreq_trigger_dos, $uevent_helper_breakout, $vmcoreinfo_readable, $VULN_CVE_2019_5021, $self_mem_readable
|
||||
# Initial Functions: containerCheck
|
||||
# Generated Global Variables: $defautl_docker_caps, $containerd_version, $runc_version, $containerd_version
|
||||
# Generated Global Variables: $defautl_docker_caps, $containerd_version, $runc_version, $seccomp_mode_num, $seccomp_mode_desc
|
||||
# Fat linpeas: 0
|
||||
# Small linpeas: 0
|
||||
|
||||
@@ -57,14 +57,34 @@ if [ "$inContainer" ]; then
|
||||
|
||||
# Security mechanisms
|
||||
print_3title "Security Mechanisms"
|
||||
print_list "Seccomp enabled? ............... "$NC
|
||||
([ "$(grep Seccomp /proc/self/status | grep -v 0)" ] && echo "enabled" || echo "disabled") | sed "s,disabled,${SED_RED}," | sed "s,enabled,${SED_GREEN},"
|
||||
seccomp_mode_num="$(awk '/^Seccomp:/{print $2}' /proc/self/status 2>/dev/null)"
|
||||
seccomp_mode_desc="unknown"
|
||||
case "$seccomp_mode_num" in
|
||||
0) seccomp_mode_desc="disabled" ;;
|
||||
1) seccomp_mode_desc="strict" ;;
|
||||
2) seccomp_mode_desc="filtering" ;;
|
||||
esac
|
||||
|
||||
print_list "Seccomp mode ................... "$NC
|
||||
(printf "%s (%s)\n" "$seccomp_mode_desc" "${seccomp_mode_num:-?}") | sed "s,disabled,${SED_RED}," | sed "s,strict,${SED_RED_YELLOW}," | sed "s,filtering,${SED_GREEN},"
|
||||
|
||||
if grep -q "^Seccomp_filters:" /proc/self/status 2>/dev/null; then
|
||||
print_list "Seccomp filters ............... "$NC
|
||||
awk '/^Seccomp_filters:/{print $2}' /proc/self/status 2>/dev/null | sed -${E} "s,^[0-9]+$,${SED_GREEN}&,"
|
||||
fi
|
||||
|
||||
print_list "AppArmor profile? .............. "$NC
|
||||
(cat /proc/self/attr/current 2>/dev/null || echo "disabled") | sed "s,disabled,${SED_RED}," | sed "s,kernel,${SED_GREEN},"
|
||||
|
||||
print_list "User proc namespace? ........... "$NC
|
||||
if [ "$(cat /proc/self/uid_map 2>/dev/null)" ]; then (printf "enabled"; cat /proc/self/uid_map) | sed "s,enabled,${SED_GREEN},"; else echo "disabled" | sed "s,disabled,${SED_RED},"; fi
|
||||
if [ "$(cat /proc/self/uid_map 2>/dev/null)" ]; then
|
||||
(printf "enabled"; cat /proc/self/uid_map) | sed "s,enabled,${SED_GREEN},";
|
||||
echo ""
|
||||
echo " Mappings (Container -> Host -> Range):"
|
||||
cat /proc/self/uid_map | awk '{print " " $1 " -> " $2 " -> " $3}'
|
||||
else
|
||||
echo "disabled" | sed "s,disabled,${SED_RED},";
|
||||
fi
|
||||
|
||||
# Known vulnerabilities
|
||||
print_3title "Known Vulnerabilities"
|
||||
@@ -155,6 +175,9 @@ if [ "$inContainer" ]; then
|
||||
cat /proc/self/status | tr '\t' ' ' | grep Cap | sed -${E} "s, .*,${SED_RED},g" | sed -${E} "s/00000000a80425fb/$defautl_docker_caps/g" | sed -${E} "s,0000000000000000|00000000a80425fb,${SED_GREEN},g"
|
||||
echo $ITALIC"Run capsh --decode=<hex> to decode the capabilities"$NC
|
||||
fi
|
||||
|
||||
print_list "Ambient capabilities ........... "$NC
|
||||
(grep "CapAmb:" /proc/self/status 2>/dev/null | grep -v "0000000000000000" | sed "s,CapAmb:.,," || echo "No") | sed -${E} "s,No,${SED_GREEN}," | sed -${E} "s,[0-9a-fA-F]\+,${SED_RED}&,"
|
||||
|
||||
# Additional capability checks
|
||||
print_list "Dangerous syscalls allowed ... "$NC
|
||||
@@ -200,6 +223,10 @@ if [ "$inContainer" ]; then
|
||||
echo "No"
|
||||
fi
|
||||
|
||||
|
||||
print_list "Looking and enumerating Docker Sockets (if any):\n"$NC
|
||||
enumerateDockerSockets
|
||||
|
||||
# Additional breakout vectors
|
||||
print_3title "Additional Breakout Vectors"
|
||||
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
# Title: Container - Am I Containered
|
||||
# ID: CT_Am_I_contained
|
||||
# Author: Carlos Polop
|
||||
# Last Update: 22-08-2023
|
||||
# Description: Am I Containered tool
|
||||
# License: GNU GPL
|
||||
# Version: 1.0
|
||||
# Functions Used: print_2title, execBin
|
||||
# Global Variables:
|
||||
# Initial Functions:
|
||||
# Generated Global Variables: $FAT_LINPEAS_AMICONTAINED
|
||||
# Fat linpeas: 1
|
||||
# Small linpeas: 0
|
||||
|
||||
|
||||
if [ "$$FAT_LINPEAS_AMICONTAINED" ]; then
|
||||
print_2title "Am I Containered?"
|
||||
FAT_LINPEAS_AMICONTAINED="peass{https://github.com/genuinetools/amicontained/releases/latest/download/amicontained-linux-amd64}"
|
||||
execBin "AmIContainered" "https://github.com/genuinetools/amicontained" "$FAT_LINPEAS_AMICONTAINED"
|
||||
fi
|
||||
@@ -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
|
||||
@@ -1,14 +1,14 @@
|
||||
# Title: Cloud - AWS ECS
|
||||
# ID: CL_AWS_ECS
|
||||
# Author: Carlos Polop
|
||||
# Last Update: 22-08-2023
|
||||
# Last Update: 17-01-2026
|
||||
# Description: AWS ECS Enumeration
|
||||
# License: GNU GPL
|
||||
# Version: 1.0
|
||||
# Functions Used: check_aws_ecs, exec_with_jq, print_2title, print_3title
|
||||
# Global Variables: $aws_ecs_metadata_uri, $aws_ecs_service_account_uri, $is_aws_ecs
|
||||
# Initial Functions: check_aws_ecs
|
||||
# Generated Global Variables: $aws_ecs_req
|
||||
# Generated Global Variables: $aws_ecs_req, $aws_exec_env, $ecs_task_metadata, $launch_type, $network_modes, $imds_tool, $imds_token, $imds_roles, $imds_http_code, $ecs_block_line, $ecs_host_line, $iptables_cmd, $docker_rules, $first_role
|
||||
# Fat linpeas: 0
|
||||
# Small linpeas: 1
|
||||
|
||||
@@ -44,5 +44,146 @@ if [ "$is_aws_ecs" = "Yes" ]; then
|
||||
else
|
||||
echo "I couldn't find AWS_CONTAINER_CREDENTIALS_RELATIVE_URI env var to get IAM role info (the task is running without a task role probably)"
|
||||
fi
|
||||
|
||||
print_3title "ECS task metadata hints"
|
||||
aws_exec_env=$(printenv AWS_EXECUTION_ENV 2>/dev/null)
|
||||
if [ "$aws_exec_env" ]; then
|
||||
printf "AWS_EXECUTION_ENV=%s\n" "$aws_exec_env"
|
||||
fi
|
||||
|
||||
ecs_task_metadata=""
|
||||
if [ "$aws_ecs_metadata_uri" ]; then
|
||||
ecs_task_metadata=$(eval $aws_ecs_req "$aws_ecs_metadata_uri/task" 2>/dev/null)
|
||||
fi
|
||||
|
||||
if [ "$ecs_task_metadata" ]; then
|
||||
launch_type=$(printf "%s" "$ecs_task_metadata" | grep -oE '"LaunchType":"[^"]+"' | head -n 1 | cut -d '"' -f4)
|
||||
if [ "$launch_type" ]; then
|
||||
printf "ECS LaunchType reported: %s\n" "$launch_type"
|
||||
fi
|
||||
network_modes=$(printf "%s" "$ecs_task_metadata" | grep -oE '"NetworkMode":"[^"]+"' | cut -d '"' -f4 | sort -u | tr '\n' ' ')
|
||||
if [ "$network_modes" ]; then
|
||||
printf "Reported NetworkMode(s): %s\n" "$network_modes"
|
||||
fi
|
||||
else
|
||||
echo "Unable to fetch task metadata (check ECS_CONTAINER_METADATA_URI)."
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
|
||||
print_3title "IMDS reachability from this task"
|
||||
imds_token=""
|
||||
imds_roles=""
|
||||
imds_http_code=""
|
||||
imds_tool=""
|
||||
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
imds_tool="curl"
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
imds_tool="wget"
|
||||
fi
|
||||
|
||||
if [ "$imds_tool" = "curl" ]; then
|
||||
imds_token=$(curl -s --connect-timeout 2 --max-time 2 -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600" 2>/dev/null)
|
||||
if [ "$imds_token" ]; then
|
||||
printf "[!] IMDSv2 token request succeeded (metadata reachable from this task).\n"
|
||||
imds_roles=$(curl -s --connect-timeout 2 --max-time 2 -H "X-aws-ec2-metadata-token: $imds_token" "http://169.254.169.254/latest/meta-data/iam/security-credentials/" 2>/dev/null | tr '\n' ' ')
|
||||
if [ "$imds_roles" ]; then
|
||||
printf " Instance profile role(s) exposed via IMDS: %s\n" "$imds_roles"
|
||||
first_role=$(printf "%s" "$imds_roles" | awk '{print $1}')
|
||||
if [ "$first_role" ]; then
|
||||
printf " Example: curl -H 'X-aws-ec2-metadata-token: <TOKEN>' http://169.254.169.254/latest/meta-data/iam/security-credentials/%s\n" "$first_role"
|
||||
fi
|
||||
else
|
||||
printf " No IAM role names returned (instance profile might be missing).\n"
|
||||
fi
|
||||
else
|
||||
imds_http_code=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 2 --max-time 2 "http://169.254.169.254/latest/meta-data/" 2>/dev/null)
|
||||
case "$imds_http_code" in
|
||||
000|"")
|
||||
printf "[i] IMDS endpoint did not respond (likely blocked via hop-limit or host firewalling).\n"
|
||||
;;
|
||||
401)
|
||||
printf "[i] IMDS requires v2 tokens but token requests are being blocked (bridge-mode tasks rely on this when hop limit = 1).\n"
|
||||
;;
|
||||
*)
|
||||
printf "[i] IMDS GET returned HTTP %s (investigate host configuration).\n" "$imds_http_code"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
elif [ "$imds_tool" = "wget" ]; then
|
||||
imds_token=$(wget -q -O - --timeout=2 --tries=1 --method=PUT --header="X-aws-ec2-metadata-token-ttl-seconds: 21600" "http://169.254.169.254/latest/api/token" 2>/dev/null)
|
||||
if [ "$imds_token" ]; then
|
||||
printf "[!] IMDSv2 token request succeeded (metadata reachable from this task).\n"
|
||||
imds_roles=$(wget -q -O - --timeout=2 --tries=1 --header="X-aws-ec2-metadata-token: $imds_token" "http://169.254.169.254/latest/meta-data/iam/security-credentials/" 2>/dev/null | tr '\n' ' ')
|
||||
if [ "$imds_roles" ]; then
|
||||
printf " Instance profile role(s) exposed via IMDS: %s\n" "$imds_roles"
|
||||
else
|
||||
printf " No IAM role names returned (instance profile might be missing).\n"
|
||||
fi
|
||||
else
|
||||
wget --server-response -O /dev/null --timeout=2 --tries=1 "http://169.254.169.254/latest/meta-data/" 2>&1 | awk 'BEGIN{code=""} /^ HTTP/{code=$2} END{ if(code!="") { printf("[i] IMDS GET returned HTTP %s (token could not be retrieved).\n", code); } else { print "[i] IMDS endpoint did not respond (likely blocked)."; } }'
|
||||
fi
|
||||
else
|
||||
echo "Neither curl nor wget were found, I can't test IMDS reachability."
|
||||
fi
|
||||
echo ""
|
||||
|
||||
print_3title "ECS agent IMDS settings"
|
||||
if [ -r "/etc/ecs/ecs.config" ]; then
|
||||
ecs_block_line=$(grep -E "^ECS_AWSVPC_BLOCK_IMDS=" /etc/ecs/ecs.config 2>/dev/null | tail -n 1)
|
||||
ecs_host_line=$(grep -E "^ECS_ENABLE_TASK_IAM_ROLE_NETWORK_HOST=" /etc/ecs/ecs.config 2>/dev/null | tail -n 1)
|
||||
if [ "$ecs_block_line" ]; then
|
||||
printf "%s\n" "$ecs_block_line"
|
||||
if echo "$ecs_block_line" | grep -qi "=true"; then
|
||||
echo " -> awsvpc-mode tasks should be blocked from IMDS by the ECS agent."
|
||||
else
|
||||
echo " -> awsvpc-mode tasks can still reach IMDS (set this to true to block)."
|
||||
fi
|
||||
else
|
||||
echo "ECS_AWSVPC_BLOCK_IMDS not set (awsvpc tasks inherit host IMDS reachability)."
|
||||
fi
|
||||
|
||||
if [ "$ecs_host_line" ]; then
|
||||
printf "%s\n" "$ecs_host_line"
|
||||
if echo "$ecs_host_line" | grep -qi "=false"; then
|
||||
echo " -> Host-network tasks lose IAM task roles but IMDS is blocked."
|
||||
else
|
||||
echo " -> Host-network tasks keep IAM task roles and retain IMDS access."
|
||||
fi
|
||||
else
|
||||
echo "ECS_ENABLE_TASK_IAM_ROLE_NETWORK_HOST not set (defaults keep IMDS reachable for host-mode tasks)."
|
||||
fi
|
||||
else
|
||||
echo "Cannot read /etc/ecs/ecs.config (file missing or permissions denied)."
|
||||
fi
|
||||
echo ""
|
||||
|
||||
print_3title "DOCKER-USER IMDS filtering"
|
||||
iptables_cmd=""
|
||||
if command -v iptables >/dev/null 2>&1; then
|
||||
iptables_cmd=$(command -v iptables)
|
||||
elif command -v iptables-nft >/dev/null 2>&1; then
|
||||
iptables_cmd=$(command -v iptables-nft)
|
||||
fi
|
||||
|
||||
if [ "$iptables_cmd" ]; then
|
||||
docker_rules=$($iptables_cmd -S DOCKER-USER 2>/dev/null)
|
||||
if [ $? -eq 0 ]; then
|
||||
if [ "$docker_rules" ]; then
|
||||
echo "$docker_rules"
|
||||
else
|
||||
echo "(DOCKER-USER chain exists but no rules were found)"
|
||||
fi
|
||||
if echo "$docker_rules" | grep -q "169\\.254\\.169\\.254"; then
|
||||
echo " -> IMDS traffic is explicitly filtered before Docker NAT."
|
||||
else
|
||||
echo " -> No DOCKER-USER rule drops 169.254.169.254 traffic (bridge tasks rely on hop limit or host firewalling)."
|
||||
fi
|
||||
else
|
||||
echo "Unable to read DOCKER-USER chain (missing chain or insufficient permissions)."
|
||||
fi
|
||||
else
|
||||
echo "iptables binary not found; cannot inspect DOCKER-USER chain."
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# License: GNU GPL
|
||||
# Version: 1.2
|
||||
# Functions Used: echo_not_found, print_2title, print_info, print_3title
|
||||
# Global Variables: $EXTRA_CHECKS, $SEARCH_IN_FOLDER, $IAMROOT, $WRITABLESYSTEMDPATH
|
||||
# Global Variables: $EXTRA_CHECKS, $IAMROOT, $SEARCH_IN_FOLDER, $TIMEOUT, $WRITABLESYSTEMDPATH
|
||||
# Initial Functions:
|
||||
# Generated Global Variables: $service_unit, $service_path, $service_content, $finding, $findings, $service_file, $exec_path, $exec_paths, $service, $line, $target_file, $target_exec, $relpath1, $relpath2
|
||||
# Fat linpeas: 0
|
||||
@@ -178,7 +178,11 @@ if ! [ "$SEARCH_IN_FOLDER" ]; then
|
||||
if [ "$EXTRA_CHECKS" ]; then
|
||||
echo ""
|
||||
print_3title "Service versions and status:"
|
||||
(service --status-all || service -e || chkconfig --list || rc-status || launchctl list) 2>/dev/null || echo_not_found "service|chkconfig|rc-status|launchctl"
|
||||
if [ "$TIMEOUT" ]; then
|
||||
$TIMEOUT 30 sh -c "(service --status-all || service -e || chkconfig --list || rc-status || launchctl list) 2>/dev/null" || echo_not_found "service|chkconfig|rc-status|launchctl"
|
||||
else
|
||||
(service --status-all || service -e || chkconfig --list || rc-status || launchctl list) 2>/dev/null || echo_not_found "service|chkconfig|rc-status|launchctl"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check systemd path writability
|
||||
@@ -190,4 +194,4 @@ if ! [ "$SEARCH_IN_FOLDER" ]; then
|
||||
fi
|
||||
|
||||
echo ""
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
# Functions Used: print_2title, print_list, echo_not_found
|
||||
# Global Variables: $SEARCH_IN_FOLDER, $Wfolders, $SED_RED, $SED_RED_YELLOW, $NC
|
||||
# Initial Functions:
|
||||
# Generated Global Variables: $WRITABLESYSTEMDPATH, $line, $service, $file, $version, $user, $caps, $path, $path_line, $service_file, $exec_line, $cmd
|
||||
# Generated Global Variables: $WRITABLESYSTEMDPATH, $line, $service, $file, $version, $user, $caps, $path, $path_line, $service_file, $exec_line, $exec_value, $cmd, $cmd_path, $svc_path_entry, $svc_writable_path
|
||||
# Fat linpeas: 0
|
||||
# Small linpeas: 1
|
||||
|
||||
@@ -113,21 +113,39 @@ if ! [ "$SEARCH_IN_FOLDER" ]; then
|
||||
service=$(echo "$line" | awk '{print $1}')
|
||||
service_file=$(get_service_file "$service")
|
||||
if [ -n "$service_file" ]; then
|
||||
# Check service-specific PATH entries (Environment=PATH=...)
|
||||
svc_writable_path=$(grep -E '^Environment=.*PATH=' "$service_file" 2>/dev/null | sed -E 's/^Environment=//; s/^"//; s/"$//; s/^PATH=//' | tr ':' '\n' | while read -r svc_path_entry; do
|
||||
[ -z "$svc_path_entry" ] && continue
|
||||
if [ -d "$svc_path_entry" ] && [ -w "$svc_path_entry" ]; then
|
||||
echo "$svc_path_entry"
|
||||
fi
|
||||
done)
|
||||
if [ "$svc_writable_path" ]; then
|
||||
for svc_path_entry in $svc_writable_path; do
|
||||
echo "$service: Writable service PATH entry '$svc_path_entry'" | sed -${E} "s,.*,${SED_RED_YELLOW},g"
|
||||
done
|
||||
fi
|
||||
|
||||
# Check ExecStart paths
|
||||
grep -E "ExecStart|ExecStartPre|ExecStartPost" "$service_file" 2>/dev/null |
|
||||
while read -r exec_line; do
|
||||
# Extract the first word after ExecStart* as the command
|
||||
cmd=$(echo "$exec_line" | awk '{print $2}' | tr -d '"')
|
||||
# Extract the rest as arguments
|
||||
args=$(echo "$exec_line" | awk '{$1=$2=""; print $0}' | tr -d '"')
|
||||
# Extract command from the right side of Exec*=, not from argv
|
||||
exec_value="${exec_line#*=}"
|
||||
exec_value=$(echo "$exec_value" | sed 's/^[[:space:]]*//')
|
||||
cmd=$(echo "$exec_value" | awk '{print $1}' | tr -d '"')
|
||||
# Strip systemd command prefixes (-, @, :, +, !) before path checks
|
||||
cmd_path=$(echo "$cmd" | sed -E 's/^[-@:+!]+//')
|
||||
|
||||
# Only check the command path, not arguments
|
||||
if [ -n "$cmd" ] && [ -w "$cmd" ]; then
|
||||
echo "$service: $cmd (from $exec_line)" | sed -${E} "s,.*,${SED_RED},g"
|
||||
if [ -n "$cmd_path" ] && [ -w "$cmd_path" ]; then
|
||||
echo "$service: $cmd_path (from $exec_line)" | sed -${E} "s,.*,${SED_RED},g"
|
||||
fi
|
||||
# Check for relative paths only in the command, not arguments
|
||||
if [ -n "$cmd" ] && [ "${cmd#/}" = "$cmd" ] && ! echo "$cmd" | grep -qE '^-|^--'; then
|
||||
echo "$service: Uses relative path '$cmd' (from $exec_line)" | sed -${E} "s,.*,${SED_RED},g"
|
||||
if [ -n "$cmd_path" ] && [ "${cmd_path#/}" = "$cmd_path" ] && [ "${cmd_path#\$}" = "$cmd_path" ]; then
|
||||
echo "$service: Uses relative path '$cmd_path' (from $exec_line)" | sed -${E} "s,.*,${SED_RED},g"
|
||||
if [ "$svc_writable_path" ]; then
|
||||
echo "$service: Relative Exec path + writable service PATH can allow path hijacking" | sed -${E} "s,.*,${SED_RED_YELLOW},g"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
@@ -153,4 +171,4 @@ if ! [ "$SEARCH_IN_FOLDER" ]; then
|
||||
fi
|
||||
|
||||
echo ""
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
# License: GNU GPL
|
||||
# Version: 1.1
|
||||
# Functions Used: print_2title, print_info
|
||||
# Global Variables: $EXTRA_CHECKS, $groupsB, $groupsVB, $IAMROOT, $idB, $knw_grps, $knw_usrs, $nosh_usrs, $SEARCH_IN_FOLDER, $sh_usrs, $USER, $SED_RED, $SED_GREEN, $NC, $RED
|
||||
# Global Variables: $EXTRA_CHECKS, $groupsB, $groupsVB, $IAMROOT, $idB, $knw_grps, $knw_usrs, $nosh_usrs, $SEARCH_IN_FOLDER, $sh_usrs, $USER, $SED_RED, $SED_GREEN, $SED_RED_YELLOW, $NC, $RED
|
||||
# Initial Functions:
|
||||
# Generated Global Variables: $unix_scks_list, $unix_scks_list2, $perms, $owner, $owner_info, $response, $socket, $cmd, $mode, $group
|
||||
# Fat linpeas: 0
|
||||
@@ -142,10 +142,13 @@ if ! [ "$IAMROOT" ]; then
|
||||
# Highlight dangerous ownership
|
||||
if echo "$owner_info" | grep -q "root"; then
|
||||
echo " └─(${RED}Owned by root${NC})"
|
||||
if echo "$perms" | grep -q "Write"; then
|
||||
echo " └─High risk: root-owned and writable Unix socket" | sed -${E} "s,.*,${SED_RED_YELLOW},g"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
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,126 @@
|
||||
# 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 [ "$candidates" ]; then
|
||||
|
||||
# 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
|
||||
fi
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# Title: Processes & Cron & Services & Timers - Deleted open files
|
||||
# ID: PR_Deleted_open_files
|
||||
# Author: Carlos Polop
|
||||
# Last Update: 2025-01-07
|
||||
# Description: Identify deleted files still held open by running processes
|
||||
# License: GNU GPL
|
||||
# Version: 1.0
|
||||
# Functions Used: print_2title, print_info
|
||||
# Global Variables: $DEBUG, $EXTRA_CHECKS, $E, $SED_RED
|
||||
# Initial Functions:
|
||||
# Generated Global Variables:
|
||||
# Fat linpeas: 0
|
||||
# Small linpeas: 1
|
||||
|
||||
if [ "$(command -v lsof 2>/dev/null || echo -n '')" ] || [ "$DEBUG" ]; then
|
||||
print_2title "Deleted files still open"
|
||||
print_info "Open deleted files can hide tools and still consume disk space"
|
||||
lsof +L1 2>/dev/null | sed -${E} "s,\\(deleted\\),${SED_RED},g"
|
||||
echo ""
|
||||
elif [ "$EXTRA_CHECKS" ] || [ "$DEBUG" ]; then
|
||||
print_2title "Deleted files still open"
|
||||
print_info "lsof not found, scanning /proc for deleted file descriptors"
|
||||
ls -l /proc/[0-9]*/fd 2>/dev/null | grep "(deleted)" | sed -${E} "s,\\(deleted\\),${SED_RED},g" | head -n 200
|
||||
echo ""
|
||||
fi
|
||||
@@ -23,6 +23,7 @@ if ! [ "$SEARCH_IN_FOLDER" ]; then
|
||||
incrontab -l 2>/dev/null
|
||||
ls -alR /etc/cron* /var/spool/cron/crontabs /var/spool/anacron 2>/dev/null | sed -${E} "s,$cronjobsG,${SED_GREEN},g" | sed "s,$cronjobsB,${SED_RED},g"
|
||||
cat /etc/cron* /etc/at* /etc/anacrontab /var/spool/cron/crontabs/* /etc/incron.d/* /var/spool/incron/* 2>/dev/null | tr -d "\r" | grep -v "^#" | sed -${E} "s,$Wfolders,${SED_RED_YELLOW},g" | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed "s,$USER,${SED_LIGHT_MAGENTA}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed "s,root,${SED_RED},"
|
||||
grep -Hn '^PATH=' /etc/crontab /etc/cron.d/* 2>/dev/null | sed -${E} "s,$Wfolders,${SED_RED_YELLOW},g"
|
||||
crontab -l -u "$USER" 2>/dev/null | tr -d "\r"
|
||||
ls -lR /usr/lib/cron/tabs/ /private/var/at/jobs /var/at/tabs/ /etc/periodic/ 2>/dev/null | sed -${E} "s,$cronjobsG,${SED_GREEN},g" | sed "s,$cronjobsB,${SED_RED},g" #MacOS paths
|
||||
atq 2>/dev/null
|
||||
@@ -247,4 +248,4 @@ else
|
||||
print_info "https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/index.html#scheduledcron-jobs"
|
||||
find "$SEARCH_IN_FOLDER" '(' -type d -or -type f ')' '(' -name "cron*" -or -name "anacron" -or -name "anacrontab" -or -name "incron.d" -or -name "incron" -or -name "at" -or -name "periodic" ')' -exec echo {} \; -exec ls -lR {} \;
|
||||
fi
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
# Description: Check for internet access
|
||||
# License: GNU GPL
|
||||
# Version: 1.0
|
||||
# Functions Used: check_dns, check_icmp, check_tcp_443, check_tcp_443_bin, check_tcp_80, print_2title, check_external_hostname
|
||||
# Global Variables:
|
||||
# Functions Used: check_dns, check_icmp, check_tcp_443, check_tcp_443_bin, check_tcp_80, print_2title, print_3title, print_info, check_external_hostname
|
||||
# Global Variables: $E
|
||||
# Initial Functions:
|
||||
# Generated Global Variables: $pid4, $pid2, $pid1, $pid3, $$tcp443_bin_status, $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
|
||||
|
||||
@@ -29,8 +29,8 @@ 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 + 1 )) && kill -9 $pid1 $pid2 $pid3 $pid4 2>/dev/null) &
|
||||
# Kill all check workers after timeout + 1s without relying on integer arithmetic
|
||||
(sleep "$TIMEOUT_INTERNET_SECONDS"; sleep 1; kill -9 $pid1 $pid2 $pid3 $pid4 2>/dev/null) &
|
||||
|
||||
check_tcp_443_bin $TIMEOUT_INTERNET_SECONDS 2>/dev/null
|
||||
tcp443_bin_status=$?
|
||||
@@ -50,3 +50,9 @@ if [ "$tcp443_bin_status" -eq 0 ] && \
|
||||
fi
|
||||
|
||||
echo ""
|
||||
print_3title "Proxy discovery"
|
||||
print_info "Checking common proxy env vars and apt proxy config"
|
||||
(env | grep -iE '^(http|https|ftp|all)_proxy=|^no_proxy=') 2>/dev/null | sed -${E} "s,_proxy|no_proxy,${SED_RED_YELLOW},g"
|
||||
grep -RinE 'Acquire::(http|https)::Proxy|proxy' /etc/apt/apt.conf /etc/apt/apt.conf.d 2>/dev/null | sed -${E} "s,proxy|Acquire::http::Proxy|Acquire::https::Proxy,${SED_RED_YELLOW},g"
|
||||
|
||||
echo ""
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
# Description: Check network interfaces
|
||||
# License: GNU GPL
|
||||
# Version: 1.0
|
||||
# Functions Used: print_2title
|
||||
# Global Variables:
|
||||
# Functions Used: print_2title, print_3title
|
||||
# Global Variables: $E, $SED_RED_YELLOW
|
||||
# Initial Functions:
|
||||
# Generated Global Variables: $iface, $state, $mac, $ip_file, $line
|
||||
# Fat linpeas: 0
|
||||
@@ -73,4 +73,22 @@ else
|
||||
parse_network_interfaces
|
||||
fi
|
||||
|
||||
echo ""
|
||||
if command -v ip >/dev/null 2>&1; then
|
||||
print_3title "Routing & policy quick view"
|
||||
ip route 2>/dev/null
|
||||
ip -6 route 2>/dev/null | head -n 30
|
||||
echo ""
|
||||
ip rule 2>/dev/null
|
||||
|
||||
print_3title "Virtual/overlay interfaces quick view"
|
||||
ip -d link 2>/dev/null | grep -E "^[0-9]+:|veth|docker|cni|flannel|br-|bridge|vlan|bond|tun|tap|wg|tailscale" | sed -${E} "s,veth|docker|cni|flannel|br-|bridge|vlan|bond|tun|tap|wg|tailscale,${SED_RED_YELLOW},g"
|
||||
|
||||
print_3title "Network namespaces quick view"
|
||||
ip netns list 2>/dev/null
|
||||
ls -la /var/run/netns/ 2>/dev/null
|
||||
fi
|
||||
|
||||
print_3title "Forwarding status"
|
||||
sysctl net.ipv4.ip_forward net.ipv6.conf.all.forwarding 2>/dev/null | sed -${E} "s,=[[:space:]]*1,${SED_RED_YELLOW},g"
|
||||
|
||||
echo ""
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# License: GNU GPL
|
||||
# Version: 1.0
|
||||
# Functions Used: print_2title, print_3title, print_info
|
||||
# Global Variables: $E, $SED_RED
|
||||
# Global Variables: $E, $SED_RED, $SED_RED_YELLOW
|
||||
# Initial Functions:
|
||||
# Generated Global Variables: $pid_dir, $tx_queue, $pid, $rem_port, $proc_file, $rem_ip, $local_ip, $rx_queue, $proto, $rem_addr, $program, $state, $header_sep, $proc_info, $inode, $header, $line, $local_addr, $local_port
|
||||
# Fat linpeas: 0
|
||||
@@ -122,6 +122,45 @@ get_open_ports() {
|
||||
parse_proc_net_ports "udp"
|
||||
fi
|
||||
|
||||
# Focused local service exposure view
|
||||
print_3title "Local-only listeners (loopback)"
|
||||
if command -v ss >/dev/null 2>&1; then
|
||||
ss -nltpu 2>/dev/null | grep -E "127\.0\.0\.1:|::1:" | sed -${E} "s,127\.0\.0\.1:|::1:,${SED_RED},g"
|
||||
elif command -v netstat >/dev/null 2>&1; then
|
||||
netstat -punta 2>/dev/null | grep -i listen | grep -E "127\.0\.0\.1:|::1:" | sed -${E} "s,127\.0\.0\.1:|::1:,${SED_RED},g"
|
||||
fi
|
||||
|
||||
print_3title "Unique listener bind addresses"
|
||||
if command -v ss >/dev/null 2>&1; then
|
||||
ss -nltpuH 2>/dev/null | awk '{
|
||||
a=$5
|
||||
if (a ~ /^\[/) {
|
||||
sub(/^\[/, "", a)
|
||||
sub(/\]:[0-9]+$/, "", a)
|
||||
} else if (a ~ /:[0-9]+$/) {
|
||||
sub(/:[0-9]+$/, "", a)
|
||||
}
|
||||
sub(/^::ffff:/, "", a)
|
||||
if (a != "") print a
|
||||
}' | sort -u | sed -${E} "s,127\.0\.0\.1|::1,${SED_RED},g"
|
||||
elif command -v netstat >/dev/null 2>&1; then
|
||||
netstat -punta 2>/dev/null | grep -i listen | awk '{
|
||||
a=$4
|
||||
if (a ~ /^\[/) {
|
||||
sub(/^\[/, "", a)
|
||||
sub(/\]:[0-9]+$/, "", a)
|
||||
} else if (a ~ /:[0-9]+$/) {
|
||||
sub(/:[0-9]+$/, "", a)
|
||||
}
|
||||
if (a == ":::" ) a="::"
|
||||
sub(/^::ffff:/, "", a)
|
||||
if (a != "") print a
|
||||
}' | sort -u | sed -${E} "s,127\.0\.0\.1|::1,${SED_RED},g"
|
||||
fi
|
||||
|
||||
print_3title "Potential local forwarders/relays"
|
||||
ps aux 2>/dev/null | grep -E "[s]ocat|[s]sh .*(-L|-R|-D)|[n]cat|[n]c .*-l" | sed -${E} "s,socat|ssh|-L|-R|-D|ncat|nc,${SED_RED_YELLOW},g"
|
||||
|
||||
# Additional port information
|
||||
if [ "$EXTRA_CHECKS" ] || [ "$DEBUG" ]; then
|
||||
print_3title "Additional Port Information"
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
# License: GNU GPL
|
||||
# Version: 1.0
|
||||
# Functions Used: print_2title, print_3title, print_info, warn_exec
|
||||
# Global Variables: $EXTRA_CHECKS, $E, $SED_RED, $SED_GREEN
|
||||
# Global Variables: $EXTRA_CHECKS, $E, $SED_RED, $SED_GREEN, $SED_RED_YELLOW
|
||||
# Initial Functions:
|
||||
# Generated Global Variables: $tools_found, $tool, $interfaces, $interfaces_found, $iface, $cmd, $pattern, $patterns
|
||||
# Generated Global Variables: $tools_found, $tool, $interfaces, $interfaces_found, $iface, $cmd, $pattern, $patterns, $dumpcap_test_file
|
||||
# Fat linpeas: 0
|
||||
# Small linpeas: 1
|
||||
|
||||
@@ -26,8 +26,17 @@ check_command() {
|
||||
# Function to check if we can sniff on an interface
|
||||
check_interface_sniffable() {
|
||||
local iface=$1
|
||||
if timeout 1 tcpdump -i "$iface" -c 1 >/dev/null 2>&1; then
|
||||
return 0
|
||||
if check_command tcpdump; then
|
||||
if timeout 1 tcpdump -i "$iface" -c 1 >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
elif check_command dumpcap; then
|
||||
dumpcap_test_file="/tmp/.linpeas_dumpcap_test_$$.pcap"
|
||||
if timeout 2 dumpcap -i "$iface" -c 1 -q -w "$dumpcap_test_file" >/dev/null 2>&1; then
|
||||
rm -f "$dumpcap_test_file" 2>/dev/null
|
||||
return 0
|
||||
fi
|
||||
rm -f "$dumpcap_test_file" 2>/dev/null
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
@@ -55,6 +64,20 @@ check_network_traffic_analysis() {
|
||||
tools_found=1
|
||||
# Check tcpdump version and capabilities
|
||||
warn_exec tcpdump --version 2>/dev/null | head -n 1
|
||||
getcap "$(command -v tcpdump)" 2>/dev/null
|
||||
fi
|
||||
|
||||
if check_command dumpcap; then
|
||||
echo "dumpcap is available" | sed -${E} "s,.*,${SED_GREEN},g"
|
||||
tools_found=1
|
||||
warn_exec dumpcap --version 2>/dev/null | head -n 1
|
||||
getcap "$(command -v dumpcap)" 2>/dev/null
|
||||
|
||||
if id -nG 2>/dev/null | grep -qw wireshark; then
|
||||
echo "Current user is in wireshark group" | sed -${E} "s,.*,${SED_GREEN},g"
|
||||
elif getent group wireshark >/dev/null 2>&1; then
|
||||
echo "wireshark group exists but current user is not in it" | sed -${E} "s,.*,${SED_RED_YELLOW},g"
|
||||
fi
|
||||
fi
|
||||
|
||||
if check_command tshark; then
|
||||
@@ -68,10 +91,28 @@ check_network_traffic_analysis() {
|
||||
echo "wireshark is available" | sed -${E} "s,.*,${SED_GREEN},g"
|
||||
tools_found=1
|
||||
fi
|
||||
|
||||
if check_command ngrep; then
|
||||
echo "ngrep is available" | sed -${E} "s,.*,${SED_GREEN},g"
|
||||
tools_found=1
|
||||
fi
|
||||
|
||||
if check_command tcpflow; then
|
||||
echo "tcpflow is available" | sed -${E} "s,.*,${SED_GREEN},g"
|
||||
tools_found=1
|
||||
fi
|
||||
|
||||
if [ $tools_found -eq 0 ]; then
|
||||
echo "No sniffing tools found" | sed -${E} "s,.*,${SED_RED},g"
|
||||
fi
|
||||
|
||||
if check_command tcpdump; then
|
||||
echo "Sniffable interfaces according to tcpdump -D:"
|
||||
timeout 2 tcpdump -D 2>/dev/null
|
||||
elif check_command dumpcap; then
|
||||
echo "Sniffable interfaces according to dumpcap -D:"
|
||||
timeout 2 dumpcap -D 2>/dev/null
|
||||
fi
|
||||
|
||||
# Check network interfaces
|
||||
echo ""
|
||||
@@ -88,25 +129,28 @@ check_network_traffic_analysis() {
|
||||
fi
|
||||
|
||||
for iface in $interfaces; do
|
||||
if [ "$iface" != "lo" ]; then # Skip loopback
|
||||
if [ "$iface" = "lo" ]; then
|
||||
echo -n "Interface $iface (loopback): "
|
||||
else
|
||||
echo -n "Interface $iface: "
|
||||
if check_interface_sniffable "$iface"; then
|
||||
echo "Sniffable" | sed -${E} "s,.*,${SED_GREEN},g"
|
||||
interfaces_found=1
|
||||
|
||||
# Check promiscuous mode
|
||||
if check_promiscuous_mode "$iface"; then
|
||||
echo " - Promiscuous mode enabled" | sed -${E} "s,.*,${SED_RED},g"
|
||||
fi
|
||||
|
||||
# Get interface details
|
||||
if [ "$EXTRA_CHECKS" ]; then
|
||||
echo " - Interface details:"
|
||||
warn_exec ip addr show "$iface" 2>/dev/null || ifconfig "$iface" 2>/dev/null
|
||||
fi
|
||||
else
|
||||
echo "Not sniffable" | sed -${E} "s,.*,${SED_RED},g"
|
||||
fi
|
||||
|
||||
if check_interface_sniffable "$iface"; then
|
||||
echo "Sniffable" | sed -${E} "s,.*,${SED_GREEN},g"
|
||||
interfaces_found=1
|
||||
|
||||
# Check promiscuous mode
|
||||
if [ "$iface" != "lo" ] && check_promiscuous_mode "$iface"; then
|
||||
echo " - Promiscuous mode enabled" | sed -${E} "s,.*,${SED_RED},g"
|
||||
fi
|
||||
|
||||
# Get interface details
|
||||
if [ "$EXTRA_CHECKS" ]; then
|
||||
echo " - Interface details:"
|
||||
warn_exec ip addr show "$iface" 2>/dev/null || ifconfig "$iface" 2>/dev/null
|
||||
fi
|
||||
else
|
||||
echo "Not sniffable" | sed -${E} "s,.*,${SED_RED},g"
|
||||
fi
|
||||
done
|
||||
|
||||
@@ -145,7 +189,12 @@ check_network_traffic_analysis() {
|
||||
print_info "To capture sensitive traffic, you can use:"
|
||||
echo "tcpdump -i <interface> -w capture.pcap" | sed -${E} "s,.*,${SED_GREEN},g"
|
||||
echo "tshark -i <interface> -w capture.pcap" | sed -${E} "s,.*,${SED_GREEN},g"
|
||||
echo "dumpcap -i <interface> -w capture.pcap" | sed -${E} "s,.*,${SED_GREEN},g"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
print_3title "Running sniffing/traffic reconstruction processes"
|
||||
ps aux 2>/dev/null | grep -E "[t]cpdump|[d]umpcap|[t]shark|[w]ireshark|[n]grep|[t]cpflow" | sed -${E} "s,.*,${SED_RED_YELLOW},g"
|
||||
|
||||
# Additional information
|
||||
if [ "$EXTRA_CHECKS" ]; then
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
# License: GNU GPL
|
||||
# Version: 1.0
|
||||
# Functions Used: print_2title, print_3title, warn_exec, echo_not_found
|
||||
# Global Variables: $EXTRA_CHECKS, $E, $SED_RED, $SED_GREEN, $SED_YELLOW
|
||||
# Global Variables: $EXTRA_CHECKS, $E, $SED_RED, $SED_GREEN, $SED_YELLOW, $SED_RED_YELLOW
|
||||
# Initial Functions:
|
||||
# Generated Global Variables: $rules_file, $cmd, $tool, $config_file
|
||||
# Generated Global Variables: $rules_file, $cmd, $tool, $config_file, $sysctl_var
|
||||
# Fat linpeas: 0
|
||||
# Small linpeas: 1
|
||||
|
||||
@@ -90,6 +90,9 @@ analyze_nftables() {
|
||||
# List all rules
|
||||
echo -e "\nNftables Ruleset:"
|
||||
warn_exec nft list ruleset 2>/dev/null
|
||||
|
||||
echo -e "\nNftables Ruleset with handles (-a):"
|
||||
warn_exec nft -a list ruleset 2>/dev/null | sed -${E} "s,\\bdrop\\b|\\breject\\b|handle [0-9]+,${SED_RED_YELLOW},g"
|
||||
|
||||
# Check for saved rules
|
||||
echo -e "\nSaved Rules:"
|
||||
@@ -180,6 +183,17 @@ analyze_firewall_rules() {
|
||||
analyze_nftables
|
||||
analyze_firewalld
|
||||
analyze_ufw
|
||||
|
||||
echo ""
|
||||
print_3title "Forwarding and rp_filter"
|
||||
for sysctl_var in net.ipv4.ip_forward net.ipv6.conf.all.forwarding net.ipv4.conf.all.rp_filter; do
|
||||
sysctl "$sysctl_var" 2>/dev/null | sed -${E} "s,=[[:space:]]*1,${SED_RED_YELLOW},g"
|
||||
done
|
||||
|
||||
if check_command conntrack; then
|
||||
echo -e "\nConntrack state (first 20):"
|
||||
warn_exec conntrack -L 2>/dev/null | head -n 20
|
||||
fi
|
||||
|
||||
# Additional checks if EXTRA_CHECKS is enabled
|
||||
if [ "$EXTRA_CHECKS" ]; then
|
||||
@@ -207,4 +221,4 @@ analyze_firewall_rules() {
|
||||
}
|
||||
|
||||
# Run the main function
|
||||
analyze_firewall_rules
|
||||
analyze_firewall_rules
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
# Functions Used: print_2title, print_info
|
||||
# Global Variables: $Groups, $groupsB, $groupsVB, $nosh_usrs, $sh_usrs, $USER
|
||||
# Initial Functions:
|
||||
# Generated Global Variables: $pkexec_bin, $policy_dir, $policy_file
|
||||
# Generated Global Variables: $pkexec_bin, $pkexec_version, $policy_dir, $policy_file
|
||||
# Fat linpeas: 0
|
||||
# Small linpeas: 1
|
||||
|
||||
@@ -30,6 +30,10 @@ if [ -n "$pkexec_bin" ]; then
|
||||
# Check polkit version for known vulnerabilities
|
||||
if command -v pkexec >/dev/null 2>&1; then
|
||||
pkexec --version 2>/dev/null
|
||||
pkexec_version="$(pkexec --version 2>/dev/null | grep -oE '[0-9]+(\\.[0-9]+)+')"
|
||||
if [ "$pkexec_version" ] && [ "$(printf '%s\n' "$pkexec_version" "0.120" | sort -V | head -n1)" = "$pkexec_version" ] && [ "$pkexec_version" != "0.120" ]; then
|
||||
echo "Potentially vulnerable to CVE-2021-4034 (PwnKit) - check distro patches" | sed -${E} "s,.*,${SED_RED_YELLOW},"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# License: GNU GPL
|
||||
# Version: 1.0
|
||||
# Functions Used: print_2title
|
||||
# Global Variables: $MACPEAS, $sh_usrs, $USER
|
||||
# Global Variables: $MACPEAS, $sh_usrs, $TIMEOUT, $USER
|
||||
# Initial Functions:
|
||||
# Generated Global Variables: $ushell, $no_shells, $unexpected_shells
|
||||
# Fat linpeas: 0
|
||||
@@ -26,8 +26,16 @@ else
|
||||
no_shells=$(grep -Ev "sh$" /etc/passwd 2>/dev/null | cut -d ':' -f 7 | sort | uniq)
|
||||
unexpected_shells=""
|
||||
printf "%s\n" "$no_shells" | while read f; do
|
||||
if $f -c 'whoami' 2>/dev/null | grep -q "$USER"; then
|
||||
unexpected_shells="$f\n$unexpected_shells"
|
||||
if [ -x "$f" ]; then
|
||||
if [ "$TIMEOUT" ]; then
|
||||
if $TIMEOUT 1 "$f" -c 'whoami' 2>/dev/null | grep -q "$USER"; then
|
||||
unexpected_shells="$f\n$unexpected_shells"
|
||||
fi
|
||||
else
|
||||
if "$f" -c 'whoami' 2>/dev/null | grep -q "$USER"; then
|
||||
unexpected_shells="$f\n$unexpected_shells"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
grep "sh$" /etc/passwd 2>/dev/null | sort | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed "s,$USER,${SED_LIGHT_MAGENTA}," | sed "s,root,${SED_RED},"
|
||||
@@ -41,4 +49,4 @@ else
|
||||
done
|
||||
fi
|
||||
fi
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
# Title: Users Information - subuid/subgid mappings
|
||||
# ID: UG_Subuid_subgid_mappings
|
||||
# Author: Carlos Polop
|
||||
# Last Update: 13-02-2026
|
||||
# Description: Show delegated user namespace ID ranges from /etc/subuid and /etc/subgid.
|
||||
# License: GNU GPL
|
||||
# Version: 1.0
|
||||
# Functions Used: print_2title
|
||||
# Global Variables: $MACPEAS
|
||||
# Initial Functions:
|
||||
# Generated Global Variables:
|
||||
# Fat linpeas: 0
|
||||
# Small linpeas: 1
|
||||
|
||||
|
||||
print_2title "User namespace mappings (subuid/subgid)"
|
||||
if [ "$MACPEAS" ]; then
|
||||
echo "Not applicable on macOS"
|
||||
else
|
||||
if [ -r /etc/subuid ]; then
|
||||
echo "subuid:"
|
||||
grep -v -E '^\s*#|^\s*$' /etc/subuid 2>/dev/null
|
||||
else
|
||||
echo "/etc/subuid not readable or not present"
|
||||
fi
|
||||
|
||||
if [ -r /etc/subgid ]; then
|
||||
echo ""
|
||||
echo "subgid:"
|
||||
grep -v -E '^\s*#|^\s*$' /etc/subgid 2>/dev/null
|
||||
else
|
||||
echo "/etc/subgid not readable or not present"
|
||||
fi
|
||||
fi
|
||||
echo ""
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
# Functions Used: echo_not_found, print_2title, print_info
|
||||
# Global Variables:$IAMROOT, $PASSWORD, $sudoB, $sudoG, $sudoVB1, $sudoVB2
|
||||
# Initial Functions:
|
||||
# Generated Global Variables:
|
||||
# Generated Global Variables: $secure_path_line
|
||||
# Fat linpeas: 0
|
||||
# Small linpeas: 1
|
||||
|
||||
@@ -19,14 +19,27 @@ print_info "https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation
|
||||
if [ "$PASSWORD" ]; then
|
||||
(echo "$PASSWORD" | timeout 1 sudo -S -l | sed "s,_proxy,${SED_RED},g" | sed "s,$sudoG,${SED_GREEN},g" | sed -${E} "s,$sudoVB1,${SED_RED_YELLOW}," | sed -${E} "s,$sudoVB2,${SED_RED_YELLOW}," | sed -${E} "s,$sudoB,${SED_RED},g") 2>/dev/null || echo_not_found "sudo"
|
||||
fi
|
||||
(sudo -n -l 2>/dev/null | sed "s,_proxy,${SED_RED},g" | sed "s,$sudoG,${SED_GREEN},g" | sed -${E} "s,$sudoVB1,${SED_RED_YELLOW}," | sed -${E} "s,$sudoVB2,${SED_RED_YELLOW}," | sed -${E} "s,$sudoB,${SED_RED},g" | sed "s,\!root,${SED_RED},") 2>/dev/null || echo "No cached sudo token (sudo -n -l)"
|
||||
|
||||
secure_path_line=$(sudo -l 2>/dev/null | grep -o "secure_path=[^,]*" | head -n 1 | cut -d= -f2)
|
||||
if [ "$secure_path_line" ]; then
|
||||
for p in $(echo "$secure_path_line" | tr ':' ' '); do
|
||||
if [ -w "$p" ]; then
|
||||
echo "Writable secure_path entry: $p" | sed -${E} "s,.*,${SED_RED},g"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
( grep -Iv "^$" cat /etc/sudoers | grep -v "#" | sed "s,_proxy,${SED_RED},g" | sed "s,$sudoG,${SED_GREEN},g" | sed -${E} "s,$sudoVB1,${SED_RED_YELLOW}," | sed -${E} "s,$sudoVB2,${SED_RED_YELLOW}," | sed -${E} "s,$sudoB,${SED_RED},g" | sed "s,pwfeedback,${SED_RED},g" ) 2>/dev/null || echo_not_found "/etc/sudoers"
|
||||
if ! [ "$IAMROOT" ] && [ -w '/etc/sudoers.d/' ]; then
|
||||
echo "You can create a file in /etc/sudoers.d/ and escalate privileges" | sed -${E} "s,.*,${SED_RED_YELLOW},"
|
||||
fi
|
||||
for f in /etc/sudoers.d/*; do
|
||||
if [ -w "$f" ]; then
|
||||
echo "Sudoers file: $f is writable and may allow privilege escalation" | sed -${E} "s,.*,${SED_RED_YELLOW},g"
|
||||
fi
|
||||
if [ -r "$f" ]; then
|
||||
echo "Sudoers file: $f is readable" | sed -${E} "s,.*,${SED_RED},g"
|
||||
grep -Iv "^$" "$f" | grep -v "#" | sed "s,_proxy,${SED_RED},g" | sed "s,$sudoG,${SED_GREEN},g" | sed -${E} "s,$sudoVB1,${SED_RED_YELLOW}," | sed -${E} "s,$sudoVB2,${SED_RED_YELLOW}," | sed -${E} "s,$sudoB,${SED_RED},g" | sed "s,pwfeedback,${SED_RED},g"
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
@@ -40,4 +40,18 @@ else
|
||||
echo "ptrace protection is enabled ($ptrace_scope)" | sed "s,is enabled,${SED_GREEN},g";
|
||||
|
||||
fi
|
||||
|
||||
if [ -d "/var/run/sudo/ts" ]; then
|
||||
echo "Sudo token directory perms:" | sed -${E} "s,.*,${SED_LIGHT_CYAN},g"
|
||||
ls -ld /var/run/sudo/ts 2>/dev/null
|
||||
if [ -w "/var/run/sudo/ts" ]; then
|
||||
echo "/var/run/sudo/ts is writable" | sed -${E} "s,.*,${SED_RED},g"
|
||||
fi
|
||||
if [ -f "/var/run/sudo/ts/$USER" ]; then
|
||||
ls -l "/var/run/sudo/ts/$USER" 2>/dev/null
|
||||
if [ -w "/var/run/sudo/ts/$USER" ]; then
|
||||
echo "User sudo token file is writable" | sed -${E} "s,.*,${SED_RED},g"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
echo ""
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
# Title: Software Information - Browser Profiles
|
||||
# ID: SW_Browser_profiles
|
||||
# Author: Carlos Polop
|
||||
# Last Update: 10-03-2025
|
||||
# Description: List browser profiles that may store credentials/cookies
|
||||
# License: GNU GPL
|
||||
# Version: 1.0
|
||||
# Functions Used: print_2title, print_3title, print_info
|
||||
# Global Variables: $HOMESEARCH, $SED_RED
|
||||
# Initial Functions:
|
||||
# Generated Global Variables: $h, $firefox_ini, $chrome_base, $profiles
|
||||
# Fat linpeas: 0
|
||||
# Small linpeas: 1
|
||||
|
||||
print_2title "Browser Profiles"
|
||||
print_info "https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/index.html#browser-data"
|
||||
|
||||
echo ""
|
||||
|
||||
for h in $HOMESEARCH; do
|
||||
[ -d "$h" ] || continue
|
||||
|
||||
firefox_ini="$h/.mozilla/firefox/profiles.ini"
|
||||
if [ -f "$firefox_ini" ]; then
|
||||
print_3title "Firefox profiles ($h)"
|
||||
awk -F= '
|
||||
/^\[Profile/ { in_profile=1 }
|
||||
/^Path=/ { path=$2 }
|
||||
/^IsRelative=/ { isrel=$2 }
|
||||
/^$/ {
|
||||
if (path != "") {
|
||||
if (isrel == "1") {
|
||||
print base "/.mozilla/firefox/" path
|
||||
} else {
|
||||
print path
|
||||
}
|
||||
}
|
||||
path=""; isrel=""
|
||||
}
|
||||
END {
|
||||
if (path != "") {
|
||||
if (isrel == "1") {
|
||||
print base "/.mozilla/firefox/" path
|
||||
} else {
|
||||
print path
|
||||
}
|
||||
}
|
||||
}
|
||||
' base="$h" "$firefox_ini" 2>/dev/null | sed -${E} "s,.*,${SED_RED},"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
for chrome_base in "$h/.config/google-chrome" "$h/.config/chromium" "$h/.config/BraveSoftware/Brave-Browser" "$h/.config/microsoft-edge" "$h/.config/microsoft-edge-beta" "$h/.config/microsoft-edge-dev"; do
|
||||
if [ -d "$chrome_base" ]; then
|
||||
profiles=$(find "$chrome_base" -maxdepth 1 -type d \( -name "Default" -o -name "Profile *" \) 2>/dev/null)
|
||||
if [ "$profiles" ]; then
|
||||
print_3title "Chromium profiles ($chrome_base)"
|
||||
printf "%s\n" "$profiles" | sed -${E} "s,.*,${SED_RED},"
|
||||
echo ""
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
done
|
||||
@@ -1,30 +0,0 @@
|
||||
# Title: Software Information - Checking leaks in git repositories
|
||||
# ID: SI_Leaks_git_repo
|
||||
# Author: Carlos Polop
|
||||
# Last Update: 22-08-2023
|
||||
# Description: Checking leaks in git repositories
|
||||
# License: GNU GPL
|
||||
# Version: 1.0
|
||||
# Functions Used: execBin, print_2title
|
||||
# Global Variables: $MACPEAS, $TIMEOUT
|
||||
# Initial Functions:
|
||||
# Generated Global Variables: $git_dirname, $FAT_LINPEAS_GITLEAKS
|
||||
# Fat linpeas: 1
|
||||
# Small linpeas: 0
|
||||
|
||||
|
||||
if ! [ "$FAST" ] && ! [ "$SUPERFAST" ] && [ "$TIMEOUT" ]; then
|
||||
print_2title "Checking leaks in git repositories"
|
||||
printf "%s\n" "$PSTORAGE_GITHUB" | while read f; do
|
||||
if echo "$f" | grep -Eq ".git$"; then
|
||||
git_dirname=$(dirname "$f")
|
||||
if [ "$MACPEAS" ]; then
|
||||
FAT_LINPEAS_GITLEAKS="peass{https://github.com/gitleaks/gitleaks/releases/download/v8.17.0/gitleaks_8.17.0_darwin_arm64.tar.gz}"
|
||||
else
|
||||
FAT_LINPEAS_GITLEAKS="peass{https://github.com/gitleaks/gitleaks/releases/download/v8.17.0/gitleaks_8.17.0_linux_x64.tar.gz}"
|
||||
fi
|
||||
execBin "GitLeaks (checking $git_dirname)" "https://github.com/zricethezav/gitleaks" "$FAT_LINPEAS_GITLEAKS" "detect -s '$git_dirname' -v | grep -E 'Description|Match|Secret|Message|Date'"
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
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
|
||||
@@ -0,0 +1,72 @@
|
||||
# Title: Software Information - PostgreSQL Event Triggers
|
||||
# ID: SI_Postgresql_Event_Triggers
|
||||
# Author: HT Bot
|
||||
# Last Update: 19-11-2025
|
||||
# Description: Detect unsafe PostgreSQL event triggers and postgres_fdw custom scripts that grant temporary SUPERUSER
|
||||
# License: GNU GPL
|
||||
# Version: 1.0
|
||||
# Functions Used: echo_not_found, print_2title, print_info
|
||||
# Global Variables: $DEBUG, $E, $SED_GREEN, $SED_RED, $SED_YELLOW, $TIMEOUT
|
||||
# Initial Functions:
|
||||
# Generated Global Variables: $psql_bin, $psql_evt_output, $psql_evt_status, $psql_evt_err_line, $postgres_fdw_dirs, $postgres_fdw_hits, $old_ifs, $evtname, $enabled, $owner, $owner_is_super, $func, $func_owner, $func_owner_is_super, $IFS
|
||||
# Fat linpeas: 0
|
||||
# Small linpeas: 1
|
||||
|
||||
|
||||
if [ "$DEBUG" ] || { [ "$TIMEOUT" ] && [ "$(command -v psql 2>/dev/null || echo -n '')" ]; }; then
|
||||
print_2title "PostgreSQL event trigger ownership & postgres_fdw hooks"
|
||||
print_info "https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/index.html#postgresql-event-triggers"
|
||||
|
||||
psql_bin="$(command -v psql 2>/dev/null || echo -n '')"
|
||||
if [ "$TIMEOUT" ] && [ "$psql_bin" ]; then
|
||||
psql_evt_output="$($TIMEOUT 5 "$psql_bin" -w -X -q -A -t -d postgres -c "WITH evt AS ( SELECT e.evtname, e.evtenabled, pg_get_userbyid(e.evtowner) AS trig_owner, tr.rolsuper AS trig_owner_super, n.nspname || '.' || p.proname AS function_name, pg_get_userbyid(p.proowner) AS func_owner, fr.rolsuper AS func_owner_super FROM pg_event_trigger e JOIN pg_proc p ON e.evtfoid = p.oid JOIN pg_namespace n ON p.pronamespace = n.oid LEFT JOIN pg_roles tr ON tr.oid = e.evtowner LEFT JOIN pg_roles fr ON fr.oid = p.proowner ) SELECT evtname || '|' || evtenabled || '|' || COALESCE(trig_owner,'?') || '|' || COALESCE(CASE WHEN trig_owner_super THEN 'yes' ELSE 'no' END,'unknown') || '|' || function_name || '|' || COALESCE(func_owner,'?') || '|' || COALESCE(CASE WHEN func_owner_super THEN 'yes' ELSE 'no' END,'unknown') FROM evt WHERE COALESCE(trig_owner_super,false) = false OR COALESCE(func_owner_super,false) = false;" 2>&1)"
|
||||
psql_evt_status=$?
|
||||
if [ $psql_evt_status -eq 0 ]; then
|
||||
if [ "$psql_evt_output" ]; then
|
||||
echo "Non-superuser-owned event triggers were found (trigger|enabled?|owner|owner_is_super|function|function_owner|fn_owner_is_super):" | sed -${E} "s,.*,${SED_RED},"
|
||||
printf "%s\n" "$psql_evt_output" | while IFS='|' read evtname enabled owner owner_is_super func func_owner func_owner_is_super; do
|
||||
case "$enabled" in
|
||||
O) enabled="enabled" ;;
|
||||
D) enabled="disabled" ;;
|
||||
*) enabled="status_$enabled" ;;
|
||||
esac
|
||||
echo " - $evtname ($enabled) uses $func owned by $func_owner (superuser:$func_owner_is_super); trigger owner: $owner (superuser:$owner_is_super)" | sed -${E} "s,superuser:no,${SED_RED},g"
|
||||
done
|
||||
else
|
||||
echo "No event triggers owned by non-superusers were returned." | sed -${E} "s,.*,${SED_GREEN},"
|
||||
fi
|
||||
else
|
||||
psql_evt_err_line=$(printf '%s\n' "$psql_evt_output" | head -n1)
|
||||
echo "Could not query pg_event_trigger (psql exit $psql_evt_status): $psql_evt_err_line" | sed -${E} "s,.*,${SED_YELLOW},"
|
||||
fi
|
||||
else
|
||||
if ! [ "$TIMEOUT" ]; then
|
||||
echo_not_found "timeout"
|
||||
fi
|
||||
if ! [ "$psql_bin" ]; then
|
||||
echo_not_found "psql"
|
||||
fi
|
||||
fi
|
||||
|
||||
postgres_fdw_dirs="/etc/postgresql /var/lib/postgresql /var/lib/postgres /usr/lib/postgresql /usr/local/lib/postgresql /opt/supabase /opt/postgres /srv/postgres"
|
||||
postgres_fdw_hits=""
|
||||
for d in $postgres_fdw_dirs; do
|
||||
if [ -d "$d" ]; then
|
||||
old_ifs="$IFS"
|
||||
IFS="\n"
|
||||
for f in $(find "$d" -maxdepth 5 -type f \( -name '*postgres_fdw*.sql' -o -name '*postgres_fdw*.psql' -o -name 'after-create.sql' \) 2>/dev/null); do
|
||||
if [ -f "$f" ] && grep -qiE "alter[[:space:]]+role[[:space:]]+postgres[[:space:]]+superuser" "$f" 2>/dev/null; then
|
||||
postgres_fdw_hits="$postgres_fdw_hits\n$f"
|
||||
fi
|
||||
done
|
||||
IFS="$old_ifs"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$postgres_fdw_hits" ]; then
|
||||
echo "Detected postgres_fdw custom scripts granting postgres SUPERUSER (check for SupaPwn-style window):" | sed -${E} "s,.*,${SED_RED},"
|
||||
printf "%s\n" "$postgres_fdw_hits" | sed "s,^, - ,"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
@@ -8,12 +8,12 @@
|
||||
# Functions Used: print_2title, print_info
|
||||
# Global Variables:$DEBUG, $SEARCH_IN_FOLDER, $USER, $wgroups
|
||||
# Initial Functions:
|
||||
# Generated Global Variables: $screensess, $screensess2
|
||||
# Generated Global Variables: $screensess, $screensess2, $uscreen
|
||||
# Fat linpeas: 0
|
||||
# Small linpeas: 1
|
||||
|
||||
|
||||
if ([ "$screensess" ] || [ "$screensess2" ] || [ "$DEBUG" ]) && ! [ "$SEARCH_IN_FOLDER" ]; then
|
||||
if (command -v screen >/dev/null 2>&1 || [ -d "/run/screen" ] || [ "$DEBUG" ]) && ! [ "$SEARCH_IN_FOLDER" ]; then
|
||||
print_2title "Searching screen sessions"
|
||||
print_info "https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/index.html#open-shell-sessions"
|
||||
screensess=$(screen -ls 2>/dev/null)
|
||||
@@ -25,5 +25,16 @@ if ([ "$screensess" ] || [ "$screensess2" ] || [ "$DEBUG" ]) && ! [ "$SEARCH_IN_
|
||||
find /run/screen -type s -path "/run/screen/S-*" -not -user $USER '(' '(' -perm -o=w ')' -or '(' -perm -g=w -and '(' $wgroups ')' ')' ')' 2>/dev/null | while read f; do
|
||||
echo "Other user screen socket is writable: $f" | sed "s,$f,${SED_RED_YELLOW},"
|
||||
done
|
||||
|
||||
if [ -r "/etc/passwd" ]; then
|
||||
print_3title "Checking other users screen sessions"
|
||||
cut -d: -f1,7 /etc/passwd 2>/dev/null | grep "sh$" | cut -d: -f1 | grep -v "^$USER$" | while read u; do
|
||||
uscreen=$(screen -ls "${u}/" 2>/dev/null | grep -v "No Sockets found" | grep -v "^$")
|
||||
if [ "$uscreen" ]; then
|
||||
echo "User $u screen sessions:"
|
||||
printf "%s\n" "$uscreen" | sed -${E} "s,.*,${SED_RED},"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
# Functions Used: print_2title, print_3title
|
||||
# Global Variables: $HOME, $HOMESEARCH, $ROOT_FOLDER, $SEARCH_IN_FOLDER, $TIMEOUT, $USER, $wgroups
|
||||
# Initial Functions:
|
||||
# Generated Global Variables: $certsb4_grep, $hostsallow, $hostsdenied, $sshconfig, $writable_agents, $privatekeyfilesetc, $privatekeyfileshome, $privatekeyfilesroot, $privatekeyfilesmnt,
|
||||
# Generated Global Variables: $certsb4_grep, $hostsallow, $hostsdenied, $sshconfig, $writable_agents, $agent_sockets, $privatekeyfilesetc, $privatekeyfileshome, $privatekeyfilesroot, $privatekeyfilesmnt,
|
||||
# Fat linpeas: 0
|
||||
# Small linpeas: 1
|
||||
|
||||
@@ -19,31 +19,37 @@ if ! [ "$SEARCH_IN_FOLDER" ]; then
|
||||
sshconfig="$(ls /etc/ssh/ssh_config 2>/dev/null)"
|
||||
hostsdenied="$(ls /etc/hosts.denied 2>/dev/null)"
|
||||
hostsallow="$(ls /etc/hosts.allow 2>/dev/null)"
|
||||
writable_agents=$(find /tmp /etc /home -type s -name "agent.*" -or -name "*gpg-agent*" '(' '(' -user $USER ')' -or '(' -perm -o=w ')' -or '(' -perm -g=w -and '(' $wgroups ')' ')' ')' 2>/dev/null)
|
||||
agent_sockets=$(find /run/user /tmp -type s \( -path "/run/user/*/ssh-*/agent.*" -o -name "ssh-agent.sock" -o -path "/tmp/ssh-*" \) 2>/dev/null)
|
||||
writable_agents=$(find /tmp /etc /home /run/user \
|
||||
\( -type s -a \( -name "agent.*" -o -name "ssh-agent.sock" -o -path "*/ssh-*/agent.*" -o -name "*gpg-agent*" \) \
|
||||
-a \( \( -user "$USER" \) -o \( -perm -o=w \) -o \( -perm -g=w -a \( $wgroups \) \) \) \) 2>/dev/null)
|
||||
else
|
||||
sshconfig="$(ls ${ROOT_FOLDER}etc/ssh/ssh_config 2>/dev/null)"
|
||||
hostsdenied="$(ls ${ROOT_FOLDER}etc/hosts.denied 2>/dev/null)"
|
||||
hostsallow="$(ls ${ROOT_FOLDER}etc/hosts.allow 2>/dev/null)"
|
||||
writable_agents=$(find ${ROOT_FOLDER} -type s -name "agent.*" -or -name "*gpg-agent*" '(' '(' -user $USER ')' -or '(' -perm -o=w ')' -or '(' -perm -g=w -and '(' $wgroups ')' ')' ')' 2>/dev/null)
|
||||
agent_sockets=$(find "${ROOT_FOLDER}"tmp "${ROOT_FOLDER}"run -type s \( -name "agent.*" -o -name "ssh-agent.sock" \) 2>/dev/null)
|
||||
writable_agents=$(find "${ROOT_FOLDER}" \
|
||||
\( -type s -a \( -name "agent.*" -o -name "ssh-agent.sock" -o -path "*/ssh-*/agent.*" -o -name "*gpg-agent*" \) \
|
||||
-a \( \( -user "$USER" \) -o \( -perm -o=w \) -o \( -perm -g=w -a \( $wgroups \) \) \) \) 2>/dev/null)
|
||||
fi
|
||||
|
||||
peass{SSH}
|
||||
|
||||
grep "PermitRootLogin \|ChallengeResponseAuthentication \|PasswordAuthentication \|UsePAM \|Port\|PermitEmptyPasswords\|PubkeyAuthentication\|ListenAddress\|ForwardAgent\|AllowAgentForwarding\|AuthorizedKeysFiles" /etc/ssh/sshd_config 2>/dev/null | grep -v "#" | sed -${E} "s,PermitRootLogin.*es|PermitEmptyPasswords.*es|ChallengeResponseAuthentication.*es|FordwardAgent.*es,${SED_RED},"
|
||||
grep "PermitRootLogin \|ChallengeResponseAuthentication \|PasswordAuthentication \|UsePAM \|Port\|PermitEmptyPasswords\|PubkeyAuthentication\|ListenAddress\|ForwardAgent\|AllowAgentForwarding\|AuthorizedKeysFile" /etc/ssh/sshd_config 2>/dev/null | grep -v "#" | sed -${E} "s,PermitRootLogin.*es|PermitEmptyPasswords.*es|ChallengeResponseAuthentication.*es|FordwardAgent.*es,${SED_RED},"
|
||||
|
||||
if ! [ "$SEARCH_IN_FOLDER" ]; then
|
||||
if [ "$TIMEOUT" ]; then
|
||||
privatekeyfilesetc=$(timeout 40 grep -rl '\-\-\-\-\-BEGIN .* PRIVATE KEY.*\-\-\-\-\-' /etc 2>/dev/null)
|
||||
privatekeyfileshome=$(timeout 40 grep -rl '\-\-\-\-\-BEGIN .* PRIVATE KEY.*\-\-\-\-\-' $HOMESEARCH 2>/dev/null)
|
||||
privatekeyfilesroot=$(timeout 40 grep -rl '\-\-\-\-\-BEGIN .* PRIVATE KEY.*\-\-\-\-\-' /root 2>/dev/null)
|
||||
privatekeyfilesmnt=$(timeout 40 grep -rl '\-\-\-\-\-BEGIN .* PRIVATE KEY.*\-\-\-\-\-' /mnt 2>/dev/null)
|
||||
privatekeyfilesetc=$(timeout 40 grep -rl '\-\-\-\-\-BEGIN .* PRIVATE KEY\-\-\-\-\-' /etc 2>/dev/null)
|
||||
privatekeyfileshome=$(timeout 40 grep -rl '\-\-\-\-\-BEGIN .* PRIVATE KEY\-\-\-\-\-' $HOMESEARCH 2>/dev/null)
|
||||
privatekeyfilesroot=$(timeout 40 grep -rl '\-\-\-\-\-BEGIN .* PRIVATE KEY\-\-\-\-\-' /root 2>/dev/null)
|
||||
privatekeyfilesmnt=$(timeout 40 grep -rl '\-\-\-\-\-BEGIN .* PRIVATE KEY\-\-\-\-\-' /mnt 2>/dev/null)
|
||||
else
|
||||
privatekeyfilesetc=$(grep -rl '\-\-\-\-\-BEGIN .* PRIVATE KEY.*\-\-\-\-\-' /etc 2>/dev/null) #If there is tons of files linpeas gets frozen here without a timeout
|
||||
privatekeyfileshome=$(grep -rl '\-\-\-\-\-BEGIN .* PRIVATE KEY.*\-\-\-\-\-' $HOME/.ssh 2>/dev/null)
|
||||
privatekeyfilesetc=$(grep -rl '\-\-\-\-\-BEGIN .* PRIVATE KEY\-\-\-\-\-' /etc 2>/dev/null) #If there is tons of files linpeas gets frozen here without a timeout
|
||||
privatekeyfileshome=$(grep -rl '\-\-\-\-\-BEGIN .* PRIVATE KEY\-\-\-\-\-' $HOME/.ssh 2>/dev/null)
|
||||
fi
|
||||
else
|
||||
# If $SEARCH_IN_FOLDER lets just search for private keys in the whole firmware
|
||||
privatekeyfilesetc=$(timeout 120 grep -rl '\-\-\-\-\-BEGIN .* PRIVATE KEY.*\-\-\-\-\-' "$ROOT_FOLDER" 2>/dev/null)
|
||||
privatekeyfilesetc=$(timeout 120 grep -rl '\-\-\-\-\-BEGIN .* PRIVATE KEY\-\-\-\-\-' "$ROOT_FOLDER" 2>/dev/null)
|
||||
fi
|
||||
|
||||
if [ "$privatekeyfilesetc" ] || [ "$privatekeyfileshome" ] || [ "$privatekeyfilesroot" ] || [ "$privatekeyfilesmnt" ] ; then
|
||||
@@ -58,7 +64,7 @@ fi
|
||||
if [ "$certsb4_grep" ] || [ "$PSTORAGE_CERTSBIN" ]; then
|
||||
print_3title "Some certificates were found (out limited):"
|
||||
printf "$certsb4_grep\n" | head -n 20
|
||||
printf "$$PSTORAGE_CERTSBIN\n" | head -n 20
|
||||
printf "$PSTORAGE_CERTSBIN\n" | head -n 20
|
||||
echo ""
|
||||
fi
|
||||
if [ "$PSTORAGE_CERTSCLIENT" ]; then
|
||||
@@ -71,6 +77,11 @@ if [ "$PSTORAGE_SSH_AGENTS" ]; then
|
||||
printf "$PSTORAGE_SSH_AGENTS\n"
|
||||
echo ""
|
||||
fi
|
||||
if [ "$agent_sockets" ]; then
|
||||
print_3title "Potential SSH agent sockets were found:"
|
||||
printf "%s\n" "$agent_sockets" | sed -${E} "s,.*,${SED_RED},"
|
||||
echo ""
|
||||
fi
|
||||
if ssh-add -l 2>/dev/null | grep -qv 'no identities'; then
|
||||
print_3title "Listing SSH Agents"
|
||||
ssh-add -l
|
||||
|
||||
@@ -17,7 +17,7 @@ if ! [ "$IAMROOT" ]; then
|
||||
print_2title "Interesting writable files owned by me or writable by everyone (not in Home) (max 200)"
|
||||
print_info "https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/index.html#writable-files"
|
||||
#In the next file, you need to specify type "d" and "f" to avoid fake link files apparently writable by all
|
||||
obmowbe=$(find $ROOT_FOLDER '(' -type f -or -type d ')' '(' '(' -user $USER ')' -or '(' -perm -o=w ')' ')' ! -path "/proc/*" ! -path "/sys/*" ! -path "$HOME/*" 2>/dev/null | grep -Ev "$notExtensions" | sort | uniq | awk -F/ '{line_init=$0; if (!cont){ cont=0 }; $NF=""; act=$0; if (act == pre){(cont += 1)} else {cont=0}; if (cont < 5){ print line_init; } if (cont == "5"){print "#)You_can_write_even_more_files_inside_last_directory\n"}; pre=act }' | head -n 200)
|
||||
obmowbe=$(find $ROOT_FOLDER '(' -type f -or -type d ')' '(' '(' -user $USER ')' -or '(' -perm -o=w ')' ')' ! -path "/proc/*" ! -path "/sys/*" ! -path "/dev/*" ! -path "/snap/*" ! -path "$HOME/*" 2>/dev/null | grep -Ev "$notExtensions" | sort | uniq | awk -F/ '{line_init=$0; if (!cont){ cont=0 }; $NF=""; act=$0; if (act == pre){(cont += 1)} else {cont=0}; if (cont < 5){ print line_init; } if (cont == "5"){print "#)You_can_write_even_more_files_inside_last_directory\n"}; pre=act }' | head -n 200)
|
||||
printf "%s\n" "$obmowbe" | while read l; do
|
||||
if echo "$l" | grep -q "You_can_write_even_more_files_inside_last_directory"; then printf $ITALIC"$l\n"$NC;
|
||||
elif echo "$l" | grep -qE "$writeVB"; then
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
# Title: Interesting Permissions Files - IGEL OS SUID setup/date abuse
|
||||
# ID: IP_IGEL_OS_SUID
|
||||
# Author: HT Bot
|
||||
# Last Update: 29-11-2025
|
||||
# Description: Detect IGEL OS environments that expose the SUID-root `setup`/`date` binaries and highlight writable NetworkManager/systemd configs that enable the documented privilege escalation chain (Metasploit linux/local/igel_network_priv_esc).
|
||||
# License: GNU GPL
|
||||
# Version: 1.0
|
||||
# Functions Used: print_2title, print_info
|
||||
# Global Variables: $ITALIC, $NC, $SED_GREEN, $SED_RED, $SED_RED_YELLOW, $SUPERFAST
|
||||
# Initial Functions:
|
||||
# Generated Global Variables: $igel_markers, $igel_marker_sources, $marker, $igel_suid_hits, $candidate, $writable_nm, $writable_systemd, $unitdir, $tmp_units
|
||||
# Fat linpeas: 0
|
||||
# Small linpeas: 1
|
||||
|
||||
igel_markers=""
|
||||
igel_marker_sources=""
|
||||
if [ -f /etc/os-release ] && grep -qi "igel" /etc/os-release 2>/dev/null; then
|
||||
igel_markers="Yes"
|
||||
igel_marker_sources="/etc/os-release"
|
||||
fi
|
||||
if [ -f /etc/issue ] && grep -qi "igel" /etc/issue 2>/dev/null; then
|
||||
igel_markers="Yes"
|
||||
igel_marker_sources="${igel_marker_sources} /etc/issue"
|
||||
fi
|
||||
for marker in /etc/igel /wfs/igel /userhome/.igel /config/sessions/igel; do
|
||||
if [ -e "$marker" ]; then
|
||||
igel_markers="Yes"
|
||||
igel_marker_sources="${igel_marker_sources} $marker"
|
||||
fi
|
||||
done
|
||||
|
||||
igel_suid_hits=""
|
||||
for candidate in /usr/bin/setup /bin/setup /usr/sbin/setup /opt/igel/bin/setup /usr/bin/date /bin/date /usr/lib/igel/date; do
|
||||
if [ -u "$candidate" ]; then
|
||||
igel_suid_hits="${igel_suid_hits}$(ls -lah "$candidate" 2>/dev/null)\n"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "$igel_markers" ] || [ -n "$igel_suid_hits" ]; then
|
||||
print_2title "IGEL OS SUID setup/date privilege escalation surface"
|
||||
print_info "https://www.rapid7.com/blog/post/pt-metasploit-wrap-up-11-28-2025"
|
||||
if [ -n "$igel_markers" ]; then
|
||||
echo "Potential IGEL OS detected via: $igel_marker_sources" | sed -${E} "s,.*,${SED_GREEN},"
|
||||
else
|
||||
echo "IGEL-specific SUID helpers found but IGEL markers were not detected" | sed -${E} "s,.*,${SED_RED},"
|
||||
fi
|
||||
if [ -n "$igel_suid_hits" ]; then
|
||||
echo "SUID-root helpers exposing configuration primitives:" | sed -${E} "s,.*,${SED_RED_YELLOW},"
|
||||
printf "%b" "$igel_suid_hits"
|
||||
else
|
||||
echo "No SUID setup/date binaries were located (system may be patched)."
|
||||
fi
|
||||
|
||||
writable_nm=""
|
||||
writable_systemd=""
|
||||
if ! [ "$SUPERFAST" ]; then
|
||||
if [ -d /etc/NetworkManager ]; then
|
||||
writable_nm=$(find /etc/NetworkManager -maxdepth 3 -type f -writable 2>/dev/null | head -n 25)
|
||||
fi
|
||||
for unitdir in /etc/systemd/system /lib/systemd/system /usr/lib/systemd/system; do
|
||||
if [ -d "$unitdir" ]; then
|
||||
tmp_units=$(find "$unitdir" -maxdepth 2 -type f -writable 2>/dev/null | head -n 15)
|
||||
if [ -n "$tmp_units" ]; then
|
||||
writable_systemd="${writable_systemd}${tmp_units}\n"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [ -n "$writable_nm" ]; then
|
||||
echo "Writable NetworkManager profiles/hooks (swap Exec path to your payload):" | sed -${E} "s,.*,${SED_RED_YELLOW},"
|
||||
echo "$writable_nm"
|
||||
fi
|
||||
if [ -n "$writable_systemd" ]; then
|
||||
echo "Writable systemd unit files (edit ExecStart, then restart via setup/date):" | sed -${E} "s,.*,${SED_RED_YELLOW},"
|
||||
printf "%b" "$writable_systemd"
|
||||
fi
|
||||
printf "$ITALIC Known exploitation chain: Use the SUID setup/date binaries to edit NetworkManager or systemd configs so ExecStart points to your payload, then trigger a service restart via the same helper to run as root (Metasploit linux/local/igel_network_priv_esc).$NC\n"
|
||||
fi
|
||||
echo ""
|
||||
@@ -0,0 +1,36 @@
|
||||
# Title: Interesting Permissions Files - Writable root-owned executables
|
||||
# ID: IP_Writable_root_execs
|
||||
# Author: HT Bot
|
||||
# Last Update: 29-11-2025
|
||||
# Description: Locate root-owned executables outside home folders that the current user can modify
|
||||
# License: GNU GPL
|
||||
# Version: 1.0
|
||||
# Functions Used: print_2title, print_info, echo_not_found
|
||||
# Global Variables: $DEBUG, $IAMROOT, $ROOT_FOLDER, $HOME, $writeVB
|
||||
# Initial Functions:
|
||||
# Generated Global Variables: $writable_root_execs
|
||||
# Fat linpeas: 0
|
||||
# Small linpeas: 1
|
||||
|
||||
if ! [ "$IAMROOT" ]; then
|
||||
print_2title "Writable root-owned executables I can modify (max 200)"
|
||||
print_info "https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/index.html#writable-files"
|
||||
|
||||
writable_root_execs=$(
|
||||
find "$ROOT_FOLDER" -type f -user root -perm -u=x \
|
||||
\( -perm -g=w -o -perm -o=w \) \
|
||||
! -path "/proc/*" ! -path "/sys/*" ! -path "/run/*" ! -path "/dev/*" ! -path "/snap/*" ! -path "$HOME/*" 2>/dev/null \
|
||||
| while IFS= read -r f; do
|
||||
if [ -w "$f" ]; then
|
||||
ls -l "$f" 2>/dev/null
|
||||
fi
|
||||
done | head -n 200
|
||||
)
|
||||
|
||||
if [ "$writable_root_execs" ] || [ "$DEBUG" ]; then
|
||||
printf "%s\n" "$writable_root_execs" | sed -${E} "s,$writeVB,${SED_RED_YELLOW},"
|
||||
else
|
||||
echo_not_found "Writable root-owned executables"
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
@@ -23,6 +23,7 @@ if ! [ "$STRACE" ]; then
|
||||
fi
|
||||
suids_files=$(find $ROOT_FOLDER -perm -4000 -type f ! -path "/dev/*" 2>/dev/null)
|
||||
printf "%s\n" "$suids_files" | while read s; do
|
||||
[ -z "$s" ] && continue
|
||||
s=$(ls -lahtr "$s")
|
||||
#If starts like "total 332K" then no SUID bin was found and xargs just executed "ls" in the current folder
|
||||
if echo "$s" | grep -qE "^total"; then break; fi
|
||||
@@ -37,14 +38,14 @@ printf "%s\n" "$suids_files" | while read s; do
|
||||
else
|
||||
c="a"
|
||||
for b in $sidB; do
|
||||
if echo $s | grep -q $(echo $b | cut -d % -f 1); then
|
||||
if echo "$sname" | grep -q $(echo $b | cut -d % -f 1); then
|
||||
echo "$s" | sed -${E} "s,$(echo $b | cut -d % -f 1),${C}[1;31m& ---> $(echo $b | cut -d % -f 2)${C}[0m,"
|
||||
c=""
|
||||
break;
|
||||
fi
|
||||
done;
|
||||
if [ "$c" ]; then
|
||||
if echo "$s" | grep -qE "$sidG1" || echo "$s" | grep -qE "$sidG2" || echo "$s" | grep -qE "$sidG3" || echo "$s" | grep -qE "$sidG4" || echo "$s" | grep -qE "$sidVB" || echo "$s" | grep -qE "$sidVB2"; then
|
||||
if echo "$sname" | grep -qE "$sidG1" || echo "$sname" | grep -qE "$sidG2" || echo "$sname" | grep -qE "$sidG3" || echo "$sname" | grep -qE "$sidG4" || echo "$sname" | grep -qE "$sidVB" || echo "$sname" | grep -qE "$sidVB2"; then
|
||||
echo "$s" | sed -${E} "s,$sidG1,${SED_GREEN}," | sed -${E} "s,$sidG2,${SED_GREEN}," | sed -${E} "s,$sidG3,${SED_GREEN}," | sed -${E} "s,$sidG4,${SED_GREEN}," | sed -${E} "s,$sidVB,${SED_RED_YELLOW}," | sed -${E} "s,$sidVB2,${SED_RED_YELLOW},"
|
||||
else
|
||||
echo "$s (Unknown SUID binary!)" | sed -${E} "s,/.*,${SED_RED},"
|
||||
@@ -59,6 +60,8 @@ printf "%s\n" "$suids_files" | while read s; do
|
||||
if [ -O "$sline_first" ] || [ -w "$sline_first" ]; then #And modifiable
|
||||
printf "$ITALIC --- It looks like $RED$sname$NC$ITALIC is using $RED$sline_first$NC$ITALIC and you can modify it (strings line: $sline) (https://tinyurl.com/suidpath)\n"
|
||||
fi
|
||||
elif echo "$sline_first" | grep -q "/" && [ -d "$(dirname "$sline_first")" ] && [ -w "$(dirname "$sline_first")" ]; then #If path does not exist but can be created
|
||||
printf "$ITALIC --- It looks like $RED$sname$NC$ITALIC is using $RED$sline_first$NC$ITALIC and you can create it inside writable dir $RED$(dirname "$sline_first")$NC$ITALIC (strings line: $sline) (https://tinyurl.com/suidpath)\n"
|
||||
else #If not a path
|
||||
if [ ${#sline_first} -gt 2 ] && command -v "$sline_first" 2>/dev/null | grep -q '/' && echo "$sline_first" | grep -Eqv "\.\."; then #Check if existing binary
|
||||
printf "$ITALIC --- It looks like $RED$sname$NC$ITALIC is executing $RED$sline_first$NC$ITALIC and you can impersonate it (strings line: $sline) (https://tinyurl.com/suidpath)\n"
|
||||
@@ -96,4 +99,4 @@ printf "%s\n" "$suids_files" | while read s; do
|
||||
fi
|
||||
fi
|
||||
done;
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
@@ -17,6 +17,7 @@ print_2title "SGID"
|
||||
print_info "https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/index.html#sudo-and-suid"
|
||||
sgids_files=$(find $ROOT_FOLDER -perm -2000 -type f ! -path "/dev/*" 2>/dev/null)
|
||||
printf "%s\n" "$sgids_files" | while read s; do
|
||||
[ -z "$s" ] && continue
|
||||
s=$(ls -lahtr "$s")
|
||||
#If starts like "total 332K" then no SUID bin was found and xargs just executed "ls" in the current folder
|
||||
if echo "$s" | grep -qE "^total";then break; fi
|
||||
@@ -53,6 +54,8 @@ printf "%s\n" "$sgids_files" | while read s; do
|
||||
if [ -O "$sline_first" ] || [ -w "$sline_first" ]; then #And modifiable
|
||||
printf "$ITALIC --- It looks like $RED$sname$NC$ITALIC is using $RED$sline_first$NC$ITALIC and you can modify it (strings line: $sline)\n"
|
||||
fi
|
||||
elif echo "$sline_first" | grep -q "/" && [ -d "$(dirname "$sline_first")" ] && [ -w "$(dirname "$sline_first")" ]; then #If path does not exist but can be created
|
||||
printf "$ITALIC --- It looks like $RED$sname$NC$ITALIC is using $RED$sline_first$NC$ITALIC and you can create it inside writable dir $RED$(dirname "$sline_first")$NC$ITALIC (strings line: $sline)\n"
|
||||
else #If not a path
|
||||
if [ ${#sline_first} -gt 2 ] && command -v "$sline_first" 2>/dev/null | grep -q '/'; then #Check if existing binary
|
||||
printf "$ITALIC --- It looks like $RED$sname$NC$ITALIC is executing $RED$sline_first$NC$ITALIC and you can impersonate it (strings line: $sline)\n"
|
||||
@@ -90,4 +93,4 @@ printf "%s\n" "$sgids_files" | while read s; do
|
||||
fi
|
||||
fi
|
||||
done;
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# License: GNU GPL
|
||||
# Version: 1.0
|
||||
# Functions Used: echo_not_found, print_2title, print_info
|
||||
# Global Variables: $HOMESEARCH, $knw_usrs, $MACPEAS, $nosh_usrs, $SEARCH_IN_FOLDER, $sh_usrs, $USER
|
||||
# Global Variables: $HOMESEARCH, $knw_usrs, $MACPEAS, $nosh_usrs, $SEARCH_IN_FOLDER, $sh_usrs, $USER, $writeB, $writeVB
|
||||
# Initial Functions:
|
||||
# Generated Global Variables:
|
||||
# Fat linpeas: 0
|
||||
@@ -16,12 +16,12 @@
|
||||
print_2title "Files with ACLs (limited to 50)"
|
||||
print_info "https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/index.html#acls"
|
||||
if ! [ "$SEARCH_IN_FOLDER" ]; then
|
||||
( (getfacl -t -s -R -p /bin /etc $HOMESEARCH /opt /sbin /usr /tmp /root 2>/dev/null) || echo_not_found "files with acls in searched folders" ) | head -n 70 | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed -${E} "s,$knw_usrs,${SED_GREEN}," | sed "s,$USER,${SED_RED},"
|
||||
( (getfacl -t -s -R -p /bin /etc $HOMESEARCH /opt /sbin /usr /tmp /root 2>/dev/null) || echo_not_found "files with acls in searched folders" ) | head -n 70 | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed -${E} "s,$knw_usrs,${SED_GREEN}," | sed "s,$USER,${SED_RED}," | sed -${E} "s,$writeVB,${SED_RED_YELLOW},g" | sed -${E} "s,$writeB,${SED_RED},g"
|
||||
else
|
||||
( (getfacl -t -s -R -p $SEARCH_IN_FOLDER 2>/dev/null) || echo_not_found "files with acls in searched folders" ) | head -n 70 | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed -${E} "s,$knw_usrs,${SED_GREEN}," | sed "s,$USER,${SED_RED},"
|
||||
( (getfacl -t -s -R -p $SEARCH_IN_FOLDER 2>/dev/null) || echo_not_found "files with acls in searched folders" ) | head -n 70 | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed -${E} "s,$knw_usrs,${SED_GREEN}," | sed "s,$USER,${SED_RED}," | sed -${E} "s,$writeVB,${SED_RED_YELLOW},g" | sed -${E} "s,$writeB,${SED_RED},g"
|
||||
fi
|
||||
|
||||
if [ "$MACPEAS" ] && ! [ "$FAST" ] && ! [ "$SUPERFAST" ] && ! [ "$(command -v getfacl || echo -n '')" ]; then #Find ACL files in macos (veeeery slow)
|
||||
ls -RAle / 2>/dev/null | grep -v "group:everyone deny delete" | grep -E -B1 "\d: " | head -n 70 | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed -${E} "s,$knw_usrs,${SED_GREEN}," | sed "s,$USER,${SED_RED},"
|
||||
ls -RAle / 2>/dev/null | grep -v "group:everyone deny delete" | grep -E -B1 "\d: " | head -n 70 | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed -${E} "s,$knw_usrs,${SED_GREEN}," | sed "s,$USER,${SED_RED}," | sed -${E} "s,$writeVB,${SED_RED_YELLOW},g" | sed -${E} "s,$writeB,${SED_RED},g"
|
||||
fi
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
# Functions Used: echo_not_found, print_2title, print_info, print_3title
|
||||
# Global Variables: $capsB, $capsVB, $IAMROOT, $SEARCH_IN_FOLDER
|
||||
# Initial Functions:
|
||||
# Generated Global Variables: $cap_name, $cap_value, $cap_line, $capVB, $capname, $capbins, $capsVB_vuln
|
||||
# Generated Global Variables: $cap_name, $cap_value, $cap_line, $capVB, $capname, $capbins, $capsVB_vuln, $proc_status, $proc_pid, $proc_name, $proc_uid, $user_name, $proc_inh, $proc_prm, $proc_eff, $proc_bnd, $proc_amb, $proc_inh_dec, $proc_prm_dec, $proc_eff_dec, $proc_bnd_dec, $proc_amb_dec
|
||||
# Fat linpeas: 0
|
||||
# Small linpeas: 1
|
||||
|
||||
@@ -69,6 +69,40 @@ if ! [ "$SEARCH_IN_FOLDER" ]; then
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
|
||||
print_3title "Processes with capability sets (non-zero CapEff/CapAmb, limit 40)"
|
||||
find /proc -maxdepth 2 -path "/proc/[0-9]*/status" 2>/dev/null | head -n 400 | while read -r proc_status; do
|
||||
proc_pid=$(echo "$proc_status" | cut -d/ -f3)
|
||||
proc_name=$(awk '/^Name:/{print $2}' "$proc_status" 2>/dev/null)
|
||||
proc_uid=$(awk '/^Uid:/{print $2}' "$proc_status" 2>/dev/null)
|
||||
user_name=$(awk -F: -v uid="$proc_uid" '$3==uid{print $1; exit}' /etc/passwd 2>/dev/null)
|
||||
[ -z "$user_name" ] && user_name="$proc_uid"
|
||||
|
||||
proc_inh=$(awk '/^CapInh:/{print $2}' "$proc_status" 2>/dev/null)
|
||||
proc_prm=$(awk '/^CapPrm:/{print $2}' "$proc_status" 2>/dev/null)
|
||||
proc_eff=$(awk '/^CapEff:/{print $2}' "$proc_status" 2>/dev/null)
|
||||
proc_bnd=$(awk '/^CapBnd:/{print $2}' "$proc_status" 2>/dev/null)
|
||||
proc_amb=$(awk '/^CapAmb:/{print $2}' "$proc_status" 2>/dev/null)
|
||||
|
||||
[ -z "$proc_eff" ] && continue
|
||||
if [ "$proc_eff" != "0000000000000000" ] || [ "$proc_amb" != "0000000000000000" ]; then
|
||||
echo "PID $proc_pid ($proc_name) user=$user_name"
|
||||
|
||||
proc_inh_dec=$(capsh --decode=0x"$proc_inh" 2>/dev/null)
|
||||
proc_prm_dec=$(capsh --decode=0x"$proc_prm" 2>/dev/null)
|
||||
proc_eff_dec=$(capsh --decode=0x"$proc_eff" 2>/dev/null)
|
||||
proc_bnd_dec=$(capsh --decode=0x"$proc_bnd" 2>/dev/null)
|
||||
proc_amb_dec=$(capsh --decode=0x"$proc_amb" 2>/dev/null)
|
||||
|
||||
echo " CapInh: $proc_inh_dec" | sed -${E} "s,$capsB,${SED_RED},g"
|
||||
echo " CapPrm: $proc_prm_dec" | sed -${E} "s,$capsB,${SED_RED},g"
|
||||
echo " CapEff: $proc_eff_dec" | sed -${E} "s,$capsB,${SED_RED_YELLOW},g"
|
||||
echo " CapBnd: $proc_bnd_dec" | sed -${E} "s,$capsB,${SED_RED},g"
|
||||
echo " CapAmb: $proc_amb_dec" | sed -${E} "s,$capsB,${SED_RED_YELLOW},g"
|
||||
echo ""
|
||||
fi
|
||||
done | head -n 240
|
||||
echo ""
|
||||
|
||||
else
|
||||
print_3title "Current shell capabilities"
|
||||
|
||||
@@ -6,19 +6,27 @@
|
||||
# License: GNU GPL
|
||||
# Version: 1.0
|
||||
# Functions Used: echo_not_found, print_2title, print_info
|
||||
# Global Variables: $DEBUG, $knw_usrs, $nosh_usrs, $sh_usrs, $USER
|
||||
# Global Variables: $capsB, $DEBUG, $knw_usrs, $nosh_usrs, $sh_usrs, $USER
|
||||
# Initial Functions:
|
||||
# Generated Global Variables:
|
||||
# Generated Global Variables: $pam_cap_lines
|
||||
# Fat linpeas: 0
|
||||
# Small linpeas: 0
|
||||
|
||||
|
||||
if [ -f "/etc/security/capability.conf" ] || [ "$DEBUG" ]; then
|
||||
if [ -f "/etc/security/capability.conf" ] || [ "$DEBUG" ] || grep -Rqs "pam_cap\.so" /etc/pam.d /etc/pam.conf 2>/dev/null; then
|
||||
print_2title "Users with capabilities"
|
||||
print_info "https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/index.html#capabilities"
|
||||
if [ -f "/etc/security/capability.conf" ]; then
|
||||
grep -v '^#\|none\|^$' /etc/security/capability.conf 2>/dev/null | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed -${E} "s,$knw_usrs,${SED_GREEN}," | sed "s,$USER,${SED_RED},"
|
||||
grep -v '^#\|none\|^$' /etc/security/capability.conf 2>/dev/null | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed -${E} "s,$nosh_usrs,${SED_BLUE}," | sed -${E} "s,$knw_usrs,${SED_GREEN}," | sed "s,$USER,${SED_RED}," | sed -${E} "s,$capsB,${SED_RED},g"
|
||||
else echo_not_found "/etc/security/capability.conf"
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
print_info "Checking if PAM loads pam_cap.so"
|
||||
pam_cap_lines=$(grep -RIn "pam_cap\.so" /etc/pam.d /etc/pam.conf 2>/dev/null)
|
||||
if [ "$pam_cap_lines" ]; then
|
||||
printf "%s\n" "$pam_cap_lines" | sed -${E} "s,pam_cap\\.so,${SED_RED_YELLOW},g"
|
||||
else
|
||||
echo_not_found "pam_cap.so in /etc/pam.d or /etc/pam.conf"
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# License: GNU GPL
|
||||
# Version: 1.0
|
||||
# Functions Used: print_2title, print_info
|
||||
# Global Variables: $IAMROOT, $ITALIC, $SEARCH_IN_FOLDER, $USER, $Wfolders, $wgroups
|
||||
# Global Variables: $IAMROOT, $ITALIC, $SEARCH_IN_FOLDER, $USER, $Wfolders, $ldsoconfdG, $wgroups
|
||||
# Initial Functions:
|
||||
# Generated Global Variables: $ini_path, $fpath
|
||||
# Fat linpeas: 0
|
||||
@@ -26,40 +26,53 @@ if ! [ "$SEARCH_IN_FOLDER" ] && ! [ "$IAMROOT" ]; then
|
||||
echo "Content of /etc/ld.so.conf:"
|
||||
cat /etc/ld.so.conf 2>/dev/null | sed -${E} "s,$Wfolders,${SED_RED_YELLOW},g"
|
||||
|
||||
# Check each configured folder
|
||||
cat /etc/ld.so.conf 2>/dev/null | while read l; do
|
||||
if echo "$l" | grep -q include; then
|
||||
# Check each configured folder and include directives
|
||||
cat /etc/ld.so.conf 2>/dev/null | while IFS= read -r l; do
|
||||
l=$(echo "$l" | sed 's/#.*$//' | xargs 2>/dev/null)
|
||||
[ -z "$l" ] && continue
|
||||
|
||||
if echo "$l" | grep -qE '^include[[:space:]]+'; then
|
||||
ini_path=$(echo "$l" | cut -d " " -f 2)
|
||||
fpath=$(dirname "$ini_path")
|
||||
|
||||
if [ -d "/etc/ld.so.conf" ] && [ -w "$fpath" ]; then
|
||||
echo "You have write privileges over $fpath" | sed -${E} "s,.*,${SED_RED_YELLOW},";
|
||||
if [ -d "$fpath" ] && [ -w "$fpath" ]; then
|
||||
echo "You have write privileges over $fpath" | sed -${E} "s,.*,${SED_RED_YELLOW},";
|
||||
printf $RED_YELLOW$ITALIC"$fpath\n"$NC;
|
||||
else
|
||||
printf $GREEN$ITALIC"$fpath\n"$NC;
|
||||
fi
|
||||
|
||||
if [ "$(find $fpath -type f '(' '(' -user $USER ')' -or '(' -perm -o=w ')' -or '(' -perm -g=w -and '(' $wgroups ')' ')' ')' 2>/dev/null)" ]; then
|
||||
echo "You have write privileges over $(find $fpath -type f '(' '(' -user $USER ')' -or '(' -perm -o=w ')' -or '(' -perm -g=w -and '(' $wgroups ')' ')' ')' 2>/dev/null)" | sed -${E} "s,.*,${SED_RED_YELLOW},";
|
||||
if [ "$(find "$fpath" -type f '(' '(' -user "$USER" ')' -or '(' -perm -o=w ')' -or '(' -perm -g=w -and '(' $wgroups ')' ')' ')' 2>/dev/null)" ]; then
|
||||
echo "You have write privileges over $(find "$fpath" -type f '(' '(' -user "$USER" ')' -or '(' -perm -o=w ')' -or '(' -perm -g=w -and '(' $wgroups ')' ')' ')' 2>/dev/null)" | sed -${E} "s,.*,${SED_RED_YELLOW},";
|
||||
fi
|
||||
|
||||
for f in $fpath/*; do
|
||||
if [ -w "$f" ]; then
|
||||
echo "You have write privileges over $f" | sed -${E} "s,.*,${SED_RED_YELLOW},";
|
||||
for f in $ini_path; do
|
||||
[ -f "$f" ] || continue
|
||||
|
||||
if [ -w "$f" ]; then
|
||||
echo "You have write privileges over $f" | sed -${E} "s,.*,${SED_RED_YELLOW},";
|
||||
printf $RED_YELLOW$ITALIC"$f\n"$NC;
|
||||
else
|
||||
printf $GREEN$ITALIC" $f\n"$NC;
|
||||
fi
|
||||
|
||||
cat "$f" | grep -v "^#" | while read l2; do
|
||||
if [ -f "$l2" ] && [ -w "$l2" ]; then
|
||||
echo "You have write privileges over $l2" | sed -${E} "s,.*,${SED_RED_YELLOW},";
|
||||
cat "$f" 2>/dev/null | grep -v "^#" | while IFS= read -r l2; do
|
||||
l2=$(echo "$l2" | xargs 2>/dev/null)
|
||||
[ -z "$l2" ] && continue
|
||||
|
||||
if [ -d "$l2" ] && [ -w "$l2" ]; then
|
||||
echo "You have write privileges over $l2" | sed -${E} "s,.*,${SED_RED_YELLOW},";
|
||||
printf $RED_YELLOW$ITALIC" - $l2\n"$NC;
|
||||
else
|
||||
echo $ITALIC" - $l2"$NC | sed -${E} "s,$l2,${SED_GREEN}," | sed -${E} "s,$Wfolders,${SED_RED_YELLOW},g";
|
||||
elif [ -d "$l2" ]; then
|
||||
echo $ITALIC" - $l2"$NC | sed -${E} "s,$ldsoconfdG,${SED_GREEN},g" | sed -${E} "s,$Wfolders,${SED_RED_YELLOW},g";
|
||||
fi
|
||||
done
|
||||
done
|
||||
elif [ -d "$l" ] && [ -w "$l" ]; then
|
||||
echo "You have write privileges over $l" | sed -${E} "s,.*,${SED_RED_YELLOW},";
|
||||
printf $RED_YELLOW$ITALIC"$l\n"$NC;
|
||||
else
|
||||
echo $ITALIC"$l"$NC | sed -${E} "s,$ldsoconfdG,${SED_GREEN},g" | sed -${E} "s,$Wfolders,${SED_RED_YELLOW},g";
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
@@ -75,4 +88,4 @@ if ! [ "$SEARCH_IN_FOLDER" ] && ! [ "$IAMROOT" ]; then
|
||||
if [ -f "$l" ] && [ -w "$l" ]; then echo "You have write privileges over $l" | sed -${E} "s,.*,${SED_RED_YELLOW},"; fi
|
||||
done
|
||||
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -17,10 +17,10 @@ check_external_hostname(){
|
||||
INTERNET_SEARCH_TIMEOUT=15
|
||||
# wget or curl?
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl "https://2e6ppt7izvuv66qmx2r3et2ufi0mxwqs.lambda-url.us-east-1.on.aws/" -H "User-Agent: linpeas" -d "{\"hostname\":\"$(hostname)\"}" -H "Content-Type: application/json" --max-time "$INTERNET_SEARCH_TIMEOUT"
|
||||
curl "https://tools.hacktricks.wiki/api/host-checker" -H "User-Agent: linpeas" -d "{\"hostname\":\"$(hostname)\"}" -H "Content-Type: application/json" --max-time "$INTERNET_SEARCH_TIMEOUT"
|
||||
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" --post-data "{\"hostname\":\"$(hostname)\"}" -H "Content-Type: application/json" --timeout "$INTERNET_SEARCH_TIMEOUT"
|
||||
wget -q -O - "https://tools.hacktricks.wiki/api/host-checker" --header "User-Agent: linpeas" --post-data "{\"hostname\":\"$(hostname)\"}" -H "Content-Type: application/json" --timeout "$INTERNET_SEARCH_TIMEOUT"
|
||||
else
|
||||
echo "wget or curl not found"
|
||||
fi
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,11 +15,12 @@
|
||||
|
||||
check_tcp_443_bin () {
|
||||
local TIMEOUT_INTERNET_SECONDS_443_BIN=$1
|
||||
local url_lambda="https://2e6ppt7izvuv66qmx2r3et2ufi0mxwqs.lambda-url.us-east-1.on.aws/"
|
||||
local url_lambda="https://tools.hacktricks.wiki/api/host-checker"
|
||||
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
if curl -s --connect-timeout $TIMEOUT_INTERNET_SECONDS_443_BIN "$url_lambda" \
|
||||
-H "User-Agent: linpeas" -H "Content-Type: application/json" >/dev/null 2>&1
|
||||
-H "User-Agent: linpeas" -H "Content-Type: application/json" \
|
||||
-d "{\"hostname\":\"$(hostname)\"}" >/dev/null 2>&1
|
||||
then
|
||||
echo "Port 443 is accessible with curl"
|
||||
return 0 # ✅ success
|
||||
@@ -30,7 +31,8 @@ check_tcp_443_bin () {
|
||||
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
if wget -q --timeout=$TIMEOUT_INTERNET_SECONDS_443_BIN -O - "$url_lambda" \
|
||||
--header "User-Agent: linpeas" -H "Content-Type: application/json" >/dev/null 2>&1
|
||||
--header "User-Agent: linpeas" -H "Content-Type: application/json" \
|
||||
--post-data "{\"hostname\":\"$(hostname)\"}" >/dev/null 2>&1
|
||||
then
|
||||
echo "Port 443 is accessible with wget"
|
||||
return 0
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
# License: GNU GPL
|
||||
# Version: 1.0
|
||||
# Functions Used: echo_not_found
|
||||
# Global Variables: $GREP_DOCKER_SOCK_INFOS, $GREP_DOCKER_SOCK_INFOS_IGNORE, $IAMROOT
|
||||
# Global Variables: $GREP_DOCKER_SOCK_INFOS, $GREP_DOCKER_SOCK_INFOS_IGNORE
|
||||
# Initial Functions:
|
||||
# Generated Global Variables: $SEARCHED_DOCKER_SOCKETS, $dock_sock, $docker_enumerated, $dockerVersion, $int_sock, $sockInfoResponse
|
||||
# Generated Global Variables: $SEARCHED_DOCKER_SOCKETS, $docker_enumerated, $dockerVersion, $int_sock, $sockInfoResponse
|
||||
# Fat linpeas: 0
|
||||
# Small linpeas: 1
|
||||
|
||||
@@ -17,34 +17,55 @@ enumerateDockerSockets() {
|
||||
dockerVersion="$(echo_not_found)"
|
||||
if ! [ "$SEARCHED_DOCKER_SOCKETS" ]; then
|
||||
SEARCHED_DOCKER_SOCKETS="1"
|
||||
for int_sock in $(find / ! -path "/sys/*" -type s -name "docker.sock" -o -name "docker.socket" -o -name "dockershim.sock" -o -name "containerd.sock" -o -name "crio.sock" -o -name "frakti.sock" -o -name "rktlet.sock" 2>/dev/null); do
|
||||
if ! [ "$IAMROOT" ] && [ -w "$int_sock" ]; then
|
||||
# NOTE: This is intentionally "lightweight" (checks common runtime socket names) and avoids
|
||||
# pseudo filesystems (/sys, /proc) to reduce noise and latency.
|
||||
for int_sock in $(find / \
|
||||
-path "/sys" -prune -o \
|
||||
-path "/proc" -prune -o \
|
||||
-type s \( \
|
||||
-name "docker.sock" -o \
|
||||
-name "docker.socket" -o \
|
||||
-name "dockershim.sock" -o \
|
||||
-name "containerd.sock" -o \
|
||||
-name "crio.sock" -o \
|
||||
-name "frakti.sock" -o \
|
||||
-name "rktlet.sock" \
|
||||
\) -print 2>/dev/null); do
|
||||
|
||||
# Basic permissions hint (you generally need write perms to connect to a unix socket).
|
||||
if [ -w "$int_sock" ]; then
|
||||
if echo "$int_sock" | grep -Eq "docker"; then
|
||||
dock_sock="$int_sock"
|
||||
echo "You have write permissions over Docker socket $dock_sock" | sed -${E} "s,$dock_sock,${SED_RED_YELLOW},g"
|
||||
echo "Docker enummeration:"
|
||||
docker_enumerated=""
|
||||
|
||||
if [ "$(command -v curl || echo -n '')" ]; then
|
||||
sockInfoResponse="$(curl -s --unix-socket $dock_sock http://localhost/info)"
|
||||
dockerVersion=$(echo "$sockInfoResponse" | tr ',' '\n' | grep 'ServerVersion' | cut -d'"' -f 4)
|
||||
echo $sockInfoResponse | tr ',' '\n' | grep -E "$GREP_DOCKER_SOCK_INFOS" | grep -v "$GREP_DOCKER_SOCK_INFOS_IGNORE" | tr -d '"'
|
||||
if [ "$sockInfoResponse" ]; then docker_enumerated="1"; fi
|
||||
fi
|
||||
|
||||
if [ "$(command -v docker || echo -n '')" ] && ! [ "$docker_enumerated" ]; then
|
||||
sockInfoResponse="$(docker info)"
|
||||
dockerVersion=$(echo "$sockInfoResponse" | tr ',' '\n' | grep 'Server Version' | cut -d' ' -f 4)
|
||||
printf "$sockInfoResponse" | tr ',' '\n' | grep -E "$GREP_DOCKER_SOCK_INFOS" | grep -v "$GREP_DOCKER_SOCK_INFOS_IGNORE" | tr -d '"'
|
||||
fi
|
||||
|
||||
echo "You have write permissions over Docker socket $int_sock" | sed -${E} "s,$int_sock,${SED_RED_YELLOW},g"
|
||||
else
|
||||
echo "You have write permissions over interesting socket $int_sock" | sed -${E} "s,$int_sock,${SED_RED},g"
|
||||
fi
|
||||
|
||||
else
|
||||
echo "You don't have write permissions over interesting socket $int_sock" | sed -${E} "s,$int_sock,${SED_GREEN},g"
|
||||
fi
|
||||
|
||||
# Validate whether this looks like a Docker Engine API socket (amicontained-style) when curl exists.
|
||||
docker_enumerated=""
|
||||
if [ "$(command -v curl 2>/dev/null || echo -n '')" ]; then
|
||||
sockInfoResponse="$(curl -s --max-time 2 --unix-socket "$int_sock" http://localhost/info 2>/dev/null)"
|
||||
if echo "$sockInfoResponse" | grep -q "ServerVersion"; then
|
||||
echo "Valid Docker API socket: $int_sock" | sed -${E} "s,$int_sock,${SED_RED_YELLOW},g"
|
||||
dockerVersion=$(echo "$sockInfoResponse" | tr ',' '\n' | grep 'ServerVersion' | cut -d'"' -f 4)
|
||||
echo "$sockInfoResponse" | tr ',' '\n' | grep -E "$GREP_DOCKER_SOCK_INFOS" | grep -v "$GREP_DOCKER_SOCK_INFOS_IGNORE" | tr -d '"'
|
||||
docker_enumerated="1"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Fallback to docker CLI if curl is missing or the /info request didn't work.
|
||||
# Use DOCKER_HOST so we can target non-default socket paths when possible.
|
||||
if [ "$(command -v docker 2>/dev/null || echo -n '')" ] && ! [ "$docker_enumerated" ]; then
|
||||
if [ -w "$int_sock" ] && echo "$int_sock" | grep -Eq "docker"; then
|
||||
sockInfoResponse="$(DOCKER_HOST="unix://$int_sock" docker info 2>/dev/null)"
|
||||
if [ "$sockInfoResponse" ]; then
|
||||
dockerVersion=$(echo "$sockInfoResponse" | grep -i "^ Server Version:" | awk '{print $4}' | head -n 1)
|
||||
printf "%s\n" "$sockInfoResponse" | grep -E "$GREP_DOCKER_SOCK_INFOS" | grep -v "$GREP_DOCKER_SOCK_INFOS_IGNORE" | tr -d '"'
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Title: LinPeasBase - su_try_pwd
|
||||
# ID: su_try_pwd
|
||||
# Author: Carlos Polop
|
||||
# Last Update: 22-08-2023
|
||||
# Last Update: 15-12-2025
|
||||
# Description: Try to login as user using a password
|
||||
# License: GNU GPL
|
||||
# Version: 1.0
|
||||
@@ -17,7 +17,7 @@ su_try_pwd(){
|
||||
BFUSER=$1
|
||||
PASSWORDTRY=$2
|
||||
trysu=$(echo "$PASSWORDTRY" | timeout 1 su $BFUSER -c whoami 2>/dev/null)
|
||||
if [ "$trysu" ]; then
|
||||
if [ $? -eq 0 ]; then
|
||||
echo " You can login as $BFUSER using password: $PASSWORDTRY" | sed -${E} "s,.*,${SED_RED_YELLOW},"
|
||||
fi
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,7 +217,7 @@ print_title(){
|
||||
max_title_len=80
|
||||
rest_len=$((($max_title_len - $title_len) / 2))
|
||||
|
||||
printf ${BLUE}
|
||||
printf "%s" "${BLUE}"
|
||||
for i in $(seq 1 $rest_len); do printf " "; done
|
||||
printf "╔"
|
||||
for i in $(seq 1 $title_len); do printf "═"; done; printf "═";
|
||||
@@ -231,13 +231,13 @@ print_title(){
|
||||
|
||||
echo ""
|
||||
|
||||
printf ${BLUE}
|
||||
printf "%s" "${BLUE}"
|
||||
for i in $(seq 1 $rest_len); do printf " "; done
|
||||
printf "╚"
|
||||
for i in $(seq 1 $title_len); do printf "═"; done; printf "═";
|
||||
printf "╝"
|
||||
|
||||
printf $NC
|
||||
printf "%s" "${NC}"
|
||||
echo ""
|
||||
}
|
||||
|
||||
@@ -371,7 +371,7 @@ echo ""
|
||||
printf ${BLUE}"Linux Privesc Checklist: ${YELLOW}https://book.hacktricks.wiki/en/linux-hardening/linux-privilege-escalation-checklist.html\n"$NC
|
||||
echo " LEGEND:" | sed "s,LEGEND,${C}[1;4m&${C}[0m,"
|
||||
echo " RED/YELLOW: 95% a PE vector" | sed "s,RED/YELLOW,${SED_RED_YELLOW},"
|
||||
echo " RED: You should take a look to it" | sed "s,RED,${SED_RED},"
|
||||
echo " RED: You should take a look into it" | sed "s,RED,${SED_RED},"
|
||||
echo " LightCyan: Users with console" | sed "s,LightCyan,${SED_LIGHT_CYAN},"
|
||||
echo " Blue: Users without console & mounted devs" | sed "s,Blue,${SED_BLUE},"
|
||||
echo " Green: Common things (users, groups, SUID/SGID, mounts, .sh scripts, cronjobs) " | sed "s,Green,${SED_GREEN},"
|
||||
@@ -514,4 +514,4 @@ else
|
||||
HOMESEARCH="$HOME $HOMESEARCH"
|
||||
fi
|
||||
fi
|
||||
GREPHOMESEARCH=$(echo "$HOMESEARCH" | sed 's/ *$//g' | tr " " "|") #Remove ending spaces before putting "|"
|
||||
GREPHOMESEARCH=$(echo "$HOMESEARCH" | sed 's/ *$//g' | tr " " "|") #Remove ending spaces before putting "|"
|
||||
|
||||
@@ -13,4 +13,4 @@
|
||||
# Small linpeas: 1
|
||||
|
||||
|
||||
capsB="=ep|cap_chown|cap_former|cap_setfcap|cap_dac_override|cap_dac_read_search|cap_setuid|cap_setgid|cap_kill|cap_net_bind_service|cap_net_raw|cap_net_admin|cap_sys_admin|cap_sys_ptrace|cap_sys_module"
|
||||
capsB="=ep|cap_chown|cap_fowner|cap_fsetid|cap_setpcap|cap_setfcap|cap_dac_override|cap_dac_read_search|cap_setuid|cap_setgid|cap_kill|cap_net_bind_service|cap_net_raw|cap_net_admin|cap_sys_admin|cap_sys_ptrace|cap_sys_module|cap_sys_rawio|cap_bpf|cap_perfmon"
|
||||
|
||||
@@ -18,7 +18,9 @@ cap_sys_ptrace:python \
|
||||
cap_sys_module:kmod|python \
|
||||
cap_dac_override:python|vim \
|
||||
cap_chown:chown|python \
|
||||
cap_former:chown|python \
|
||||
cap_fowner:chown|python \
|
||||
cap_setfcap:python|perl|ruby|php|node|lua|bash \
|
||||
cap_setpcap:python|perl|ruby|php|node|lua|bash \
|
||||
cap_setuid:peass{CAP_SETUID_HERE} \
|
||||
cap_setgid:peass{CAP_SETGID_HERE} \
|
||||
cap_net_raw:python|tcpdump"
|
||||
cap_net_raw:python|tcpdump|dumpcap|tcpflow"
|
||||
|
||||
@@ -24,4 +24,4 @@ pwd_in_variables7="MAILGUN_APIKEY|MAILGUN_API_KEY|MAILGUN_DOMAIN|MAILGUN_PRIV_KE
|
||||
pwd_in_variables8="OKTA_OAUTH2_ISSUER|OMISE_KEY|OMISE_PKEY|OMISE_PUBKEY|OMISE_SKEY|ONESIGNAL_API_KEY|ONESIGNAL_USER_AUTH_KEY|OPENWHISK_KEY|OPEN_WHISK_KEY|OSSRH_PASS|OSSRH_SECRET|OSSRH_USER|OS_AUTH_URL|OS_PROJECT_NAME|OS_TENANT_ID|OS_TENANT_NAME|PAGERDUTY_APIKEY|PAGERDUTY_ESCALATION_POLICY_ID|PAGERDUTY_FROM_USER|PAGERDUTY_PRIORITY_ID|PAGERDUTY_SERVICE_ID|PANTHEON_SITE|PARSE_APP_ID|PARSE_JS_KEY|PAYPAL_CLIENT_ID|PAYPAL_CLIENT_SECRET|PERCY_TOKEN|PERSONAL_KEY|PERSONAL_SECRET|PG_DATABASE|PG_HOST|PLACES_APIKEY|PLACES_API_KEY|PLACES_APPID|PLACES_APPLICATION_ID|PLOTLY_APIKEY|POSTGRESQL_DB|POSTGRESQL_PASS|POSTGRES_ENV_POSTGRES_DB|POSTGRES_ENV_POSTGRES_USER|POSTGRES_PORT|PREBUILD_AUTH|PROD.ACCESS.KEY.ID|PROD.SECRET.KEY|PROD_BASE_URL_RUNSCOPE|PROJECT_CONFIG|PUBLISH_KEY|PUBLISH_SECRET|PUSHOVER_TOKEN|PUSHOVER_USER|PYPI_PASSOWRD|QUIP_TOKEN|RABBITMQ_SERVER_ADDR|REDISCLOUD_URL|REDIS_STUNNEL_URLS|REFRESH_TOKEN|RELEASE_GH_TOKEN|RELEASE_TOKEN|remoteUserToShareTravis|REPORTING_WEBDAV_URL|REPORTING_WEBDAV_USER|repoToken|REST_API_KEY|RINKEBY_PRIVATE_KEY|ROPSTEN_PRIVATE_KEY|route53_access_key_id|RTD_KEY_PASS|RTD_STORE_PASS|RUBYGEMS_AUTH_TOKEN|s3_access_key|S3_ACCESS_KEY_ID|S3_BUCKET_NAME_APP_LOGS|S3_BUCKET_NAME_ASSETS|S3_KEY"
|
||||
pwd_in_variables9="S3_KEY_APP_LOGS|S3_KEY_ASSETS|S3_PHOTO_BUCKET|S3_SECRET_APP_LOGS|S3_SECRET_ASSETS|S3_SECRET_KEY|S3_USER_ID|S3_USER_SECRET|SACLOUD_ACCESS_TOKEN|SACLOUD_ACCESS_TOKEN_SECRET|SACLOUD_API|SALESFORCE_BULK_TEST_SECURITY_TOKEN|SANDBOX_ACCESS_TOKEN|SANDBOX_AWS_ACCESS_KEY_ID|SANDBOX_AWS_SECRET_ACCESS_KEY|SANDBOX_LOCATION_ID|SAUCE_ACCESS_KEY|SECRETACCESSKEY|SECRETKEY|SECRET_0|SECRET_10|SECRET_11|SECRET_1|SECRET_2|SECRET_3|SECRET_4|SECRET_5|SECRET_6|SECRET_7|SECRET_8|SECRET_9|SECRET_KEY_BASE|SEGMENT_API_KEY|SELION_SELENIUM_SAUCELAB_GRID_CONFIG_FILE|SELION_SELENIUM_USE_SAUCELAB_GRID|SENDGRID|SENDGRID_API_KEY|SENDGRID_FROM_ADDRESS|SENDGRID_KEY|SENDGRID_USER|SENDWITHUS_KEY|SENTRY_AUTH_TOKEN|SERVICE_ACCOUNT_SECRET|SES_ACCESS_KEY|SES_SECRET_KEY|setDstAccessKey|setDstSecretKey|setSecretKey|SIGNING_KEY|SIGNING_KEY_SECRET|SIGNING_KEY_SID|SNOOWRAP_CLIENT_SECRET|SNOOWRAP_REDIRECT_URI|SNOOWRAP_REFRESH_TOKEN|SNOOWRAP_USER_AGENT|SNYK_API_TOKEN|SNYK_ORG_ID|SNYK_TOKEN|SOCRATA_APP_TOKEN|SOCRATA_USER|SONAR_ORGANIZATION_KEY|SONAR_PROJECT_KEY|SONAR_TOKEN|SONATYPE_GPG_KEY_NAME|SONATYPE_GPG_PASSPHRASE|SONATYPE_PASSSONATYPE_TOKEN_USER|SONATYPE_USER|SOUNDCLOUD_CLIENT_ID|SOUNDCLOUD_CLIENT_SECRET|SPACES_ACCESS_KEY_ID|SPACES_SECRET_ACCESS_KEY"
|
||||
pwd_in_variables10="SPA_CLIENT_ID|SPOTIFY_API_ACCESS_TOKEN|SPOTIFY_API_CLIENT_ID|SPOTIFY_API_CLIENT_SECRET|sqsAccessKey|sqsSecretKey|SRCCLR_API_TOKEN|SSHPASS|SSMTP_CONFIG|STARSHIP_ACCOUNT_SID|STARSHIP_AUTH_TOKEN|STAR_TEST_AWS_ACCESS_KEY_ID|STAR_TEST_BUCKET|STAR_TEST_LOCATION|STAR_TEST_SECRET_ACCESS_KEY|STORMPATH_API_KEY_ID|STORMPATH_API_KEY_SECRET|STRIPE_PRIVATE|STRIPE_PUBLIC|STRIP_PUBLISHABLE_KEY|STRIP_SECRET_KEY|SURGE_LOGIN|SURGE_TOKEN|SVN_PASS|SVN_USER|TESCO_API_KEY|THERA_OSS_ACCESS_ID|THERA_OSS_ACCESS_KEY|TRAVIS_ACCESS_TOKEN|TRAVIS_API_TOKEN|TRAVIS_COM_TOKEN|TRAVIS_E2E_TOKEN|TRAVIS_GH_TOKEN|TRAVIS_PULL_REQUEST|TRAVIS_SECURE_ENV_VARS|TRAVIS_TOKEN|TREX_CLIENT_ORGURL|TREX_CLIENT_TOKEN|TREX_OKTA_CLIENT_ORGURL|TREX_OKTA_CLIENT_TOKEN|TWILIO_ACCOUNT_ID|TWILIO_ACCOUNT_SID|TWILIO_API_KEY|TWILIO_API_SECRET|TWILIO_CHAT_ACCOUNT_API_SERVICE|TWILIO_CONFIGURATION_SID|TWILIO_SID|TWILIO_TOKEN|TWITTEROAUTHACCESSSECRET|TWITTEROAUTHACCESSTOKEN|TWITTER_CONSUMER_KEY|TWITTER_CONSUMER_SECRET|UNITY_SERIAL|URBAN_KEY|URBAN_MASTER_SECRET|URBAN_SECRET|userTravis|USER_ASSETS_ACCESS_KEY_ID|USER_ASSETS_SECRET_ACCESS_KEY|VAULT_APPROLE_SECRET_ID|VAULT_PATH|VIP_GITHUB_BUILD_REPO_DEPLOY_KEY|VIP_GITHUB_DEPLOY_KEY|VIP_GITHUB_DEPLOY_KEY_PASS"
|
||||
pwd_in_variables11="VIRUSTOTAL_APIKEY|VISUAL_RECOGNITION_API_KEY|V_SFDC_CLIENT_ID|V_SFDC_CLIENT_SECRET|WAKATIME_API_KEY|WAKATIME_PROJECT|WATSON_CLIENT|WATSON_CONVERSATION_WORKSPACE|WATSON_DEVICE|WATSON_DEVICE_TOPIC|WATSON_TEAM_ID|WATSON_TOPIC|WIDGET_BASIC_USER_2|WIDGET_BASIC_USER_3|WIDGET_BASIC_USER_4|WIDGET_BASIC_USER_5|WIDGET_FB_USER|WIDGET_FB_USER_2|WIDGET_FB_USER_3|WIDGET_TEST_SERVERWORDPRESS_DB_USER|WORKSPACE_ID|WPJM_PHPUNIT_GOOGLE_GEOCODE_API_KEY|WPT_DB_HOST|WPT_DB_NAME|WPT_DB_USER|WPT_PREPARE_DIR|WPT_REPORT_API_KEY|WPT_SSH_CONNECT|WPT_SSH_PRIVATE_KEY_BASE64|YANGSHUN_GH_TOKEN|YT_ACCOUNT_CHANNEL_ID|YT_ACCOUNT_CLIENT_ID|YT_ACCOUNT_CLIENT_SECRET|YT_ACCOUNT_REFRESH_TOKEN|YT_API_KEY|YT_CLIENT_ID|YT_CLIENT_SECRET|YT_PARTNER_CHANNEL_ID|YT_PARTNER_CLIENT_ID|YT_PARTNER_CLIENT_SECRET|YT_PARTNER_ID|YT_PARTNER_REFRESH_TOKEN|YT_SERVER_API_KEY|ZHULIANG_GH_TOKEN|ZOPIM_ACCOUNT_KEY"
|
||||
pwd_in_variables11="VIRUSTOTAL_APIKEY|VISUAL_RECOGNITION_API_KEY|V_SFDC_CLIENT_ID|V_SFDC_CLIENT_SECRET|WAKATIME_API_KEY|WAKATIME_PROJECT|WATSON_CLIENT|WATSON_CONVERSATION_WORKSPACE|WATSON_DEVICE|WATSON_DEVICE_TOPIC|WATSON_TEAM_ID|WATSON_TOPIC|WIDGET_BASIC_USER_2|WIDGET_BASIC_USER_3|WIDGET_BASIC_USER_4|WIDGET_BASIC_USER_5|WIDGET_FB_USER|WIDGET_FB_USER_2|WIDGET_FB_USER_3|WIDGET_TEST_SERVERWORDPRESS_DB_USER|WORKSPACE_ID|WPJM_PHPUNIT_GOOGLE_GEOCODE_API_KEY|WPT_DB_HOST|WPT_DB_NAME|WPT_DB_USER|WPT_PREPARE_DIR|WPT_REPORT_API_KEY|WPT_SSH_CONNECT|WPT_SSH_PRIVATE_KEY_BASE64|YANGSHUN_GH_TOKEN|YT_ACCOUNT_CHANNEL_ID|YT_ACCOUNT_CLIENT_ID|YT_ACCOUNT_CLIENT_SECRET|YT_ACCOUNT_REFRESH_TOKEN|YT_API_KEY|YT_CLIENT_ID|YT_CLIENT_SECRET|YT_PARTNER_CHANNEL_ID|YT_PARTNER_CLIENT_ID|YT_PARTNER_CLIENT_SECRET|YT_PARTNER_ID|YT_PARTNER_REFRESH_TOKEN|YT_SERVER_API_KEY|ZHULIANG_GH_TOKEN|ZOPIM_ACCOUNT_KEY|USERNAME|PASSWORD|PASSWD|CREDENTIALS?"
|
||||
|
||||
@@ -15,6 +15,5 @@
|
||||
|
||||
sidG1="/abuild-sudo$|/accton$|/allocate$|/ARDAgent$|/arping$|/atq$|/atrm$|/authpf$|/authpf-noip$|/authopen$|/batch$|/bbsuid$|/bsd-write$|/btsockstat$|/bwrap$|/cacaocsc$|/camel-lock-helper-1.2$|/ccreds_validate$|/cdrw$|/chage$|/check-foreground-console$|/chrome-sandbox$|/chsh$|/cons.saver$|/crontab$|/ct$|/cu$|/dbus-daemon-launch-helper$|/deallocate$|/desktop-create-kmenu$|/dma$|/dma-mbox-create$|/dmcrypt-get-device$|/doas$|/dotlockfile$|/dotlock.mailutils$|/dtaction$|/dtfile$|/eject$|/execabrt-action-install-debuginfo-to-abrt-cache$|/execdbus-daemon-launch-helper$|/execdma-mbox-create$|/execlockspool$|/execlogin_chpass$|/execlogin_lchpass$|/execlogin_passwd$|/execssh-keysign$|/execulog-helper$|/exim4|/expiry$|/fdformat$|/fstat$|/fusermount$|/fusermount3$"
|
||||
sidG2="/gnome-pty-helper$|/glines$|/gnibbles$|/gnobots2$|/gnome-suspend$|/gnometris$|/gnomine$|/gnotski$|/gnotravex$|/gpasswd$|/gpg$|/gpio$|/gtali|/.hal-mtab-lock$|/helper$|/imapd$|/inndstart$|/kismet_cap_nrf_51822$|/kismet_cap_nxp_kw41z$|/kismet_cap_ti_cc_2531$|/kismet_cap_ti_cc_2540$|/kismet_cap_ubertooth_one$|/kismet_capture$|/kismet_cap_linux_bluetooth$|/kismet_cap_linux_wifi$|/kismet_cap_nrf_mousejack$|/ksu$|/list_devices$|/load_osxfuse$|/locate$|/lock$|/lockdev$|/lockfile$|/login_activ$|/login_crypto$|/login_radius$|/login_skey$|/login_snk$|/login_token$|/login_yubikey$|/lpc$|/lpd$|/lpd-port$|/lppasswd$|/lpq$|/lpr$|/lprm$|/lpset$|/lxc-user-nic$|/mahjongg$|/mail-lock$|/mailq$|/mail-touchlock$|/mail-unlock$|/mksnap_ffs$|/mlocate$|/mlock$|/mount$|/mount.cifs$|/mount.ecryptfs_private$|/mount.nfs$|/mount.nfs4$|/mount_osxfuse$|/mtr$|/mutt_dotlock$"
|
||||
sidG3="/ncsa_auth$|/netpr$|/netkit-rcp$|/netkit-rlogin$|/netkit-rsh$|/netreport$|/netstat$|/newgidmap$|/newtask$|/newuidmap$|/nvmmctl$|/opieinfo$|/opiepasswd$|/pam_auth$|/pam_extrausers_chkpwd$|/pam_timestamp_check$|/pamverifier$|/pfexec$|/ping$|/ping6$|/pmconfig$|/pmap$|/polkit-agent-helper-1$|/polkit-explicit-grant-helper$|/polkit-grant-helper$|/polkit-grant-helper-pam$|/polkit-read-auth-helper$|/polkit-resolve-exe-helper$|/polkit-revoke-helper$|/polkit-set-default-helper$|/postdrop$|/postqueue$|/poweroff$|/ppp$|/procmail$|/pstat$|/pt_chmod$|/pwdb_chkpwd$|/quota$|/rcmd|/remote.unknown$|/rlogin$|/rmformat$|/rnews$|/run-mailcap$|/sacadm$|/same-gnome$|screen.real$|/security_authtrampoline$|/sendmail.sendmail$|/shutdown$|/skeyaudit$|/skeyinfo$|/skeyinit$|/sliplogin|/slocate$|/smbmnt$|/smbumount$|/smpatch$|/smtpctl$|/sperl5.8.8$|/ssh-agent$|/ssh-keysign$|/staprun$|/startinnfeed$|/stclient$|/su$|/suexec$|/sys-suspend$|/sysstat$|/systat$"
|
||||
sidG3="/ncsa_auth$|/netpr$|/netkit-rcp$|/netkit-rlogin$|/netkit-rsh$|/netreport$|/netstat$|/newgidmap$|/newtask$|/newuidmap$|/nvmmctl$|/opieinfo$|/opiepasswd$|/pam_auth$|/pam_extrausers_chkpwd$|/pam_timestamp_check$|/pamverifier$|/pfexec$|/hping3$|/ping$|/ping6$|/pmconfig$|/pmap$|/polkit-agent-helper-1$|/polkit-explicit-grant-helper$|/polkit-grant-helper$|/polkit-grant-helper-pam$|/polkit-read-auth-helper$|/polkit-resolve-exe-helper$|/polkit-revoke-helper$|/polkit-set-default-helper$|/postdrop$|/postqueue$|/poweroff$|/ppp$|/procmail$|/pstat$|/pt_chmod$|/pwdb_chkpwd$|/quota$|/rcmd|/remote.unknown$|/rlogin$|/rmformat$|/rnews$|/run-mailcap$|/sacadm$|/same-gnome$|screen.real$|/security_authtrampoline$|/sendmail.sendmail$|/shutdown$|/skeyaudit$|/skeyinfo$|/skeyinit$|/sliplogin|/slocate$|/smbmnt$|/smbumount$|/smpatch$|/smtpctl$|/sperl5.8.8$|/ssh-agent$|/ssh-keysign$|/staprun$|/startinnfeed$|/stclient$|/su$|/suexec$|/sys-suspend$|/sysstat$|/systat$"
|
||||
sidG4="/telnetlogin$|/timedc$|/tip$|/top$|/traceroute6$|/traceroute6.iputils$|/trpt$|/tsoldtlabel$|/tsoljdslabel$|/tsolxagent$|/ufsdump$|/ufsrestore$|/ulog-helper$|/umount.cifs$|/umount.nfs$|/umount.nfs4$|/unix_chkpwd$|/uptime$|/userhelper$|/userisdnctl$|/usernetctl$|/utempter$|/utmp_update$|/uucico$|/uuglist$|/uuidd$|/uuname$|/uusched$|/uustat$|/uux$|/uuxqt$|/VBoxHeadless$|/VBoxNetAdpCtl$|/VBoxNetDHCP$|/VBoxNetNAT$|/VBoxSDL$|/VBoxVolInfo$|/VirtualBoxVM$|/vmstat$|/vmware-authd$|/vmware-user-suid-wrapper$|/vmware-vmx$|/vmware-vmx-debug$|/vmware-vmx-stats$|/vncserver-x11$|/volrmmount$|/w$|/wall$|/whodo$|/write$|/X$|/Xorg.wrap$|/Xsun$|/Xvnc$|/yppasswd$"
|
||||
|
||||
|
||||
@@ -12,5 +12,4 @@
|
||||
# Fat linpeas: 0
|
||||
# Small linpeas: 1
|
||||
|
||||
|
||||
sudoB="$(whoami)|ALL:ALL|ALL : ALL|ALL|env_keep|NOPASSWD|SETENV|/apache2|/cryptsetup|/mount"
|
||||
sudoB="$(whoami)|ALL:ALL|ALL : ALL|ALL|env_keep|NOPASSWD|SETENV|/apache2|/cryptsetup|/mount|/restic|/usermod|/sbin/ldconfig|/usr/sbin/ldconfig|ldconfig -f|--password-command|--password-file|-o ProxyCommand|-o PreferredAuthentications"
|
||||
|
||||
@@ -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|env_keep\W*\+=.*PATH|!env_reset|!requiretty|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]"
|
||||
|
||||
@@ -13,4 +13,4 @@
|
||||
# Small linpeas: 1
|
||||
|
||||
|
||||
writeVB="/etc/anacrontab|/etc/apt/apt.conf.d|/etc/bash.bashrc|/etc/bash_completion|/etc/bash_completion.d/|/etc/cron|/etc/environment|/etc/environment.d/|/etc/group|/etc/incron.d/|/etc/init|/etc/ld.so.conf.d/|/etc/master.passwd|/etc/passwd|/etc/profile.d/|/etc/profile|/etc/rc.d|/etc/shadow|/etc/skey/|/etc/sudoers|/etc/sudoers.d/|/etc/supervisor/conf.d/|/etc/supervisor/supervisord.conf|/etc/systemd|/etc/sys|/lib/systemd|/etc/update-motd.d/|/root/.ssh/|/run/systemd|/usr/lib/cron/tabs/|/usr/lib/systemd|/systemd/system|/var/db/yubikey/|/var/spool/anacron|/var/spool/cron/crontabs|"$(echo $PATH 2>/dev/null | sed 's/:\.:/:/g' | sed 's/:\.$//g' | sed 's/^\.://g' | sed 's/:/$|^/g') #Add Path but remove simple dot in PATH
|
||||
writeVB="/etc/anacrontab|/etc/apt/apt.conf.d|/etc/bash.bashrc|/etc/bash_completion|/etc/bash_completion.d/|/etc/cron|/etc/environment|/etc/environment.d/|/etc/group|/etc/incron.d/|/etc/init|/etc/ld.so.conf.d/|/etc/ld.so.preload|/etc/master.passwd|/etc/passwd|/etc/profile.d/|/etc/profile|/etc/rc.d|/etc/shadow|/etc/skey/|/etc/sudoers|/etc/sudoers.d/|/etc/supervisor/conf.d/|/etc/supervisor/supervisord.conf|/etc/systemd|/etc/sys|/lib/systemd|/etc/update-motd.d/|/root/.ssh/|/run/systemd|/usr/lib/cron/tabs/|/usr/lib/systemd|/systemd/system|/var/db/yubikey/|/var/spool/anacron|/var/spool/cron/crontabs|"$(echo $PATH 2>/dev/null | sed 's/:\.:/:/g' | sed 's/:\.$//g' | sed 's/^\.://g' | sed 's/:/$|^/g') #Add Path but remove simple dot in PATH
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
@@ -115,7 +115,7 @@ class LinpeasBuilder:
|
||||
suidVB, sudoVB, capsVB = self.__get_gtfobins_lists()
|
||||
assert len(suidVB) > 185, f"Len suidVB is {len(suidVB)}"
|
||||
assert len(sudoVB) > 250, f"Len sudo is {len(sudoVB)}"
|
||||
assert len(capsVB) > 10, f"Len suidVB is {len(capsVB)}"
|
||||
assert len(capsVB) > 2, f"Len capsVB is {len(capsVB)}"
|
||||
|
||||
self.__replace_mark(SUIDVB1_MARKUP, suidVB[:int(len(suidVB)/2)], "|")
|
||||
self.__replace_mark(SUIDVB2_MARKUP, suidVB[int(len(suidVB)/2):], "|")
|
||||
@@ -348,8 +348,25 @@ class LinpeasBuilder:
|
||||
return bin_b64
|
||||
|
||||
def __get_gtfobins_lists(self) -> tuple:
|
||||
r = requests.get("https://github.com/GTFOBins/GTFOBins.github.io/tree/master/_gtfobins")
|
||||
bins = re.findall(r'_gtfobins/([a-zA-Z0-9_ \-]+).md', r.text)
|
||||
bins = []
|
||||
api_url = "https://api.github.com/repos/GTFOBins/GTFOBins.github.io/contents/_gtfobins?per_page=100"
|
||||
while api_url:
|
||||
r = requests.get(api_url, timeout=10)
|
||||
if not r.ok:
|
||||
break
|
||||
data = r.json()
|
||||
for entry in data:
|
||||
if entry.get("type") == "file" and entry.get("name"):
|
||||
bins.append(entry["name"])
|
||||
api_url = None
|
||||
link = r.headers.get("Link", "")
|
||||
for part in link.split(","):
|
||||
if 'rel="next"' in part:
|
||||
api_url = part.split(";")[0].strip().strip("<>")
|
||||
break
|
||||
if not bins:
|
||||
r = requests.get("https://github.com/GTFOBins/GTFOBins.github.io/tree/master/_gtfobins", timeout=10)
|
||||
bins = re.findall(r'_gtfobins/([a-zA-Z0-9_ \-]+)(?:\\.md)?', r.text)
|
||||
|
||||
sudoVB = []
|
||||
suidVB = []
|
||||
@@ -357,12 +374,12 @@ class LinpeasBuilder:
|
||||
|
||||
for b in bins:
|
||||
try:
|
||||
rb = requests.get(f"https://raw.githubusercontent.com/GTFOBins/GTFOBins.github.io/master/_gtfobins/{b}.md", timeout=5)
|
||||
rb = requests.get(f"https://raw.githubusercontent.com/GTFOBins/GTFOBins.github.io/master/_gtfobins/{b}", timeout=5)
|
||||
except:
|
||||
try:
|
||||
rb = requests.get(f"https://raw.githubusercontent.com/GTFOBins/GTFOBins.github.io/master/_gtfobins/{b}.md", timeout=5)
|
||||
rb = requests.get(f"https://raw.githubusercontent.com/GTFOBins/GTFOBins.github.io/master/_gtfobins/{b}", timeout=5)
|
||||
except:
|
||||
rb = requests.get(f"https://raw.githubusercontent.com/GTFOBins/GTFOBins.github.io/master/_gtfobins/{b}.md", timeout=5)
|
||||
rb = requests.get(f"https://raw.githubusercontent.com/GTFOBins/GTFOBins.github.io/master/_gtfobins/{b}", timeout=5)
|
||||
if "sudo:" in rb.text:
|
||||
if len(b) <= 3:
|
||||
sudoVB.append("[^a-zA-Z0-9]"+b+"$") # Less false possitives applied to small names
|
||||
@@ -388,7 +405,7 @@ class LinpeasBuilder:
|
||||
name = entry["name"]
|
||||
caseinsensitive = entry.get("caseinsensitive", False)
|
||||
regex = entry["regex"]
|
||||
regex = regex.replace('"', '\\"').strip()
|
||||
regex = regex.replace("\\", "\\\\").replace('"', '\\"').strip()
|
||||
falsePositives = entry.get("falsePositives", False)
|
||||
|
||||
if falsePositives:
|
||||
@@ -402,9 +419,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"""
|
||||
|
||||
@@ -8,6 +8,7 @@ from .yamlGlobals import (
|
||||
class LinpeasModule:
|
||||
def __init__(self, path):
|
||||
self.path = path
|
||||
real_path = os.path.realpath(path)
|
||||
with open(path, 'r') as file:
|
||||
self.module_text = file.read()
|
||||
|
||||
@@ -29,7 +30,7 @@ class LinpeasModule:
|
||||
self.section_info = {}
|
||||
if not (self.is_base or self.is_function or self.is_variable):
|
||||
for module in LINPEAS_PARTS["modules"]:
|
||||
if module["folder_path"] in path:
|
||||
if os.path.realpath(module["folder_path"]) in real_path:
|
||||
self.section_info = module
|
||||
self.is_check = True
|
||||
break
|
||||
|
||||
9558
linPEAS/linpeas_fat.sh
Normal file
9558
linPEAS/linpeas_fat.sh
Normal file
File diff suppressed because one or more lines are too long
40
linPEAS/tests/test_builder.py
Normal file
40
linPEAS/tests/test_builder.py
Normal file
@@ -0,0 +1,40 @@
|
||||
import os
|
||||
import stat
|
||||
import subprocess
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class LinpeasBuilderTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.repo_root = Path(__file__).resolve().parents[2]
|
||||
self.linpeas_dir = self.repo_root / "linPEAS"
|
||||
|
||||
def _run_builder(self, args, output_path):
|
||||
cmd = ["python3", "-m", "builder.linpeas_builder"] + args + ["--output", str(output_path)]
|
||||
result = subprocess.run(cmd, cwd=str(self.linpeas_dir), capture_output=True, text=True)
|
||||
if result.returncode != 0:
|
||||
raise AssertionError(
|
||||
f"linpeas_builder failed:\nstdout:\n{result.stdout}\nstderr:\n{result.stderr}"
|
||||
)
|
||||
|
||||
def test_small_build_creates_executable(self):
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
output_path = Path(tmpdir) / "linpeas_small.sh"
|
||||
self._run_builder(["--small"], output_path)
|
||||
self.assertTrue(output_path.exists(), "linpeas_small.sh was not created.")
|
||||
mode = output_path.stat().st_mode
|
||||
self.assertTrue(mode & stat.S_IXUSR, "linpeas_small.sh is not executable.")
|
||||
|
||||
def test_include_exclude_modules(self):
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
output_path = Path(tmpdir) / "linpeas_include.sh"
|
||||
self._run_builder(["--include", "system_information,container", "--exclude", "container"], output_path)
|
||||
content = output_path.read_text(encoding="utf-8", errors="ignore")
|
||||
self.assertIn("Operative system", content)
|
||||
self.assertNotIn("Am I Containered?", content)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
60
linPEAS/tests/test_modules_metadata.py
Normal file
60
linPEAS/tests/test_modules_metadata.py
Normal file
@@ -0,0 +1,60 @@
|
||||
import re
|
||||
import sys
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class LinpeasModulesMetadataTests(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.repo_root = Path(__file__).resolve().parents[2]
|
||||
cls.linpeas_dir = cls.repo_root / "linPEAS"
|
||||
cls.parts_dir = cls.linpeas_dir / "builder" / "linpeas_parts"
|
||||
|
||||
# Ensure `import builder.*` works when tests are run from repo root.
|
||||
sys.path.insert(0, str(cls.linpeas_dir))
|
||||
|
||||
from builder.src.linpeasModule import LinpeasModule # pylint: disable=import-error
|
||||
|
||||
cls.LinpeasModule = LinpeasModule
|
||||
|
||||
def _iter_module_files(self):
|
||||
return sorted(self.parts_dir.rglob("*.sh"))
|
||||
|
||||
def test_all_modules_parse(self):
|
||||
module_files = self._iter_module_files()
|
||||
self.assertGreater(len(module_files), 0, "No linPEAS module files were found.")
|
||||
|
||||
# Parsing a module validates its metadata and dependencies.
|
||||
for path in module_files:
|
||||
_ = self.LinpeasModule(str(path))
|
||||
|
||||
def test_check_module_id_matches_filename(self):
|
||||
for path in self._iter_module_files():
|
||||
module = self.LinpeasModule(str(path))
|
||||
if not getattr(module, "is_check", False):
|
||||
continue
|
||||
|
||||
# For checks, the filename (without numeric prefix) must match the module ID
|
||||
# (either full ID or stripping section prefix like `SI_`).
|
||||
file_base = re.sub(r"^[0-9]+_", "", path.stem)
|
||||
module_id = getattr(module, "id", "")
|
||||
module_id_tail = module_id[3:] if len(module_id) >= 3 else ""
|
||||
self.assertIn(
|
||||
file_base,
|
||||
{module_id, module_id_tail},
|
||||
f"Module ID mismatch in {path}: id={module_id} expected suffix={file_base}",
|
||||
)
|
||||
|
||||
def test_module_ids_are_unique(self):
|
||||
ids = []
|
||||
for path in self._iter_module_files():
|
||||
module = self.LinpeasModule(str(path))
|
||||
ids.append(getattr(module, "id", ""))
|
||||
|
||||
duplicates = {x for x in ids if x and ids.count(x) > 1}
|
||||
self.assertEqual(set(), duplicates, f"Duplicate module IDs found: {sorted(duplicates)}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -270,7 +270,7 @@ class MetasploitModule < Msf::Post
|
||||
if datastore['CUSTOM_URL'] != ""
|
||||
url_peass = datastore['CUSTOM_URL']
|
||||
else
|
||||
url_peass = datastore['WINPEASS'] ? "https://github.com/peass-ng/PEASS-ng/releases/latest/download/winPEASany_ofs.exe" : "https://github.com/peass-ng/PEASS-ng/releases/latest/download/linpeas.sh"
|
||||
url_peass = datastore['WINPEASS'].to_s.strip.downcase == 'true' ? "https://github.com/peass-ng/PEASS-ng/releases/latest/download/winPEASany_ofs.exe" : "https://github.com/peass-ng/PEASS-ng/releases/latest/download/linpeas.sh"
|
||||
end
|
||||
# If URL is set, check if it is a valid URL or local file
|
||||
if url_peass.include?("http://") || url_peass.include?("https://")
|
||||
|
||||
@@ -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)
|
||||
@@ -129,7 +127,9 @@ def parse_line(line: str):
|
||||
|
||||
elif is_section(line, INFO_PATTERN):
|
||||
title = parse_title(line)
|
||||
C_SECTION["infos"].append(title)
|
||||
if C_SECTION == {}:
|
||||
return
|
||||
C_SECTION.setdefault("infos", []).append(title)
|
||||
|
||||
#If here, then it's text
|
||||
else:
|
||||
@@ -145,17 +145,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:
|
||||
|
||||
@@ -69,57 +69,62 @@ ECHO.
|
||||
CALL :T_Progress 2
|
||||
|
||||
:ListHotFixes
|
||||
wmic qfe get Caption,Description,HotFixID,InstalledOn | more
|
||||
where wmic >nul 2>&1
|
||||
if %errorlevel% equ 0 (
|
||||
wmic qfe get Caption,Description,HotFixID,InstalledOn
|
||||
) else (
|
||||
powershell -command "Get-HotFix | Format-Table -AutoSize"
|
||||
)
|
||||
set expl=no
|
||||
for /f "tokens=3-9" %%a in ('systeminfo') do (ECHO."%%a %%b %%c %%d %%e %%f %%g" | findstr /i "2000 XP 2003 2008 vista" && set expl=yes) & (ECHO."%%a %%b %%c %%d %%e %%f %%g" | findstr /i /C:"windows 7" && set expl=yes)
|
||||
IF "%expl%" == "yes" ECHO. [i] Possible exploits (https://github.com/codingo/OSCP-2/blob/master/Windows/WinPrivCheck.bat)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB2592799" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB2592799" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS11-080 patch is NOT installed! (Vulns: XP/SP3,2K3/SP3-afd.sys)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB3143141" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB3143141" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS16-032 patch is NOT installed! (Vulns: 2K8/SP1/2,Vista/SP2,7/SP1-secondary logon)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB2393802" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB2393802" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS11-011 patch is NOT installed! (Vulns: XP/SP2/3,2K3/SP2,2K8/SP2,Vista/SP1/2,7/SP0-WmiTraceMessageVa)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB982799" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB982799" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS10-59 patch is NOT installed! (Vulns: 2K8,Vista,7/SP0-Chimichurri)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB979683" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB979683" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS10-21 patch is NOT installed! (Vulns: 2K/SP4,XP/SP2/3,2K3/SP2,2K8/SP2,Vista/SP0/1/2,7/SP0-Win Kernel)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB2305420" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB2305420" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS10-092 patch is NOT installed! (Vulns: 2K8/SP0/1/2,Vista/SP1/2,7/SP0-Task Sched)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB981957" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB981957" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS10-073 patch is NOT installed! (Vulns: XP/SP2/3,2K3/SP2/2K8/SP2,Vista/SP1/2,7/SP0-Keyboard Layout)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB4013081" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB4013081" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS17-017 patch is NOT installed! (Vulns: 2K8/SP2,Vista/SP2,7/SP1-Registry Hive Loading)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB977165" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB977165" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS10-015 patch is NOT installed! (Vulns: 2K,XP,2K3,2K8,Vista,7-User Mode to Ring)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB941693" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB941693" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS08-025 patch is NOT installed! (Vulns: 2K/SP4,XP/SP2,2K3/SP1/2,2K8/SP0,Vista/SP0/1-win32k.sys)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB920958" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB920958" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS06-049 patch is NOT installed! (Vulns: 2K/SP4-ZwQuerySysInfo)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB914389" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB914389" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS06-030 patch is NOT installed! (Vulns: 2K,XP/SP2-Mrxsmb.sys)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB908523" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB908523" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS05-055 patch is NOT installed! (Vulns: 2K/SP4-APC Data-Free)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB890859" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB890859" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS05-018 patch is NOT installed! (Vulns: 2K/SP3/4,XP/SP1/2-CSRSS)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB842526" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB842526" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS04-019 patch is NOT installed! (Vulns: 2K/SP2/3/4-Utility Manager)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB835732" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB835732" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS04-011 patch is NOT installed! (Vulns: 2K/SP2/3/4,XP/SP0/1-LSASS service BoF)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB841872" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB841872" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS04-020 patch is NOT installed! (Vulns: 2K/SP4-POSIX)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB2975684" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB2975684" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS14-040 patch is NOT installed! (Vulns: 2K3/SP2,2K8/SP2,Vista/SP2,7/SP1-afd.sys Dangling Pointer)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB3136041" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB3136041" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS16-016 patch is NOT installed! (Vulns: 2K8/SP1/2,Vista/SP2,7/SP1-WebDAV to Address)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB3057191" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB3057191" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS15-051 patch is NOT installed! (Vulns: 2K3/SP2,2K8/SP2,Vista/SP2,7/SP1-win32k.sys)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB2989935" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB2989935" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS14-070 patch is NOT installed! (Vulns: 2K3/SP2-TCP/IP)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB2778930" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB2778930" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS13-005 patch is NOT installed! (Vulns: Vista,7,8,2008,2008R2,2012,RT-hwnd_broadcast)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB2850851" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB2850851" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS13-053 patch is NOT installed! (Vulns: 7SP0/SP1_x86-schlamperei)
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn | findstr /C:"KB2870008" 1>NUL
|
||||
IF "%expl%" == "yes" wmic qfe get Caption,Description,HotFixID,InstalledOn 2>nul | findstr /C:"KB2870008" 1>NUL
|
||||
IF "%expl%" == "yes" IF errorlevel 1 ECHO.MS13-081 patch is NOT installed! (Vulns: 7SP0/SP1_x86-track_popup_menu)
|
||||
ECHO.
|
||||
CALL :T_Progress 2
|
||||
@@ -197,7 +202,12 @@ CALL :T_Progress 1
|
||||
|
||||
:AVSettings
|
||||
CALL :ColorLine " %E%33m[+]%E%97m Registered Anti-Virus(AV)"
|
||||
WMIC /Node:localhost /Namespace:\\root\SecurityCenter2 Path AntiVirusProduct Get displayName /Format:List | more
|
||||
where wmic >nul 2>&1
|
||||
if %errorlevel% equ 0 (
|
||||
WMIC /Node:localhost /Namespace:\\root\SecurityCenter2 Path AntiVirusProduct Get displayName /Format:List
|
||||
) else (
|
||||
powershell -command "Get-CimInstance -Namespace root/SecurityCenter2 -ClassName AntiVirusProduct | Select-Object -ExpandProperty displayName"
|
||||
)
|
||||
ECHO.Checking for defender whitelisted PATHS
|
||||
reg query "HKLM\SOFTWARE\Microsoft\Windows Defender\Exclusions\Paths" 2>nul
|
||||
CALL :T_Progress 1
|
||||
@@ -226,7 +236,12 @@ CALL :T_Progress 3
|
||||
:MountedDisks
|
||||
CALL :ColorLine " %E%33m[+]%E%97m MOUNTED DISKS"
|
||||
ECHO. [i] Maybe you find something interesting
|
||||
(wmic logicaldisk get caption 2>nul | more) || (fsutil fsinfo drives 2>nul)
|
||||
where wmic >nul 2>&1
|
||||
if %errorlevel% equ 0 (
|
||||
wmic logicaldisk get caption
|
||||
) else (
|
||||
fsutil fsinfo drives
|
||||
)
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
|
||||
@@ -273,15 +288,29 @@ tasklist /SVC
|
||||
ECHO.
|
||||
CALL :T_Progress 2
|
||||
ECHO. [i] Checking file permissions of running processes (File backdooring - maybe the same files start automatically when Administrator logs in)
|
||||
for /f "tokens=2 delims='='" %%x in ('wmic process list full^|find /i "executablepath"^|find /i /v "system32"^|find ":"') do (
|
||||
for /f eol^=^"^ delims^=^" %%z in ('ECHO.%%x') do (
|
||||
icacls "%%z" 2>nul | findstr /i "(F) (M) (W) :\\" | findstr /i ":\\ everyone authenticated users todos %username%" && ECHO.
|
||||
where wmic >nul 2>&1
|
||||
if %errorlevel% equ 0 (
|
||||
for /f "tokens=2 delims='='" %%x in ('wmic process list full ^|find /i "executablepath"^|find /i /v "system32"^|find ":"') do (
|
||||
for /f eol^=^"^ delims^=^" %%z in ('ECHO.%%x') do (
|
||||
icacls "%%z" 2>nul | findstr /i "(F) (M) (W) :\\" | findstr /i ":\\ everyone authenticated users todos %username%" && ECHO.
|
||||
)
|
||||
)
|
||||
) else (
|
||||
for /f "tokens=*" %%x in ('powershell -command "Get-Process | Where-Object {$_.Path -and $_.Path -notlike '*system32*'} | Select-Object -ExpandProperty Path -Unique"') do (
|
||||
icacls "%%x" 2>nul | findstr /i "(F) (M) (W) :\\" | findstr /i ":\\ everyone authenticated users todos %username%" && ECHO.
|
||||
)
|
||||
)
|
||||
ECHO.
|
||||
ECHO. [i] Checking directory permissions of running processes (DLL injection)
|
||||
for /f "tokens=2 delims='='" %%x in ('wmic process list full^|find /i "executablepath"^|find /i /v "system32"^|find ":"') do for /f eol^=^"^ delims^=^" %%y in ('ECHO.%%x') do (
|
||||
icacls "%%~dpy\" 2>nul | findstr /i "(F) (M) (W) :\\" | findstr /i ":\\ everyone authenticated users todos %username%" && ECHO.
|
||||
where wmic >nul 2>&1
|
||||
if %errorlevel% equ 0 (
|
||||
for /f "tokens=2 delims='='" %%x in ('wmic process list full ^|find /i "executablepath"^|find /i /v "system32"^|find ":"') do for /f eol^=^"^ delims^=^" %%y in ('ECHO.%%x') do (
|
||||
icacls "%%~dpy\" 2>nul | findstr /i "(F) (M) (W) :\\" | findstr /i ":\\ everyone authenticated users todos %username%" && ECHO.
|
||||
)
|
||||
) else (
|
||||
for /f "tokens=*" %%x in ('powershell -command "Get-Process | Where-Object {$_.Path -and $_.Path -notlike '*system32*'} | Select-Object -ExpandProperty Path -Unique"') do (
|
||||
for /f "delims=" %%d in ("%%~dpx") do icacls "%%d" 2>nul | findstr /i "(F) (M) (W) :\\" | findstr /i ":\\ everyone authenticated users todos %username%" && ECHO.
|
||||
)
|
||||
)
|
||||
ECHO.
|
||||
CALL :T_Progress 3
|
||||
@@ -376,7 +405,7 @@ CALL :T_Progress 1
|
||||
|
||||
:BasicUserInfo
|
||||
CALL :ColorLine "%E%32m[*]%E%97m BASIC USER INFO
|
||||
ECHO. [i] Check if you are inside the Administrators group or if you have enabled any token that can be use to escalate privileges like SeImpersonatePrivilege, SeAssignPrimaryPrivilege, SeTcbPrivilege, SeBackupPrivilege, SeRestorePrivilege, SeCreateTokenPrivilege, SeLoadDriverPrivilege, SeTakeOwnershipPrivilege, SeDebbugPrivilege
|
||||
ECHO. [i] Check if you are inside the Administrators group or if you have enabled any token that can be use to escalate privileges like SeImpersonatePrivilege, SeAssignPrimaryPrivilege, SeTcbPrivilege, SeBackupPrivilege, SeRestorePrivilege, SeCreateTokenPrivilege, SeLoadDriverPrivilege, SeTakeOwnershipPrivilege, SeDebugPrivilege
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#users--groups
|
||||
ECHO.
|
||||
CALL :ColorLine " %E%33m[+]%E%97m CURRENT USER"
|
||||
@@ -452,8 +481,19 @@ ECHO.
|
||||
:ServiceBinaryPermissions
|
||||
CALL :ColorLine " %E%33m[+]%E%97m SERVICE BINARY PERMISSIONS WITH WMIC and ICACLS"
|
||||
ECHO. [?] https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#services
|
||||
for /f "tokens=2 delims='='" %%a in ('cmd.exe /c wmic service list full ^| findstr /i "pathname" ^|findstr /i /v "system32"') do (
|
||||
for /f eol^=^"^ delims^=^" %%b in ("%%a") do icacls "%%b" 2>nul | findstr /i "(F) (M) (W) :\\" | findstr /i ":\\ everyone authenticated users todos usuarios %username%" && ECHO.
|
||||
where wmic >nul 2>&1
|
||||
if %errorlevel% equ 0 (
|
||||
for /f "tokens=2 delims='='" %%a in ('cmd.exe /c wmic service list full ^| findstr /i "pathname" ^|findstr /i /v "system32"') do (
|
||||
for /f eol^=^"^ delims^=^" %%b in ("%%a") do icacls "%%b" 2>nul | findstr /i "(F) (M) (W) :\\" | findstr /i ":\\ everyone authenticated users todos usuarios %username%" && ECHO.
|
||||
)
|
||||
) else (
|
||||
for /f "tokens=*" %%a in ('powershell -command "Get-CimInstance -ClassName Win32_Service | Where-Object {$_.PathName -and $_.PathName -notlike '*system32*'} | Select-Object -ExpandProperty PathName"') do (
|
||||
for /f "tokens=1 delims= " %%b in ("%%a") do (
|
||||
set "svcpath=%%b"
|
||||
set "svcpath=!svcpath:~1,-1!"
|
||||
if exist "!svcpath!" icacls "!svcpath!" 2>nul | findstr /i "(F) (M) (W) :\\" | findstr /i ":\\ everyone authenticated users todos usuarios %username%" && ECHO.
|
||||
)
|
||||
)
|
||||
)
|
||||
ECHO.
|
||||
CALL :T_Progress 1
|
||||
@@ -628,16 +668,29 @@ if "%long%" == "true" (
|
||||
ECHO.
|
||||
ECHO. [i] Iterating through the drives
|
||||
ECHO.
|
||||
for /f %%x in ('wmic logicaldisk get name^| more') do (
|
||||
set tdrive=%%x
|
||||
if "!tdrive:~1,2!" == ":" (
|
||||
%%x
|
||||
CALL :ColorLine " %E%33m[+]%E%97m FILES THAT CONTAINS THE WORD PASSWORD WITH EXTENSION: .xml .ini .txt *.cfg *.config"
|
||||
findstr /s/n/m/i password *.xml *.ini *.txt *.cfg *.config 2>nul | findstr /v /i "\\AppData\\Local \\WinSxS ApnDatabase.xml \\UEV\\InboxTemplates \\Microsoft.Windows.Cloud \\Notepad\+\+\\ vmware cortana alphabet \\7-zip\\" 2>nul
|
||||
ECHO.
|
||||
CALL :ColorLine " %E%33m[+]%E%97m FILES WHOSE NAME CONTAINS THE WORD PASS CRED or .config not inside \Windows\"
|
||||
dir /s/b *pass* == *cred* == *.config* == *.cfg 2>nul | findstr /v /i "\\windows\\"
|
||||
ECHO.
|
||||
where wmic >nul 2>&1
|
||||
if !errorlevel! equ 0 (
|
||||
for /f %%x in ('wmic logicaldisk get name') do (
|
||||
set tdrive=%%x
|
||||
if "!tdrive:~1,2!" == ":" (
|
||||
%%x
|
||||
CALL :ColorLine " %E%33m[+]%E%97m FILES THAT CONTAINS THE WORD PASSWORD WITH EXTENSION: .xml .ini .txt *.cfg *.config"
|
||||
findstr /s/n/m/i password *.xml *.ini *.txt *.cfg *.config 2>nul | findstr /v /i "\\AppData\\Local \\WinSxS ApnDatabase.xml \\UEV\\InboxTemplates \\Microsoft.Windows.Cloud \\Notepad\+\+\\ vmware cortana alphabet \\7-zip\\" 2>nul
|
||||
ECHO.
|
||||
CALL :ColorLine " %E%33m[+]%E%97m FILES WHOSE NAME CONTAINS THE WORD PASS CRED or .config not inside \Windows\"
|
||||
dir /s/b *pass* == *cred* == *.config* == *.cfg 2>nul | findstr /v /i "\\windows\\"
|
||||
ECHO.
|
||||
)
|
||||
)
|
||||
) else (
|
||||
for /f %%x in ('powershell -command "Get-PSDrive -PSProvider FileSystem | Where-Object {$_.Root -match ':'} | Select-Object -ExpandProperty Name"') do (
|
||||
%%x:
|
||||
CALL :ColorLine " %E%33m[+]%E%97m FILES THAT CONTAINS THE WORD PASSWORD WITH EXTENSION: .xml .ini .txt *.cfg *.config"
|
||||
findstr /s/n/m/i password *.xml *.ini *.txt *.cfg *.config 2>nul | findstr /v /i "\\AppData\\Local \\WinSxS ApnDatabase.xml \\UEV\\InboxTemplates \\Microsoft.Windows.Cloud \\Notepad\+\+\\ vmware cortana alphabet \\7-zip\\" 2>nul
|
||||
ECHO.
|
||||
CALL :ColorLine " %E%33m[+]%E%97m FILES WHOSE NAME CONTAINS THE WORD PASS CRED or .config not inside \Windows\"
|
||||
dir /s/b *pass* == *cred* == *.config* == *.cfg 2>nul | findstr /v /i "\\windows\\"
|
||||
ECHO.
|
||||
)
|
||||
)
|
||||
CALL :T_Progress 2
|
||||
@@ -654,7 +707,8 @@ EXIT /B
|
||||
|
||||
:SetOnce
|
||||
REM :: ANSI escape character is set once below - for ColorLine Subroutine
|
||||
SET "E=0x1B["
|
||||
for /F %%a in ('echo prompt $E ^| cmd') do set "ESC=%%a"
|
||||
SET "E=%ESC%["
|
||||
SET "PercentageTrack=0"
|
||||
EXIT /B
|
||||
|
||||
@@ -666,5 +720,5 @@ EXIT /B
|
||||
|
||||
:ColorLine
|
||||
SET "CurrentLine=%~1"
|
||||
FOR /F "delims=" %%A IN ('FORFILES.EXE /P %~dp0 /M %~nx0 /C "CMD /C ECHO.!CurrentLine!"') DO ECHO.%%A
|
||||
ECHO.!CurrentLine!
|
||||
EXIT /B
|
||||
|
||||
26
winPEAS/winPEASexe/CMakeLists.txt
Normal file
26
winPEAS/winPEASexe/CMakeLists.txt
Normal file
@@ -0,0 +1,26 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(winPEAS_dotnet NONE)
|
||||
|
||||
set(PROJECT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/winPEAS.csproj")
|
||||
|
||||
find_program(DOTNET_EXECUTABLE dotnet)
|
||||
find_program(MSBUILD_EXECUTABLE msbuild)
|
||||
find_program(XBUILD_EXECUTABLE xbuild)
|
||||
|
||||
if(DOTNET_EXECUTABLE)
|
||||
set(BUILD_TOOL "${DOTNET_EXECUTABLE}")
|
||||
set(BUILD_ARGS build "${PROJECT_FILE}" -c Release)
|
||||
elseif(MSBUILD_EXECUTABLE)
|
||||
set(BUILD_TOOL "${MSBUILD_EXECUTABLE}")
|
||||
set(BUILD_ARGS "${PROJECT_FILE}" /p:Configuration=Release)
|
||||
elseif(XBUILD_EXECUTABLE)
|
||||
set(BUILD_TOOL "${XBUILD_EXECUTABLE}")
|
||||
set(BUILD_ARGS "${PROJECT_FILE}" /p:Configuration=Release)
|
||||
else()
|
||||
message(FATAL_ERROR "dotnet, msbuild, or xbuild is required to build winPEAS")
|
||||
endif()
|
||||
|
||||
add_custom_target(winpeas ALL
|
||||
COMMAND ${BUILD_TOOL} ${BUILD_ARGS}
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
)
|
||||
@@ -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,16 @@ 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.
|
||||
|
||||
- Flag installed OEM utilities such as ASUS DriverHub, MSI Center, Acer Control Centre and Razer Synapse 4, highlighting writable updater folders and world-accessible pipes tied to recent CVEs.
|
||||
|
||||
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)**.
|
||||
|
||||
|
||||
## 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):
|
||||
@@ -122,7 +128,7 @@ Once you have installed and activated it you need to:
|
||||
|
||||
- **System Information**
|
||||
- [x] Basic System info information
|
||||
- [x] Use Watson to search for vulnerabilities
|
||||
- [x] Use WES-NG to search for vulnerabilities
|
||||
- [x] Enumerate Microsoft updates
|
||||
- [x] PS, Audit, WEF and LAPS Settings
|
||||
- [x] LSA protection
|
||||
@@ -140,6 +146,7 @@ Once you have installed and activated it you need to:
|
||||
- [x] Applocker Configuration & bypass suggestions
|
||||
- [x] Printers
|
||||
- [x] Named Pipes
|
||||
- [x] Named Pipe ACL abuse candidates
|
||||
- [x] AMSI Providers
|
||||
- [x] SysMon
|
||||
- [x] .NET Versions
|
||||
@@ -204,7 +211,7 @@ Once you have installed and activated it you need to:
|
||||
- [x] SCCM
|
||||
- [x] Security Package Credentials
|
||||
- [x] AlwaysInstallElevated
|
||||
- [x] WSUS
|
||||
- [x] WSUS (HTTP downgrade + CVE-2025-59287 exposure)
|
||||
|
||||
- **Browser Information**
|
||||
- [x] Firefox DBs
|
||||
@@ -255,7 +262,7 @@ Once you have installed and activated it you need to:
|
||||
|
||||
## TODO
|
||||
- Add more checks
|
||||
- Mantain updated Watson (last JAN 2021)
|
||||
- Maintain updated WES-NG
|
||||
|
||||
If you want to help with any of this, you can do it using **[github issues](https://github.com/peass-ng/PEASS-ng/issues)** or you can submit a pull request.
|
||||
|
||||
|
||||
@@ -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" />
|
||||
|
||||
36
winPEAS/winPEASexe/Tests/ArgumentParsingTests.cs
Normal file
36
winPEAS/winPEASexe/Tests/ArgumentParsingTests.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace winPEAS.Tests
|
||||
{
|
||||
[TestClass]
|
||||
public class ArgumentParsingTests
|
||||
{
|
||||
private static bool InvokeIsNetworkTypeValid(string arg)
|
||||
{
|
||||
var method = typeof(winPEAS.Checks.Checks).GetMethod("IsNetworkTypeValid", BindingFlags.NonPublic | BindingFlags.Static);
|
||||
Assert.IsNotNull(method, "IsNetworkTypeValid method not found.");
|
||||
return (bool)method.Invoke(null, new object[] { arg });
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ShouldAcceptValidNetworkTypes()
|
||||
{
|
||||
Assert.IsTrue(InvokeIsNetworkTypeValid("-network=auto"));
|
||||
Assert.IsTrue(InvokeIsNetworkTypeValid("-network=10.10.10.10"));
|
||||
Assert.IsTrue(InvokeIsNetworkTypeValid("-network=10.10.10.10/24"));
|
||||
Assert.IsTrue(InvokeIsNetworkTypeValid("-network=10.10.10.10,10.10.10.20"));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ShouldRejectInvalidNetworkTypes()
|
||||
{
|
||||
Assert.IsFalse(InvokeIsNetworkTypeValid("-network="));
|
||||
Assert.IsFalse(InvokeIsNetworkTypeValid("-network=10.10.10.999"));
|
||||
Assert.IsFalse(InvokeIsNetworkTypeValid("-network=10.10.10.10/64"));
|
||||
Assert.IsFalse(InvokeIsNetworkTypeValid("-network=999.999.999.999/24"));
|
||||
Assert.IsFalse(InvokeIsNetworkTypeValid("-network=not-an-ip"));
|
||||
}
|
||||
}
|
||||
}
|
||||
37
winPEAS/winPEASexe/Tests/ChecksArgumentEdgeCasesTests.cs
Normal file
37
winPEAS/winPEASexe/Tests/ChecksArgumentEdgeCasesTests.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace winPEAS.Tests
|
||||
{
|
||||
[TestClass]
|
||||
public class ChecksArgumentEdgeCasesTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void ShouldNotThrowOnEmptyLogFileArg()
|
||||
{
|
||||
// Should return early with a user-friendly error, not crash.
|
||||
Program.Main(new[] { "log=" });
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ShouldNotThrowOnPortsWithoutNetwork()
|
||||
{
|
||||
// Should warn and return early because -network was not provided.
|
||||
Program.Main(new[] { "-ports=80,443" });
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ShouldNotThrowOnInvalidNetworkArgument()
|
||||
{
|
||||
// Should warn and return early because the IP is invalid.
|
||||
Program.Main(new[] { "-network=10.10.10.999" });
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ShouldNotThrowOnEmptyNetworkArgument()
|
||||
{
|
||||
// Should warn and return early because the value is empty.
|
||||
Program.Main(new[] { "-network=" });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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" />
|
||||
|
||||
@@ -61,9 +61,11 @@
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MSTest.TestFramework.2.2.5\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MSTest.TestFramework.2.2.5\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.ComponentModel.Composition" />
|
||||
@@ -83,6 +85,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" />
|
||||
@@ -91,6 +97,7 @@
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ArgumentParsingTests.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="SmokeTests.cs" />
|
||||
</ItemGroup>
|
||||
@@ -104,6 +111,40 @@
|
||||
<Name>winPEAS</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="CopyVSTestFrameworkToMSTestAdapter" AfterTargets="Build">
|
||||
<PropertyGroup>
|
||||
<_PackagesDir>$(MSBuildThisFileDirectory)..\packages\</_PackagesDir>
|
||||
<_MSTestFrameworkDir>$(_PackagesDir)MSTest.TestFramework.2.2.5\lib\net45\</_MSTestFrameworkDir>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition="Exists('$(_MSTestFrameworkDir)')">
|
||||
<_VSTestFrameworkDlls Include="$(_MSTestFrameworkDir)Microsoft.VisualStudio.TestPlatform.TestFramework*.dll" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<_VSTestCopyDirs Include="$(TargetDir)" Condition="'$(TargetDir)' != '' AND Exists('$(TargetDir)')" />
|
||||
<_MSTestAdapterDirs Include="$(_PackagesDir)MSTest.TestAdapter.2.2.5\build\net45\" Condition="Exists('$(_PackagesDir)MSTest.TestAdapter.2.2.5\build\net45\')" />
|
||||
<_MSTestAdapterDirs Include="$(_PackagesDir)MSTest.TestAdapter.2.2.5\build\_common\" Condition="Exists('$(_PackagesDir)MSTest.TestAdapter.2.2.5\build\_common\')" />
|
||||
</ItemGroup>
|
||||
|
||||
<Message
|
||||
Condition="@(_VSTestFrameworkDlls) != ''"
|
||||
Importance="high"
|
||||
Text="CopyVSTestFrameworkToMSTestAdapter: copying @( _VSTestFrameworkDlls )" />
|
||||
|
||||
<Copy
|
||||
Condition="@(_VSTestFrameworkDlls) != '' AND @(_VSTestCopyDirs) != ''"
|
||||
SourceFiles="@(_VSTestFrameworkDlls)"
|
||||
DestinationFolder="%(_VSTestCopyDirs.Identity)"
|
||||
SkipUnchangedFiles="true" />
|
||||
|
||||
<Copy
|
||||
Condition="@(_VSTestFrameworkDlls) != '' AND @(_MSTestAdapterDirs) != ''"
|
||||
SourceFiles="@(_VSTestFrameworkDlls)"
|
||||
DestinationFolder="%(_MSTestAdapterDirs.Identity)"
|
||||
SkipUnchangedFiles="true" />
|
||||
</Target>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
@@ -129,4 +170,4 @@
|
||||
<Import Project="..\packages\Stub.System.Data.SQLite.Core.NetFramework.1.0.119.0\build\net451\Stub.System.Data.SQLite.Core.NetFramework.targets" Condition="Exists('..\packages\Stub.System.Data.SQLite.Core.NetFramework.1.0.119.0\build\net451\Stub.System.Data.SQLite.Core.NetFramework.targets')" />
|
||||
<Import Project="..\packages\Fody.6.5.5\build\Fody.targets" Condition="Exists('..\packages\Fody.6.5.5\build\Fody.targets')" />
|
||||
<Import Project="..\packages\Costura.Fody.5.7.0\build\Costura.Fody.targets" Condition="Exists('..\packages\Costura.Fody.5.7.0\build\Costura.Fody.targets')" />
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -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" />
|
||||
|
||||
1391
winPEAS/winPEASexe/winPEAS/Checks/ActiveDirectoryInfo.cs
Normal file
1391
winPEAS/winPEASexe/winPEAS/Checks/ActiveDirectoryInfo.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -88,10 +88,13 @@ namespace winPEAS.Checks
|
||||
new SystemCheck("userinfo", new UserInfo()),
|
||||
new SystemCheck("processinfo", new ProcessInfo()),
|
||||
new SystemCheck("servicesinfo", new ServicesInfo()),
|
||||
new SystemCheck("soapclientinfo", new SoapClientInfo()),
|
||||
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("registryinfo", new RegistryInfo()),
|
||||
new SystemCheck("browserinfo", new BrowserInfo()),
|
||||
new SystemCheck("filesinfo", new FilesInfo()),
|
||||
new SystemCheck("fileanalysis", new FileAnalysis()),
|
||||
@@ -353,7 +356,7 @@ namespace winPEAS.Checks
|
||||
{
|
||||
var rangeParts = networkType.Split('/');
|
||||
|
||||
if (rangeParts.Length == 2 && int.TryParse(rangeParts[1], out int res) && res <= 32 && res >= 0)
|
||||
if (rangeParts.Length == 2 && IPAddress.TryParse(rangeParts[0], out _) && int.TryParse(rangeParts[1], out int res) && res <= 32 && res >= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -392,7 +392,7 @@ namespace winPEAS.Checks
|
||||
|
||||
foreach (string regHkcu in passRegHkcu)
|
||||
{
|
||||
Beaprint.DictPrint(RegistryHelper.GetRegValues("HKLM", regHkcu), false);
|
||||
Beaprint.DictPrint(RegistryHelper.GetRegValues("HKCU", regHkcu), false);
|
||||
}
|
||||
|
||||
foreach (string regHklm in passRegHklm)
|
||||
@@ -524,7 +524,7 @@ namespace winPEAS.Checks
|
||||
{
|
||||
Beaprint.MainPrint("Looking for documents --limit 100--");
|
||||
List<string> docFiles = InterestingFiles.InterestingFiles.ListUsersDocs();
|
||||
Beaprint.ListPrint(docFiles.GetRange(0, docFiles.Count <= 100 ? docFiles.Count : 100));
|
||||
Beaprint.ListPrint(MyUtils.GetLimitedRange(docFiles, 100));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -546,7 +546,7 @@ namespace winPEAS.Checks
|
||||
|
||||
if (recFiles.Count != 0)
|
||||
{
|
||||
foreach (Dictionary<string, string> recF in recFiles.GetRange(0, recFiles.Count <= 70 ? recFiles.Count : 70))
|
||||
foreach (Dictionary<string, string> recF in MyUtils.GetLimitedRange(recFiles, 70))
|
||||
{
|
||||
Beaprint.AnsiPrint(" " + recF["Target"] + "(" + recF["Accessed"] + ")", colorF);
|
||||
}
|
||||
|
||||
@@ -348,8 +348,7 @@ namespace winPEAS.Checks
|
||||
Beaprint.MainPrint("DNS cached --limit 70--");
|
||||
Beaprint.GrayPrint(string.Format(" {0,-38}{1,-38}{2}", "Entry", "Name", "Data"));
|
||||
List<Dictionary<string, string>> DNScache = NetworkInfoHelper.GetDNSCache();
|
||||
foreach (Dictionary<string, string> entry in DNScache.GetRange(0,
|
||||
DNScache.Count <= 70 ? DNScache.Count : 70))
|
||||
foreach (Dictionary<string, string> entry in MyUtils.GetLimitedRange(DNScache, 70))
|
||||
{
|
||||
Console.WriteLine($" {entry["Entry"],-38}{entry["Name"],-38}{entry["Data"]}");
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
141
winPEAS/winPEASexe/winPEAS/Checks/RegistryInfo.cs
Normal file
141
winPEAS/winPEASexe/winPEAS/Checks/RegistryInfo.cs
Normal file
@@ -0,0 +1,141 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using winPEAS.Helpers;
|
||||
using winPEAS.Helpers.Registry;
|
||||
|
||||
namespace winPEAS.Checks
|
||||
{
|
||||
internal class RegistryInfo : ISystemCheck
|
||||
{
|
||||
private const string TypingInsightsRelativePath = @"Software\Microsoft\Input\TypingInsights";
|
||||
|
||||
private static readonly string[] KnownWritableSystemKeyCandidates = new[]
|
||||
{
|
||||
@"SOFTWARE\Microsoft\CoreShell",
|
||||
@"SOFTWARE\Microsoft\DRM",
|
||||
@"SOFTWARE\Microsoft\Input\Locales",
|
||||
@"SOFTWARE\Microsoft\Input\Settings",
|
||||
@"SOFTWARE\Microsoft\Shell\Oobe",
|
||||
@"SOFTWARE\Microsoft\Shell\Session",
|
||||
@"SOFTWARE\Microsoft\Tracing",
|
||||
@"SOFTWARE\Microsoft\Windows\UpdateApi",
|
||||
@"SOFTWARE\Microsoft\WindowsUpdate\UX",
|
||||
@"SOFTWARE\WOW6432Node\Microsoft\DRM",
|
||||
@"SOFTWARE\WOW6432Node\Microsoft\Tracing",
|
||||
@"SYSTEM\Software\Microsoft\TIP",
|
||||
@"SYSTEM\ControlSet001\Control\Cryptography\WebSignIn\Navigation",
|
||||
@"SYSTEM\ControlSet001\Control\MUI\StringCacheSettings",
|
||||
@"SYSTEM\ControlSet001\Control\USB\AutomaticSurpriseRemoval",
|
||||
@"SYSTEM\ControlSet001\Services\BTAGService\Parameters\Settings",
|
||||
};
|
||||
|
||||
private static readonly string[] ScanBasePaths = new[]
|
||||
{
|
||||
@"SOFTWARE\Microsoft",
|
||||
@"SOFTWARE\WOW6432Node\Microsoft",
|
||||
@"SYSTEM\CurrentControlSet\Services",
|
||||
@"SYSTEM\CurrentControlSet\Control",
|
||||
@"SYSTEM\ControlSet001\Control",
|
||||
};
|
||||
|
||||
public void PrintInfo(bool isDebug)
|
||||
{
|
||||
Beaprint.GreatPrint("Registry permissions for hive exploitation");
|
||||
|
||||
new List<Action>
|
||||
{
|
||||
PrintTypingInsightsPermissions,
|
||||
PrintKnownSystemWritableKeys,
|
||||
PrintHeuristicWritableKeys,
|
||||
}.ForEach(action => CheckRunner.Run(action, isDebug));
|
||||
}
|
||||
|
||||
private void PrintTypingInsightsPermissions()
|
||||
{
|
||||
Beaprint.MainPrint("Cross-user TypingInsights key (HKCU/HKU)");
|
||||
|
||||
var matches = new List<RegistryWritableKeyInfo>();
|
||||
var seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
if (RegistryAclScanner.TryGetWritableKey("HKCU", TypingInsightsRelativePath, out var currentUserKey))
|
||||
{
|
||||
if (seen.Add(currentUserKey.FullPath))
|
||||
{
|
||||
matches.Add(currentUserKey);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var sid in RegistryHelper.GetUserSIDs())
|
||||
{
|
||||
if (string.IsNullOrEmpty(sid) || sid.Equals(".DEFAULT", StringComparison.OrdinalIgnoreCase) || sid.EndsWith("_Classes", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string relativePath = $"{sid}\\{TypingInsightsRelativePath}";
|
||||
if (RegistryAclScanner.TryGetWritableKey("HKU", relativePath, out var info) && seen.Add(info.FullPath))
|
||||
{
|
||||
matches.Add(info);
|
||||
}
|
||||
}
|
||||
|
||||
if (matches.Count == 0)
|
||||
{
|
||||
Beaprint.GrayPrint(" [-] TypingInsights key does not grant write access to low-privileged groups.");
|
||||
return;
|
||||
}
|
||||
|
||||
PrintEntries(matches);
|
||||
Beaprint.LinkPrint("https://projectzero.google/2025/05/the-windows-registry-adventure-8-exploitation.html", "Writable TypingInsights enables cross-user hive tampering and DoS.");
|
||||
}
|
||||
|
||||
private void PrintKnownSystemWritableKeys()
|
||||
{
|
||||
Beaprint.MainPrint("Known HKLM descendants writable by standard users");
|
||||
|
||||
var matches = new List<RegistryWritableKeyInfo>();
|
||||
foreach (var path in KnownWritableSystemKeyCandidates)
|
||||
{
|
||||
if (RegistryAclScanner.TryGetWritableKey("HKLM", path, out var info))
|
||||
{
|
||||
matches.Add(info);
|
||||
}
|
||||
}
|
||||
|
||||
if (matches.Count == 0)
|
||||
{
|
||||
Beaprint.GrayPrint(" [-] None of the tracked HKLM keys are writable by low-privileged groups.");
|
||||
return;
|
||||
}
|
||||
|
||||
PrintEntries(matches);
|
||||
}
|
||||
|
||||
private void PrintHeuristicWritableKeys()
|
||||
{
|
||||
Beaprint.MainPrint("Sample of additional writable HKLM keys (depth-limited scan)");
|
||||
|
||||
var matches = RegistryAclScanner.ScanWritableKeys("HKLM", ScanBasePaths, maxDepth: 3, maxResults: 25);
|
||||
if (matches.Count == 0)
|
||||
{
|
||||
Beaprint.GrayPrint(" [-] No additional writable HKLM keys were found within the sampled paths.");
|
||||
return;
|
||||
}
|
||||
|
||||
PrintEntries(matches);
|
||||
Beaprint.GrayPrint(" [*] Showing up to 25 entries from the sampled paths to avoid noisy output.");
|
||||
}
|
||||
|
||||
private static void PrintEntries(IEnumerable<RegistryWritableKeyInfo> entries)
|
||||
{
|
||||
foreach (var entry in entries)
|
||||
{
|
||||
var principals = string.Join(", ", entry.Principals);
|
||||
var rights = entry.Rights.Count > 0 ? string.Join(", ", entry.Rights.Distinct(StringComparer.OrdinalIgnoreCase)) : "Write access";
|
||||
var displayPath = string.IsNullOrEmpty(entry.FullPath) ? $"{entry.Hive}\\{entry.RelativePath}" : entry.FullPath;
|
||||
Beaprint.BadPrint($" [!] {displayPath} -> {principals} ({rights})");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using winPEAS.Helpers;
|
||||
using winPEAS.Helpers.Registry;
|
||||
using winPEAS.Info.ServicesInfo;
|
||||
|
||||
namespace winPEAS.Checks
|
||||
@@ -34,6 +36,9 @@ namespace winPEAS.Checks
|
||||
PrintModifiableServices,
|
||||
PrintWritableRegServices,
|
||||
PrintPathDllHijacking,
|
||||
PrintOemPrivilegedUtilities,
|
||||
PrintLegacySignedKernelDrivers,
|
||||
PrintKernelQuickIndicators,
|
||||
}.ForEach(action => CheckRunner.Run(action, isDebug));
|
||||
}
|
||||
|
||||
@@ -206,5 +211,190 @@ namespace winPEAS.Checks
|
||||
}
|
||||
}
|
||||
|
||||
void PrintOemPrivilegedUtilities()
|
||||
{
|
||||
try
|
||||
{
|
||||
Beaprint.MainPrint("OEM privileged utilities & risky components");
|
||||
var findings = OemSoftwareHelper.GetPotentiallyVulnerableComponents(Checks.CurrentUserSiDs);
|
||||
|
||||
if (findings.Count == 0)
|
||||
{
|
||||
Beaprint.GoodPrint(" None of the supported OEM utilities were detected.");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var finding in findings)
|
||||
{
|
||||
bool hasCves = finding.Cves != null && finding.Cves.Length > 0;
|
||||
string cveSuffix = hasCves ? $" ({string.Join(", ", finding.Cves)})" : string.Empty;
|
||||
Beaprint.BadPrint($" {finding.Name}{cveSuffix}");
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(finding.Description))
|
||||
{
|
||||
Beaprint.GrayPrint($" {finding.Description}");
|
||||
}
|
||||
|
||||
foreach (var evidence in finding.Evidence)
|
||||
{
|
||||
string message = $" - {evidence.Message}";
|
||||
if (evidence.Highlight)
|
||||
{
|
||||
Beaprint.BadPrint(message);
|
||||
}
|
||||
else
|
||||
{
|
||||
Beaprint.GrayPrint(message);
|
||||
}
|
||||
}
|
||||
|
||||
Beaprint.PrintLineSeparator();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Beaprint.PrintException(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
void PrintLegacySignedKernelDrivers()
|
||||
{
|
||||
try
|
||||
{
|
||||
Beaprint.MainPrint("Kernel drivers with weak/legacy signatures");
|
||||
Beaprint.LinkPrint("https://research.checkpoint.com/2025/cracking-valleyrat-from-builder-secrets-to-kernel-rootkits/",
|
||||
"Legacy cross-signed drivers (pre-July-2015) can still grant kernel execution on modern Windows");
|
||||
|
||||
List<ServicesInfoHelper.KernelDriverInfo> drivers = ServicesInfoHelper.GetKernelDriverInfos();
|
||||
if (drivers.Count == 0)
|
||||
{
|
||||
Beaprint.InfoPrint(" Unable to enumerate kernel services");
|
||||
return;
|
||||
}
|
||||
|
||||
var suspiciousDrivers = drivers.Where(d => d.Signature != null && (!d.Signature.IsSigned || d.Signature.IsLegacyExpired))
|
||||
.OrderBy(d => d.Name)
|
||||
.ToList();
|
||||
|
||||
if (suspiciousDrivers.Count == 0)
|
||||
{
|
||||
Beaprint.InfoPrint(" No unsigned or legacy-signed kernel drivers detected");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var driver in suspiciousDrivers)
|
||||
{
|
||||
var signature = driver.Signature ?? new ServicesInfoHelper.KernelDriverSignatureInfo();
|
||||
List<string> reasons = new List<string>();
|
||||
|
||||
if (!signature.IsSigned)
|
||||
{
|
||||
reasons.Add("unsigned or signature missing");
|
||||
}
|
||||
else if (signature.IsLegacyExpired)
|
||||
{
|
||||
reasons.Add("signed with certificate that expired before 29-Jul-2015 (legacy exception)");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(driver.StartMode) &&
|
||||
(driver.StartMode.Equals("System", StringComparison.OrdinalIgnoreCase) ||
|
||||
driver.StartMode.Equals("Boot", StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
reasons.Add($"loads at early boot (Start={driver.StartMode})");
|
||||
}
|
||||
|
||||
if (string.Equals(driver.Name, "kernelquick", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
reasons.Add("service name matches ValleyRAT rootkit loader");
|
||||
}
|
||||
|
||||
string reason = reasons.Count > 0 ? string.Join("; ", reasons) : "Potentially risky driver";
|
||||
string signatureLine = signature.IsSigned
|
||||
? $"Subject: {signature.Subject}; Issuer: {signature.Issuer}; Valid: {FormatDate(signature.NotBefore)} - {FormatDate(signature.NotAfter)}"
|
||||
: $"Signature issue: {signature.Error ?? "Unsigned"}";
|
||||
|
||||
Beaprint.BadPrint($" {driver.Name} ({driver.DisplayName})");
|
||||
Beaprint.NoColorPrint($" Path : {driver.PathName}");
|
||||
Beaprint.NoColorPrint($" Start/State: {driver.StartMode}/{driver.State}");
|
||||
Beaprint.NoColorPrint($" Reason : {reason}");
|
||||
Beaprint.NoColorPrint($" Signature : {signatureLine}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Beaprint.PrintException(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
void PrintKernelQuickIndicators()
|
||||
{
|
||||
try
|
||||
{
|
||||
Beaprint.MainPrint("KernelQuick / ValleyRAT rootkit indicators");
|
||||
|
||||
bool found = false;
|
||||
|
||||
Dictionary<string, object> serviceValues = RegistryHelper.GetRegValues("HKLM", @"SYSTEM\\CurrentControlSet\\Services\\kernelquick");
|
||||
if (serviceValues != null)
|
||||
{
|
||||
found = true;
|
||||
string imagePath = serviceValues.ContainsKey("ImagePath") ? serviceValues["ImagePath"].ToString() : "Unknown";
|
||||
string start = serviceValues.ContainsKey("Start") ? serviceValues["Start"].ToString() : "Unknown";
|
||||
Beaprint.BadPrint(" Service HKLM\\SYSTEM\\CurrentControlSet\\Services\\kernelquick present");
|
||||
Beaprint.NoColorPrint($" ImagePath : {imagePath}");
|
||||
Beaprint.NoColorPrint($" Start : {start}");
|
||||
}
|
||||
|
||||
foreach (var path in new[] { @"SOFTWARE\\KernelQuick", @"SOFTWARE\\WOW6432Node\\KernelQuick", @"SYSTEM\\CurrentControlSet\\Services\\kernelquick" })
|
||||
{
|
||||
Dictionary<string, object> values = RegistryHelper.GetRegValues("HKLM", path);
|
||||
if (values == null)
|
||||
continue;
|
||||
|
||||
var kernelQuickValues = values.Where(k => k.Key.StartsWith("KernelQuick_", StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
if (kernelQuickValues.Count == 0)
|
||||
continue;
|
||||
|
||||
found = true;
|
||||
Beaprint.BadPrint($" Registry values under HKLM\\{path}");
|
||||
foreach (var kv in kernelQuickValues)
|
||||
{
|
||||
string displayValue = kv.Value is byte[] bytes ? $"(binary) {bytes.Length} bytes" : string.Format("{0}", kv.Value);
|
||||
Beaprint.NoColorPrint($" {kv.Key} = {displayValue}");
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary<string, object> ipdatesValues = RegistryHelper.GetRegValues("HKLM", @"SOFTWARE\\IpDates");
|
||||
if (ipdatesValues != null)
|
||||
{
|
||||
found = true;
|
||||
Beaprint.BadPrint(" Possible kernel shellcode staging key HKLM\\SOFTWARE\\IpDates");
|
||||
foreach (var kv in ipdatesValues)
|
||||
{
|
||||
string displayValue = kv.Value is byte[] bytes ? $"(binary) {bytes.Length} bytes" : string.Format("{0}", kv.Value);
|
||||
Beaprint.NoColorPrint($" {kv.Key} = {displayValue}");
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
Beaprint.InfoPrint(" No KernelQuick-specific registry indicators were found");
|
||||
}
|
||||
else
|
||||
{
|
||||
Beaprint.LinkPrint("https://research.checkpoint.com/2025/cracking-valleyrat-from-builder-secrets-to-kernel-rootkits/",
|
||||
"KernelQuick_* values and HKLM\\SOFTWARE\\IpDates are used by the ValleyRAT rootkit to hide files and stage APC payloads");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Beaprint.PrintException(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private string FormatDate(DateTime? dateTime)
|
||||
{
|
||||
return dateTime.HasValue ? dateTime.Value.ToString("yyyy-MM-dd HH:mm") : "n/a";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
88
winPEAS/winPEASexe/winPEAS/Checks/SoapClientInfo.cs
Normal file
88
winPEAS/winPEASexe/winPEAS/Checks/SoapClientInfo.cs
Normal file
@@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using winPEAS.Helpers;
|
||||
using winPEAS.Info.ApplicationInfo;
|
||||
|
||||
namespace winPEAS.Checks
|
||||
{
|
||||
internal class SoapClientInfo : ISystemCheck
|
||||
{
|
||||
public void PrintInfo(bool isDebug)
|
||||
{
|
||||
Beaprint.GreatPrint(".NET SOAP Client Proxies (SOAPwn)");
|
||||
|
||||
CheckRunner.Run(PrintSoapClientFindings, isDebug);
|
||||
}
|
||||
|
||||
private static void PrintSoapClientFindings()
|
||||
{
|
||||
try
|
||||
{
|
||||
Beaprint.MainPrint("Potential SOAPwn / HttpWebClientProtocol abuse surfaces");
|
||||
Beaprint.LinkPrint(
|
||||
"https://labs.watchtowr.com/soapwn-pwning-net-framework-applications-through-http-client-proxies-and-wsdl/",
|
||||
"Look for .NET services that let attackers control SoapHttpClientProtocol URLs or WSDL imports to coerce NTLM or drop files.");
|
||||
|
||||
List<SoapClientProxyFinding> findings = SoapClientProxyAnalyzer.CollectFindings();
|
||||
if (findings.Count == 0)
|
||||
{
|
||||
Beaprint.NotFoundPrint();
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (SoapClientProxyFinding finding in findings)
|
||||
{
|
||||
string severity = finding.BinaryIndicators.Contains("ServiceDescriptionImporter")
|
||||
? "Dynamic WSDL import"
|
||||
: "SOAP proxy usage";
|
||||
|
||||
Beaprint.BadPrint($" [{severity}] {finding.BinaryPath}");
|
||||
|
||||
foreach (SoapClientProxyInstance instance in finding.Instances)
|
||||
{
|
||||
string instanceInfo = $" -> {instance.SourceType}: {instance.Name}";
|
||||
if (!string.IsNullOrEmpty(instance.Account))
|
||||
{
|
||||
instanceInfo += $" ({instance.Account})";
|
||||
}
|
||||
if (!string.IsNullOrEmpty(instance.Extra))
|
||||
{
|
||||
instanceInfo += $" | {instance.Extra}";
|
||||
}
|
||||
|
||||
Beaprint.GrayPrint(instanceInfo);
|
||||
}
|
||||
|
||||
if (finding.BinaryIndicators.Count > 0)
|
||||
{
|
||||
Beaprint.BadPrint(" Binary indicators: " + string.Join(", ", finding.BinaryIndicators));
|
||||
}
|
||||
|
||||
if (finding.ConfigIndicators.Count > 0)
|
||||
{
|
||||
string configLabel = string.IsNullOrEmpty(finding.ConfigPath)
|
||||
? "Config indicators"
|
||||
: $"Config indicators ({finding.ConfigPath})";
|
||||
Beaprint.BadPrint(" " + configLabel + ": " + string.Join(", ", finding.ConfigIndicators));
|
||||
}
|
||||
|
||||
if (finding.BinaryScanFailed)
|
||||
{
|
||||
Beaprint.GrayPrint(" (Binary scan skipped due to access/size limits)");
|
||||
}
|
||||
|
||||
if (finding.ConfigScanFailed)
|
||||
{
|
||||
Beaprint.GrayPrint(" (Unable to read config file)");
|
||||
}
|
||||
|
||||
Beaprint.PrintLineSeparator();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Beaprint.PrintException(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Management;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.RegularExpressions;
|
||||
@@ -81,12 +82,16 @@ namespace winPEAS.Checks
|
||||
PrintKrbRelayUp,
|
||||
PrintInsideContainer,
|
||||
PrintAlwaysInstallElevated,
|
||||
PrintObjectManagerRaceAmplification,
|
||||
PrintLSAInfo,
|
||||
PrintNtlmSettings,
|
||||
PrintLocalGroupPolicy,
|
||||
PrintPotentialGPOAbuse,
|
||||
AppLockerHelper.PrintAppLockerPolicy,
|
||||
PrintPrintNightmarePointAndPrint,
|
||||
PrintPrintersWMIInfo,
|
||||
PrintNamedPipes,
|
||||
PrintNamedPipeAbuseCandidates,
|
||||
PrintAMSIProviders,
|
||||
PrintSysmon,
|
||||
PrintDotNetVersions
|
||||
@@ -560,27 +565,66 @@ namespace winPEAS.Checks
|
||||
{
|
||||
Beaprint.MainPrint("Checking WSUS");
|
||||
Beaprint.LinkPrint("https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#wsus");
|
||||
string path = "Software\\Policies\\Microsoft\\Windows\\WindowsUpdate";
|
||||
string path2 = "Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU";
|
||||
string HKLM_WSUS = RegistryHelper.GetRegValue("HKLM", path, "WUServer");
|
||||
string using_HKLM_WSUS = RegistryHelper.GetRegValue("HKLM", path2, "UseWUServer");
|
||||
if (HKLM_WSUS.Contains("http://"))
|
||||
string policyPath = "Software\\Policies\\Microsoft\\Windows\\WindowsUpdate";
|
||||
string policyAUPath = "Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU";
|
||||
string wsusPolicyValue = RegistryHelper.GetRegValue("HKLM", policyPath, "WUServer");
|
||||
string useWUServerValue = RegistryHelper.GetRegValue("HKLM", policyAUPath, "UseWUServer");
|
||||
|
||||
if (!string.IsNullOrEmpty(wsusPolicyValue) && wsusPolicyValue.StartsWith("http://", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Beaprint.BadPrint(" WSUS is using http: " + HKLM_WSUS);
|
||||
Beaprint.BadPrint(" WSUS is using http: " + wsusPolicyValue);
|
||||
Beaprint.InfoPrint("You can test https://github.com/pimps/wsuxploit to escalate privileges");
|
||||
if (using_HKLM_WSUS == "1")
|
||||
if (useWUServerValue == "1")
|
||||
Beaprint.BadPrint(" And UseWUServer is equals to 1, so it is vulnerable!");
|
||||
else if (using_HKLM_WSUS == "0")
|
||||
else if (useWUServerValue == "0")
|
||||
Beaprint.GoodPrint(" But UseWUServer is equals to 0, so it is not vulnerable!");
|
||||
else
|
||||
Console.WriteLine(" But UseWUServer is equals to " + using_HKLM_WSUS + ", so it may work or not");
|
||||
Console.WriteLine(" But UseWUServer is equals to " + useWUServerValue + ", so it may work or not");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (string.IsNullOrEmpty(HKLM_WSUS))
|
||||
if (string.IsNullOrEmpty(wsusPolicyValue))
|
||||
Beaprint.NotFoundPrint();
|
||||
else
|
||||
Beaprint.GoodPrint(" WSUS value: " + HKLM_WSUS);
|
||||
Beaprint.GoodPrint(" WSUS value: " + wsusPolicyValue);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(wsusPolicyValue))
|
||||
{
|
||||
bool clientsForced = useWUServerValue == "1";
|
||||
if (clientsForced)
|
||||
{
|
||||
Beaprint.BadPrint(" CVE-2025-59287: Clients talk to WSUS at " + wsusPolicyValue + " (UseWUServer=1). Unpatched WSUS allows unauthenticated deserialization to SYSTEM.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Beaprint.InfoPrint(" CVE-2025-59287: WSUS endpoint discovered at " + wsusPolicyValue + ". Confirm patch level before attempting exploitation.");
|
||||
if (!string.IsNullOrEmpty(useWUServerValue))
|
||||
Beaprint.InfoPrint(" UseWUServer is set to " + useWUServerValue + ", clients may still reach Microsoft Update.");
|
||||
}
|
||||
}
|
||||
|
||||
string wsusSetupPath = @"SOFTWARE\Microsoft\Update Services\Server\Setup";
|
||||
string wsusVersion = RegistryHelper.GetRegValue("HKLM", wsusSetupPath, "VersionString");
|
||||
string wsusInstallPath = RegistryHelper.GetRegValue("HKLM", wsusSetupPath, "InstallPath");
|
||||
bool wsusRoleDetected = !string.IsNullOrEmpty(wsusVersion) || !string.IsNullOrEmpty(wsusInstallPath);
|
||||
|
||||
if (TryGetServiceStateAndAccount("WSUSService", out string wsusServiceState, out string wsusServiceAccount))
|
||||
{
|
||||
wsusRoleDetected = true;
|
||||
string serviceMsg = " WSUSService status: " + wsusServiceState;
|
||||
if (!string.IsNullOrEmpty(wsusServiceAccount))
|
||||
serviceMsg += " (runs as " + wsusServiceAccount + ")";
|
||||
Beaprint.BadPrint(serviceMsg);
|
||||
}
|
||||
|
||||
if (wsusRoleDetected)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(wsusVersion))
|
||||
Beaprint.BadPrint(" WSUS Server version: " + wsusVersion + " (verify patch level for CVE-2025-59287).");
|
||||
if (!string.IsNullOrEmpty(wsusInstallPath))
|
||||
Beaprint.InfoPrint(" WSUS install path: " + wsusInstallPath);
|
||||
Beaprint.BadPrint(" CVE-2025-59287: Local WSUS server exposes an unauthenticated deserialization surface reachable over HTTP(S). Patch or restrict access.");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -589,6 +633,32 @@ namespace winPEAS.Checks
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TryGetServiceStateAndAccount(string serviceName, out string state, out string account)
|
||||
{
|
||||
state = string.Empty;
|
||||
account = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
string query = $"SELECT Name, State, StartName FROM Win32_Service WHERE Name='{serviceName.Replace("'", "''")}'";
|
||||
using (var searcher = new ManagementObjectSearcher(@"root\cimv2", query))
|
||||
{
|
||||
foreach (ManagementObject service in searcher.Get())
|
||||
{
|
||||
state = service["State"]?.ToString() ?? string.Empty;
|
||||
account = service["StartName"]?.ToString() ?? string.Empty;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Beaprint.PrintException(ex.Message);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void PrintKrbRelayUp()
|
||||
{
|
||||
try
|
||||
@@ -666,6 +736,31 @@ namespace winPEAS.Checks
|
||||
}
|
||||
}
|
||||
|
||||
static void PrintObjectManagerRaceAmplification()
|
||||
{
|
||||
try
|
||||
{
|
||||
Beaprint.MainPrint("Object Manager race-window amplification primitives");
|
||||
Beaprint.LinkPrint("https://projectzero.google/2025/12/windows-exploitation-techniques.html", "Project Zero write-up:");
|
||||
|
||||
if (ObjectManagerHelper.TryCreateSessionEvent(out var objectName, out var error))
|
||||
{
|
||||
Beaprint.BadPrint($" Created a test named event ({objectName}) under \\BaseNamedObjects.");
|
||||
Beaprint.InfoPrint(" -> Low-privileged users can slow NtOpen*/NtCreate* lookups using ~32k-character names or ~16k-level directory chains.");
|
||||
Beaprint.InfoPrint(" -> Point attacker-controlled symbolic links to the slow path to stretch kernel race windows.");
|
||||
Beaprint.InfoPrint(" -> Use this whenever a bug follows check -> NtOpenX -> privileged action patterns.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Beaprint.InfoPrint($" Could not create a test event under \\BaseNamedObjects ({error}). The namespace might be locked down.");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Beaprint.PrintException(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private static void PrintNtlmSettings()
|
||||
{
|
||||
Beaprint.MainPrint($"Enumerating NTLM Settings");
|
||||
@@ -742,6 +837,39 @@ namespace winPEAS.Checks
|
||||
}
|
||||
}
|
||||
|
||||
private static void PrintPrintNightmarePointAndPrint()
|
||||
{
|
||||
Beaprint.MainPrint("PrintNightmare PointAndPrint Policies");
|
||||
Beaprint.LinkPrint("https://itm4n.github.io/printnightmare-exploitation/", "Check PointAndPrint policy hardening");
|
||||
|
||||
try
|
||||
{
|
||||
string key = @"Software\\Policies\\Microsoft\\Windows NT\\Printers\\PointAndPrint";
|
||||
var restrict = RegistryHelper.GetDwordValue("HKLM", key, "RestrictDriverInstallationToAdministrators");
|
||||
var noWarn = RegistryHelper.GetDwordValue("HKLM", key, "NoWarningNoElevationOnInstall");
|
||||
var updatePrompt = RegistryHelper.GetDwordValue("HKLM", key, "UpdatePromptSettings");
|
||||
|
||||
if (restrict == null && noWarn == null && updatePrompt == null)
|
||||
{
|
||||
Beaprint.NotFoundPrint();
|
||||
return;
|
||||
}
|
||||
|
||||
Beaprint.NoColorPrint($" RestrictDriverInstallationToAdministrators: {restrict}\n" +
|
||||
$" NoWarningNoElevationOnInstall: {noWarn}\n" +
|
||||
$" UpdatePromptSettings: {updatePrompt}");
|
||||
|
||||
if (restrict == 0 && noWarn == 1 && updatePrompt == 2)
|
||||
{
|
||||
Beaprint.BadPrint(" [!] Potentially vulnerable to PrintNightmare misconfiguration");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Beaprint.PrintException(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private static void PrintPrintersWMIInfo()
|
||||
{
|
||||
Beaprint.MainPrint("Enumerating Printers (WMI)");
|
||||
@@ -790,6 +918,48 @@ namespace winPEAS.Checks
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void PrintNamedPipeAbuseCandidates()
|
||||
{
|
||||
Beaprint.MainPrint("Named Pipes with Low-Priv Write Access to Privileged Servers");
|
||||
|
||||
try
|
||||
{
|
||||
var candidates = NamedPipeSecurityAnalyzer.GetNamedPipeAbuseCandidates().ToList();
|
||||
|
||||
if (!candidates.Any())
|
||||
{
|
||||
Beaprint.NoColorPrint(" No risky named pipe ACLs were found.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var candidate in candidates)
|
||||
{
|
||||
var aclSummary = candidate.LowPrivilegeAces.Any()
|
||||
? string.Join("; ", candidate.LowPrivilegeAces.Select(ace =>
|
||||
$"{ace.Principal} [{ace.RightsDescription}]").Where(s => !string.IsNullOrEmpty(s)))
|
||||
: "Unknown";
|
||||
|
||||
var serverSummary = candidate.Processes.Any()
|
||||
? string.Join("; ", candidate.Processes.Select(proc =>
|
||||
$"{proc.ProcessName} (PID {proc.Pid}, {proc.UserName ?? proc.UserSid})"))
|
||||
: "No privileged handles observed (service idle or access denied)";
|
||||
|
||||
var color = candidate.HasPrivilegedServer ? Beaprint.ansi_color_bad : Beaprint.ansi_color_yellow;
|
||||
|
||||
Beaprint.ColorPrint($" \\\\.\\pipe\\{candidate.Name}", color);
|
||||
Beaprint.NoColorPrint($" Low-priv ACLs : {aclSummary}");
|
||||
Beaprint.NoColorPrint($" Observed owners: {serverSummary}");
|
||||
Beaprint.NoColorPrint($" SDDL : {candidate.Sddl}");
|
||||
Beaprint.PrintLineSeparator();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Beaprint.PrintException(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private void PrintAMSIProviders()
|
||||
{
|
||||
Beaprint.MainPrint("Enumerating AMSI registered providers");
|
||||
@@ -1131,6 +1301,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
|
||||
|
||||
@@ -156,15 +156,63 @@ namespace winPEAS.Checks
|
||||
try
|
||||
{
|
||||
Beaprint.MainPrint("RDP Sessions");
|
||||
Beaprint.LinkPrint("https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/credentials-mgmt/rdp-sessions", "Disconnected high-privilege RDP sessions keep reusable tokens inside LSASS.");
|
||||
List<Dictionary<string, string>> rdp_sessions = UserInfoHelper.GetRDPSessions();
|
||||
if (rdp_sessions.Count > 0)
|
||||
{
|
||||
string format = " {0,-10}{1,-15}{2,-15}{3,-25}{4,-10}{5}";
|
||||
string header = string.Format(format, "SessID", "pSessionName", "pUserName", "pDomainName", "State", "SourceIP");
|
||||
string format = " {0,-8}{1,-15}{2,-20}{3,-22}{4,-15}{5,-18}{6,-10}";
|
||||
string header = string.Format(format, "SessID", "Session", "User", "Domain", "State", "SourceIP", "HighPriv");
|
||||
Beaprint.GrayPrint(header);
|
||||
var colors = ColorsU();
|
||||
List<Dictionary<string, string>> flaggedSessions = new List<Dictionary<string, string>>();
|
||||
foreach (Dictionary<string, string> rdpSes in rdp_sessions)
|
||||
{
|
||||
Beaprint.AnsiPrint(string.Format(format, rdpSes["SessionID"], rdpSes["pSessionName"], rdpSes["pUserName"], rdpSes["pDomainName"], rdpSes["State"], rdpSes["SourceIP"]), ColorsU());
|
||||
rdpSes.TryGetValue("SessionID", out string sessionId);
|
||||
rdpSes.TryGetValue("pSessionName", out string sessionName);
|
||||
rdpSes.TryGetValue("pUserName", out string userName);
|
||||
rdpSes.TryGetValue("pDomainName", out string domainName);
|
||||
rdpSes.TryGetValue("State", out string state);
|
||||
rdpSes.TryGetValue("SourceIP", out string sourceIp);
|
||||
|
||||
sessionId = sessionId ?? string.Empty;
|
||||
sessionName = sessionName ?? string.Empty;
|
||||
userName = userName ?? string.Empty;
|
||||
domainName = domainName ?? string.Empty;
|
||||
state = state ?? string.Empty;
|
||||
sourceIp = sourceIp ?? string.Empty;
|
||||
|
||||
bool isHighPriv = UserInfoHelper.IsHighPrivilegeAccount(userName, domainName);
|
||||
string highPrivLabel = isHighPriv ? "Yes" : "No";
|
||||
rdpSes["HighPriv"] = highPrivLabel;
|
||||
|
||||
if (isHighPriv && string.Equals(state, "Disconnected", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
flaggedSessions.Add(rdpSes);
|
||||
}
|
||||
|
||||
Beaprint.AnsiPrint(string.Format(format, sessionId, sessionName, userName, domainName, state, sourceIp, highPrivLabel), colors);
|
||||
}
|
||||
|
||||
if (flaggedSessions.Count > 0)
|
||||
{
|
||||
Beaprint.BadPrint(" [!] Disconnected high-privilege RDP sessions detected. Their credentials/tokens stay in LSASS until the user signs out.");
|
||||
foreach (Dictionary<string, string> session in flaggedSessions)
|
||||
{
|
||||
session.TryGetValue("pDomainName", out string flaggedDomain);
|
||||
session.TryGetValue("pUserName", out string flaggedUser);
|
||||
session.TryGetValue("SessionID", out string flaggedSessionId);
|
||||
session.TryGetValue("SourceIP", out string flaggedIp);
|
||||
|
||||
flaggedDomain = flaggedDomain ?? string.Empty;
|
||||
flaggedUser = flaggedUser ?? string.Empty;
|
||||
flaggedSessionId = flaggedSessionId ?? string.Empty;
|
||||
flaggedIp = flaggedIp ?? string.Empty;
|
||||
|
||||
string userDisplay = string.Format("{0}\\{1}", flaggedDomain, flaggedUser).Trim('\\');
|
||||
string source = string.IsNullOrEmpty(flaggedIp) ? "local" : flaggedIp;
|
||||
Beaprint.BadPrint(string.Format(" -> Session {0} ({1}) from {2}", flaggedSessionId, userDisplay, source));
|
||||
}
|
||||
Beaprint.LinkPrint("https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/credentials-mgmt/rdp-sessions", "Dump LSASS / steal tokens (e.g., comsvcs.dll, LsaLogonSessions, custom SSPs) to reuse those privileges.");
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -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,8 +129,10 @@ 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 + " registryinfo" + GRAY + " Flag writable HKLM/HKU keys that enable hive tampering" + NOCOLOR);
|
||||
Console.WriteLine(LCYAN + " browserinfo" + GRAY + " Search browser information" + NOCOLOR);
|
||||
Console.WriteLine(LCYAN + " filesinfo" + GRAY + " Search generic files that can contains credentials" + NOCOLOR);
|
||||
Console.WriteLine(LCYAN + " fileanalysis" + GRAY + " [NOT RUN BY DEFAULT] Search specific files that can contains credentials and for regexes inside files. Might take several minutes." + 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;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user