lookup

Splunk의 공식 문서를 참고하여 작성되었습니다.

lookup Docs external lookup Docs

  1. lookup 정의
  2. lookup 유형
  3. lookup 실습
  4. Step1: Splunk App 생성
  5. Step2: App 권한 설정
  6. Step3: Python Script 생성
  7. Step4: transforms 생성
  8. Step5: 조회
  9. Step6: Dashboard 생성

lookup 정의

Splunk에서 외부 데이터를 가져와 검색 결과에 추가 정보를 제공하거나 변환하는 기능

lookup 유형

  • CSV lookup : CSV 파일에서 데이터를 가져옴
  • External lookup : 외부 시스템이나 데이터 소스에서 데이터를 가져옴
  • KV Store lookup : Key-Value 스토어를 사용하여 동적 데이터를 검색하고 기존 데이터와 통합
  • Geospatlal lookup : 지리적 위치 정보를 기반으로하는 lookup 기능으로, 지도 시각화 및 지리 정보에 대한 분석에 활용

lookup 실습

Python Script를 사용하여 데이터를 수집하고, external lookup 기능을 활용하여 Splunk 형식으로 변환한 후 사용자에게 정보를 제공하는 Splunk 애플리케이션을 개발

External lookup을 사용하면 웹 사이트, 데이터베이스, API 등에서 데이터를 가져올 수 있습니다. Script를 통해 데이터를 가져오면 실시간으로 사용자에게 최신 정보를 제공할 수 있습니다.

  • 버전 : Splunk 8.2.7
  • 유형 : External lookup
  • 언어 : Python
  • 환경 : Windows
  • 내용 : NVD API를 활용하여 CVE 데이터를 수집하고, 이를 Splunk 사용자에게 제공

Step1: Splunk App 생성

  • Splunk에서 앱을 생성하기 위해 Splunk 인터페이스에서 “앱”을 선택
  • “앱 만들기”를 클릭하여 앱을 생성

Step2: App 권한 설정

  • Python Script를 실행하기 위해 해당 앱에 대한 권한을 설정
  • 모든 사용자 읽기, 쓰기 권한 부여

Step3: Python Script 생성

  • NVD API 공식 문서를 참고하였습니다.
  • NVD API Docs
  • 경로 : {Splunk 설치 경로}/Splunk/etc/apps/nvd_api/bin/
  • 파일 : nvd.py 생성
  • field : cve, published, descriptions, baseScore, weaknesses

import Statements

import csv
import sys
import json
import requests

main 함수

def main():
    # Splunk field 값은 총 5개로 지정 : cve, published, descriptions, baseScore, weaknesses
    # 명령어를 포함하여 field 값이 6개가 아닐 경우 예외처리
    if len(sys.argv) != 6:
        print("Usage: python external_lookup.py [cve field] [published field] [descriptions field] [baseScore field] [weaknesses field]")
        sys.exit(1)

    # 해당 field값에 사용자로부터 입력받은 field값 저장
    cvefield = sys.argv[1]
    publishedfield = sys.argv[2]
    descriptionsfield = sys.argv[3]
    baseScorefield = sys.argv[4]
    weaknessesfield = sys.argv[5]

    # STDIN 입력 스트림을 사용하여 검색 결과로부터 입력 데이터를 읽고,
    # STDOUT 출력 스트림을 사용하여 조회 데이터를 검색 파이프라인에 반환
    infile = sys.stdin
    outfile = sys.stdout

    # 입력 및 출력 데이터를 CSV 테이블로 변환, 
    # 이때 field 이름이 테이블 헤더로 사용.
    r = csv.DictReader(infile)
    header = r.fieldnames
    w = csv.DictWriter(outfile, fieldnames=header)
    w.writeheader()

    # cvefield 값을 기반으로 데이터를 조회하고,
    # 조회된 데이터를 각 field 값에 저장
    for result in r:
        if result[cvefield]: 
            search = lookup(result[cvefield])
            result[publishedfield] = data_nvd[0]
            result[descriptionsfield] = data_nvd[1]
            result[baseScorefield] = data_nvd[2]
            result[weaknessesfield] = data_nvd[3]
            w.writerow(result)
            
data_nvd = ["None"] * 4
main()

nvd api 함수

def lookup(cve):
    try:
        # 사용자로부터 입력받은 CVE를 바탕으로 NVD API 요청
        nvd_url = "https://services.nvd.nist.gov/rest/json/cves/2.0"
        api_key = "your_api_key" # NVD API key

        search_url = nvd_url + "?cveId=" + cve
        headers = {
            "api_key": api_key
        }
        
        response = requests.get(search_url, headers=headers)
        data_req = response.text

        # NVD data를 json 형식으로 load
        json_data = json.loads(data_req)

        # NVD json data에서 field 값 저장
        published = json_data['vulnerabilities'][0]['cve']['published']
        data_nvd[0] = (published if published else "None")
        
        descriptions = json_data['vulnerabilities'][0]['cve']['descriptions'][0]['value']
        data_nvd[1] = (descriptions if descriptions else "None")

        baseScore = None
        source = json_data['vulnerabilities'][0]['cve']['metrics']['cvssMetricV31'][0]['source']
        if source == 'nvd@nist.gov':
            baseScore = json_data['vulnerabilities'][0]['cve']['metrics']['cvssMetricV31'][0]['cvssData']['baseScore']
            data_nvd[2] = (baseScore if baseScore else "None")
        else:
            data_nvd[2] = ("None")
            
        weaknesses = json_data['vulnerabilities'][0]['cve']['weaknesses'][0]['description'][0]['value']
        data_nvd[3] = (weaknesses if weaknesses else "None")

    except:
        return []

Step4: transforms 생성

  • NVD 데이터를 splunk에 맞게 변환하기 위한 설정 파일
  • 경로 : {Splunk 설치 경로}/Splunk/etc/apps/nvd_api/default/
  • 파일 : transforms.conf 생성
  • 파일 생성 후 Splunk 서버 재시작

transforms.conf

[nvd]
external_cmd = nvd.py cve published descriptions baseScore weaknesses
fields_list = cve published descriptions baseScore weaknesses
python.version = python3

Step5: 조회

  • Splunk nvd cve query
  • 예시 cve : CVE-2023-36553

NVD API를 요청할 때, 입력된 CVE 번호가 소문자로 제공되면 오류가 발생합니다. 따라서 모든 CVE 번호를 대문자로 변환하여 조회해야 합니다.

| makeresults
| eval cve="CVE-2023-36553"
| lookup nvd cve
| fields cve, baseScore, descriptions, published, weaknesses

Step6: Dashboard 생성

  • 해당 앱의 인터페이스에서 “대시보드”를 선택
  • “새 대시보드 만들기”를 클릭하여 생성 후, “클래식 대시보드” 선택

대시보드 편집 (원본)

<form theme="dark">
  <label>CVE 검색 대시보드 / - / NVD API</label>
  <description>SHW0331</description>
  <fieldset submitButton="true" autoRun="false">
    <input type="text" token="cve_token" searchWhenChanged="true">
      <default>CVE-2024-1252</default>
      <label>cve_id</label>
    </input>
  </fieldset>
  <row>
    <panel>
      <title>NVD SEARCH</title>
      <table>
        <search>
          <query>
| makeresults 
| eval cve="$cve_token$" 
| mvexpand cve 
| lookup nvd cve 
| fields cve, baseScore, descriptions, published, weaknesses
          </query>
          <earliest></earliest>
          <latest></latest>
        </search>
        <option name="count">10</option>
        <option name="dataOverlayMode">none</option>
        <option name="drilldown">none</option>
        <option name="refresh.display">progressbar</option>
        <option name="rowNumbers">false</option>
        <option name="wrap">true</option>
      </table>
    </panel>
  </row>
</form>