Compare commits

..

18 Commits

Author SHA1 Message Date
HackTricks News Bot
569b573f22 Add winpeas privilege escalation checks from: HTB: Rainbow — crashing a custom Windows web server to RCE, then UAC bypass to f 2025-08-25 11:08:42 +02:00
SirBroccoli
41128808a6 Merge pull request #483 from securitytime/patch-1
Update Beaprint.cs
2025-07-01 16:23:13 +02:00
carlospolop
6fd96f4bdb f 2025-07-01 12:12:01 +02:00
carlospolop
a745f00dd7 fix 2025-07-01 11:10:21 +02:00
securitytime
933e12d7f1 Update Beaprint.cs
A space character is missing here:
"... educational purposes only.Any misuse of this software  ..."
2025-06-28 09:12:40 +02:00
SirBroccoli
4061cef7e8 Merge pull request #476 from peass-ng/codex/fix-url-reference-in-linpeasbuilder.py
Fix url variable reference in linpeasBuilder
2025-06-25 01:59:43 +02:00
SirBroccoli
b66ced3c63 Merge pull request #475 from peass-ng/codex/find-and-fix-a-bug
Fix parser global state reuse
2025-06-25 01:59:03 +02:00
SirBroccoli
cde725dacc Merge pull request #477 from peass-ng/codex/update-docstring-and-fix-typo
Fix docstring and comment in linpeasBuilder
2025-06-25 01:57:58 +02:00
SirBroccoli
f0f829890c Merge pull request #479 from peass-ng/codex/replace--parth--with--path--in-argparse
Fix typo in linpeas builder arg help
2025-06-25 01:57:11 +02:00
SirBroccoli
99c36b8562 Merge pull request #480 from Signum21/master
Fixed multiple bugs in Vulnerable Leaked Handlers
2025-06-25 01:56:58 +02:00
SirBroccoli
a74c6c820f Merge pull request #482 from Aarav-Juneja/builder-exclude-fix
Fix exclude modules on linPEASS
2025-06-25 01:55:48 +02:00
SirBroccoli
53fd4d8dc8 Merge pull request #481 from ertaku12/master
Added a privilege escalation vulnerability for MySQL 4.x/5.x versions.
2025-06-25 01:55:25 +02:00
Aarav Juneja
9b37fd4ef4 Fix exclude modules on linPEASS 2025-06-24 13:05:10 -07:00
John Doe
f27b1d4816 Added a privilege escalation vulnerability for MySQL 4.x/5.x versions. 2025-06-23 22:37:44 +03:00
Signum21
d335b9254f Fixed multiple bugs in Vulnerable Leaked Handlers 2025-06-15 20:59:20 +02:00
SirBroccoli
d5e3c2a885 Fix typo in linpeas builder output argument 2025-06-06 00:38:05 +02:00
SirBroccoli
4af321d138 Fix docstring and comment typo 2025-06-06 00:01:29 +02:00
SirBroccoli
39066f6867 Fix leftover debug code and reset state in parser 2025-06-06 00:00:39 +02:00
10 changed files with 173 additions and 28 deletions

View File

@@ -33,7 +33,7 @@ if __name__ == "__main__":
parser.add_argument('--small', action='store_true', help='Build small version of linpeas.')
parser.add_argument('--include', type=str, help='Build linpeas only with the modules indicated you can indicate section names or module IDs).')
parser.add_argument('--exclude', type=str, help='Exclude the given modules (you can indicate section names or module IDs).')
parser.add_argument('--output', required=True, type=str, help='Parth to write the final linpeas file to.')
parser.add_argument('--output', required=True, type=str, help='Path to write the final linpeas file to.')
args = parser.parse_args()
all_modules = args.all

View File

@@ -8,7 +8,7 @@
# Functions Used: print_2title
# Global Variables: $DEBUG, $knw_usrs, $nosh_usrs, $sh_usrs, $DEBUG, $USER, $STRINGS
# Initial Functions:
# Generated Global Variables: $mysqluser, $mysqlexec, $mysqlconnect, $mysqlconnectnopass
# Generated Global Variables: $mysqluser, $mysqlexec, $mysqlconnect, $mysqlconnectnopass, $mysqluser, $version_output, $major_version, $version, $process_info
# Fat linpeas: 0
# Small linpeas: 1
@@ -102,4 +102,42 @@ if [ "$(command -v mysql || echo -n '')" ] || [ "$(command -v mysqladmin || echo
else echo_no
fi
echo ""
fi
### This section checks if MySQL (mysqld) is running as root and if its version is 4.x or 5.x to refer a known local privilege escalation exploit! ###
# Find the mysqld process
process_info=$(ps aux | grep '[m]ysqld' | head -n1)
if [ -z "$process_info" ]; then
echo "MySQL process not found." | sed -${E} "s,.*,${SED_GREEN},"
else
# Extract the process user
mysqluser=$(echo "$process_info" | awk '{print $1}')
# Get the MySQL version string
version_output=$(mysqld --version 2>&1)
# Extract the version number (expects format like X.Y.Z)
version=$(echo "$version_output" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1)
if [ -z "$version" ]; then
echo "Unable to determine MySQL version." | sed -${E} "s,.*,${SED_GREEN},"
else
# Extract the major version number (X from X.Y.Z)
major_version=$(echo "$version" | cut -d. -f1)
# Check if MySQL is running as root and if the version is either 4.x or 5.x
if [ "$mysqluser" = "root" ] && { [ "$major_version" -eq 4 ] || [ "$major_version" -eq 5 ]; }; then
echo "MySQL is running as root with version $version. This is a potential local privilege escalation vulnerability!" | sed -${E} "s,.*,${SED_RED},"
echo "\tRefer to: https://www.exploit-db.com/exploits/1518" | sed -${E} "s,.*,${SED_YELLOW},"
echo "\tRefer to: https://medium.com/r3d-buck3t/privilege-escalation-with-mysql-user-defined-functions-996ef7d5ceaf" | sed -${E} "s,.*,${SED_YELLOW},"
else
echo "MySQL is running as user '$mysqluser' with version $version." | sed -${E} "s,.*,${SED_GREEN},"
fi
### ------------------------------------------------------------------------------------------------------------------------------------------------ ###
fi
fi

View File

@@ -292,9 +292,12 @@ class LinpeasBaseBuilder:
all_module_paths += self.enumerate_directory(LINPEAS_PARTS["variables"])
for module in LINPEAS_PARTS["modules"]:
exclude = False
for ex_module in exclude_modules:
if ex_module in module["folder_path"] or ex_module in [module["name"], module["name_check"]]:
continue
exclude = True
break
if exclude: continue
all_module_paths += self.enumerate_directory(module["folder_path"])
for module in all_module_paths:

View File

@@ -402,9 +402,9 @@ class LinpeasBuilder:
def __replace_mark(self, mark: str, find_calls: list, join_char: str):
"""Substitude the markup with the actual code"""
self.linpeas_sh = self.linpeas_sh.replace(mark, join_char.join(find_calls)) #New line char is't needed
"""Substitute the markup with the actual code"""
self.linpeas_sh = self.linpeas_sh.replace(mark, join_char.join(find_calls)) #New line char isn't needed
def write_linpeas(self, path):
"""Write on disk the final linpeas"""

View File

@@ -106,8 +106,6 @@ def parse_line(line: str):
global FINAL_JSON, C_SECTION, C_MAIN_SECTION, C_2_SECTION, C_3_SECTION
if "Cron jobs" in line:
a=1
if is_section(line, TITLE1_PATTERN):
title = parse_title(line)
@@ -145,17 +143,26 @@ def parse_line(line: str):
def parse_peass(outputpath: str, jsonpath: str = ""):
global OUTPUT_PATH, JSON_PATH
global OUTPUT_PATH, JSON_PATH, FINAL_JSON, C_SECTION, C_MAIN_SECTION, C_2_SECTION, C_3_SECTION
OUTPUT_PATH = outputpath
JSON_PATH = jsonpath
for line in open(OUTPUT_PATH, 'r', encoding="utf8").readlines():
line = line.strip()
if not line or not clean_colors(line): #Remove empty lines or lines just with colors hex
continue
# Reset globals to avoid data leaking between executions
FINAL_JSON = {}
C_SECTION = FINAL_JSON
C_MAIN_SECTION = FINAL_JSON
C_2_SECTION = FINAL_JSON
C_3_SECTION = FINAL_JSON
parse_line(line)
with open(OUTPUT_PATH, 'r', encoding="utf8") as f:
for line in f.readlines():
line = line.strip()
# Remove empty lines or lines containing only color codes
if not line or not clean_colors(line):
continue
parse_line(line)
if JSON_PATH:
with open(JSON_PATH, "w") as f:

View File

@@ -134,7 +134,7 @@ Once you have installed and activated it you need to:
- [x] Current drives information
- [x] AV
- [x] Windows Defender
- [x] UAC configuration
- [x] UAC configuration and fodhelper (ms-settings) hijack detection
- [x] NTLM Settings
- [x] Local Group Policy
- [x] Applocker Configuration & bypass suggestions

View File

@@ -102,17 +102,15 @@ namespace winPEAS.Checks
{
vulnHandlers = ProcessesInfo.GetVulnHandlers(progress);
}
Dictionary<string, string> colors = new Dictionary<string, string>();
colors[Checks.CurrentUserName] = Beaprint.ansi_color_bad;
colors[HandlesHelper.elevatedProcess] = Beaprint.ansi_color_bad;
foreach (Dictionary<string, string> handler in vulnHandlers)
{
Dictionary<string, string> colors = new Dictionary<string, string>()
{
{ Checks.CurrentUserName, Beaprint.ansi_color_bad },
{ handler["Reason"], Beaprint.ansi_color_bad },
};
Beaprint.DictPrint(vulnHandlers, colors, true);
colors[handler["Reason"]] = Beaprint.ansi_color_bad;
}
Beaprint.DictPrint(vulnHandlers, colors, true);
}
catch (Exception ex)
{

View File

@@ -20,6 +20,7 @@ using winPEAS.Info.SystemInfo.Printers;
using winPEAS.Info.SystemInfo.SysMon;
using winPEAS.Info.SystemInfo.WindowsDefender;
using winPEAS.Native.Enums;
using Alphaleonis.Win32.Security;
namespace winPEAS.Checks
{
@@ -72,7 +73,9 @@ namespace winPEAS.Checks
PrintAVInfo,
PrintWindowsDefenderInfo,
PrintUACInfo,
PrintPSInfo,
PrintUACFodhelperCheck,
PrintPSInfo,
PrintPowerShellSessionSettings,
PrintTranscriptPS,
PrintInetInfo,
@@ -1201,5 +1204,78 @@ namespace winPEAS.Checks
{
}
}
// --- Begin: UAC fodhelper check ---
// Detect and summarize the classic UAC bypass via fodhelper.exe (HKCU\Software\Classes\ms-settings hijack)
static void PrintUACFodhelperCheck()
{
try
{
Beaprint.MainPrint("UAC Bypass Candidates (fodhelper.exe)");
Beaprint.LinkPrint("https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#from-administrator-medium-to-high-integrity-level--uac-bypasss", "Detection of the HKCU ms-settings COM hijack used by fodhelper.exe");
// Preconditions for this bypass to be useful
bool isUacEnabled = ProcessContext.IsUacEnabled;
bool isAdminContext = Helpers.MyUtils.IsHighIntegrity(); // actually checks Administrators group membership
bool isElevated = ProcessContext.IsElevatedProcess;
var uacPol = Info.SystemInfo.SystemInfo.GetUACSystemPolicies();
string consentPromptRaw = (uacPol != null && uacPol.ContainsKey("ConsentPromptBehaviorAdmin")) ? uacPol["ConsentPromptBehaviorAdmin"] : "";
string consentPromptValue = winPEAS.Helpers.Registry.RegistryHelper.GetRegValue("HKLM", "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System", "ConsentPromptBehaviorAdmin");
// fodhelper binary
string fodhelperPath = System.IO.Path.Combine(Environment.SystemDirectory, "fodhelper.exe");
bool fodhelperExists = File.Exists(fodhelperPath);
// Hijack key state
string msSettingsKey = "Software\\Classes\\ms-settings\\Shell\\Open\\command";
var currentDelegate = winPEAS.Helpers.Registry.RegistryHelper.GetRegValue("HKCU", msSettingsKey, "DelegateExecute");
var currentDefault = winPEAS.Helpers.Registry.RegistryHelper.GetRegValue("HKCU", msSettingsKey, ""); // (Default)
// Print a brief context line
Beaprint.InfoPrint($"Context -> Admin group: {isAdminContext}, Elevated: {isElevated}, UAC enabled: {isUacEnabled}, CPBA: {consentPromptRaw}");
Beaprint.InfoPrint($"Binary -> {fodhelperPath} present: {fodhelperExists}");
// Report registry state (if key exists)
if (!string.IsNullOrEmpty(currentDelegate) || !string.IsNullOrEmpty(currentDefault))
{
Beaprint.BadPrint("Suspicious ms-settings hijack values found under HKCU:");
Beaprint.BadPrint($" HKCU\\{msSettingsKey}\\(Default): '{currentDefault}'");
Beaprint.BadPrint($" HKCU\\{msSettingsKey}\\DelegateExecute: '{currentDelegate}'");
Beaprint.InfoPrint("This pattern is commonly used to auto-elevate fodhelper.exe without a prompt.");
}
else
{
Beaprint.NotFoundPrint();
}
// Heuristic recommendation on likelihood
if (isAdminContext && !isElevated && isUacEnabled && fodhelperExists)
{
// CPBA guidance
if (consentPromptValue == "2")
{
Beaprint.GoodPrint("CPBA is 'Always Notify' (2). Fodhelper-style auto-elevation is typically blocked by this setting.");
}
else if (consentPromptValue == "0")
{
Beaprint.GoodPrint("UAC prompts are disabled for administrators (0). New admin processes elevate automatically; a bypass is unnecessary.");
}
else
{
Beaprint.BadPrint("Potential UAC bypass via fodhelper.exe is LIKELY. You're an Administrator running at medium integrity with UAC enabled.");
Beaprint.InfoPrint("Create HKCU\\Software\\Classes\\ms-settings\\Shell\\Open\\command with an empty 'DelegateExecute' and set (Default) to your command, then start fodhelper.exe.");
}
}
else
{
Beaprint.GoodPrint("Conditions for fodhelper.exe UAC bypass not met (not in Admin group, already elevated, UAC disabled, or binary missing).");
}
}
catch (Exception ex)
{
Beaprint.PrintException(ex.Message);
}
}
// --- End: UAC fodhelper check ---
}
}

View File

@@ -31,7 +31,7 @@ namespace winPEAS.Helpers
public static string ansi_current_user = MAGENTA;
private static string Advisory =
"winpeas should be used for authorized penetration testing and/or educational purposes only." +
"winpeas should be used for authorized penetration testing and/or educational purposes only. " +
"Any misuse of this software will not be the responsibility of the author or of any other collaborator. " +
"Use it at your own devices and/or with the device owner's permission.";

View File

@@ -12,6 +12,7 @@ namespace winPEAS.Helpers
private const int CNST_SYSTEM_EXTENDED_HANDLE_INFORMATION = 64;
public const uint STATUS_INFO_LENGTH_MISMATCH = 0xC0000004;
public const int DUPLICATE_SAME_ACCESS = 0x2;
public const string elevatedProcess = "Access denied, process is probably elevated";
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct FILE_NAME_INFO
@@ -171,7 +172,7 @@ namespace winPEAS.Helpers
// Hex perms from https://docs.microsoft.com/en-us/windows/win32/procthread/process-security-and-access-rights and https://github.com/buffer/maltracer/blob/master/defines.py
//PROCESS_ALL_ACCESS
if ((h.GrantedAccess & 0x001F0FFF) == h.GrantedAccess)
if ((h.GrantedAccess & 0x001F0FFF) == h.GrantedAccess || (h.GrantedAccess & 0x1FFFFF) == h.GrantedAccess)
{
vulnHandler.isVuln = true;
vulnHandler.reason = "PROCESS_ALL_ACCESS";
@@ -454,6 +455,8 @@ namespace winPEAS.Helpers
}
catch
{
data["name"] = elevatedProcess;
data["sid"] = elevatedProcess;
return data;
}
finally
@@ -469,12 +472,32 @@ namespace winPEAS.Helpers
public static PT_RELEVANT_INFO getProcInfoById(int pid)
{
PT_RELEVANT_INFO pri = new PT_RELEVANT_INFO();
Process proc;
Process proc = Process.GetProcessById(pid);
try
{
proc = Process.GetProcessById(pid);
}
catch
{
pri.pid = pid;
pri.name = "Error, process may not exist";
pri.userName = "Error, process may not exist";
pri.userSid = "Error, process may not exist";
pri.imagePath = "Error, process may not exist";
return pri;
}
Dictionary<string, string> user = GetProcU(proc);
StringBuilder fileName = new StringBuilder(2000);
Native.Psapi.GetProcessImageFileName(proc.Handle, fileName, 2000);
try
{
Native.Psapi.GetProcessImageFileName(proc.Handle, fileName, 2000);
}
catch
{
fileName = new StringBuilder(elevatedProcess);
}
pri.pid = pid;
pri.name = proc.ProcessName;