Compare commits

..

20 Commits

Author SHA1 Message Date
codex-action
6251c5e1fd Fix CI failures for PR #574 2026-01-20 22:31:08 +00:00
Carlos Polop
92d9f27e8b Test CI failure flow 2026-01-20 23:24:03 +01:00
Carlos Polop
b24694f00b Gate codex triage on successful PR tests 2026-01-20 23:23:42 +01:00
Carlos Polop
e777c81eba Run Codex triage after PR tests succeed 2026-01-20 23:23:42 +01:00
SirBroccoli
21a86bc365 Auto-merge PR #573 (Codex) 2026-01-20 22:17:38 +00:00
SirBroccoli
ac7cb9c73c Auto-merge PR #572 (Codex) 2026-01-20 22:17:02 +00:00
SirBroccoli
d054715fbd Merge pull request #564 from peass-ng/fix/issue-410-printnightmare
Check PrintNightmare PointAndPrint policy
2026-01-20 23:06:58 +01:00
SirBroccoli
b4c1043a93 Merge branch 'master' into fix/issue-410-printnightmare 2026-01-20 23:06:29 +01:00
Carlos Polop
1b8706aac6 Handle missing PointAndPrint values in PS1 2026-01-20 23:04:35 +01:00
SirBroccoli
3371be7bd6 Merge pull request #557 from peass-ng/fix/issue-474-service-timeout
Add timeout to service enumeration
2026-01-20 23:02:35 +01:00
SirBroccoli
2344f5b106 Auto-merge PR #570 (Codex) 2026-01-20 17:25:25 +00:00
SirBroccoli
485f91d46c Auto-merge PR #569 (Codex) 2026-01-20 17:25:00 +00:00
SirBroccoli
018e8866e6 Auto-merge PR #568 (Codex) 2026-01-20 17:24:04 +00:00
SirBroccoli
d707317278 Auto-merge PR #567 (Codex) 2026-01-20 17:23:33 +00:00
SirBroccoli
f4ef371afc Auto-merge PR #566 (Codex) 2026-01-20 17:22:47 +00:00
SirBroccoli
61f6282b5f Auto-merge PR #565 (Codex) 2026-01-20 17:22:35 +00:00
codex-action
a363541d77 Fix CI failures for PR #564 2026-01-20 17:09:07 +00:00
Carlos Polop
6fc41c9a23 Add PrintNightmare PointAndPrint policy check 2026-01-20 18:03:55 +01:00
codex-action
710709834a Fix CI failures for PR #557 2026-01-20 17:03:40 +00:00
Carlos Polop
c54f483648 Add timeout to service enumeration in extra checks 2026-01-20 17:58:36 +01:00
14 changed files with 203 additions and 31 deletions

View File

@@ -1,41 +1,94 @@
name: Codex PR Triage
on:
pull_request:
types: [opened]
workflow_run:
workflows: ["PR-tests"]
types: [completed]
jobs:
codex_triage:
if: ${{ github.event.pull_request.user.login == 'carlospolop' }}
if: ${{ github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
outputs:
should_run: ${{ steps.gate.outputs.should_run }}
pr_number: ${{ steps.gate.outputs.pr_number }}
pr_title: ${{ steps.gate.outputs.pr_title }}
pr_body: ${{ steps.gate.outputs.pr_body }}
base_ref: ${{ steps.gate.outputs.base_ref }}
head_ref: ${{ steps.gate.outputs.head_ref }}
base_sha: ${{ steps.gate.outputs.base_sha }}
head_sha: ${{ steps.gate.outputs.head_sha }}
decision: ${{ steps.parse.outputs.decision }}
message: ${{ steps.parse.outputs.message }}
steps:
- name: Resolve PR context
id: gate
env:
GH_TOKEN: ${{ github.token }}
run: |
pr_number="${{ github.event.workflow_run.pull_requests[0].number }}"
if [ -z "$pr_number" ]; then
echo "No pull request found for this workflow_run; skipping."
echo "should_run=false" >> "$GITHUB_OUTPUT"
echo "pr_number=" >> "$GITHUB_OUTPUT"
exit 0
fi
author="$(gh pr view "$pr_number" --json author --jq .author.login)"
if [ "$author" != "carlospolop" ]; then
echo "PR author is $author; skipping."
echo "should_run=false" >> "$GITHUB_OUTPUT"
echo "pr_number=$pr_number" >> "$GITHUB_OUTPUT"
exit 0
fi
pr_title="$(gh pr view "$pr_number" --json title --jq .title)"
pr_body="$(gh pr view "$pr_number" --json body --jq .body)"
base_ref="$(gh pr view "$pr_number" --json baseRefName --jq .baseRefName)"
head_ref="$(gh pr view "$pr_number" --json headRefName --jq .headRefName)"
base_sha="$(gh pr view "$pr_number" --json baseRefOid --jq .baseRefOid)"
head_sha="$(gh pr view "$pr_number" --json headRefOid --jq .headRefOid)"
echo "should_run=true" >> "$GITHUB_OUTPUT"
echo "pr_number=$pr_number" >> "$GITHUB_OUTPUT"
echo "pr_title<<EOF" >> "$GITHUB_OUTPUT"
echo "$pr_title" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
echo "pr_body<<EOF" >> "$GITHUB_OUTPUT"
echo "$pr_body" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
echo "base_ref=$base_ref" >> "$GITHUB_OUTPUT"
echo "head_ref=$head_ref" >> "$GITHUB_OUTPUT"
echo "base_sha=$base_sha" >> "$GITHUB_OUTPUT"
echo "head_sha=$head_sha" >> "$GITHUB_OUTPUT"
- name: Checkout PR merge ref
uses: actions/checkout@v5
with:
ref: refs/pull/${{ github.event.pull_request.number }}/merge
ref: refs/pull/${{ steps.gate.outputs.pr_number }}/merge
if: ${{ steps.gate.outputs.should_run == 'true' }}
- name: Pre-fetch base and head refs
if: ${{ steps.gate.outputs.should_run == 'true' }}
run: |
git fetch --no-tags origin \
${{ github.event.pull_request.base.ref }} \
+refs/pull/${{ github.event.pull_request.number }}/head
${{ steps.gate.outputs.base_ref }} \
+refs/pull/${{ steps.gate.outputs.pr_number }}/head
- name: Run Codex
id: run_codex
if: ${{ steps.gate.outputs.should_run == 'true' }}
uses: openai/codex-action@v1
with:
openai-api-key: ${{ secrets.OPENAI_API_KEY }}
output-schema-file: .github/codex/pr-merge-schema.json
model: gpt-5.2-codex
prompt: |
You are reviewing PR #${{ github.event.pull_request.number }} for ${{ github.repository }}.
You are reviewing PR #${{ steps.gate.outputs.pr_number }} for ${{ github.repository }}.
Decide whether to merge or comment. Merge only if all of the following are true:
- Changes are simple and safe (no DoS, no long operations, no backdoors).
@@ -48,16 +101,17 @@ jobs:
Pull request title and body:
----
${{ github.event.pull_request.title }}
${{ github.event.pull_request.body }}
${{ steps.gate.outputs.pr_title }}
${{ steps.gate.outputs.pr_body }}
Review ONLY the changes introduced by the PR:
git log --oneline ${{ github.event.pull_request.base.sha }}...${{ github.event.pull_request.head.sha }}
git log --oneline ${{ steps.gate.outputs.base_sha }}...${{ steps.gate.outputs.head_sha }}
Output JSON only, following the provided schema.
- name: Parse Codex decision
id: parse
if: ${{ steps.gate.outputs.should_run == 'true' }}
env:
CODEX_MESSAGE: ${{ steps.run_codex.outputs.final-message }}
run: |
@@ -78,7 +132,7 @@ jobs:
merge_or_comment:
runs-on: ubuntu-latest
needs: codex_triage
if: ${{ needs.codex_triage.outputs.decision != '' }}
if: ${{ github.event.workflow_run.conclusion == 'success' && needs.codex_triage.outputs.should_run == 'true' && needs.codex_triage.outputs.decision != '' }}
permissions:
contents: write
pull-requests: write
@@ -87,7 +141,7 @@ jobs:
if: ${{ needs.codex_triage.outputs.decision == 'merge' }}
env:
GH_TOKEN: ${{ github.token }}
PR_NUMBER: ${{ github.event.pull_request.number }}
PR_NUMBER: ${{ needs.codex_triage.outputs.pr_number }}
run: |
gh api \
-X PUT \
@@ -100,7 +154,7 @@ jobs:
if: ${{ needs.codex_triage.outputs.decision == 'comment' }}
uses: actions/github-script@v7
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
PR_NUMBER: ${{ needs.codex_triage.outputs.pr_number }}
CODEX_MESSAGE: ${{ needs.codex_triage.outputs.message }}
with:
github-token: ${{ github.token }}

View File

@@ -31,8 +31,8 @@
# Small linpeas: 0
if apt list --installed 2>/dev/null | grep -E 'polkit.*0\.105-26' | grep -qEv 'ubuntu1\.[1-9]' || \
yum list installed 2>/dev/null | grep -q 'polkit.*\(0\.117-2\|0\.115-6\)' || \
rpm -qa 2>/dev/null | grep -q 'polkit.*\(0\.117-2\|0\.115-6\)'; then
yum list installed 2>/dev/null | grep -qE 'polkit.*\(0\.117-2\|0\.115-6\|0\.11[3-9]\)' || \
rpm -qa 2>/dev/null | grep -qE 'polkit.*\(0\.117-2\|0\.115-6\|0\.11[3-9]\)'; then
echo "Vulnerable to CVE-2021-3560" | sed -${E} "s,.*,${SED_RED_YELLOW},"
echo ""
fi

View File

@@ -30,7 +30,7 @@
# Functions Used: echo_not_found, print_2title, print_list, warn_exec
# Global Variables:
# Initial Functions:
# Generated Global Variables: $ASLR, $hypervisorflag, $detectedvirt, $unpriv_userns_clone, $perf_event_paranoid, $mmap_min_addr, $ptrace_scope, $dmesg_restrict, $kptr_restrict, $unpriv_bpf_disabled
# Generated Global Variables: $ASLR, $hypervisorflag, $detectedvirt, $unpriv_userns_clone, $perf_event_paranoid, $mmap_min_addr, $ptrace_scope, $dmesg_restrict, $kptr_restrict, $unpriv_bpf_disabled, $protected_symlinks, $protected_hardlinks
# Fat linpeas: 0
# Small linpeas: 0

View File

@@ -6,7 +6,7 @@
# License: GNU GPL
# Version: 1.2
# Functions Used: echo_not_found, print_2title, print_info, print_3title
# Global Variables: $EXTRA_CHECKS, $SEARCH_IN_FOLDER, $IAMROOT, $WRITABLESYSTEMDPATH
# Global Variables: $EXTRA_CHECKS, $IAMROOT, $SEARCH_IN_FOLDER, $TIMEOUT, $WRITABLESYSTEMDPATH
# Initial Functions:
# Generated Global Variables: $service_unit, $service_path, $service_content, $finding, $findings, $service_file, $exec_path, $exec_paths, $service, $line, $target_file, $target_exec, $relpath1, $relpath2
# Fat linpeas: 0
@@ -178,7 +178,11 @@ if ! [ "$SEARCH_IN_FOLDER" ]; then
if [ "$EXTRA_CHECKS" ]; then
echo ""
print_3title "Service versions and status:"
(service --status-all || service -e || chkconfig --list || rc-status || launchctl list) 2>/dev/null || echo_not_found "service|chkconfig|rc-status|launchctl"
if [ "$TIMEOUT" ]; then
$TIMEOUT 30 sh -c "(service --status-all || service -e || chkconfig --list || rc-status || launchctl list) 2>/dev/null" || echo_not_found "service|chkconfig|rc-status|launchctl"
else
(service --status-all || service -e || chkconfig --list || rc-status || launchctl list) 2>/dev/null || echo_not_found "service|chkconfig|rc-status|launchctl"
fi
fi
# Check systemd path writability
@@ -190,4 +194,4 @@ if ! [ "$SEARCH_IN_FOLDER" ]; then
fi
echo ""
fi
fi

View File

@@ -6,7 +6,7 @@
# License: GNU GPL
# Version: 1.0
# Functions Used: print_2title
# Global Variables: $MACPEAS, $sh_usrs, $USER
# Global Variables: $MACPEAS, $sh_usrs, $TIMEOUT, $USER
# Initial Functions:
# Generated Global Variables: $ushell, $no_shells, $unexpected_shells
# Fat linpeas: 0
@@ -26,8 +26,16 @@ else
no_shells=$(grep -Ev "sh$" /etc/passwd 2>/dev/null | cut -d ':' -f 7 | sort | uniq)
unexpected_shells=""
printf "%s\n" "$no_shells" | while read f; do
if $f -c 'whoami' 2>/dev/null | grep -q "$USER"; then
unexpected_shells="$f\n$unexpected_shells"
if [ -x "$f" ]; then
if [ "$TIMEOUT" ]; then
if $TIMEOUT 1 "$f" -c 'whoami' 2>/dev/null | grep -q "$USER"; then
unexpected_shells="$f\n$unexpected_shells"
fi
else
if "$f" -c 'whoami' 2>/dev/null | grep -q "$USER"; then
unexpected_shells="$f\n$unexpected_shells"
fi
fi
fi
done
grep "sh$" /etc/passwd 2>/dev/null | sort | sed -${E} "s,$sh_usrs,${SED_LIGHT_CYAN}," | sed "s,$USER,${SED_LIGHT_MAGENTA}," | sed "s,root,${SED_RED},"
@@ -41,4 +49,4 @@ else
done
fi
fi
echo ""
echo ""

View File

@@ -8,7 +8,7 @@
# Functions Used: echo_not_found, print_2title, print_info
# Global Variables:$IAMROOT, $PASSWORD, $sudoB, $sudoG, $sudoVB1, $sudoVB2
# Initial Functions:
# Generated Global Variables:
# Generated Global Variables: $secure_path_line
# Fat linpeas: 0
# Small linpeas: 1

View File

@@ -1,5 +1,5 @@
# Title: Software Information - Browser Profiles
# ID: SW_Browser_Profiles
# ID: SW_Browser_profiles
# Author: Carlos Polop
# Last Update: 10-03-2025
# Description: List browser profiles that may store credentials/cookies

View File

@@ -405,7 +405,7 @@ class LinpeasBuilder:
name = entry["name"]
caseinsensitive = entry.get("caseinsensitive", False)
regex = entry["regex"]
regex = regex.replace('"', '\\"').strip()
regex = regex.replace("\\", "\\\\").replace('"', '\\"').strip()
falsePositives = entry.get("falsePositives", False)
if falsePositives:

View File

@@ -127,7 +127,9 @@ def parse_line(line: str):
elif is_section(line, INFO_PATTERN):
title = parse_title(line)
C_SECTION["infos"].append(title)
if C_SECTION == {}:
return
C_SECTION.setdefault("infos", []).append(title)
#If here, then it's text
else:

View File

@@ -71,7 +71,7 @@ CALL :T_Progress 2
:ListHotFixes
where wmic >nul 2>&1
if %errorlevel% equ 0 (
wmic qfe get Caption,Description,HotFixID,InstalledOn | more
wmic qfe get Caption,Description,HotFixID,InstalledOn
) else (
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)"
where wmic >nul 2>&1
if %errorlevel% equ 0 (
WMIC /Node:localhost /Namespace:\\root\SecurityCenter2 Path AntiVirusProduct Get displayName /Format:List | more
WMIC /Node:localhost /Namespace:\\root\SecurityCenter2 Path AntiVirusProduct Get displayName /Format:List
) else (
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
where wmic >nul 2>&1
if %errorlevel% equ 0 (
wmic logicaldisk get caption | more
wmic logicaldisk get caption
) else (
fsutil fsinfo drives
)
@@ -670,7 +670,7 @@ if "%long%" == "true" (
ECHO.
where wmic >nul 2>&1
if !errorlevel! equ 0 (
for /f %%x in ('wmic logicaldisk get name ^| more') do (
for /f %%x in ('wmic logicaldisk get name') do (
set tdrive=%%x
if "!tdrive:~1,2!" == ":" (
%%x

View File

@@ -0,0 +1,26 @@
cmake_minimum_required(VERSION 3.16)
project(winPEAS_dotnet NONE)
set(PROJECT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/winPEAS.csproj")
find_program(DOTNET_EXECUTABLE dotnet)
find_program(MSBUILD_EXECUTABLE msbuild)
find_program(XBUILD_EXECUTABLE xbuild)
if(DOTNET_EXECUTABLE)
set(BUILD_TOOL "${DOTNET_EXECUTABLE}")
set(BUILD_ARGS build "${PROJECT_FILE}" -c Release)
elseif(MSBUILD_EXECUTABLE)
set(BUILD_TOOL "${MSBUILD_EXECUTABLE}")
set(BUILD_ARGS "${PROJECT_FILE}" /p:Configuration=Release)
elseif(XBUILD_EXECUTABLE)
set(BUILD_TOOL "${XBUILD_EXECUTABLE}")
set(BUILD_ARGS "${PROJECT_FILE}" /p:Configuration=Release)
else()
message(FATAL_ERROR "dotnet, msbuild, or xbuild is required to build winPEAS")
endif()
add_custom_target(winpeas ALL
COMMAND ${BUILD_TOOL} ${BUILD_ARGS}
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
)

View File

@@ -88,6 +88,7 @@ namespace winPEAS.Checks
PrintLocalGroupPolicy,
PrintPotentialGPOAbuse,
AppLockerHelper.PrintAppLockerPolicy,
PrintPrintNightmarePointAndPrint,
PrintPrintersWMIInfo,
PrintNamedPipes,
PrintNamedPipeAbuseCandidates,
@@ -836,6 +837,39 @@ namespace winPEAS.Checks
}
}
private static void PrintPrintNightmarePointAndPrint()
{
Beaprint.MainPrint("PrintNightmare PointAndPrint Policies");
Beaprint.LinkPrint("https://itm4n.github.io/printnightmare-exploitation/", "Check PointAndPrint policy hardening");
try
{
string key = @"Software\\Policies\\Microsoft\\Windows NT\\Printers\\PointAndPrint";
var restrict = RegistryHelper.GetDwordValue("HKLM", key, "RestrictDriverInstallationToAdministrators");
var noWarn = RegistryHelper.GetDwordValue("HKLM", key, "NoWarningNoElevationOnInstall");
var updatePrompt = RegistryHelper.GetDwordValue("HKLM", key, "UpdatePromptSettings");
if (restrict == null && noWarn == null && updatePrompt == null)
{
Beaprint.NotFoundPrint();
return;
}
Beaprint.NoColorPrint($" RestrictDriverInstallationToAdministrators: {restrict}\n" +
$" NoWarningNoElevationOnInstall: {noWarn}\n" +
$" UpdatePromptSettings: {updatePrompt}");
if (restrict == 0 && noWarn == 1 && updatePrompt == 2)
{
Beaprint.BadPrint(" [!] Potentially vulnerable to PrintNightmare misconfiguration");
}
}
catch (Exception ex)
{
Beaprint.PrintException(ex.Message);
}
}
private static void PrintPrintersWMIInfo()
{
Beaprint.MainPrint("Enumerating Printers (WMI)");

View File

@@ -88,6 +88,10 @@ namespace winPEAS.KnownFileCreds
if (SID.StartsWith("S-1-5") && !SID.EndsWith("_Classes"))
{
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)
{
@@ -129,6 +133,10 @@ namespace winPEAS.KnownFileCreds
else
{
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
if (selfKey != null)
@@ -198,6 +206,10 @@ namespace winPEAS.KnownFileCreds
if (SID.StartsWith("S-1-5") && !SID.EndsWith("_Classes"))
{
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))
{
Dictionary<string, string> putty_ssh = new Dictionary<string, string>
@@ -216,6 +228,10 @@ namespace winPEAS.KnownFileCreds
else
{
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))
{
Dictionary<string, string> putty_ssh = new Dictionary<string, string>();

View File

@@ -821,6 +821,34 @@ $Hotfix = Get-HotFix | Sort-Object -Descending -Property InstalledOn -ErrorActio
$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
Write-Host ""
if ($TimeStamp) { TimeElapsed }