Step 107. 리눅스 로그 탐구 — /var/log

Step 107. 리눅스 로그 탐구 — /var/log

Level 2 — 보안 입문과 공격 스킬 기초 | 난이도 ★★☆☆☆ | 예상 소요 시간 2.5시간

전제: Step 20의 grep·find, Step 26의 프로세스 개념, Step 27의 디렉토리 구조. root 또는 sudo 권한이 있는 리눅스(WSL 가능).

  • 준비물: 리눅스 터미널. WSL도 됩니다 — 오늘의 실측은 전부 WSL 우분투에서 했습니다.
  • ⚠️ 이 챕터의 실습은 내 랩·합법 플랫폼 전용입니다. 허가 없는 시스템에 적용하면 범죄입니다.
  • 주의: 로그 읽기는 시스템을 바꾸지 않는 안전한 조회입니다. 다만 로그에는 다른 사용자의 기록도 들어 있으니, 공유 서버라면 읽기 범위를 내 작업 확인으로 한정하세요.

지금까지 우리는 "문을 뚫는 쪽"의 기술을 배웠습니다. 오늘은 시선을 바꿉니다 — 누가 언제 문을 두드렸는가를 기록하는 곳, /var/log를 읽습니다. 리눅스에서 일어난 일은 거의 전부 이 폴더에 흔적을 남깁니다. 로그인 성공과 실패, sudo 사용, 서비스의 시작과 죽음까지.

로그는 공방의 핵심 전장입니다. 공격자는 침입 후 로그를 지우거나 조작하려 하고, 방어자는 로그를 읽어 침입을 재구성합니다. 오늘은 양쪽 모두의 첫걸음 — "로그가 어디 있고, 한 줄을 어떻게 읽는가"를 몸에 익힙니다. 그리고 직접 사건을 일으켜 로그가 찍히는 것을 지켜볼 것입니다.


1. 학습 목표

이 챕터를 끝내면 다음을 할 수 있습니다:

  • /var/log의 주요 파일(auth.log, syslog, kern.log, wtmp 등)의 역할을 말한다
  • 로그 한 줄을 시각·호스트·프로세스·메시지로 해부해 읽는다
  • grep으로 로그인 성공/실패와 sudo 사용 기록을 찾아낸다
  • 로그 로테이션(.1, .gz)의 이유와 읽는 법을 안다
  • 로그 삭제·위조의 개념과 그 대응(로테이션, 원격 전송)을 설명한다

2. 배경 지식 — 오늘의 도구와 개념

오늘의 도구 한눈에 보기

구분 내용
언어·환경 리눅스 셸 + 텍스트 검색
오늘의 명령어 ls -la /var/log, tail, grep -a, zcat, last, journalctl
필요한 개념 syslog 형식, 로그 로테이션(logrotate), 인증 로그, 바이너리 로그(wtmp), 원격 로그 전송
오늘의 산출물 "내가 일으킨 사건 → 로그 한 줄" 대조 기록

2-1. /var/log — 사건 기록부의 보관소

/var는 "변하는(variable) 데이터"의 폴더이고, 그 안의 log가 기록 보관소입니다. 배포판과 설치된 서비스에 따라 내용이 다르지만, 우분투 계열의 핵심 멤버는 정해져 있습니다.

파일 기록하는 것
auth.log 로그인·su·sudo 등 인증 사건 (우분투/데비안 계열)
syslog 시스템 전반의 메시지 (인증 외 전부)
kern.log 커널 메시지 — 드라이버, 방화벽 로그 등
dpkg.log, apt/ 패키지 설치·삭제 기록
wtmp, btmp 로그인 성공(wtmp)·실패(btmp)의 바이너리 기록
journal/ systemd 저널 — 요즘 시스템의 병행 기록

CentOS/Rocky 계열에서는 auth.logsecure라는 이름입니다. 이름만 다르고 역할은 같습니다.

2-2. 로그 한 줄의 해부

syslog 계열의 한 줄은 네 조각입니다.

2026-09-09T15:27:27+09:00  mypc  su:  pam_unix(su:auth): authentication failure; ...
└── 시각(시간대 포함) ──┘  └호스트┘ └주체┘ └──────── 메시지 ────────┘

읽는 순서는 거꾸로가 편합니다 — 메시지를 먼저 읽어 "무슨 사건인지"를 파악하고, 시각으로 언제인지, 주체로 누가(어떤 프로그램이) 남겼는지를 확인합니다.

2-3. 로그 로테이션 — 기록부는 찢어서 보관한다

로그는 영원히 커질 수 없습니다. 디스크를 삼키기 전에 시스템은 오래된 로그를 잘라 보관합니다 — 이것이 로테이션이고, logrotate가 담당합니다. auth.log가 꽉 차면 auth.log.1로 이름이 바뀌고, 더 오래되면 auth.log.2.gz처럼 압축됩니다. 그래서 "어제 사건"을 찾을 때는 .1.gz까지 뒤져야 합니다.

2-4. 공방의 전장 — 지우는 자와 지키는 자

공격자가 침입에 성공하면 로그가 가장 위험한 증인입니다. 그래서 하는 짓이 정해져 있습니다 — 자기 줄만 지우거나, 파일을 통째로 지우거나, 로그를 쓰는 프로그램(rsyslog)을 멈추거나. 방어자의 대응도 정해져 있습니다 — 로그를 생성 즉시 다른 서버로 전송(원격 로깅)해, 침입당한 머신에서 지워도 사본이 남게 하는 것입니다. 오늘은 이 공방의 무대를 지도로 익히는 날입니다.


3. 따라 하기

3-1. /var/log 구경하기 (실측)

ls -la /var/log/

출력 (2026-09-09 실측, WSL Ubuntu 24.04 — 환경에 따라 다릅니다):

-rw-r--r--   1 root   root    25855 Sep  8 21:12 alternatives.log
drwxr-xr-x   2 root   root     4096 Sep  8 21:12 apt
-rw-r-----   1 syslog adm     63461 Sep  9 15:12 auth.log
-rw-rw----   1 root   utmp        0 Feb 10  2026 btmp
-rw-r--r--   1 root   root   460954 Sep  8 21:13 dpkg.log
-rw-r-----   1 syslog adm   1094645 Sep  9 15:07 kern.log
-rw-r-----   1 syslog adm   4070410 Sep  9 15:12 syslog
-rw-rw-r--   1 root   utmp   130176 Sep  9 15:07 wtmp
drwxr-sr-x+  3 root   systemd-journal 4096 Sep  8 21:11 journal
(일부 생략)

읽는 법: 권한부터 봅시다. auth.log-rw-r----- syslog adm — 소유자 syslog만 쓰고, adm 그룹만 읽습니다. 인증 기록은 아무나 못 읽게 되어 있습니다. 여러분이 읽으려면 sudo가 필요하거나 adm 그룹이어야 합니다. Step 23~24의 권한 지식이 바로 여기서 쓰입니다.

3-2. 사건을 일으키고 실시간으로 잡기 (실측)

로그는 읽는 것보다 "찍히는 것을 보는 것"이 백 배 빨리 이해됩니다. sudo를 한 번 실행해 사건을 일으키고, 바로 확인합니다.

sudo -n true
sleep 1
sudo tail -5 /var/log/auth.log

출력 (2026-09-09 실측, 경로와 호스트명은 가공):

2026-09-09T15:12:49+09:00 mypc sudo:     root : TTY=pts/0 ; PWD=/home/user/project ; USER=root ; COMMAND=/usr/bin/true
2026-09-09T15:12:49+09:00 mypc sudo: pam_unix(sudo:session): session opened for user root(uid=0) by (uid=0)
2026-09-09T15:12:49+09:00 mypc sudo: pam_unix(sudo:session): session closed for user root

읽는 법: 방금 친 sudo가 세 줄로 기록됐습니다. 첫 줄의 네 조각 — TTY(어느 터미널), PWD(어느 폴더에서), USER(누구로), COMMAND(무엇을). 여러분이 지금 이 챕터를 공부하고 있다는 사실조차 로그에 남는다는 체감이 오늘의 핵심 경험입니다. 침입자의 명령도 똑같이 남습니다.

3-3. 실패한 로그인 찾기 (실측)

이번엔 일부러 실패를 만듭니다. 잘못된 비밀번호로 su를 시도합니다.

su -s /bin/sh nobody -c "echo wrongpw | su -c true root"
sudo grep -a "fail" /var/log/auth.log | tail -2

출력 (2026-09-09 실측):

2026-09-09T15:27:27+09:00 mypc su: pam_unix(su:auth): authentication failure; logname= uid=65534 euid=0 tty= ruser=nobody rhost=  user=root
2026-09-09T15:27:30+09:00 mypc su[660]: FAILED SU (to root) nobody on none

읽는 법: "누가(ruser=nobody) 누구로 되려다(user=root) 실패했는가"가 명확합니다. 인터넷에 노출된 서버의 auth.log에는 Failed password for ... from <IP> 형태의 무차별 로그인 시도가 하루에도 수천 줄씩 쌓입니다 — 방어자가 가장 먼저 보는 줄입니다.

여기서 -a 옵션에 주목하세요. 그냥 grep sudo /var/log/auth.log를 치면 이렇게 나올 수 있습니다 (2026-09-09 실측):

grep: /var/log/auth.log: binary file matches

원인: 로그 파일에 NUL 바이트가 섞여 있으면 grep이 파일을 "바이너리"로 판정해 내용을 안 보여 줍니다. -a(text로 강제)를 붙이면 해결됩니다.

3-4. 바이너리 로그 — wtmp는 cat이 아니라 last로 (실측)

wtmp는 텍스트가 아니라 구조화된 바이너리라 cat으로 읽으면 깨집니다. 전용 도구가 있습니다.

last -5

출력 (2026-09-09 실측):

reboot   system boot  6.18.33.2-micros Wed Sep  9 15:07   still running
reboot   system boot  6.18.33.2-micros Wed Sep  9 14:32 - 14:32  (00:00)
reboot   system boot  6.18.33.2-micros Wed Sep  9 14:29 - 14:31  (00:02)

wtmp begins Tue Sep  8 21:11:41 2026

읽는 법: "언제 부팅했고 얼마나 켜져 있었나"가 나옵니다. 사용자 로그인이 있는 시스템에서는 사용자명 tty 출발지IP 시각 행이 함께 나옵니다 — 침입 시각 재구성의 첫 자료입니다. "로그인 실패"의 바이너리판인 btmp는 lastb로 읽습니다.

3-5. 로테이션된 로그 읽기 (실측)

ls /var/log/*.gz
zcat /var/log/dmesg.1.gz | head -1
grep "rotate\|weekly" /etc/logrotate.conf

출력 (2026-09-09 실측):

/var/log/dmesg.1.gz  /var/log/dmesg.2.gz  /var/log/dmesg.3.gz  ...
[    0.000000] kernel: Linux version 6.18.33.2-microsoft-standard-WSL2 ...
weekly
rotate 4

읽는 법: .gz로 압축된 옛 로그는 zcat(압축을 풀며 출력)으로 읽습니다. logrotate.confweekly + rotate 4는 "매주 자르고 4개까지 보관" — 즉 이 시스템의 기억은 약 4주라는 뜻입니다. 사고 조사는 로그가 지워지기 전에 시작해야 하는 이유입니다.

3-6. journalctl — systemd의 병행 기록 (실측)

요즘 배포판은 syslog와 별도로 systemd 저널도 씁니다.

journalctl -n 3 --no-pager

출력 (2026-09-09 실측, WSL — 없는 환경도 있으며, 그 경우 3-1~3-5로 충분합니다):

Sep 09 15:12:14 mypc systemd[1]: Stopped user-runtime-dir@65534.service - User Runtime Directory /run/user/65534.
...

읽는 법: 같은 사건이지만 도구가 다릅니다. journalctl -u 서비스명(특정 서비스만), -p err(에러 이상만), --since "1 hour ago"(시간 조건)가 실무 3종 세트입니다.

3-7. 공격자 시선으로 다시 보기 (개념 정리)

오늘 본 것을 공격자의 할 일 목록으로 뒤집어 봅시다 — 방어가 보이기 위한 반대 읽기입니다.

  1. 침입하면 auth.log와 wtmp에 내 접속이 남는다 → 지우고 싶다
  2. 하지만 파일 통째 삭제는 wtmp begins 날짜의 공백처럼 삭제 자체의 흔적을 남긴다
  3. 로그를 외부 서버로 실시간 전송해 두면 지워도 소용없다
  4. 그래서 성숙한 방어는 "로그를 남기는 것"이 아니라 "로그를 빼돌려 두는 것"

로그 위조·삭제의 기법 자체는 실습하지 않습니다. "왜 그것이 통하지 않게 만드는가"를 이해하는 것이 오늘의 방어 소양입니다.


4. 미션과 연습문제

미션 — 사건 재구성 연습

  1. 터미널에서 sudo를 한 번 실행하고, 방금 생성된 sudo 로그 줄을 찾아 네 조각(TTY/PWD/USER/COMMAND)을 메모합니다
  2. 일부러 실패한 su를 한 번 만들고, FAILED SU 줄을 grep으로 찾아냅니다
  3. last -5로 최근 부팅·로그인 기록을 읽고 현재 세션(또는 부팅) 하나를 식별합니다
  4. 위키에 "사건 → 로그 줄" 대조표를 만듭니다 — 내가 한 일 세 개와 그에 대응하는 로그 줄 세 개

연습문제

문제 1. auth.log 한 줄 ... mypc su[660]: FAILED SU (to root) nobody on none에서 알 수 있는 것을 최대한 많이 나열해 보세요.

문제 2. wtmpcat으로 읽으면 안 되는 이유와, 대신 쓰는 명령을 말해 보세요.

문제 3. logrotate 설정이 weekly, rotate 4일 때, 6주 전의 인증 사건을 조사하려면 어떤 문제가 생기나요?

문제 4. 공격자가 침입 서버의 auth.log를 통째로 삭제했는데도 방어자가 침입 기록을 확보할 수 있는 구조를 한 가지 설명해 보세요.


5. 모범 답안과 완료 기준

미션 모범 답안

대조표의 모범 형식 (2026-09-09 실측 기반, 가공):

내가 한 일 로그 줄 (핵심 부분)
sudo -n true sudo: root : TTY=pts/0 ; PWD=... ; COMMAND=/usr/bin/true
틀린 비밀번호로 su root su[660]: FAILED SU (to root) nobody on none
(시스템 부팅) last 출력의 reboot system boot ... still running

검증하는 법: ① sudo 로그에서 COMMAND가 내가 친 명령과 정확히 일치하는가. ② FAILED SU 줄의 ruser(시도한 사람)와 user(목표 계정)를 구분해 읽었는가. ③ last 출력에서 "wtmp begins" 날짜를 확인했는가 — 그 날짜가 이 로그의 기억 시작점입니다.

연습문제 해답

문제 1 해답. 시각(초 단위와 시간대), 호스트명, 주체 프로그램(su와 PID 660), 사건의 종류(실패한 신분 전환), 시도자(nobody), 목표(root), 단말 정보(none — 터미널 없이 실행됐다는 뜻으로 스크립트 경유의 신호). 한 줄에서 이 정도를 읽어 내는 것이 로그 분석의 기본기입니다.

문제 2 해답. wtmp는 사람이 읽는 텍스트가 아니라 프로그램이 쓰는 바이너리 구조체의 나열이라, cat으로 읽으면 깨진 문자가 나옵니다. last가 이 구조를 해석해 보여 줍니다 (실패 기록 btmp는 lastb).

문제 3 해답. 4개까지만 보관하므로 6주 전의 로그는 이미 삭제되었을 가능성이 높습니다. 사고 조사에서 "로그 보관 기간이 사고 시점을 덮는가"가 첫 확인 사항이며, 장기 보관이 필요하면 원격 로그 서버나 별도 백업이 필수입니다.

문제 4 해답. rsyslog 등으로 로그를 생성 즉시 외부 로그 서버로 전송해 두면, 침입 서버에서 원본을 지워도 사본이 남습니다. 공격자가 두 대를 모두 장악하지 않는 한 기록이 생존합니다 — 이것이 "로그는 남기는 게 아니라 빼돌리는 것"이라는 말의 실체입니다.

완료 기준 체크리스트

  • [ ] /var/log의 핵심 파일 4개(auth.log, syslog, kern.log, wtmp)의 역할을 말할 수 있다
  • [ ] auth.log가 왜 일반 사용자에게 닫혀 있는지 권한으로 설명할 수 있다
  • [ ] 로그 한 줄을 시각·호스트·주체·메시지로 해부할 수 있다
  • [ ] grep -a가 필요한 상황(바이너리 판정)을 설명할 수 있다
  • [ ] wtmp/btmp는 전용 명령(last/lastb)으로 읽어야 함을 안다
  • [ ] 로테이션 파일(.1, .gz)을 zcat으로 읽을 수 있다
  • [ ] 미션: 사건 재구성 대조표를 완성했다

6. 흔한 실수와 해결

벽 1. auth.log가 없다

증상: ls: cannot access '/var/log/auth.log': No such file or directory.
원인: 배포판 차이입니다 — CentOS/Rocky는 /var/log/secure를 씁니다. WSL이나 컨테이너는 로깅 서비스(rsyslog)가 안 떠 있어 아예 없을 수도 있습니다.
해결: ls /var/log/로 무엇이 있는지부터 보세요. syslog 계열 파일이 하나도 없고 journal/만 있으면 journalctl 중심으로 읽으면 됩니다. (본 챕터의 실측은 WSL Ubuntu 24.04에서 auth.log가 존재하는 환경이었습니다.)

벽 2. grep이 "binary file matches"만 뱉는다

증상 (2026-09-09 실측):

grep: /var/log/auth.log: binary file matches

원인: 로그에 NUL 바이트가 섞여 grep이 바이너리로 판정했습니다.
해결: grep -a를 붙이세요. "로그는 항상 순수 텍스트다"는 가정이 깨지는 순간이니 기억해 둘 만합니다.

벽 3. Permission denied로 로그를 못 읽는다

증상: tail: cannot open '/var/log/auth.log' for reading: Permission denied.
원인: 3-1에서 본 권한 때문입니다 — auth.log는 소유자 syslog와 adm 그룹만 읽습니다.
해결: sudo tail ...로 읽거나, 관리받는 서버라면 adm 그룹에 속하는지 groups로 확인하세요.

벽 4. 분명 일어난 일인데 로그에 없다

증상: 방금 한 작업의 기록이 안 보입니다.
원인: ① 이미 로테이션되어 .1이나 .gz로 넘어갔거나, ② 보는 파일이 틀렸거나(인증은 auth.log, 서비스는 syslog/journal), ③ 일부 서비스는 자체 로그(/var/log/서비스명/)에 씁니다.
해결: ls -lt /var/log/ | head최근 수정된 로그부터 확인하세요. 사건 직후 갱신된 파일이 범인입니다.

벽 5. journalctl이 없거나 비어 있다

증상: 명령이 없거나 -- No entries --.
원인: WSL·컨테이너 등 systemd가 제한된 환경입니다.
해결: 정상입니다. syslog 파일들로 읽으세요. 반대로 journal만 있고 파일이 없는 시스템도 있으니, 둘 다 읽을 줄 알면 어디서든 막히지 않습니다.


7. 정리

오늘의 개념

개념 한 줄 설명
auth.log 인증 사건의 보관소 (우분투) — CentOS는 secure
syslog 인증 외 시스템 전반의 메시지
로그 로테이션 오래된 로그를 잘라 .1.gz로 보관, logrotate가 담당
wtmp/btmp 로그인 성공/실패의 바이너리 기록 — last/lastb로 읽음
journalctl systemd 저널을 읽는 도구 — syslog와 병행
원격 로깅 로그를 즉시 외부로 전송해 삭제 공격을 무력화하는 방어
삭제의 흔적 로그를 지우면 "지워진 구간" 자체가 증거가 된다

오늘의 명령어

명령 하는 일
ls -la /var/log/ 로그 목록과 권한 확인
sudo tail -f /var/log/auth.log 인증 로그 실시간 감시
sudo grep -a "패턴" /var/log/auth.log 로그 검색 (-a = 텍스트 강제)
last / lastb 로그인 성공/실패 이력 (wtmp/btmp)
zcat 파일.gz 압축된 옛 로그 읽기
journalctl -n 10 systemd 저널 최근 10줄
ls -lt /var/log/ | head 최근 갱신된 로그부터 보기

명령어보다 중요한 감각

로그를 읽는 능력은 "시스템에게 무슨 일이 있었는지 묻는 능력"입니다. 공격자 관점에서 오늘의 교훈은 명확합니다 — 모든 행동은 기록된다. 워게임에서는 상관없지만 실전에서는 명령 한 줄이 증거 한 줄입니다. 방어자 관점에서는 더 단순합니다 — 사건이 나면 auth.log부터, 시간 순으로, 실패한 기록부터 읽는 것. 그리고 로그 보관 기간과 원격 전송 여부를 미리 확인해 두는 것. 오늘 sudo 한 번이 세 줄의 로그를 남기는 것을 본 눈은, 앞으로 어떤 시스템에서도 "조용한 행동"을 의심하게 될 것입니다.


전부 체크되면 Step 107 완료입니다. 사이드바의 체크박스를 눌러 진도를 저장하세요.