mirror of
https://github.com/carlospolop/privilege-escalation-awesome-scripts-suite.git
synced 2026-02-14 00:26:33 +00:00
Compare commits
61 Commits
fix-pr-fai
...
test/chack
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
10e1786e6d | ||
|
|
e60c50100e | ||
|
|
8e917c239f | ||
|
|
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 |
28
.github/workflows/CI-master_tests.yml
vendored
28
.github/workflows/CI-master_tests.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
# checkout
|
# checkout
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@master
|
uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.head_ref }}
|
ref: ${{ github.head_ref }}
|
||||||
|
|
||||||
@@ -36,11 +36,11 @@ jobs:
|
|||||||
|
|
||||||
# Add MSBuild to the PATH: https://github.com/microsoft/setup-msbuild
|
# Add MSBuild to the PATH: https://github.com/microsoft/setup-msbuild
|
||||||
- name: Setup MSBuild.exe
|
- name: Setup MSBuild.exe
|
||||||
uses: microsoft/setup-msbuild@v1.0.2
|
uses: microsoft/setup-msbuild@v2
|
||||||
|
|
||||||
# Setup NuGet
|
# Setup NuGet
|
||||||
- name: Setup NuGet.exe
|
- name: Setup NuGet.exe
|
||||||
uses: nuget/setup-nuget@v1
|
uses: nuget/setup-nuget@v2
|
||||||
|
|
||||||
# Restore the packages for testing
|
# Restore the packages for testing
|
||||||
- name: Restore the application
|
- name: Restore the application
|
||||||
@@ -48,23 +48,23 @@ jobs:
|
|||||||
|
|
||||||
# build
|
# build
|
||||||
- name: run MSBuild
|
- 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
|
# Execute all unit tests in the solution
|
||||||
#- name: Execute unit tests
|
- name: Execute unit tests
|
||||||
# run: dotnet test $env:Solution_Path
|
run: dotnet test $env:Solution_Path --configuration $env:Configuration
|
||||||
|
|
||||||
# Build & update all versions
|
# Build & update all versions
|
||||||
- name: Build all versions
|
- name: Build all versions
|
||||||
run: |
|
run: |
|
||||||
echo "build x64"
|
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"
|
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"
|
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
|
- name: Execute winPEAS -h
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
@@ -220,6 +220,7 @@ jobs:
|
|||||||
- uses: actions/setup-go@v6
|
- uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version: '1.23'
|
go-version: '1.23'
|
||||||
|
cache: false
|
||||||
- run: go version
|
- run: go version
|
||||||
|
|
||||||
# Build linpeas
|
# Build linpeas
|
||||||
@@ -230,6 +231,9 @@ jobs:
|
|||||||
python3 -m builder.linpeas_builder --all --output linpeas_fat.sh
|
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 --all-no-fat --output linpeas.sh
|
||||||
python3 -m builder.linpeas_builder --small --output linpeas_small.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
|
# Build linpeas binaries
|
||||||
- name: Build linpeas binaries
|
- name: Build linpeas binaries
|
||||||
@@ -362,7 +366,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
# Download repo
|
# Download repo
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v5
|
||||||
|
|
||||||
# Build linpeas
|
# Build linpeas
|
||||||
- name: Build macpeas
|
- name: Build macpeas
|
||||||
@@ -469,11 +473,11 @@ jobs:
|
|||||||
|
|
||||||
- name: Get current date
|
- name: Get current date
|
||||||
id: 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
|
- name: Generate random
|
||||||
id: random_n
|
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
|
# Create the release
|
||||||
- name: Create Release
|
- name: Create Release
|
||||||
|
|||||||
28
.github/workflows/PR-tests.yml
vendored
28
.github/workflows/PR-tests.yml
vendored
@@ -8,6 +8,8 @@ on:
|
|||||||
paths-ignore:
|
paths-ignore:
|
||||||
- '.github/**'
|
- '.github/**'
|
||||||
|
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
Build_and_test_winpeas_pr:
|
Build_and_test_winpeas_pr:
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
@@ -20,7 +22,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
# checkout
|
# checkout
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@master
|
uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.head_ref }}
|
ref: ${{ github.head_ref }}
|
||||||
|
|
||||||
@@ -30,11 +32,11 @@ jobs:
|
|||||||
|
|
||||||
# Add MSBuild to the PATH
|
# Add MSBuild to the PATH
|
||||||
- name: Setup MSBuild.exe
|
- name: Setup MSBuild.exe
|
||||||
uses: microsoft/setup-msbuild@v1.0.2
|
uses: microsoft/setup-msbuild@v2
|
||||||
|
|
||||||
# Setup NuGet
|
# Setup NuGet
|
||||||
- name: Setup NuGet.exe
|
- name: Setup NuGet.exe
|
||||||
uses: nuget/setup-nuget@v1
|
uses: nuget/setup-nuget@v2
|
||||||
|
|
||||||
# Restore the packages for testing
|
# Restore the packages for testing
|
||||||
- name: Restore the application
|
- name: Restore the application
|
||||||
@@ -42,19 +44,23 @@ jobs:
|
|||||||
|
|
||||||
# build
|
# build
|
||||||
- name: run MSBuild
|
- name: run MSBuild
|
||||||
run: msbuild $env:Solution_Path
|
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
|
# Build all versions
|
||||||
- name: Build all versions
|
- name: Build all versions
|
||||||
run: |
|
run: |
|
||||||
echo "build x64"
|
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"
|
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"
|
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
|
- name: Execute winPEAS -h
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
@@ -105,7 +111,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
# Download repo
|
# Download repo
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.head_ref }}
|
ref: ${{ github.head_ref }}
|
||||||
|
|
||||||
@@ -113,6 +119,7 @@ jobs:
|
|||||||
- uses: actions/setup-go@v6
|
- uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version: '1.23'
|
go-version: '1.23'
|
||||||
|
cache: false
|
||||||
- run: go version
|
- run: go version
|
||||||
|
|
||||||
# Build linpeas
|
# Build linpeas
|
||||||
@@ -123,6 +130,9 @@ jobs:
|
|||||||
python3 -m builder.linpeas_builder --all --output linpeas_fat.sh
|
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 --all-no-fat --output linpeas.sh
|
||||||
python3 -m builder.linpeas_builder --small --output linpeas_small.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
|
# Run linpeas help as quick test
|
||||||
- name: Run linpeas help
|
- name: Run linpeas help
|
||||||
@@ -161,7 +171,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
# Download repo
|
# Download repo
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.head_ref }}
|
ref: ${{ github.head_ref }}
|
||||||
|
|
||||||
|
|||||||
179
.github/workflows/chack-agent-pr-triage.yml
vendored
Normal file
179
.github/workflows/chack-agent-pr-triage.yml
vendored
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
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
|
||||||
|
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:
|
||||||
|
GH_REPO: ${{ github.repository }}
|
||||||
|
GH_TOKEN: ${{ github.token }}
|
||||||
|
run: |
|
||||||
|
pr_number="${{ github.event.workflow_run.pull_requests[0].number }}"
|
||||||
|
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: Run Chack Agent
|
||||||
|
id: run_chack
|
||||||
|
if: ${{ steps.gate.outputs.should_run == 'true' }}
|
||||||
|
uses: carlospolop/chack-agent@master
|
||||||
|
with:
|
||||||
|
provider: openrouter
|
||||||
|
model_primary: BEST_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}"
|
||||||
|
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
|
||||||
|
openrouter_api_key: ${{ secrets.OPENROUTER_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
|
||||||
|
|
||||||
|
data = json.loads(os.environ.get('CHACK_MESSAGE', '') or '{}')
|
||||||
|
decision = data.get('decision', 'comment')
|
||||||
|
message = data.get('message', '').strip() or 'Chack Agent did not provide details.'
|
||||||
|
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,
|
||||||
|
});
|
||||||
165
.github/workflows/ci-master-failure-chack-agent-pr.yml
vendored
Normal file
165
.github/workflows/ci-master-failure-chack-agent-pr.yml
vendored
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
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 }}
|
||||||
|
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: Run Chack Agent
|
||||||
|
id: run_chack
|
||||||
|
uses: carlospolop/chack-agent@master
|
||||||
|
with:
|
||||||
|
provider: openrouter
|
||||||
|
model_primary: BEST_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}"
|
||||||
|
openrouter_api_key: ${{ secrets.OPENROUTER_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
|
||||||
|
git reset -- chack_failure_summary.txt chack_prompt.txt chack_failed_steps_logs.txt
|
||||||
|
git commit -m "Fix CI-master failures for run #${{ github.event.workflow_run.id }}"
|
||||||
|
git push origin HEAD:"$FIX_BRANCH"
|
||||||
|
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,
|
||||||
|
});
|
||||||
113
.github/workflows/codex-pr-triage.yml
vendored
113
.github/workflows/codex-pr-triage.yml
vendored
@@ -1,113 +0,0 @@
|
|||||||
name: Codex PR Triage
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
types: [opened]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
codex_triage:
|
|
||||||
if: ${{ github.event.pull_request.user.login == 'carlospolop' }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
pull-requests: write
|
|
||||||
outputs:
|
|
||||||
decision: ${{ steps.parse.outputs.decision }}
|
|
||||||
message: ${{ steps.parse.outputs.message }}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout PR merge ref
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
with:
|
|
||||||
ref: refs/pull/${{ github.event.pull_request.number }}/merge
|
|
||||||
|
|
||||||
- name: Pre-fetch base and head refs
|
|
||||||
run: |
|
|
||||||
git fetch --no-tags origin \
|
|
||||||
${{ github.event.pull_request.base.ref }} \
|
|
||||||
+refs/pull/${{ github.event.pull_request.number }}/head
|
|
||||||
|
|
||||||
- name: Run Codex
|
|
||||||
id: run_codex
|
|
||||||
uses: openai/codex-action@v1
|
|
||||||
with:
|
|
||||||
openai-api-key: ${{ secrets.OPENAI_API_KEY }}
|
|
||||||
output-schema-file: .github/codex/pr-merge-schema.json
|
|
||||||
model: gpt-5.2-codex
|
|
||||||
prompt: |
|
|
||||||
You are reviewing PR #${{ github.event.pull_request.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:
|
|
||||||
----
|
|
||||||
${{ github.event.pull_request.title }}
|
|
||||||
${{ github.event.pull_request.body }}
|
|
||||||
|
|
||||||
Review ONLY the changes introduced by the PR:
|
|
||||||
git log --oneline ${{ github.event.pull_request.base.sha }}...${{ github.event.pull_request.head.sha }}
|
|
||||||
|
|
||||||
Output JSON only, following the provided schema.
|
|
||||||
|
|
||||||
- name: Parse Codex decision
|
|
||||||
id: parse
|
|
||||||
env:
|
|
||||||
CODEX_MESSAGE: ${{ steps.run_codex.outputs.final-message }}
|
|
||||||
run: |
|
|
||||||
python3 - <<'PY'
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
|
|
||||||
data = json.loads(os.environ.get('CODEX_MESSAGE', '') or '{}')
|
|
||||||
decision = data.get('decision', 'comment')
|
|
||||||
message = data.get('message', '').strip() or 'Codex did not provide details.'
|
|
||||||
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: codex_triage
|
|
||||||
if: ${{ needs.codex_triage.outputs.decision != '' }}
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
pull-requests: write
|
|
||||||
steps:
|
|
||||||
- name: Merge PR when approved
|
|
||||||
if: ${{ needs.codex_triage.outputs.decision == 'merge' }}
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ github.token }}
|
|
||||||
PR_NUMBER: ${{ github.event.pull_request.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} (Codex)"
|
|
||||||
|
|
||||||
- name: Comment with doubts
|
|
||||||
if: ${{ needs.codex_triage.outputs.decision == 'comment' }}
|
|
||||||
uses: actions/github-script@v7
|
|
||||||
env:
|
|
||||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
|
||||||
CODEX_MESSAGE: ${{ needs.codex_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.CODEX_MESSAGE,
|
|
||||||
});
|
|
||||||
201
.github/workflows/pr-failure-chack-agent-dispatch.yml
vendored
Normal file
201
.github/workflows/pr-failure-chack-agent-dispatch.yml
vendored
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
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' &&
|
||||||
|
github.event.workflow_run.pull_requests &&
|
||||||
|
github.event.workflow_run.pull_requests[0] &&
|
||||||
|
!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 }}
|
||||||
|
GH_TOKEN: ${{ github.token }}
|
||||||
|
run: |
|
||||||
|
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: read
|
||||||
|
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: Run Chack Agent
|
||||||
|
id: run_chack
|
||||||
|
uses: carlospolop/chack-agent@master
|
||||||
|
with:
|
||||||
|
provider: openrouter
|
||||||
|
model_primary: BEST_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}"
|
||||||
|
openrouter_api_key: ${{ secrets.OPENROUTER_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 }}
|
||||||
|
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
|
||||||
|
git reset -- chack_failure_summary.txt chack_prompt.txt
|
||||||
|
git commit -m "Fix CI failures for PR #${PR_NUMBER}"
|
||||||
|
git push origin HEAD:${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,
|
||||||
|
});
|
||||||
136
.github/workflows/pr-failure-codex-dispatch.yml
vendored
136
.github/workflows/pr-failure-codex-dispatch.yml
vendored
@@ -1,136 +0,0 @@
|
|||||||
name: PR Failure Codex Dispatch
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_run:
|
|
||||||
workflows: ["PR-tests"]
|
|
||||||
types: [completed]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
codex_on_failure:
|
|
||||||
if: >
|
|
||||||
${{ github.event.workflow_run.conclusion == 'failure' &&
|
|
||||||
github.event.workflow_run.pull_requests &&
|
|
||||||
github.event.workflow_run.pull_requests[0].user.login == 'carlospolop' &&
|
|
||||||
!startsWith(github.event.workflow_run.head_commit.message, 'Fix CI failures for PR #') }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
pull-requests: write
|
|
||||||
issues: write
|
|
||||||
actions: read
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Comment on PR with failure info
|
|
||||||
uses: actions/github-script@v7
|
|
||||||
env:
|
|
||||||
PR_NUMBER: ${{ github.event.workflow_run.pull_requests[0].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 Codex to attempt a fix.`;
|
|
||||||
await github.rest.issues.createComment({
|
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo,
|
|
||||||
issue_number: prNumber,
|
|
||||||
body,
|
|
||||||
});
|
|
||||||
|
|
||||||
- name: Checkout PR head
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
with:
|
|
||||||
repository: ${{ github.event.workflow_run.head_repository.full_name }}
|
|
||||||
ref: ${{ github.event.workflow_run.head_sha }}
|
|
||||||
fetch-depth: 0
|
|
||||||
persist-credentials: true
|
|
||||||
|
|
||||||
- name: Configure git author
|
|
||||||
run: |
|
|
||||||
git config user.name "codex-action"
|
|
||||||
git config user.email "codex-action@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('codex_failure_summary.txt', 'w') as handle:
|
|
||||||
handle.write(summary)
|
|
||||||
PY
|
|
||||||
|
|
||||||
- name: Create Codex prompt
|
|
||||||
env:
|
|
||||||
PR_NUMBER: ${{ github.event.workflow_run.pull_requests[0].number }}
|
|
||||||
RUN_URL: ${{ github.event.workflow_run.html_url }}
|
|
||||||
HEAD_BRANCH: ${{ github.event.workflow_run.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 codex_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."
|
|
||||||
} > codex_prompt.txt
|
|
||||||
|
|
||||||
- name: Run Codex
|
|
||||||
id: run_codex
|
|
||||||
uses: openai/codex-action@v1
|
|
||||||
with:
|
|
||||||
openai-api-key: ${{ secrets.OPENAI_API_KEY }}
|
|
||||||
prompt-file: codex_prompt.txt
|
|
||||||
sandbox: workspace-write
|
|
||||||
model: gpt-5.2-codex
|
|
||||||
|
|
||||||
- name: Commit and push if changed
|
|
||||||
env:
|
|
||||||
TARGET_BRANCH: ${{ github.event.workflow_run.head_branch }}
|
|
||||||
PR_NUMBER: ${{ github.event.workflow_run.pull_requests[0].number }}
|
|
||||||
run: |
|
|
||||||
if git diff --quiet; then
|
|
||||||
echo "No changes to commit."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
git add -A
|
|
||||||
git commit -m "Fix CI failures for PR #${PR_NUMBER}"
|
|
||||||
git push origin HEAD:${TARGET_BRANCH}
|
|
||||||
|
|
||||||
- name: Comment with Codex result
|
|
||||||
if: steps.run_codex.outputs.final-message != ''
|
|
||||||
uses: actions/github-script@v7
|
|
||||||
env:
|
|
||||||
PR_NUMBER: ${{ github.event.workflow_run.pull_requests[0].number }}
|
|
||||||
CODEX_MESSAGE: ${{ steps.run_codex.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.CODEX_MESSAGE,
|
|
||||||
});
|
|
||||||
@@ -1705,7 +1705,7 @@ search:
|
|||||||
auto_check: True
|
auto_check: True
|
||||||
exec:
|
exec:
|
||||||
- '( redis-server --version || echo_not_found "redis-server") 2>/dev/null'
|
- '( 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:
|
files:
|
||||||
- name: "redis.conf"
|
- name: "redis.conf"
|
||||||
|
|||||||
@@ -53,3 +53,4 @@ if __name__ == "__main__":
|
|||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
main(all_modules, all_no_fat_modules, no_network_scanning, small, include_modules, exclude_modules, output)
|
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
|
# Fat linpeas: 0
|
||||||
# Small linpeas: 0
|
# Small linpeas: 0
|
||||||
|
|
||||||
if apt list --installed 2>/dev/null | grep -q 'polkit.*0\.105-26' || \
|
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 -q 'polkit.*\(0\.117-2\|0\.115-6\)' || \
|
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 -q 'polkit.*\(0\.117-2\|0\.115-6\)'; then
|
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 "Vulnerable to CVE-2021-3560" | sed -${E} "s,.*,${SED_RED_YELLOW},"
|
||||||
echo ""
|
echo ""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -30,11 +30,33 @@
|
|||||||
# Functions Used: echo_not_found, print_2title, print_list, warn_exec
|
# Functions Used: echo_not_found, print_2title, print_list, warn_exec
|
||||||
# Global Variables:
|
# Global Variables:
|
||||||
# Initial Functions:
|
# Initial Functions:
|
||||||
# Generated Global Variables: $ASLR, $hypervisorflag, $detectedvirt, $unpriv_userns_clone, $perf_event_paranoid, $mmap_min_addr, $ptrace_scope, $dmesg_restrict, $kptr_restrict, $unpriv_bpf_disabled
|
# 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
|
# Fat linpeas: 0
|
||||||
# Small 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
|
#-- SY) AppArmor
|
||||||
print_2title "Protections"
|
print_2title "Protections"
|
||||||
print_list "AppArmor enabled? .............. "$NC
|
print_list "AppArmor enabled? .............. "$NC
|
||||||
@@ -81,51 +103,25 @@ 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
|
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
|
#-- SY) Unprivileged user namespaces
|
||||||
print_list "unpriv_userns_clone? ........... "$NC
|
print_sysctl_eq_zero "unpriv_userns_clone? ........... " "/proc/sys/kernel/unprivileged_userns_clone" "unpriv_userns_clone" "$SED_GREEN" "$SED_RED"
|
||||||
unpriv_userns_clone=$(cat /proc/sys/kernel/unprivileged_userns_clone 2>/dev/null)
|
|
||||||
if [ -z "$unpriv_userns_clone" ]; then
|
|
||||||
echo_not_found "/proc/sys/kernel/unprivileged_userns_clone"
|
|
||||||
else
|
|
||||||
if [ "$unpriv_userns_clone" -eq 0 ]; then echo "0" | sed -${E} "s,0,${SED_GREEN},"; else echo "$unpriv_userns_clone" | sed -${E} "s,.*,${SED_RED},g"; fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
#-- SY) Unprivileged eBPF
|
#-- SY) Unprivileged eBPF
|
||||||
print_list "unpriv_bpf_disabled? ........... "$NC
|
print_sysctl_eq_zero "unpriv_bpf_disabled? ........... " "/proc/sys/kernel/unprivileged_bpf_disabled" "unpriv_bpf_disabled" "$SED_RED" "$SED_GREEN"
|
||||||
unpriv_bpf_disabled=$(cat /proc/sys/kernel/unprivileged_bpf_disabled 2>/dev/null)
|
|
||||||
if [ -z "$unpriv_bpf_disabled" ]; then
|
|
||||||
echo_not_found "/proc/sys/kernel/unprivileged_bpf_disabled"
|
|
||||||
else
|
|
||||||
if [ "$unpriv_bpf_disabled" -eq 0 ]; then echo "0" | sed -${E} "s,0,${SED_RED},"; else echo "$unpriv_bpf_disabled" | sed -${E} "s,.*,${SED_GREEN},g"; fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
#-- SY) cgroup2
|
#-- SY) cgroup2
|
||||||
print_list "Cgroup2 enabled? ............... "$NC
|
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},"
|
([ "$(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
|
#-- SY) Kernel hardening sysctls
|
||||||
print_list "kptr_restrict? ................. "$NC
|
print_sysctl_eq_zero "kptr_restrict? ................. " "/proc/sys/kernel/kptr_restrict" "kptr_restrict" "$SED_RED" "$SED_GREEN"
|
||||||
kptr_restrict=$(cat /proc/sys/kernel/kptr_restrict 2>/dev/null)
|
|
||||||
if [ -z "$kptr_restrict" ]; then
|
|
||||||
echo_not_found "/proc/sys/kernel/kptr_restrict"
|
|
||||||
else
|
|
||||||
if [ "$kptr_restrict" -eq 0 ]; then echo "0" | sed -${E} "s,0,${SED_RED},"; else echo "$kptr_restrict" | sed -${E} "s,.*,${SED_GREEN},g"; fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
print_list "dmesg_restrict? ................ "$NC
|
print_sysctl_eq_zero "dmesg_restrict? ................ " "/proc/sys/kernel/dmesg_restrict" "dmesg_restrict" "$SED_RED" "$SED_GREEN"
|
||||||
dmesg_restrict=$(cat /proc/sys/kernel/dmesg_restrict 2>/dev/null)
|
|
||||||
if [ -z "$dmesg_restrict" ]; then
|
|
||||||
echo_not_found "/proc/sys/kernel/dmesg_restrict"
|
|
||||||
else
|
|
||||||
if [ "$dmesg_restrict" -eq 0 ]; then echo "0" | sed -${E} "s,0,${SED_RED},"; else echo "$dmesg_restrict" | sed -${E} "s,.*,${SED_GREEN},g"; fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
print_list "ptrace_scope? .................. "$NC
|
print_sysctl_eq_zero "ptrace_scope? .................. " "/proc/sys/kernel/yama/ptrace_scope" "ptrace_scope" "$SED_RED" "$SED_GREEN"
|
||||||
ptrace_scope=$(cat /proc/sys/kernel/yama/ptrace_scope 2>/dev/null)
|
|
||||||
if [ -z "$ptrace_scope" ]; then
|
print_sysctl_eq_zero "protected_symlinks? ............ " "/proc/sys/fs/protected_symlinks" "protected_symlinks" "$SED_RED" "$SED_GREEN"
|
||||||
echo_not_found "/proc/sys/kernel/yama/ptrace_scope"
|
|
||||||
else
|
print_sysctl_eq_zero "protected_hardlinks? ........... " "/proc/sys/fs/protected_hardlinks" "protected_hardlinks" "$SED_RED" "$SED_GREEN"
|
||||||
if [ "$ptrace_scope" -eq 0 ]; then echo "0" | sed -${E} "s,0,${SED_RED},"; else echo "$ptrace_scope" | sed -${E} "s,.*,${SED_GREEN},g"; fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
print_list "perf_event_paranoid? ........... "$NC
|
print_list "perf_event_paranoid? ........... "$NC
|
||||||
perf_event_paranoid=$(cat /proc/sys/kernel/perf_event_paranoid 2>/dev/null)
|
perf_event_paranoid=$(cat /proc/sys/kernel/perf_event_paranoid 2>/dev/null)
|
||||||
@@ -135,13 +131,7 @@ 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
|
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
|
fi
|
||||||
|
|
||||||
print_list "mmap_min_addr? ................. "$NC
|
print_sysctl_eq_zero "mmap_min_addr? ................. " "/proc/sys/vm/mmap_min_addr" "mmap_min_addr" "$SED_RED" "$SED_GREEN"
|
||||||
mmap_min_addr=$(cat /proc/sys/vm/mmap_min_addr 2>/dev/null)
|
|
||||||
if [ -z "$mmap_min_addr" ]; then
|
|
||||||
echo_not_found "/proc/sys/vm/mmap_min_addr"
|
|
||||||
else
|
|
||||||
if [ "$mmap_min_addr" -eq 0 ]; then echo "0" | sed -${E} "s,0,${SED_RED},"; else echo "$mmap_min_addr" | sed -${E} "s,.*,${SED_GREEN},g"; fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
print_list "lockdown mode? ................. "$NC
|
print_list "lockdown mode? ................. "$NC
|
||||||
if [ -f "/sys/kernel/security/lockdown" ]; then
|
if [ -f "/sys/kernel/security/lockdown" ]; then
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
# Last Update: 07-03-2024
|
# Last Update: 07-03-2024
|
||||||
# Description: Check for additional disk information and system resources relevant to privilege escalation:
|
# Description: Check for additional disk information and system resources relevant to privilege escalation:
|
||||||
# - Disk utilization
|
# - Disk utilization
|
||||||
|
# - Inode usage
|
||||||
# - System resources
|
# - System resources
|
||||||
# - Storage statistics
|
# - Storage statistics
|
||||||
# - Common vulnerable scenarios:
|
# - Common vulnerable scenarios:
|
||||||
@@ -44,4 +45,8 @@ if [ "$EXTRA_CHECKS" ] || [ "$DEBUG" ]; then
|
|||||||
(df -h || lsblk) 2>/dev/null || echo_not_found "df and lsblk"
|
(df -h || lsblk) 2>/dev/null || echo_not_found "df and lsblk"
|
||||||
warn_exec free 2>/dev/null
|
warn_exec free 2>/dev/null
|
||||||
echo ""
|
echo ""
|
||||||
fi
|
|
||||||
|
print_2title "Inode usage"
|
||||||
|
warn_exec df -i 2>/dev/null
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
# License: GNU GPL
|
# License: GNU GPL
|
||||||
# Version: 1.2
|
# Version: 1.2
|
||||||
# Functions Used: echo_not_found, print_2title, print_info, print_3title
|
# 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:
|
# 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
|
# 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
|
# Fat linpeas: 0
|
||||||
@@ -178,7 +178,11 @@ if ! [ "$SEARCH_IN_FOLDER" ]; then
|
|||||||
if [ "$EXTRA_CHECKS" ]; then
|
if [ "$EXTRA_CHECKS" ]; then
|
||||||
echo ""
|
echo ""
|
||||||
print_3title "Service versions and status:"
|
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
|
fi
|
||||||
|
|
||||||
# Check systemd path writability
|
# Check systemd path writability
|
||||||
@@ -190,4 +194,4 @@ if ! [ "$SEARCH_IN_FOLDER" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
# Functions Used: print_2title, print_list, echo_not_found
|
# Functions Used: print_2title, print_list, echo_not_found
|
||||||
# Global Variables: $SEARCH_IN_FOLDER, $Wfolders, $SED_RED, $SED_RED_YELLOW, $NC
|
# Global Variables: $SEARCH_IN_FOLDER, $Wfolders, $SED_RED, $SED_RED_YELLOW, $NC
|
||||||
# Initial Functions:
|
# 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
|
||||||
# Fat linpeas: 0
|
# Fat linpeas: 0
|
||||||
# Small linpeas: 1
|
# Small linpeas: 1
|
||||||
|
|
||||||
@@ -116,18 +116,20 @@ if ! [ "$SEARCH_IN_FOLDER" ]; then
|
|||||||
# Check ExecStart paths
|
# Check ExecStart paths
|
||||||
grep -E "ExecStart|ExecStartPre|ExecStartPost" "$service_file" 2>/dev/null |
|
grep -E "ExecStart|ExecStartPre|ExecStartPost" "$service_file" 2>/dev/null |
|
||||||
while read -r exec_line; do
|
while read -r exec_line; do
|
||||||
# Extract the first word after ExecStart* as the command
|
# Extract command from the right side of Exec*=, not from argv
|
||||||
cmd=$(echo "$exec_line" | awk '{print $2}' | tr -d '"')
|
exec_value="${exec_line#*=}"
|
||||||
# Extract the rest as arguments
|
exec_value=$(echo "$exec_value" | sed 's/^[[:space:]]*//')
|
||||||
args=$(echo "$exec_line" | awk '{$1=$2=""; print $0}' | tr -d '"')
|
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
|
# Only check the command path, not arguments
|
||||||
if [ -n "$cmd" ] && [ -w "$cmd" ]; then
|
if [ -n "$cmd_path" ] && [ -w "$cmd_path" ]; then
|
||||||
echo "$service: $cmd (from $exec_line)" | sed -${E} "s,.*,${SED_RED},g"
|
echo "$service: $cmd_path (from $exec_line)" | sed -${E} "s,.*,${SED_RED},g"
|
||||||
fi
|
fi
|
||||||
# Check for relative paths only in the command, not arguments
|
# Check for relative paths only in the command, not arguments
|
||||||
if [ -n "$cmd" ] && [ "${cmd#/}" = "$cmd" ] && ! echo "$cmd" | grep -qE '^-|^--'; then
|
if [ -n "$cmd_path" ] && [ "${cmd_path#/}" = "$cmd_path" ] && [ "${cmd_path#\$}" = "$cmd_path" ]; then
|
||||||
echo "$service: Uses relative path '$cmd' (from $exec_line)" | sed -${E} "s,.*,${SED_RED},g"
|
echo "$service: Uses relative path '$cmd_path' (from $exec_line)" | sed -${E} "s,.*,${SED_RED},g"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
@@ -153,4 +155,4 @@ if ! [ "$SEARCH_IN_FOLDER" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
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
|
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"
|
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},"
|
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"
|
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
|
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
|
atq 2>/dev/null
|
||||||
@@ -247,4 +248,4 @@ else
|
|||||||
print_info "https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/index.html#scheduledcron-jobs"
|
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 {} \;
|
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
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
# Functions Used: print_2title, print_info
|
# Functions Used: print_2title, print_info
|
||||||
# Global Variables: $Groups, $groupsB, $groupsVB, $nosh_usrs, $sh_usrs, $USER
|
# Global Variables: $Groups, $groupsB, $groupsVB, $nosh_usrs, $sh_usrs, $USER
|
||||||
# Initial Functions:
|
# 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
|
# Fat linpeas: 0
|
||||||
# Small linpeas: 1
|
# Small linpeas: 1
|
||||||
|
|
||||||
@@ -30,6 +30,10 @@ if [ -n "$pkexec_bin" ]; then
|
|||||||
# Check polkit version for known vulnerabilities
|
# Check polkit version for known vulnerabilities
|
||||||
if command -v pkexec >/dev/null 2>&1; then
|
if command -v pkexec >/dev/null 2>&1; then
|
||||||
pkexec --version 2>/dev/null
|
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
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
# License: GNU GPL
|
# License: GNU GPL
|
||||||
# Version: 1.0
|
# Version: 1.0
|
||||||
# Functions Used: print_2title
|
# Functions Used: print_2title
|
||||||
# Global Variables: $MACPEAS, $sh_usrs, $USER
|
# Global Variables: $MACPEAS, $sh_usrs, $TIMEOUT, $USER
|
||||||
# Initial Functions:
|
# Initial Functions:
|
||||||
# Generated Global Variables: $ushell, $no_shells, $unexpected_shells
|
# Generated Global Variables: $ushell, $no_shells, $unexpected_shells
|
||||||
# Fat linpeas: 0
|
# Fat linpeas: 0
|
||||||
@@ -26,8 +26,16 @@ else
|
|||||||
no_shells=$(grep -Ev "sh$" /etc/passwd 2>/dev/null | cut -d ':' -f 7 | sort | uniq)
|
no_shells=$(grep -Ev "sh$" /etc/passwd 2>/dev/null | cut -d ':' -f 7 | sort | uniq)
|
||||||
unexpected_shells=""
|
unexpected_shells=""
|
||||||
printf "%s\n" "$no_shells" | while read f; do
|
printf "%s\n" "$no_shells" | while read f; do
|
||||||
if $f -c 'whoami' 2>/dev/null | grep -q "$USER"; then
|
if [ -x "$f" ]; then
|
||||||
unexpected_shells="$f\n$unexpected_shells"
|
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
|
fi
|
||||||
done
|
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},"
|
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
|
done
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
# Functions Used: echo_not_found, print_2title, print_info
|
# Functions Used: echo_not_found, print_2title, print_info
|
||||||
# Global Variables:$IAMROOT, $PASSWORD, $sudoB, $sudoG, $sudoVB1, $sudoVB2
|
# Global Variables:$IAMROOT, $PASSWORD, $sudoB, $sudoG, $sudoVB1, $sudoVB2
|
||||||
# Initial Functions:
|
# Initial Functions:
|
||||||
# Generated Global Variables:
|
# Generated Global Variables: $secure_path_line
|
||||||
# Fat linpeas: 0
|
# Fat linpeas: 0
|
||||||
# Small linpeas: 1
|
# Small linpeas: 1
|
||||||
|
|
||||||
@@ -19,6 +19,16 @@ print_info "https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation
|
|||||||
if [ "$PASSWORD" ]; then
|
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"
|
(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
|
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"
|
( 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
|
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},"
|
echo "You can create a file in /etc/sudoers.d/ and escalate privileges" | sed -${E} "s,.*,${SED_RED_YELLOW},"
|
||||||
@@ -29,4 +39,4 @@ for f in /etc/sudoers.d/*; do
|
|||||||
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"
|
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
|
fi
|
||||||
done
|
done
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
@@ -40,4 +40,18 @@ else
|
|||||||
echo "ptrace protection is enabled ($ptrace_scope)" | sed "s,is enabled,${SED_GREEN},g";
|
echo "ptrace protection is enabled ($ptrace_scope)" | sed "s,is enabled,${SED_GREEN},g";
|
||||||
|
|
||||||
fi
|
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 ""
|
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
|
|
||||||
@@ -37,14 +37,14 @@ printf "%s\n" "$suids_files" | while read s; do
|
|||||||
else
|
else
|
||||||
c="a"
|
c="a"
|
||||||
for b in $sidB; do
|
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,"
|
echo "$s" | sed -${E} "s,$(echo $b | cut -d % -f 1),${C}[1;31m& ---> $(echo $b | cut -d % -f 2)${C}[0m,"
|
||||||
c=""
|
c=""
|
||||||
break;
|
break;
|
||||||
fi
|
fi
|
||||||
done;
|
done;
|
||||||
if [ "$c" ]; then
|
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},"
|
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
|
else
|
||||||
echo "$s (Unknown SUID binary!)" | sed -${E} "s,/.*,${SED_RED},"
|
echo "$s (Unknown SUID binary!)" | sed -${E} "s,/.*,${SED_RED},"
|
||||||
@@ -96,4 +96,4 @@ printf "%s\n" "$suids_files" | while read s; do
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done;
|
done;
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
@@ -17,10 +17,10 @@ check_external_hostname(){
|
|||||||
INTERNET_SEARCH_TIMEOUT=15
|
INTERNET_SEARCH_TIMEOUT=15
|
||||||
# wget or curl?
|
# wget or curl?
|
||||||
if command -v curl >/dev/null 2>&1; then
|
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
|
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
|
else
|
||||||
echo "wget or curl not found"
|
echo "wget or curl not found"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,11 +15,12 @@
|
|||||||
|
|
||||||
check_tcp_443_bin () {
|
check_tcp_443_bin () {
|
||||||
local TIMEOUT_INTERNET_SECONDS_443_BIN=$1
|
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 command -v curl >/dev/null 2>&1; then
|
||||||
if curl -s --connect-timeout $TIMEOUT_INTERNET_SECONDS_443_BIN "$url_lambda" \
|
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
|
then
|
||||||
echo "Port 443 is accessible with curl"
|
echo "Port 443 is accessible with curl"
|
||||||
return 0 # ✅ success
|
return 0 # ✅ success
|
||||||
@@ -30,7 +31,8 @@ check_tcp_443_bin () {
|
|||||||
|
|
||||||
elif command -v wget >/dev/null 2>&1; then
|
elif command -v wget >/dev/null 2>&1; then
|
||||||
if wget -q --timeout=$TIMEOUT_INTERNET_SECONDS_443_BIN -O - "$url_lambda" \
|
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
|
then
|
||||||
echo "Port 443 is accessible with wget"
|
echo "Port 443 is accessible with wget"
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
@@ -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$"
|
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$"
|
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$"
|
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$"
|
||||||
|
|
||||||
|
|||||||
@@ -13,5 +13,5 @@
|
|||||||
# Small linpeas: 1
|
# Small linpeas: 1
|
||||||
|
|
||||||
|
|
||||||
sudoVB1=" \*|env_keep\W*\+=.*LD_PRELOAD|env_keep\W*\+=.*LD_LIBRARY_PATH|env_keep\W*\+=.*BASH_ENV|env_keep\W*\+=.* ENV|peass{SUDOVB1_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}"
|
sudoVB2="peass{SUDOVB2_HERE}"
|
||||||
|
|||||||
@@ -405,7 +405,7 @@ class LinpeasBuilder:
|
|||||||
name = entry["name"]
|
name = entry["name"]
|
||||||
caseinsensitive = entry.get("caseinsensitive", False)
|
caseinsensitive = entry.get("caseinsensitive", False)
|
||||||
regex = entry["regex"]
|
regex = entry["regex"]
|
||||||
regex = regex.replace('"', '\\"').strip()
|
regex = regex.replace("\\", "\\\\").replace('"', '\\"').strip()
|
||||||
falsePositives = entry.get("falsePositives", False)
|
falsePositives = entry.get("falsePositives", False)
|
||||||
|
|
||||||
if falsePositives:
|
if falsePositives:
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ from .yamlGlobals import (
|
|||||||
class LinpeasModule:
|
class LinpeasModule:
|
||||||
def __init__(self, path):
|
def __init__(self, path):
|
||||||
self.path = path
|
self.path = path
|
||||||
|
real_path = os.path.realpath(path)
|
||||||
with open(path, 'r') as file:
|
with open(path, 'r') as file:
|
||||||
self.module_text = file.read()
|
self.module_text = file.read()
|
||||||
|
|
||||||
@@ -29,7 +30,7 @@ class LinpeasModule:
|
|||||||
self.section_info = {}
|
self.section_info = {}
|
||||||
if not (self.is_base or self.is_function or self.is_variable):
|
if not (self.is_base or self.is_function or self.is_variable):
|
||||||
for module in LINPEAS_PARTS["modules"]:
|
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.section_info = module
|
||||||
self.is_check = True
|
self.is_check = True
|
||||||
break
|
break
|
||||||
|
|||||||
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()
|
||||||
@@ -127,7 +127,9 @@ def parse_line(line: str):
|
|||||||
|
|
||||||
elif is_section(line, INFO_PATTERN):
|
elif is_section(line, INFO_PATTERN):
|
||||||
title = parse_title(line)
|
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
|
#If here, then it's text
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ CALL :T_Progress 2
|
|||||||
:ListHotFixes
|
:ListHotFixes
|
||||||
where wmic >nul 2>&1
|
where wmic >nul 2>&1
|
||||||
if %errorlevel% equ 0 (
|
if %errorlevel% equ 0 (
|
||||||
wmic qfe get Caption,Description,HotFixID,InstalledOn | more
|
wmic qfe get Caption,Description,HotFixID,InstalledOn
|
||||||
) else (
|
) else (
|
||||||
powershell -command "Get-HotFix | Format-Table -AutoSize"
|
powershell -command "Get-HotFix | Format-Table -AutoSize"
|
||||||
)
|
)
|
||||||
@@ -204,7 +204,7 @@ CALL :T_Progress 1
|
|||||||
CALL :ColorLine " %E%33m[+]%E%97m Registered Anti-Virus(AV)"
|
CALL :ColorLine " %E%33m[+]%E%97m Registered Anti-Virus(AV)"
|
||||||
where wmic >nul 2>&1
|
where wmic >nul 2>&1
|
||||||
if %errorlevel% equ 0 (
|
if %errorlevel% equ 0 (
|
||||||
WMIC /Node:localhost /Namespace:\\root\SecurityCenter2 Path AntiVirusProduct Get displayName /Format:List | more
|
WMIC /Node:localhost /Namespace:\\root\SecurityCenter2 Path AntiVirusProduct Get displayName /Format:List
|
||||||
) else (
|
) else (
|
||||||
powershell -command "Get-CimInstance -Namespace root/SecurityCenter2 -ClassName AntiVirusProduct | Select-Object -ExpandProperty displayName"
|
powershell -command "Get-CimInstance -Namespace root/SecurityCenter2 -ClassName AntiVirusProduct | Select-Object -ExpandProperty displayName"
|
||||||
)
|
)
|
||||||
@@ -238,7 +238,7 @@ CALL :ColorLine " %E%33m[+]%E%97m MOUNTED DISKS"
|
|||||||
ECHO. [i] Maybe you find something interesting
|
ECHO. [i] Maybe you find something interesting
|
||||||
where wmic >nul 2>&1
|
where wmic >nul 2>&1
|
||||||
if %errorlevel% equ 0 (
|
if %errorlevel% equ 0 (
|
||||||
wmic logicaldisk get caption | more
|
wmic logicaldisk get caption
|
||||||
) else (
|
) else (
|
||||||
fsutil fsinfo drives
|
fsutil fsinfo drives
|
||||||
)
|
)
|
||||||
@@ -670,7 +670,7 @@ if "%long%" == "true" (
|
|||||||
ECHO.
|
ECHO.
|
||||||
where wmic >nul 2>&1
|
where wmic >nul 2>&1
|
||||||
if !errorlevel! equ 0 (
|
if !errorlevel! equ 0 (
|
||||||
for /f %%x in ('wmic logicaldisk get name ^| more') do (
|
for /f %%x in ('wmic logicaldisk get name') do (
|
||||||
set tdrive=%%x
|
set tdrive=%%x
|
||||||
if "!tdrive:~1,2!" == ":" (
|
if "!tdrive:~1,2!" == ":" (
|
||||||
%%x
|
%%x
|
||||||
|
|||||||
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}"
|
||||||
|
)
|
||||||
@@ -128,7 +128,7 @@ Once you have installed and activated it you need to:
|
|||||||
|
|
||||||
- **System Information**
|
- **System Information**
|
||||||
- [x] Basic System info 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] Enumerate Microsoft updates
|
||||||
- [x] PS, Audit, WEF and LAPS Settings
|
- [x] PS, Audit, WEF and LAPS Settings
|
||||||
- [x] LSA protection
|
- [x] LSA protection
|
||||||
@@ -262,7 +262,7 @@ Once you have installed and activated it you need to:
|
|||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
- Add more checks
|
- 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.
|
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.
|
||||||
|
|
||||||
|
|||||||
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=" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -61,9 +61,11 @@
|
|||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
<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>
|
<HintPath>..\packages\MSTest.TestFramework.2.2.5\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
<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>
|
<HintPath>..\packages\MSTest.TestFramework.2.2.5\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.ComponentModel.Composition" />
|
<Reference Include="System.ComponentModel.Composition" />
|
||||||
@@ -95,6 +97,7 @@
|
|||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="ArgumentParsingTests.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="SmokeTests.cs" />
|
<Compile Include="SmokeTests.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@@ -108,6 +111,40 @@
|
|||||||
<Name>winPEAS</Name>
|
<Name>winPEAS</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</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" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
@@ -133,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\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\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')" />
|
<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>
|
||||||
|
|||||||
@@ -356,7 +356,7 @@ namespace winPEAS.Checks
|
|||||||
{
|
{
|
||||||
var rangeParts = networkType.Split('/');
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -392,7 +392,7 @@ namespace winPEAS.Checks
|
|||||||
|
|
||||||
foreach (string regHkcu in passRegHkcu)
|
foreach (string regHkcu in passRegHkcu)
|
||||||
{
|
{
|
||||||
Beaprint.DictPrint(RegistryHelper.GetRegValues("HKLM", regHkcu), false);
|
Beaprint.DictPrint(RegistryHelper.GetRegValues("HKCU", regHkcu), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (string regHklm in passRegHklm)
|
foreach (string regHklm in passRegHklm)
|
||||||
@@ -524,7 +524,7 @@ namespace winPEAS.Checks
|
|||||||
{
|
{
|
||||||
Beaprint.MainPrint("Looking for documents --limit 100--");
|
Beaprint.MainPrint("Looking for documents --limit 100--");
|
||||||
List<string> docFiles = InterestingFiles.InterestingFiles.ListUsersDocs();
|
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)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -546,7 +546,7 @@ namespace winPEAS.Checks
|
|||||||
|
|
||||||
if (recFiles.Count != 0)
|
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);
|
Beaprint.AnsiPrint(" " + recF["Target"] + "(" + recF["Accessed"] + ")", colorF);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -348,8 +348,7 @@ namespace winPEAS.Checks
|
|||||||
Beaprint.MainPrint("DNS cached --limit 70--");
|
Beaprint.MainPrint("DNS cached --limit 70--");
|
||||||
Beaprint.GrayPrint(string.Format(" {0,-38}{1,-38}{2}", "Entry", "Name", "Data"));
|
Beaprint.GrayPrint(string.Format(" {0,-38}{1,-38}{2}", "Entry", "Name", "Data"));
|
||||||
List<Dictionary<string, string>> DNScache = NetworkInfoHelper.GetDNSCache();
|
List<Dictionary<string, string>> DNScache = NetworkInfoHelper.GetDNSCache();
|
||||||
foreach (Dictionary<string, string> entry in DNScache.GetRange(0,
|
foreach (Dictionary<string, string> entry in MyUtils.GetLimitedRange(DNScache, 70))
|
||||||
DNScache.Count <= 70 ? DNScache.Count : 70))
|
|
||||||
{
|
{
|
||||||
Console.WriteLine($" {entry["Entry"],-38}{entry["Name"],-38}{entry["Data"]}");
|
Console.WriteLine($" {entry["Entry"],-38}{entry["Name"],-38}{entry["Data"]}");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ namespace winPEAS.Checks
|
|||||||
PrintLocalGroupPolicy,
|
PrintLocalGroupPolicy,
|
||||||
PrintPotentialGPOAbuse,
|
PrintPotentialGPOAbuse,
|
||||||
AppLockerHelper.PrintAppLockerPolicy,
|
AppLockerHelper.PrintAppLockerPolicy,
|
||||||
|
PrintPrintNightmarePointAndPrint,
|
||||||
PrintPrintersWMIInfo,
|
PrintPrintersWMIInfo,
|
||||||
PrintNamedPipes,
|
PrintNamedPipes,
|
||||||
PrintNamedPipeAbuseCandidates,
|
PrintNamedPipeAbuseCandidates,
|
||||||
@@ -836,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()
|
private static void PrintPrintersWMIInfo()
|
||||||
{
|
{
|
||||||
Beaprint.MainPrint("Enumerating Printers (WMI)");
|
Beaprint.MainPrint("Enumerating Printers (WMI)");
|
||||||
|
|||||||
@@ -21,6 +21,11 @@ namespace winPEAS.Helpers
|
|||||||
""); //To get the default object you need to use an empty string
|
""); //To get the default object you need to use an empty string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<T> GetLimitedRange<T>(List<T> items, int limit)
|
||||||
|
{
|
||||||
|
return items.GetRange(0, Math.Min(items.Count, limit));
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////
|
////////////////////////////////////
|
||||||
/////// MISC - Files & Paths ///////
|
/////// MISC - Files & Paths ///////
|
||||||
////////////////////////////////////
|
////////////////////////////////////
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ namespace winPEAS.Info.NetworkInfo
|
|||||||
|
|
||||||
// 4. Call external checker
|
// 4. Call external checker
|
||||||
var resp = httpClient
|
var resp = httpClient
|
||||||
.PostAsync("https://2e6ppt7izvuv66qmx2r3et2ufi0mxwqs.lambda-url.us-east-1.on.aws/", payload)
|
.PostAsync("https://tools.hacktricks.wiki/api/host-checker", payload)
|
||||||
.GetAwaiter().GetResult();
|
.GetAwaiter().GetResult();
|
||||||
|
|
||||||
if (resp.IsSuccessStatusCode)
|
if (resp.IsSuccessStatusCode)
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ using System.Net.Http;
|
|||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Net.NetworkInformation;
|
using System.Net.NetworkInformation;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace winPEAS.Info.NetworkInfo
|
namespace winPEAS.Info.NetworkInfo
|
||||||
@@ -48,7 +50,7 @@ namespace winPEAS.Info.NetworkInfo
|
|||||||
{ "1.1.1.1", "8.8.8.8" };
|
{ "1.1.1.1", "8.8.8.8" };
|
||||||
|
|
||||||
private const string LAMBDA_URL =
|
private const string LAMBDA_URL =
|
||||||
"https://2e6ppt7izvuv66qmx2r3et2ufi0mxwqs.lambda-url.us-east-1.on.aws/";
|
"https://tools.hacktricks.wiki/api/host-checker";
|
||||||
|
|
||||||
// Shared HttpClient (kept for HTTP & Lambda checks)
|
// Shared HttpClient (kept for HTTP & Lambda checks)
|
||||||
private static readonly HttpClient http = new HttpClient
|
private static readonly HttpClient http = new HttpClient
|
||||||
@@ -118,7 +120,12 @@ namespace winPEAS.Info.NetworkInfo
|
|||||||
using var cts =
|
using var cts =
|
||||||
new CancellationTokenSource(TimeSpan.FromMilliseconds(HTTP_TIMEOUT_MS));
|
new CancellationTokenSource(TimeSpan.FromMilliseconds(HTTP_TIMEOUT_MS));
|
||||||
|
|
||||||
var req = new HttpRequestMessage(HttpMethod.Get, LAMBDA_URL);
|
var payload = new StringContent(
|
||||||
|
JsonSerializer.Serialize(new { hostname = Environment.MachineName }),
|
||||||
|
Encoding.UTF8,
|
||||||
|
"application/json");
|
||||||
|
var req = new HttpRequestMessage(HttpMethod.Post, LAMBDA_URL);
|
||||||
|
req.Content = payload;
|
||||||
req.Headers.UserAgent.ParseAdd("winpeas");
|
req.Headers.UserAgent.ParseAdd("winpeas");
|
||||||
req.Headers.Accept.Add(
|
req.Headers.Accept.Add(
|
||||||
new MediaTypeWithQualityHeaderValue("application/json"));
|
new MediaTypeWithQualityHeaderValue("application/json"));
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ namespace winPEAS.Info.UserInfo.SAM
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
if (_maxPasswordAge == long.MinValue)
|
||||||
|
{
|
||||||
|
return TimeSpan.MinValue;
|
||||||
|
}
|
||||||
return -new TimeSpan(_maxPasswordAge);
|
return -new TimeSpan(_maxPasswordAge);
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
@@ -28,6 +32,10 @@ namespace winPEAS.Info.UserInfo.SAM
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
if (_minPasswordAge == long.MinValue)
|
||||||
|
{
|
||||||
|
return TimeSpan.MinValue;
|
||||||
|
}
|
||||||
return -new TimeSpan(_minPasswordAge);
|
return -new TimeSpan(_minPasswordAge);
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
|
|||||||
@@ -88,6 +88,10 @@ namespace winPEAS.KnownFileCreds
|
|||||||
if (SID.StartsWith("S-1-5") && !SID.EndsWith("_Classes"))
|
if (SID.StartsWith("S-1-5") && !SID.EndsWith("_Classes"))
|
||||||
{
|
{
|
||||||
string[] subKeys = RegistryHelper.GetRegSubkeys("HKU", string.Format("{0}\\Software\\SimonTatham\\PuTTY\\Sessions\\", SID));
|
string[] subKeys = RegistryHelper.GetRegSubkeys("HKU", string.Format("{0}\\Software\\SimonTatham\\PuTTY\\Sessions\\", SID));
|
||||||
|
if (subKeys.Length == 0)
|
||||||
|
{
|
||||||
|
subKeys = RegistryHelper.GetRegSubkeys("HKU", string.Format("{0}\\Software\\SimonTatham\\PuTTY\\Sessions", SID));
|
||||||
|
}
|
||||||
|
|
||||||
foreach (string sessionName in subKeys)
|
foreach (string sessionName in subKeys)
|
||||||
{
|
{
|
||||||
@@ -129,6 +133,10 @@ namespace winPEAS.KnownFileCreds
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
string[] subKeys = RegistryHelper.GetRegSubkeys("HKCU", "Software\\SimonTatham\\PuTTY\\Sessions\\");
|
string[] subKeys = RegistryHelper.GetRegSubkeys("HKCU", "Software\\SimonTatham\\PuTTY\\Sessions\\");
|
||||||
|
if (subKeys.Length == 0)
|
||||||
|
{
|
||||||
|
subKeys = RegistryHelper.GetRegSubkeys("HKCU", "Software\\SimonTatham\\PuTTY\\Sessions");
|
||||||
|
}
|
||||||
RegistryKey selfKey = Registry.CurrentUser.OpenSubKey(@"Software\\SimonTatham\\PuTTY\\Sessions"); // extract own Sessions registry keys
|
RegistryKey selfKey = Registry.CurrentUser.OpenSubKey(@"Software\\SimonTatham\\PuTTY\\Sessions"); // extract own Sessions registry keys
|
||||||
|
|
||||||
if (selfKey != null)
|
if (selfKey != null)
|
||||||
@@ -198,6 +206,10 @@ namespace winPEAS.KnownFileCreds
|
|||||||
if (SID.StartsWith("S-1-5") && !SID.EndsWith("_Classes"))
|
if (SID.StartsWith("S-1-5") && !SID.EndsWith("_Classes"))
|
||||||
{
|
{
|
||||||
Dictionary<string, object> hostKeys = RegistryHelper.GetRegValues("HKU", string.Format("{0}\\Software\\SimonTatham\\PuTTY\\SshHostKeys\\", SID));
|
Dictionary<string, object> hostKeys = RegistryHelper.GetRegValues("HKU", string.Format("{0}\\Software\\SimonTatham\\PuTTY\\SshHostKeys\\", SID));
|
||||||
|
if ((hostKeys == null) || (hostKeys.Count == 0))
|
||||||
|
{
|
||||||
|
hostKeys = RegistryHelper.GetRegValues("HKU", string.Format("{0}\\Software\\SimonTatham\\PuTTY\\SshHostKeys", SID));
|
||||||
|
}
|
||||||
if ((hostKeys != null) && (hostKeys.Count != 0))
|
if ((hostKeys != null) && (hostKeys.Count != 0))
|
||||||
{
|
{
|
||||||
Dictionary<string, string> putty_ssh = new Dictionary<string, string>
|
Dictionary<string, string> putty_ssh = new Dictionary<string, string>
|
||||||
@@ -216,6 +228,10 @@ namespace winPEAS.KnownFileCreds
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
Dictionary<string, object> hostKeys = RegistryHelper.GetRegValues("HKCU", "Software\\SimonTatham\\PuTTY\\SshHostKeys\\");
|
Dictionary<string, object> hostKeys = RegistryHelper.GetRegValues("HKCU", "Software\\SimonTatham\\PuTTY\\SshHostKeys\\");
|
||||||
|
if ((hostKeys == null) || (hostKeys.Count == 0))
|
||||||
|
{
|
||||||
|
hostKeys = RegistryHelper.GetRegValues("HKCU", "Software\\SimonTatham\\PuTTY\\SshHostKeys");
|
||||||
|
}
|
||||||
if ((hostKeys != null) && (hostKeys.Count != 0))
|
if ((hostKeys != null) && (hostKeys.Count != 0))
|
||||||
{
|
{
|
||||||
Dictionary<string, string> putty_ssh = new Dictionary<string, string>();
|
Dictionary<string, string> putty_ssh = new Dictionary<string, string>();
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ namespace winPEAS
|
|||||||
[STAThread]
|
[STAThread]
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
|
// TODO: keep Main minimal; this line was an intentional break in test PR.
|
||||||
Checks.Checks.Run(args);
|
Checks.Checks.Run(args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,7 +57,7 @@
|
|||||||
<Prefer32Bit>false</Prefer32Bit>
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
<LangVersion>8.0</LangVersion>
|
<LangVersion>8.0</LangVersion>
|
||||||
<RunCodeAnalysis>false</RunCodeAnalysis>
|
<RunCodeAnalysis>false</RunCodeAnalysis>
|
||||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet Condition="Exists('MinimumRecommendedRules.ruleset')">MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
@@ -71,7 +71,7 @@
|
|||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
<LangVersion>8.0</LangVersion>
|
<LangVersion>8.0</LangVersion>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet Condition="Exists('MinimumRecommendedRules.ruleset')">MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
<Prefer32Bit>false</Prefer32Bit>
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<NoWarn>0168 ; 0169; 0414; 0618; 0649</NoWarn>
|
<NoWarn>0168 ; 0169; 0414; 0618; 0649</NoWarn>
|
||||||
@@ -84,7 +84,7 @@
|
|||||||
<PlatformTarget>x64</PlatformTarget>
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
<LangVersion>8.0</LangVersion>
|
<LangVersion>8.0</LangVersion>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet Condition="Exists('MinimumRecommendedRules.ruleset')">MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
<Prefer32Bit>false</Prefer32Bit>
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
@@ -96,7 +96,7 @@
|
|||||||
<PlatformTarget>x86</PlatformTarget>
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
<LangVersion>8.0</LangVersion>
|
<LangVersion>8.0</LangVersion>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet Condition="Exists('MinimumRecommendedRules.ruleset')">MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
<Prefer32Bit>false</Prefer32Bit>
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
@@ -108,7 +108,7 @@
|
|||||||
<PlatformTarget>x86</PlatformTarget>
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
<LangVersion>8.0</LangVersion>
|
<LangVersion>8.0</LangVersion>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet Condition="Exists('MinimumRecommendedRules.ruleset')">MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
<Prefer32Bit>false</Prefer32Bit>
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -815,12 +815,40 @@ systeminfo.exe
|
|||||||
Write-Host ""
|
Write-Host ""
|
||||||
if ($TimeStamp) { TimeElapsed }
|
if ($TimeStamp) { TimeElapsed }
|
||||||
Write-Host -ForegroundColor Blue "=========|| WINDOWS HOTFIXES"
|
Write-Host -ForegroundColor Blue "=========|| WINDOWS HOTFIXES"
|
||||||
Write-Host "=| Check if windows is vulnerable with Watson https://github.com/rasta-mouse/Watson" -ForegroundColor Yellow
|
Write-Host "=| Check missing patches with WES-NG https://github.com/bitsadmin/wesng" -ForegroundColor Yellow
|
||||||
Write-Host "Possible exploits (https://github.com/codingo/OSCP-2/blob/master/Windows/WinPrivCheck.bat)" -ForegroundColor Yellow
|
Write-Host "Possible exploits (https://github.com/codingo/OSCP-2/blob/master/Windows/WinPrivCheck.bat)" -ForegroundColor Yellow
|
||||||
$Hotfix = Get-HotFix | Sort-Object -Descending -Property InstalledOn -ErrorAction SilentlyContinue | Select-Object HotfixID, Description, InstalledBy, InstalledOn
|
$Hotfix = Get-HotFix | Sort-Object -Descending -Property InstalledOn -ErrorAction SilentlyContinue | Select-Object HotfixID, Description, InstalledBy, InstalledOn
|
||||||
$Hotfix | Format-Table -AutoSize
|
$Hotfix | Format-Table -AutoSize
|
||||||
|
|
||||||
|
|
||||||
|
# PrintNightmare PointAndPrint policy checks
|
||||||
|
Write-Host ""
|
||||||
|
if ($TimeStamp) { TimeElapsed }
|
||||||
|
Write-Host -ForegroundColor Blue "=========|| PRINTNIGHTMARE POINTANDPRINT POLICY"
|
||||||
|
$pnKey = "HKLM:\Software\Policies\Microsoft\Windows NT\Printers\PointAndPrint"
|
||||||
|
if (Test-Path $pnKey) {
|
||||||
|
$pn = Get-ItemProperty -Path $pnKey -ErrorAction SilentlyContinue
|
||||||
|
$restrict = $pn.RestrictDriverInstallationToAdministrators
|
||||||
|
$noWarn = $pn.NoWarningNoElevationOnInstall
|
||||||
|
$updatePrompt = $pn.UpdatePromptSettings
|
||||||
|
|
||||||
|
Write-Host "RestrictDriverInstallationToAdministrators: $restrict"
|
||||||
|
Write-Host "NoWarningNoElevationOnInstall: $noWarn"
|
||||||
|
Write-Host "UpdatePromptSettings: $updatePrompt"
|
||||||
|
|
||||||
|
$hasAllValues = ($null -ne $restrict) -and ($null -ne $noWarn) -and ($null -ne $updatePrompt)
|
||||||
|
if (-not $hasAllValues) {
|
||||||
|
Write-Host "PointAndPrint policy values are missing or not configured" -ForegroundColor Gray
|
||||||
|
} elseif (($restrict -eq 0) -and ($noWarn -eq 1) -and ($updatePrompt -eq 2)) {
|
||||||
|
Write-Host "Potentially vulnerable to PrintNightmare misconfiguration" -ForegroundColor Red
|
||||||
|
} else {
|
||||||
|
Write-Host "PointAndPrint policy is not in the known risky configuration" -ForegroundColor Green
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-Host "PointAndPrint policy key not found" -ForegroundColor Gray
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#Show all unique updates installed
|
#Show all unique updates installed
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
if ($TimeStamp) { TimeElapsed }
|
if ($TimeStamp) { TimeElapsed }
|
||||||
@@ -1649,7 +1677,7 @@ if ($TimeStamp) { TimeElapsed }
|
|||||||
Write-Host -ForegroundColor Blue "=========|| WHOAMI INFO"
|
Write-Host -ForegroundColor Blue "=========|| WHOAMI INFO"
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
if ($TimeStamp) { TimeElapsed }
|
if ($TimeStamp) { TimeElapsed }
|
||||||
Write-Host -ForegroundColor Blue "=========|| Check Token access here: https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/privilege-escalation-abusing-tokens.html#abusing-tokens" -ForegroundColor yellow
|
Write-Host -ForegroundColor Blue "=========|| Check Token access here: https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/privilege-escalation-abusing-tokens.html#abusing-tokens"
|
||||||
Write-Host -ForegroundColor Blue "=========|| 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"
|
Write-Host -ForegroundColor Blue "=========|| 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"
|
||||||
Write-Host "https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#users--groups" -ForegroundColor Yellow
|
Write-Host "https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#users--groups" -ForegroundColor Yellow
|
||||||
Start-Process whoami.exe -ArgumentList "/all" -Wait -NoNewWindow
|
Start-Process whoami.exe -ArgumentList "/all" -Wait -NoNewWindow
|
||||||
|
|||||||
Reference in New Issue
Block a user