전공영역 공부 기록

컨테이너 원리 - pivot_root(chroot 취약점을 해결)

악분 2024. 9. 8. 03:15
반응형

글을 읽기 위해 chroot 알고 있어야 합니다. chroot 저의 이전 글에 정리했습니다.

 

1. chroot 취약점

chroot는 디렉터리를 탐색할 있는 취약점 있습니다.

 

아래 예제는 chroot nginx컨테이너를 생성한 프로세스입니다. nginx 컨테이너가 디렉터리 탐색을 사용해서 최상위 경로로 루트 디렉터리를 변경했습니다.

 

nginx 컨테이너의 루트 디렉터리가 호스트 루트 디렉터리로 변경되었기 때문에, 호스트에 있는 정보를 탈취할 있습니다. 아래 예는 /etc/passwd파일을 탈취했습니다. 실습환경이 vagrant이기 때문에 vagrant user가 보입니다.

 

아래 코드는 파이썬 탈옥코드입니다. 탈옥코드는 chdir chroot 같이 사용하면 됩니다. chdir 현재 작업 디렉터리를 변경하고 chroot 루트 디렉터리를 변경합니다.

import os

if not os.path.exists("chroot-dir"):
    os.mkdir("chroot-dir")

os.chroot("chroot-dir")

for i in range(1000):
    os.chdir("..")

os.chroot(".")
os.system("/bin/bash")

 

2.  chroot 탈옥이 가능한 이유?

chroot 루트 디렉터리를 변경하면, 루트 디렉터리와 현재 작업 디렉터리가 상대경로로 변경됩니다. 상대경로는 디렉터리 탐색(: ../) 가능하기 때문에 탈옥이 가능합니다.

 

루트 디렉터리와 작업 디렉터리는 /proc/{process_id}/root, /proc/{process_id}/cwd 있습니다.

# chroot 프로세스 id 조회
$ echo $$
5394

# host에서 chroot 프로세스 루트 디렉터리(root), 작업 디렉터리(cwd)조회
$ cat /proc/5394/root
$ cat /proc/5394/cwd

 

3. pivot_root?

pivot_root chroot 취약점을 보완했습니다. pivot_root 실행하면 아래 그림처럼 루트 디렉터리가 “/” 변경됩니다. 루트 디렉터리가 상대경로로 설정되는 chroot 다른 결과입니다.

 

pivot_root 원리는 루트 디렉터리가 “/” 설정되도록 루트 파일 시스템을 변경합니다. man chroot man pivot_root 설명을 보면, chroot 루트 디렉터를 변경하고 pivot_root 루트 파일 시스템을 변경한다고 되어 있습니다.

man chroot
man pivot_root

 

4. pivot_root 실행방법

pivot_root 현재 루트 파일 시스템을 디렉터리에 백업한 , 지정한 경로로 루트 파일시스템을 변경합니다. 생각은 mount namespace 사용하면 백업한 루트 파일 시스템은 사용할 일이 없을 같습니다.

mkdir .old_root
pivot_root {새로운 루트 파일 시스템 경로} .old_root

 

5. 실습

실습에서는 pivot_root 루트 파일 시스템을 변경하고 탈옥이 되는지 테스트합니다. 실습을 하기 위해 docker 필요합니다.

 

python 설치된 debian 리눅스 컨테이너를 실행하고 docker export 컨테이너 파일을 추출합니다. 추출된 파일은 debian_python.tar압축파일입니다.

docker export $(docker create python:bullseye) -o /root/test/debian_python.tar
ls -l /root/test/debian_python.tar

 

debian압축파일을 압축해제합니다. 저는 /root/test경로에 압축해제했습니다.

mkdir /root/test
cd /root/test

mkdir -p ./debian_python
tar -xvf ./debian_python.tar -C ./debian_python

 

mount namespace 생성하면서 sh쉘을 실행합니다. sh쉘을 생성한 이유는 mount namespace 사용하여 mount작업을 격리하기 위해서입니다.

unshare --mount sh
mount --bind ./debian_python ./debian_python

 

sh쉘의 루트 파일 시스템을 백업할 디렉터리를 만듭니다.

mkdir ./debian_python/.oldrootfs

 

pivot_root 사용하여 루트 파일 시스템을 debian_python 디렉터리로 변경합니다.

cd ./debian_python
pivot_root . .oldrootfs

 

루트 파일 시스템을 변경한 , 수동으로 변경된 루트 디렉터리로 이동해줘야합니다.

cd  /

 

루트 디렉터리 이동 ls, python 명령어가 실행되는지 확인합니다.

ls
whoami
python

 

이제 sh쉘이 탈옥이 되는지 확인해봅니다. pivot_root 사용했기 때문에 당연히 안되야 합니다. 탈옥코드는 chroot테스트와 동일하게 파이썬 스크립트를 사용합니다.

cat > breakout.py
import os
if not os.path.exists("chroot-dir"):
    os.mkdir("chroot-dir")
os.chroot("chroot-dir")
for i in range(1000):
    os.chdir("..")
os.chroot(".")
os.system("/bin/bash")

 

탈옥코드를 실행하고 /etc/passwd 확인하여 탈옥이 실패했는지 확인합니다. debian 컨테이너의 /etc/passwd 보여야 합니다.

# 탈옥 시도
python3 breakout.py

# debian 컨테이너의 /etc/passwd가 보이면 탈옥 실패
cat /etc/passwd

 

탈옥이 실패한 이유는 루트 파일 시스템이 변경되어서, 루트 디렉터리가 상대경로가 아닌 “/” 변경되었기 때문입니다.

# chroot를 실행한 프로세스에서 process id 조회
$ echo $$
7513

# host에서 실행
$ ls -l /proc/7513/root
$ ls -l /proc/7513/cwd

 

참고자료

이하공백

반응형