KANS) 컨테이너의 시작 chroot 감옥 체험기
컨테이너는 가상머신과 다르게 커널을 공유해서 바로 프로세스를 실행 할 수 있는 구조이다. 아래 그림과 같이 호스트 커널을 공유하지만 각각의 독립된 사용자 공간을 가진다.
이러한 컨테이너의 시작은 특정 디렉토리를 루트(/)로 지정하여 해당 경로에 프로세스를 가두는 방식이다.
루트디렉토리 아래에 있는 디렉토리 A를 루트로 지정하여 들어가게되면
안에 있는 프로세스들은 디렉토리 A를 루트로 갇히게 된다.
사용되는 명령어
chroot :프로세스가 실행되는 루트 디렉토리를 특정 디렉토리로 변경한다.
pivot_root :프로세스의 마운트 네임스페이스에서 루트 마운트를 특정 디렉토리에 마운트 되어있는 새 마운트로 변경한다.
감옥생성
# 루트가 될 디렉토리(new-root)를 생성 후 필요한 명령어 복사
mkdir -p new-root/bin
cp $(which bash) new-root/bin
# 명령어 실행 시 참조하는 라이브러리 복사
ldd /bin/bash
cp /lib/x86_64-linux-gnu/libtinfo.so.6 new-root/lib/
...
이런식으로 필요한 명령어들을 하나씩 복사해서 넣어준다. chroot 명령어를 통해 들어가보면 만들어진 루트 디렉토리에 갇힌 것을 확인할 수 있다.
탈옥
탈옥하기에 앞서 위와 같이 명령어를 하나씩 다 넣기는 힘드니 만들어진 이미지를 사용하여 새로운 루트를 만들어준다.
# nginx이미지를 tar로 압축 후 nginx-root 디렉토리에 압축 해제
docker export $(docker create nginx:latest) | tar -C nginx-root -xvf -
# 탈옥 코드
cat <<EOF >escape_chroot.c
#include <sys/stat.h>
#include <unistd.h>
int main(void)
{
mkdir(".out",0755);
chroot(".out");
chdir("../../../../../");
chroot(".");
return execl("/bin/sh", "-i", NULL);
}
EOF
# 위의 코드를 컴파일하여 nginx-root에 escape_chroot이라는 실행 파일을 생성
gcc -o nginx-root/escape_chroot escape_chroot.c
chroot 명령어를 사용하여 들어가 탈옥코드로 만든 실행파일을 실행시키면 진짜 루트 디렉토리로 나오게된다.
문제 해결을 위해 pivot_root와 mount namespace를 이용하여 다시 가두기
# 디렉토리 생성 후 800M사이즈의 파일시스템을 마운트
mkdir new-root
mount -n -t tmpfs -o size=800M none new-root
# 위에서 테스트 했던 nginx-root의 파일들을 복사하여 새 디렉토리에 붙여넣기
cp -r nginx-root/* new-root/
# 마운트 포인트 디렉토리 생성
mkdir new-root/old-root
# 호스트에 영향을 주지않기 위해 mount namespace분리
unshare -m
escape_chroot을 돌려도 만들어진 루트 디렉토리에서 빠져나오지 못하는 것을 확인할 수 있다.
이렇게 격리된 환경의 리소스들은 해당 네임스페이스 안에서만 볼 수 있고 변경되지만, 자식은 부모의 네임스페이스를 상속받기 때문에 호스트에서 컨테이너 파일들에 접근과 프로세스 확인이 가능하다.
컨테이너 파일에 접근하여 파일 생성 및 삭제가 가능하고
호스트에서 컨테이너의 프로세스 확인 후 프로세스를 종료시키면 컨테이너 안에서도 종료되는 것을 확인할 수 있다.
참고
- https://netpple.github.io/docs/make-container-without-docker/container-internal-1
- https://netpple.github.io/docs/make-container-without-docker/container-internal-2
-
https://www.44bits.io/ko/post/change-root-directory-by-using-chroot
- https://man7.org/linux/man-pages/man2/chroot.2.html
- https://manpages.debian.org/bullseye/manpages-dev/pivot_root.2.en.html