Compare commits

..

25 Commits

Author SHA1 Message Date
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
4e556fd594 Fix variable reference when parsing URLs 2025-06-06 00:01:17 +02:00
SirBroccoli
39066f6867 Fix leftover debug code and reset state in parser 2025-06-06 00:00:39 +02:00
SirBroccoli
c3a93a57fe
Merge pull request #473 from Signum21/master
Fix IdentityNotMappedException in Vulnerable Leaked Handlers
2025-05-31 22:36:49 +02:00
Signum21
f62d9fc550 Fix System.Security.Principal.IdentityNotMappedException in Vulnerable Leaked Handlers 2025-05-31 04:56:14 +02:00
SirBroccoli
11e9b8dde6
Merge pull request #472 from Jack-Vaughn/NoEnvVars-Update
Add 4 noisy environment variables to NoEnvVars.sh
2025-05-26 23:57:40 +02:00
Jack Vaughn
b9a9ad5ddf
Add 4 noisy and useless environment variables to NoEnvVars.sh
These variables (^PATH=|^INVOCATION_ID=|^WATCHDOG_PID=|^LISTEN_PID=) frequently appear across processes 
on busy systems (10+ each on tested system) and produce a large volume of irrelevant output
2025-05-25 21:32:51 -04:00
carlospolop
88f08a405e l 2025-05-26 02:55:07 +02:00
SirBroccoli
322792c4ec
Merge pull request #471 from Jack-Vaughn/environ-check
Add module to check for sensitive environment variables via /proc/*/environ
2025-05-26 02:33:43 +02:00
Jack
c150e63b52 This module scans /proc/*/environ for potentially sensitive environment variables on Linux systems.
It targets common keywords like token, password, secret, AWS, API, etc.

Uses 'tr' instead of 'strings' to improve compatibility in minimal environments like containers.

The check is skipped entirely on MacPEAS.
2025-05-25 12:55:34 -04:00
13 changed files with 163 additions and 33 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('--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('--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('--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() args = parser.parse_args()
all_modules = args.all all_modules = args.all

View File

@ -26,7 +26,7 @@
# License: GNU GPL # License: GNU GPL
# Version: 1.0 # Version: 1.0
# Functions Used: echo_not_found, print_2title, print_info # Functions Used: echo_not_found, print_2title, print_info
# Global Variables: # Global Variables: $NoEnvVars, $EnvVarsRed
# Initial Functions: # Initial Functions:
# Generated Global Variables: # Generated Global Variables:
# Fat linpeas: 0 # Fat linpeas: 0
@ -35,5 +35,5 @@
print_2title "Environment" print_2title "Environment"
print_info "Any private information inside environment variables?" print_info "Any private information inside environment variables?"
(env || printenv || set) 2>/dev/null | grep -v "RELEVANT*|FIND*|^VERSION=|dbuslistG|mygroups|ldsoconfdG|pwd_inside_history|kernelDCW_Ubuntu_Precise|kernelDCW_Ubuntu_Trusty|kernelDCW_Ubuntu_Xenial|kernelDCW_Rhel|^sudovB=|^rootcommon=|^mounted=|^mountG=|^notmounted=|^mountpermsB=|^mountpermsG=|^kernelB=|^C=|^RED=|^GREEN=|^Y=|^B=|^NC=|TIMEOUT=|groupsB=|groupsVB=|knw_grps=|sidG|sidB=|sidVB=|sidVB2=|sudoB=|sudoG=|sudoVB=|timersG=|capsB=|notExtensions=|Wfolders=|writeB=|writeVB=|_usrs=|compiler=|LS_COLORS=|pathshG=|notBackup=|processesDump|processesB|commonrootdirs|USEFUL_SOFTWARE|PSTORAGE_" | sed -${E} "s,[pP][aA][sS][sS][wW]|[aA][pP][iI][kK][eE][yY]|[aA][pP][iI][_][kK][eE][yY]|KRB5CCNAME,${SED_RED},g" || echo_not_found "env || set" (env || printenv || set) 2>/dev/null | grep -Eiv "$NoEnvVars" | sed -${E} "s,$EnvVarsRed,${SED_RED},g" || echo_not_found "env || set"
echo "" echo ""

View File

@ -8,7 +8,7 @@
# Functions Used: print_2title # Functions Used: print_2title
# Global Variables: $DEBUG, $knw_usrs, $nosh_usrs, $sh_usrs, $DEBUG, $USER, $STRINGS # Global Variables: $DEBUG, $knw_usrs, $nosh_usrs, $sh_usrs, $DEBUG, $USER, $STRINGS
# Initial Functions: # 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 # Fat linpeas: 0
# Small linpeas: 1 # Small linpeas: 1
@ -103,3 +103,41 @@ if [ "$(command -v mysql || echo -n '')" ] || [ "$(command -v mysqladmin || echo
fi fi
echo "" echo ""
fi 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

@ -0,0 +1,22 @@
# Title: Interesting Files - Interesting Environment Variables
# ID: IF_Interesting_environment_variables
# Author: Jack Vaughn
# Last Update: 25-05-2025
# Description: Searching possible sensitive environment variables inside of /proc/*/environ
# License: GNU GPL
# Version: 1.0
# Functions Used: print_2title
# Global Variables: $MACPEAS, $NoEnvVars, $EnvVarsRed
# Initial Functions:
# Generated Global Variables:
# Fat linpeas: 0
# Small linpeas: 1
if [ -z "$MACPEAS" ]; then
print_2title "Checking all env variables in /proc/*/environ removing duplicates and filtering out useless env vars"
cat /proc/[0-9]*/environ 2>/dev/null | \
tr '\0' '\n' | \
grep -Eiv "$NoEnvVars" | \
sort -u | \
sed -${E} "s,$EnvVarsRed,${SED_RED},g"
fi

View File

@ -0,0 +1,18 @@
# Title: Variables - EnvVarsRed
# ID: EnvVarsRed
# Author: Carlos Polop
# Last Update: 26-05-2025
# Description: Useless env vars
# License: GNU GPL
# Version: 1.0
# Functions Used:
# Global Variables:
# Initial Functions:
# Generated Global Variables: $EnvVarsRed
# Fat linpeas: 0
# Small linpeas: 1
EnvVarsRed="[pP][aA][sS][sS][wW]|[aA][pP][iI][kK][eE][yY]|[aA][pP][iI][_][kK][eE][yY]|KRB5CCNAME|[aA][pP][iI][_][kK][eE][yY]|[aA][wW][sS]|[aA][zZ][uU][rR][eE]|[gG][cC][pP]|[aA][pP][iI]|[sS][eE][cC][rR][eE][tT]|[sS][qQ][lL]|[dD][aA][tT][aA][bB][aA][sS][eE]|[tT][oO][kK][eE][nN]"

View File

@ -0,0 +1,16 @@
# Title: Variables - NoEnvVars
# ID: NoEnvVars
# Author: Carlos Polop
# Last Update: 26-05-2025
# Description: Useless env vars
# License: GNU GPL
# Version: 1.0
# Functions Used:
# Global Variables:
# Initial Functions:
# Generated Global Variables: $NoEnvVars
# Fat linpeas: 0
# Small linpeas: 1
NoEnvVars="LESS_TERMCAP|JOURNAL_STREAM|XDG_SESSION|DBUS_SESSION|systemd\/sessions|systemd_exec|MEMORY_PRESSURE_WATCH|RELEVANT*|FIND*|^VERSION=|dbuslistG|mygroups|ldsoconfdG|pwd_inside_history|kernelDCW_Ubuntu_Precise|kernelDCW_Ubuntu_Trusty|kernelDCW_Ubuntu_Xenial|kernelDCW_Rhel|^sudovB=|^rootcommon=|^mounted=|^mountG=|^notmounted=|^mountpermsB=|^mountpermsG=|^kernelB=|^C=|^RED=|^GREEN=|^Y=|^B=|^NC=|TIMEOUT=|groupsB=|groupsVB=|knw_grps=|sidG|sidB=|sidVB=|sidVB2=|sudoB=|sudoG=|sudoVB=|timersG=|capsB=|notExtensions=|Wfolders=|writeB=|writeVB=|_usrs=|compiler=|LS_COLORS=|pathshG=|notBackup=|processesDump|processesB|commonrootdirs|USEFUL_SOFTWARE|PSTORAGE_|^PATH=|^INVOCATION_ID=|^WATCHDOG_PID=|^LISTEN_PID="

View File

@ -292,9 +292,12 @@ class LinpeasBaseBuilder:
all_module_paths += self.enumerate_directory(LINPEAS_PARTS["variables"]) all_module_paths += self.enumerate_directory(LINPEAS_PARTS["variables"])
for module in LINPEAS_PARTS["modules"]: for module in LINPEAS_PARTS["modules"]:
exclude = False
for ex_module in exclude_modules: for ex_module in exclude_modules:
if ex_module in module["folder_path"] or ex_module in [module["name"], module["name_check"]]: 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"]) all_module_paths += self.enumerate_directory(module["folder_path"])
for module in all_module_paths: for module in all_module_paths:

View File

@ -97,7 +97,7 @@ class LinpeasBuilder:
for orig_url in urls: for orig_url in urls:
tar_gz_bin_name = "" tar_gz_bin_name = ""
if ",,," in orig_url: if ",,," in orig_url:
tar_gz_bin_name = url.split(",,,")[1] tar_gz_bin_name = orig_url.split(",,,")[1]
url = orig_url.split(",,,")[0] url = orig_url.split(",,,")[0]
else: else:
url = orig_url url = orig_url
@ -402,9 +402,9 @@ class LinpeasBuilder:
def __replace_mark(self, mark: str, find_calls: list, join_char: str): def __replace_mark(self, mark: str, find_calls: list, join_char: str):
"""Substitude the markup with the actual code""" """Substitute 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 self.linpeas_sh = self.linpeas_sh.replace(mark, join_char.join(find_calls)) #New line char isn't needed
def write_linpeas(self, path): def write_linpeas(self, path):
"""Write on disk the final linpeas""" """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 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): if is_section(line, TITLE1_PATTERN):
title = parse_title(line) title = parse_title(line)
@ -145,14 +143,23 @@ def parse_line(line: str):
def parse_peass(outputpath: str, jsonpath: 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 OUTPUT_PATH = outputpath
JSON_PATH = jsonpath JSON_PATH = jsonpath
for line in open(OUTPUT_PATH, 'r', encoding="utf8").readlines(): # 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
with open(OUTPUT_PATH, 'r', encoding="utf8") as f:
for line in f.readlines():
line = line.strip() line = line.strip()
if not line or not clean_colors(line): #Remove empty lines or lines just with colors hex # Remove empty lines or lines containing only color codes
if not line or not clean_colors(line):
continue continue
parse_line(line) parse_line(line)

View File

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

View File

@ -31,7 +31,7 @@ namespace winPEAS.Helpers
public static string ansi_current_user = MAGENTA; public static string ansi_current_user = MAGENTA;
private static string Advisory = 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. " + "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."; "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; private const int CNST_SYSTEM_EXTENDED_HANDLE_INFORMATION = 64;
public const uint STATUS_INFO_LENGTH_MISMATCH = 0xC0000004; public const uint STATUS_INFO_LENGTH_MISMATCH = 0xC0000004;
public const int DUPLICATE_SAME_ACCESS = 0x2; public const int DUPLICATE_SAME_ACCESS = 0x2;
public const string elevatedProcess = "Access denied, process is probably elevated";
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct FILE_NAME_INFO 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 // 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 //PROCESS_ALL_ACCESS
if ((h.GrantedAccess & 0x001F0FFF) == h.GrantedAccess) if ((h.GrantedAccess & 0x001F0FFF) == h.GrantedAccess || (h.GrantedAccess & 0x1FFFFF) == h.GrantedAccess)
{ {
vulnHandler.isVuln = true; vulnHandler.isVuln = true;
vulnHandler.reason = "PROCESS_ALL_ACCESS"; vulnHandler.reason = "PROCESS_ALL_ACCESS";
@ -454,6 +455,8 @@ namespace winPEAS.Helpers
} }
catch catch
{ {
data["name"] = elevatedProcess;
data["sid"] = elevatedProcess;
return data; return data;
} }
finally finally
@ -469,12 +472,32 @@ namespace winPEAS.Helpers
public static PT_RELEVANT_INFO getProcInfoById(int pid) public static PT_RELEVANT_INFO getProcInfoById(int pid)
{ {
PT_RELEVANT_INFO pri = new PT_RELEVANT_INFO(); 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); Dictionary<string, string> user = GetProcU(proc);
StringBuilder fileName = new StringBuilder(2000); StringBuilder fileName = new StringBuilder(2000);
try
{
Native.Psapi.GetProcessImageFileName(proc.Handle, fileName, 2000); Native.Psapi.GetProcessImageFileName(proc.Handle, fileName, 2000);
}
catch
{
fileName = new StringBuilder(elevatedProcess);
}
pri.pid = pid; pri.pid = pid;
pri.name = proc.ProcessName; pri.name = proc.ProcessName;

View File

@ -195,11 +195,11 @@ namespace winPEAS.Info.ProcessInfo
continue; continue;
List<string> permsFile = PermissionsHelper.GetPermissionsFile(sFilePath, Checks.Checks.CurrentUserSiDs, PermissionType.WRITEABLE_OR_EQUIVALENT); List<string> permsFile = PermissionsHelper.GetPermissionsFile(sFilePath, Checks.Checks.CurrentUserSiDs, PermissionType.WRITEABLE_OR_EQUIVALENT);
IdentityReference sid = null;
try try
{ {
System.Security.AccessControl.FileSecurity fs = System.IO.File.GetAccessControl(sFilePath); System.Security.AccessControl.FileSecurity fs = System.IO.File.GetAccessControl(sFilePath);
IdentityReference sid = fs.GetOwner(typeof(SecurityIdentifier)); sid = fs.GetOwner(typeof(SecurityIdentifier));
string ownerName = sid.Translate(typeof(NTAccount)).ToString();
// If current user already have permissions over that file or the proc belongs to the owner of the file, // If current user already have permissions over that file or the proc belongs to the owner of the file,
// handler not interesting to elevate privs // handler not interesting to elevate privs
@ -207,6 +207,8 @@ namespace winPEAS.Info.ProcessInfo
continue; continue;
to_add["File Path"] = sFilePath; to_add["File Path"] = sFilePath;
string ownerName = sid.Translate(typeof(NTAccount)).ToString();
to_add["File Owner"] = ownerName; to_add["File Owner"] = ownerName;
} }
catch (System.IO.FileNotFoundException) catch (System.IO.FileNotFoundException)
@ -218,7 +220,10 @@ namespace winPEAS.Info.ProcessInfo
{ {
continue; continue;
} }
catch (System.Security.Principal.IdentityNotMappedException)
{
to_add["File Owner"] = sid.ToString();
}
} }
else if (typeName == "key") else if (typeName == "key")