
snapd를 통한 리눅스 권한 상승 익스플로잇 (CVE-2019-7304)
2019년 1월, 현재 버전의 Ubuntu Linux가 snapd API의 버그로 인해 로컬 권한 상승에 취약한 것으로 밝혀졌습니다. 이 저장소는 원본 익스플로잇 POC를 포함하며, 연구 및 교육 목적으로 제공됩니다. 취약점과 익스플로잇에 대한 자세한 설명은 여기 블로그 게시물을 참조하십시오.
Ubuntu는 기본적으로 snapd를 제공하지만, 이 패키지가 설치된 모든 배포판에서 익스플로잇이 가능합니다. 시스템이 취약한지 쉽게 확인할 수 있습니다. 아래 명령어를 실행하세요. snapd 버전이 2.37.1 이상이면 안전합니다.
$ snap version
...
snapd 2.37.1
...
일부 시스템은 위 예제에 표시된 업스트림 버전 대신 snapd의 배포판 패키지 버전을 반환할 수 있습니다. snapd 버전에 Ubuntu 버전 번호가 추가된 경우(예: 2.34.2ubuntu0.1 또는 2.35.5+18.10.1) 패치된 버전을 실행 중인지 확인하려면 이 링크를 참조하십시오.
이 익스플로잇은 로컬 snapd 서비스의 제한된 API 기능(POST /v2/create-user)에 대한 액세스 제어 검사를 우회합니다. 제공된 이메일 주소의 사용자 이름과 공개 SSH 키를 Ubuntu SSO에 쿼리한 다음, 이 값을 기반으로 로컬 사용자를 생성합니다.
이 버전의 성공적인 익스플로잇에는 아웃바운드 인터넷 연결과 localhost에서 액세스 가능한 SSH 서비스가 필요합니다.
익스플로잇하려면 먼저 Ubuntu SSO에서 계정을 만드세요. 확인 후 프로필을 편집하고 SSH 공개 키를 업로드하세요. 그런 다음 다음과 같이 익스플로잇을 실행하세요 (업로드한 공개 키에 해당하는 SSH 개인 키 사용):
python3 ./dirty_sockv1.py -u "[email protected]" -k "id_rsa"
[+] Slipped dirty sock on random socket file: /tmp/ktgolhtvdk;uid=0;
[+] Binding to socket file...
[+] Connecting to snapd API...
[+] Sending payload...
[+] Success! Enjoy your new account with sudo rights!
[Script will automatically ssh to localhost with the SSH key here]
이 익스플로잇은 로컬 snapd 서비스의 제한된 API 기능(POST /v2/snaps)에 대한 액세스 제어 검사를 우회합니다. 이는 임의의 snap 설치를 허용합니다. "devmode"의 Snap은 샌드박스를 우회하며 설치 시점에 루트 컨텍스트에서 실행되는 "install hook"을 포함할 수 있습니다.
dirty_sockv2는 취약점을 활용하여 로컬 시스템에 새 사용자를 추가하는 후크를 포함하는 빈 "devmode" snap을 설치합니다. 이 사용자는 sudo 명령을 실행할 권한을 갖게 됩니다.
버전 1과 달리 SSH 서비스가 실행 중일 필요가 없습니다. 또한 인터넷 연결이 전혀 없는 최신 Ubuntu 버전에서도 작동하므로 변경에 강하고 제한된 환경에서 효과적입니다.
참고: 이 버전의 익스플로잇은 악성 snap 내부에 숨지 않습니다. 대신 사용자 생성 페이로드의 전달 메커니즘으로 악성 snap을 사용합니다. 이는 버전 1과 동일한 uid=0 버그 덕분에 가능합니다.
이 익스플로잇은 snapd가 설치되었지만 호환되지 않는 Linux 셸 구문으로 인해 "create-user" API를 지원하지 않는 비 Ubuntu 시스템에서도 효과적이어야 합니다.
일부 구형 Ubuntu 시스템(예: 16.04)에는 사이드로딩에 필요한 snapd 구성 요소가 설치되지 않았을 수 있습니다. 이 경우 이 버전의 익스플로잇이 해당 종속성을 설치하도록 트리거할 수 있습니다. 설치 중에 snapd가 취약하지 않은 버전으로 업그레이드될 수 있습니다. 테스트 결과 이 시나리오에서도 익스플로잇이 성공하는 것으로 나타났습니다. 자세한 내용은 문제 해결 섹션을 참조하십시오.
익스플로잇하려면 취약한 시스템에서 인수 없이 스크립트를 실행하기만 하면 됩니다.
python3 ./dirty_sockv2.py
[+] Slipped dirty sock on random socket file: /tmp/gytwczalgx;uid=0;
[+] Binding to socket file...
[+] Connecting to snapd API...
[+] Deleting trojan snap (and sleeping 5 seconds)...
[+] Installing the trojan snap (and sleeping 8 seconds)...
[+] Deleting trojan snap (and sleeping 5 seconds)...
********************
Success! You can now `su` to the following account and use sudo:
username: dirty_sock
password: dirty_sock
********************
버전 2를 사용했는데 익스플로잇이 완료되었지만 새 계정이 보이지 않는 경우, 이는 백그라운드 snap 업데이트 때문일 수 있습니다. snap changes를 실행한 다음 snap change #(dirty_sock snap 설치를 나타내는 줄 참조)를 실행하여 확인할 수 있습니다. 결국 완료되면 계정을 사용할 수 있어야 합니다.
버전 1은 환경이 지원하는 경우(SSH 서비스가 실행 중이고 localhost에서 액세스 가능) 가장 쉽고 빠른 것으로 보입니다.
취약하지 않은 시스템은 다음과 같은 출력을 생성합니다:
[!] System may not be vulnerable, here is the API reply:
HTTP/1.1 401 Unauthorized
Content-Type: application/json
Date: Mon, 18 Feb 2019 07:07:12 GMT
Content-Length: 119
{"type":"error","status-code":401,"status":"Unauthorized",
"result":{"message":"access denied","kind":"login-required"}}
이상한 점이 있으면 이슈를 열어 주세요.
이 문제는 Ubuntu의 버그 트래커를 통해 snapd 팀에 직접 보고되었습니다. 전체 스레드는 여기에서 읽을 수 있습니다.
Canonical의 대응에 깊은 인상을 받았습니다. 팀과 협력하는 것이 훌륭했으며, 전반적인 경험을 통해 Ubuntu 사용자라는 것이 매우 좋게 느껴집니다.
공개 권고 링크:
참고: 이 GitHub 저장소, 제 블로그(initblog.com) 및 제 팀 블로그(shenaniganslabs.io)에만 정보를 게시합니다. 공식 출처를 사칭하는 사이트는 제 통제 범위를 벗어나니 유의하시기 바랍니다.