작은 메모장
25. Snort 기초 설정 본문
네트워크 보안의 시작
네트워크라는 이름 그대로, 전 세계를 연결하는 정보 통신망이다.
네트워크는 정말 무식하게 구현하였는데, 정말 "물리적으로" 전 세계의 통신망을 연결하였다.
케이블로 전 세계를 전부 연결한 것이다.
이말은 즉 물리적 제약이 적다는 의미고, 이말은 즉 해킹을 막을 물리적인 수단이 적다는 뜻이다.
더 자세하게 말하면, 네트워크 안에서 피아 식별이 매우 어렵다는 뜻이다.
정확하게 "이 사람이다"하는 물리적인 수단이 없다 보니, 피아 구분이 어려워 네트워크 방어가 매우 어렵다.
그럼에도 불구하고, 이 "네트워크 망"의 방식은 매우 효율적이었는데, 결국에는 내가 사용하는 네트워크 망으로 들어올 수 있는 경로는 제한되어 있기 때문이다.
이 들어오는 경로에 대해서만 아주 정밀하게 접근 제어를 실행하면 강도높은 보안을 구축이 가능하다.
방화벽
1994년, 체크포인트 Firewall-1이라는 이름으로 방화벽이 처음 등장했다.
이때의 방화벽은 정말 단순한 원리로 동작했는데, IP와 Port만 보고 접근과 차단을 결정했다.
허용 정책에 포함되지 않는 모든 IP와 Port는 전부 차단을 한 간단한 방식이었다.
하지만 웹 사이트 등, 웹 서비스의 등장으로 기존 방화벽 방식으로 차단할 수 없는 서비스가 나오기 시작했다.
웹 서비스는 어느 누구나 접근해야하기 때문에 기존 방화벽 방식은 사용할 수 없었고,
이에 웹 해킹의 개념이 등장하면서 새로운 방화벽 방식이 요구되었다.
IDS
앞서 설명한 이유로 IP와 Port의 상위 개념의 접근 제어 필요성이 대두되었다.
누구나 들어올 수 있는 웹 서비스를 IP와 Port만으로는 막기 어렵기 때문이었다.
이에 애플리케이션 레이어의 데이터 패턴을 검사하는 snort가 1998년에 개발되었고,
이 snort의 주요 동작 원리는 패턴 매칭이었다.
패턴매칭
인류에게 있어 가장 효과적이고 확실한 데이터 수집/분석 방법은 도청이다.
아무리 숨겨도 데이터가 오고가는 길목에서 그걸 통째로 들어버리면 데이터를 놓칠 일이 없기 때문이다.
이에 기본적으로 IDS는 데이터 도청을 한다는 전제로 동작한다.
데이터의 통신은 사람의 대화와 비슷하며, 이는 주고 받는 패턴이 명확하게 존재한다.
가령, TCP 연결이 시작할 때 3-way-handshake를 하는 것처럼 명확하게 정해진 패턴이 존재한다.
이를 파악하여 데이터를 주고 받는 대화 상대가 어떤 관계인지를 파악할 수 있다.
침입탐지 모델
1986년, An Intrusion Detection Model이라는 이름으로 패턴매칭의 2가지 방법이 제시되었다.
패턴매칭(오용행위 분석) | 이상징후(비정상행위 분석) | |
개념 | 정의된 패턴을 갖는 공격만 막는다 | 정의된 패턴을 같는 정상만 허용한다 |
장점 | 알려져 있는 공격을 효과적으로 막는다 | 알려지지 않은 공격또한 막을 수 있다 |
단점 | 알려지지 않은 공격은 그대로 당한다 | 정상 범위를 정의하기 어렵다 |
구현예시 | IDS, IPS (Black List) | 방화벽, 웹방화벽(White List) |
초기의 보안은 오용(공격) 패턴을 찾는 패턴매칭 중심으로 발전했다.
그렇다고 이상징후 분석을 아얘 배재한 것은 아니라, 패킷 임계치 초과 등 이상징후 분석의 일부분은 수용하였다.
패턴매칭의 장점은 적용하기 쉽고, 개념적으로도 이해가 빠르며, 검사 범위를 좁힐 수 있는 장점이 있다.
알려져 있는 공격에 대해서는 효과적으로 막을 수 있기 때문에, 알려져 있는 공격만 발빠르게 막으면 안전한 셈.
그래서 2000년대 중기까지 IDS, IPS, WAF까지 패턴매칭 방식을 사용하였으며, 문제가 없어보이는 듯 했다.
오탐
인터넷 게임에서 가장 막기 어려운 것 중 하나가 욕설 필터링이라고 한다.
보통 욕설 필터링을 블랙리스트 방식으로 적용하는데, 이를 피하기 위해 중간에 숫자 혹은 특수문자를 섞어 넣거나 글자를 대체하는 등 다양한 방법으로 표현한다.
그렇다고 너무 강도높은 욕설 필터링을 적용하면, 일반적인 대화에도 필터링이 영향을 끼쳐 정상적인 대화가 힘들어지기도 한다.
이런 이유로 욕설만을 필터링을 완벽하게 하는 것은 불가능한 수준이라고 한다.
네트워크 데이터도 마찬가지로, 트래픽이라는 것은 수십 개 수준의 문자 기호로 수십만 이상의 문자열이 조합된 문자 덩어리이다.
당연하게도 IDS가 데이터의 흐름과 상황같은 건 따지지도 않고 무조건 패턴만 구분하며,
일반적인 트래픽 흐름에 꼭 필요한 구문이 알려져 있는 공격에 대한 패턴에 있다면 무조건 탐지/차단하기에,
IDS가 정상적인 데이터 흐름을 막고 있는 것이다.
즉, 잘 만들어지지 않은 IDS 패턴 시그니처 때문에 정상적인 데이터 흐름을 공격이라고 잘못 탐지하고 있다.
이에 2000년대 초반부터 이 "잘못 탐지하는 문제", 오탐에 대해서 문제가 제기되었고,
지속적으로 룰을 고쳐나가면서 "정상트래픽은 영향이 없으면서, 이상 트래픽은 검출하는" 패턴을 찾고 있는 상태다.
Vim
Vi iMproved, vi 편집기의 향상버전으로 리눅스의 메모장 역할을 맡고 있다.
원래는 리눅스에서 쓰는 CLI용 vim이 주였지만, 인기가 늘어나면서 GUI용 gVim도 있기도 하다.
vi편집기는 사용하기에도 가볍고 직관적이었으나, 가독성이 매우매우 떨어지는 문제가 있었고, 그 외에도 다른 문제들도 수두룩하였다.
이에 vim에서, 파일의 완성, 비교, 병합, 도움말 시스템, 확장 정규 표현식, 플러그인 지원 등 엄청난 개선이 이루어졌으며,
네트워크 프로토콜을 경유한 파일 편집, 맞춤법 검사, 세션 상태 보존, 수직/수평 탭 창, 유니코드 및 기타 다언어 지원, 문법 강조 등의 시각적 표현 또한 향상되었다.
vim의 명령어는 상당히 많지만, 다음의 명령어를 주로 사용한다
명령어
- i : 현재 커서 위치에서 문자 입력
- A : 현재 커서가 위치한 줄 끝에서 문자 입력
- ESC : 일반 모드(읽기만 가능)로 전환
- x : 현재 커서 위치의 문자 삭제
- dd : 현재 커서 위치의 줄(Line) 삭제
- gg : 첫 번째 줄로 커서 이동
- G : 마지막 줄로 커서 이동
- u : 실행 취소 (undo)
- CTRL + r : 재실행 (redo)
검색 모드
- / : 검색
- n : 위에서부터 검색어와 일치하는 문자의 위치로 커서 이동
- N : 아래에서부터 검색어와 일치하는 문자의 위치로 커서 이동
명령 모드
- :w : 저장
- :q : 종료
- :wq : 저장 후 종료
- :번호 : 해당 줄 번호로 커서 이동
명령 모드는 뒤에 !를 붙이면 강제 실행이 된다.
워드나 한글 프로그램 종료시 팝업 뜨는 창을 무시하고 강제로 실행하는 걸 생각하면 편하다.
SQL
Structured Query Language의 줄임말로, 데이터 조회 및 가곡 등에 사용하는 구조적 질의 언어
즉, 저장된 데이터를 조회하기 위한 질문이다.
가끔 SQL문이 그냥 데이터를 가져오기 위한 명령어로 혼동하는데,
비슷한 느낌이긴 하지만 어디까지나 Query, 즉 데이터베이스에게 질의를 하는 것이 SQL이다.
이를 혼동하면 안된다.
SQL의 기본 구조는 select, from, where의 구조로,
- select : 어떤 필드를 탐색하는가
- from : 어떤 테이블에서 탐색하는가
- where : 어떤 조건으로 탐색하는가
이 3가지 조건만 알고 있으면 된다.
예를 들면, "student"라는 테이블에서 학번이 11인 학생의 이름을 찾고 싶다.
그렇다면, 다음과 같은 조건으로 정리할 수 있을 것이다.
- 내가 찾고 싶은 것은 학생의 "이름"이다. = select 성명
- 내가 찾으려는 곳은 student 테이블이다. = from student
- 내가 찾으려는 조건은 학번이 11이다. = where 학번 = 11
따라서 다음과 같은 SQL문이 완성된다.
select 성명 from student where 학번 = 11 |
snort에서 주요한 테이블과 필드의 내역은 다음과 같다.
눈여겨 볼만한 곳은 event 테이블과 signature 테이블로, 각각 트래픽 발생 이벤트와 각 룰의 시그니처를 담고 있는 테이블이다.
이 두 테이블의 signature 필드값과 sig_id 필드값이 동일하다면, 그건 이벤트가 발생한 트래픽 값과 룰에 있는 트래픽 값이 동일하다는 의미로, 룰에 있는 이벤트가 발생하였다는 의미다.
때문에 검색할 때는 where event.signature = signature.sig_id 형태로 검색하는 편이다.
SQL은 정말 다양한 기능을 제공하고 있는데, 테이블을 일일히 치기 귀찮은 사람들을 위해 별칭 부여 기능도 제공하고 있다.
아래의 SQL문을 한번 살펴보자.
select a.timestamp, b.sig_name from event a, signature b where a.signature = b.sig_id |
select를 할 때 뭔가 이상한 방법으로 select를 하고 있다.
테이블의 이름이 아닌, 별칭을 앞에 쓰고 .을 붙인 후, 뒤에 필드 이름을 붙여 select 문을 완성했다.
그 이후엔 별칭을 마치 테이블처럼 사용하고 있는 모습을 확인할 수 있다.
이처럼 처음 select문을 선언할 시, select [별칭].[필드]으로 선언하게 되면 별칭을 테이블처럼 사용할 수 있다.
DB의 검색조건을 만들어주는 where문은 조건을 여러개 사용할 수 있다.
select a.timestamp, b.sig_name, c.data_payload from event a, signature b where a.signature = b.sig_id and a.sid = c.sid and b.sid = c.sid |
이런 식으로 and 문을 써서 여러 조건을 동시에 적용할 수 있다.
또 다른 편의기능으로는 unhex함수를 사용할 수 있다.
select a.timestamp, b.sig_name, unhex(c.data_payload) from event a, signature b where a.signature = b.sig_id and a.sid = c.sid and b.sid = c.sid |
이는 16진수를 디코딩해주는 함수로, 그 결과가 payload할 위치에 디코딩되어 저장되게 된다.
이처럼 다양한 기능을 사용할 수 있으므로, SQL 문을 사용할 때는 찾아가면서 적용시키는 것도 좋은 사용이다.
Snort
Snort 실습을 위해 간단한 환경을 구성할 것이다.
환경은 다음과 같다
OS: CentOS 7 (VirtualBox 구동)
Terminal: PUTTY
네트워크 구성도
실습
CentOS를 VirtualBox로 실행한다. 초기설정 후, 네트워크 구성에 맞게 NAT 설정과 eth1 IP 설정을 변경한다.
PUTTY를 이용하여 SSH 연결(56.100)
Snort 설치 후 설치 여부 확인
Snort 설치를 위해 다음의 명령어 입력
[snort 설치] yum install epel-release -y yum install wget gcc gcc-c++ libnetfilter_queue-devel git flex bison zlib zlib-devel pcre pcredevel libdnet* libpcap* nghttp2 xz-devel libtool libsfbpf* daq* -y rpm -ivh https://snort.org/downloads/snort/snort-2.9.20-1.centos.x86_64.rpm ln -s /usr/lib64/libdnet.so.1.0.1 /usr/lib64/libdnet.1 |
여기까지 실행됬다면, 현재의 Snort 설정은 다음과 같을 것이다.
이는 Snort가 어디서 실행되고, 설정 변경은 어디서 하며, 룰 변경은 어디서 해야할 지를 도식화한 것으로
실행파일은 설정파일의 위치를, 설정파일은 룰 파일의 위치를 서로 참고하고 있다.
간단한 설정을 해보자
vim 편집기로 /etc/snort/rules/local.rules 파일을 다음과 같이 수정
vim 편집기로 /etc/snort/snort.conf 파일 수정. Line 145, checksum_mode 값 none으로 변경
vim 편집기로 /etc/snort/snort.conf 파일 수정. Line 253, dynamic rules 설정 주석 처리
vim 편집기로 /etc/snort/snort.conf 파일 수정. Line 510~512, white/blacklist 설정 주석 처리
vim 편집기로 /etc/snort/snort.conf 파일 수정. Line 521, 탐지로그 저장 설정
vim 편집기로 /etc/snort/snort.conf 파일 수정. 해당 명령어를 통해 Line 548~651, 룰 설정 주석처리
저장 후 종료
Snort를 실행하려면 다음과 같은 명령어를 입력하면 된다.
snort -i [인터페이스] -c /etc/snort/snort.conf |
이는 가장 기본적인 실행방법으로, 경고와 패킷 데이터 구분 없이 저장되게 된다.
만약 구분하고 싶다면, 다음과 같은 여러 방법들이 있다.
- snort -i eth0 -c /etc/snort/snort.conf -A fast (IP 헤더 수준 기록)
- snort -i eth0 -c /etc/snort/snort.conf -A full (프로토콜 헤더 수준 기록)
- snort -i eth0 -c /etc/snort/snort.conf -K ascii (출발지별 프로토콜 헤더 수준 기록)
새 세션을 열어서 동작을 확인해보자
로그파일이 저장되는 공간이다. alert와 snort로그가 전부 크기가 0인것을 확인할 수 있다.
적당하게 ping을 날린 후, 로그 파일을 다시 확인하면 크기가 늘어나 있는 것을 확인할 수 있다.
alert 파일을 확인하면 ping이 찍혀있는 것을 확인할 수 있다.
로그 파일도 tcpdump를 사용하여 확인하면 로그 파일이 생성되어 있는 것을 확인할 수 있다.
부가 서비스 설치 (Mysql, barnyard2)
해당 명령어를 사용하여 mysql을 설치한다.
rpm -ivh https://dev.mysql.com/get/mysql80-community-release-el7-7.noarch.rpm yum install mysql-server mysql-devel -y |
만약 mysql-server 패키지 설치 시 GPG key 오류가 난다면 vim /etc/yum.repos.d/mysql-community.repo 의 파일을 수정해주면 된다.
[mysql80-community] 항목의 'gpgcheck' 옵션을 'gpgcheck=0'으로 수정하고 다시 시도하면 된다.
mysql 서비스를 시작해준다.
mysql 서비스를 시작한다면 패스워드 정책을 변경해준다.
echo >> /etc/my.cnf echo "default_password_lifetime=0" >> /etc/my.cnf echo "validate_password.policy=LOW" >> /etc/my.cnf echo "validate_password.length=6" >> /etc/my.cnf echo "validate_password.special_char_count=0" >> /etc/my.cnf echo "validate_password.mixed_case_count=0" >> /etc/my.cnf echo "validate_password.number_count=0" >> /etc/my.cnf echo "skip_external_locking" >> /etc/my.cnf echo "skip_name_resolve " >> /etc/my.cnf service mysqld restart |
서비스 재시작까지 완료하면 정책이 반영이 됬을 것이다.
패스워드 재설정을 해보자. Mysql의 패스워드 및 접속권한 변경은 아래와 같이 설정한다.
[mysql 패스워드/접속권한 변경] grep "temporary password is generated" /var/log/mysqld.log | grep -oP "\S+$" mysql --connect-expired-password -uroot -p -e "alter user 'root'@'localhost' identified with mysql_native_password by 'no1ids';" mysql -uroot -p -e "create user 'root'@'%' identified by 'no1ids';" mysql -uroot -p -e "alter user 'root'@'%' identified with mysql_native_password by 'no1ids';" mysql -uroot -p -e "grant all privileges on *.* to 'root'@'%' with grant option;" |
두 번째 명령어를 입력할 때, 첫 번째 명령을 입력해서 나온 임시 비밀번호를 입력하면 된다.
이후의 명령은 따로 재설정한 비밀번호(여기서는 no1ids)를 입력하면 된다.
설정한 id와 비밀번호로 접속을 시도
만들어둔 SQL로 접속이 잘 되는것을 확인할 수 있다.
DB도 만들었고, Snort도 만들었으니 이제 설정이 끝났을것 같지만, DB와 Snort는 서로 연결할 수가 없다.
때문에 이를 강제로 연결해주는 패키지를 설치해야하는데, 이것이 barnyard2이다.
따라서 barnyard2를 설치한 후의 최종적인 구조는 다음과 같을 것이다.
barnyard2는 패키지 설치가 자동으로 되지 않는다.
따라서 수동으로 패키지 압축 해제부터 경로 설정까지 전부 수작업으로 진행한다.
wget https://github.com/firnsy/barnyard2/archive/master.tar.gz -O barnyard2.tar.gz tar xvzf barnyard2.tar.gz |
위 명령으로 barnyard2 파일을 다운 받고, 압축을 해제한다.
cd barnyard2-master sed -i 's/my_bool/bool/' src/output-plugins/spo_database.h ./autogen.sh ./configure --with-mysql --with-mysql-libraries=/usr/lib64/mysql && make && make install |
그 후, 압축 해제한 디렉토리로 이동 후, 설치 파일을 실행한다.
mkdir /var/log/barnyard2 touch /var/log/snort/barnyard2.temp cp /usr/local/etc/barnyard2.conf /etc/snort/ |
그 후, /var 디렉토리 안에 barnyard2 전용 디렉토리를 생성해주고, snort 안에도 barnyard2를 연결시켜준다.
mysql -u root -p -e "create database snort"; mysql -u root -p -D snort < schemas/create_mysql |
마지막으로 DB에 snort DB를 생성해준다.
barnyard2가 가져온 데이터를 어디에 저장할 지 설정해줘야한다.
barnyard2는 어디에 어떤 DB가 어떤 정보로 있는지 모르기 때문이다.
vim /etc/snort/barnyard2.conf |
Line 351, output database라는 이름으로 가져온 데이터를 저장할 경로를 설정하는 부분이 있다.
여기에 현재 환경에 맞게 설정하면 된다.
이 명령어는 log파일을 mysql의 root계정(비밀번호 no1ids)으로 snort라는 db에 저장하겠다는 의미이다.
최종적으로 barnyard2의 구성은 위와 같다.
barnyard2 실행파일이 설정파일을 참조하고,
설정파일은 sid-msg의 데이터를 불러오며,
sid-msg는 snort의 룰파일을 통해 데이터를 받아오는 구조다.
그리고 위 설정을 전부 끝마쳤다면, 위와 같은 구조가 완성이 되었을 것이다.
snort와 barnyard2가 잘 동작하는지 테스트해보자.
저번에 만들었던 룰을 그대로 사용할 것이다. 단, rev 옵션을 추가해야만 barnyard2와 연동이 가능하다.
vim /etc/snort/rules/local.rules |
현재 barnyard2는 설정파일이 참고할 sid-msg파일이 존재하지 않고 있다. 이를 만들어주자.
vim /etc/snort/sid-msg.map |
설정했던 sid 값에 맞게 파이프라이닝으로 태그를 달아주면 된다.
barnyard2와 snort를 실행할 차례다.
실행 순서는 barnyard2를 실행 후, snort를 실행하면 된다.
barnyard2 -c ‘설정 파일’ -d ‘snort 로그 경로’ -f ‘snort 로그 파일’ -w ‘임시 파일’ |
barnyard2의 실행방법이다. 요구하는 경로에 맞게 명령어를 입력하면 된다.
정상적으로 실행이 되는 모습
snort -i '랜카드 인터페이스' -c '설정 파일' |
위에서도 설명한 snort 실행방법이다. 랜카드 인터페이스를 혼동하지 않도록 유의하자.
snort 또한 정상적으로 실행이 되는 모습
이 상태에서 ping을 날려보자
그럼 정상적으로 snort가 실행되는 것을 확인할 수 있다.
기본적으로 제공한 snort os 이미지 파일을 사용하였다.
새 이미지를 생성하였고, 접속 ip 대역은 58.101 이다.
snort 룰 파일과 sid-msg 파일을 확인하였다. 여기에 icmp-response 또한 새로 입력할 것이다.
각각에 파일에 sid 1000001번으로 icmp response 값을 새로 입력한다.
snort 임시파일이 없는 것을 확인하였다. 동작할 때 오류가 날 수 있으므로, 임시파일을 만들어준다.
정상적으로 생성된 것을 확인하였다.
이제 snort와 barnyard2를 실행해보자
barnyard2 실행완료
snort 실행완료
이제 윈도우 환경에서 ping을 날려보자
그럼 이렇게 barnyard에서 트래픽을 잡은 것을 확인할 수 있다.
트래픽 캡쳐 결과를 확인해보자.
수정된 IP를 기반으로 DB에 접근한다.
그 후, 다음의 SQL 문을 입력한다.
select a.timestamp, b.sig_name from event a, signature b where a.signature = b.sig_id |
그럼 이렇게 DB에 icmp 트래픽이 저장된 것을 확인할 수 있다.
'실더스 루키즈 교육' 카테고리의 다른 글
27. PCRE (0) | 2024.01.23 |
---|---|
26. Snort 룰 (0) | 2024.01.23 |
24. 개인정보보호법 개요 2 (0) | 2024.01.05 |
23. 개인정보보호법 개요 (0) | 2024.01.05 |
22. Amazon S3 (0) | 2023.12.28 |