DEV Community

tktkkame
tktkkame

Posted on Originally published at zenn.dev

SSH that skipped the bastion was lateral movement confessing

The scenario is fictional (RFC 5737 and 10.0.0.0/8 addresses).

After the first server falls, attackers move sideways. Lateral movement detection sounds hard. But one rule makes it a confession:

Internal servers accept SSH only from the bastion.

What you'll learn

  • Why defining "impossible" traffic simplifies detection
  • A one-liner for auth.log, plus network-side evidence
  • How auth method hints at the root cause
  • Handling false positives

The story at a glance

Bastion 10.0.0.9, compromised web03 (10.0.0.50), database db01 (10.0.0.60, bastion-only SSH).

Time What happened
02:31 10.0.0.50 -> 10.0.0.60:22 traffic
02:35 SSH success on db01, not via the bastion
02:41 Logs and history wiped on web03

Detector

awk '/Accepted/{for(i=1;i<=NF;i++)if($i=="from")ip=$(i+1); if(ip!="10.0.0.9")print $1,$2,$3,$9,$11}' /var/log/auth.log
Enter fullscreen mode Exit fullscreen mode

Tested on a synthetic log: it outputs only the two non-bastion successes (admin from 10.0.0.50, www-data from 203.0.113.77), ignores bastion logins and failures.

Network-side evidence (book examples, untested here)

Zeek conn.log: id.orig_h=10.0.0.50 id.resp_h=10.0.0.60 id.resp_p=22. Servers can erase their own logs; the network can't be erased by the host.

Auth method clues

Accepted password for www-data from 203.0.113.77 is itself abnormal: a service account with interactive password SSH from outside.

False positives

Ansible, backup, monitoring: allow-list sources, accounts and times. Be able to say why each entry is there.

Best defense

Firewall: SSH to internal servers only from the bastion. Use ssh -J [email protected] [email protected]. Detection is the safety net.

Next: the cleanup, and how deleted logs make noise.


Adapted from chapters 9, 18 and 27 of my Japanese book on server defense.

Top comments (0)