전공영역 공부 기록

chroot - 컨테이너는 어떻게 파일을 실행할까?

악분 2024. 9. 2. 00:34
반응형

 

 

 

글을 이해하기 위해 mount namespace이해가 필요합니다. 저의 이전 참고해주세요.

 

1. 최소 파일을 갖는 컨테이너

컨테이너의 장점은 애플리케이션 실행에 필요한 최소 파일과 라이브러리를 관리합니다.

 

예를 들어 자바 8 실행하는 컨테이너는 자바8실행파일과 자바8 관련된 라이브러리가 있습니다. 자바11 실행하는 컨테이너도 자바11실행파일과 자바11 관련된 라이브러리가 있습니다. 서버에서 자바 8 자바11 실행한다면, 자바8 11 실행파일 모두 가지고 있어야되고 관련 라이브러리를 설치해야 합니다. 최악의 경우 라이브러리 충돌로 인해 설치가 안되는 슬픈상황이 발생합니다.

 

2. 컨테이너가 개별적으로 최소 파일을 가질 있는 이유

이전 에서 설명한 것처럼 컨테이너는mount namespace 사용하여 자기만의 파일 시스템 가집니다. 따라서 컨테이너가 설치한 실행파일과 라이브러리는 다른 컨테이너에 영항을 가지 않습니다.

 

3. 컨테이너는 어떻게 파일을 실행할까?

컨테이너에서 파일 실행하는 방법은 특별하지 않습니다. 운영체제에서 파일을 실행하는 것과 동일합니다.

{실행파일 경로}

 

4. 실습

4.1 sh쉘 실행 준비

sh 실행파일을 실행하기 위해 아래처럼 sh바이너리와 sh실행하기 위한 라이브러리를 /root/base_dir경로에 준비했습니다.

 

그림처럼 준비하기 위해 디렉터리를 생성합니다.

mkdir /root/bash_dir
mkdir /root/bash_dir/bin
mkdir -p /root/bash_dir/lib/aarch64-linux-gnu

 

sh실행파일을 생성한 디렉터리로 복사합니다.

cp /bin/sh /root/bash_dir/bin

 

sh가 참조하는 라이브러리는 ldd명령어로 확인합니다.

ldd /bin/sh

 

ldd로 확인하는 라이브러리를 이전에 생성한 디렉터리로 복사합니다.

cp /lib/aarch64-linux-gnu/libc.so.6 /root/bash_dir/lib/aarch64-linux-gnu/
cp /lib/ld-linux-aarch64.so.1 /root/bash_dir/lib/

 

4.2 sh쉘 실행

준비한 sh를 실행해봅시다. mount namespace를 생성하면서 sh쉘을 실행합니다.

unshare -m /root/bash_dir/bin/sh

 

sh쉘이 잘 실행되었습니다.

 

4.3 논리적인 오류 확인

sh 쉘이 실행되는 것을 보면 동작하는 것처럼 보입니다. 하지만 sh 실행 파일이 참조하는 라이브러리 경로가 잘못 설정되어 있습니다. 제가 준비한 라이브러리 경로를 사용하지 않고, /lib 경로를 참조하고 있습니다.

 

strace 사용하여 sh실행파일이 참조하는 라이브러리를 확인할 있습니다.

strace -e trace=openat unshare -m /root/bash_dir/bin/sh -c "exit" 2>&1 \ 
  grep -E "openat.*(lib.*\.so)"

 

strace명령어 결과를 분석하면, 리눅스 sh실행 파일이 라이브러리를 참조할 /lib 또는 /lib64 경로를 사용하고 있다는 것을 있습니다. 리눅스 실행파일이 아니더라도 개발에 사용하는 SDK /lib, /lib64디렉토리 경로를 참조하는 경우가 많습니다.

 

4.4 논리적인 오류 수정 chroot

앞서 논리적인 오류는 실행파일이 우리가 준비한 라이브러리 경로를 바라보지 않는 것입니다. 문제를 해결하기 위해 root디렉터리를 우리가 준비한 디렉터리 경로로 변경하면 됩니다. 예제에서는 /root/bash_dir디렉터리가 root디렉터리가 되야 합니다.

 

현재 root 디렉터리 경로는 부모 프로세스의 root디렉터리입니다. mount namespace 생성할 부모 프로세스 mount point 복사했기 때문입니다.

 

root디렉터리를 변경하려면 chroot syscall 사용하면 됩니다.

man chroot

 

chroot 사용방법은 아래와 같습니다.

chroot {변경할 root 디렉터리 경로} {실행할 명령어}

 

예제에서 root 디렉터리를 변경하려면 아려처럼 chroot 사용합니다.

unshare -m chroot /root/bash_dir/ /bin/sh

 

chroot root 디렉터리를 변경하면 ls명령어를 실행하지 못합니다. sh실행파일만 준비했고 ls실행파일은 준비하지 않았기 때문입니다.

 

4.5 root 디렉터리 확인방법

ls명령어를 사용할 없기 때문에 다른 방법으로 root 디렉터리를 확인해야 합니다. root 디렉터리는 /proc에서 확인 있습니다. process id unshare 실행한 /bin/sh쉘에서 확인해야 합니다.

# unshare로 실행한 /bin/sh쉘에서 실행
$ echo $$
19560

# host에서 실행
$ ls -l /proc/19560/root
/proc/19560/root -> /root/bash_dir

 

/proc에서 root 디렉터리를 확인하면chroot경로에 설정한 /root/bash_dir root 디렉터리로 되어 있습니다.

 

5. chroot의 취약점

chroot 변경된 root디렉터리는 디렉터리 탐색 공격(Directory Traversal) 취약합니다. root 디렉터리가 절대경로로 변경된게 아니라 심볼릭 링크로 변경되었기 때문에, “cd ../../”같이 root 디렉터리의 상위 디렉터리로 이동이 가능합니다.

 

root 디렉터리의 상위 디렉터리로 이동하는 것을 탈옥이라고 부릅니다. chroot 탈옥 문제를 해결하려면 chroot대신 pivot_root라는 syscall 사용하면 됩니다.

 

참고자료

이하공백

반응형