
MikroTik v6.x.x 원격 탈옥
| / __ _ |/ | | | | | | | | | || | | ( | | ___ | | | || | | || | _ | / _ / _` | | | | || || | ) | || __/ (| | || _/|/ __|_,|
FOISted는 MikroTik RouterOS의 두 가지 인증 후(post-authentication) 취약점을 이용한 익스플로잇입니다. 6.34(2016)부터 6.49.6(최신 v6 릴리스)까지 실행되는 RouterOS를 원격으로 탈옥(jailbreak)하는 데 사용할 수 있습니다.
이 저장소에는 x86을 실행하는 장치용 익스플로잇 스크립트가 포함되어 있습니다. 취약점은 다른 장치 버전에도 존재합니다. ropchain 작성은 독자의 몫으로 남겨 둡니다 :)
자세한 내용은 RouterOS 내부 구조에 관한 블로그 게시물을 확인하세요: https://margin.re/blog/pulling-mikrotik-into-the-limelight.aspx
자동 매직:
$ python3 exploit.py -H <router_ip> -u <username> -p <password>
그런 다음:
$ nc <router_ip> 1337
익스플로잇 스크립트는 RouterOS 버전을 자동으로 확인하고 올바른 ropchain을 자동으로 배포합니다. 참고: 현재 x86 RouterOS만 지원됩니다.
어떤 이유로 버전이 식별되지 않으면 다음과 같이 명시적으로 전달할 수 있습니다:
-v <version> # e.g. 6.49.6
6.49.6(공개 당시 최신 버전)보다 최신 RouterOS 버전에서 이 스크립트를 실행하는 경우 해당 RouterOS 버전이 가젯 데이터베이스(./db)에 없을 수 있습니다. 대신 /nova/bin/www 경로를 전달하면 익스플로잇 스크립트가 ropchain에 맞는 올바른 가젯을 자동으로 찾으려 시도합니다:
-f /path/to/nova/bin/www
FOISted는 RouterOS v6의 두 가지 취약점을 활용하여 원격 코드 실행을 가능하게 합니다. 이 섹션에서는 RouterOS IPC에 대한 배경 지식을 살펴보고 두 가지 취약점에 대해 논의합니다.
참고: 이 섹션은 대부분 전체 블로그 게시물의 요약 버전입니다. 자세한 내용은 반드시 해당 게시물을 확인하세요!
MikroTik RouterOS 내부에서 프로그램들은 사용자 지정 IPC 프로토콜을 사용하여 서로 통신합니다.
실제 데이터 패킷은 Nova 메시지(내부적으로 nv::message)입니다. 이 메시지는 의사 JSON 형식(6.38 이전)과 직렬화된 바이너리 형식으로 존재합니다:

각 프로세스는 RouterOS 시스템 내에서 고정된 주소를 가지고 있습니다. 예를 들어 /nova/bin/user는 주소 13에 있고 /nova/bin/www는 주소 70에 있습니다. 또한 각 프로그램은 하위 네임스페이스에서 특정 기능을 구현하는 핸들러를 등록할 수 있습니다. 예를 들어 /nova/bin/user에는 "login" 엔드포인트 역할을 하며 다른 서비스의 인증을 수행하는 주소 4의 핸들러가 있습니다:

IPC 통신은 RouterOS 작동의 중요한 부분입니다. 다음 용도로 사용됩니다:
리버스 엔지니어링 작업 중에 우리는 라우터 작동 중에 교환되는 모든 메시지를 시각화할 수 있는 내부 메시지 트레이서 도구를 작성했습니다.
다음 데모에서는 웹 인터페이스를 페이지네이션할 때 교환되는 모든 메시지를 볼 수 있습니다: https://youtu.be/Em1hVWnbzQ4
RouterOS 웹 인터페이스는 /nova/bin/www 바이너리에 의해 구현됩니다. 그러나 특정 페이지는 별도의 공유 라이브러리에서 기능을 구현하는 별도의 "Servlet" 라이브러리에 의해 처리될 수 있습니다.
예를 들어 jsproxy.p 서블릿은 /jsproxy 요청을 처리하고 winbox.p 서블릿은 /winbox 요청을 처리합니다.
이러한 서블릿은 처음 필요할 때 /nova/bin/www에 로드되는 라이브러리입니다. 예를 들어 /jsproxy를 처음 로드하면 jsproxy.p 라이브러리가 메모리 공간에 로드됩니다.
이 라이브러리 로딩 과정에서 우리는 메시지 트레이서에서 흥미로운 트래픽을 발견했습니다:

구체적으로, 우리는 www 바이너리 에서 www의 핸들러 #2로 전송되는 메시지를 발견했습니다. 이는 RouterOS IPC가 동일한 프로세스 내부 통신이 아닌 _프로세스 간 통신_을 위한 것이기 때문에 이미 의심스럽습니다...
또한 두 인자가 가상 포인터(32비트 x86)로 보여서 매우 이례적이었기 때문에 우리의 관심을 끌었습니다.
/nova/bin/www의 핸들러 #2 내부의 실제 함수를 조사해 보면 이러한 유형의 메시지가 수신될 때 실행되는 FoisHandler::cmdUnknown이라는 함수를 찾을 수 있습니다.
놀랍게도 이 함수는 메시지에서 매개변수 0x11을 꺼내 다른 두 매개변수를 인자로 사용하여 함수로 호출합니다!
따라서 분명히 이 핸들러에 도달하는 제어된 메시지를 보낼 수 있다면 원하는 어떤 함수든 호출할 수 있습니다. 그리고 거기에서 ropchain으로 피벗하여 더 정교한 작업을 수행하는 것은 비교적 쉽습니다.
RouterOS 사용자로서 내부 IPC 메시지를 보내는 방법은 여러 가지가 있습니다. 실제로 모든 외부 클라이언트는 인증 후 임의의 메시지를 보낼 수 있게 해줍니다:
8291 포트로 접근) -- winbox.exe 클라이언트에서 사용이 인터페이스들은 초기 인증 핸드셰이크를 수행하는 방식이 다르지만, 일단 인증되면 사용자가 임의의 Nova 메시지를 내부 시스템으로 프록시할 수 있습니다. Winbox 및 MAC Telnet 암호화 프로토콜의 리버스 엔지니어링에 대한 자세한 내용은 블로그 게시물과 저장소를 참조하세요!
이 익스플로잇 구현에서는 WebFig 엔드포인트를 기본 통신 메커니즘으로 사용합니다. 리버스 엔지니어링된 클라이언트 구현은 webfig.py를 참조하세요.
그러나 취약한 FoisHandler 엔드포인트를 호출하려고 하면 문제가 있습니다:
RouterOS의 모든 핸들러는 호출할 수 있는 사용자를 지정하는 "정책" 비트마스크를 정의할 수 있습니다. FoisHandler의 정책은 0x80000000으로 내부 액세스 전용(즉, 다른 시스템 프로세스에서 발생한 메시지)을 나타냅니다.
관리자 사용자로서 GUI로 설정할 수 있는 최대 권한 비트마스크는 0x7fffe뿐이며 이는 충분하지 않습니다.
이것이 우리의 두 번째 버그로 이어집니다: 관리자(admin)에서 슈퍼 관리자(super-admin)로의 권한 상승입니다.
GUI에서는 0x7fffe의 권한 비트마스크만 설정할 수 있지만, 내부적으로는 실제로 필드 중 하나에 비트마스크 값을 포함하는 IPC 메시지를 보내는 것뿐입니다:

따라서 권한 비트마스크 값을 0xffffffff로 설정한 자체 메시지를 위조하기만 하면 됩니다!
이렇게 하면 시스템의 모든 엔드포인트에 제한 없이 액세스할 수 있습니다!
우리의 익스플로잇은 FTP를 통해 시스템에 두 개의 파일을 업로드하는 것으로 시작합니다:
stage2: 포트 1337에서 수신 대기하는 리버스 셸 생성기 포함busybox: 적절한 셸 환경을 제공그런 다음 익스플로잇은 FoisHandler 엔드포인트에 도달할 수 있도록 권한 상승을 수행합니다.
마지막으로 메시지에 포함된 ropchain으로 피벗하기 위해 조작된 메시지를 보냅니다. ropchain은 uClibc에서 chmod 및 execve의 주소를 계산하고 다음을 수행합니다:
chmod 0777 stage2execve stage2stage2가 실행되면 포트 1337에 연결하여 셸을 얻을 수 있습니다!
아니요, 이 두 취약점 모두 악용하려면 관리자 자격 증명이 필요합니다.
취약점은 최소 6.27(우리가 다운로드할 수 있었던 가장 초기 소프트웨어)부터 최신 v6인 6.49.6까지 존재합니다. 웹 인터페이스는 RouterOS v7에서 리팩터링되어 취약한 핸들러가 완전히 제거되었습니다. 우리의 POC는 x86용으로 작성되었습니다.
익스플로잇 스크립트는 6.34부터 6.49.6까지 모든 RouterOS 버전에서 작동합니다(테스트 완료!).