How to Hack a MacOS Application

Introduction

“How to Hack a MacOS Application”은 Apple의 MacOS에서 동작하는 어플리케이션을 테스팅하는 방법입니다. 전반적인 테스팅 메커니즘과 환경 구성에 대한 내용을 주로 다룹니다.

Directory Structure

Application

Application 디렉토리는 실제 앱 파일과 메니페스트 정보가 위치합니다. MacOS 앱 분석 시 CLI 도구를 통해서 체크하는 부분도 많은데, 이 때 해당 디렉토리의 바이너리를 활용합니다.

/Applications/<APP NAME>/Contents
  • Info.plist: 패키지에 대한 자세한 정보
  • MacOS: 실제 앱 실행에 사용되는 바이너리가 위치한 디렉토리
  • PkgInfo: 패키지 정보
  • _CodeSignature: 서명
  • Frameworks: 앱에 사용된 프레임워크들
  • Resources: 리소스 디렉토리
  • CodeResources: 코드 리소스

Data

Data 디렉토리는 앱이 사용하는 데이터들이 모인 디렉토리입니다. 대표적으로 Cache, Local DB 등이 있고 해당 디렉토리도 자세하게 체크해야할 디렉토리입니다.

/Users/<USER NAME>/Library/Application Support/<APP NAME>

Hack Mechanism

File system

위 Directory Structure에서 이야기한 2개의 디렉토리는 정말 중요합니다. 해당 디렉토리에서 분석에 필요한 전반적인 정보를 얻을 수 있습니다.

  • /Applications/<APP NAME>/Contents
  • /Users/<USER NAME>/Library/Application Support/<APP NAME>

Info.plist

/Applications/<APP NAME>/Contents에 있는 Info.plist는 앱에 대한 정보를 담고있는 plist(xml) 파일입니다. plist 파일이 떄문에 plutil 등으로 확인해야 정상적인 내용을 볼 수 있습니다.

plutil -p Info.plist

Notion 앱 예시

{
  "BuildMachineOSBuild" => "19F101"
  "CFBundleDisplayName" => "Notion"
  "CFBundleExecutable" => "Notion"
  "CFBundleIconFile" => "electron.icns"
  "CFBundleIdentifier" => "notion.id"
  "CFBundleInfoDictionaryVersion" => "6.0"
  "CFBundleName" => "Notion"
  "CFBundlePackageType" => "APPL"
  "CFBundleShortVersionString" => "2.0.22"
  "CFBundleURLTypes" => [
    0 => {
      "CFBundleURLName" => "notion"
      "CFBundleURLSchemes" => [
        0 => "notion"
      ]
    }
  ]
  "CFBundleVersion" => "2.0.22"
  "DTCompiler" => "com.apple.compilers.llvm.clang.1_0"
  "DTSDKBuild" => "11.0"
  "DTSDKName" => "macosx11.0"
  "DTXcode" => "1220"
  "DTXcodeBuild" => "12B45b"
  "LSApplicationCategoryType" => "public.app-category.productivity"
  "LSMinimumSystemVersion" => "10.10.0"
  "NSBluetoothAlwaysUsageDescription" => "This app needs access to Bluetooth"
  "NSBluetoothPeripheralUsageDescription" => "This app needs access to Bluetooth"
  "NSCameraUsageDescription" => "This app needs access to the camera"
  "NSHighResolutionCapable" => 1
  "NSMainNibFile" => "MainMenu"
  "NSMicrophoneUsageDescription" => "This app needs access to the microphone"
  "NSPrincipalClass" => "AtomApplication"
  "NSQuitAlwaysKeepsWindows" => 0
  "NSRequiresAquaSystemAppearance" => 0
  "NSSupportsAutomaticGraphicsSwitching" => 1
}

버전, 패키지 이름을 비롯하여, CFBundleURLSchemes에서 앱의 스킴 이름, 그리고 개발자가 저장해둔 일부 정보를 보실 수 있습니다.

Strings to Binary

strings 명령은 바이너리 내 문자열을 추출하는 명령입니다. 이를 통해 바이너리에 저장된 문자열을 추출할 수 있습니다.

strings ./MacOS/Notion

때떄로 중요한 API Endpoint나 키 값이 노출되기도 합니다.

API Testing

MacOS Application 또한 Web 기반의 API를 사용할 수 있고 최근에는 Electron app 등 웹을 사용하는 앱의 비중이 높기 떄문에 기존 Web Application 테스팅과 동일하게 보안 테스팅을 진행합니다.

이를 위해선 시스템 프록시 설정으로 MacOS Application에서 발생하는 트래픽이 ZAP이나 Burpsuite 등 Proxy 도구를 거쳐가도록 구성해야합니다. 구성에 대한 자세한 내용은 아래 Environment > Set Proxy 부분을 확인해주세요.

Check Listen Port

Listen Port를 체크하는 것은 간단하지만 중요한 과정입니다. 보통 listen port는 netstat을 생각하지만 lsof 명령으로 PID와 Application 이름을 같이 확인하는 것이 가독성이 좋습니다.

lsof -iTCP -sTCP:LISTEN -n -P

e.g

lsof -iTCP -sTCP:LISTEN -n -P
COMMAND     PID   USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
rapportd    500 hahwul    5u  IPv4 0xe46fe57c5b35640d      0t0  TCP *:64356 (LISTEN)
rapportd    500 hahwul    6u  IPv6 0xe46fe57c5be4c6ad      0t0  TCP *:64356 (LISTEN)
....
com.docke 33499 hahwul   11u  IPv4 0xe46fe57c5b33f6d5      0t0  TCP 127.0.0.1:62604 (LISTEN)
Notion    96251 hahwul   35u  IPv4 0xe46fe57c5b33c40d      0t0  TCP 127.0.0.1:52981 (LISTEN)

이를 통해 각 App이 Listen 상태로 있는 Port를 확인할 수 있고, 이는 추가적인 테스팅의 좋은 Endpoint가 됩니다.

  • HTTP 기반 포트의 경우 웹 기반으로 테스팅할 수 있습니다.
  • Socket 기반 포트의 경우 Fuzzing 등으로 오동작을 유도할 수 있습니다.

참고로 이렇게 로컬 포트를 열고 있는 앱은 생각보다 많습니다 🤔

Log Analysis

MacOS Application 또한 iOS App과 동일하게 Console 앱으로 로그를 받을 수 있습니다.

Reverse Engineering

MacOS Application은 최종적으로 바이너리로 컴파일되어 동작하기 때문에 Windows나 Linux Application과 동일하게 Reverse Engineering이 가능합니다. IDA나 Ghidra, Frida를 통해 어플리케이션의 흐름을 분석하고 숨겨진 관리 기능이나 메모리 단 취약점을 찾을 수도 있습니다.

🛠 Environment

Set Proxy

Certificate

Proxy 설정보다 먼저 인증서 설정(RootCA)을 하는 것이 좋습니다. 사용하시는 도구(ZAP or Burp 등) 에서 인증서 파일을 생성하여 다운로드한 후 파일을 더블클릭 하거나 키체인 앱을 통해 인증서 파일을 등록합니다. 이후 해당 인증서는 모두 신뢰 설정 되어야 합니다.

Use System Proxy

시스템 설정 > 네트워크 > 고급(현재 연결된 네트워크의 상세 설정) > 프록시 > 웹 프록시(HTTP)와 보안 웹 프록시(HTTPS) 에서 시스템 프록시를 설정할 수 있습니다.

Use Proxychains

Proxychains는 시스템 프록시를 중개해주는 도구입니다. 기본값은 Tor network를 사용하도록 되어 있어서 IP 우회 등에 사용되지만, configuation을 통해 지정한 프록시로 통신할 수 있도록 구성이 가능하기 때문에 환경 설정 후 사용 시 매우 편리하게 쓸 수 있습니다.

설치는 homebrew 통해서 진행해줍니다.

brew install proxychains-ng
Usage:	proxychains4 -q -f config_file program_name [arguments]
	-q makes proxychains quiet - this overrides the config setting
	-f allows one to manually specify a configfile to use
	for example : proxychains telnet somehost.com
More help in README file

Configuration 파일은 /usr/local/etc/proxychains.conf 경로에 있습니다. vim으로 열어서 사용할 proxy 포트와 서비스를 지정합니다.

vim /usr/local/etc/proxychains.conf
http    127.0.0.1       8090

이후 proxychains4 명령을 통해 어플리케이션 실행 시 앱이 지정한 Proxy로 통신하게 됩니다.

proxychains4 /Applications/Notion.app/Contents/MacOS/Notion

If use Pulse VPN

회사 등에서 VPN을 위해 Pulse를 사용하느 경우 일반적인 시스템 설정으로 Proxy가 정상적으로 잡히지 않습니다. 이는 Pulse 자체에서도 트래픽을 처리하기 위함이기 때문입니다. 이러한 문제는 Pulse 쪽 Configuration을 조정하여 해결할 수 있고, 이를 쉽게할 수 있는 psproxy란 도구가 있습니다.

먼저 npm을 통해 도구를 설치합니다.

npm i -g psproxy

이후 아래 명령으로 psproxy를 활성화하여 Pulse 사용중에도 트래픽이 우리가 의도한 도구로 흘러갈 수 있도록 변경합니다.

sudo psproxy on

원본 상태로 되돌리기 위해선 아래 명령으로 변경할 수 있습니다.

sudo psproxy off

Articles

  • https://www.hahwul.com/2020/09/18/use-proxy-in-macos-and-pulse-with-psproxy-for-zapburp/
  • https://www.hahwul.com/2021/08/28/mac-listen-port/

References

  • none