안동민 개발노트

본문 시작

보안 위협과 방어

버퍼 오버플로와 악성 코드의 공격 경로를 살펴보고 메모리 보호·SELinux·AppArmor·방화벽의 계층적 방어를 구성합니다.

보호 메커니즘이 완벽하더라도 공격자는 소프트웨어의 취약점을 파고듭니다.

OS 수준의 보안 위협과 방어 기법을 이해하면, 안전한 코드를 작성하고 시스템을 견고하게 구성하는 능력이 생깁니다.

보안은 단일 기술이 아니라 계층적 방어(Defense in Depth)입니다.


버퍼 오버플로우

버퍼 오버플로우(Buffer Overflow)는 오래되었지만 여전히 대표적인 취약점 중 하나입니다.

1988년 모리스 웜부터 현재까지 계속 발견됩니다.

배열의 범위를 넘어서 데이터를 쓰면, 인접한 메모리 영역(리턴 주소, 함수 포인터 등)을 덮어쓸 수 있습니다.

vulnerable_code.c
#include <string.h>
#include <stdio.h>

/* 취약한 코드 — 절대 이렇게 작성하지 마세요 */
void vulnerable(char *input) {
    char buffer[64];
    strcpy(buffer, input);  /* 문자열 내용이 64바이트 이상이면 널 문자까지 들어가지 못함 */
    printf("Buffer: %s\n", buffer);
}

/* 경계 검사를 추가한 코드 */
void safe(const char *input) {
    char buffer[64];
    snprintf(buffer, sizeof(buffer), "%s", input);  /* 길이를 넘으면 잘라서 널 종단 */
    printf("Buffer: %s\n", buffer);
}

스택 스매싱 공격

버퍼 경계와 각 완화책의 범위
배열 밖 쓰기와 보호 지점제한 없는 쓰기는 버퍼를 넘어 인접 저장 영역과 제어 데이터를 훼손할 수 있습니다. 길이 검사, 카나리, CFI, ASLR과 NX는 서로 다른 지점을 다룹니다.buffer[64]널 문자까지 용량에 포함인접 저장 영역카나리가 있을 수 있음제어에 쓰이는 값복귀 주소 등경계 검사쓰기 전 차단카나리 검사일부 변조 탐지CFI 등제어 전환 제한ASLR·PIE: 주소 예측을 어렵게NX: 실행 금지 영역의 실행 차단

스택 프레임의 개념 배치이며 실제 순서·간격·카나리 유무는 ABI·컴파일러·옵션에 따라 다릅니다. 길이 검사는 범위 밖 쓰기를 막고, 완화책은 일부 손상을 탐지하거나 악용을 어렵게 합니다.

공격자가 리턴 주소를 조작하면 함수 반환 시 제어 흐름이 공격자가 의도한 위치로 이동할 수 있습니다.

현대 시스템에서는 직접 shellcode 실행뿐 아니라 ROP 같은 코드 재사용 공격도 함께 고려해야 합니다.

snprintf 예제는 입력이 유효한 널 종료 문자열이라는 전제에서 버퍼 크기를 지킵니다. 잘린 입력을 허용해도 되는지는 반환값과 애플리케이션 의미를 확인해야 합니다.

다계층 방어

defense_demo.c
#include <stdio.h>
#include <stdlib.h>

int main() {
    /* 1. 안전한 함수 사용 */
    char buf[32];
    /* 크기 확인 + snprintf/fgets; strncpy도 널 종단을 보장하지 않음 */
    if (fgets(buf, sizeof(buf), stdin) == NULL) return 1;

    /* 2. 컴파일러 방어 (-fstack-protector) */
    /* 스택 카나리: 리턴 주소 앞에 랜덤 값 삽입 */
    /* 함수 반환 시 카나리가 변조되었으면 __stack_chk_fail() 호출 */

    /* 3. OS 방어 (ASLR) */
    printf("스택 변수 주소: %p\n", (void *)buf);
    void *heap = malloc(1);
    if (!heap) return 1;
    printf("힙 주소:       %p\n", heap);
    free(heap);
    /* ASLR 설정과 빌드에 따라 배치가 달라질 수 있음; 매번 다른 값 보장 아님 */

    return 0;
}
security_compile.sh
# 주요 보안 옵션을 켜고 컴파일
gcc -O2 \
    -fstack-protector-all \
    -D_FORTIFY_SOURCE=2 \
    -Wformat -Wformat-security \
    -pie -fPIE \
    -Wl,-z,relro,-z,now \
    -Wl,-z,noexecstack \
    -o program program.c

# -fstack-protector-all:  모든 함수에 스택 카나리
# -D_FORTIFY_SOURCE=2:    최적화 옵션과 함께 버퍼 크기 검사 강화
# -pie -fPIE:             위치 독립 실행 파일 (ASLR 효과 극대화)
# -Wl,-z,relro,-z,now:    GOT 보호 (Full RELRO)
# -Wl,-z,noexecstack:     스택 실행 금지 표시
방어 기법대상동작
스택 카나리스택 오버플로우검사 지점에서 카나리 변조 탐지
ASLR주소 예측메모리 레이아웃 무작위화
DEP/NX코드 주입데이터 영역 실행 금지
PIE코드 영역 예측ASLR이 코드도 재배치할 수 있게 함
RELROGOT 변조GOT 영역 읽기 전용화
CFI간접 호출 변조제어 흐름 무결성 검증

악성 코드 분류

유형전파 방식특징예시
바이러스숙주 프로그램에 삽입실행 시 활성화, 자기 복제CIH, Melissa
웜네트워크 자동 전파독립 실행, 취약점 이용Morris, WannaCry
트로이 목마유용한 프로그램 위장백도어 설치Zeus, Emotet
랜섬웨어다양 (이메일, 웹)파일 암호화 후 몸값 요구WannaCry, Ryuk
루트킷기존 침입 후 설치사용자·커널 등 여러 계층에서 은닉Sony Rootkit
키로거트로이 목마/물리적키 입력 기록 전송-

위 악성 코드 분류는 겹칠 수 있습니다. 예를 들어 랜섬웨어가 웜 방식으로 전파될 수도 있으며, 이름 하나로 공격 경로나 방어법이 모두 정해지지는 않습니다.

실무 방어

integrity_check.py
import hashlib
import os

def file_hash(path):
    """파일의 SHA-256 해시 계산"""
    h = hashlib.sha256()
    with open(path, "rb") as f:
        for chunk in iter(lambda: f.read(8192), b""):
            h.update(chunk)
    return h.hexdigest()

# 중요 시스템 파일의 해시를 저장하고 주기적으로 비교
critical_files = ["/usr/bin/sudo", "/usr/bin/ssh", "/usr/sbin/sshd"]
for f in critical_files:
    if os.path.exists(f):
        print(f"{f}: {file_hash(f)}")

# 해시 변화는 정상 업데이트 또는 변조 가능성; 신뢰한 기준선·변경 이력과 대조
# 실무에서는 AIDE, Tripwire, OSSEC 같은 무결성 검사 도구 사용

위 해시 코드는 현재 값만 출력합니다. 신뢰한 기준선 저장·비교·알림을 구현한 감시 프로그램은 아니며, 침해된 OS 안에서 읽은 해시만으로 무결성을 보장하지 않습니다.

강제 접근 제어 (MAC)

일반적인 Unix 권한(DAC, Discretionary Access Control)은 파일 소유자가 권한을 마음대로 설정할 수 있습니다.

root 권한이 탈취되면 DAC 기반 보호의 많은 부분을 우회할 수 있습니다. 별도의 MAC 정책이나 다른 신뢰 경계까지 모두 자동으로 무력화되는 것은 아닙니다.

MAC(Mandatory Access Control)은 시스템 관리자가 정의한 정책에 따라 접근을 제어합니다.

정책이 enforcing 상태라면, root 권한 프로세스도 허용되지 않은 접근은 제한됩니다.

SELinux

NSA가 개발한 MAC 구현입니다.

프로세스마다 보안 컨텍스트(타입)를 부여하고, 정책에 명시적으로 허용된 접근만 가능합니다.

selinux_demo.sh
# SELinux 상태 확인
getenforce          # Enforcing, Permissive, Disabled
sestatus            # 상세 상태

# 파일의 보안 컨텍스트 확인
ls -Z /var/www/html/index.html
# -rw-r--r--. root root system_u:object_r:httpd_sys_content_t:s0

# httpd_t의 접근은 실제 정책·boolean·파일 타입 등에 따라 결정됨
# httpd_sys_content_t는 웹 콘텐츠용 타입의 한 예; 유일한 허용 타입은 아님

# 컨텍스트 복원
restorecon -Rv /var/www/html/

웹 서버 프로세스가 침해되더라도 confined 도메인에 갇혀 있다면, SELinux 정책에 의해 /etc/shadow 읽기나 임의 포트 변경 같은 행동이 차단될 수 있습니다.

AppArmor

프로그램별로 접근 가능한 파일, 네트워크, 커패빌리티를 프로파일로 정의합니다.

주로 경로 기반 규칙을 사용하며, 설정 난이도는 애플리케이션과 배포판 정책에 따라 다릅니다.

apparmor_profile.sh
# /etc/apparmor.d/usr.sbin.nginx 프로파일 예시
# /usr/sbin/nginx {
#   /var/www/** r,          # 웹 콘텐츠 읽기만
#   /var/log/nginx/** w,    # 로그 쓰기만
#   /run/nginx.pid rw,      # PID 파일
#   network inet tcp,       # TCP 네트워크 허용
#   deny /etc/shadow r,     # shadow 파일 읽기 명시적 거부
# }

# AppArmor 상태 확인
aa-status

# 위 주석은 일부 권한만 보인 발췌이며 완전한 nginx 프로파일이 아님
# 필요한 로더·라이브러리·설정 접근까지 갖춘 실제 프로파일을 enforce로 설정
aa-enforce /etc/apparmor.d/usr.sbin.nginx

네트워크 보안 기초

방화벽 (iptables/nftables)

firewall_basics.sh
# IPv4 filter 테이블의 최소 예시: 허용 규칙을 준비한 뒤 기본 정책 설정

# 기존 연결 유지
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# SSH (포트 22) 허용
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# HTTP/HTTPS 허용
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# 로컬 루프백 허용
iptables -A INPUT -i lo -j ACCEPT

# 허용 규칙 뒤에 기본 정책 적용
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

이 규칙은 기존 규칙이 없는 IPv4 실습 환경의 조각입니다. 기존 ACCEPT 규칙을 제거하지 않으며 IPv6·ICMP·다른 관리 포트·컨테이너 네트워크와 영속 저장까지 포함한 완성된 방화벽 설정은 아닙니다. 실제 원격 환경에서는 허용 경로와 복구 수단을 먼저 준비합니다.

보안 모니터링

security_monitoring.sh
# 실패한 로그인 시도 확인
grep "Failed password" /var/log/auth.log | tail -20

# 현재 열린 포트 확인
ss -tlnp

# 최근 sudo 사용 기록
grep sudo /var/log/auth.log | tail -10

# 비정상 프로세스 확인
ps aux --sort=-pcpu | head -20

보안 계층 정리

계층방어 수단
네트워크방화벽, IDS/IPS, VPN
운영체제MAC(SELinux/AppArmor), 패치 관리, 로깅
애플리케이션입력 검증, 안전한 함수, 코드 분석
데이터암호화, 해싱, 백업
물리잠금장치, BIOS 패스워드, TPM

보안은 OS의 한 기능이 아니라, 물리적 접근부터 애플리케이션 코드까지 전 계층에 걸친 노력입니다.

다음 장에서는 현대 인프라의 핵심인 가상화와 컨테이너를 다루겠습니다.