ClamAV 명령어 및 TCP 통신을 통한 ClamAV 사용법
ClamAV는 TCP socket을 통해 명령을 제어할 수 있다. File Socket을 통해 명령을 제어할 수 있으나 여기서는 다루지 않겠다.
- 요청-응답 당 하나의 connection을 갖는다.
- 명령앞에 ‘n’ prefix를 추가하는걸 권장 (특정 명령은 n이 무조건 필요하다.)
- ex) PING 명령을 하는경우
nPINGecho "sPING" | nc localhost 3310
- ex) PING 명령을 하는경우
명령어
PING- 무조건 PONG이 반환되어야 한다.
VERSION- clamav의 버전 및 DB의 버전을 반환한다.
RELOAD- Signature Database 리로드
SHUTDOWN- ClamAV 데몬 종료
SCAN파일/디렉토리- ClamAV가 설치된 서버의 파일이나 디렉토리(재귀적으로)를 검사한다.
- 기본적으로 아카이브파일에 대한 검사를 허용함 (clamd.conf 비활성화 가능)
- 압축 파일내 파일들을 검사하는 것
RAWSCAN파일/디렉토리CONTSCAN파일/디렉토리- ClamAV가 설치된 서버의 파일이나 디렉토리(재귀적으로) 검사하며 바이러스가 감지되어도 검사를 중단하지 않음
- 기본적으로 아카이브파일에 대한 검사를 허용함
MULTISCAN파일/디렉토리- 파일의 경우 SCAN처럼 동작한다.
- 디랙토리의 경우 멀티 스래드를 사용하여 검사한다.
ALLMATCHSCAN파일/디렉토리- 감염된 파일에 대한 모든 시그니처를 반환한다.
- infected.doc 라는 파일에 2개의 시그니처가 존재하면 아래와 같이 반환된다.
SCAN의 경우infected.doc: Trojan.Agent FOUND
ALLMATCHSCAN의 경우infected.doc: Trojan.Agent FOUND infected.doc: Macro.Downloader FOUND
INSTREAM- 바이트스트림 기반 검사를 수행합니다.
FILDES- 검사시 파일 경로를 직접 호출하는게 아닌 파일 디스크립터(fd)를 통해 검사합니다.
- 이미 열려있는 파일을 clam이 검사하려고 할 때 유용하게 사용됨
- Unix 시스템에서만 동작
STATS- clamav의 상태를 리턴한다.
- 스캔 큐(queue) 상태
- 현재 큐에 쌓인 파일들 정보
- clamd 프로세스의 메모리 사용량 등
- clamav의 상태를 리턴한다.
IDSESSION, END- 일반적으로는
SCAN이나INSTREAM같은 명령을 보낼 때마다 소켓을 열고 → 명령 보내고 → 응답 받고 → 닫음 패턴을 따릅니다. - 그런데 파일을 많이 검사해야 하면, 매번 소켓을 새로 여닫는 건 오버헤드가 커집니다.
- 그래서
IDSESSION을 쓰면 하나의 연결(socket)을 열어둔 채로 여러 명령을 순차적으로 보낼 수 있음.
- 일반적으로는
코드 예제
1. SCAN을 통한 바이러스 파일 및 일반 파일 검사
코드
public static void main(String[] args) throws Exception {
Socket virusTestSocket = new Socket( // clamav 소켓생성
"<clamav-server-ip>", 3310
);
var in = virusTestSocket.getInputStream();
var out = virusTestSocket.getOutputStream();
out.write("nSCAN /tmp/eicar.com.txt\n".getBytes()); // /tmp/eicar.com.txt 파일에 대한 검사 요청 명령
out.flush(); // 명령 전달
var virusResult = new String(in.readAllBytes()); // 응답
Socket normalTestSocket = new Socket( // clamav 소켓생성
"<clamav-server-ip>", 3310
);
in = normalTestSocket.getInputStream();
out = normalTestSocket.getOutputStream();
out.write("nSCAN /tmp/normal-txt\n".getBytes()); // /tmp/normal-txt 파파일에 대한 검사 요청 명령
out.flush(); // 명령 전달
var normalResult = new String(in.readAllBytes()); // 응답
System.out.println("virus sample result : " + virusResult);
System.out.println("normal sample result : " + normalResult);
}
출력
virus sample result : /tmp/eicar.com.txt: Win.Test.EICAR_HDB-1 FOUND
normal sample result : /tmp/normal-txt: OK
출력된 결과를 보면 normal sample result 이전 줄이 줄바꿈 되어있는데 이는 하나의 매시지가 끝나면 개행문자(\n) 을 통해 메세지의 끝을 구분하기 때문이다.
2. IDSESSION, END 을 통한 다중 SCAN
코드
public static void main(String[] args) throws Exception {
Socket virusTestSocket = new Socket( // clamav 소켓생성
"<clamav-server-ip>", 3310
);
var in = virusTestSocket.getInputStream();
var out = virusTestSocket.getOutputStream();
out.write("nIDSESSION\n".getBytes()); // 세션 시작
// out.write("nPING\n".getBytes()); // PING 요청 (만약 오랬동안 세션을 열고 있으면 주기적인 PING 체크가 필요할 수 있다.
out.write("nSCAN /tmp/eicar.com.txt\n".getBytes()); // /tmp/eicar.com.txt 파일에 대한 검사 요청 명령
out.write("nSCAN /tmp/normal-txt\n".getBytes()); // //tmp/normal-txt 파일에 대한 검사 요청 명령
out.write("nEND\n".getBytes()); // 세션 요청 끝
out.flush(); // 명령 전달
var result = new String(in.readAllBytes()); // 응답
System.out.println(result);
}
출력
2: /tmp/normal-txt: OK
1: /tmp/eicar.com.txt: Win.Test.EICAR_HDB-1 FOUND
출력된 결과를 보면 명령을 보낸 순서와 다르게 출력되는걸 확인할 수 있다.
따라서 명령별 순차적인 ID를 부여하여 이를 응답에 매칭하는 처리가 필요하다.
CLI로 테스트 - nc
echo "nPING" | nc localhost 3310 # PING 요청
echo "nSCAN /tmp/eicar.com.txt" | nc localhost 3310 # scan 요청