기본적으로 스크립트 자체가 디비와 연동하기도 하고 웹페이지에 간단한 대쉬보드도 만들어야 하기 때문에 APM을 설치해야한다.
Apache, PHP, Mysql에 대한 설정은 아래 블로그에 굉장히 자세히 나와있으니 따라해보도록 하자
필자는 Mysql의 M자도 모르기 때문에 PMA를 사용하여 간단히 조작하려 한다.
이또한 phpmyadmin에 대한 설치 및 설정은 아래 블로그에 자세히 나와있다.
애석하게도 필자의 경우 phpmyadmin를 설치하면 꼭 설정해주는 것이 있는데, Mariadb 서버에서 계정 접속이 기본적으로 localhost기 때문에 외부 접속을 위해 별도로 계정 설정을 해줘야 로그인이 되었다. 비슷한 케이스를 겪는다면 케이스에 맞게 아래 링크를 참고하길 바란다.
APM과 PMA준비가 끝났으면 데이터베이스를 먼저 생성해 보도록 하자
필자는 DB튜닝에 'ㅌ'자도 모르기 때문에 주먹구구식으로 배운 방법으로 최대한 범용성과 규칙성, 확장성 있게 디비를 꾸려보도록 한다.
DB에 기록된 량이 많을수록 쿼리를 던졌을 때 처리 속도가 떨어지기 때문에 일부 데이터는 아에 raw로 디스크에 저장하여 I/O를 빠르게 처리하려고 했는데 진짜 저 방식은 범용성은 둘째치고 확장성이 굉장히 떨어진다.
그래서 최대한 DB를 잘 사용하는 것으로 하고 인덱스 설정이나 DB최적화를 어디선가 주워들어서 입맛에 맞게 설정하도록 하자.
데이터베이스의 스키마틱을 잘 짜는 편은 아니지만 대충 아래와 같이 짜보았다. 미리 짜놓은 데이터베이스의 덤프파일은 바로 아래에서 받을 수 있으니 만들기 귀찮으면 임포트 하도록 하자
- 다운로드 첨부
첫 번째 내용은 1편의 내용과 같다.
uri_crawl (데이터베이스)
-> imp_domains : 크롤링 할 도메인 목록
Culumn Name | Culumn Type | Value | Description |
imp_index | int | 4 | Primary |
imp_datetime | datetime | ||
imp_domain_name | varchar | 300 | |
imp_domain_name_srv | varchar | 50 | |
imp_domain_ip_address | varchar | 20 | |
imp_domain_ip_ISP | varchar | 50 | |
imp_domain_verify | boolean | 도메인 유효성 확인 | |
imp_domain_script_crwal | boolean | 스크립트 시작점 확인 |
-> imp_src_patterns : 웹 파일 로드 패턴 등록 (script src, iframe src 등등...)
Culumn Name | Culumn Type | Value | Description |
imp_idx | int | 4 | Primary |
imp_datetime | datetime | ||
imp_src_pattern | varchar | 300 | 정규 표현식 또는 문자열 |
imp_src_pattern_base64 | varchar | 500 | 패턴 base64 인코딩 |
imp_src_call_unraveler_script | varchar | 50 | 분석 스크립트의 MD5 |
imp_src_tag | varchar | 10 | 탐지 태그 (ex #JS-Script) |
imp_enable | boolean | 기능 사용 유/무 |
-> imp_detect_patterns : 탐지 패턴 등록 (정규식이나 쿼리에서 영향을 받을 수 있기 때문에 Base64로 인코딩하여 등록)
Culumn Name | Culumn Type | Value | Description |
imp_idx | int | 4 | Primary |
imp_datetime | datetime | ||
imp_det_pattern_original | varchar | 300 | 정규 표현식 또는 문자열 |
imp_det_pattern_base64 | varchar | 500 | 패턴 base64 인코딩 |
imp_det_call_analyzer_script | varchar | 50 | 분석 스크립트의 MD5 |
imp_det_tag | varchar | 10 | 탐지 태그 (ex #Eval-Code) |
imp_enable | boolean | 기능 사용 유/무 |
-> mon_uris : 악성링크 데이터
Culumn Name | Culumn Type | Value | Description |
mon_idx | int | 4 | Primary |
mon_datetime | datetime | ||
mon_uri | varchar | 1000 | 악성링크 주소 |
mon_uri_grade | varchar | 10 | 악성링크 주소의 위험도 |
mon_uri_tag | varchar | 10 | 탐지 태그 (ex #Suspicious) |
mon_enable | boolean | 기능 사용 유/무 |
-> logic_analyzer : 탐지 패턴에 따른 분석 스크립트 분류
Culumn Name | Culumn Type | Value | Description |
logic_idx | int | 4 | Primary |
logic_datetime | datetime | ||
logic_analyzer_script | varchar | 100 | 스크립트 이름 |
logic_analyzer_script_MD5 | varchar | 50 | 패턴 탐지와 연결됨 |
logic_enable | boolean | 기능 사용 유/무 |
-> logic_unraveler : 웹 탐지 패턴에 따른 분석 스크립트 분류
Culumn Name | Culumn Type | Value | Description |
logic_idx | int | 4 | Primary |
logic_datetime | datetime | ||
logic_unraveler_script | varchar | 100 | 스크립트 이름 |
logic_unraveler_script_MD5 | varchar | 50 | 웹 패턴 탐지와 연결됨 |
logic_enable | boolean | 기능 사용 유/무 |
-> rec_connection : 접속 기록 (domain, uri, ip address, Hash 등등..)
Culumn Name | Culumn Type | Value | Description |
rec_idx | int | 4 | Primary |
rec_datetime | datetime | 접속 날짜, 시간 | |
rec_domain | varchar | 1000 | 접속한 링크의 도메인 |
rec_dom_String_MD5 | varchar | 100 | 가능한 많은 해쉬를 보관하는게 좋다 |
rec_dom_File_MD5 | varchar | 100 | |
rec_dom_String_SHA128 | varchar | 200 | |
rec_dom_File_SHA128 | varchar | 200 | |
rec_dom_String_SHA256 | varchar | 300 | |
rec_dom_File_SHA256 | varchar | 300 | |
rec_dom_File_Size | varchar | 10 | |
rec_dom_File_type | varchar | 50 | |
rec_dom_http_request_code | varchat | 10 | 응답 코드 |
-> rec_sub_connection : 하위 링크 접속 기록 (파일 사이즈, http 리턴 코드 등...)
Culumn Name | Culumn Type | Value | Description |
rec_idx | int | 4 | Primary |
rec_datetime | datetime | 접속 날짜, 시간 | |
rec_uri | varchar | 1000 | 접속한 링크의 URI |
rec_uri_String_MD5 | varchar | 100 | 가능한 많은 해쉬를 보관하는게 좋다 |
rec_uri_File_MD5 | varchar | 100 | |
rec_uri_String_SHA128 | varchar | 200 | |
rec_uri_File_SHA128 | varchar | 200 | |
rec_uri_String_SHA256 | varchar | 300 | |
rec_uri_File_SHA256 | varchar | 300 | |
rec_uri_File_Size | varchar | 10 | |
rec_uri_File_type | varchar | 50 | |
rec_uri_http_request_code | varchat | 10 | 응답 코드 |
-> rec_connection_raw_files
Culumn Name | Culumn Type | Value | Description |
rec_idx | int | 4 | Primary |
rec_datetime | datetime | 접속 날짜, 시간 | |
rec_domain | varchar | 1000 | 접속한 링크의 도메인 |
rec_dom_File_MD5 | varchar | 100 | rec_connection과 연결된다 |
rec_dom_File_SHA128 | varchar | 200 | |
rec_dom_File_SHA256 | varchar | 300 | |
rec_raw_file_path | varchat | 200 | 웹페이지 다운로드 로컬 경로 |
rec_raw_file_path (ex randing_pages/2024-03-20/dogdrip.net/20240320_001423_dogdrip.net_ipaddress_md5hash.rand.txt
-> rec_sub_connection_raw_files
Culumn Name | Culumn Type | Value | Description |
rec_idx | int | 4 | Primary |
rec_datetime | datetime | 접속 날짜, 시간 | |
rec_uri | varchar | 1000 | 접속한 링크의 URI |
rec_uri_File_MD5 | varchar | 100 | rec_sub_connection과 연결된다 |
rec_uri_File_SHA128 | varchar | 200 | |
rec_uri_File_SHA256 | varchar | 300 | |
rec_raw_file_path | varchat | 200 | 웹페이지 다운로드 로컬 경로 |
rec_raw_file_path (ex sub_pages/2024-03-20/dogdrip.net/20240320_001423_dogdrip.net_ipaddress_md5hash.sub.txt
-> rec_parsing_domains : 파싱한 주소의 도메인 기록
Culumn Name | Culumn Type | Value | Description |
rec_idx | int | 4 | Primary |
rec_datetime | datetime | 접속 날짜, 시간 | |
rec_parsing_domain | varchar | 1000 | 접속한 링크의 domain |
rec_fw_with_original_domain | varchar | 50 | rec_connection의 도메인 해시 |
rec_fw_with_paring_uri | varchar | 50 | rec_parsing_uris의 uri String 해시 |
-> rec_parsing_uris : 파싱한 주소의 전체 주소 기록
Culumn Name | Culumn Type | Value | Description |
rec_idx | int | 4 | Primary |
rec_datetime | datetime | 접속 날짜, 시간 | |
rec_parsing_uri | varchar | 1000 | 접속한 도메인에서 파싱 한 주소 |
rec_fw_with_origin_domain | varchar | 50 | rec_connection의 도메인 해시 |
rec_fw_with_parsing_domain | varchar | 50 | rec_parsing_domains의 도메인 해시 |
-> rec_detected_uris : 패턴 탐지가 된 uri 기록
Culumn Name | Culumn Type | Value | Description |
rec_idx | int | 4 | Primary |
rec_datetime | datetime | 접속 날짜, 시간 | |
rec_detect_uri | varchar | 1000 | mon_uris에 쿼리 전송 후 확인 |
rec_uri_grade | varchar | 50 | mon_uris에서 정보 가져오기 |
rec_uri_tag | varchar | 50 | mon_uris에서 정보 가져오기 |
-> rec_detected_pattern_result : 악성 패턴 탐지 결과
Culumn Name | Culumn Type | Value | Description |
rec_idx | int | 4 | Primary |
rec_datetime | datetime | 접속 날짜, 시간 | |
rec_detected_pattern | varchar | 1000 | imp_detect_patterns에 쿼리 전송 후 확인 |
rec_uri_tag | varchar | 50 | imp_detect_patterns에서 정보 가져오기 |
-> rec_analyzed_result : 악성 패턴 분석 결과
Culumn Name | Culumn Type | Value | Description |
rec_idx | int | 4 | Primary |
rec_datetime | datetime | 접속 날짜, 시간 | |
rec_analyzed_result | varchar | 1000 | 분석 스크립트의 결론 입력 |
rec_uri_tag | varchar | 50 | 해당 파일의 별칭 (ex #CK_VIP_EK) |
접두사는 각 imp(import), mon(monitor), logic(script logic), rec(record)라는 별칭을 지어주었다.
우리는 아직 웹에서 어떤식으로 유포되는지는 모르고 기존에 알고있는 몇몇 방식들이 있지만 해당 방식들은 이미 오래전에 사장된 내용일 수 있다.
단순 시그니처 등록으로 재밌는 웹 페이지를 찾을 수 있다면 과연 어떤 시그니처가 있을까 고민해보니, 디페이스 공격이 떠올랐다 'hacked by'라던가 'defaced'라는 단어로 찾아보면 되지않을...까... 했지만 defaced나 hacked by같은 시그니처는 보안 뉴스사이트에 한번씩 올라오게되니 이것은 알아서 거르든 화이트리스트로 만들든 .... 해야겠다
다음 편에서는 본격적으로 스크립트의 골격을 만들어보자