Skip to content
KitploitKITPLOIT
도구익스플로잇블로그
Log in
제출
도구익스플로잇블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
ubuntils — Ubuntu 시스템의 포렌식 트리아지를 위한 Python CLI/TUI — 아티팩트 수집, 타임라인 상관 분석, Wazuh 통합을 통해 지속성 메커니즘을 탐지하고 치료합니다. | Kitploit
도구/GitHubGitHub/asmitdesai/ubuntils
Defensive ToolsIndicator of Compromise (IOC) ManagementPersistence MechanismsVulnerability AnalysisScripting & AutomationConfiguration AuditingForensicsDigital ForensicsIncident ResponseLog Analysis
GitHub
1472일 전아직 검토되지 않음

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유
asmitdesai/ubuntils

ubuntils

Ubuntu 시스템의 포렌식 트리아지를 위한 Python CLI/TUI — 아티팩트 수집, 타임라인 상관 분석, Wazuh 통합을 통해 지속성 메커니즘을 탐지하고 치료합니다.

저장소 보기

ubuntils

라이브 Ubuntu 시스템을 위한 포렌식 트리아지 — 5초 이내에 자동화된 아티팩트 수집, 지속성 탐지, 그리고 가이드 기반 교정.

CI Python Tests Coverage License Arch Ubuntu Offline analysis Detection rules SIEM


문제점

Linux 시스템이 침해당했다고 의심될 때, 처음 30-40분은 보통 동일한 열 개의 명령을 순서대로 실행하는 데 소비됩니다. 실행 중인 프로세스를 확인하고, 이상한 cron 작업을 찾고, LD_PRELOAD를 grep하고, authorized_keys에서 새 항목을 스캔하고, sudoers를 감사합니다. 각 단계는 수동이고, 컨텍스트 전환이 필요하며, 압박 속에서 오류가 발생하기 쉽습니다. 한 가지 소스를 놓치면 — 예를 들어 /etc/sudoers만이 아니라 /etc/sudoers.d/를, 또는 /etc/cron.d/에 더해 사용자 crontab을 — 불완전한 그림을 갖게 됩니다.

기존 옵션들은 이 문제를 깔끔하게 해결하지 못합니다. lynis는 강화 감사 도구이지 트리아지 도구가 아닙니다 — 깨끗한 시스템에서는 구성 약점을 보고하고, 감염된 시스템에서는 노이즈를 생성합니다. chkrootkit과 rkhunter는 알려진 루트킷 시그니처를 검사하지만 악용된 systemd 타이머나 정상처럼 보이는 cron 항목 같은 새로운 지속성 기법에는 눈이 먼 상태입니다. 일반적인 SIEM 쿼리는 보고 있는 시스템에 존재하지 않을 수 있는 로그 인프라를 필요로 합니다. 그리고 Volatility 같은 포렌식 제품군은 메모리 이미지를 대상으로 하지, 실행 중인 호스트의 라이브 셸을 대상으로 하지 않습니다.

이 격차는 바로 지금 라이브 시스템에서 실행되고, 가장 흔한 지속성 벡터를 커버하며, 여러 로그 소스에 걸친 활동을 타임라인으로 상관시키고, 외부 에이전트나 데이터베이스, 인터넷 연결 없이 정확히 무엇을 봐야 하는지 알려주는 도구의 부재입니다.


ubuntils가 하는 일

ubuntils는 네 개의 순차적 단계로 실행됩니다:

  1. 수집(Collection) — 열한 개의 수집기가 /proc, cron 테이블, systemd 유닛, SSH 키, sudoers 파일, 환경 정의, 패키지 무결성(dpkg --verify), PAM/NSS 구성, 로드된 커널 모듈에서 포렌식 아티팩트를 동시에 수집합니다. 일반적인 시스템에서 약 2.5초가 걸립니다.
  2. 탐지(Detection) — 탐지 엔진이 열여섯 개의 내장 규칙 — 그리고 --rules로 로드된 사용자 정의 규칙 — 을 수집된 아티팩트에 대해 실행하여 약 1초 만에 순위가 매겨지고 신뢰도 점수가 부여된 발견 사항 목록을 생성합니다.
  3. 타임라인(Timeline) — 타임라인 빌더가 syslog, journald, auditd를 병렬로 읽고 이벤트를 시간순으로 상관시켜 약 0.3초를 추가합니다. 그런 다음 각 발견 사항이 타임라인에 대해 자동으로 상관되어, 관련된 주변 이벤트를 함께 포함합니다.
  4. 출력(Output) — 결과는 대화형 4탭 TUI(기본값) 또는 stdout의 구조화된 JSON(--json)으로 나타납니다.

ubuntils 자체는 네트워크 호출을 하지 않으며, 사용자 정의 규칙과 상관 분석을 포함한 모든 기능이 로컬에서 수집된 아티팩트에 대해 실행됩니다. 발견 사항이 호스트를 떠날 수 있는 유일한 방법은 Wazuh 통합입니다: Wazuh 에이전트가 설치되어 있으면 라이브 scan이 발견 사항을 로컬 파일에 기록하고 에이전트가 이를 매니저로 전송합니다. 실행 시 이를 끄려면 --no-wazuh를 전달하세요.

ubuntils scan은 아래의 모든 내용에 의해 변경되지 않습니다 — 여전히 100% 라이브, 단일 호스트이며, 모든 기존 플래그가 동일하게 작동합니다. 두 개의 추가 명령인 collect와 analyze는 동일한 탐지/타임라인 파이프라인을 오프라인 친화적인 수집 후 분석 워크플로로 분할하여, 조사 중인 호스트에서 직접 탐지를 실행할 수 없거나 실행하고 싶지 않은 경우를 위한 것입니다 — 아래의 오프라인 분석: collect와 analyze를 참조하세요. 여기에는 탐지 커버리지 관련 주의 사항이 포함됩니다.


설치

Ubuntu 22.04+ 및 PEP 668을 적용한 모든 시스템(권장):

Ubuntu 22.04+는 시스템 전역 pip install을 차단합니다. pipx를 사용하세요 — 환경을 투명하게 처리하므로 신경 쓸 필요가 없습니다:```bash sudo apt install pipx -y cd ubuntils pipx install -e . ubuntils scan

root@kitploit:~
**구형 시스템 / 수동 설치:**```bash
git clone https://github.com/asmitdesai/ubuntils.git
cd ubuntils
pip install -r requirements.txt -e .
ubuntils scan

ubuntils는 전체 아티팩트에 접근하려면 root 권한이 필요합니다. 비-root 사용자로 ubuntils scan을 실행하면 동일한 Python 인터프리터(절대 경로 기준)를 사용하여 자동으로 sudo로 재실행되므로, PATH를 root 프로세스로 전달하지 않고도 올바른 환경이 사용됩니다. 모든 외부 명령(ss, dpkg, systemctl, …)은 고정된 root 소유의 검색 경로에서 확인되며, 사용자의 PATH는 절대 사용되지 않습니다. root 없이 실행하면 /etc/shadow, 일부 /proc 항목, 보호된 cron 파일을 건너뛰고 각각에 대해 경고를 기록합니다.


빠른 시작

탐지만 — 대화형 TUI:```bash sudo ubuntils scan

root@kitploit:~
**JSON 출력을 파일로 저장한 탐지:**```bash
sudo ubuntils scan --json > /tmp/triage-$(hostname)-$(date +%Y%m%d).json

CLI 복구 미리보기를 통한 탐지 (드라이 런 — 변경 사항 적용되지 않음):```bash sudo ubuntils scan --remediate

root@kitploit:~
**CLI 교정 적용 후 탐지:**```bash
sudo ubuntils scan --remediate --confirm

인쇄 버전:```bash ubuntils version

root@kitploit:~
**나중에 또는 오프라인 분석을 위해 변조 방지 번들을 수집하세요:**```bash
sudo ubuntils collect --output /path/to/bundle.tar.gz

이전에 수집된 번들을 분석합니다(루트 권한 불필요):```bash ubuntils analyze /path/to/bundle.tar.gz --json

root@kitploit:~
**번들 대신 마운트된 포렌식 이미지 또는 추출된 파일시스템 트리를 분석합니다:**```bash
ubuntils analyze --root /mnt/forensic-image --json

오프라인 분석: 수집 및 분석에 대해서는 오프라인 분석: 수집 및 분석을 참조하십시오. 특히 번들 형식과 라이브 scan과 비교하여 오프라인 분석이 감지할 수 없는 항목에 유의하십시오.


플래그 및 구성```

ubuntils scan [OPTIONS] --json Output JSON to stdout instead of launching the TUI --output FILE Write the JSON report to FILE (implies --json) --remediate Run the remediation engine after detection --confirm Required with --remediate to actually apply changes (else dry-run) --min-confidence N Only auto-remediate findings with confidence >= N (default 40) --no-wazuh Never forward findings to a local Wazuh agent --config FILE YAML allowlist of findings to suppress (see below) --baseline FILE YAML baseline of environment-specific known-good fingerprints to suppress (see below) --since TIME Limit the timeline to events since TIME (e.g. '24h', '7d', '2026-05-20') --rules FILE YAML file of custom detection rules to add (see below) --verbose Verbose structlog output

ubuntils collect [OPTIONS] --output FILE Bundle path to write (default ./ubuntils-bundle-.tar.gz) --verbose Verbose structlog output

ubuntils analyze (BUNDLE | --root PATH) [OPTIONS] --root PATH Analyze a mounted image / artifact tree instead of a bundle --json Output JSON instead of launching the TUI --output FILE Write the JSON report to FILE (implies --json) --config FILE YAML allowlist of findings to suppress (same format as scan) --baseline FILE YAML baseline of environment-specific known-good fingerprints to suppress (same format as scan) --rules FILE YAML file of custom detection rules to add (same format as scan) --since TIME Limit the timeline to events since TIME (e.g. '24h', '7d', '2026-05-20') --verbose Verbose structlog output

ubuntils version Print version string and exit

root@kitploit:~
### 오탐 허용 목록 (`--config`)

새로 프로비저닝되었거나 CI로 관리되는 호스트는 예상된 노이즈를 생성합니다 — 배포 키, 프로비저닝 crontab, 내장된 셸 초기화 등입니다. 대응 담당자에게 이를 정신적으로 걸러내도록 가르치는 대신, YAML 허용 목록으로 명시적으로 억제하십시오:```yaml
# allowlist.yaml
allowlist:
  rules:
    - SHELL_RC_MODIFICATION          # suppress this rule entirely
  paths:
    - /home/ci/.ssh/authorized_keys  # suppress any finding on this exact path

주요 기능

  • 다중 소스 수집: GitHub, GitLab, 로컬 디렉터리, ZIP 아카이브, 개별 파일
  • 지능형 분석: 언어 감지, 프레임워크 식별, 의존성 추출
  • 보안 스캐닝: 비밀 정보 탐지, SAST 규칙, 의존성 취약점 검사
  • 유연한 보고: JSON, Markdown, HTML, SARIF 형식
  • CI/CD 통합: GitHub Actions, GitLab CI, Jenkins용 사전 구성된 워크플로우
  • 확장 가능한 아키텍처: 사용자 정의 분석기 및 보고서 생성기 플러그인 지원```bash sudo ubuntils scan --json --config allowlist.yaml
root@kitploit:~
억제는 항상 명시적입니다 — 규칙 ID 및/또는 정확한 아티팩트 경로로 지정합니다. "모든 것을 무시"하는 일괄 스위치는 없습니다. 샘플은 [`examples/allowlist.yaml`](https://github.com/asmitdesai/ubuntils/blob/main/examples/allowlist.yaml)에 있습니다.

### 알려진 정상 기준선 설정 (`--baseline`)

`--config`는 *이 코드베이스에 대해 ubuntils를 실행하는 모든 사람에 대해* 규칙이나 경로를 억제합니다. `--baseline`은 더 좁고 환경별입니다: "이 환경에서는 이 정확한 아티팩트 — 이 SSH 키, 이 RC 파일 — 가 알려진 정상"이라고 말하며, 같은 도구로 스캔하는 다른 모든 호스트에 대해 규칙이나 경로를 음소거하지 않습니다. `--config`와 별도의 파일로 유지되는 이유는 `--rules`가 분리된 것과 같습니다: 억제와 규칙 전체 허용 목록은 하나의 파일에 있어서는 안 되는 서로 다른 관심사입니다.```yaml
# baseline.yaml
baseline:
  - rule_id: SSH_UNAUTHORIZED_KEY
    fingerprint: ci@ci-runner          # substring match against the finding's raw_value
  - rule_id: SHELL_RC_MODIFICATION
    fingerprint: /home/deploy/.bashrc  # exact match against the finding's artifact_path

감사합니다!

이 프로젝트에 기여하고 싶으시다면, 다음을 수행해 주세요:

  1. 이 저장소를 포크합니다.
  2. 기능 브랜치를 생성합니다 (git checkout -b feature/AmazingFeature).
  3. 변경 사항을 커밋합니다 (git commit -m 'Add some AmazingFeature').
  4. 브랜치에 푸시합니다 (git push origin feature/AmazingFeature).
  5. 풀 리퀘스트를 엽니다.

라이선스

이 프로젝트는 MIT 라이선스에 따라 라이선스가 부여됩니다 - 자세한 내용은 LICENSE 파일을 참조하세요.

연락처

프로젝트 링크: https://github.com/yourusername/yourproject

감사의 글

  • 여기에 감사의 글을 작성하세요
  • 또 다른 감사의 글
  • 또 다른 감사의 글

부록

A. 자주 묻는 질문 (FAQ)

Q: 이 도구는 무엇인가요? A: 이 도구는 [여기에 설명을 작성하세요]를 위한 것입니다.

Q: 어떻게 설치하나요? A: 위의 설치 섹션을 참조하세요.

Q: 어떻게 사용하나요? A: 위의 사용법 섹션을 참조하세요.

Q: 라이선스는 무엇인가요? A: MIT 라이선스입니다.

B. 문제 해결

문제: 도구가 실행되지 않습니다. 해결책: Python 버전이 3.8 이상인지 확인하세요.

문제: 종속성 오류가 발생합니다. 해결책: pip install -r requirements.txt를 실행하세요.

문제: 권한이 거부되었습니다. 해결책: chmod +x tool.py를 실행하세요.

C. 변경 로그

버전 1.0.0

  • 최초 릴리스
  • 기본 기능
  • 문서

버전 1.1.0

  • 버그 수정
  • 성능 개선
  • 새로운 기능

버전 1.2.0

  • 추가 기능
  • 문서 업데이트
  • 종속성 업데이트

D. 로드맵

  • 기능 1
  • 기능 2
  • 기능 3
  • 완료된 기능

E. 기여자

  • 기여자 1
  • 기여자 2
  • 기여자 3

F. 크레딧

  • 크레딧 1
  • 크레딧 2
  • 크레딧 3

G. 법적 고지

이 도구는 교육 및 윤리적 해킹 목적으로만 사용해야 합니다. 이 도구의 오용은 전적으로 사용자의 책임입니다. 작성자는 이 도구의 사용으로 인해 발생할 수 있는 어떠한 손해나 피해에 대해서도 책임을 지지 않습니다.

H. 면책 조항

이 도구는 "있는 그대로" 제공되며, 명시적이든 묵시적이든 어떠한 종류의 보증도 없이 제공됩니다. 작성자는 이 도구의 사용으로 인해 발생할 수 있는 어떠한 손해나 피해에 대해서도 책임을 지지 않습니다.

I. 감사의 말

이 도구를 가능하게 해주신 모든 분들께 감사드립니다.

J. 연락처

질문이나 제안 사항이 있으시면 [email protected]으로 연락해 주세요.


즐거운 해킹 되세요!```bash sudo ubuntils scan --json --baseline baseline.yaml

root@kitploit:~
기준선 항목은 `rule_id`와 `fingerprint`로 일치하며, `fingerprint`는 발견 항목의 `raw_value`에 대한 부분 문자열로 검사되거나 `artifact_path`에 대한 정확한 일치로 검사됩니다. 일치하는 항목은 보고서에서 발견 항목을 완전히 제거합니다. 하지만 억제가 결코 조용히 이루어지지는 않습니다. 기준선이 제거한 발견 항목의 수는 항상 `scan_metadata.suppressed_by_baseline`에 표시됩니다. 허용 목록(`--config`) 억제는 기준선 억제 위에 여전히 적용됩니다. `scan`과 `analyze`에서 동일하게 작동합니다. 예시는 [`examples/baseline.yaml`](https://github.com/asmitdesai/ubuntils/blob/main/examples/baseline.yaml)에 있습니다.

### 사용자 정의 탐지 규칙 (`--rules`)

`--config`는 발견 항목을 *억제*하고, `--rules`는 발견 항목을 *추가*합니다. 이 둘은 서로 반대되는 관심사이기 때문에 의도적으로 별도의 파일로 분리되어 있습니다.

규칙 파일은 패턴 일치만 수행합니다. 표현식도, 조건문도, 코드 실행도 없으므로, 규칙 파일을 로드한다고 해서 공격자가 제공한 로직이 실행될 수는 없습니다. 각 규칙은 아티팩트 `source`, `match` 모드, 그리고 `pattern`을 지정합니다:```yaml
# custom_rules.yaml
rules:
  - id: CUSTOM_KNOWN_MINER
    severity: HIGH                     # HIGH | MEDIUM | LOW
    title: Known cryptominer in process cmdline
    description: A running process command line matches a known miner.
    source: process                    # cron | environment | ssh | process | network
    match: substring                   # regex | substring | glob
    pattern: xmrig

4.3.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.```bash

sudo ubuntils scan --json --rules custom_rules.yaml

root@kitploit:~
| `source` | 매칭 대상 |
|---|---|
| `cron` | cron 명령 (path: crontab 파일) |
| `environment` | 원시 환경/셸 초기화 라인 (path: 정의 파일) |
| `ssh` | 키 유형, 키 데이터, 주석 (path: `authorized_keys` 파일) |
| `process` | 프로세스 cmdline (path: exe 경로) |
| `network` | 연결 설명 (path: `remote_addr:remote_port`) |

`regex`와 `substring`은 텍스트 열과 매칭되고, `glob`은 경로 열과 매칭됩니다 — 따라서 `203.0.113.*:*`와 같은 `network` glob은 원격 엔드포인트를 대상으로 합니다. 사용자 정의 규칙 탐지 결과는 플래그 전용이며(자동 교정되지 않음) 여전히 `--config` 억제 대상입니다. 샘플은 [`examples/custom_rules.yaml`](https://github.com/asmitdesai/ubuntils/blob/main/examples/custom_rules.yaml)에 있습니다.

### 보고서 무결성

모든 `--json` 보고서에는 `report_sha256` 필드가 포함됩니다 — 이는 정규 보고서 내용에 대한 SHA-256입니다. 이로써 수집된 트리아지 아티팩트가 변조 방지되고, 사건 파일에서 다이제스트로 특정 스캔을 참조할 수 있습니다. 보고서는 또한 `scan_metadata` 아래에 `tool_version`, `hostname`, UTC `generated_at` 타임스탬프를 기록합니다. `scan`의 경우 `hostname`/`ubuntu_version`은 `ubuntils`가 실행 중인 머신을 설명하고, `analyze --root`의 경우 이미지 자체의 `/etc/hostname`과 `/etc/os-release`에서 읽습니다. `analyze BUNDLE`의 경우에는 대신 번들 자체의 매니페스트에서 가져옵니다 — `analyze`를 실행하는 호스트가 아니라 *수집된* 호스트를 나타내며, `collection_run_id`와 수집의 `collected_at_utc_start`/`collected_at_utc_end`도 함께 제공되므로 보고서의 증거 보관 기록이 분석가의 워크스테이션이 아닌 증거를 따릅니다.

**보고서 검증.** 보고서는 정규 형식(키 정렬, 2칸 들여쓰기)으로 출력되며, 다이제스트는 `report_sha256` 자체를 제외한 모든 내용을 포함합니다:```python
import hashlib, json
doc = json.load(open("report.json"))
claimed = doc.pop("report_sha256")
assert hashlib.sha256(json.dumps(doc, indent=2, sort_keys=True).encode()).hexdigest() == claimed

오프라인 분석: 수집 및 분석

ubuntils scan은 라이브 호스트에 대해 수집, 탐지, 타임라인을 함께 실행합니다. collect와 analyze는 그 파이프라인을 둘로 나눕니다. collect는 호스트로부터 변조 방지 번들을 획득하고(탐지는 실행하지 않음), analyze는 scan에서 사용하는 것과 동일한 탐지/타임라인 파이프라인을 번들에 대해, 또는 --root를 통해 마운트된 이미지에 대해 실행하며, root 권한이 필요 없고 원본 호스트를 다시 건드리지도 않습니다. 이는 아티팩트를 한 번 획득한 뒤 나중에, 다른 곳에서, 또는 반복적으로 분석하려는 경우 — 또는 실행 중인 시스템이 아닌 디스크 이미지를 트리아지하는 경우를 위한 것입니다.

`ubuntils collect````bash

sudo ubuntils collect --output /path/to/bundle.tar.gz

root@kitploit:~
root 권한이 필요하며, `scan`과 유사합니다. 고정된 파일 목록(`/etc/passwd`, `/etc/group`, `/etc/shadow`, `/etc/sudoers`, `/etc/ld.so.preload`, `/etc/environment`, `/etc/crontab`, `/etc/profile`, `/var/log/syslog`, `/var/log/messages`, `/var/log/audit/audit.log`)을 읽고 고정된 명령 목록(`ss -tunap`, `netstat -tunap`, JSON 및 텍스트 형식의 `systemctl list-timers`, 그리고 지난 7일간의 `journalctl -o json`)을 실행하여, 캡처된 각 항목을 해시하고 모든 내용과 `manifest.json`을 `.tar.gz` 번들에 기록합니다. 캡처된 로그 파일과 journalctl 출력은 `analyze BUNDLE`이 오프라인에서 실제 타임라인을 구축할 수 있게 해줍니다. `--output`을 생략하면 번들은 현재 디렉터리의 `./ubuntils-bundle-<UTC timestamp>.tar.gz`에 기록됩니다.

### `ubuntils analyze````bash
ubuntils analyze BUNDLE.tar.gz [--json] [--output FILE] [--config FILE] [--baseline FILE] [--rules FILE] [--since TIME]
ubuntils analyze --root /mnt/forensic-image [--json] [--output FILE] [--config FILE] [--baseline FILE] [--rules FILE] [--since TIME]

위치 인수로 번들 경로를 받거나, 마운트된 이미지 / 추출된 파일시스템 트리를 가리키는 --root PATH를 받는다 — 둘 다는 아니다. scan에서 사용하는 것과 동일한 탐지 엔진, 사용자 정의 규칙, 허용 목록, 베이스라인 로직을 실행한다. root 권한이 필요하지 않다. 번들은 분석이 끝나는 즉시 삭제되는 비공개 임시 디렉터리로 추출된다 (/etc/shadow를 포함할 수 있다).

두 오프라인 모드 간에는 커버리지가 다르다. 번들은 collect 시점의 재생된 캡처 상태를 담고 있는 반면, --root는 마운트된 파일시스템에 있는 것만 가지고 있기 때문이다:

  • **analyze BUNDLE**은 collect 시점에 캡처된 실제 ss/systemctl list-timers/journalctl 명령 출력을 재생하므로, NetworkCollector와 SystemdCollector가 해당 스냅샷으로부터 진짜 탐지 결과를 생성한다 — 건너뛰지 않는다. 타임라인은 번들이 캡처한 syslog/messages/audit.log/journalctl로부터 구축되므로 완전히 채워지고, 탐지 결과는 실제 related_events 상관관계를 얻게 된다.
  • **analyze --root PATH**는 쿼리할 라이브 프로세스나 커널 상태가 없는 죽은 마운트 이미지를 가리키므로, 명령 실행이 완전히 비활성화된다: NetworkCollector와 SystemdCollector는 건너뛰어지고 scan_metadata.command_collectors_skipped에 기록된다. 타임라인은 여전히 구축되지만, 이미지에 존재하는 정적 로그 파일(/var/log/syslog, , )로부터 구축된다 — 죽은 이미지를 쿼리할 라이브 이 없으므로 여기서는 journald 재생을 사용할 수 없다.

오프라인 탐지 커버리지 격차의 전체 목록은 오프라인 분석: collect와 analyze를 참조하라.

번들 형식

번들은 모든 것이 bundle/ 접두사 아래에 있는 gzip 압축 tarball이다:``` bundle/ ├── manifest.json ├── files/ │ ├── etc/passwd │ ├── etc/shadow │ ├── var/log/syslog │ └── ... # every captured file, path-flattened under files/ └── commands/ ├── ss.txt ├── netstat.txt ├── systemctl_list_timers_json.txt ├── systemctl_list_timers_text.txt └── journalctl.txt

root@kitploit:~
`manifest.json` 스키마:

| 필드 | 타입 | 설명 |
|---|---|---|
| `run_id` | string | 각 `collect` 실행마다 새로 생성되는 UUID |
| `host_id` | string | 향후 다중 호스트 상관 분석을 위해 예약됨; 현재는 비어 있음 |
| `hostname` | string | 수집 시점의 `socket.gethostname()` |
| `ubuntu_version` | string | 감지된 Ubuntu 릴리스 문자열 |
| `collected_at_utc_start` / `collected_at_utc_end` | string (ISO 8601) | 수집 실행의 실시간 경계 |
| `tool_version` | string | 번들을 생성한 ubuntils 버전 |
| `files[]` | array | 캡처된 파일당 하나의 항목: `source_path`, `bundle_path`, `sha256`, `size`, `mtime`, `ctime` (소스 호스트에서 파일이 없거나 읽을 수 없는 경우 수집을 중단하는 대신 `sha256: ""`, `size: -1`로 기록됨) |
| `commands[]` | array | 캡처된 명령당 하나의 항목: `name`, `argv`, `bundle_path`, `sha256`, `exit_code` |
| `bundle_sha256` | string | 매니페스트의 나머지 부분(위의 모든 항목, 정규 직렬화됨)에 대한 SHA-256 — 전체 번들에 대한 변조 증거 앵커 |

### JSON 출력의 번들 무결성

`analyze`의 `scan_metadata.bundle_integrity`는 세 가지 값 중 하나를 보고합니다:

- `"live"` — `scan`과 `analyze --root`가 이 값을 보고합니다; 검증할 번들이 없습니다.
- `"ok"` — `analyze BUNDLE`이 매니페스트에 대해 `bundle_sha256`을, 그리고 캡처된 각 파일의 SHA-256을 번들 내용에 대해 검증했습니다; `collect`가 기록한 이후 아무것도 변경되지 않았습니다.
- `"mismatch"` — 매니페스트 다이제스트, 캡처된 파일의 해시, 또는 캡처된 명령 출력의 해시가 일치하지 않았습니다. 번들 내 무언가가 수집 후에 수정, 잘림, 또는 손상되었으며, 그로부터 파생된 어떤 것도 증거 보존 체인(chain-of-custody)이 깨끗한 것으로 신뢰해서는 안 됩니다. `analyze`는 여전히 보고서를 생성하지만, stderr에 빨간색 경고를 출력하고, TUI Summary 탭 상단에 무결성 배너를 표시하며, **상태 3으로 종료**하므로 스크립트가 변조된 번들의 결과를 권위 있는 것으로 오인할 수 없습니다.

### ⚠️ 오프라인 분석에는 실제 탐지 공백이 있습니다 — 의존하기 전에 읽어보세요

**번들 또는 `--root` 소스의 `analyze` 실행은 라이브 `scan`과 탐지 동등성을 가지지 않습니다.** 이는 예외적인 경우가 아니라 정적 오프라인 수집의 구조적 한계이며, 영향을 받는 규칙에 대해 오류 대신 더 적은(또는 0개의) 발견을 생성합니다. 수집기가 *볼 수 없었다는 것을 아는* 경우(실패한 명령, 읽을 수 없는 파일)에는 `scan_metadata.collectors_degraded`에 기록되고 TUI Summary 탭에 플래그가 표시됩니다 — 하지만 단순히 캡처되지 않은 파일은 존재하지 않는 파일과 동일하게 보입니다. (타임라인 자체는 더 이상 이러한 공백 중 하나가 *아닙니다*: `analyze BUNDLE`은 `collect` 시점의 캡처된 syslog/messages/audit.log/journalctl을 재생하고, `analyze --root`는 마운트된 이미지에 존재하는 정적 로그 파일을 읽으므로, 둘 다 실제 타임라인과 실제 `related_events` 상관 관계를 생성합니다 — 위의 [`ubuntils analyze`](#ubuntils-analyze)를 참조하세요.)

- **`PROCESS_MASQUERADE`와 `PROCESS_SUSPICIOUS_CONNECTION`은 오프라인 모드에서 항상 0개의 발견을 보고합니다.** 두 규칙 모두 프로세스의 `exe` 필드를 기반으로 하는데, 이는 아티팩트 소스를 통해 `/proc/<pid>/exe` 심볼릭 링크 대상을 읽어 채워집니다(분석가 자신의 `/proc`이 아님). 번들에는 읽을 라이브 `/proc`이 없고, `--root`는 `/proc`이 없는 마운트된 파일시스템 트리를 가리킵니다 — 현재 오프라인에서 해석된 exe 심볼릭 링크 대상을 캡처하거나 재구성할 메커니즘이 없으므로, `exe`는 항상 비어 있고 호스트에 실제로 무엇이 있든 관계없이 두 규칙 모두 절대 발동하지 않습니다.
- **오프라인에서는 프로세스 열거가 전혀 발생하지 않습니다.** `collect`에는 PID별 캡처 단계(`/proc/*/status`, `/proc/*/cmdline`)가 없으므로, 애초에 번들에 분석할 프로세스가 존재하지 않습니다 — 이는 위의 요점과 동일한 근본 원인을 수집 측면에서 본 것입니다.
- **`CRON_TMP_PATH`, `SUDOERS_NOPASSWD`, `SSH_UNAUTHORIZED_KEY`는 번들 소스 분석에서 제한되거나 누락됩니다.** `collect`의 파일 목록은 정적이며 `/etc/cron.d/*`, `/etc/sudoers.d/*`, `/etc/profile.d/*`, 또는 사용자별 `~/.ssh/authorized_keys`를 글로브 확장할 수 없습니다 — `/etc/crontab`, `/etc/sudoers`, `/etc/environment`/`/etc/profile`만 캡처됩니다. (전체 마운트된 파일시스템 트리에 대한 `--root`는 실제 디렉터리가 디스크에 존재하므로 이 공백이 없습니다.) `SSH_UNAUTHORIZED_KEY` 또는 `SHELL_RC_MODIFICATION`이 *실제로* 발동할 때(라이브 스캔, 또는 실제 사용자별 디렉터리가 존재하는 `--root`), 이제 mtime만이 아니라 ctime과 파일 내용으로부터도 신뢰도를 점수화합니다 — 아래의 [신뢰도 점수화](#json-output)를 참조하세요. 이는 발동하는 발견을 얼마나 신뢰해야 하는지를 개선하지만, 오프라인에서 규칙이 발동하는지 여부 자체를 바꾸지는 않습니다.
- **`SUSPICIOUS_SYSTEMD_TIMER` 탐지는 번들에 대해 약화됩니다.** 서비스 유닛은 유닛 디렉터리(`/etc/systemd/system`, `/usr/lib/systemd/system`, 사용자별 `~/.config/systemd/user`, …)에서 직접 읽히므로, `--root`는 전체 서비스 커버리지를 얻습니다. 그러나 번들은 이러한 디렉터리를 캡처하지 않습니다: 타이머는 캡처된 `systemctl list-timers` 출력에서 나타나지만, 각 타이머의 `ExecStart`는 `collect`가 수행하지 않는 유닛별 `systemctl show` 호출에서 오므로, 규칙은 번들된 타이머가 무엇을 실행하는지 평가할 수 없습니다.

**중요한 경우:** 라이브 상태이고 접근 가능한 호스트를 트리아지하는 경우 `sudo ubuntils scan`을 사용하세요 — 전체 탐지 커버리지를 갖추고 있습니다. 한 번 수집하고 다른 곳에서 분석해야 하거나, root 없이 분석해야 하거나, `scan`이 전혀 옵션이 아닌 디스크 이미지에서 작업하는 경우 `collect`/`analyze`를 사용하세요 — 그리고 위 규칙에 대한 깨끗한 `analyze` 결과를 "검사되지 않음"으로 취급하고 "검사되었고 깨끗함"으로 취급하지 마세요.

---

## TUI

`sudo ubuntils scan`을 실행하면(`--json` 없이) 전체 터미널 대화형 TUI가 시작됩니다.

### 스캔 화면

수집기가 실행되는 동안 ubuntils는 라이브 체크리스트를 표시합니다 — 수집기당 한 행. 각 행은 수집기가 완료됨에 따라 실시간으로 업데이트됩니다:```
Scanning system…

  ✓  Process
  ✓  Network
  ✓  Users
  ⠹  Cron
     Systemd
     SSH
     Sudoers
     Environment

✓는 성공, ✗는 실패를 표시하며, 스피너는 활성 수집기를 나타내고 빈 행은 대기 중입니다. 모든 수집기가 완료되고 탐지 + 타임라인이 완료되면 TUI가 자동으로 결과 화면으로 전환됩니다.

결과 화면

결과 화면에는 숫자 키로 탐색할 수 있는 네 개의 탭이 있습니다:

q 또는 Ctrl+C를 눌러 종료합니다.

요약 탭 (키 1)

스캔 메타데이터와 주요 발견 사항을 한 화면에 표시합니다:``` Collectors: 8 run · 0 failed Findings: 2 HIGH · 1 MEDIUM · 0 LOW Timeline: 47 events Duration: 2.8s

● HIGH CRON_TMP_PATH /etc/cron.d/cleanup ● HIGH LD_PRELOAD_INJECT /home/alice/.bashrc ○ MED SSH_UNAUTHORIZED_KEY /home/bob/.ssh/authorized_keys

root@kitploit:~
깨끗한 시스템에서는 이 탭에 `System appears clean.`이 표시됩니다.

### Findings 탭 (키 `2`)

모든 findings를 HIGH → MEDIUM → LOW 순으로 정렬한 스크롤 가능한 목록입니다. finding을 선택하면(Enter 또는 화살표 키) 하단에 상세 창이 펼쳐져 전체 설명, 아티팩트 경로, 원시 트리거 값, 그리고 해결 정보를 보여줍니다.```
HIGH  CRON_TMP_PATH           /etc/cron.d/cleanup
HIGH  LD_PRELOAD_INJECT       /home/alice/.bashrc
MED   SSH_UNAUTHORIZED_KEY    /home/bob/.ssh/authorized_keys
───────────────────────────────────────────────────────
A cron job was found referencing /tmp, /var/tmp, or /dev/shm.
These directories are world-writable and commonly used as
attacker staging grounds.

Artifact:  /etc/cron.d/cleanup
Raw:       0 * * * * root /tmp/.update
Fix:       Will remove the offending cron entry from
           /etc/cron.d/cleanup after creating a timestamped backup.

R: remediate

TUI 내 수정

자동 수정이 가능한 발견 사항의 경우, 해당 발견 사항이 선택된 상태에서 R을 누릅니다. 확인 모달이 나타납니다:``` ┌─────────────────────────────────────────────────┐ │ Remediate CRON_TMP_PATH? │ │ │ │ Will remove the offending cron entry from │ │ /etc/cron.d/cleanup after creating a backup. │ │ Backup will be created at /var/backups/ubuntils/…│ │ │ │ Y: confirm Esc: cancel │ └─────────────────────────────────────────────────┘

root@kitploit:~
`Y`를 눌러 확인합니다. remediator는 백그라운드 스레드에서 실행됩니다. 완료되면 목록의 finding 행이 `[fixed]`로 업데이트되고 세부 정보 창에 결과가 표시됩니다:```
✓ Remediated
Backup:    /var/backups/ubuntils/20260115_142201/etc_cron.d_cleanup
Rollback:  cp /var/backups/ubuntils/20260115_142201/etc_cron.d_cleanup /etc/cron.d/cleanup

실패하면 상세 창에 오류가 표시됩니다. 백업은 변경을 시도하기 전에 항상 생성됩니다.

Esc를 눌러 상세 창을 접습니다.

타임라인 탭 (키 3)

상관관계가 분석된 로그 이벤트의 스크롤 가능한 시간순 목록입니다. 각 행에는 타임스탬프, 소스, 설명이 표시됩니다. 이벤트는 syslog, journald, auditd에서 수집되며 중복이 제거됩니다.

통계 탭 (키 4)

스캔의 요약 보기: 감지된 Ubuntu 버전, 아키텍처, 스캔 소요 시간, 수집기 수와 실패 수, 그리고 심각도별 발견 건수와 총 타임라인 이벤트 수입니다.


탐지 항목

각 규칙이 존재하는 이유

CRON_ROOT_EXEC — 사용자 crontab은 crontab 소유자로 실행됩니다. sudo나 root 소유 인터프리터를 호출하는 항목은 사용자가 지속적인 sudo 접근 권한 없이도 정기적으로 root 권한으로 코드를 실행하도록 설정했음을 의미합니다. 이는 비밀번호 변경 후에도 유지됩니다.

발견 예시:``` [HIGH] CRON_ROOT_EXEC Title: User crontab executing with sudo Artifact: /var/spool/cron/crontabs/alice Raw value: */5 * * * * sudo /usr/bin/python3 /tmp/beacon.py Remediation: available

root@kitploit:~
**CRON_TMP_PATH** — /tmp 및 /dev/shm과 같이 전 세계적으로 쓰기 가능한 디렉터리는 공격자가 흔히 사용하는 준비 거점입니다. 해당 위치를 가리키는 cron 작업은 영구 경로를 전혀 건드리지 않고도 호출 사이에 페이로드를 교체할 수 있음을 의미합니다. 이는 `@reboot`/`@daily` 스타일 항목과 `/etc/cron.{hourly,daily,weekly,monthly}` 내의 스크립트를 포함하며, 해당 스크립트에서 발견된 사항은 플래그 전용입니다. 셸 스크립트에서 한 줄을 삭제하는 것은 안전한 자동 수정이 아니기 때문입니다.

*예시 발견 사항:*```
[HIGH] CRON_TMP_PATH
Title:         Cron job references writable temp directory
Artifact:      /etc/cron.d/cleanup
Raw value:     0 * * * * root /tmp/.update
Remediation:   available

LD_PRELOAD_INJECT — LD_PRELOAD는 동적 링커가 지정된 공유 라이브러리를 다른 모든 라이브러리보다 먼저 로드하도록 하여, 동적으로 링크된 모든 바이너리에서 임의의 함수를 가로챌 수 있게 한다. 표준 라이브러리 경로를 벗어난 값을 가리키는 것은 거의 확실한 사용자 공간 루트킷 지표이며, 공백 또는 콜론으로 구분된 목록의 모든 라이브러리가 검사된다. /etc/ld.so.preload는 모든 프로세스에 주입되며 기본 Ubuntu에서는 비어 있으므로, 그 안에 있는 모든 항목은 보고된다 — 흔한 루트킷 수법인 /lib 내부에 심어진 항목조차도 마찬가지다. 교정은 /etc/ld.so.preload 항목을 주석 처리하는 대신 제거하는데, 이는 로더가 해당 파일에서 주석 문법을 지원하지 않기 때문이다.

예시 탐지 결과:``` [HIGH] LD_PRELOAD_INJECT Title: LD_PRELOAD set to non-standard library path Artifact: /home/alice/.bashrc Raw value: export LD_PRELOAD=/tmp/.libssl.so Remediation: available

root@kitploit:~
**SUSPICIOUS_SYSTEMD_TIMER** — Systemd 타이머는 대부분의 대응자에게 cron 작업보다 더 지속적이고 덜 눈에 띕니다. ExecStart가 임시 디렉터리를 참조하거나 root가 소유하지 않은 바이너리를 실행하는 타이머 — 또는 더 흔한 지속성 수단이며 타이머가 전혀 필요 없는 일반 `.service` 유닛 — 는 공격자가 생성한 지속성의 징후입니다. 서비스 유닛은 사용자별 `~/.config/systemd/user`를 포함한 유닛 디렉터리에서 직접 읽습니다. 플래그 전용 — systemd 유닛 제거에는 사람의 판단이 필요합니다.

*예시 발견 사항:*```
[HIGH] SUSPICIOUS_SYSTEMD_TIMER
Title:         Systemd timer ExecStart points to suspicious path
Artifact:      /etc/systemd/system/update-check.timer
Raw value:     ExecStart=/tmp/.sys/update
Remediation:   not available

SSH_UNAUTHORIZED_KEY — 새로 추가된 SSH 키는 비밀번호와 무관하게 지속적인 원격 접근을 허용합니다. 7일 윈도우는 최근 추가된 항목을 포착하면서도 오래된 시스템의 초기 프로비저닝으로 인한 노이즈를 피합니다. 참고: 이 규칙은 파일 mtime을 사용하며, 이는 각 개별 키의 삽입 타임스탬프가 아니라 authorized_keys 파일에 대한 마지막 쓰기 시각을 반영합니다.

예시 발견 사항:``` [MEDIUM] SSH_UNAUTHORIZED_KEY Title: SSH authorized key added in last 7 days Artifact: /home/bob/.ssh/authorized_keys Raw value: ssh-rsa AAAAB3NzaC1... attacker@evil Remediation: available

root@kitploit:~
**SUDOERS_NOPASSWD** — 사람 사용자 계정(로그인 셸이 있는 UID ≥ 1000)에 대한 비밀번호 없는 sudo는 다른 지속성 메커니즘이 제거된 후에도 살아남는 권한 상승 벡터입니다. 정당한 NOPASSWD 부여는 거의 항상 로그인 셸이 없는 서비스 계정에 대한 것입니다. 그룹 규칙(`%sudo ALL=(ALL) NOPASSWD:ALL`)은 구성원으로 해석되며, `#include`/`@includedir` 파일도 따라갑니다. 그룹 발견 사항은 플래그 전용입니다: `%sudo`와 같은 규칙을 삭제하면 시스템의 모든 sudo 부여가 제거될 수 있습니다.

*예시 발견 사항:*```
[MEDIUM] SUDOERS_NOPASSWD
Title:         NOPASSWD sudo grant for regular user
Artifact:      /etc/sudoers.d/alice
Raw value:     alice ALL=(ALL) NOPASSWD: ALL
Remediation:   available

PROCESS_MASQUERADE — 악성 바이너리에 알려진 시스템 프로세스(sshd, python3, bash)의 이름을 붙이는 것은 ps 출력에서 탐지를 회피하기 위한 기본적인 기법입니다. 이 규칙은 /proc/<pid>/status의 프로세스 이름을 /proc/<pid>/exe에서 확인된 실행 파일 경로와 교차 검증합니다. 표준 위치에는 /usr/local/{bin,sbin}, /usr/lib, /usr/libexec, /snap이 포함되므로 systemd(/usr/lib/systemd/systemd)와 snap 패키지는 이 규칙에 걸리지 않습니다. 플래그 전용 — 프로세스를 종료하려면 사람의 판단이 필요합니다.

예시 탐지 결과:``` [MEDIUM] PROCESS_MASQUERADE Title: Process masquerading as system binary Artifact: /proc/1337/exe Raw value: name=sshd, exe=/tmp/.sshd Remediation: not available

root@kitploit:~
**USER_UID_ZERO** — `root`만이 UID 0을 가져야 합니다. UID 0으로 매핑된 두 번째 계정(CIS Ubuntu Benchmark 6.2.x)은 신뢰도 높은 백도어입니다. 이는 root 자체의 자격 증명을 변경하지 않고도 완전한 슈퍼유저 권한을 부여하며, root 비밀번호 재설정 후에도 유지됩니다. 오탐률이 거의 0에 가깝습니다. 플래그 전용 — UID-0 계정 제거에는 사람의 판단이 필요합니다.

*예시 발견 사항:*```
[HIGH] USER_UID_ZERO
Title:         Non-root account with UID 0
Artifact:      /etc/passwd
Raw value:     toor:x:0:0:...:/bin/bash
Remediation:   not available

USER_EMPTY_PASSWORD — /etc/shadow의 비밀번호 필드가 비어 있는 계정은 비밀번호가 전혀 없으며, Ubuntu의 기본 PAM 스택(pam_unix ... nullok)은 비밀번호 없이 로그인할 수 있게 해줍니다. 로그인 셸이 있는 계정에서는 이는 활짝 열린 문과 같습니다. 플래그만 표시 — 조사하는 동안 passwd -l로 잠그십시오.

예시 발견 사항:``` [HIGH] USER_EMPTY_PASSWORD Title: Login account with no password Artifact: /etc/shadow Raw value: eve:: Remediation: not available

root@kitploit:~
**PROCESS_SUSPICIOUS_CONNECTION** — 지속성은 그림의 절반에 불과합니다. 아무것도 통신하지 않는 발판은 당신이 신경 쓸 대상인 경우가 드뭅니다. 이 규칙은 PID를 기준으로 프로세스 수집기와 네트워크 수집기를 결합하여, 플래그된 프로세스가 현재 연결과 함께 나타나도록 합니다. `/tmp`에 배치된 실행 파일이 설정된 아웃바운드 소켓을 보유하고 있으면 HIGH이고, 합법적인 바이너리가 비표준 원격 포트에 연결하면 MEDIUM이며 살펴볼 가치가 있습니다. 이는 현재 상태의 스냅샷이며 지속적인 모니터링이 아닙니다. 스캔 시점에 잠들어 있는 비컨은 나타나지 않습니다. 플래그 전용입니다.

*예시 발견 사항:*```
[HIGH] PROCESS_SUSPICIOUS_CONNECTION
Title:         Process with suspicious outbound connection
Artifact:      /proc/1337/exe
Raw value:     203.0.113.9:4444
Remediation:   not available

SHELL_RC_MODIFICATION — 셸 초기화 파일은 사용자가 로그인할 때마다 실행되므로 신뢰할 수 있는 지속성 벡터입니다. 이 규칙은 최근 수정 사항을 사람이 검토할 수 있도록 표시합니다. 플래그 전용 — 셸 RC 내용은 조치를 취하기 전에 읽어야 합니다.

예시 발견 사항:``` [LOW] SHELL_RC_MODIFICATION Title: Shell init file recently modified Artifact: /root/.bashrc Raw value: mtime=2024-01-15 14:22:01 (6 hours ago) Remediation: not available

root@kitploit:~
**PACKAGE_TAMPERED** — 시스템 소유 바이너리와 구성 파일은 신뢰의 기반입니다. 이 규칙은 `dpkg --verify`를 사용하여 패키지 소유 파일이 수정되거나 삭제되었거나 내용/모드/크기 불일치가 있는 경우를 탐지합니다. Conffile 전용 편집(예상되는 로컬 구성 변경)은 노이즈를 피하기 위해 보고에서 제외됩니다. 플래그 전용 — 변조는 합법적(사용자 지정 로컬 편집)이거나 악의적(파일 교체)일 수 있으며, 판단에는 사람의 판단이 필요합니다.

*예시 발견:*```
[HIGH] PACKAGE_TAMPERED
Title:         Package-owned file modified since installation
Artifact:      /usr/bin/sshd
Raw value:     ....5..T. (content and mtime differ)
Remediation:   not available

IMMUTABLE_FLAG_SET — 공격자는 종종 파일에 immutable 플래그(i)나 append-only 플래그(a)를 설정하여 root를 포함한 누구도 수정하거나 삭제하지 못하게 하며, 이는 추가 편집이나 로그 로테이션으로부터 변조를 숨기는 데에도 사용됩니다. /etc/passwd, /etc/sudoers, /etc/pam.d/*, 또는 auth/syslog/wtmp/btmp 로그 파일과 같은 민감한 시스템 파일에 이러한 플래그를 설정하는 것은 공격자의 강화(hardening)를 나타내는 강력한 지표입니다. 이 규칙은 해당 고정된 민감 경로 목록에 대해 lsattr를 통해 immutable 및 append-only 플래그를 탐지합니다. 플래그 전용 — 플래그 변경은 사람의 검토가 필요합니다.

예시 발견 사항:``` [MEDIUM] IMMUTABLE_FLAG_SET Title: Sensitive file has an unexpected chattr flag Artifact: /etc/ld.so.preload Raw value: ----i--------e--- Remediation: not available

root@kitploit:~
**PAM_BACKDOOR** — PAM(Pluggable Authentication Modules)과 NSS(Name Service Switch)는 Linux의 핵심 인증 및 신원 확인 시스템입니다. 이 규칙은 mtime 기반의 "이 파일이 수정되었는가" 탐지를 수행하지 **않습니다** — 대신 파일 *내용*을 패턴 매칭합니다: (1) 임의의 /etc/pam.d/* 파일에 있는 리터럴 `pam_permit.so` 줄(이 모듈은 항상 성공하며 전형적인 인증 우회 백도어입니다), 또는 (2) /etc/nsswitch.conf에 나열된 NSS 모듈 중 ubuntils의 내장 허용 목록에 없는 것. **참고:** NSS 검사는 내장 허용 목록 외의 모듈을 사용하는 도메인 가입/SSSD/LDAP/Winbind 호스트에서 오탐이 발생합니다 — 이러한 이유로 pam_permit.so 매칭보다 의도적으로 낮은 신뢰도로 점수가 매겨집니다; 환경에 맞게 인식되지 않는 모듈 이름을 허용 목록에 추가하려면 `--config`를 사용하십시오. 플래그 전용 — 인증 구성 변경은 신중한 검증이 필요합니다.

*예시 발견 사항:*```
[HIGH] PAM_BACKDOOR
Title:         PAM config unconditionally permits authentication
Artifact:      /etc/pam.d/sshd
Raw value:     auth required pam_permit.so
Remediation:   not available
root@kitploit:~
[HIGH] PAM_BACKDOOR
Title:         Unexpected NSS module in nsswitch.conf
Artifact:      /etc/nsswitch.conf
Raw value:     passwd: files evilmod
Remediation:   not available

KERNEL_MODULE_SUSPICIOUS — 커널 모듈은 링 0에서 무제한 접근 권한으로 실행됩니다. 공격자는 루트킷, 패킷 스니핑, 프로세스 은닉을 위해 사용자 정의 커널 모듈을 자주 로드합니다. 이 규칙은 현재 로드된 모듈을 대부분의 시스템에 공통적인 예상 내장 모듈의 작은 허용 목록과 비교합니다. 허용 목록이 의도적으로 좁기 때문에 심각도는 LOW입니다. 참고: GPU 드라이버, Wi-Fi 카드 또는 독점 드라이버가 있는 하드웨어 중심 호스트에서는 오탐이 발생합니다. 대응 담당자는 --config를 통해 호스트의 예상 모듈을 추가하고 모듈 이름(artifact_path로 사용됨)으로 허용 목록에 등록해야 합니다. 플래그 전용 — 커널 모듈 조사에는 포렌식 도구와 인간 전문 지식이 필요합니다.

예시 발견 사항:``` [LOW] KERNEL_MODULE_SUSPICIOUS Title: Loaded kernel module not in the expected set Artifact: implant_rootkit Raw value: {'name': 'implant_rootkit', 'size': '12288', 'used_by': []} Remediation: not available

root@kitploit:~
**SETUID_INVENTORY** — setuid 및 setgid 바이너리는 실행될 때 자동으로 권한을 상승시킵니다. 공격자는 권한 상승을 지속하기 위해 사용자 정의 setuid/setgid 바이너리를 생성하며, 대부분 표준 시스템 바이너리 디렉터리 외부(예: /opt와 같은 일반적인 설치 경로, 사용자 자신의 /home, /srv, 또는 전 세계 쓰기 가능한 임시 디렉터리)에 배치합니다. 이 규칙은 `find -perm -4000 -o -perm -2000`을 통해 `/usr /bin /sbin /opt /home /srv /tmp /var/tmp /dev/shm` 전반에서 setuid/setgid 바이너리를 목록화하고, 알려진 정상 시스템 유틸리티 기준 집합 외부에 있는 모든 항목을 플래그합니다. 플래그 전용 — 예상치 못한 setuid/setgid 바이너리는 조사가 필요하지만, 애플리케이션이 설치한 정상 바이너리일 수도 있습니다.

*예시 발견 사항:*```
[LOW] SETUID_INVENTORY
Title:         Unexpected setuid binary
Artifact:      /tmp/.hidden/backdoor
Raw value:     setuid
Remediation:   not available

JSON 출력

--json은 stdout에 단일 JSON 객체를 출력합니다. 그 외에는 아무것도 출력되지 않습니다.```json { "scan_metadata": { "tool_version": "2.1.0", "hostname": "web-01", "generated_at": "2026-06-10T08:22:03.114523+00:00", "ubuntu_version": "Ubuntu 22.04.3 LTS", "architecture": "x86_64", "duration_s": 2.84, "collector_failures": 0, "bundle_integrity": "live", "command_collectors_skipped": [], "collectors_degraded": {}, "rules_failed": [], "timeline_error": null, "suppressed_by_baseline": 1 }, "artifact_counts": { "ProcessCollector": 142, "NetworkCollector": 23, "UserCollector": 4, "CronCollector": 7, "SystemdCollector": 12, "SSHCollector": 3, "SudoersCollector": 5, "EnvironmentCollector": 18 }, "findings": [ { "rule_id": "CRON_TMP_PATH", "severity": "HIGH", "title": "Cron job references writable temp directory", "description": "A cron job was found referencing /tmp, /var/tmp, or /dev/shm. These directories are world-writable and commonly used as attacker staging grounds.", "artifact_path": "/etc/cron.d/cleanup", "raw_value": "0 * * * * root /tmp/.update", "remediation_available": true, "remediation_description": "Will remove the offending cron entry from /etc/cron.d/cleanup after creating a timestamped backup.", "related_events": [ { "timestamp": "2024-01-15T08:20:00+00:00", "source": "syslog", "description": "CRON[2841]: (root) CMD (/tmp/.update)" } ], "confidence": 75, "confidence_band": "HIGH", "signals": [ {"name": "timeline_corroboration", "weight": 25, "detail": "1 nearby timeline event(s)"} ] }, { "rule_id": "PROCESS_MASQUERADE", "severity": "MEDIUM", "title": "Process masquerading as system binary", "description": "Process 'sshd' (pid=1337) has exe path outside standard binary directories: /tmp/.sshd", "artifact_path": "/proc/1337/exe", "raw_value": "/tmp/.sshd", "remediation_available": false, "guided_remediation": "Confirm pid 1337 is malicious (ls -l /proc/1337/exe, cat /proc/1337/cmdline), then terminate it: kill -9 1337.", "confidence": 50, "confidence_band": "MEDIUM", "signals": [] } ], "timeline": [ { "timestamp": "2024-01-15T08:22:01+00:00", "source": "syslog", "description": "sshd: Accepted publickey for alice from 10.0.0.42 port 52341" } ], "report_sha256": "a3f1c9…(64 hex chars)" }

root@kitploit:~
`remediation_results`는 `--remediate`가 전달된 경우에만 추가 최상위 키로 나타납니다. `report_sha256`은 항상 존재하며 문서의 나머지 부분에 대해 계산됩니다. `scan_metadata.bundle_integrity`는 `scan` 및 `analyze --root`의 경우 `"live"`, `analyze`에 전달된 검증된 번들의 경우 `"ok"`, 번들의 내용이 매니페스트와 일치하지 않는 경우 `"mismatch"`입니다 — [JSON 출력의 번들 무결성](#bundle-integrity-in-json-output)을 참조하세요. `scan_metadata.command_collectors_skipped`는 `--root` 실행에서 건너뛴 명령 기반 수집기(`NetworkCollector`, `SystemdCollector`, `PackageCollector`, `KernelCollector`)의 이름을 나열합니다 — `scan` 및 `analyze BUNDLE`에서는 항상 비어 있습니다. `scan_metadata.suppressed_by_baseline`은 `--baseline` 파일이 이 보고서에서 제거한 발견 항목의 수입니다 — [알려진 양호 기준선 설정](#known-good-baselining---baseline)을 참조하세요. `scan_metadata.collectors_degraded`는 수집기 이름을 데이터가 불완전한 이유(실패하거나 시간 초과된 명령, 읽을 수 없는 파일, 건너뛴 잘못된 형식의 줄)에 매핑하고, `rules_failed`는 충돌한 탐지 규칙을 나열하며, `timeline_error`는 타임라인을 구축할 수 없는 경우 설정됩니다. 정상 실행에서는 세 가지 모두 비어 있습니다. 빈 발견 항목 목록을 "깨끗함"으로 읽기 전에 이들을 확인하세요.

`related_events`와 `guided_remediation`은 내용이 있을 때만 발견 항목에 나타납니다. `related_events`는 아티팩트 경로와 규칙 키워드로 발견 항목에 매칭된 최대 5개의 타임라인 이벤트를 최신순으로 담고 있습니다 — 인과 관계 주장이 아닌 표면화 보조 수단입니다. `guided_remediation`은 직접 실행할 검토된 명령 시퀀스이며, ubuntils는 절대 이를 실행하지 않습니다.

### 신뢰도 점수

모든 발견 항목은 `confidence` 점수(0–100, 기본값 50)와 `confidence_band`(`HIGH` ≥ 75, `MEDIUM` ≥ 40, 그 미만은 `LOW`)를 가지며, 해당 점수가 어떻게 산출되었는지 정확히 보여주는 `signals` 목록이 함께 제공됩니다 — 각 항목은 `{"name", "weight", "detail"}`이므로 점수는 항상 설명 가능하며 결코 블랙박스가 아닙니다. 시그널은 기본 신뢰도 50 위에 가산되며, 이를 생성한 규칙이나 파이프라인 단계에서 적용됩니다:

- 탐지 규칙은 발견 시점에 자체 시그널을 적용합니다 — 예를 들어 `SSH_UNAUTHORIZED_KEY`와 `SHELL_RC_MODIFICATION`은 아티팩트의 내용이 알려진 위험 패턴(위험한 SSH 키 옵션, 셸 RC 파일의 curl/wget-to-shell 또는 base64-decode 줄)과 일치할 때 `content_match`(+30)를 추가하고, 파일의 ctime도 탐지 윈도우 내에 있을 때(단독 mtime보다 위조하기 어려움) `ctime_corroborates_mtime`(+20)을 추가하며, 최신성만이 *유일한* 시그널이고 ctime이 이를 뒷받침하지 않을 때 `mtime_only`(−20)를 추가합니다 — mtime이 소급 조작되었을 수 있다는 단서입니다.
- 파이프라인은 발견 항목↔타임라인 상관 관계 이후, 발견 항목에 하나 이상의 `related_events`가 있을 때 `timeline_corroboration`(+25)을 적용합니다.

`LOW` 밴드 발견 항목은 무시되거나 숨겨지지 않습니다 — 다른 항목과 똑같이 발견 항목 목록과 JSON 출력에 나타납니다 — 하지만 이 밴드는 추가 조사 전에 얼마나 비중을 둘지 알려줍니다. 이는 `SSH_UNAUTHORIZED_KEY`/`SHELL_RC_MODIFICATION`에 대한 기존의 mtime 전용 휴리스틱을 대체합니다. 기존 방식에서는 오래되었지만 정당하게 접근된 파일(예: 매 실행마다 `.bashrc`를 다시 작성하는 구성 관리 도구)이 진짜 새로운 백도어와 동일하게 보였습니다.

**알려진 한계:** 현재 활성화된 것은 콘텐츠 패턴 및 ctime 시그널뿐입니다. 소유권/지문 기반 시그널 — 알 수 없는 SSH 키 지문, 키의 `from=` 제한 옵션, 또는 RC 파일 소유자/모드 불일치(`ownership_anomaly` 시그널) — 은 아직 구현되지 않았습니다. 이는 향후 릴리스에서 추적되는 지연된 커버리지 격차이며, 현재 신뢰도 점수가 고려하는 사항이 아닙니다.

---

## 교정

16개 탐지 규칙 중 5개는 자동 교정을 지원합니다: `CRON_ROOT_EXEC`, `CRON_TMP_PATH`, `LD_PRELOAD_INJECT`, `SSH_UNAUTHORIZED_KEY`, `SUDOERS_NOPASSWD`. 나머지는 플래그 전용이며 절대 자동 교정되지 않습니다. 안전하게 조치하려면 사람이 먼저 살펴봐야 하기 때문입니다.

### 가이드 교정

`SUSPICIOUS_SYSTEMD_TIMER`, `PROCESS_MASQUERADE`, `SHELL_RC_MODIFICATION`은 `guided_remediation` 문자열을 포함합니다: 발견 항목을 확인한 후 실행할 정확한 명령 — `systemctl disable --now <unit>`, `kill -9 <pid>`, 또는 RC 파일 검토 및 되돌리기. TUI 상세 창과 JSON에 표시됩니다. ubuntils는 절대 대신 실행하지 않으며, 이 규칙들은 설계상 `--remediate --confirm` 일괄 처리에서 제외됩니다.

### TUI에서

Findings 탭에서 교정이 있는 발견 항목을 선택한 후 `R`을 누릅니다. 확인 모달이 계획된 작업을 미리 보여줍니다. `Y`를 눌러 적용합니다 — 교정기는 백그라운드 스레드에서 실행되므로 TUI가 응답성을 유지합니다. 완료되면 발견 항목 행이 `[fixed]`로 업데이트되며, 백업 경로와 정확한 롤백 명령이 인라인으로 표시됩니다.

### CLI에서

`--confirm` 없는 `--remediate`는 안전한 드라이 런입니다: 백업이 생성되고 검증이 실행되지만 변경 사항은 적용되지 않습니다. 실제로 변경하려면 두 플래그를 모두 전달하세요. 이 모드에서는 TUI가 시작되기 전에 파이프라인이 실행되며, Summary 탭에 모든 교정 결과가 백업 경로 및 롤백 명령과 함께 나열됩니다.

`--remediate --confirm`은 신뢰도 점수가 최소 40(MEDIUM 밴드)인 발견 항목에만 작용합니다 — 신뢰도가 낮은 mtime 전용 `SSH_UNAUTHORIZED_KEY`는 키가 삭제되는 대신 `SKIPPED`로 보고됩니다. `--min-confidence N`으로 임계값을 조정하세요.```bash
sudo ubuntils scan --remediate          # dry run
sudo ubuntils scan --remediate --confirm # apply changes, then open TUI
sudo ubuntils scan --remediate --confirm --min-confidence 75  # only HIGH-confidence findings

보호 조치

모든 교정은 트리거 방식과 관계없이 동일한 패턴을 따릅니다:

  1. 아티팩트 경로가 심볼릭 링크인지 감지 — 그렇다면 거부 (공격자가 제어하는 심볼릭 링크를 통한 루트 쓰기 방지)
  2. /var/backups/ubuntils/YYYYMMDD_HHMMSS/에 모드 0700으로 타임스탬프가 포함된 백업 생성
  3. 현재 상태 검증 (정확한 줄이 여전히 존재해야 함)
  4. 최소한의 변경 적용 — cron 항목과 키는 줄 단위로 제거; 셸 초기화 파일의 LD_PRELOAD 줄은 주석 처리; /etc/ld.so.preload의 항목은 제거 (로더에는 주석 구문이 없으므로 주석 처리된 항목도 여전히 로드됨). sudoers의 경우, 편집된 내용은 실제 파일을 건드리기 전에 임시 복사본에 대해 visudo -cf로 검사됨
  5. 원자적 쓰기 — 새 내용은 원본 옆의 임시 파일에 기록되고 (동일한 모드와 소유자), fsync된 후 원본 위로 이름이 변경되므로, 쓰기 중 충돌이 발생해도 잘린 /etc/sudoers가 남지 않음
  6. 정확한 줄이 사라졌는지 확인

어떤 단계라도 실패하면 교정은 즉시 중단되고, 시스템은 변경되지 않은 상태로 유지되며, 백업 경로와 롤백 명령과 함께 전체 오류가 보고됩니다. Sudo 접근은 두 가지 방식으로 보호됩니다: %group NOPASSWD 규칙(예: %sudo)은 플래그 전용이며 절대 자동 제거되지 않고, sudoers 교정기는 메인 sudoers 파일에서 마지막 규칙을 제거하는 것을 거부합니다.


Wazuh 통합

ubuntils는 단일 호스트, 특정 시점의 트리아지를 위해 만들어졌습니다 — 이미 뭔가 잘못되었다고 의심될 때 실행하며, 스캔이 끝난 후에도 외부로 통신하거나 계속 감시하지 않습니다. 이는 의도된 것이지만, ubuntils의 발견 사항이 그것을 전달하는 무언가가 없는 한 해당 보고서에만 존재한다는 의미이기도 합니다. 규모에 관계없이 Ubuntu를 운영하는 대부분의 팀은 이미 지속적인 탐지 측면을 담당하는 SIEM을 갖추고 있으므로, ubuntils를 자체적인 장기 실행 모니터링 에이전트로 구축하는 대신, 이미 운영 중일 가능성이 높은 Wazuh에 발견 사항을 전달합니다.

호스트에 Wazuh 에이전트가 존재하는 경우(/var/ossec/bin/wazuh-agentd 또는 /var/ossec/etc/ossec.conf가 존재), ubuntils scan(--no-wazuh로 실행하지 않는 한)은 각 발견 사항을 에이전트가 수집할 수 있도록 /var/log/ubuntils/wazuh-alerts.json에 하나의 JSON 줄로 추가합니다 — 이는 순수한 포워더이며 Wazuh 모듈이 아닙니다: 네트워크 호출도, API 키도 없고, ubuntils가 이미 수행하는 동일한 로컬 아티팩트 쓰기만 있을 뿐입니다 — 물론 에이전트는 해당 줄을 호스트 외부의 매니저로 전송할 것입니다; 그것이 핵심입니다. 플래그 없이 자동 감지되므로(--no-wazuh를 사용하여 실행을 제외할 수 있음), 에이전트가 등록된 호스트 플릿에서 스크립트 또는 예약된 ubuntils scan이 추가 배선 없이 즉시 SIEM에 공급을 시작합니다. 이는 오프라인 ubuntils analyze(번들 또는 --root) 중에는 절대 발생하지 않습니다. 해당 발견 사항은 로컬 Wazuh 에이전트를 실행하는 호스트와 다른 호스트를 설명하기 때문입니다 — 번들의 발견 사항을 분석가 자신의 에이전트로 전달하면 잘못된 머신에 귀속되게 됩니다.

의도는 대응자가 두 번째 도구를 돌보도록 요구하는 대신 ubuntils를 기존 경보/에스컬레이션 파이프라인에 통합하는 것입니다: 아래 예시 규칙이 로드되면, HIGH 심각도의 ubuntils 발견 사항(새 UID-0 계정, LD_PRELOAD 루트킷, PAM 백도어)이 일반 Wazuh 경보로 나타나고, 매니저가 이미 구성한 알림 라우팅을 상속하며, 누군가 확인하는 것을 기억해야 하는 독립형 JSON 파일 대신 동일한 타임라인에서 다른 모든 신호와 함께 위치합니다.

Wazuh가 이러한 발견 사항을 파싱하고 경보하도록 하려면, examples/wazuh/의 예시 규칙을 Wazuh 매니저에 복사하고, examples/wazuh/ossec_localfile_snippet.xml의 <localfile> 블록을 에이전트의 /var/ossec/etc/ossec.conf에 추가하십시오. 사용자 정의 디코더 설치는 필요하지 않습니다: localfile은 log_format json으로 구성되므로, Wazuh의 내장 JSON 디코더가 각 줄을 파싱하고 모든 최상위 JSON 키 k를 data.k에 매핑하며, local_rules.xml이 이를 직접 매칭합니다.

  1. examples/wazuh/local_rules.xml → 매니저의 /var/ossec/etc/rules/
  2. examples/wazuh/ossec_localfile_snippet.xml의 <localfile> 블록 → 에이전트의 /var/ossec/etc/ossec.conf
  3. 둘 다 재시작: systemctl restart wazuh-manager (매니저), systemctl restart wazuh-agent (에이전트 호스트)

이는 예시 템플릿일 뿐이며 시작점으로 제공됩니다 — 실제 Wazuh 매니저에 대해 테스트되지 않았으므로 의존하기 전에 비프로덕션 환경에서 검증해야 합니다.

줄당 JSON 스키마:


수집기

수집기 의존성

PackageCollector는 라이브 호스트에 세 가지 표준 Ubuntu 도구(dpkg, lsattr, find — 모두 기본 Ubuntu 설치에 존재)가 필요합니다. 어떤 명령이든 사용할 수 없는 경우, PackageCollector는 충돌하는 대신 해당 부분에 대해 빈 데이터를 우아하게 생성합니다. 오프라인 분석(analyze BUNDLE)은 collect 시점에 캡처된 명령 출력을 재생하므로, 분석기 호스트에서의 명령 가용성은 필요하지 않습니다.

setuid/setgid find 스캔은 범위를 제한하기 위해 -xdev를 전달합니다 — 별도로 마운트된 파일시스템(/opt 아래의 별도 마운트, NFS로 마운트된 /home 등)으로 내려가지 않습니다. 이는 의도적인 런타임 대 커버리지 트레이드오프입니다: -xdev 없이는 스캔이 네트워크 마운트나 가상 파일시스템을 스캔하다가 멈출 수 있습니다. 환경에서 이러한 경로를 별도 파일시스템에 마운트하는 경우, 스캔되지 않는다는 점을 유의하십시오.

dpkg --verify와 setuid/setgid find 스캔은 넉넉한 비기본 타임아웃(각각 10분과 5분, ubuntils/collectors/packages.py 참조)을 사용합니다. 둘 다 대규모 패키지 데이터베이스나 파일시스템 트리를 가진 실제 호스트에서 라이브러리 기본값인 30초를 훨씬 초과하여 정당하게 실행될 수 있기 때문입니다; ubuntils collect는 이러한 명령을 번들로 캡처할 때 동일한 타임아웃을 사용합니다.


호환성

지원됨
Ubuntu20.04, 22.04, 24.04
아키텍처amd64, arm64
Python3.9+
권한전체 아티팩트 접근을 위해 루트 필요

루트 없이 실행하면 경고와 함께 부분 스캔이 생성됩니다. /etc/shadow, 보호된 crontab 디렉터리, 일부 /proc 항목과 같은 중요한 경로는 건너뜁니다.


로드맵

v1.0.0

  • 8개 수집기 모두
  • 8개 탐지 규칙 모두
  • 타임라인 빌더 (syslog, journald, auditd)
  • 수집기별 ✓/✗가 표시되는 라이브 스캔 진행 화면
  • 대화형 4탭 TUI (Summary / Findings / Timeline / Stats)
  • 확인 모달과 백그라운드 워커를 갖춘 TUI 내 교정
  • JSON 출력 모드
  • 백업, 롤백, 심볼릭 링크 가드를 갖춘 5개 규칙에 대한 CLI 교정
  • Ubuntu 20.04/22.04/24.04 지원
  • 90% 커버리지의 240개 테스트

v1.1.0

  • 규칙 ID 또는 경로별 오탐 허용 목록 (--config)
  • 보고서를 직접 작성하는 --output FILE
  • --since 타임라인 윈도잉
  • 변조 감지 가능한 보고서 (report_sha256, hostname, timestamp)
  • USER_UID_ZERO 탐지 규칙

v1.5.0

  • YAML을 통한 사용자 정의 패턴 매칭 탐지 규칙 (--rules)
  • PROCESS_SUSPICIOUS_CONNECTION — PID별 프로세스↔네트워크 상관
  • 자동 발견 사항↔타임라인 상관 (related_events)
  • 판단이 필요한 세 가지 규칙에 대한 가이드 교정
  • 92% 커버리지의 282개 테스트

VirusTotal 해시 조회와 MISP IOC 내보내기는 이 릴리스에서 제외되었습니다. VirusTotal은 알려진 해시에만 응답합니다 — 이는 rkhunter가 이미 커버하는 사례이며, ubuntils가 목표로 하는 신종 기법 격차와는 반대입니다 — 그리고 두 기능 모두 네트워크 호출을 하지 않는 것이 가치의 근간인 도구에 네트워크 호출을 넣었을 것입니다. ubuntils 자체는 여전히 네트워크 호출을 하지 않습니다 (발견 사항이 로컬 에이전트를 통해 호스트를 떠날 수 있는 유일한 옵트아웃 가능 방식은 Wazuh 통합 참조).

v2.0.0 — 오프라인 collect/analyze 분리

  • ubuntils collect — 라이브 호스트에서 변조 감지 가능한 번들(manifest.json + 해시된 파일/명령)을 획득, 탐지 없음
  • ubuntils analyze (BUNDLE | --root PATH) — 번들 또는 마운트된 이미지에 대해 scan과 동일한 탐지/타임라인 파이프라인을 실행, 루트 불필요
  • scan_metadata에 bundle_integrity (live/ok/mismatch) 표시
  • 오프라인 모드의 탐지 커버리지 격차 문서화 (PROCESS_MASQUERADE, PROCESS_SUSPICIOUS_CONNECTION, cron/sudoers/SSH 글롭 경로 및 systemd 타이머 에 대한 축소된 커버리지)

v2.1.0 — SIEM 전달

  • 라이브 ubuntils scan 발견 사항을 로컬 Wazuh 에이전트로 JSONL로 전달, 자동 감지 (플래그 불필요)
  • 예시 Wazuh 디코더/규칙 및 ossec.conf <localfile> 스니펫 (examples/wazuh/)
  • 전달은 의도적으로 라이브 scan에만 범위 지정 — 오프라인 analyze 중에는 절대 발생하지 않음, 번들 또는 이미지는 에이전트를 실행하는 호스트와 다른 호스트를 설명하기 때문
  • 스캔을 전달에서 제외하는 --no-wazuh

v2.1.0 — 강화 (전체 코드베이스 감사)

  • 보안: sudo 재실행이 더 이상 호출자의 PATH를 전달하지 않고, 명령은 고정된 보안 경로에서 해석됨; sudoers 편집은 파일을 건드리기 전에 visudo로 검사됨; 원자적 교정 쓰기; 심볼릭 링크 안전한 보고서/번들 출력; analyze 후 추출된 번들 삭제
  • 탐지 커버리지: /etc/ld.so.preload 파싱, @reboot/@daily cron 항목 및 /etc/cron.{hourly,daily,weekly,monthly} 스크립트, systemd .service 유닛 및 비루트 소유 ExecStart 바이너리, %group sudoers 규칙 및 #include/@includedir, LD_PRELOAD 목록의 모든 요소
  • 새로운 규칙 (비밀번호 없는 로그인 계정)

v3.0.0 / v4.0.0 (탐색적)

  • 다중 호스트 트리아지를 위한 웹 대시보드
  • macOS 지원

기여

현재 가장 유용한 기여는 새로운 탐지 규칙(detectors/rules.py에 독립 실행형 함수로 추가하고 일치하는 테스트 포함), 아직 커버되지 않은 아티팩트 유형에 대한 추가 수집기, SUSPICIOUS_SYSTEMD_TIMER와 SHELL_RC_MODIFICATION에 대한 교정 모듈(둘 다 현재 설계상 플래그 전용이지만 안전한 자동 교정 경로가 존재할 수 있음), 특정 Ubuntu 구성의 엣지 케이스에 대한 테스트 케이스, 문서 개선입니다.

대규모 기여를 시작하기 전에 중복 작업을 피하기 위해 이슈를 열어주십시오.


라이선스

MIT


작성자

Asmit이 제작 — BTech Computer Science, PES University, Bengaluru. 이 도구는 수동 Ubuntu 트리아지가 잘 범위가 지정된 스크립트로 자동화할 수 있는 것에 비해 얼마나 오래 걸리는지에 대한 좌절에서 나왔습니다.

도구 다운로드
/var/log/messages
/var/log/audit/audit.log
journalctl
키탭내용
1요약스캔 통계 + 주요 발견 사항을 한눈에
2발견 사항인라인 상세 정보와 해결 방법이 포함된 전체 발견 사항 목록
3타임라인시간순으로 상관된 로그 이벤트
4통계Ubuntu 버전, 아키텍처, 소요 시간, 수집기 수
규칙 ID심각도수정 가능검사 내용
CRON_ROOT_EXECHIGH예root 소유 경로에서 명령을 실행하거나 sudo를 인라인으로 사용하는 비-root 사용자 crontab
CRON_TMP_PATHHIGH예*/tmp, /var/tmp, /dev/shm을 참조하는 모든 cron 작업 (@reboot/@daily 항목과 /etc/cron.{hourly,daily,weekly,monthly}의 스크립트 포함). *스크립트 라인은 플래그만 표시
LD_PRELOAD_INJECTHIGH예/etc/ld.so.preload의 모든 항목 (기본 Ubuntu에서는 비어 있음), 또는 /lib, /usr/lib, /lib64, /usr/lib64 외부의 라이브러리를 나열한 모든 셸 초기화 파일의 LD_PRELOAD
SUSPICIOUS_SYSTEMD_TIMERHIGH아니요ExecStart가 전역 쓰기 가능 디렉터리를 참조하거나 root가 소유하지 않은 바이너리를 실행하는 systemd 타이머 및 서비스 유닛
SSH_UNAUTHORIZED_KEYMEDIUM예최근 7일 이내에 수정된 authorized_keys 파일
USER_UID_ZEROHIGH아니요root 외에 UID가 0인 모든 계정 (숨겨진 두 번째 슈퍼유저)
USER_EMPTY_PASSWORDHIGH아니요/etc/shadow 비밀번호 필드가 비어 있는 로그인 셸 계정 (Ubuntu의 기본 PAM nullok은 비밀번호 없이 로그인을 허용함)
SUDOERS_NOPASSWDMEDIUM예*UID ≥ 1000이고 로그인 셸을 가진 사용자에 대한 NOPASSWD sudoers 부여 (직접 또는 %group 규칙을 통해), 포함된 파일도 추적됨. *그룹 규칙은 플래그만 표시 (%sudo를 제거하면 모든 sudo 접근 권한이 제거될 수 있음)
PROCESS_MASQUERADEMEDIUM아니요이름은 알려진 시스템 바이너리와 일치하지만 실행 파일이 표준 시스템 디렉터리 (/usr/bin, /usr/sbin, /bin, /sbin, /usr/local/{bin,sbin}, /usr/lib, /usr/libexec, /lib, /snap) 외부에 있는 프로세스
PROCESS_SUSPICIOUS_CONNECTIONHIGH / MEDIUM아니요실행 파일이 전역 쓰기 가능 임시 디렉터리에 있거나 디스크에서 삭제된 (HIGH) 아웃바운드 연결을 보유한 프로세스, 또는 표준 시스템 디렉터리 외부에 있거나 비표준 원격 포트와 통신하는 (MEDIUM) 프로세스
SHELL_RC_MODIFICATIONLOW아니요로그인 셸을 가진 모든 사용자에 대해 최근 48시간 이내에 수정된 셸 초기화 파일 (bashrc, profile, zshrc 등)
PACKAGE_TAMPEREDHIGH아니요시스템 소유 패키지 파일이 수정되었거나 누락되었거나 내용/모드/크기가 패키지 매니페스트와 일치하지 않음 (dpkg --verify 사용)
IMMUTABLE_FLAG_SETMEDIUM아니요/etc/passwd, /etc/sudoers, /etc/pam.d/*와 같은 민감한 파일에 설정된 immutable (i) 또는 append-only (a) 플래그 (lsattr로 감지)
PAM_BACKDOORHIGH아니요모든 /etc/pam.d/* 파일의 리터럴 pam_permit.so 라인, 또는 허용 목록 (files/sss/ldap/winbind/...) 외부의 /etc/nsswitch.conf NSS 모듈
KERNEL_MODULE_SUSPICIOUSLOW아니요일반적인 내장 모듈 허용 목록 외부의 로드된 커널 모듈 — 참고: 하드웨어가 많은 호스트 (GPU, Wi-Fi 카드, 독점 드라이버)에서는 오탐이 발생할 수 있음; --config를 통해 예상 모듈을 추가하세요
SETUID_INVENTORYLOW아니요알려진 기준 집합 외부의 예상치 못한 setuid 또는 setgid 바이너리 (두 비트는 별도로 검사되고 보고됨)
필드타입설명
timestampstring (ISO 8601)발견 사항이 전달된 시각
hostnamestring스캔된 호스트
rule_idstringubuntils의 탐지 규칙 ID와 일치 (위의 탐지 규칙 표 참조)
severitystringHIGH | MEDIUM | LOW
titlestring사람이 읽을 수 있는 짧은 제목
descriptionstring전체 발견 사항 설명
artifact_pathstring문제가 발견된 파일/리소스 경로
raw_valuestring규칙을 트리거한 원시 줄/값
remediation_availableboolubuntils에 이 규칙에 대한 교정기가 있는지 여부
related_eventsarray (선택 사항)상관된 타임라인 이벤트 (있는 경우)
수집기수집되는 아티팩트
ProcessCollector/proc 및 ps 출력의 실행 중인 프로세스
NetworkCollectorss/netstat의 열린 연결 및 리스너
UserCollector/etc/passwd, /etc/shadow, /etc/group
CronCollector/etc/cron* 디렉터리 및 /var/spool/cron/crontabs/*
SystemdCollectorsystemctl list-timers 및 list-units 출력
SSHCollector모든 사용자의 ~/.ssh/authorized_keys
SudoersCollector/etc/sudoers 및 /etc/sudoers.d/ 아래의 모든 파일
EnvironmentCollector/etc/environment, /etc/profile.d/*, 사용자 셸 초기화 파일
PackageCollectordpkg --verify를 통한 시스템 패키지 무결성, lsattr를 통한 불변 플래그 속성, find를 통한 setuid/setgid 바이너리
PamCollector/etc/pam.d/* 파일 및 /etc/nsswitch.conf
KernelCollectorlsmod를 통한 로드된 커널 모듈
ExecStart
  • 신뢰할 수 있는 탐지: 신뢰도 점수 (confidence/confidence_band/signals), --baseline 억제, SSH_UNAUTHORIZED_KEY/SHELL_RC_MODIFICATION의 mtime 전용 휴리스틱을 ctime + 콘텐츠 신호로 대체, analyze BUNDLE과 analyze --root 모두에 대한 실제 오프라인 타임라인
  • 커버리지 팩: PACKAGE_TAMPERED, IMMUTABLE_FLAG_SET, PAM_BACKDOOR, KERNEL_MODULE_SUSPICIOUS, SETUID_INVENTORY (PackageCollector, PamCollector, KernelCollector를 통해; 모두 설계상 플래그 전용)
  • 93.79% 커버리지의 400개 테스트
  • USER_EMPTY_PASSWORD
  • 오탐 감소: 구분자로 경계가 지정된 경로 검사, setuid와 setgid 구분, snap//usr/lib 데몬을 표준으로 처리, KERNEL_MODULE_SUSPICIOUS를 LOW로 강등, 모듈당 하나의 NSS 발견 사항
  • 정직한 보고서: 실패한 규칙과 성능 저하된 수집기가 scan_metadata와 TUI에 기록됨; 타임라인 실패가 더 이상 발견 사항을 버리지 않음; 변조된 번들은 경고하고 종료 코드 3으로 종료; syslog 연도/시간대가 올바르게 처리됨
  • 더 안전한 교정: --min-confidence 게이트 (기본값 40), scan --remediate 후 TUI에 결과 표시
  • 94.29% 커버리지의 444개 테스트