Compare commits

..

1 Commits

Author SHA1 Message Date
Carlos Polop
08c4c6fc1d Fix PR author detection for failure dispatch 2026-01-19 00:05:31 +01:00
47 changed files with 183 additions and 733 deletions

View File

@@ -26,7 +26,7 @@ jobs:
steps: steps:
# checkout # checkout
- name: Checkout - name: Checkout
uses: actions/checkout@v5 uses: actions/checkout@master
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@v2 uses: microsoft/setup-msbuild@v1.0.2
# Setup NuGet # Setup NuGet
- name: Setup NuGet.exe - name: Setup NuGet.exe
uses: nuget/setup-nuget@v2 uses: nuget/setup-nuget@v1
# 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 /p:Configuration=$env:Configuration /p:UseSharedCompilation=false run: msbuild $env:Solution_Path
# 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 --configuration $env:Configuration # run: dotnet test $env:Solution_Path
# 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" /p:UseSharedCompilation=false msbuild -m $env:Solution_Path /t:Rebuild /p:Configuration=$env:Configuration /p:Platform="x64"
echo "build x86" echo "build x86"
msbuild -m $env:Solution_Path /t:Rebuild /p:Configuration=$env:Configuration /p:Platform="x86" /p:UseSharedCompilation=false msbuild -m $env:Solution_Path /t:Rebuild /p:Configuration=$env:Configuration /p:Platform="x86"
echo "build Any CPU" echo "build Any CPU"
msbuild -m $env:Solution_Path /t:Rebuild /p:Configuration=$env:Configuration /p:Platform="Any CPU" /p:UseSharedCompilation=false msbuild -m $env:Solution_Path /t:Rebuild /p:Configuration=$env:Configuration /p:Platform="Any CPU"
- name: Execute winPEAS -h - name: Execute winPEAS -h
shell: pwsh shell: pwsh
@@ -220,7 +220,6 @@ 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
@@ -231,9 +230,6 @@ 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
@@ -366,7 +362,7 @@ jobs:
steps: steps:
# Download repo # Download repo
- uses: actions/checkout@v5 - uses: actions/checkout@v2
# Build linpeas # Build linpeas
- name: Build macpeas - name: Build macpeas
@@ -473,11 +469,11 @@ jobs:
- name: Get current date - name: Get current date
id: date id: date
run: echo "date=$(date +'%Y%m%d')" >> "$GITHUB_OUTPUT" run: echo "::set-output name=date::$(date +'%Y%m%d')"
- name: Generate random - name: Generate random
id: random_n id: random_n
run: echo "some_rand=$(openssl rand -hex 4)" >> "$GITHUB_OUTPUT" run: echo "::set-output name=some_rand::$(openssl rand -hex 4)"
# Create the release # Create the release
- name: Create Release - name: Create Release

View File

@@ -8,8 +8,6 @@ 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
@@ -22,7 +20,7 @@ jobs:
steps: steps:
# checkout # checkout
- name: Checkout - name: Checkout
uses: actions/checkout@v5 uses: actions/checkout@master
with: with:
ref: ${{ github.head_ref }} ref: ${{ github.head_ref }}
@@ -32,11 +30,11 @@ jobs:
# Add MSBuild to the PATH # Add MSBuild to the PATH
- name: Setup MSBuild.exe - name: Setup MSBuild.exe
uses: microsoft/setup-msbuild@v2 uses: microsoft/setup-msbuild@v1.0.2
# Setup NuGet # Setup NuGet
- name: Setup NuGet.exe - name: Setup NuGet.exe
uses: nuget/setup-nuget@v2 uses: nuget/setup-nuget@v1
# Restore the packages for testing # Restore the packages for testing
- name: Restore the application - name: Restore the application
@@ -44,23 +42,19 @@ jobs:
# build # build
- name: run MSBuild - name: run MSBuild
run: msbuild $env:Solution_Path /p:Configuration=$env:Configuration /p:UseSharedCompilation=false run: msbuild $env:Solution_Path
# 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" /p:UseSharedCompilation=false msbuild -m $env:Solution_Path /t:Rebuild /p:Configuration=$env:Configuration /p:Platform="x64"
echo "build x86" echo "build x86"
msbuild -m $env:Solution_Path /t:Rebuild /p:Configuration=$env:Configuration /p:Platform="x86" /p:UseSharedCompilation=false msbuild -m $env:Solution_Path /t:Rebuild /p:Configuration=$env:Configuration /p:Platform="x86"
echo "build Any CPU" echo "build Any CPU"
msbuild -m $env:Solution_Path /t:Rebuild /p:Configuration=$env:Configuration /p:Platform="Any CPU" /p:UseSharedCompilation=false msbuild -m $env:Solution_Path /t:Rebuild /p:Configuration=$env:Configuration /p:Platform="Any CPU"
- name: Execute winPEAS -h - name: Execute winPEAS -h
shell: pwsh shell: pwsh
@@ -111,7 +105,7 @@ jobs:
steps: steps:
# Download repo # Download repo
- uses: actions/checkout@v5 - uses: actions/checkout@v2
with: with:
ref: ${{ github.head_ref }} ref: ${{ github.head_ref }}
@@ -119,7 +113,6 @@ 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
@@ -130,9 +123,6 @@ 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
@@ -171,7 +161,7 @@ jobs:
steps: steps:
# Download repo # Download repo
- uses: actions/checkout@v5 - uses: actions/checkout@v2
with: with:
ref: ${{ github.head_ref }} ref: ${{ github.head_ref }}

View File

@@ -1,95 +1,41 @@
name: Codex PR Triage name: Codex PR Triage
on: on:
workflow_run: pull_request:
workflows: ["PR-tests"] types: [opened]
types: [completed]
jobs: jobs:
codex_triage: codex_triage:
if: ${{ github.event.workflow_run.conclusion == 'success' }} if: ${{ github.event.pull_request.user.login == 'carlospolop' }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
contents: write contents: write
pull-requests: write pull-requests: write
outputs: 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 }} decision: ${{ steps.parse.outputs.decision }}
message: ${{ steps.parse.outputs.message }} message: ${{ steps.parse.outputs.message }}
steps: 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 - name: Checkout PR merge ref
uses: actions/checkout@v5 uses: actions/checkout@v5
with: with:
ref: refs/pull/${{ steps.gate.outputs.pr_number }}/merge ref: refs/pull/${{ github.event.pull_request.number }}/merge
if: ${{ steps.gate.outputs.should_run == 'true' }}
- name: Pre-fetch base and head refs - name: Pre-fetch base and head refs
if: ${{ steps.gate.outputs.should_run == 'true' }}
run: | run: |
git fetch --no-tags origin \ git fetch --no-tags origin \
${{ steps.gate.outputs.base_ref }} \ ${{ github.event.pull_request.base.ref }} \
+refs/pull/${{ steps.gate.outputs.pr_number }}/head +refs/pull/${{ github.event.pull_request.number }}/head
- name: Run Codex - name: Run Codex
id: run_codex id: run_codex
if: ${{ steps.gate.outputs.should_run == 'true' }}
uses: openai/codex-action@v1 uses: openai/codex-action@v1
with: with:
openai-api-key: ${{ secrets.OPENAI_API_KEY }} openai-api-key: ${{ secrets.OPENAI_API_KEY }}
output-schema-file: .github/codex/pr-merge-schema.json output-schema-file: .github/codex/pr-merge-schema.json
model: gpt-5.2-codex model: gpt-5.2-codex
prompt: | prompt: |
You are reviewing PR #${{ steps.gate.outputs.pr_number }} for ${{ github.repository }}. 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: 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 are simple and safe (no DoS, no long operations, no backdoors).
@@ -102,17 +48,16 @@ jobs:
Pull request title and body: Pull request title and body:
---- ----
${{ steps.gate.outputs.pr_title }} ${{ github.event.pull_request.title }}
${{ steps.gate.outputs.pr_body }} ${{ github.event.pull_request.body }}
Review ONLY the changes introduced by the PR: Review ONLY the changes introduced by the PR:
git log --oneline ${{ steps.gate.outputs.base_sha }}...${{ steps.gate.outputs.head_sha }} git log --oneline ${{ github.event.pull_request.base.sha }}...${{ github.event.pull_request.head.sha }}
Output JSON only, following the provided schema. Output JSON only, following the provided schema.
- name: Parse Codex decision - name: Parse Codex decision
id: parse id: parse
if: ${{ steps.gate.outputs.should_run == 'true' }}
env: env:
CODEX_MESSAGE: ${{ steps.run_codex.outputs.final-message }} CODEX_MESSAGE: ${{ steps.run_codex.outputs.final-message }}
run: | run: |
@@ -133,7 +78,7 @@ jobs:
merge_or_comment: merge_or_comment:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: codex_triage needs: codex_triage
if: ${{ github.event.workflow_run.conclusion == 'success' && needs.codex_triage.outputs.should_run == 'true' && needs.codex_triage.outputs.decision != '' }} if: ${{ needs.codex_triage.outputs.decision != '' }}
permissions: permissions:
contents: write contents: write
pull-requests: write pull-requests: write
@@ -142,7 +87,7 @@ jobs:
if: ${{ needs.codex_triage.outputs.decision == 'merge' }} if: ${{ needs.codex_triage.outputs.decision == 'merge' }}
env: env:
GH_TOKEN: ${{ github.token }} GH_TOKEN: ${{ github.token }}
PR_NUMBER: ${{ needs.codex_triage.outputs.pr_number }} PR_NUMBER: ${{ github.event.pull_request.number }}
run: | run: |
gh api \ gh api \
-X PUT \ -X PUT \
@@ -155,7 +100,7 @@ jobs:
if: ${{ needs.codex_triage.outputs.decision == 'comment' }} if: ${{ needs.codex_triage.outputs.decision == 'comment' }}
uses: actions/github-script@v7 uses: actions/github-script@v7
env: env:
PR_NUMBER: ${{ needs.codex_triage.outputs.pr_number }} PR_NUMBER: ${{ github.event.pull_request.number }}
CODEX_MESSAGE: ${{ needs.codex_triage.outputs.message }} CODEX_MESSAGE: ${{ needs.codex_triage.outputs.message }}
with: with:
github-token: ${{ github.token }} github-token: ${{ github.token }}

View File

@@ -6,7 +6,7 @@ on:
types: [completed] types: [completed]
jobs: jobs:
resolve_pr_context: codex_on_failure:
if: > if: >
${{ github.event.workflow_run.conclusion == 'failure' && ${{ github.event.workflow_run.conclusion == 'failure' &&
github.event.workflow_run.pull_requests && github.event.workflow_run.pull_requests &&
@@ -14,14 +14,11 @@ jobs:
!startsWith(github.event.workflow_run.head_commit.message, 'Fix CI failures for PR #') }} !startsWith(github.event.workflow_run.head_commit.message, 'Fix CI failures for PR #') }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
pull-requests: read contents: write
issues: read pull-requests: write
outputs: issues: write
number: ${{ steps.pr_context.outputs.number }} actions: read
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: steps:
- name: Resolve PR context - name: Resolve PR context
id: pr_context id: pr_context
@@ -29,46 +26,38 @@ jobs:
PR_NUMBER: ${{ github.event.workflow_run.pull_requests[0].number }} PR_NUMBER: ${{ github.event.workflow_run.pull_requests[0].number }}
GH_TOKEN: ${{ github.token }} GH_TOKEN: ${{ github.token }}
run: | run: |
pr_author=$(gh api -H "Accept: application/vnd.github+json" \ pr_json=$(gh api -H "Accept: application/vnd.github+json" \
/repos/${{ github.repository }}/pulls/${PR_NUMBER} \ /repos/${{ github.repository }}/pulls/${PR_NUMBER})
--jq '.user.login') pr_author=$(printf "%s" "$pr_json" | python3 - <<'PY'
pr_head_repo=$(gh api -H "Accept: application/vnd.github+json" \ import json,sys
/repos/${{ github.repository }}/pulls/${PR_NUMBER} \ data=json.load(sys.stdin)
--jq '.head.repo.full_name') print(data.get("user",{}).get("login",""))
pr_head_branch=$(gh api -H "Accept: application/vnd.github+json" \ PY
/repos/${{ github.repository }}/pulls/${PR_NUMBER} \ )
--jq '.head.ref') pr_head_repo=$(printf "%s" "$pr_json" | python3 - <<'PY'
pr_labels=$(gh api -H "Accept: application/vnd.github+json" \ import json,sys
/repos/${{ github.repository }}/issues/${PR_NUMBER} \ data=json.load(sys.stdin)
--jq '.labels[].name') print(data.get("head",{}).get("repo",{}).get("full_name",""))
if echo "$pr_labels" | grep -q "^codex-fix-attempted$"; then PY
echo "codex fix already attempted for PR #${PR_NUMBER}; skipping." )
should_run=false pr_head_branch=$(printf "%s" "$pr_json" | python3 - <<'PY'
else import json,sys
should_run=true data=json.load(sys.stdin)
fi print(data.get("head",{}).get("ref",""))
PY
)
{ {
echo "number=${PR_NUMBER}" echo "number=${PR_NUMBER}"
echo "author=${pr_author}" echo "author=${pr_author}"
echo "head_repo=${pr_head_repo}" echo "head_repo=${pr_head_repo}"
echo "head_branch=${pr_head_branch}" echo "head_branch=${pr_head_branch}"
echo "should_run=${should_run}"
} >> "$GITHUB_OUTPUT" } >> "$GITHUB_OUTPUT"
codex_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 - name: Comment on PR with failure info
if: ${{ steps.pr_context.outputs.author == 'carlospolop' }}
uses: actions/github-script@v7 uses: actions/github-script@v7
env: env:
PR_NUMBER: ${{ needs.resolve_pr_context.outputs.number }} PR_NUMBER: ${{ steps.pr_context.outputs.number }}
RUN_URL: ${{ github.event.workflow_run.html_url }} RUN_URL: ${{ github.event.workflow_run.html_url }}
WORKFLOW_NAME: ${{ github.event.workflow_run.name }} WORKFLOW_NAME: ${{ github.event.workflow_run.name }}
with: with:
@@ -83,30 +72,23 @@ jobs:
body, 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[]=codex-fix-attempted
- name: Checkout PR head - name: Checkout PR head
if: ${{ steps.pr_context.outputs.author == 'carlospolop' }}
uses: actions/checkout@v5 uses: actions/checkout@v5
with: with:
repository: ${{ needs.resolve_pr_context.outputs.head_repo }} repository: ${{ steps.pr_context.outputs.head_repo }}
ref: ${{ github.event.workflow_run.head_sha }} ref: ${{ github.event.workflow_run.head_sha }}
fetch-depth: 0 fetch-depth: 0
persist-credentials: true persist-credentials: true
token: ${{ secrets.CODEX_FIXER_TOKEN }}
- name: Configure git author - name: Configure git author
if: ${{ steps.pr_context.outputs.author == 'carlospolop' }}
run: | run: |
git config user.name "codex-action" git config user.name "codex-action"
git config user.email "codex-action@users.noreply.github.com" git config user.email "codex-action@users.noreply.github.com"
- name: Fetch failure summary - name: Fetch failure summary
if: ${{ steps.pr_context.outputs.author == 'carlospolop' }}
env: env:
GH_TOKEN: ${{ github.token }} GH_TOKEN: ${{ github.token }}
RUN_ID: ${{ github.event.workflow_run.id }} RUN_ID: ${{ github.event.workflow_run.id }}
@@ -134,10 +116,11 @@ jobs:
PY PY
- name: Create Codex prompt - name: Create Codex prompt
if: ${{ steps.pr_context.outputs.author == 'carlospolop' }}
env: env:
PR_NUMBER: ${{ needs.resolve_pr_context.outputs.number }} PR_NUMBER: ${{ steps.pr_context.outputs.number }}
RUN_URL: ${{ github.event.workflow_run.html_url }} RUN_URL: ${{ github.event.workflow_run.html_url }}
HEAD_BRANCH: ${{ needs.resolve_pr_context.outputs.head_branch }} HEAD_BRANCH: ${{ steps.pr_context.outputs.head_branch }}
run: | run: |
{ {
echo "You are fixing CI failures for PR #${PR_NUMBER} in ${{ github.repository }}." echo "You are fixing CI failures for PR #${PR_NUMBER} in ${{ github.repository }}."
@@ -153,6 +136,7 @@ jobs:
} > codex_prompt.txt } > codex_prompt.txt
- name: Run Codex - name: Run Codex
if: ${{ steps.pr_context.outputs.author == 'carlospolop' }}
id: run_codex id: run_codex
uses: openai/codex-action@v1 uses: openai/codex-action@v1
with: with:
@@ -162,25 +146,24 @@ jobs:
model: gpt-5.2-codex model: gpt-5.2-codex
- name: Commit and push if changed - name: Commit and push if changed
if: ${{ steps.pr_context.outputs.author == 'carlospolop' }}
env: env:
TARGET_BRANCH: ${{ needs.resolve_pr_context.outputs.head_branch }} TARGET_BRANCH: ${{ steps.pr_context.outputs.head_branch }}
PR_NUMBER: ${{ needs.resolve_pr_context.outputs.number }} PR_NUMBER: ${{ steps.pr_context.outputs.number }}
run: | run: |
if git diff --quiet; then if git diff --quiet; then
echo "No changes to commit." echo "No changes to commit."
exit 0 exit 0
fi fi
rm -f codex_failure_summary.txt codex_prompt.txt
git add -A git add -A
git reset -- codex_failure_summary.txt codex_prompt.txt
git commit -m "Fix CI failures for PR #${PR_NUMBER}" git commit -m "Fix CI failures for PR #${PR_NUMBER}"
git push origin HEAD:${TARGET_BRANCH} git push origin HEAD:${TARGET_BRANCH}
- name: Comment with Codex result - name: Comment with Codex result
if: ${{ steps.run_codex.outputs.final-message != '' }} if: ${{ steps.pr_context.outputs.author == 'carlospolop' && steps.run_codex.outputs.final-message != '' }}
uses: actions/github-script@v7 uses: actions/github-script@v7
env: env:
PR_NUMBER: ${{ needs.resolve_pr_context.outputs.number }} PR_NUMBER: ${{ steps.pr_context.outputs.number }}
CODEX_MESSAGE: ${{ steps.run_codex.outputs.final-message }} CODEX_MESSAGE: ${{ steps.run_codex.outputs.final-message }}
with: with:
github-token: ${{ github.token }} github-token: ${{ github.token }}

0
LICENSE Normal file → Executable file
View File

0
README.md Normal file → Executable file
View File

View File

@@ -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'
- 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 - 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
files: files:
- name: "redis.conf" - name: "redis.conf"

View File

@@ -30,9 +30,10 @@
# Fat linpeas: 0 # Fat linpeas: 0
# Small linpeas: 0 # Small linpeas: 0
if apt list --installed 2>/dev/null | grep -E 'polkit.*0\.105-26' | grep -qEv 'ubuntu1\.[1-9]' || \ if apt list --installed 2>/dev/null | grep -q 'polkit.*0\.105-26' || \
yum list installed 2>/dev/null | grep -qE 'polkit.*\(0\.117-2\|0\.115-6\|0\.11[3-9]\)' || \ yum list installed 2>/dev/null | grep -q 'polkit.*\(0\.117-2\|0\.115-6\)' || \
rpm -qa 2>/dev/null | grep -qE 'polkit.*\(0\.117-2\|0\.115-6\|0\.11[3-9]\)'; then rpm -qa 2>/dev/null | grep -q 'polkit.*\(0\.117-2\|0\.115-6\)'; 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

View File

@@ -30,33 +30,11 @@
# 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, $protected_symlinks, $protected_hardlinks, $label, $sysctl_path, $sysctl_var, $zero_color, $nonzero_color, $sysctl_value # Generated Global Variables: $ASLR, $hypervisorflag, $detectedvirt, $unpriv_userns_clone, $perf_event_paranoid, $mmap_min_addr, $ptrace_scope, $dmesg_restrict, $kptr_restrict, $unpriv_bpf_disabled
# 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
@@ -103,25 +81,51 @@ 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_sysctl_eq_zero "unpriv_userns_clone? ........... " "/proc/sys/kernel/unprivileged_userns_clone" "unpriv_userns_clone" "$SED_GREEN" "$SED_RED" print_list "unpriv_userns_clone? ........... "$NC
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_sysctl_eq_zero "unpriv_bpf_disabled? ........... " "/proc/sys/kernel/unprivileged_bpf_disabled" "unpriv_bpf_disabled" "$SED_RED" "$SED_GREEN" print_list "unpriv_bpf_disabled? ........... "$NC
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_sysctl_eq_zero "kptr_restrict? ................. " "/proc/sys/kernel/kptr_restrict" "kptr_restrict" "$SED_RED" "$SED_GREEN" print_list "kptr_restrict? ................. "$NC
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_sysctl_eq_zero "dmesg_restrict? ................ " "/proc/sys/kernel/dmesg_restrict" "dmesg_restrict" "$SED_RED" "$SED_GREEN" print_list "dmesg_restrict? ................ "$NC
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_sysctl_eq_zero "ptrace_scope? .................. " "/proc/sys/kernel/yama/ptrace_scope" "ptrace_scope" "$SED_RED" "$SED_GREEN" print_list "ptrace_scope? .................. "$NC
ptrace_scope=$(cat /proc/sys/kernel/yama/ptrace_scope 2>/dev/null)
print_sysctl_eq_zero "protected_symlinks? ............ " "/proc/sys/fs/protected_symlinks" "protected_symlinks" "$SED_RED" "$SED_GREEN" if [ -z "$ptrace_scope" ]; then
echo_not_found "/proc/sys/kernel/yama/ptrace_scope"
print_sysctl_eq_zero "protected_hardlinks? ........... " "/proc/sys/fs/protected_hardlinks" "protected_hardlinks" "$SED_RED" "$SED_GREEN" else
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)
@@ -131,7 +135,13 @@ 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_sysctl_eq_zero "mmap_min_addr? ................. " "/proc/sys/vm/mmap_min_addr" "mmap_min_addr" "$SED_RED" "$SED_GREEN" print_list "mmap_min_addr? ................. "$NC
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

View File

@@ -4,7 +4,6 @@
# 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:
@@ -45,8 +44,4 @@ 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

View File

@@ -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, $IAMROOT, $SEARCH_IN_FOLDER, $TIMEOUT, $WRITABLESYSTEMDPATH # Global Variables: $EXTRA_CHECKS, $SEARCH_IN_FOLDER, $IAMROOT, $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,11 +178,7 @@ 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:"
if [ "$TIMEOUT" ]; then (service --status-all || service -e || chkconfig --list || rc-status || launchctl list) 2>/dev/null || echo_not_found "service|chkconfig|rc-status|launchctl"
$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
@@ -194,4 +190,4 @@ if ! [ "$SEARCH_IN_FOLDER" ]; then
fi fi
echo "" echo ""
fi fi

View File

@@ -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, $exec_value, $cmd, $cmd_path # Generated Global Variables: $WRITABLESYSTEMDPATH, $line, $service, $file, $version, $user, $caps, $path, $path_line, $service_file, $exec_line, $cmd
# Fat linpeas: 0 # Fat linpeas: 0
# Small linpeas: 1 # Small linpeas: 1
@@ -116,20 +116,18 @@ 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 command from the right side of Exec*=, not from argv # Extract the first word after ExecStart* as the command
exec_value="${exec_line#*=}" cmd=$(echo "$exec_line" | awk '{print $2}' | tr -d '"')
exec_value=$(echo "$exec_value" | sed 's/^[[:space:]]*//') # Extract the rest as arguments
cmd=$(echo "$exec_value" | awk '{print $1}' | tr -d '"') args=$(echo "$exec_line" | awk '{$1=$2=""; print $0}' | 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_path" ] && [ -w "$cmd_path" ]; then if [ -n "$cmd" ] && [ -w "$cmd" ]; then
echo "$service: $cmd_path (from $exec_line)" | sed -${E} "s,.*,${SED_RED},g" echo "$service: $cmd (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_path" ] && [ "${cmd_path#/}" = "$cmd_path" ] && [ "${cmd_path#\$}" = "$cmd_path" ]; then if [ -n "$cmd" ] && [ "${cmd#/}" = "$cmd" ] && ! echo "$cmd" | grep -qE '^-|^--'; then
echo "$service: Uses relative path '$cmd_path' (from $exec_line)" | sed -${E} "s,.*,${SED_RED},g" echo "$service: Uses relative path '$cmd' (from $exec_line)" | sed -${E} "s,.*,${SED_RED},g"
fi fi
done done
fi fi
@@ -155,4 +153,4 @@ if ! [ "$SEARCH_IN_FOLDER" ]; then
fi fi
echo "" echo ""
fi fi

View File

@@ -1,25 +0,0 @@
# 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

View File

@@ -23,7 +23,6 @@ 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
@@ -248,4 +247,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 ""

View File

@@ -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, $pkexec_version, $policy_dir, $policy_file # Generated Global Variables: $pkexec_bin, $policy_dir, $policy_file
# Fat linpeas: 0 # Fat linpeas: 0
# Small linpeas: 1 # Small linpeas: 1
@@ -30,10 +30,6 @@ 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

View File

@@ -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, $TIMEOUT, $USER # Global Variables: $MACPEAS, $sh_usrs, $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,16 +26,8 @@ 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 [ -x "$f" ]; then if $f -c 'whoami' 2>/dev/null | grep -q "$USER"; then
if [ "$TIMEOUT" ]; then unexpected_shells="$f\n$unexpected_shells"
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},"
@@ -49,4 +41,4 @@ else
done done
fi fi
fi fi
echo "" echo ""

View File

@@ -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: $secure_path_line # Generated Global Variables:
# Fat linpeas: 0 # Fat linpeas: 0
# Small linpeas: 1 # Small linpeas: 1
@@ -19,16 +19,6 @@ 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},"
@@ -39,4 +29,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 ""

View File

@@ -40,18 +40,4 @@ 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 ""

View File

@@ -1,64 +0,0 @@
# 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

View File

@@ -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 "$sname" | grep -q $(echo $b | cut -d % -f 1); then if echo $s | 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 "$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 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
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 ""

View File

@@ -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://tools.hacktricks.wiki/api/host-checker" -H "User-Agent: linpeas" -d "{\"hostname\":\"$(hostname)\"}" -H "Content-Type: application/json" --max-time "$INTERNET_SEARCH_TIMEOUT" 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"
elif command -v wget >/dev/null 2>&1; then elif command -v wget >/dev/null 2>&1; then
wget -q -O - "https://tools.hacktricks.wiki/api/host-checker" --header "User-Agent: linpeas" --post-data "{\"hostname\":\"$(hostname)\"}" -H "Content-Type: application/json" --timeout "$INTERNET_SEARCH_TIMEOUT" wget -q -O - "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"
else else
echo "wget or curl not found" echo "wget or curl not found"
fi fi
} }

View File

@@ -15,12 +15,11 @@
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://tools.hacktricks.wiki/api/host-checker" local url_lambda="https://2e6ppt7izvuv66qmx2r3et2ufi0mxwqs.lambda-url.us-east-1.on.aws/"
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" \ -H "User-Agent: linpeas" -H "Content-Type: application/json" >/dev/null 2>&1
-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
@@ -31,8 +30,7 @@ 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" \ --header "User-Agent: linpeas" -H "Content-Type: application/json" >/dev/null 2>&1
--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

View File

@@ -15,5 +15,6 @@
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$|/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$" 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$"
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$"

View File

@@ -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|env_keep\W*\+=.*PATH|!env_reset|!requiretty|peass{SUDOVB1_HERE}" sudoVB1=" \*|env_keep\W*\+=.*LD_PRELOAD|env_keep\W*\+=.*LD_LIBRARY_PATH|env_keep\W*\+=.*BASH_ENV|env_keep\W*\+=.* ENV|peass{SUDOVB1_HERE}"
sudoVB2="peass{SUDOVB2_HERE}" sudoVB2="peass{SUDOVB2_HERE}"

View File

@@ -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("\\", "\\\\").replace('"', '\\"').strip() regex = regex.replace('"', '\\"').strip()
falsePositives = entry.get("falsePositives", False) falsePositives = entry.get("falsePositives", False)
if falsePositives: if falsePositives:

View File

@@ -8,7 +8,6 @@ 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()
@@ -30,7 +29,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 os.path.realpath(module["folder_path"]) in real_path: if module["folder_path"] in path:
self.section_info = module self.section_info = module
self.is_check = True self.is_check = True
break break

View File

@@ -1,40 +0,0 @@
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()

View File

@@ -1,60 +0,0 @@
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()

View File

@@ -127,9 +127,7 @@ 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)
if C_SECTION == {}: C_SECTION["infos"].append(title)
return
C_SECTION.setdefault("infos", []).append(title)
#If here, then it's text #If here, then it's text
else: else:

View File

@@ -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 wmic qfe get Caption,Description,HotFixID,InstalledOn | more
) 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 WMIC /Node:localhost /Namespace:\\root\SecurityCenter2 Path AntiVirusProduct Get displayName /Format:List | more
) 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 wmic logicaldisk get caption | more
) 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') do ( for /f %%x in ('wmic logicaldisk get name ^| more') do (
set tdrive=%%x set tdrive=%%x
if "!tdrive:~1,2!" == ":" ( if "!tdrive:~1,2!" == ":" (
%%x %%x

View File

@@ -1,26 +0,0 @@
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}"
)

View File

@@ -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 WES-NG to search for vulnerabilities - [x] Use Watson 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
- Maintain updated WES-NG - Mantain updated Watson (last JAN 2021)
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.

View File

@@ -1,36 +0,0 @@
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"));
}
}
}

View File

@@ -1,37 +0,0 @@
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=" });
}
}
}

View File

@@ -61,11 +61,9 @@
</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" />
@@ -97,7 +95,6 @@
<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>
@@ -111,40 +108,6 @@
<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>
@@ -170,4 +133,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>

View File

@@ -356,7 +356,7 @@ namespace winPEAS.Checks
{ {
var rangeParts = networkType.Split('/'); var rangeParts = networkType.Split('/');
if (rangeParts.Length == 2 && IPAddress.TryParse(rangeParts[0], out _) && int.TryParse(rangeParts[1], out int res) && res <= 32 && res >= 0) if (rangeParts.Length == 2 && int.TryParse(rangeParts[1], out int res) && res <= 32 && res >= 0)
{ {
return true; return true;
} }

View File

@@ -392,7 +392,7 @@ namespace winPEAS.Checks
foreach (string regHkcu in passRegHkcu) foreach (string regHkcu in passRegHkcu)
{ {
Beaprint.DictPrint(RegistryHelper.GetRegValues("HKCU", regHkcu), false); Beaprint.DictPrint(RegistryHelper.GetRegValues("HKLM", 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(MyUtils.GetLimitedRange(docFiles, 100)); Beaprint.ListPrint(docFiles.GetRange(0, docFiles.Count <= 100 ? docFiles.Count : 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 MyUtils.GetLimitedRange(recFiles, 70)) foreach (Dictionary<string, string> recF in recFiles.GetRange(0, recFiles.Count <= 70 ? recFiles.Count : 70))
{ {
Beaprint.AnsiPrint(" " + recF["Target"] + "(" + recF["Accessed"] + ")", colorF); Beaprint.AnsiPrint(" " + recF["Target"] + "(" + recF["Accessed"] + ")", colorF);
} }

View File

@@ -348,7 +348,8 @@ 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 MyUtils.GetLimitedRange(DNScache, 70)) foreach (Dictionary<string, string> entry in DNScache.GetRange(0,
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"]}");
} }

View File

@@ -88,7 +88,6 @@ namespace winPEAS.Checks
PrintLocalGroupPolicy, PrintLocalGroupPolicy,
PrintPotentialGPOAbuse, PrintPotentialGPOAbuse,
AppLockerHelper.PrintAppLockerPolicy, AppLockerHelper.PrintAppLockerPolicy,
PrintPrintNightmarePointAndPrint,
PrintPrintersWMIInfo, PrintPrintersWMIInfo,
PrintNamedPipes, PrintNamedPipes,
PrintNamedPipeAbuseCandidates, PrintNamedPipeAbuseCandidates,
@@ -837,39 +836,6 @@ 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)");

View File

@@ -21,11 +21,6 @@ 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 ///////
//////////////////////////////////// ////////////////////////////////////

View File

@@ -46,7 +46,7 @@ namespace winPEAS.Info.NetworkInfo
// 4. Call external checker // 4. Call external checker
var resp = httpClient var resp = httpClient
.PostAsync("https://tools.hacktricks.wiki/api/host-checker", payload) .PostAsync("https://2e6ppt7izvuv66qmx2r3et2ufi0mxwqs.lambda-url.us-east-1.on.aws/", payload)
.GetAwaiter().GetResult(); .GetAwaiter().GetResult();
if (resp.IsSuccessStatusCode) if (resp.IsSuccessStatusCode)

View File

@@ -4,8 +4,6 @@ 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
@@ -50,7 +48,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://tools.hacktricks.wiki/api/host-checker"; "https://2e6ppt7izvuv66qmx2r3et2ufi0mxwqs.lambda-url.us-east-1.on.aws/";
// 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
@@ -120,12 +118,7 @@ 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 payload = new StringContent( var req = new HttpRequestMessage(HttpMethod.Get, LAMBDA_URL);
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"));

View File

@@ -16,10 +16,6 @@ namespace winPEAS.Info.UserInfo.SAM
{ {
get get
{ {
if (_maxPasswordAge == long.MinValue)
{
return TimeSpan.MinValue;
}
return -new TimeSpan(_maxPasswordAge); return -new TimeSpan(_maxPasswordAge);
} }
set set
@@ -32,10 +28,6 @@ namespace winPEAS.Info.UserInfo.SAM
{ {
get get
{ {
if (_minPasswordAge == long.MinValue)
{
return TimeSpan.MinValue;
}
return -new TimeSpan(_minPasswordAge); return -new TimeSpan(_minPasswordAge);
} }
set set

View File

@@ -88,10 +88,6 @@ 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)
{ {
@@ -133,10 +129,6 @@ 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)
@@ -206,10 +198,6 @@ 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>
@@ -228,10 +216,6 @@ 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>();

View File

@@ -11,7 +11,6 @@ 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);
} }
} }

View File

@@ -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 Condition="Exists('MinimumRecommendedRules.ruleset')">MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRuleSet>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 Condition="Exists('MinimumRecommendedRules.ruleset')">MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRuleSet>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 Condition="Exists('MinimumRecommendedRules.ruleset')">MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRuleSet>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 Condition="Exists('MinimumRecommendedRules.ruleset')">MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRuleSet>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 Condition="Exists('MinimumRecommendedRules.ruleset')">MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>false</Prefer32Bit> <Prefer32Bit>false</Prefer32Bit>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>

View File

@@ -815,40 +815,12 @@ 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 missing patches with WES-NG https://github.com/bitsadmin/wesng" -ForegroundColor Yellow Write-Host "=| Check if windows is vulnerable with Watson https://github.com/rasta-mouse/Watson" -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 }
@@ -1677,7 +1649,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" 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 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