콘텐츠로 이동

펌웨어 분석 가이드

네트워크 장비 펌웨어 바이너리(.bin, .img, squashfs 등)에서 구성요소를 식별하고 SBOM과 라이선스, 취약점을 점검하는 방법을 설명합니다. 협력사에서 받은 펌웨어처럼 소스 없이 바이너리만 있을 때 씁니다.

동작 방식

펌웨어는 운영체제와 라이브러리 수십 개가 통째로 압축·밀봉된 파일입니다. 그래서 펌웨어 파일을 그대로 일반 스캔에 넣으면 거의 검출하지 못하고 빈 SBOM이 나옵니다. 펌웨어 분석은 먼저 압축을 풀어 내용물을 꺼낸 뒤 구성요소를 식별합니다.

  1. 언팩(unblob, 폴백으로 unsquashfs·7z·binwalk)으로 펌웨어를 풀어 rootfs를 추출합니다.
  2. syft로 패키지 매니저(opkg, dpkg, apk, rpm)가 설치한 구성요소를 식별합니다. 하나의 이미지가 파일시스템을 여럿 담을 수 있고, rootfs 안이 아니라 옆에 놓인 트리도 함께 식별합니다. 세 가지를 알아보며, 판정 근거는 디렉터리 이름이 아니라 그 안에 무엇이 설치돼 있는지를 적은 기록입니다. 첫째는 컨테이너 이미지 저장소로 Docker가 남기는 이미지 색인으로 알아봅니다(스위치 운영체제에서 흔한 구조로, 실제로 동작하는 것 대부분이 컨테이너 안에 있습니다). 둘째는 자체 패키지 데이터베이스를 가진 또 하나의 파일시스템입니다. 셋째는 Python site-packages처럼 인터프리터가 설치한 라이브러리 묶음입니다. rootfs만 읽으려면 FW_EXTRA_ROOTS=false로 둡니다. 컨테이너 저장소에서 나온 구성요소에는 어느 컨테이너 이미지에서 나왔는지가 bomlens:container:image 속성으로 남고, 이미지 자체도 container 구성요소로 들어갑니다. 컨테이너 안에서 dpkg로 설치된 패키지는 그 컨테이너가 어떤 배포판을 쓰는지를 자기 계층의 os-release에서 읽어 식별하며, 그래야 취약점 단계에서 대조할 대상이 생깁니다. 이렇게 식별한 것에는 bomlens:purlSource 속성이 붙습니다. SPDX로 내보내도 이 내용이 남습니다. 이미지와 배포판은 SPDX 패키지가 되고, 소속은 CONTAINS 관계로 들어갑니다.
  3. cve-bin-tool로 stripped 정적 바이너리(busybox, openssl, dropbear 등)의 버전과 취약점을 찾습니다.
  4. 두 결과를 하나의 SBOM으로 병합한 뒤, 일반 스캔과 동일한 후처리(라이선스, CVE, 서명)를 거칩니다.

펌웨어 이미지 준비

펌웨어 분석에는 언팩과 바이너리 식별 도구(unblob, cve-bin-tool 등)가 들어 있는 별도 이미지가 필요합니다. 이 도구들은 GPL 계열이라 경량 기본 이미지에는 넣지 않고, opt-in 펌웨어 이미지로 분리되어 있습니다.

docker pull ghcr.io/sktelecom/bomlens-firmware:latest

기본값이 이 이미지이므로 별도 지정 없이 --firmware만 붙여도 받습니다. 다른 태그를 쓰려면 환경변수 SBOM_FIRMWARE_IMAGE로 지정합니다.

웹 UI와 데스크톱 앱에서는 이 명령을 직접 칠 필요가 없습니다. 펌웨어 입력에 내려받을 용량과 함께 받기 버튼이 나오고, 받는 동안 레이어 몇 개가 끝났는지 보여 줍니다. 받아 두지 않아도 첫 펌웨어 스캔에서 자동으로 받으므로, 차이는 기다리는 시점이 스캔 전인지 스캔 도중인지입니다.

실행하기

펌웨어 분석에는 위의 펌웨어 이미지가 필요합니다. 웹 UI든 CLI든 마찬가지입니다.

웹 UI에서

웹 UI를 평소처럼 띄우면 됩니다. 이 이미지를 따로 지정할 필요는 없습니다. Docker 엔진이 켜져 있으면 기본 UI 이미지가 Docker 소켓을 통해 위 펌웨어 이미지를 곁들임 컨테이너로 직접 띄우므로, 펌웨어 업로드 타일이 자동으로 나타납니다.

./scripts/scan-sbom.sh --ui
#   Windows: sbom-ui.bat을 그대로 더블클릭

다른 태그나 사내 미러 레지스트리를 쓰고 싶을 때만 SBOM_FIRMWARE_IMAGE로 지정하세요. 실제 환경변수를 설정했을 때만 적용되며, .bat 더블클릭이 읽는 설정 파일(bomlens.settings.txt)에는 이 항목이 없습니다.

SBOM_FIRMWARE_IMAGE=<사내 미러>:<태그> ./scripts/scan-sbom.sh --ui

프로젝트 이름과 버전을 입력하고, 펌웨어 업로드 타일을 골라 파일을 올린 뒤 스캔을 실행합니다. 온라인 첫 실행에서 CVE 데이터베이스를 받는 동안에는 UI에 다운로드 진행률 바가 표시됩니다.

CLI에서

받은 펌웨어 파일을 --target에 넘기고 --firmware를 붙입니다.

./scripts/scan-sbom.sh --project device-fw --version 1.0.0 \
  --target "./device.bin" --firmware \
  --all --generate-only
  • 인식 가능한 확장자(.bin, .img, .squashfs, .ubi, .ubifs, .trx, .chk, .fw, .rom)는 --firmware 없이도 자동 감지되지만, 명시를 권장합니다.
  • 산출물은 일반 스캔과 같은 3종입니다. 고지문(_NOTICE), SBOM(_bom.json), 위험분석보고서(_risk-report).

결과 읽는 법

산출물은 다른 스캔과 같은 고지문, SBOM, 위험분석보고서입니다(일반적인 구성은 보고서 읽는 법산출물 레퍼런스 참고). 다만 펌웨어 SBOM을 읽기 전에 알아둘 점이 하나 있습니다. 일부 컴포넌트는 버전이 아예 없습니다. 바이너리의 버전 문자열이 빌드 과정에서 남지 않은 경우에도, BomLens는 그 라이브러리가 링크돼 있다는 사실만은 기록합니다. 문자열 매칭이 아니라 ELF의 SONAME·NEEDED 항목이라는 구조 자체에서 읽은 것이며, 이런 컴포넌트에는 bomlens:evidenceGrade = presence-only 속성이 붙습니다. 버전이 없다고 해서 스캔이 놓친 것이 아니라, 바이너리 자체에 읽을 버전이 없다는 뜻이며 컴포넌트 자체는 실재합니다. 라이선스 의무 판단에는 이것으로 충분하지만(어느 릴리스인지와 무관하게 그 라이브러리는 존재하므로), 버전 기반 CVE 매칭은 이 컴포넌트를 판단할 근거가 없습니다.

syft의 패키지 식별 단계가 실패해도 스캔은 멈추지 않습니다. syft 자체의 오류가 스캔 로그에 남고, SBOM에는 어느 단계가 실패했는지 bomlens:pipeline-step-failed로 기록됩니다(메인 rootfs는 firmware-packages, 압축 해제 중 함께 발견되는 별도 패키지 소스, 예를 들어 내장된 컨테이너 이미지 저장소나 독자적인 패키지 데이터베이스를 가진 파일시스템은 firmware-extra-roots). 예상보다 컴포넌트 수가 적으면 펌웨어에 실제로 그만큼만 있다고 단정하기 전에 스캔 로그에서 이 기록부터 확인하는 편이 좋습니다.

CVE 매칭, 온라인과 오프라인

정적 바이너리의 CVE 매칭은 cve-bin-tool과 그 전용 취약점 데이터베이스로 이뤄집니다. 펌웨어 이미지는 하이브리드 방식이라, 같은 이미지로 에어갭 환경과 온라인 환경에서 모두 동작합니다.

  • 이미지를 빌드할 때 데이터베이스를 번들하면, 펌웨어 스캔이 스캔 시점에 오프라인으로 CVE를 매칭합니다. 빠르고 에어갭에 적합한 경로입니다.
  • 번들 데이터베이스가 없지만 네트워크에 닿을 수 있으면, cve-bin-tool이 실행 중에 NVD에서 데이터베이스를 받습니다. 첫 실행은 느리며, 받는 동안 웹 UI에 다운로드 진행률 바가 표시됩니다.
  • 번들 데이터베이스도 네트워크도 없으면, CVE 단계를 조용히 빼는 대신 사유를 로그로 남기고 구성요소 식별만 하는(CVE 없음) 동작으로 낮춥니다.

CVE_BIN_TOOL_MODE로 동작을 고릅니다. auto(기본값으로, 번들 데이터베이스를 우선하고 없으면 온라인일 때 내려받음), offline, online, components-only입니다.

데이터베이스는 NVD뿐 아니라 여러 출처(NVD, PURL2CPE 등)를 합친 집계 데이터입니다. cve-bin-tool은 "This product uses the NVD API but is not endorsed or certified by the NVD." 고지를 출력합니다.

OSV(Open Source Vulnerabilities) 권고는 재배포 이미지에 share-alike 데이터를 포함하지 않으려고 번들하지 않습니다. 대신 웹 UI에 "Include OSV advisories" opt-in 토글이 있어, 켜면 그 스캔에 한해 osv.dev에서 OSV를 받아옵니다. 데이터가 이미지에 동봉되는 게 아니라 사용자 머신에서 직접 내려받는 방식입니다.

라이선스 주의

펌웨어 이미지에는 GPL 도구(cve-bin-tool, sasquatch, unblob이 의존하는 일부 extractor)가 들어 있습니다. 셸 스크립트는 이 도구들을 별도 프로세스로 호출만 하므로 copyleft가 이 저장소의 코드로 전파되지는 않습니다. 다만 GPL 바이너리를 이미지에 담아 재배포하므로, 라이선스 텍스트 동봉과 소스 오퍼 의무는 그대로 적용됩니다. 상세 인벤토리는 번들 도구 라이선스를 참고하세요. GPL 분석 도구는 이 펌웨어 이미지에만 들어갑니다. 다만 기본 이미지를 포함한 모든 이미지는 Debian 기반이라 GPL 시스템 패키지를 함께 담고 있으며, 그 소스 안내도 같은 문서에 있습니다.

한계

  • 오픈소스 도구 스택의 검출률은 약 60~85%이며, 펌웨어 종류와 strip 정도, 언팩 성공 여부에 크게 좌우됩니다.
  • 함수 수준 바이너리 핑거프린팅이 없어서 strip되거나 인라인된 컴포넌트, 버전 문자열이 제거된 바이너리는 놓칩니다.
  • 정적 링크 라이브러리와 벤더가 변형한 squashfs, 암호화·서명된 펌웨어, 사명을 바꾼 라이브러리는 검출하지 못하거나 부정확합니다.
  • 결과 SBOM은 완전하지 않은 근사 추정이므로, 법적 라이선스 컴플라이언스의 단일 근거로 사용하지 마세요.

관련 문서: 시작하기 | 시나리오 가이드 | CLI 레퍼런스 | 고지문·보안 보고서 가이드