리눅스 시스템 기초 · 입문편 — 본문의 "N편"은 입문 과정 번호다. 번호별 글과 전체 250편 구성은 통합 로드맵에서 확인할 수 있다.

리눅스 시스템 기초 3 / 50 · Part 1. Linux 기본 구조
실습 환경: Rocky Linux 9 (10.0.0.200) · 비교: Ubuntu 22.04
이전 글: 2. Linux Kernel의 역할

1. 들어가며

1편에서 Shell은 "명령을 해석해 fork()와 execve()로 실행하는 프로그램"이라고 정리했다. 이번 글은 그 Shell, 특히 대부분의 Linux 서버에서 기본으로 쓰는 Bash 를 자세히 본다.

관제 관점에서 Bash를 알아야 하는 이유는 명확하다. 공격자가 서버에 침투해서 가장 먼저 얻으려는 것이 쉘(명령 실행 환경) 이고, 침투 후 남기는 흔적의 상당 부분이 Bash 설정 파일과 명령 이력 에 있다.

이번 글에서 답할 질문:

  • Shell의 종류와 Bash의 위치는?
  • 로그인할 때 어떤 설정 파일이 어떤 순서로 실행되는가?
  • 명령 이력(history)은 언제, 어디에, 어떻게 저장되는가?
  • 공격자는 이 구조를 어떻게 악용하고, 관제에서는 무엇을 확인하는가?

2. 핵심 개념

2-1. Shell의 종류

Shell특징주로 쓰이는 곳
shPOSIX 표준 쉘스크립트 호환성 기준
bashsh 호환 + 이력·자동완성·배열 등 기능 확장RHEL·Ubuntu 로그인 쉘 기본값
dash가볍고 빠른 POSIX 쉘Ubuntu의 /bin/sh (시스템 스크립트용)
zsh확장 기능, 플러그인macOS 기본, 개인 개발 환경

Rocky Linux의 /bin/sh는 bash를 가리키고, Ubuntu의 /bin/sh는 dash를 가리킨다. ls -l /bin/sh로 확인할 수 있다. 같은 스크립트가 배포판마다 다르게 동작하는 원인이 되기도 한다.

2-2. 사용자의 기본 쉘은 어디에 정해지는가

/etc/passwd의 마지막 필드가 로그인 쉘이다.

roror:x:1000:1000:roror:/home/roror:/bin/bash
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin

/sbin/nologin은 로그인을 거부하는 쉘이다. 서비스 계정은 원래 이렇게 설정되어 있어야 하며, 서비스 계정의 쉘이 /bin/bash로 바뀌어 있다면 점검 대상 이다.

2-3. 쉘의 실행 방식 4가지

구분예읽는 설정 파일
로그인 + 대화형SSH 접속, su -/etc/profile → ~/.bash_profile 등
비로그인 + 대화형로그인 후 bash 입력, 새 터미널 창~/.bashrc
비대화형bash script.sh, cron 작업(원칙적으로 대화형 설정 파일을 읽지 않음)
원격 명령ssh host 'uptime'비대화형으로 실행

3. 동작 원리

3-1. 시작 파일 실행 순서

Bash 시작 파일 실행 순서와 관제 포인트

로그인 쉘은 /etc/profile을 먼저 읽고, 사용자 홈의 ~/.bash_profile, ~/.bash_login, ~/.profile 중 처음 발견한 하나만 실행한다. RHEL 계열은 ~/.bash_profile이 ~/.bashrc를 호출하고, ~/.bashrc가 다시 /etc/bashrc를 호출하는 구조다.

즉, 로그인할 때마다 여러 파일이 자동으로 실행된다. 이것이 편리함의 원천이자 공격자의 지속성(Persistence) 경로다.

3-2. 명령어 해석 순서 (확장)

Bash는 명령을 실행하기 전에 다음 순서로 확장(expansion)한다.

입력: echo ~/logs/{secure,messages} $USER $(date +%F) *.log
  ↓ 1. 중괄호 확장     ~/logs/secure ~/logs/messages
  ↓ 2. 틸드 확장       /home/roror/logs/...
  ↓ 3. 변수 확장       $USER → roror
  ↓ 4. 명령 치환       $(date +%F) → 2026-09-23
  ↓ 5. 산술 확장       $((1+1))
  ↓ 6. 단어 분리
  ↓ 7. 경로명 확장     *.log → 실제 파일 목록
실행

따옴표에 따라 확장 여부가 달라진다.

표기변수·명령 치환예
'...' 작은따옴표하지 않음echo '$HOME' → $HOME
"..." 큰따옴표함echo "$HOME" → /home/roror

로그 분석에서 grep에 정규식을 넘길 때 작은따옴표를 쓰는 이유가 이것이다. 쉘이 먼저 *나 $를 해석해 버리면 의도와 다른 패턴이 전달된다.

3-3. history가 저장되는 방식

변수의미기본값(대체로)
HISTFILE이력 파일 경로~/.bash_history
HISTSIZE메모리에 유지할 개수1000
HISTFILESIZE파일에 저장할 개수1000
HISTTIMEFORMAT실행 시각 기록 형식없음 (시각 미기록)
HISTCONTROL저장 제외 규칙ignoredups 등

중요한 사실 두 가지:

  1. 명령 이력은 셸이 종료될 때 파일에 기록 된다. 세션이 끊기지 않은 상태라면 아직 파일에 없을 수 있다.
  2. 기본 설정에서는 실행 시각이 기록되지 않는다. HISTTIMEFORMAT을 설정해야 시각이 남는다.

4. 실습

# 1) 현재 쉘 확인
echo $SHELL          # 로그인 쉘 (passwd에 지정된 값)
echo $0              # 현재 실행 중인 쉘 이름 (-bash 면 로그인 쉘)
ps -p $$ -o pid,ppid,cmd
cat /etc/shells
ls -l /bin/sh

# 2) 계정별 로그인 쉘 확인
awk -F: '{print $1, $7}' /etc/passwd | column -t

# 3) 명령어 종류 확인
type cd ls ll
alias

# 4) 시작 파일 확인
ls -la --time-style=full-iso ~/.bash* /etc/profile /etc/bashrc
ls -la /etc/profile.d/

# 5) history에 시각 기록 설정 (본인 계정)
echo 'export HISTTIMEFORMAT="%F %T "' >> ~/.bashrc
source ~/.bashrc
history | tail -5

5. 결과 분석

아래 출력은 형식 설명용 예시다.

① echo $0

결과의미
-bash앞에 -가 붙으면 로그인 쉘
bash비로그인 쉘

② awk -F: '{print $1, $7}' /etc/passwd

root     /bin/bash
bin      /sbin/nologin
apache   /sbin/nologin
roror    /bin/bash

사람이 쓰는 계정만 /bin/bash이고 나머지는 /sbin/nologin인 것이 정상 패턴이다.

③ history (HISTTIMEFORMAT 설정 후)

  101  2026-09-23 10:12:03 sudo tail -n 20 /var/log/secure
  102  2026-09-23 10:13:40 ss -tulnp

시각이 남으면 다른 로그(/var/log/secure, auditd)와 같은 타임라인에 올려 비교 할 수 있다. 관제 환경에서는 /etc/profile.d/에 전사 공통으로 설정하는 경우가 많다.


6. 보안 관점

공격 기법방법흔적
시작 파일 지속성~/.bashrc, /etc/profile.d/*.sh에 명령 삽입 → 로그인할 때마다 실행파일 수정 시각 변경, 낯선 명령 줄
alias 가로채기alias sudo='...'로 비밀번호 입력을 가로챔alias, type sudo 결과가 alias로 표시
이력 회피unset HISTFILE, HISTFILE=/dev/null, ~/.bash_history를 /dev/null 링크이력 파일 크기 0, 심볼릭 링크
이력 삭제history -c, 파일 삭제로그인 기록은 있는데 이력이 비어 있음
쉘 변경서비스 계정 쉘을 /bin/bash로 변경/etc/passwd 변경, usermod 기록

여기서 중요한 점은 bash history는 증거로서 한계가 있다 는 것이다. 사용자가 쉽게 지우거나 끌 수 있기 때문이다. 그래서 관제에서는 history를 참고 자료로 보고, 사용자가 조작하기 어려운 auditd(커널 수준의 실행 기록) 나 SIEM으로 이미 전송된 로그 를 핵심 증거로 삼는다.


7. SOC / 보안관제 활용

7-1. 침해 의심 시 쉘 관련 점검

# 시작 파일 최근 변경 여부 (최근 7일)
sudo find /etc/profile /etc/profile.d /etc/bashrc -type f -mtime -7
sudo find /root /home -maxdepth 2 -name '.bash*' -mtime -7

# history 파일 이상 여부 (크기 0, /dev/null 링크)
sudo ls -la /root/.bash_history /home/*/.bash_history

# 로그인 가능한 쉘을 가진 계정
awk -F: '$7 !~ /(nologin|false)$/ {print $1, $7}' /etc/passwd

7-2. auditd로 실행 명령 기록

history에 의존하지 않고 커널 수준에서 명령 실행을 기록하려면 execve 감사 규칙을 사용한다(5편 System Call에서 자세히 다룬다).

# /etc/audit/rules.d/exec.rules
-a always,exit -F arch=b64 -S execve -F auid>=1000 -F auid!=unset -k user_exec

auid는 로그인할 때 부여되어 sudo·su를 거쳐도 바뀌지 않는 원래 사용자 ID 다. 그래서 "누가 root로 이 명령을 실행했는가"를 추적할 때 핵심 필드가 된다.

7-3. 판단 흐름

[Event]   로그인 성공(secure) 이후 history 비어 있음
   ↓
[IOC]     ~/.bash_history → /dev/null 링크, ~/.bashrc 최근 수정
   ↓
[분석]    auditd user_exec 이벤트로 실제 실행 명령 복원
   ↓
[판단]    의도적 흔적 삭제 → 침해 의심 등급 상향
   ↓
[대응]    시작 파일 원본 보존(해시) → 삽입된 명령 분석 → 계정 조치

8. 핵심 정리

  • Bash는 RHEL·Ubuntu 서버의 기본 로그인 쉘이다. Ubuntu의 /bin/sh는 dash라는 차이가 있다.
  • 로그인 쉘은 /etc/profile → ~/.bash_profile(또는 .bash_login, .profile 중 하나) → ~/.bashrc 순으로 설정을 읽는다.
  • 로그인할 때 자동 실행되는 파일은 지속성(Persistence) 공격 경로 다. 수정 시각과 내용을 점검한다.
  • history는 셸 종료 시 저장 되고, 기본적으로 시각이 없다. HISTTIMEFORMAT으로 보완한다.
  • history는 사용자가 지울 수 있어 증거 가치가 제한적이다. auditd의 auid 기반 실행 기록 이 더 신뢰할 수 있다.
  • 서비스 계정의 쉘이 /sbin/nologin인지 확인한다.

9. 다음 글

다음 글 「4. User Space와 Kernel Space」 에서는 1·2편에서 나온 두 공간의 경계를 메모리 관점에서 더 깊게 본다. 프로세스마다 독립된 가상 메모리가 어떻게 구성되는지, 커널 스레드는 어떻게 구분하는지, 그리고 커널 스레드처럼 이름을 위장한 악성 프로세스를 어떻게 찾아내는지 다룬다.


참고 자료

profile
코드에 숨겨진 위협을 읽고 AI로 보안의 미래를 설계합니다. 프론트엔드 개발 경험을 자산 삼아 더 견고하고 지능적인 보안 운영 시스템을 구축해 나가는 과정을 기록합니다

0개의 댓글