LKRG (Linux Kernel Runtime Guard)
LKRG(Linux Kernel Runtime Guard)는 Openwall 프로젝트에서 개발한 커널 모듈(Kernel Module)로, 런타임에 커널과 프로세스(Process)의 무결성(Integrity)을 검증합니다. 커널 코드/모듈 텍스트 해시(Hash) 검증, 프로세스 자격증명(cred) 변조 탐지, SELinux 우회 탐지, 커널 핵심 객체(IDT/GDT/MSR) 보호를 수행하여 루트킷과 권한 상승 공격을 탐지합니다.
일상 비유: LKRG는 건물의 실시간(Real-time) CCTV 모니터링과 비슷합니다. 건물의 벽(커널 코드), 출입 카드 권한(프로세스 자격증명), 보안 규칙(SELinux 정책)이 누군가에 의해 변조되지 않았는지 주기적으로 확인하고, 이상을 감지하면 즉시 경보를 울립니다.
핵심 요약
| 보호 계층 | 검증 대상 | 탐지 방식 | 대응 옵션 |
|---|---|---|---|
| 코드 무결성 | 커널 텍스트, 모듈 텍스트 | SHA-256 해시 비교 | 로그 / 패닉 |
| 자격증명 감시 | struct cred (uid/gid/cap) | 참조 카운터 + 해시 | 프로세스 종료 |
| SELinux 보호 | selinux_enforcing 플래그 | 값 변조 감시 | 복원 / 패닉 |
| 객체 보호 | IDT, GDT, MSR, syscall table | 주기적 스냅샷 비교 | 로그 / 패닉 |
| 모듈 감시 | 모듈 로드/언로드 이벤트 | notifier + 해시 갱신 | 실시간 업데이트 |
- Openwall 프로젝트에서 개발 및 유지보수 (주 개발자: Adam "pi3" Zabrocki)
- GPLv2 라이선스, DKMS를 통한 간편 설치 지원
- 커널 5.x ~ 6.x 광범위 지원, x86_64 및 ARM64 아키텍처
- 런타임 감지 전용 — 사전 예방이 아닌 사후 탐지(detection, not prevention) 도구
sysctl lkrg.*인터페이스로 모든 동작 파라미터 조정 가능
LKRG 개요
LKRG는 2018년 Openwall(John the Ripper 개발사)이 공개한 오픈소스 커널 모듈입니다. 전통적인 호스트 기반 침입 탐지 시스템(HIDS)이 파일 시스템 수준에서 동작하는 것과 달리, LKRG는 커널 메모리 내부에서 직접 무결성을 검증합니다.
설계 철학
| 원칙 | 설명 |
|---|---|
| Detection over Prevention | 공격을 차단하기보다 변조를 탐지하여 알림. 오탐(false positive) 최소화 |
| Out-of-tree 모듈 | 메인라인 커널 수정 없이 로드 가능. DKMS로 커널 업그레이드 시 자동 빌드 |
| 최소 성능 영향 | 이벤트 기반 + 주기적 검사 혼합으로 CPU 오버헤드(Overhead) 최소화 |
| 계층적 보호 | 코드, 데이터, 자격증명, 보안 정책을 다층적으로 검증 |
LKRG의 역사
- 2018.02 — LKRG 0.0 첫 공개 릴리스
- 2019 — ARM64 지원 추가, credential 검사 강화
- 2020 — SELinux 우회 탐지 기능 추가
- 2021~2022 — 커널 5.x 시리즈 전면 지원, UMH(User Mode Helper) 감시
- 2023~2024 — 커널 6.x 대응, kCFI 호환성, 성능 최적화
LKRG 아키텍처
LKRG는 내부적으로 세 가지 핵심 컴포넌트로 구성됩니다:
- CI (Code Integrity) — 커널과 모듈의 코드(.text) 영역 해시를 관리하는 엔진. 초기화 시 기준 해시를 생성하고, 모듈 로드/언로드 이벤트에 동적으로 대응합니다.
- PCFI (Process Credentials and Flow Integrity) — 프로세스 자격증명(struct cred)의 무결성을 검증하는 엔진. kprobe/kretprobe를 통해 합법적 변경을 추적하고, 비정상적 변경을 탐지합니다.
- SI (System Integrity) — IDT, GDT, MSR, syscall table 등 CPU 특수 구조의 무결성을 검증하는 엔진. per-CPU 단위로 검사를 수행합니다.
/* LKRG 내부 데이터베이스 — 기준값 저장 구조 (단순화) */
struct p_lkrg_global_db {
/* CI: Code Integrity */
char kernel_hash[32]; /* 커널 .text SHA-256 */
struct list_head module_list; /* 모듈별 해시 리스트 */
unsigned int module_count; /* 활성 모듈 수 */
/* SI: System Integrity */
char idt_hash[32]; /* IDT 해시 */
u64 msr_lstar; /* MSR_LSTAR 기준값 */
char syscall_table_hash[32]; /* syscall table 해시 */
/* PCFI: 프로세스 자격증명 */
unsigned int task_count; /* 추적 중인 태스크 수 */
/* SELinux 상태 */
int selinux_enforcing; /* SELinux enforcing 기준값 */
/* 타이머 */
struct timer_list timer; /* 주기적 검사 타이머 */
unsigned long interval; /* 검사 간격 (jiffies) */
};
코드 무결성 검증
LKRG의 핵심 기능은 커널 코드 영역의 무결성을 런타임에 검증하는 것입니다. 커널이 부팅된 후 .text 섹션은 읽기 전용(Read-Only)이어야 하므로, 해시값이 변하면 코드 변조(code patching)가 발생한 것입니다.
커널 텍스트 해시 검증
LKRG는 초기화 시 커널의 _stext부터 _etext까지의 전체 코드 영역에 대해 SHA-256 해시를 계산합니다. 이후 주기적으로 또는 이벤트 트리거 시 해시를 재계산하여 기준값과 비교합니다.
/* LKRG 내부 구조 — 커널 텍스트 해시 검증 (단순화) */
struct p_text_pgs {
unsigned long p_addr; /* 텍스트 시작 주소 */
unsigned long p_size; /* 텍스트 크기 */
char p_hash[32]; /* SHA-256 해시 */
};
/* 해시 계산 흐름 */
static int p_check_integrity(void) {
char current_hash[32];
/* 1. 현재 커널 텍스트의 SHA-256 계산 */
p_hash_from_text(_stext, _etext - _stext, current_hash);
/* 2. 초기화 시 저장한 기준 해시와 비교 */
if (memcmp(current_hash, p_db.kernel_hash, 32) != 0) {
/* 변조 탐지! */
p_print_log(P_LOG_ALERT,
"Kernel .text integrity violation detected!");
return P_LKRG_INTEGRITY_FAIL;
}
return P_LKRG_INTEGRITY_OK;
}
모듈 텍스트 해시 검증
커널에 로드된 각 모듈의 .text 섹션도 개별적으로 해시를 계산합니다. 모듈이 로드/언로드될 때 module_notifier를 통해 해시 데이터베이스를 갱신합니다.
/* 모듈 로드 시 해시 데이터베이스 갱신 */
static int p_module_notifier_callback(
struct notifier_block *nb,
unsigned long action, void *data)
{
struct module *mod = data;
switch (action) {
case MODULE_STATE_LIVE:
/* 모듈이 활성화되면 텍스트 해시 계산 및 저장 */
p_add_module_hash(mod);
break;
case MODULE_STATE_GOING:
/* 모듈이 제거되면 해시 데이터베이스에서 삭제 */
p_del_module_hash(mod);
break;
}
return NOTIFY_OK;
}
해시 알고리즘과 성능
LKRG는 내부적으로 커널 crypto API를 사용하여 SHA-256(또는 빌드 구성에 따라 다른 알고리즘) 해시를 계산합니다. 커널 텍스트 영역의 크기는 일반적으로 10~30MB이며, SHA-256 해시 계산은 최신 CPU에서 수 밀리초 내에 완료됩니다.
| 영역 | 일반적 크기 | 해시 계산 시간 (참고값) |
|---|---|---|
| 커널 .text | 10~30 MB | ~5ms |
| 모듈 .text (개당) | 수 KB~수 MB | < 1ms |
| IDT (전체) | 4 KB | < 0.01ms |
| syscall table | ~3 KB (x86_64) | < 0.01ms |
모듈 텍스트 변조 탐지 사례
실제로 일부 루트킷은 기존 커널 모듈의 코드를 직접 수정하는 방식을 사용합니다. 예를 들어, 네트워크 모듈의 패킷(Packet) 필터링 함수를 NOP으로 패치(Patch)하여 방화벽(Firewall)을 우회하거나, 파일시스템(Filesystem) 모듈을 변조하여 특정 파일을 숨깁니다. LKRG는 각 모듈의 .text 해시를 개별 추적하므로, 어떤 모듈이 변조되었는지까지 식별할 수 있습니다.
프로세스 자격증명 모니터링
권한 상승(privilege escalation) 공격은 일반적으로 프로세스의 struct cred를 직접 변조하여 uid를 0(root)으로 바꾸거나 capabilities를 추가합니다. LKRG는 이러한 비정상적 자격증명 변경을 탐지합니다.
struct cred 보호 메커니즘
LKRG는 각 프로세스(task_struct)에 대해 자격증명의 해시값을 유지합니다. 정상적인 자격증명 변경(예: setuid(), execve())은 커널의 공식 경로를 통해 이루어지며, LKRG는 이 경로에 kprobe/kretprobe 훅을 설치하여 합법적 변경을 추적합니다.
/* struct cred — 프로세스 자격증명 구조체 (include/linux/cred.h) */
struct cred {
atomic_t usage;
kuid_t uid; /* 실제 UID */
kgid_t gid; /* 실제 GID */
kuid_t suid; /* 저장된 set-UID */
kgid_t sgid; /* 저장된 set-GID */
kuid_t euid; /* 유효 UID */
kgid_t egid; /* 유효 GID */
kuid_t fsuid; /* 파일시스템 UID */
kgid_t fsgid; /* 파일시스템 GID */
kernel_cap_t cap_inheritable;
kernel_cap_t cap_permitted;
kernel_cap_t cap_effective;
kernel_cap_t cap_bset;
kernel_cap_t cap_ambient;
/* ... */
};
감시 대상 필드
| 필드 | 공격 시나리오 | LKRG 탐지 방식 |
|---|---|---|
uid / euid | uid를 0으로 직접 변조 (DirtyCOW류) | 해시 비교 + setuid kretprobe |
cap_effective | CAP_SYS_ADMIN 등 추가 | capability 해시 검증 |
securebits | SECBIT_NOROOT 비활성화 | securebits 필드 해시 |
user_ns | 네임스페이스(Namespace) 탈출 | namespace 포인터 검증 |
자격증명 검증: usage 카운터
LKRG는 struct cred의 해시뿐만 아니라 usage 참조 카운터도 감시합니다. 정상적인 참조 카운터 변동은 커널의 공식 함수(get_cred(), put_cred())를 통해 이루어집니다. 비정상적으로 큰 값이나 음수 값은 UAF(Use-After-Free) 공격의 징후일 수 있습니다.
/* cred 참조 카운터 검증 */
static int p_validate_cred_usage(struct cred *cred) {
int usage = atomic_read(&cred->usage);
/* 비정상적 참조 카운터 검사 */
if (usage <= 0 || usage > P_CRED_USAGE_MAX) {
p_print_log(P_LOG_ALERT,
"Suspicious cred usage count: %d", usage);
return P_LKRG_INTEGRITY_FAIL;
}
return P_LKRG_INTEGRITY_OK;
}
namespace 탈출 탐지
컨테이너(Container) 환경에서 공격자가 네임스페이스를 탈출하면 호스트 시스템의 전체 권한을 획득할 수 있습니다. LKRG는 프로세스의 nsproxy 포인터와 user_ns를 추적하여, 공식 경로를 거치지 않은 네임스페이스 변경을 탐지합니다.
SELinux 우회 탐지
공격자가 커널 취약점(Vulnerability)을 이용하여 selinux_enforcing 변수를 0(permissive)으로 변경하면 SELinux의 모든 접근 제어(Access Control)가 무력화됩니다. LKRG는 이 변수의 변조를 감시합니다.
감시 대상
| 변수/구조체(Struct) | 위치 | 공격 시나리오 |
|---|---|---|
selinux_enforcing | security/selinux/ | enforcing → permissive 변조 |
selinux_enabled | security/selinux/ | SELinux 전체 비활성화 |
selinux_state | security/selinux/ | 상태 구조체 변조 |
/* LKRG SELinux 보호 — 개념적 흐름 */
static void p_check_selinux(void) {
int current_enforcing;
/* 현재 selinux_enforcing 값 읽기 */
current_enforcing = p_read_selinux_enforcing();
/* 초기화 시 저장한 기준값과 비교 */
if (current_enforcing != p_db.selinux_enforcing) {
p_print_log(P_LOG_ALERT,
"SELinux enforcing mode was changed! "
"Expected %d, found %d",
p_db.selinux_enforcing, current_enforcing);
/* 정책에 따라 복원 또는 패닉 */
p_trigger_response();
}
}
selinux_enforcing은 글로벌 변수 대신 struct selinux_state 내부로 이동했습니다. LKRG는 커널 버전에 따라 적절한 심볼을 탐색합니다.
SELinux 우회 공격 시나리오
실제 공격에서 SELinux 우회는 다음과 같은 패턴으로 수행됩니다:
- 커널 취약점을 통한 임의 쓰기(arbitrary write) 획득
selinux_enforcing변수의 커널 가상 주소(Virtual Address) 계산 (KASLR 우회 필요)- 해당 주소에 0 값을 기록하여 permissive 모드로 전환
- SELinux 정책에 의해 차단되던 작업 수행 (파일 접근, 프로세스 실행 등)
LKRG는 이 시나리오의 3단계에서 변조를 탐지합니다. 다만, LKRG의 검사 주기 사이에 변조가 일어나면 탐지가 지연(Latency)될 수 있으므로 lkrg.interval을 짧게 설정하는 것이 중요합니다.
AppArmor 환경
Ubuntu 등 AppArmor를 사용하는 환경에서는 SELinux 관련 검사가 적용되지 않습니다. LKRG는 SELinux가 활성화된 시스템에서만 해당 보호를 수행하며, AppArmor의 상태 변조 감시는 별도로 구현되어 있지 않습니다.
커널 객체 보호
루트킷은 커널의 핵심 데이터 구조를 변조하여 동작합니다. LKRG는 다음 객체들의 무결성을 주기적으로 검증합니다.
보호 대상 객체
| 객체 | 설명 | 변조 시 영향 |
|---|---|---|
| IDT | 인터럽트(Interrupt) 디스크립터 테이블 | 인터럽트 핸들러(Handler) 하이재킹 |
| GDT | 글로벌 디스크립터 테이블 | 세그먼트 보호 우회 |
| MSR | 모델 특정 레지스터 (LSTAR 등) | 시스템 콜(System Call) 진입점(Entry Point) 변조 |
| syscall table | sys_call_table[] | 시스템 콜 후킹 |
| IDTE count | IDT 엔트리 수 | 숨겨진 인터럽트 핸들러 |
/* IDT 무결성 검증 (x86_64) */
static void p_check_idt(void) {
struct desc_ptr idtr;
char hash[32];
/* 현재 IDT 기저 주소/크기 획득 */
store_idt(&idtr);
/* IDT 전체 내용의 해시 계산 */
p_hash_memory((void *)idtr.address, idtr.size + 1, hash);
/* 기준 해시와 비교 */
if (memcmp(hash, p_db.idt_hash, 32))
p_integrity_alert("IDT modified");
}
/* MSR LSTAR (시스템 콜 진입점) 검증 */
static void p_check_msr_lstar(void) {
u64 lstar = native_read_msr(MSR_LSTAR);
if (lstar != p_db.msr_lstar) {
p_print_log(P_LOG_ALERT,
"MSR_LSTAR changed: 0x%llx -> 0x%llx",
p_db.msr_lstar, lstar);
}
}
시스템 콜 테이블 보호
전통적인 루트킷의 대표적 기법은 sys_call_table[]의 엔트리를 변조하여 시스템 콜을 가로채는 것입니다. 예를 들어 sys_getdents64를 교체하면 파일 목록을 조작하여 루트킷 파일을 숨길 수 있습니다.
/* 시스템 콜 테이블 무결성 검증 (단순화) */
static void p_check_syscall_table(void) {
char hash[32];
unsigned long *table = (unsigned long *)p_db.syscall_table_addr;
size_t size = __NR_syscalls * sizeof(unsigned long);
/* 현재 syscall table 해시 계산 */
p_hash_memory(table, size, hash);
/* 기준 해시와 비교 */
if (memcmp(hash, p_db.syscall_table_hash, 32)) {
p_print_log(P_LOG_ALERT,
"sys_call_table has been modified!");
/* 변조된 엔트리 식별 */
for (int i = 0; i < __NR_syscalls; i++) {
if (table[i] != p_db.syscall_table_copy[i])
p_print_log(P_LOG_ALERT,
" syscall #%d: 0x%lx -> 0x%lx",
i, p_db.syscall_table_copy[i], table[i]);
}
}
}
per-CPU 검증
IDT, GDT, MSR은 각 CPU마다 독립적으로 존재할 수 있습니다. LKRG는 smp_call_function_many()를 사용하여 모든 CPU에서 동시에 검증을 수행합니다. 이는 단일 CPU만 변조하는 정교한 공격도 탐지할 수 있게 합니다.
훅 메커니즘
LKRG는 두 가지 메커니즘으로 무결성 검사를 트리거합니다: 이벤트 기반 훅과 타이머(Timer) 기반 주기적 검사.
이벤트 기반 훅 (kprobe/kretprobe)
LKRG는 자격증명 변경과 관련된 커널 함수에 kprobe/kretprobe를 설치합니다. 이를 통해 합법적인 자격증명 변경을 실시간으로 추적하고 해시를 갱신합니다.
| 훅 대상 함수 | 유형 | 목적 |
|---|---|---|
commit_creds() | kretprobe | 자격증명 변경 추적 |
override_creds() | kretprobe | 임시 자격증명 변경 추적 |
revert_creds() | kretprobe | 자격증명 복원 추적 |
do_init_module() | kretprobe | 모듈 로드 완료 후 해시 갱신 |
security_bprm_committing_creds() | kprobe | execve 시 cred 커밋 전 검사 |
cap_task_prctl() | kretprobe | prctl 통한 capability 변경 추적 |
UMH (User Mode Helper) 감시
커널은 call_usermodehelper()를 통해 사용자 공간(User Space) 프로그램을 실행할 수 있습니다. 공격자가 이 메커니즘을 악용하면 커널 권한으로 임의의 바이너리를 실행할 수 있습니다. LKRG는 UMH 호출을 감시하여 비정상적인 사용자 공간 프로그램 실행을 탐지합니다.
/* UMH 감시 훅 (단순화) */
static int p_umh_notifier(
struct notifier_block *nb,
unsigned long action, void *data)
{
struct subprocess_info *info = data;
/* UMH 실행 로깅 */
p_print_log(P_LOG_INFO,
"UMH: path=%s argv[0]=%s",
info->path,
info->argv ? info->argv[0] : "(null)");
return NOTIFY_OK;
}
타이머 기반 주기적 검사
kprobe 훅으로 캡처되지 않는 직접 메모리 변조를 탐지하기 위해, LKRG는 커널 타이머를 사용한 주기적 전체 검사를 수행합니다. 이 이중 메커니즘(이벤트 + 타이머)이 LKRG의 핵심 설계입니다.
/* LKRG 주기적 검사 — 타이머 콜백 (단순화) */
static void p_offload_work(struct work_struct *work) {
/* 1. 커널 텍스트 무결성 검사 */
p_check_kernel_integrity();
/* 2. 모듈 텍스트 무결성 검사 */
p_check_modules_integrity();
/* 3. 커널 객체 (IDT/GDT/MSR) 검사 */
p_check_critical_objects();
/* 4. SELinux 상태 검사 */
p_check_selinux();
/* 5. 전체 프로세스 자격증명 순회 검사 */
p_check_all_tasks_creds();
/* 다음 검사 스케줄 */
mod_timer(&p_timer, jiffies + p_interval);
}
탐지 및 대응
LKRG는 무결성 위반을 탐지했을 때 설정에 따라 다른 수준의 대응을 수행합니다.
대응 정책
| 정책 레벨 | sysctl 값 | 동작 | 적용 환경 |
|---|---|---|---|
| Log only | 0 | dmesg에 경고 로그만 기록 | 테스트/평가 환경 |
| Kill process | 1 | 변조된 자격증명의 프로세스 종료 | 프로덕션 (기본값) |
| Panic | 2 | 커널 패닉(Kernel Panic)으로 시스템 정지 | 고보안 환경 |
로그 메시지 형식
# dmesg에서 LKRG 관련 로그 확인
dmesg | grep -i lkrg
# 탐지 시 출력 예시
[ 123.456789] [p_lkrg] ALERT: Kernel .text integrity violation!
[ 123.456790] [p_lkrg] ALERT: Process credentials violation!
PID=1234 COMM=exploit UID=0->0 EUID=1000->0
[ 123.456791] [p_lkrg] ALERT: SELinux enforcing mode changed! 1->0
[ 123.456792] [p_lkrg] ALERT: IDT has been modified!
dmesg와 printk를 통해 출력되므로, rsyslog나 journald를 통해 SIEM(Security Information and Event Management) 시스템에 전달할 수 있습니다. [p_lkrg] ALERT 패턴으로 필터링하세요.
# rsyslog 규칙 예시: LKRG 경고를 별도 파일에 기록
# /etc/rsyslog.d/lkrg.conf
:msg, contains, "[p_lkrg] ALERT" /var/log/lkrg-alerts.log
& stop
# journalctl로 LKRG 로그만 필터링
journalctl -k --grep="p_lkrg" --since="1 hour ago"
설치
설치 전 요구사항
| 요구사항 | 최소 조건 | 확인 명령 |
|---|---|---|
| 커널 버전 | 5.4 이상 권장 | uname -r |
| 커널 헤더 | 현재 커널과 일치하는 헤더 패키지 | ls /lib/modules/$(uname -r)/build |
| CONFIG_KPROBES | y (필수) | grep KPROBES /boot/config-$(uname -r) |
| CONFIG_KALLSYMS | y (필수) | grep KALLSYMS /boot/config-$(uname -r) |
| CONFIG_MODULES | y (필수) | grep "^CONFIG_MODULES=" /boot/config-$(uname -r) |
| 컴파일러 | GCC 또는 Clang | gcc --version |
| make | GNU Make | make --version |
# 사전 점검 스크립트
echo "=== LKRG 설치 전 점검 ==="
echo "커널 버전: $(uname -r)"
echo "아키텍처: $(uname -m)"
# 필수 커널 설정 확인
for opt in KPROBES KALLSYMS MODULES JUMP_LABEL; do
val=$(grep "CONFIG_${opt}=" /boot/config-$(uname -r) 2>/dev/null)
if [ -z "$val" ]; then
echo "[WARN] CONFIG_${opt} 미확인"
else
echo "[OK] ${val}"
fi
done
# 커널 헤더 확인
if [ -d "/lib/modules/$(uname -r)/build" ]; then
echo "[OK] 커널 헤더 존재"
else
echo "[FAIL] 커널 헤더 없음 — 설치 필요"
fi
DKMS를 통한 설치 (권장)
DKMS(Dynamic Kernel Module Support)를 사용하면 커널 업그레이드 시 자동으로 LKRG 모듈을 재빌드합니다.
# 의존성 설치 (Debian/Ubuntu)
sudo apt install dkms linux-headers-$(uname -r) build-essential
# LKRG 소스 다운로드
git clone https://github.com/lkrg-org/lkrg.git
cd lkrg
# DKMS 등록 및 빌드
sudo make dkms-install
# 모듈 로드
sudo modprobe lkrg
# 부팅 시 자동 로드 설정
echo "lkrg" | sudo tee /etc/modules-load.d/lkrg.conf
소스 빌드 (수동)
# 소스에서 직접 빌드
git clone https://github.com/lkrg-org/lkrg.git
cd lkrg
make -j$(nproc)
# 수동 로드
sudo insmod output/lkrg.ko
# 언로드 (비활성화)
sudo rmmod lkrg
배포판별 패키지
| 배포판 | 패키지 | 설치 명령 |
|---|---|---|
| Whonix | lkrg-dkms | sudo apt install lkrg-dkms |
| Arch Linux (AUR) | lkrg-dkms | yay -S lkrg-dkms |
| Fedora (COPR) | lkrg | sudo dnf copr enable <repo> && sudo dnf install lkrg |
| Debian | 소스 빌드 | 위 DKMS 절차 참조 |
sysctl 설정
LKRG는 sysctl 인터페이스를 통해 런타임 설정을 변경할 수 있습니다. 모든 파라미터는 lkrg. 접두사를 사용합니다.
주요 파라미터
| 파라미터 | 기본값 | 범위 | 설명 |
|---|---|---|---|
lkrg.profile_validate | 3 | 0~4 | 전체 검증 프로파일 (0=비활성, 4=최대) |
lkrg.profile_enforce | 2 | 0~4 | 대응 정책 프로파일 (0=log only, 4=panic) |
lkrg.interval | 15 | 5~1800 | 주기적 검사 간격 (초) |
lkrg.trigger | N/A | 쓰기 전용 | 즉시 전체 검사 실행 |
lkrg.log_level | 1 | 0~4 | 로그 상세도 (0=최소, 4=디버그) |
lkrg.block_modules | 0 | 0~1 | 새 모듈 로드 차단 |
lkrg.hide | 0 | 0~1 | LKRG 모듈을 모듈 목록에서 숨김 |
lkrg.msr_validate | 1 | 0~1 | MSR 검증 활성화 |
lkrg.pcfi_validate | 2 | 0~3 | 프로세스 자격증명 검증 강도 |
lkrg.pcfi_enforce | 1 | 0~3 | 자격증명 위반 대응 강도 |
프로파일 설정 예시
# 현재 설정 확인
sysctl -a | grep lkrg
# 프로덕션 서버: 높은 검증 + 프로세스 종료 대응
sudo sysctl -w lkrg.profile_validate=3
sudo sysctl -w lkrg.profile_enforce=2
sudo sysctl -w lkrg.interval=10
# 고보안 환경: 최대 검증 + 모듈 차단 + 패닉
sudo sysctl -w lkrg.profile_validate=4
sudo sysctl -w lkrg.profile_enforce=4
sudo sysctl -w lkrg.block_modules=1
# 테스트 환경: 로그만 기록
sudo sysctl -w lkrg.profile_validate=2
sudo sysctl -w lkrg.profile_enforce=0
sudo sysctl -w lkrg.log_level=4
# 영구 설정 (/etc/sysctl.d/lkrg.conf)
echo "lkrg.profile_validate=3" | sudo tee /etc/sysctl.d/lkrg.conf
echo "lkrg.profile_enforce=2" | sudo tee -a /etc/sysctl.d/lkrg.conf
echo "lkrg.interval=15" | sudo tee -a /etc/sysctl.d/lkrg.conf
# 즉시 전체 검사 실행 (수동 트리거)
sudo sysctl -w lkrg.trigger=1
프로파일 상세 설명
lkrg.profile_validate와 lkrg.profile_enforce는 여러 개별 파라미터를 한 번에 설정하는 매크로(Macro) 역할을 합니다.
| profile_validate 값 | 코드 검증 | cred 검증 | 타이머 검사 | MSR 검증 |
|---|---|---|---|---|
| 0 (비활성) | 꺼짐 | 꺼짐 | 꺼짐 | 꺼짐 |
| 1 (최소) | 이벤트 시 | 이벤트 시 | 꺼짐 | 꺼짐 |
| 2 (경량) | 이벤트 + 타이머 | 이벤트 시 | 활성 | 꺼짐 |
| 3 (표준, 기본) | 이벤트 + 타이머 | 이벤트 + 타이머 | 활성 | 활성 |
| 4 (최대) | 이벤트 + 짧은 타이머 | 이벤트 + 타이머 + 전수 | 활성 | 활성 |
lkrg.hide=1을 설정하면 LKRG가 lsmod 출력에서 사라지며, sysctl lkrg.* 인터페이스도 접근이 제한됩니다. 이 기능은 공격자가 LKRG의 존재를 탐지하기 어렵게 하지만, 관리 편의성이 떨어지므로 숨기기 전에 모든 설정을 완료하세요.
profile_validate=3, profile_enforce=0(log only)으로 시작하세요. 1~2주간 오탐이 없음을 확인한 후 profile_enforce를 2(프로세스 종료)로 올리세요. 고보안 환경에서만 4(패닉)를 사용하세요.
LKRG vs IMA 비교
LKRG와 IMA(Integrity Measurement Architecture)는 모두 시스템 무결성을 검증하는 도구이지만, 동작 계층, 검증 시점, 대응 방식이 근본적으로 다릅니다. 두 도구의 차이를 이해하면 적절한 방어 전략을 수립할 수 있습니다.
| 특성 | LKRG | IMA |
|---|---|---|
| 검증 대상 | 커널 메모리 (코드, 데이터, 객체) | 파일 시스템 (바이너리, 라이브러리) |
| 동작 계층 | 커널 런타임 메모리 | VFS (파일 open/mmap) |
| 구현 방식 | Out-of-tree 커널 모듈 | In-tree LSM (메인라인) |
| 해시 기준 | 부팅 시 스냅샷 | 사전 서명된 해시 (x509) |
| 변조 대응 | log / kill / panic | 실행 거부 (appraise) |
| 루트킷 탐지 | 커널 수준 루트킷 탐지 가능 | 파일 수준 변조 탐지 |
| 성능 영향 | 주기적 CPU 스파이크 | 파일 I/O 시 지연 |
| TPM 연동 | 미지원 | TPM PCR 확장 지원 |
함께 사용하는 방법
# IMA + LKRG 병용 구성 예시
# 1. IMA 활성화 (커널 cmdline)
# ima_policy=tcb ima_appraise=enforce
# 2. IMA 정책: 실행 파일과 라이브러리 무결성 강제
# /etc/ima/ima-policy
# dont_appraise fsmagic=0x9fa0
# dont_appraise fsmagic=0x62656572
# appraise func=BPRM_CHECK
# appraise func=MODULE_CHECK
# measure func=BPRM_CHECK
# measure func=MODULE_CHECK
# 3. LKRG: 커널 런타임 보호
sudo modprobe lkrg
sudo sysctl -w lkrg.profile_validate=3
sudo sysctl -w lkrg.profile_enforce=2
# 결과:
# - IMA가 변조된 바이너리/모듈의 실행을 차단 (사전 예방)
# - LKRG가 커널 메모리 내부의 변조를 탐지 (사후 탐지)
# - 두 계층이 서로 다른 공격 벡터를 커버하여 보안 강화
제한사항
LKRG는 강력한 런타임 감시 도구이지만, 설계상 다음과 같은 한계가 있습니다.
근본적 제한
| 제한 | 원인 | 영향 |
|---|---|---|
| TOCTOU 취약성 | 검사 시점과 사용 시점의 차이 | 짧은 시간 내 변조 후 복원 시 탐지 불가 |
| 동일 권한 실행 | 커널 모듈로서 ring 0 실행 | 공격자가 ring 0 접근 시 LKRG도 무력화 가능 |
| 데이터만 변조 | 코드가 아닌 데이터 구조 공격 | 함수 포인터 변조 등 일부만 탐지 |
| DMA 공격 | 하드웨어 DMA를 통한 메모리 접근 | CPU를 거치지 않는 변조 탐지 불가 |
| 커널 업데이트 | 커널 버전 변경 시 재빌드 필요 | DKMS로 자동화 가능하나 호환성 문제 가능 |
알려진 우회 벡터
바이패스 기법 분석
보안 연구자들은 LKRG의 한계를 분석하여 다양한 우회 기법을 제시했습니다. 이 분석은 방어 강화에 참고됩니다.
학술 연구 결과
| 우회 기법 | 원리 | LKRG 대응 |
|---|---|---|
| Race condition 공격 | 타이머 검사 사이에 변조 → 복원 | 검사 간격 단축, 이벤트 기반 훅 강화 |
| LKRG 코드 변조 | LKRG 모듈 자체의 검사 루틴 NOP 패치 | lkrg.hide=1, 모듈 서명 검증(Signature Verification) |
| kretprobe 해제 | LKRG의 kprobe 훅을 해제 후 공격 | 타이머 기반 백업 검사로 이중 탐지 |
| 데이터 전용 공격 (DOP) | 코드 변조 없이 데이터만 변조 | cred 해시 + 주기적 전수 검사 |
| ROP/JOP 체인 | 기존 코드 재사용으로 코드 변조 회피 | kCFI/FineIBT 병용 권장 |
실전 공격 시나리오별 LKRG 효과
| 공격 유형 | 예시 CVE | LKRG 탐지 여부 | 설명 |
|---|---|---|---|
| cred 직접 변조 | CVE-2016-5195 (DirtyCOW) | 탐지 가능 | uid/euid 변경 감지 |
| syscall 테이블 후킹 | 전통적 루트킷 | 탐지 가능 | 테이블 해시 불일치 |
| 커널 코드 패치 | 인라인 후킹 | 탐지 가능 | .text 해시 불일치 |
| IDT 후킹 | 인터럽트 하이재킹 | 탐지 가능 | IDT 엔트리 비교 |
| SELinux 비활성화 | 다수의 Android 루트킷 | 탐지 가능 | enforcing 플래그 감시 |
| DOP (Data-Only) | 함수 포인터만 변조 | 부분 탐지 | 코드 해시는 정상, cred만 감시 |
| ROP/JOP 체인 | 기존 가젯 재사용 | 제한적 | 코드 변조 없으므로 해시 정상 |
| DMA 공격 | Thunderbolt/FireWire DMA | 탐지 불가 | CPU 우회 직접 메모리 접근(DMA) |
방어 강화 권장 조합
# 권장 방어 계층 구성
# 1단계: 커널 하드닝 (컴파일 시)
CONFIG_RANDOMIZE_BASE=y # KASLR
CONFIG_CFI_CLANG=y # kCFI
CONFIG_SHADOW_CALL_STACK=y # SCS (ARM64)
CONFIG_SECURITY_LOCKDOWN_LSM=y
# 2단계: 부팅 시 보안
# Secure Boot + 모듈 서명 + Lockdown 활성화
lockdown=integrity # 커널 cmdline
# 3단계: LKRG 런타임 보호
sudo modprobe lkrg
sudo sysctl -w lkrg.profile_validate=4
sudo sysctl -w lkrg.block_modules=1
sudo sysctl -w lkrg.hide=1
# 4단계: 파일 시스템 보호 (IMA)
# ima_policy=tcb ima_appraise=enforce
성능 영향
LKRG의 주요 성능 비용은 주기적 전체 검사와 이벤트 기반 kretprobe 오버헤드에서 발생합니다.
오버헤드 벤치마크
| 워크로드 | LKRG 비활성 | LKRG 활성 (기본) | 오버헤드 |
|---|---|---|---|
| 커널 빌드 (make -j8) | 100% | ~100.5% | < 1% |
| 파일 I/O (fio 4K) | 100% | ~100.2% | < 0.5% |
| 네트워크 (iperf3) | 100% | ~100.1% | < 0.2% |
| 프로세스 집중 (fork bomb 제한) | 100% | ~102% | ~2% |
| execve 집중 | 100% | ~103% | ~3% |
| 타이머 스파이크 (검사 순간) | 0ms | 10~50ms | 순간 지연 |
성능 튜닝 가이드
| 환경 | 권장 interval | pcfi_validate | profile_validate | 예상 오버헤드 |
|---|---|---|---|---|
| 고성능 DB 서버 | 60 | 1 | 2 | < 0.1% |
| 웹 서버 | 15 | 2 | 3 | < 0.5% |
| CI/CD 빌드 서버 | 30 | 1 | 2 | < 1% |
| 보안 게이트웨이 | 5 | 3 | 4 | 1~3% |
| 컨테이너 호스트 | 30 | 2 | 3 | 1~2% |
lkrg.interval을 늘리면 타이머 스파이크 빈도 감소 (보안 트레이드오프 있음)lkrg.pcfi_validate=1로 낮추면 자격증명 검사 빈도 감소- execve 집중 워크로드(컨테이너 환경)에서는 오버헤드가 상대적으로 커질 수 있음
- 프로세스 수가 많은 서버(수천 개)에서는 cred 전수 검사 시간이 길어지므로, 간격을 넓히거나
pcfi_validate를 낮추세요
perf를 이용한 오버헤드 측정
# LKRG 관련 CPU 사용량 측정
sudo perf top -g -p $(pgrep -f lkrg || echo 0)
# LKRG 타이머 콜백 실행 시간 측정
sudo perf probe -a 'p_offload_work'
sudo perf stat -e 'probe:p_offload_work' -- sleep 60
# kretprobe 오버헤드 측정 (commit_creds 호출 빈도)
sudo perf stat -e 'probe:commit_creds' -- sleep 60
# 전체 시스템 영향 비교 (LKRG 로드 전/후)
# 로드 전
sudo rmmod lkrg 2>/dev/null
sysbench cpu --threads=8 run
sysbench threads --threads=64 run
# 로드 후
sudo modprobe lkrg
sysbench cpu --threads=8 run
sysbench threads --threads=64 run
커널 호환성
LKRG는 out-of-tree 모듈이므로 커널 내부 API 변경에 민감합니다.
지원 버전
| 커널 버전 | LKRG 지원 | 비고 |
|---|---|---|
| 5.4 LTS | 지원 | Debian 11, Ubuntu 20.04 |
| 5.10 LTS | 지원 | Debian 11 backports |
| 5.15 LTS | 지원 | Ubuntu 22.04 |
| 6.1 LTS | 지원 | Debian 12 |
| 6.6 LTS | 지원 | 최신 LTS |
| 6.8~6.12 | 지원 (최신) | 최신 안정 릴리스 |
| < 5.4 | 제한적 | 이전 버전은 테스트 부족 |
호환성 이슈
- kprobe 비활성화:
CONFIG_KPROBES=n인 커널에서는 이벤트 기반 감시가 작동하지 않음 - KASLR: LKRG는 KASLR 환경에서 정상 동작하며, 심볼 검색을 통해 주소를 자동 해결
- PREEMPT_RT: RT 커널에서 테스트가 제한적이며, sleeping context 이슈 가능
- GCC vs Clang: 컴파일러에 따라 코드 레이아웃이 달라질 수 있으나, 런타임 해시는 로드 시 기준값을 새로 계산하므로 영향 없음
- kCFI/FineIBT: 간접 호출 제어 흐름 무결성(CFI)과 병용 가능하나, kretprobe 동작에 주의 필요
아키텍처별 지원
| 아키텍처 | 지원 상태 | 비고 |
|---|---|---|
| x86_64 | 완전 지원 (주요 개발 대상) | IDT/GDT/MSR/LSTAR 전체 검증 |
| ARM64 (AArch64) | 지원 | 코드 무결성 + cred 검증, 일부 CPU 객체 검사 제한 |
| x86 (32비트) | 제한적 | 이전 버전에서 지원, 최근 테스트 부족 |
| 기타 | 미지원 | RISC-V, PowerPC, MIPS 등은 미지원 |
커널 설정 충돌
# LKRG와 충돌 가능한 커널 설정
# CONFIG_DEBUG_SET_MODULE_RONX가 비활성화된 경우
# 모듈 텍스트가 쓰기 가능하여 해시 변경 가능 → 오탐 발생
# 해결: CONFIG_STRICT_MODULE_RWX=y 권장
# CONFIG_SECURITY_LOCKDOWN_LSM_EARLY=y + lockdown=confidentiality
# kprobe 등록이 차단될 수 있음
# 해결: lockdown=integrity 모드 사용
# CONFIG_TRIM_UNUSED_KSYMS=y
# 심볼 제거로 LKRG가 필요한 심볼을 찾지 못할 수 있음
# 해결: 해당 옵션 비활성화
대안 비교
LKRG 외에도 호스트 무결성 검증을 위한 다양한 도구가 있습니다.
| 도구 | 검증 계층 | 방식 | 장점 | 단점 |
|---|---|---|---|---|
| LKRG | 커널 메모리 | 런타임 해시 | 커널 루트킷 탐지 | ring 0 우회 가능 |
| IMA/EVM | 파일 시스템 | 파일 해시/서명 | 메인라인, TPM 연동 | 런타임 메모리 미검증 |
| AIDE | 파일 시스템 | 데이터베이스 비교 | 간단한 설정 | 실시간 아님, 메모리 미검증 |
| Samhain | 파일 + 커널 | 주기적 스캔 | /proc 기반 커널 검사 | LKRG 수준 깊이 부족 |
| Tripwire | 파일 시스템 | 데이터베이스 비교 | 상용/오픈소스 둘 다 | 실시간 아님 |
| OSSEC | 파일 + 로그 | 에이전트 기반 | 종합 HIDS | 커널 수준 탐지 제한 |
배포 가이드
프로덕션 배포 절차
- 사전 테스트: 스테이징 환경에서 최소 1주간
lkrg.profile_enforce=0(log only)으로 운영하여 오탐 확인 - 점진적 강화: 오탐이 없으면
profile_enforce를 단계적으로 올림 - 모니터링 연동: LKRG 로그를 SIEM에 전달하고 경보 규칙 설정
- 커널 업그레이드 계획: DKMS로 자동 빌드되지만, 주요 커널 버전 업그레이드 전 LKRG 호환성 확인
Ansible 배포 예시
---
# ansible playbook: LKRG 배포
- name: Deploy LKRG
hosts: production_servers
become: yes
tasks:
- name: 의존성 설치
apt:
name:
- dkms
- linux-headers-{{ ansible_kernel }}
- build-essential
- git
state: present
- name: LKRG 소스 클론
git:
repo: https://github.com/lkrg-org/lkrg.git
dest: /usr/src/lkrg
version: main
- name: DKMS 설치
command: make dkms-install
args:
chdir: /usr/src/lkrg
- name: 모듈 로드
modprobe:
name: lkrg
state: present
- name: 부팅 시 자동 로드
copy:
content: "lkrg\n"
dest: /etc/modules-load.d/lkrg.conf
- name: sysctl 설정
sysctl:
name: "{{ item.key }}"
value: "{{ item.value }}"
sysctl_file: /etc/sysctl.d/lkrg.conf
loop:
- { key: "lkrg.profile_validate", value: "3" }
- { key: "lkrg.profile_enforce", value: "2" }
- { key: "lkrg.interval", value: "15" }
컨테이너 환경 배포
Docker/Kubernetes 환경에서 LKRG를 사용하려면 호스트 커널에 모듈을 로드해야 합니다. 컨테이너는 호스트와 커널을 공유하므로, LKRG 하나로 전체 컨테이너의 커널 수준 보안을 강화할 수 있습니다.
# 호스트에서 LKRG 로드 (컨테이너 전체에 적용)
sudo modprobe lkrg
# 컨테이너에서 새 프로세스 실행 시 cred 검증 활성화
sudo sysctl -w lkrg.pcfi_validate=3
# 주의: 컨테이너 빈번한 생성/삭제 시 execve 오버헤드 고려
sudo sysctl -w lkrg.interval=30 # 검사 간격 넓히기
모니터링 연동 (Prometheus + AlertManager)
# LKRG 경고를 Prometheus alertable metric으로 변환
# 커스텀 exporter 스크립트 예시
#!/bin/bash
# /usr/local/bin/lkrg-exporter.sh
LKRG_ALERTS=$(dmesg | grep -c "\[p_lkrg\] ALERT" 2>/dev/null || echo 0)
echo "# HELP lkrg_alerts_total Total LKRG alert count"
echo "# TYPE lkrg_alerts_total counter"
echo "lkrg_alerts_total ${LKRG_ALERTS}"
Secure Boot 연동
Secure Boot가 활성화된 시스템에서는 서명되지 않은 out-of-tree 커널 모듈의 로드가 차단됩니다. LKRG를 사용하려면 MOK(Machine Owner Key)로 모듈에 서명해야 합니다.
MOK 키 생성 및 모듈 서명
# 1. MOK 키 페어 생성
openssl req -new -x509 -newkey rsa:2048 -keyout MOK.priv \
-outform DER -out MOK.der -nodes -days 36500 \
-subj "/CN=LKRG Module Signing Key/"
# 2. MOK 등록 (재부팅 시 비밀번호 입력 필요)
sudo mokutil --import MOK.der
# 3. 재부팅 후 MOK Manager에서 Enroll MOK 선택
sudo reboot
# 4. LKRG 모듈 서명
sudo /usr/src/linux-headers-$(uname -r)/scripts/sign-file \
sha256 MOK.priv MOK.der \
/lib/modules/$(uname -r)/updates/dkms/lkrg.ko
# 5. 서명 확인
modinfo lkrg | grep sig
# 6. 서명된 모듈 로드
sudo modprobe lkrg
DKMS 자동 서명 설정
# /etc/dkms/framework.conf에 추가
sign_tool="/usr/lib/linux-kbuild-$(uname -r | cut -d. -f1-2)/scripts/sign-file"
mok_signing_key="/root/MOK.priv"
mok_certificate="/root/MOK.der"
# 이후 DKMS 빌드 시 자동 서명됨
sudo dkms install lkrg/$(cat /usr/src/lkrg/VERSION)
키 보안 관리
# MOK 프라이빗 키 보호
sudo chmod 400 /root/MOK.priv
sudo chown root:root /root/MOK.priv
# 키 파일 무결성 보호 (immutable 속성)
sudo chattr +i /root/MOK.priv
# 키 접근 감사 (audit 규칙)
sudo auditctl -w /root/MOK.priv -p rwa -k mok_key_access
# 키가 유출되었을 때: MOK 키 교체 절차
# 1. 새 키 페어 생성
# 2. 기존 MOK 키 삭제
sudo mokutil --delete /root/MOK.der
# 3. 새 MOK 키 등록
sudo mokutil --import /root/MOK_new.der
# 4. 재부팅하여 MOK Manager에서 확인
# 5. 모든 모듈을 새 키로 재서명
MOK.priv)는 반드시 root만 읽을 수 있도록 권한을 설정하고, 가능하면 별도 암호화(Encryption)된 저장소에 보관하세요. 키가 유출되면 공격자가 악성 모듈에 서명하여 Secure Boot를 우회할 수 있습니다. 자세한 내용은 Secure Boot 페이지를 참조하세요.
Lockdown LSM과의 연동
커널 Lockdown LSM이 integrity 모드로 활성화된 경우, LKRG의 kprobe 등록은 허용되지만 /dev/mem 등을 통한 커널 메모리 직접 접근은 차단됩니다. confidentiality 모드에서는 kprobe 자체가 차단될 수 있으므로, LKRG 사용 시 lockdown=integrity를 권장합니다.
트러블슈팅
자주 발생하는 문제
| 증상 | 원인 | 해결 방법 |
|---|---|---|
insmod: ERROR: could not insert module | Secure Boot 모듈 서명 누락 | MOK으로 모듈 서명 후 재시도 |
Unknown symbol in module | 커널 헤더 버전 불일치 | apt install linux-headers-$(uname -r) 후 재빌드 |
| 빈번한 ALERT 로그 | 오탐 (ftrace, livepatch, eBPF 등) | lkrg.profile_validate 조정, 최신 LKRG 업데이트 |
| 부팅 시 커널 패닉 | lkrg.profile_enforce=4 + 초기화 경합 | GRUB에서 lkrg.profile_enforce=0으로 부팅 후 조정 |
| 성능 저하 | 짧은 검사 간격 | lkrg.interval 증가, lkrg.pcfi_validate 축소 |
| 모듈 로드 실패 (6.x) | 커널 API 변경 | 최신 LKRG git 버전 사용 |
디버깅(Debugging) 절차
# 1. LKRG 모듈 상태 확인
lsmod | grep lkrg
modinfo lkrg
# 2. 현재 sysctl 설정 확인
sysctl -a 2>/dev/null | grep lkrg
# 3. LKRG 로그 확인 (커널 메시지)
dmesg | grep -i lkrg | tail -20
# 4. 디버그 모드로 로드 (상세 로그)
sudo rmmod lkrg 2>/dev/null
sudo sysctl -w lkrg.log_level=4 2>/dev/null || true
sudo modprobe lkrg
dmesg | tail -50
# 5. LKRG 빌드 로그 확인 (DKMS)
cat /var/lib/dkms/lkrg/*/build/make.log
# 6. 커널 설정 확인 (필수 옵션)
grep -E "(KPROBES|MODULES|KALLSYMS|JUMP_LABEL)" /boot/config-$(uname -r)
# CONFIG_KPROBES=y 필수
# CONFIG_MODULES=y 필수
# CONFIG_KALLSYMS=y 권장
livepatch 호환성 처리
kpatch나 livepatch를 사용하는 환경에서는 커널 코드가 런타임에 정상적으로 변경됩니다. LKRG는 이를 코드 변조로 탐지할 수 있으므로 다음 절차를 따르세요:
# 1. livepatch 적용 전: LKRG를 log-only 모드로 전환
sudo sysctl -w lkrg.profile_enforce=0
# 2. livepatch 적용
sudo kpatch load livepatch-module.ko
# 3. LKRG 기준 해시 갱신 (수동 트리거)
sudo sysctl -w lkrg.trigger=1
# 4. 오탐이 없는지 확인
dmesg | grep -i lkrg | tail -5
# 5. 대응 정책 복원
sudo sysctl -w lkrg.profile_enforce=2
lkrg.trigger=1을 쓰면 LKRG가 현재 상태를 새 기준으로 채택하므로, livepatch 직후 즉시 실행하면 됩니다. livepatch 페이지도 참조하세요.
LKRG 완전 제거
# 모듈 언로드
sudo rmmod lkrg
# DKMS에서 제거
sudo dkms remove lkrg/$(cat /usr/src/lkrg/VERSION) --all
# 부팅 자동 로드 해제
sudo rm -f /etc/modules-load.d/lkrg.conf
# sysctl 설정 제거
sudo rm -f /etc/sysctl.d/lkrg.conf
# 소스 정리
sudo rm -rf /usr/src/lkrg
LKRG 로그 분석 가이드
LKRG 로그 메시지는 심각도에 따라 분류됩니다. 실제 운영 환경에서 로그를 해석하는 방법을 알아봅니다.
| 로그 패턴 | 심각도 | 의미 | 대응 |
|---|---|---|---|
[p_lkrg] Loading LKRG | INFO | LKRG 모듈 로드 시작 | 정상, 대응 불필요 |
[p_lkrg] LKRG initialized successfully | INFO | 초기화 완료, 기준 해시 설정됨 | 정상, 대응 불필요 |
[p_lkrg] New module registered | INFO | 새 모듈 로드, 해시 DB 갱신 | 정상, 의도된 모듈인지 확인 |
[p_lkrg] ALERT: .text integrity | ALERT | 커널/모듈 코드 변조 탐지 | 즉시 조사 — 루트킷 가능성 |
[p_lkrg] ALERT: credentials | ALERT | 프로세스 자격증명 변조 | 즉시 조사 — 권한 상승 공격 |
[p_lkrg] ALERT: SELinux | ALERT | SELinux enforcing 변조 | 즉시 조사 — 정책 우회 시도 |
[p_lkrg] ALERT: IDT/MSR | ALERT | CPU 특수 구조 변조 | 즉시 조사 — 인터럽트 하이재킹 |
# 실시간 LKRG 로그 모니터링
sudo dmesg -wH | grep --color=always "p_lkrg"
# 최근 24시간 LKRG ALERT 로그 (systemd 환경)
journalctl -k --since "24 hours ago" --grep="p_lkrg.*ALERT"
# LKRG ALERT 발생 시 자동 알림 스크립트
#!/bin/bash
# /usr/local/bin/lkrg-monitor.sh
while true; do
dmesg -c | grep "\[p_lkrg\] ALERT" | while read -r line; do
echo "LKRG ALERT on $(hostname): $line" | \
mail -s "LKRG Security Alert" admin@example.com
logger -p security.crit "LKRG: $line"
done
sleep 5
done
인시던트 대응 절차
LKRG가 ALERT를 발생시키면 다음 절차를 따르세요:
- 격리(Isolation): 네트워크에서 즉시 분리 (공격 확산 방지)
- 증거 수집:
dmesg,/var/log/kern.log, 메모리 덤프(Dump) 수집 - 프로세스 확인:
ps auxf,/proc/[pid]/exe,/proc/[pid]/maps검사 - 모듈 확인:
lsmod로 비정상 모듈 확인,cat /proc/modules비교 - 포렌식: 디스크 이미지 생성 후 오프라인 분석
- 복구: 깨끗한 이미지에서 시스템 재구축
내부 아키텍처
LKRG의 내부 구현을 더 깊이 분석합니다. 초기화 시퀀스(Sequence), 데이터베이스 구조, 동기화 메커니즘, 메모리 관리를 살펴봅니다.
초기화 시퀀스
LKRG 모듈이 로드될 때 수행하는 초기화 과정은 순서가 중요합니다. 특히 alternative patching이 완료된 후에 해시를 계산해야 오탐을 방지할 수 있습니다.
/* LKRG 모듈 초기화 — module_init() (단순화) */
static int __init p_lkrg_init(void)
{
int ret;
p_print_log(P_LOG_INFO, "Loading LKRG...");
/* 1단계: 심볼 해석 — kallsyms로 필요한 커널 심볼 검색 */
ret = p_resolve_symbols();
/* _stext, _etext, sys_call_table, selinux_enforcing 등 */
/* 2단계: CPU 정보 수집 — per-CPU IDT/GDT/MSR 읽기 */
smp_call_function_many(cpu_online_mask,
p_collect_cpu_info, NULL, 1);
/* 3단계: 커널 텍스트 기준 해시 계산 */
p_hash_from_text(_stext, _etext - _stext, p_db.kernel_hash);
/* 4단계: 모듈 텍스트 해시 데이터베이스 구축 */
p_init_module_hash_db();
/* 5단계: 전체 프로세스 자격증명 스냅샷 */
p_init_task_cred_db();
/* 6단계: SELinux 기준값 저장 */
p_init_selinux_state();
/* 7단계: kprobe/kretprobe 등록 */
ret = p_register_hooks();
/* 8단계: module_notifier 등록 */
register_module_notifier(&p_module_nb);
/* 9단계: 주기적 검사 타이머 시작 */
mod_timer(&p_timer, jiffies + p_interval);
/* 10단계: sysctl 인터페이스 등록 */
p_register_sysctl();
p_print_log(P_LOG_INFO,
"LKRG initialized successfully");
return 0;
}
내부 데이터베이스 구조
LKRG는 기준값을 저장하는 내부 데이터베이스를 유지합니다. 이 데이터베이스는 모듈의 전역 변수로 존재하며, 초기화 시 채워지고 런타임에 갱신됩니다.
/* LKRG 내부 데이터베이스 — 상세 구조 (단순화) */
struct p_lkrg_global_db {
/* === CI (Code Integrity) 데이터베이스 === */
struct {
char hash[32]; /* 커널 .text SHA-256 */
unsigned long stext_addr; /* _stext 주소 */
unsigned long etext_addr; /* _etext 주소 */
size_t text_size; /* 텍스트 영역 크기 */
} kernel_ci;
/* 모듈별 해시 데이터베이스 */
struct p_module_hash_entry {
struct list_head list;
char name[MODULE_NAME_LEN];
char hash[32];
unsigned long text_addr;
size_t text_size;
} *module_list;
unsigned int module_count;
/* === SI (System Integrity) 데이터베이스 === */
struct p_cpu_snapshot {
char idt_hash[32];
char gdt_hash[32];
u64 msr_lstar;
u64 msr_cstar; /* compat 시스템 콜 */
unsigned long cr0;
unsigned long cr4;
} per_cpu_db[NR_CPUS];
char syscall_table_hash[32];
unsigned long syscall_table_addr;
/* === PCFI (Process Credentials) 데이터베이스 === */
struct {
spinlock_t lock;
unsigned int task_count;
/* per-task: pid, cred 해시, nsproxy 해시 */
} pcfi;
/* === SELinux 기준값 === */
int selinux_enforcing;
unsigned long selinux_enforcing_addr;
/* === 타이머/설정 === */
struct timer_list timer;
unsigned long interval; /* jiffies 단위 */
struct work_struct work; /* 검사 작업 */
};
동기화와 락킹
LKRG는 다중 CPU 환경에서 안전하게 동작해야 합니다. 특히 기준 해시 갱신과 검증이 동시에 발생하면 안 됩니다.
| 보호 대상 | 동기화 메커니즘 | 용도 |
|---|---|---|
| 모듈 해시 DB | mutex | 모듈 추가/삭제 시 DB 갱신 직렬화 |
| cred 해시 테이블 | spinlock | 프로세스 생성/소멸 시 빠른 갱신 |
| 전체 검사 | mutex + preempt_disable | 타이머 검사와 이벤트 검사 직렬화 |
| per-CPU 객체 | smp_call_function | 모든 CPU에서 동시 스냅샷 |
| sysctl 변수 | atomic / READ_ONCE | 런타임 설정 변경의 원자성 |
메모리 보호
LKRG 자체의 코드와 데이터를 공격자로부터 보호하는 것은 근본적 한계가 있지만, 다음 기법으로 방어를 강화합니다.
/* LKRG 자기 보호 기법 */
/* 1. 모듈 자체를 ro+x로 설정 (커널이 자동 처리) */
/* CONFIG_STRICT_MODULE_RWX=y 필요 */
/* 2. lkrg.hide=1: 모듈 리스트에서 제거 */
static void p_hide_module(void) {
/* modules 리스트에서 자신을 제거 */
list_del(&THIS_MODULE->list);
/* kobject 제거 → /sys/module/lkrg 사라짐 */
kobject_del(&THIS_MODULE->mkobj.kobj);
/* lsmod, /proc/modules에서 보이지 않음 */
}
/* 3. sysctl 잠금: hide 후 sysctl 접근 차단 */
static void p_lock_sysctl(void) {
/* sysctl 테이블의 mode를 0으로 변경 */
/* → 외부에서 설정 변경 불가 */
}
모듈 로딩 제어
LKRG의 lkrg.block_modules 기능은 새로운 커널 모듈의 로드를 차단합니다. 이는 공격자가 악성 커널 모듈을 로드하는 것을 방지하는 강력한 방어 수단입니다.
모듈 차단 메커니즘
/* LKRG 모듈 로드 차단 구현 (단순화) */
static int p_module_notifier_callback(
struct notifier_block *nb,
unsigned long action, void *data)
{
struct module *mod = data;
switch (action) {
case MODULE_STATE_COMING:
/* block_modules=1이면 새 모듈 로드 차단 */
if (p_block_modules) {
p_print_log(P_LOG_ALERT,
"Module load blocked: %s", mod->name);
return NOTIFY_BAD; /* 모듈 로드 거부 */
}
break;
case MODULE_STATE_LIVE:
/* 모듈 활성화: 텍스트 해시 계산 및 DB 추가 */
p_add_module_hash(mod);
p_print_log(P_LOG_INFO,
"New module registered: %s (hash updated)",
mod->name);
break;
case MODULE_STATE_GOING:
/* 모듈 제거: DB에서 해시 삭제 */
p_del_module_hash(mod);
break;
}
return NOTIFY_OK;
}
모듈 차단과 커널 서명 검증 비교
| 방어 수단 | 차단 방식 | 장점 | 단점 |
|---|---|---|---|
| LKRG block_modules | 모든 새 모듈 로드 차단 | 가장 강력한 차단 | 정당한 모듈도 차단됨 |
| CONFIG_MODULE_SIG_FORCE | 서명 없는 모듈 거부 | 서명된 모듈은 허용 | 서명 키 관리 필요 |
| Lockdown LSM | 커널 수정 동작 제한 | 메인라인 통합 | 모듈 로드 자체는 허용 |
| IMA MODULE_CHECK | 해시/서명 미일치 모듈 거부 | 파일 무결성 검증 | 정책 설정 복잡 |
# 모듈 차단 운영 가이드
# 1. 필요한 모든 모듈이 로드된 후 차단 활성화
# (부팅 시 모든 드라이버 로드 완료 확인)
lsmod | wc -l # 현재 로드된 모듈 수 확인
# 2. 차단 활성화
sudo sysctl -w lkrg.block_modules=1
# 3. 차단 확인 (새 모듈 로드 시도)
sudo modprobe dummy 2>&1
# 결과: modprobe: ERROR: could not insert 'dummy'
# dmesg: [p_lkrg] ALERT: Module load blocked: dummy
# 4. 임시 해제 (유지보수 시)
sudo sysctl -w lkrg.block_modules=0
sudo modprobe needed_module
sudo sysctl -w lkrg.block_modules=1
# → LKRG가 자동으로 새 모듈의 해시를 DB에 추가
런타임 이벤트 흐름
LKRG의 런타임 동작을 이벤트 유형별로 상세히 분석합니다. 각 이벤트에서 어떤 검증이 수행되고 어떤 경로로 탐지/대응이 이루어지는지 살펴봅니다.
execve 이벤트 흐름
프로세스가 execve()를 실행하면 자격증명이 변경될 수 있습니다(setuid 바이너리 등). LKRG는 이 과정을 kretprobe로 추적합니다.
/* execve 시 LKRG 검증 흐름 (단순화) */
/* kprobe: security_bprm_committing_creds() 진입 */
static int p_bprm_committing_pre(
struct kprobe *p, struct pt_regs *regs)
{
struct task_struct *task = current;
/* 1. 현재 cred 해시 저장 (변경 전) */
p_save_pre_cred_hash(task);
return 0;
}
/* kretprobe: commit_creds() 반환 후 */
static int p_commit_creds_post(
struct kretprobe_instance *ri,
struct pt_regs *regs)
{
struct task_struct *task = current;
/* 2. 새 cred 해시 계산 */
char new_hash[32];
p_calc_cred_hash(task->cred, new_hash);
/* 3. DB의 cred 해시를 새 값으로 갱신 */
p_update_task_cred_hash(task->pid, new_hash);
/* 이 경로를 통한 변경은 합법적 */
return 0;
}
/* 주기적 타이머 검사에서 */
static void p_check_task_cred(struct task_struct *task)
{
char current_hash[32];
/* 현재 cred의 해시를 계산 */
p_calc_cred_hash(task->cred, current_hash);
/* DB에 저장된 해시와 비교 */
if (memcmp(current_hash, p_db_get_hash(task->pid), 32)) {
/* kretprobe를 거치지 않은 변경 → 변조! */
p_print_log(P_LOG_ALERT,
"Credentials violation! PID=%d COMM=%s",
task->pid, task->comm);
p_trigger_response(task);
}
}
모듈 로드/언로드 이벤트 흐름
| 이벤트 | notifier 상태 | LKRG 동작 | 해시 DB 변경 |
|---|---|---|---|
| 모듈 로드 시작 | MODULE_STATE_COMING | block_modules 검사 | 없음 |
| 모듈 활성화 | MODULE_STATE_LIVE | .text 해시 계산 | 추가 |
| 모듈 제거 시작 | MODULE_STATE_GOING | 해시 DB에서 삭제 | 삭제 |
| 타이머 검사 | - | 모든 모듈 해시 재검증 | 변경 없음 (비교만) |
오탐(False Positive) 발생 시나리오
LKRG가 오탐을 발생시킬 수 있는 합법적 커널 동작을 이해하는 것이 중요합니다.
| 시나리오 | 원인 | LKRG 반응 | 해결 방법 |
|---|---|---|---|
| Livepatch 적용 | 커널 .text가 정상적으로 변경 | 코드 무결성 ALERT | lkrg.trigger=1로 기준 갱신 |
| ftrace 활성화 | 함수 프롤로그에 NOP→call 패치 | 코드 무결성 ALERT (가능) | 최신 LKRG는 ftrace 호환 |
| eBPF trampoline | BPF 프로그램이 커널 코드에 연결 | 가끔 ALERT 발생 | profile_validate 조정 |
| CPU 핫플러그 | CPU 온/오프라인 시 per-CPU 변경 | IDT/GDT 불일치 가능 | LKRG가 핫플러그 감지 처리 |
| 커널 디버거(kgdb) | 브레이크포인트 삽입 시 코드 변경 | 코드 무결성 ALERT | 디버깅 시 LKRG 비활성화 |
오탐 최소화: 프로덕션 환경에서 오탐을 줄이려면 (1) LKRG를 최신 버전으로 유지하고, (2) ftrace/eBPF 활용이 많은 환경에서는 profile_validate=2로 설정하며, (3) livepatch 적용 직후 lkrg.trigger=1로 기준값을 갱신하세요.
LKRG와 컨테이너/가상화(Virtualization) 환경
현대 인프라에서 LKRG를 효과적으로 활용하기 위해 컨테이너와 가상화 환경에서의 동작 특성을 이해해야 합니다.
Docker/Kubernetes 환경
컨테이너는 호스트 커널을 공유하므로, 호스트에 LKRG를 설치하면 모든 컨테이너의 커널 수준 보안을 강화할 수 있습니다. 단, 컨테이너 내부의 프로세스 수가 많으면 cred 검사 오버헤드가 증가합니다.
| 환경 | LKRG 설치 위치 | 보호 범위 | 주의사항 |
|---|---|---|---|
| Docker (단일 호스트) | 호스트 커널 | 모든 컨테이너 + 호스트 | 컨테이너 수에 비례하는 cred 검사 비용 |
| Kubernetes (노드) | 각 노드 커널 | 해당 노드의 모든 Pod | DaemonSet으로 배포 자동화 |
| VM (KVM/QEMU) | 게스트 커널 | 해당 VM 내부만 | VM escape 공격은 탐지 불가 |
| 중첩 가상화 | 각 계층별 | 해당 커널 범위 | 하이퍼바이저 수준은 미보호 |
Kubernetes DaemonSet 배포
# LKRG를 Kubernetes DaemonSet으로 배포
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: lkrg
namespace: kube-system
labels:
app: lkrg
spec:
selector:
matchLabels:
app: lkrg
template:
metadata:
labels:
app: lkrg
spec:
hostPID: true
hostNetwork: true
containers:
- name: lkrg-loader
image: alpine:latest
securityContext:
privileged: true
command:
- /bin/sh
- -c
- |
# LKRG 모듈 로드
modprobe lkrg 2>/dev/null || insmod /opt/lkrg/lkrg.ko
# sysctl 설정
sysctl -w lkrg.profile_validate=3
sysctl -w lkrg.profile_enforce=2
sysctl -w lkrg.interval=15
# 모니터링 루프
while true; do
dmesg -c | grep "p_lkrg.*ALERT" >> /var/log/lkrg-alerts.log
sleep 10
done
volumeMounts:
- name: modules
mountPath: /lib/modules
readOnly: true
- name: lkrg-module
mountPath: /opt/lkrg
volumes:
- name: modules
hostPath:
path: /lib/modules
- name: lkrg-module
hostPath:
path: /opt/lkrg
탐지와 대응
LKRG의 탐지-대응 파이프라인을 세부적으로 분석하고, 프로덕션 환경에서의 운영 전략을 정리합니다.
대응 동작 상세
| 위반 유형 | enforce=0 (Log) | enforce=1 (Kill) | enforce=2 (Panic) |
|---|---|---|---|
| 커널 .text 변조 | ALERT 로그만 | ALERT 로그만 (프로세스 특정 불가) | 즉시 커널 패닉 |
| 모듈 .text 변조 | ALERT + 모듈명 로그 | ALERT 로그만 | 즉시 커널 패닉 |
| cred 변조 | ALERT + PID/COMM 로그 | 해당 프로세스 SIGKILL | 즉시 커널 패닉 |
| SELinux 변조 | ALERT 로그 | ALERT 로그 (복원 시도) | 즉시 커널 패닉 |
| IDT/MSR 변조 | ALERT 로그 | ALERT 로그만 | 즉시 커널 패닉 |
| syscall table 변조 | ALERT + 엔트리 번호 | ALERT 로그만 | 즉시 커널 패닉 |
SIEM/SOAR 연동 상세
# 1. rsyslog: LKRG 경고를 원격 SIEM으로 전송
# /etc/rsyslog.d/50-lkrg.conf
if $msg contains '[p_lkrg] ALERT' then {
action(type="omfwd"
target="siem.example.com"
port="514"
protocol="tcp"
template="RSYSLOG_SyslogProtocol23Format")
action(type="omfile"
file="/var/log/lkrg-alerts.log"
template="RSYSLOG_TraditionalFileFormat")
stop
}
# 2. Elastic Stack 연동 (Filebeat)
# /etc/filebeat/modules.d/lkrg.yml
- module: system
syslog:
enabled: true
var.paths: ["/var/log/lkrg-alerts.log"]
# 3. Prometheus/Alertmanager 경보 규칙
# /etc/prometheus/rules/lkrg.rules.yml
groups:
- name: lkrg
rules:
- alert: LKRGIntegrityViolation
expr: lkrg_alerts_total > 0
for: 0m
labels:
severity: critical
annotations:
summary: "LKRG detected integrity violation on {{ $labels.instance }}"
description: "Kernel integrity violation detected. Immediate investigation required."
자동화된 인시던트 대응 스크립트
#!/bin/bash
# /usr/local/bin/lkrg-incident-response.sh
# LKRG ALERT 발생 시 자동 수행하는 포렌식 스크립트
INCIDENT_DIR="/var/log/lkrg-incidents/$(date +%Y%m%d_%H%M%S)"
mkdir -p "$INCIDENT_DIR"
echo "=== LKRG 인시던트 대응 시작: $(date) ===" | tee "$INCIDENT_DIR/summary.txt"
# 1. 커널 로그 수집
dmesg > "$INCIDENT_DIR/dmesg.log"
journalctl -k --since "1 hour ago" > "$INCIDENT_DIR/journal_kernel.log"
# 2. 프로세스 스냅샷
ps auxf > "$INCIDENT_DIR/ps_tree.txt"
cat /proc/modules > "$INCIDENT_DIR/modules.txt"
lsmod > "$INCIDENT_DIR/lsmod.txt"
# 3. 네트워크 연결 상태
ss -tupan > "$INCIDENT_DIR/network_connections.txt"
# 4. 열린 파일/소켓
lsof -n > "$INCIDENT_DIR/open_files.txt" 2>/dev/null
# 5. LKRG 관련 로그 추출
grep -i "p_lkrg" "$INCIDENT_DIR/dmesg.log" > "$INCIDENT_DIR/lkrg_alerts.txt"
# 6. 의심 프로세스 정보 수집
for pid in $(grep "PID=" "$INCIDENT_DIR/lkrg_alerts.txt" | \
grep -oP 'PID=\K[0-9]+'); do
echo "--- PID $pid ---" >> "$INCIDENT_DIR/suspect_procs.txt"
ls -la /proc/$pid/exe >> "$INCIDENT_DIR/suspect_procs.txt" 2>/dev/null
cat /proc/$pid/cmdline >> "$INCIDENT_DIR/suspect_procs.txt" 2>/dev/null
cat /proc/$pid/maps >> "$INCIDENT_DIR/suspect_procs_maps.txt" 2>/dev/null
echo "" >> "$INCIDENT_DIR/suspect_procs.txt"
done
# 7. 아카이브 생성
tar czf "${INCIDENT_DIR}.tar.gz" -C "$(dirname $INCIDENT_DIR)" \
"$(basename $INCIDENT_DIR)"
echo "=== 수집 완료: ${INCIDENT_DIR}.tar.gz ===" | tee -a "$INCIDENT_DIR/summary.txt"
# 8. 알림 발송
echo "LKRG ALERT on $(hostname) at $(date)" | \
mail -s "[CRITICAL] LKRG Integrity Violation" security@example.com \
-A "${INCIDENT_DIR}.tar.gz"
성능 최적화
LKRG의 오버헤드를 워크로드 특성에 맞게 미세 조정하는 방법을 분석합니다.
오버헤드 분석 도구
# 1. LKRG 타이머 실행 빈도와 시간 측정
# ftrace로 LKRG 워크 함수 추적
echo 1 > /sys/kernel/debug/tracing/events/workqueue/workqueue_execute_start/enable
cat /sys/kernel/debug/tracing/trace_pipe | grep "p_offload"
# 2. kprobe 오버헤드 측정
# commit_creds 호출 빈도 (높을수록 LKRG 오버헤드 증가)
perf stat -e 'probe:commit_creds' -a -- sleep 60
# 3. LKRG 관련 CPU 시간
# /proc/timer_stats (구형 커널)
# BPF 기반 측정 (최신 커널)
bpftrace -e 'kprobe:p_offload_work { @start = nsecs; }
kretprobe:p_offload_work { @latency = hist(nsecs - @start); }'
# 4. 프로세스 수 대비 검사 시간 상관관계
echo "프로세스 수: $(ps aux | wc -l)"
echo "LKRG 검사 간격: $(sysctl -n lkrg.interval 2>/dev/null || echo 'N/A')초"
워크로드별 최적화 전략
| 시나리오 | 병목 | 조치 | 트레이드오프 |
|---|---|---|---|
| 대규모 컨테이너 | cred 전수 검사 | pcfi_validate=1, interval=60 | cred 변조 탐지 지연 |
| 빈번한 execve | kretprobe 오버헤드 | pcfi_validate=1 | 이벤트 기반 cred 추적 약화 |
| 모듈 빈번 로드 | 해시 계산 | block_modules=0, interval=30 | 악성 모듈 탐지 지연 |
| 실시간 시스템 | 타이머 스파이크 | interval=300, profile_validate=1 | 전체적 보호 약화 |
| 고보안 환경 | CPU 사용량 | interval=5, profile_validate=4 | 3~5% 오버헤드 수용 |
NUMA 환경 고려사항
대규모 NUMA(Non-Uniform Memory Access) 서버에서 LKRG의 smp_call_function_many()는 모든 CPU에서 동시에 검사를 수행합니다. 이는 IPI(Inter-Processor Interrupt) 오버헤드를 유발할 수 있습니다.
# NUMA 토폴로지 확인
numactl --hardware
# CPU 수에 따른 LKRG 설정 권장
# 8 CPU 이하: 기본 설정 유지
# 16~64 CPU: interval=15, profile_validate=3
# 64+ CPU: interval=30, profile_validate=2 (IPI 최소화)
CPU_COUNT=$(nproc)
if [ $CPU_COUNT -gt 64 ]; then
sysctl -w lkrg.interval=30
sysctl -w lkrg.profile_validate=2
elif [ $CPU_COUNT -gt 16 ]; then
sysctl -w lkrg.interval=15
sysctl -w lkrg.profile_validate=3
fi
보안 도구 전체 비교 종합
LKRG를 포함한 Linux 커널 보안 도구들의 역할과 상호 관계를 종합적으로 분석합니다.
| 도구 | 보호 시점 | 보호 계층 | 메인라인 | LKRG와의 관계 |
|---|---|---|---|---|
| LKRG | 런타임(사후 탐지) | 커널 메모리 | 아니오 | - |
| IMA/EVM | 파일 접근 시(사전 예방) | VFS/파일 | 예 | 상호 보완 (다른 계층) |
| dm-verity | 블록 읽기 시 | 블록 디바이스 | 예 | 상호 보완 (읽기 전용 파일시스템) |
| Secure Boot | 부팅 시 | 펌웨어/부트로더/커널 | 예 | 상호 보완 (부팅 체인 보호) |
| Lockdown LSM | 런타임(사전 예방) | 커널 인터페이스 | 예 | 상호 보완 (접근 차단) |
| kCFI/FineIBT | 런타임(사전 예방) | 제어 흐름 | 예 | 상호 보완 (ROP/JOP 방어) |
| KASLR | 부팅 시 | 메모리 레이아웃 | 예 | 상호 보완 (주소 예측 방지) |
| AIDE/Tripwire | 주기적 스캔 | 파일 시스템 | 아니오 | 상호 보완 (파일 변조 탐지) |
최적의 보안 스택 구성
# 프로덕션 서버 권장 보안 스택
# === 1단계: 빌드 시 (커널 설정) ===
# KASLR + kCFI + SCS + Lockdown + MODULE_SIG
CONFIG_RANDOMIZE_BASE=y
CONFIG_CFI_CLANG=y
CONFIG_SHADOW_CALL_STACK=y # ARM64
CONFIG_SECURITY_LOCKDOWN_LSM=y
CONFIG_MODULE_SIG=y
CONFIG_MODULE_SIG_FORCE=y
# === 2단계: 부팅 시 ===
# Secure Boot + Lockdown integrity + IMA
# 커널 cmdline:
# lockdown=integrity ima_policy=tcb ima_appraise=enforce
# === 3단계: 런타임 ===
# LKRG 로드 + 설정
modprobe lkrg
sysctl -w lkrg.profile_validate=3
sysctl -w lkrg.profile_enforce=2
sysctl -w lkrg.interval=15
sysctl -w lkrg.block_modules=1 # 모든 필요 모듈 로드 후
# === 4단계: 모니터링 ===
# LKRG ALERT → SIEM → 자동 대응
# IMA audit → 컴플라이언스 보고
# auditd → 행위 기반 탐지
방어 심층(Defense in Depth): 단일 보안 도구만으로는 모든 공격을 방어할 수 없습니다. LKRG(커널 메모리 런타임 검증) + IMA(파일 무결성) + Secure Boot(부팅 체인) + kCFI(제어 흐름) + Lockdown(접근 차단)을 조합하면 각 계층에서 서로 다른 공격 벡터(Attack Vector)를 방어하는 심층 방어 체계를 구축할 수 있습니다.
관련 문서
외부 참고 자료
- LKRG 공식 사이트 — Openwall 프로젝트 LKRG 홈페이지
- LKRG GitHub 저장소 — 소스 코드, 이슈 트래커, 릴리스
- Openwall 프로젝트 — John the Ripper, LKRG, 보안 도구
- LKRG — Openwall 상세 페이지 — LKRG 기능, 설치, FAQ 상세 정보입니다
- LKRG INSTALL Guide — LKRG 빌드 및 설치 가이드입니다
- LKRG Wiki — LKRG 위키 문서 (sysctl 튜닝, 호환성 등)입니다
- Kernel Module Signing — LKRG 모듈 서명 시 필요한 커널 모듈 서명 가이드입니다
- Kernel Self-Protection — LKRG와 보완적인 커널 자체 보호 메커니즘 문서입니다
- Kprobes — Kernel Documentation — LKRG가 사용하는 kprobe/kretprobe 메커니즘 문서입니다
- Whonix — LKRG Guide — Whonix 프로젝트의 LKRG 설치 및 운용 가이드입니다