GCP VM 접속후 신기한 데몬을 발견했다.
root@instance-1:~# pstree
systemd─┬─accounts-daemon───2*[{accounts-daemon}]
...
├─sshguard-journa─┬─journalctl
│ └─sshguard─┬─sshg-fw
│ └─{sshguard}
sshguard? 원래 있었는지 잘모르겠다.
GCP 기본이라고 한다.
예전에 쓰던 fail2ban 과 같은 형태의 ssh 방어 데몬인 것 같아서, 어떻게 작동되는지 궁금했다.
for 문 테스트
Client
alinos@DESKTOP-A52MBHK:~/work$ for i in `seq 0 200`; do ssh -l root -i test1.pem 8.8.8.8; ssh -l ubuntu -i test2.pem 8.8.8.8; ssh -l centos -i test1.pem 8.8.8.8; done
root@8.8.8.8: Permission denied (publickey).
ubuntu@8.8.8.8: Permission denied (publickey).
Connection closed by 8.8.8.8 port 22
root@8.8.8.8: Permission denied (publickey).
ubuntu@8.8.8.8: Permission denied (publickey).
Connection closed by 8.8.8.8 port 22
...
Server
Jun 13 10:23:53 instance-1 sshd[6190]: Connection closed by authenticating user root 8.8.4.4 port 4860 [preauth]
Jun 13 10:23:55 instance-1 sshd[6195]: Connection closed by authenticating user ubuntu 8.8.4.4 port 4861 [preauth]
Jun 13 10:23:57 instance-1 sshd[6199]: Invalid user centos from 8.8.4.4 port 4862
...
안막힌다.. 그렇다고 윈도우에서 ssh bruteforce 도구를 받아서 하는건 너무 귀찮았기 때문에, 마침 검색 후 텔넷으로 막힌다는 꿀 정보를 확인했다.
텔넷 테스트
Client
alinos@DESKTOP-A52MBHK:~/work$ telnet 8.8.8.8
Trying 8.8.8.8...
Connected to 8.8.8.8.
Escape character is '^]'.
SSH-2.0-OpenSSH_7.6p1 Ubuntu-4ubuntu0.3
Protocol mismatch.
Connection closed by foreign host.
alinos@DESKTOP-A52MBHK:~/work$ ^C
alinos@DESKTOP-A52MBHK:~/work$ telnet 8.8.8.8 22
Trying 8.8.8.8...
Connected to 8.8.8.8.
Escape character is '^]'.
SSH-2.0-OpenSSH_7.6p1 Ubuntu-4ubuntu0.3
hi?
Protocol mismatch.
Connection closed by foreign host.
alinos@DESKTOP-A52MBHK:~/work$ telnet 8.8.8.8 22
Trying 8.8.8.8...
telnet: Unable to connect to remote host: Resource temporarily unavailable
Server
root@instance-1:~# tail -f /var/log/auth.log
Jun 13 10:25:13 instance-1 sshd[6385]: Connection closed by authenticating user root 8.8.4.4 port 13520 [preauth]
Jun 13 10:25:14 instance-1 sshd[6389]: Connection closed by 8.8.4.4 port 13521 [preauth]
Jun 13 10:25:42 instance-1 sshd[6411]: Bad protocol version identification '' from 8.8.4.4 port 12961
Jun 13 10:25:49 instance-1 sshd[6412]: Bad protocol version identification 'hi?' from 8.8.4.4 port 12962
Jun 13 10:25:50 instance-1 sshguard[1152]: Blocking 8.8.4.4 for 840 secs (4 attacks in 530 secs, after 1 abuses over 530 secs)
Connection reset by 8.8.4.4 port 22
root@instance-1:~# iptables -L sshguard -n
Chain sshguard (1 references)
target prot opt source destination
...
DROP all -- 8.8.4.4 0.0.0.0/0
막힌다? 흠 그냥 암호나 키대입만 잘못한 정도는 brute force 공격으로는 안보는 것 같다.
NMAP ssh bruteforce 테스트
Client
root@instance-1:/tmp# nmap -p 22 --script ssh-brute --script-args userdb=user.list,passdb=pass.list --script-args ssh-brute.timeout=4s 127.0.0.1
Starting Nmap 7.60 ( https://nmap.org ) at 2021-06-13 12:47 UTC
Nmap scan report for localhost (127.0.0.1)
Host is up (0.000044s latency).
PORT STATE SERVICE
22/tcp open ssh
|_ssh-brute: Password authenication not allowed
Nmap done: 1 IP address (1 host up) scanned in 0.47 seconds
root@instance-1:/tmp# vi /etc/ssh/sshd_config
...
PasswordAuthentication yes
...
root@instance-1:/tmp# nmap -p 22 --script ssh-brute --script-args userdb=user.list,passdb=pass.list --script-args ssh-brute.timeout=4s 127.0.0.1
Starting Nmap 7.60 ( https://nmap.org ) at 2021-06-13 12:50 UTC
NSE: [ssh-brute] Trying username/password pair: root:root
NSE: [ssh-brute] Trying username/password pair: admin:admin
NSE: [ssh-brute] Trying username/password pair: administrator:administrator
NSE: [ssh-brute] Trying username/password pair: webadmin:webadmin
NSE: [ssh-brute] Trying username/password pair: sysadmin:sysadmin
NSE: [ssh-brute] Trying username/password pair: netadmin:netadmin
NSE: [ssh-brute] Trying username/password pair: guest:guest
NSE: [ssh-brute] Trying username/password pair: user:user
NSE: [ssh-brute] Trying username/password pair: web:web
NSE: [ssh-brute] Trying username/password pair: test:test
root@instance-1:/tmp# nmap -v -A localhost
Starting Nmap 7.60 ( https://nmap.org ) at 2021-06-13 13:00 UTC
...
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 3e:cd:e9:3e:ff:c6:80:e4:57:9f:6e:a4:30:e7:2f:31 (RSA)
| 256 c2:a3:26:71:1c:4d:c4:33:ee:7f:cd:89:d6:89:a3:7f (ECDSA)
|_ 256 da:50:3d:bc:97:69:e4:4f:eb:73:27:a4:55:64:ed:dc (EdDSA)
root@instance-1:/tmp# systemctl status sshguard
...
Jun 13 12:56:55 instance-1 sshguard[12077]: 127.0.0.1: not blocking (on whitelist)
Jun 13 13:00:47 instance-1 sshguard[12077]: 127.0.0.1: not blocking (on whitelist)
...
키 인증로는 테스트가 안되서, sshd 에서 암호 인증을 풀고 진행해봤다.
nmap도 뚫리는 암호를 받으려는 동작 덕분에 바로 Blocking 하는 동작을 하는 것 같다.
SSB(Secure Shell Bruteforcer) 테스트
Client
PS C:\temp\ssb_0.1.1_windows_amd64> .\ssb.exe -w .\pass.txt -c 1000 root@8.8.8.8
_
v0.1.0 | |
___ ___| |__
/ __/ __| '_ \
\__ \__ \ |_) |
|___/___/_.__/
Secure Shell Bruteforcer
infosec@kitabisa.com
________________________
:: Username: root
:: Hostname: 8.8.8.8
:: Port : 22
:: Wordlist: .\pass.txt
:: Threads : 1000
:: Timeout : 30s
________________________
[INF] Done!
Server
root@instance-1:~# /bin/journalctl -afb -p info -n1 -o cat SYSLOG_FACILITY=4 SYSLOG_FACILITY=10
Connection closed by authenticating user root 8.8.4.4 port 4922 [preauth]
Connection closed by authenticating user root 8.8.4.4 port 5072 [preauth]
Connection closed by authenticating user root 8.8.4.4 port 4971 [preauth]
Connection closed by authenticating user root 8.8.4.4 port 4987 [preauth]
Connection closed by authenticating user root 8.8.4.4 port 4982 [preauth]
Connection closed by authenticating user root 8.8.4.4 port 4945 [preauth]
Connection closed by authenticating user root 8.8.4.4 port 5032 [preauth]
Connection closed by authenticating user root 8.8.4.4 port 4935 [preauth]
...
흠 그냥 넘어가기엔 성이 차지 않아 ssh bruteforce 툴을 받아서 시도해 보았다. 잘 안막힌다..
음 옵션을 다시 보니 valid password 를 알아내는 옵션이 별도로 있었다. 🤨
다시 한다.
Client
PS C:\temp\ssb_0.1.1_windows_amd64> .\ssb.exe -w .\pass.txt -c 10 root@8.8.8.8 -o tset
_
v0.1.0 | |
___ ___| |__
/ __/ __| '_ \
\__ \__ \ |_) |
|___/___/_.__/
Secure Shell Bruteforcer
infosec@kitabisa.com
________________________
:: Username: root
:: Hostname: 8.8.8.8
:: Port : 22
:: Wordlist: .\pass.txt
:: Threads : 10
:: Timeout : 30s
________________________
root@instance-1:/tmp# systemctl status sshguard
...
Jun 13 13:06:26 instance-1 sshguard[12077]: 8.8.4.4 has already been blocked
...
막힌다?
음 약간의 작용 기전을보면 ssh 접속 후 정상 종료나 에러가 발생하면, 막히지 않는다.
하지만 정상 접속된 응답(비밀번호)을 받으려는 동작(Scanner)이 있으면 바로 막히는 것 같다. telnet이 막힌 부분도 이와 비슷한 형태라 생각하면 될 것 같다.
+++ 추가
Client
PS C:\temp\ssb_0.1.1_windows_amd64> .\ssb.exe -w .\pass.txt -c 10 alinos_ssb@8.8.8.8
_
v0.1.0 | |
___ ___| |__
/ __/ __| '_ \
\__ \__ \ |_) |
|___/___/_.__/
Secure Shell Bruteforcer
infosec@kitabisa.com
________________________
:: Username: alinos_ssb
:: Hostname: 8.8.8.8
:: Port : 22
:: Wordlist: .\pass.txt
:: Threads : 10
:: Timeout : 30s
________________________
[VLD] Connected with 'password'.
[INF] Done!
Server
Jun 14 01:52:52 instance-1 sshd[9590]: Failed password for alinos_ssb from 8.8.4.4 port 8799 ssh2
Jun 14 01:52:52 instance-1 sshd[9592]: Failed password for alinos_ssb from 8.8.4.4 port 8798 ssh2
Jun 14 01:52:52 instance-1 sshd[9590]: Connection closed by authenticating user alinos_ssb 8.8.4.4 port 8799 [preauth]
Jun 14 01:52:52 instance-1 sshd[9592]: Connection closed by authenticating user alinos_ssb 8.8.4.4 port 8798 [preauth]
Jun 14 01:52:52 instance-1 sshguard[12077]: 8.8.4.4 has already been blocked
Jun 14 01:52:52 instance-1 sshguard[12077]: message repeated 5 times: [ 8.8.4.4 has already been blocked]
하루가 더 지난 후 그럼 무차별 대입할 때 vaild pasword 옵션이 없으면 대입한 암호를 알 수 없는게 말이 되나? 이게 맞나하는 마음에 다시 한번 테스트를 돌려봤다. (암호 저장 옵션 없이)
다행히 위에서 ssb가 잘 안막혔던 건 sshguard 재시작 후 journalctl data 분석을 위한 충분한 시간이 없어서 그랬던 것 같다.
지금은 그냥 무차별 대입 테스트를 해도 잘 막는다.
sshguard 설정 확인
root@instance-1:~# cat /etc/default/sshguard
...
ENABLE_FIREWALL=1
# By default all units are monitored in SystemD
# list of log files to scan delimited by space (Kfreebsd only)
LOGFILES="/var/log/auth.log"
# Whitelist configuration file
WHITELIST="/etc/sshguard/whitelist"
# Other options
ARGS="-a 40 -p 420 -s 1200"
root@instance-1:~# man sshguard
...
-a thresh (default 30)
Block an attacker when its dangerousness exceeds thresh. Each attack pattern that is matched contributes a fixed dangerousness of 10.
-p interval (default 120 secs, or 2 minutes)
Wait at least interval seconds before releasing a blocked address. Repeat attackers are blocked for 1.5 times longer after each attack. Because sshguard unblocks attackers only at infrequent intervals, this parameter is inexact
(actual blocks will be longer).
-s interval (default 1800 secs, or 30 minutes)
Forget about an attacker interval seconds after its last attempt. Its dangerousness will be reset to zero. ...
막힌 후 420초 이후에는 차단이 풀리는 옵션이 걸려있지만 거의 2배 840초가 기본인듯 하다. 840초 지난 후 실제로 iptables 에 자동으로 빠지는 부분까지 확인하였다.
그리고 1200초가 지나기 전에 또 공격하면 1680초로 두배의 시간동안 또 막히고, 만약에 1200초가 지나야 위험도가 0으로 리셋되는 것 같다.
root@instance-1:~# iptables -L sshguard -n
Chain sshguard (1 references)
target prot opt source destination
...
root@instance-1:~# systemctl status sshguard
● sshguard.service - SSHGuard
Loaded: loaded (/lib/systemd/system/sshguard.service; enabled; vendor preset: enabled)
Active: active (running) since Tue 2021-01-05 06:29:42 UTC; 5 months 7 days ago
Docs: man:sshguard(8)
Main PID: 1149 (sshguard-journa)
Tasks: 5 (limit: 640)
CGroup: /system.slice/sshguard.service
├─1149 /bin/sh /usr/lib/sshguard/sshguard-journalctl -i /run/sshguard.pid -w /etc/sshguard/whitelist -a 40 -p 420 -s 1200
├─1151 /bin/journalctl -afb -p info -n1 -o cat SYSLOG_FACILITY=4 SYSLOG_FACILITY=10
├─1152 /usr/sbin/sshguard -i /run/sshguard.pid -w /etc/sshguard/whitelist -a 40 -p 420 -s 1200
└─1159 /bin/sh /usr/lib/x86_64-linux-gnu/sshg-fw
...
Jun 13 10:25:50 instance-1 sshguard[1152]: Blocking 8.8.4.4 for 840 secs (4 attacks in 530 secs, after 1 abuses over 530 secs)
Jun 13 10:57:08 instance-1 sshguard[1152]: Blocking 8.8.4.4 for 1680 secs (4 attacks in 10 secs, after 2 abuses over 2408 secs)
Jun 13 11:27:12 instance-1 sshguard[1152]: Blocking 8.8.4.4 for 3360 secs (4 attacks in 9 secs, after 3 abuses over 4212 secs
root@instance-1:~# iptables -L sshguard -n
Chain sshguard (1 references)
target prot opt source destination
...
DROP all -- 8.8.4.4 0.0.0.0/0
누적되어 막힐 때마다 2배씩 늘어나기 때문에, 계속 공격했을 시에 걷잡을 수 없이 시간이 늘어난다.
WhiteList 테스트
root@instance-1:~# echo "8.8.4.4" >> /etc/sshguard/whitelist
root@instance-1:~# cat /etc/sshguard/whitelist
...
127.0.0.0/8
::1/128
8.8.4.4
root@instance-1:~# systemctl restart sshguard.service
root@instance-1:~# systemctl status sshguard
...
Jun 13 11:28:02 instance-1 sshguard-journalctl[8212]: Chain INPUT (policy ACCEPT)
Jun 13 11:28:02 instance-1 sshguard-journalctl[8212]: target prot opt source destination
Jun 13 11:28:02 instance-1 sshguard-journalctl[8212]: sshguard all -- 0.0.0.0/0 0.0.0.0/0
Jun 13 11:28:02 instance-1 sshguard-journalctl[8212]: Chain FORWARD (policy ACCEPT)
Jun 13 11:28:02 instance-1 sshguard-journalctl[8212]: target prot opt source destination
Jun 13 11:28:02 instance-1 sshguard-journalctl[8212]: Chain OUTPUT (policy ACCEPT)
Jun 13 11:28:02 instance-1 sshguard-journalctl[8212]: target prot opt source destination
Jun 13 11:28:02 instance-1 sshguard-journalctl[8212]: Chain sshguard (1 references)
Jun 13 11:28:02 instance-1 sshguard-journalctl[8212]: target prot opt source destination
Jun 13 11:28:03 instance-1 sshguard[8215]: Monitoring attacks from stdin
root@instance-1:~# systemctl status sshguard
...
Jun 13 11:29:49 instance-1 sshguard[8215]: 8.8.4.4: not blocking (on whitelist)
Jun 13 11:29:53 instance-1 sshguard[8215]: 8.8.4.4: not blocking (on whitelist)
Jun 13 11:29:55 instance-1 sshguard[8215]: 8.8.4.4: not blocking (on whitelist)
Jun 13 11:29:57 instance-1 sshguard[8215]: 8.8.4.4: not blocking (on whitelist)
Jun 13 11:30:00 instance-1 sshguard[8215]: 8.8.4.4: not blocking (on whitelist)
whitelist 를 적용하려면 sshguard 를 적용할려면 재시작을 해야했는데, 이 때 기존 blocklist rule 들이 모두 날라간다. (블록 리스트가 많다면, 유의해야 한다.)
그 후 동일한 형태(telnet)로 공격을 가해보면 whitelist 처리가 잘 되는 것을 확인할 수 있다.
journalctl 사용
├─sshguard-journa,8212 /usr/lib/sshguard/sshguard-journalctl -i /run/sshguard.pid -w /etc/sshguard/whitelist -a 40 -p 420 -s 1200
│ ├─journalctl,8214 -afb -p info -n1 -o cat SYSLOG_FACILITY=4 SYSLOG_FACILITY=10
│ └─sshguard,8215 -i /run/sshguard.pid -w /etc/sshguard/whitelist -a 40 -p 420 -s 1200
│ ├─sshg-fw,8216 /usr/lib/x86_64-linux-gnu/sshg-fw
│ └─{sshguard},8229
root@instance-1:~# journalctl -afb -p info -n1 -o cat SYSLOG_FACILITY=4 SYSLOG_FACILITY=10
Connection closed by authenticating user ubuntu 8.8.4.4 port 8824 [preauth]
Invalid user centos from 8.8.4.4 port 8825
Connection closed by 8.8.4.4 port 8826 [preauth]
8.8.4.4: not blocking (on whitelist)
Bad protocol version identification 'asd?' from 8.8.4.4 port 8827
8.8.4.4: not blocking (on whitelist)
Connection closed by authenticating user root
root@instance-1:~# ps awux | grep -iE '8214|8215|8212' | grep -v grep
#USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 8212 0.0 0.1 4632 848 ? Ss 11:28 0:00 /bin/sh /usr/lib/sshguard/sshguard-journalctl -i /run/sshguard.pid -w /etc/sshguard/whitelist -a 40 -p 420 -s 1200
root 8214 0.0 6.5 350008 38852 ? S 11:28 0:00 /bin/journalctl -afb -p info -n1 -o cat SYSLOG_FACILITY=4 SYSLOG_FACILITY=10
root 8215 0.0 0.4 16368 2548 ? Sl 11:28 0:00 /usr/sbin/sshguard -i /run/sshguard.pid -w /etc/sshguard/whitelist -a 40 -p 420 -s 1200
journalctl 을 Tracking 하면서 작동을 하고 있기 때문에, 메모리 문제가 있을려나 싶어서 계속 공격하면서 메모리 사용율을 확인해 봤지만 별로 늘어난 것은 없었다.
아마 소스코드를 살짝 확인 한 상태라 장담할 수 없지만, Blocklist 관리 자체는 별도의 디비를 사용하지 않고 메모리에서만 관리하고 있기 때문에 엄청난 수의 blocklist 개수가 있지 않은 이상은 메모리 때문에 문제가 될 일은 없을 것 같다.
그래서, 약간의 부작용도 있을 수 있는데 iptables/nftables 가 강제 혹은 수동으로 Flushing(ex: iptables -F) 된 경우 메모리 상에선 막고 있다고 생각하지만 실제로 막혀져 있지 않은 홀이 발생할 수 있기 때문에 유의해야 한다.
+++ 추가
root@instance-1:/var/log# ps awux | grep -iE '1207[5-9]'
#USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 12075 0.0 0.0 4632 68 ? Ss Jun13 0:00 /bin/sh /usr/lib/sshguard/sshguard-journalctl -i /run/sshguard.pid -w /etc/sshguard/whitelist -a 40 -p 420 -s 1200
root 12076 0.0 2.6 354352 15444 ? S Jun13 0:00 /bin/journalctl -afb -p info -n1 -o cat SYSLOG_FACILITY=4 SYSLOG_FACILITY=10
root 12077 0.0 0.3 81904 2084 ? Sl Jun13 0:00 /usr/sbin/sshguard -i /run/sshguard.pid -w /etc/sshguard/whitelist -a 40 -p 420 -s 1200
root 12078 0.0 0.1 4632 760 ? S Jun13 0:00 /bin/sh /usr/lib/x86_64-linux-gnu/sshg-f
하루가 더 지난 후 sshguard 하위로 돌고있는 journalctl RSS 메모리가 더 늘어나진 않을까 궁금해서, 확인을 해봤더니 더 늘어나지 않았다.
결론
ssh brute force 공격시에 무조건 dictionary 공격으로만 막히는 줄 알았지만, 실제로 어떤 암호로 로그인 됐는지 확인(scan)하는 과정에서 바로 막히는 부분을 새로 알게 되었다. 😅 (이거 때매 몇 시간을 들인건지..)
(sshguard 시작 후 journalctl data가 어느 정도 쌓이면 무차별 쓰레드 공격에 대한 옵션도 바로 Blocking 되는 것도 추가로 확인했다.)
클라우드 VM사용 및 제공시에 VPC를 사용하지 않고, 퍼블릭에 노출된 형태로 운영할 때 ssh bruteforce 공격은 서비스 제공업체나 사용자나 어떻게 제어해야 할지 애매한 부분들이 있다.
사용자 입장에선 테스트 서버로 사용시에 VPN 같은 환경은 구축하기 과하고 어디든(집/카페/야외 ..) 접속할 수 있기 때문에, 최소한의 ssh 접속 제어를 해야하고, 서비스 제공 업체에선 단순히 이런 부분을 VPC/VPN 혹은 Bastion Host 같은 가이드 외에 최소한의 방어 장치로는 좋은 솔루션으로 보인다.
거기다가 큰 기능이 없어보임에도 최근까지 git 업데이트 되고 있기 때문에, 최소한의 방어 장치로 제공하는 것이 좋을 것 같다.