[번역글] Dirtycow 취약점을 이용한 Docker Escape


머릿말

Dirty Cow 취약점은 리눅스 커널에서 Copy-on-Write을 할 때 존재하는 레이스 컨디션 취약점으로, read-only private memory mapping을 파괴할 수 있다. 권한이 낮은 로컬 사용자가 이 취약점을 활용하여 다른 기타 read-only memory mapping의 쓰기권한을 획득할 수 있으며, 더 나아가 권한 상승 취약점으로 이어질 수 있다.

Dirty Cow가 발표된 이후, 이 취약점의 영향력의 범위는 점점 더 커지고 있다. 리눅스 버전을 제외하고도, 근래에 보안 연구원들은 이 취약점이 안드로이드 보안에 영향을 끼칠 수 있다고 발표하기도 했으며 현재 Docker까지 이 취약점의 범위안에 들어가게 되었다.


본문

Escape

로컬 권한 상승에 비해서, 필자가 더욱 흥미를 가지는 부분은 바로 컨테이너 안에서, 즉 ‘Docker 같은 것들 안에서 어떻게 (Dirty Cow 취약점을) 활용할 수 있는가’ 이다.

이 취약점을 활용하기 위해서 먼저 어느 부분을 공략할 것인지 찾아야 하는데, 이 때 우리가 찾은 돌파구가 바로 “vDSO”(virtual dynamic shared object)이다. vDSO은 하나의 소형 공유 라이브러리인데, 커널을 자동적으로 모든 사용자 프로세스의 메모리 공간에 매핑될 수 있도록 한다. 듣기에도 매우 유용해보이지 않는가? 이 라이브러리가 존재하는 이유는 일부 시스템에서 vDSO를 호출함으로써 전체적인

성능을 확연히 높힐 수 있기 때문이다. 따라서 우리가 악용하기에 매우 적합하다.

이제 우리는 모든 프로세스가 공유하는 라이브러리에서 코드를 실행할 수 있다.

그럼 이제 무엇을 해야할까?

scumjr의 dirtycow-vdso

scumjr가 공개한 POC에서는 dirty cow를 활용하여 vDSO 메모리 공간 안에 있는 ckock_gettime()함수를 변조하였다. 이 POC에서는 실행 중인 프로세스 뿐만 아니라 모든 호출자에 대해 이 함수의 실행을 변조하였다. 레이스컨디션이 트리거 되고 쉘코드가 실행되면 루트 권한의 쉘을 획득할 수 있다.

필자는 AWS에 테스트 환경을 구축하였는 데 아마존에서 ami-7172b611를 이용하여 환경을 구축하였다. 필자가 사용한 커널의 버전은 4.4.19-29.55.amzn1.x86_64이지만 기타 취약점이 존재하는 커널을 사용하여도 상관없다.
컨테이너를 생성하는 Dockerfiles와 사용되는 scumjr의 익스플로잇도 모두 깃허브에 올려두었다.

시연동영상

Docker escape는 사실 매우 간단하지만 높은 난이도의 기술을 쓸거라는 사람들의 생각 때문에 필자는 Docker Escape에 더욱 흥미를 느낀다.

커널 취약점은 비록 유저 레벨에서의 권한 상승 취약점에 비해 더욱 희소하지만, 예시가 없고 이해가 안되는 것도 아니다. 커널의 특성으로 인해 컨테이너와의 거리가 줄어들이 우리가 이런 커널 취약점을 이용해 컨테이너를 우회하는 익스플로잇이 가능하게 되었다.

이를 제외하고도 다른 전략을 가진 POC exploit들이 존재한다. 깃허브에 들어가면 이러한 정보들을 볼 수 있다.

vDSO 배경 지식

vDSO는 성능을 최적화하는 역할을 한다. vDSO의 메뉴얼 페이지에는 gettimeofday를 예시로 설명하였다. gettimeofday는 주로 유저 공간의 프로그램이나 C 언어 라이브러리에 의해 호출된다. 만약 하나의 프로그램에서 지금 현재의 시간을 당장 알아야 한다면 정기적인 순환이나 폴링을 빈번하게 진행할 것이다. 이것이 비밀 정보도 아니기 때문에 간단하게 그리고 안전하게 모든 프로세스에서 공유된다. 커널에서는 모든 프로세스가 접근할 수 있는 위치에 시간을 저장해야 한다. 따라서 vDSO에서 하나의 기능을 정의하여 이 오브젝트를 공유하고 프로세스로 하여끔 이런 정보들에 접근할 수 있게 한다.

이런 방식을 통해서 gettimeofday를 호출하는 소모를 대폭 줄일 수 있고 더 빠르게 진행할 수 있게 된다.

취약점 상세 설명

이 취약점은 자주 호출되는 함수의 코드가 포함되어 있는 공유 메모리가 모든 프로세스에 매핑된다는 점을 이용하였다. 이 익스플로잇은 dirty cow를 사용하여 페이로드를 vDSO에 있는 남은 공간에 쓰고, 함수의 실행 순서를 조작하여 정상적인 함수가 실행되기 전에 이 쉘코드를 호출하게 한다.

쉘코드가 초기화할 때에는 먼저 root에 의해서 호출되었는 지 여부를 검사하고, 만약 맞다면 계속 진해하지만 아니라면 반환하고 주기 함수인 clock_gettime 을 실행한다. 판단을 할 때 쉘코드에서는 /tmp/.X가 존재하는 지를 검사하고 만약 존재한다면 함수에서는 이미 자신이 root 권한이라는 것을 인지하게 된다. 그런 다음 쉘코드에서는 reverse-tcp 연결을 열어 쉘코드 안에 인코딩된 ip와 포트에 쉘을 준다.

디폴트 상황에서는 로컬에 연결하게 되어 있지만 각자의 환경에 따라 수정할 수 있다. 쉘코드에서 17,18번째 줄을 보면 우리가 필요한 ip와 포트로 수정할 수 있다는 것을 알 수 있다. 예시는 다음과 같다.

IP equ 0x0100007f
PORT equ 0xd204

업데이트

업데이트된 부분이 하나 있는 데, 명령어를 실행할 때 “ip:port”형식으로 IP와 포트를 입력할 수 있다. 이렇게 수정하는 것이 쉘코드를 수정하는 것보다는 훨씬 편할것이다.

-translated by Fandu

Advertisements

[번역글] Dirtycow 취약점을 이용한 Docker Escape”의 1개의 생각

  1. 안드로이드 7.0.1이상은 동작하질않네요.. 추가로 vikiroot의 6.0.1 도 64비트만 동작해서.. 실험해보지도 못했다는 .ㅠㅠ

    좋아요

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

%s에 연결하는 중

%d 블로거가 이것을 좋아합니다:
search previous next tag category expand menu location phone mail time cart zoom edit close