기타
2025-09-16
1분 읽기

System Hacking - vulnerability list

시스템 해킹이란 / 취약점 종류

1. System Hacking이란?

시스템 해킹(System Hacking) 이란, 프로그램이나 시스템의 취약점을 분석하고, 이를 이용해 권한을 획득하거나 정상적인 동작을 우회하여 원하는 동작을 하게 만드는 일련의 과정을 의미한다.
시스템이나 프로그램의 메모리 관리 오류나 논리적 오류를 이용하여 임의의 코드를 실행(RCE, Remote Code Execution)하거나 권한 상승(LPE, Local Privilege Escalation)을 목표로 하는 해킹 분야이다.

2. 소프트웨어 취약점

소프트웨어 취약점은 공격 방법에 따라 크게 2가지로 분류할 수 있다.

  • Memory Corruption : 프로그램이 개발자가 의도하지 않은 방식으로 동작하여 접근해서는 안되는 메모리 영역을 사용하거나 읽고 쓰는 등, 메모리의 내용이 Corruption(변형) 되는 취약점. Crash를 통해 판단할 수 있음.
  • Logical Bug : 프로그램의 논리적 오류로 발생하는 취약점. Crash가 발생하지 않으면 발견하기 어려움.

대표적인 취약점의 종류는 아래 표와 같다. [표 1] 취약점 종류 본 게시글에서는 각 취약점에 대한 간단한 설명을 다루고 자세한 내용은 별도의 게시글에서 다루도록 하겠다.

2-1. 버퍼 오버플로우 (Buffer Overflow)

할당한 버퍼보다 큰 데이터를 쓰면 인접한 메모리를 덮어써서 프로그램 흐름(리턴 주소 등)을 바꾸거나 데이터가 손상되는 취약점.

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

void vuln(char *input) {
    char buf[16];
    strcpy(buf, input); // 길이 검사 없음 -> 오버플로우 가능
    printf("buf: %s\n", buf);
}

int main(int argc, char **argv) {
    if (argc > 1) vuln(argv[1]);
    return 0;
}

대응방안: 경계 검사(strncpy, strlcpy), 스택 보호(ASLR, NX, stack canaries), 안전한 라이브러리 사용.

2-2. Use-After-Free

이미 해제(free)된 메모리를 계속 사용하면, 그 영역이 재할당되면서 예기치 않은 동작(정보 유출, 코드 실행)을 초래할 수 있는 취약점.

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

int main() {
    char *p = malloc(16);
    strcpy(p, "hello");
    free(p);
    // p를 여전히 사용
    printf("%s\n", p); // UAF: 이미 free된 메모리 접근
    return 0;
}

대응방안: free 후 포인터를 NULL로 만들기, 소유권 명확화, 메모리 할당 라이프사이클 관리.

2-3. Double Free 버그

동일한 메모리 블록을 두 번 이상 해제하면 힙 상태가 손상되어 공격자가 힙을 조작할 수 있는 취약점.

#include <stdlib.h>

int main() {
    char *p = malloc(32);
    free(p);
    free(p); // double free -> 정의되지 않은 동작(힙 손상)
    return 0;
}

대응방안: free 후 포인터 NULL 처리, 소유권 규칙(한 곳에서만 free), 메모리 관리 도구 사용(valgrind 등).

2-4. 포맷 문자열 버그 (Format String Bug)

공격자가 제어하는 문자열을 printf 계열에 직접 전달하면 메모리 읽기/쓰기(예: %x, %n)로 이어질 수 있는 취약점.

#include <stdio.h>

int main(int argc, char **argv) {
    if (argc > 1) {
        printf(argv[1]); // 안전하지 않음: 포맷 문자열 취약점
    }
}

공격 입력 예: "%x %x %x %x" 또는 "%s" 등. %n은 메모리 쓰기 가능. 대응방안: printf("%s", user_input);처럼 고정 포맷 사용, 입력 검증.

2-5. 범위 밖 접근 (Out-of-Bounds Read/Write)

배열/버퍼의 유효 범위를 벗어나 읽거나 쓰면 인접 데이터 손상 또는 정보 유출이 발생.

#include <stdio.h>

int main() {
    int arr[4] = {1,2,3,4};
    printf("%d\n", arr[5]); // OOB read: 정의되지 않은 값/정보 유출 가능
    arr[6] = 9;             // OOB write: 메모리 손상
    return 0;
}

대응방안: 인덱스 검사, 안전한 컬렉션 사용, 정적/동적 분석 도구.

2-6. 커맨드 인젝션 (Command Injection)

외부 입력을 커맨드에 그대로 연결해 시스템 명령을 실행하게 하면 임의 명령 실행으로 이어지는 취약점(특히 쉘 호출 시).

import os
def run(user):
    os.system("ls " + user)  # user가 "`; rm -rf /`" 같은 문자열을 주면 위험

대응방안: 명령어 인자 분리(예: subprocess.run([...], check=True)), 입력 검증, 화이트리스트.

2-7. 정수 오버플로우 (Integer Overflow)

정수 연산에서 최대값을 넘기면 값이 래핑되어 잘못된 크기/주소 계산으로 보안 취약점(버퍼 크기 오류 등)을 유발.

#include <stdlib.h>
#include <string.h>

void allocate_and_copy(size_t n) {
    size_t size = n * sizeof(int); // 오버플로우 가능
    int *p = malloc(size);
    if (!p) return;
    memset(p, 0, size);
}

int main() {
    allocate_and_copy(0xFFFFFFFF); // 곱셈 오버플로우 -> 작은 할당, 이후 OOB
    return 0;
}

대응방안: 범위 검사(overflow-safe 계산), 정수 산술 검증, 안전한 API 사용.

2-8. 경쟁 상태 (Race Condition)

동시성 상황에서 실행 순서에 따라 상태가 달라지는 문제 — 예: TOCTOU(time-of-check-to-time-of-use)로 권한 우회 가능.

// 파일 존재 확인 후 바로 파일 생성/열기 하는 사이 다른 프로세스가 파일 변경 가능
if (access("file.tmp", R_OK) == 0) {
    fd = open("file.tmp", O_RDWR); // TOCTOU 취약점 가능
}

대응방안: 원자적 연산 사용(예: O_CREAT|O_EXCL), 락/동기화, 권한 검증 재확인.

2-9. 타입 혼동 (Type Confusion)

오브젝트의 실제 타입과 예상 타입이 일치하지 않을 때 발생. 잘못된 타입으로 동작하면 메모리 안전성 위반(읽기/쓰기)이나 코드 실행으로 이어질 수 있음. 주로 C++ 캐스트, 언어 런타임 버그, 직렬화/역직렬화에서 발생.

Base* b = getSomeObject();
Derived* d = static_cast<Derived*>(b); // 실제로 b가 Derived가 아니면 위험
d->someDerivedMethod(); // 타입 혼동으로 정의되지 않은 동작

대응방안: 런타임 타입 체크(dynamic_cast), 안전한 직렬화, 타입 시스템/검증 강화.

2-10. 메모리 손상 취약점들의 공통 대응방안

  • 컴파일러/런타임 보호: ASLR, DEP/NX, stack canaries, Control-Flow Integrity(CFI)
  • 안전한 라이브러리와 API 사용, 바운드 체크, 입력 검증
  • 정적/동적 분석 도구(ASan, Valgrind, static analyzers) 사용
  • 최소 권한 원칙과 안전한 코딩 규약