2009년 4월 28일 화요일

SSH의 Brute Force Attak을 막기

가장 무식하지만서도 가장 확실한 SSH의 Brute Force Attack을 막기

SSH Brute Force Attack이란 흔한 사용자 이름과 암호로 ssh를 계속 접속해서 해킹을 시도하는 방법으로 잘못 이용되었을 경우 악영향을 끼친다. 기본으로 SSH 포트를 바꾸어버려 어느정도 SSH BFA를 막을 수도 있겠지만 확실한 해결책이 못된다.

방어방법
1. 강한 비밀번호 설정
2. RSA 인증 방식 사용
3. iptables를 이용한 패킷 Drop
4. sshd 로그를 이용하여 공격을 막기

1. 강한 비밀번호 설정
웬만하면 쉬운 비밀번호나 알아내기 쉬운 비밀번호를 쓰지 않도록 하는것이 좋다. 이미 쉬운비밀번호나 알아내기 쉬운 비밀번호들은 해커들의 Dic파일속에 존재하기 때문에 BFA를 몇시간째 돌리고 있으면 인츰 비밀번호가 깨질 수 있다. 특정된 구절의 이니셜을 이용하여 비밀번호를 설정하면 가장 좋다. 아니면 한글 사용자일 경우 다른 분의 이름 영문자타법에 특수문자 조합으로 설정하며 되겠다.
우점: 너무 심플하다.
결점: 비밀번호를 바꾸어도 BFA때문에 생기는 시스템 부하를 줄일수 없다.

2. RSA 인증 방식
기존에 비밀번호를 통한 인증방식보다 좀 더 고급적인 인증방식이다. 이런 방식으로 인증방식으로 바꾸면 일반 비밀번호를 통한 해킹은 전혀 의미가 없게 된다. ^^

① ssh-keygen -t rsa를 이용하여 RSA 키를 새로 생성한다. 위 명령어를 실행하면 /home/username/.ssh/id_rsa (private 키) and /home/username/.ssh/id_rsa.pub (public 키)가 생성된다.

# ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/username/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/username/.ssh/id_rsa.
Your public key has been saved in /home/username/.ssh/id_rsa.pub.
The key fingerprint is:
32-digit_hexadecimal_fingerprint username@hostname

② ssh 클라이언트 측 /home/username/.ssh/authorized_keys파일속에 기존에 만들어진 키들을 조합하여 넣는다. 알다싶이 이파일속에는 여러가지 public키들이 위치하여 이런 키들에 대한 관리가 용이해질 수 있다.
단 여기서 잊지 말아야 할 것은 authorized_keys를 만든 후 퍼민션을 필히 644로 세팅 해주어야 한다. 필자는 퍼미션을 정확히 세팅하지 않으므로 rsa인증이 잘 되지 않았다.

# cat /home/username/.ssh/id_rsa.pub >> /home/username/.ssh/authorized_keys
# chmod 644 /home/username/.ssh/authorized_keys

이렇게 생성된 authorized_keys파일을 ssh클라이언트측에 저장하여 매번 ssh접속시 사용 할 수가 있다. 위에 든 예제는 Linux상에서 public 키를 이용하여 인증하는 방식이고 윈도우에서 접속하려면 위 방식과 좀 다르다. 일단 쉘접속 툴로 많이 사용되는 SecureCRT에서 RSA 인증을 하는 과정을 보여주면 다음과 같다.
SecureCRT상에서 SSH세션을 새로 생성해준다. 다음 Session Option->Connection->SSH2 를 클릭하면 다음과 같은 대화창이 뜰거다.



위 대화창에서 볼 수 있다싶이 Authentication 방식에서 password란이 체크가 되지 않았다. Default값으로 password가 체크되어있을 것이다. 체크를 해제하고 Publickey를 선택한 상태에서 옆에 Properties버튼을 클릭하여 이미 생성한 RSA Public 키를 불러 들여오자.



단 주의할 점은 서버상 유저 루트 디렉토리 퍼미션이 700으로 설정이 되어야 정확히 인증이 된다. (이점은 좀 이상하다. 하지만 퍼미션을 707로설정하고 로그인을 시도한 결과 인증을 받을 수 없었다.)

③ 서버측 /home/username/.ssh/id_rsa 여기에는 이미 private 키가 생성이 되었으므로 별도의 작업이 필요 없다.

④ 마지막으로 /etc/ssh/sshd_config파일을 수정하여 비밀번호를 통한 인증방식을 무효화 한다. 또한 RSA Authentication 인증방식을 Yes을 바꾸어주고 주석문속에 해제한다.
마지막으로 service sshd restart하여 ssh데몬을 재시작 해준다.
우점: 보안이 상당히 믿음직스럽다. 일반 password방식보다는 한단계 업그레이드 된 인증 방식이다. 또한 password를 통한 무단 Brute Force Attack을 줄일 수 있다.
결점: 서버접속 할려면 public key를 갖고 있어야 할 뿐만 아니라 passphrase를 알고 있어야 한다. RSA인증 방식에 대한 이해를 못한 유저들은 이런 키를 자기절로 생성하여 쓸수 없으므로 다른 사람의 도움이 필요할것이다.

3. iptables를 이용한 패킷 Drop

① 정말로 약한 암호를 사용하는 사용자가 있을 경우 해당 계정이 해킹당할 수 있으며, 이 해킹당한 계정으로 로컬 커널 익스플로잇 등을 사용해서 루트를 빼앗길 수도 있다. 되도록이면 로컬 사용자를 적게 만들고 또한 만들었으면 비밀번호를 복잡하게 설정하여 이런 BFA를 어느정도 막을 수 있어야 한다. 하지만 해커가 사용하고 있는 Dictionary가 막강하면 암호를 복잡하게 만들었다 할지라도 뚤릴수 밖에 없게 된다.

② 그렇지 않더라도, 사용자 인증 로그(auth.log)에 짧은 시간 내에 수많은 실패 로그가 쌓여 다른 로그를 보는 데 방해가 될 수 있다.

③ 접속을 받는 동안 SSH 데몬이 암호학적 계산을 해야 하므로 시스템 자원을 소모할수도 있다.

iptables 는 리눅스 커널에 기본적으로 포함되어 있는 방화벽으로, 아주 다양한 방화벽 규칙을 만들 수 있으며, iptables 모듈을 사용해서 기능을 확장할 수도 있다. 다음은 iptables로 SSH Brute Force Attack을 막는 간단한 규칙이다. 이 규칙은 iptables 기본 모듈인 state와 recent를 사용한다.

state 모듈과 recent 모듈은 man 페이지에 자세하게 문서화되어 있기 때문에 문서를 참조하면 구체적인 사용법데 대하여 알수 있으므로 여기서는 생략하겠다. state 모듈은 언제 접속이 시작되고 끝나는지 추적할 수 있게 하고, recent 모듈은 IP 주소의 목록을 만들고 최근 접속 시간을 기록할 수 있게 한다.

규칙은 ssh 포트로 20초간 5회 이상 접속을 시도하면 10분간 접속을 차단하는 것이다.

우선 blacklist와 ssh 체인을 만든다.

# iptables -N blacklist
# iptables -N ssh

INPUT 체인에서 state 모듈로 ssh 포트인 22번 포트에 접속이 시작되면 ssh 체인으로 보낸다.

# iptables -A INPUT -m state --state NEW -p tcp --dport ssh -j ssh

blacklist 체인에서는 recent 모듈로 "blacklist"라는 목록에 접속 주소를 기록하고 접속을 거부한다.

# iptables -A blacklist -m recent --set --name blacklist
# iptables -A blacklist -j REJECT

규칙의 핵심인 ssh 체인은 다음과 같다.

# iptables -A ssh -m recent --update --seconds 600 --hitcount 1 --name blacklist -j REJECT
# iptables -A ssh -m recent --set --name ssh
# iptables -A ssh -m recent --update --seconds 20 --hitcount 5 --name ssh -j blacklist
# iptables -A ssh -j ACCEPT

이 규칙을 순서대로 설명하면 다음과 같다.
첫 번째 규칙은 접속 주소가 이미 "blacklist"에 들어 있고, 지난 10분간 1회 이상 접속이 있었으면 접속을 거부한다.
두 번째 규칙은 접속 주소를 "ssh" 목록에 기록한다.
세 번째 규칙은 접속 주소가 이미 "ssh" 목록에 들어 있고, 지난 20초간 5회 이상 접속이 있었으면 blacklist 체인으로 보낸다.
네 번째 규칙은 여기까지 통과한 경우 ssh 접속을 허락한다.

따라서 전체 스크립트는 다음과 같이 된다.

iptables -N blacklist
iptables -N ssh
iptables -A INPUT -m state --state NEW -p tcp --dport ssh -j ssh
iptables -A blacklist -m recent --set --name blacklist
iptables -A blacklist -j REJECT
iptables -A ssh -m recent --update --seconds 600 --hitcount 1 --name blacklist -j REJECT
iptables -A ssh -m recent --set --name ssh
iptables -A ssh -m recent --update --seconds 20 --hitcount 5 --name ssh -j blacklist
iptables -A ssh -j ACCEPT

4. sshd 로그를 이용하여 공격을 막기
서버에 들어오는 ssh 공격에 대하여 sshd 데몬은 그것들을 특정된 로그파일에 저장해주고 있는데 이렇게 생성된 파일을 참조하고 몇가지 프로그램을 조합하여 사용하는 것을 통하여 ssh 공격을 막을 수 있다.

① sshdfilter는 iptables를 이용하여 블럭을 한다. 동작방식은 상당히 간단한데 firewall 룰을 iptables에 추가하여 특정된 공격을 막는것이다. 이 방식으로 공격을 막기위하여 sshd데몬대신 sshdfilter데몬을 작동시켜야 한다. sshdfilter데몬은 sshd데몬과 흡사한데 단지 다른점이라면 생성된 log에 대한 분석을 해준다는것이다.

② Fail2Ban은 일종 Python스크립트인데 이 스크립트는 sshd로그에 근거하여 커스텀 Firewall룰을 적용시키는 방식으로 공격을 막는다. 공격을 막기 위하여 사용되는 툴로는 iptables, ipfwadm 혹은 ipfw등이다.

③ DenyHosts는 firewall을 이용하여 공격을 막는것이 아니고 관련 룰들을 /etc/hosts.deny에 써주는 방식으로 공격을 차단한다. 단 이것을 사용하기 위하여서는 sshd 데몬이 컴파일 될시 tcp_wrappers를 지원하게끔 되어있어야 한다. 사실 DenyHosts도 Python 스크립트로 씌여졌다. tcp_wrappers를 지원하고 있는 지를 판단하는 방법은 상당히 심플한데 직접 hosts.deny를 편집하고 그 속에 127.0.0.1를 넣어준 상태에서 서버에서 ssh방식으로 자기자신을 접속하게 한다. 만약 접속이 안되면 tcp_wrappers를 지원하고 있는것이다.

참조문서: http://la-samhna.de/library/brutessh.html

댓글 없음:

댓글 쓰기