macOS Process Abuse
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
프로세스는 실행 중인 실행 파일의 인스턴스이지만, 프로세스는 코드를 실행하지 않고, 이는 스레드입니다. 따라서 프로세스는 실행 중인 스레드를 위한 컨테이너일 뿐입니다. 메모리, 설명자, 포트, 권한 등을 제공합니다...
전통적으로, 프로세스는 **fork
**를 호출하여 다른 프로세스 내에서 시작되었으며, 이는 현재 프로세스의 정확한 복사본을 생성하고, 그 후 자식 프로세스는 일반적으로 **execve
**를 호출하여 새로운 실행 파일을 로드하고 실행합니다. 그런 다음, **vfork
**가 도입되어 메모리 복사 없이 이 프로세스를 더 빠르게 만들었습니다.
그 후 **posix_spawn
**이 도입되어 **vfork
**와 **execve
**를 하나의 호출로 결합하고 플래그를 수용했습니다:
POSIX_SPAWN_RESETIDS
: 유효 ID를 실제 ID로 재설정
POSIX_SPAWN_SETPGROUP
: 프로세스 그룹 소속 설정
POSUX_SPAWN_SETSIGDEF
: 신호 기본 동작 설정
POSIX_SPAWN_SETSIGMASK
: 신호 마스크 설정
POSIX_SPAWN_SETEXEC
: 동일한 프로세스에서 exec (더 많은 옵션이 있는 execve
와 유사)
POSIX_SPAWN_START_SUSPENDED
: 시작 시 일시 중지
_POSIX_SPAWN_DISABLE_ASLR
: ASLR 없이 시작
_POSIX_SPAWN_NANO_ALLOCATOR:
libmalloc의 Nano 할당기 사용
_POSIX_SPAWN_ALLOW_DATA_EXEC:
데이터 세그먼트에서 rwx
허용
POSIX_SPAWN_CLOEXEC_DEFAULT
: exec(2)에서 기본적으로 모든 파일 설명자 닫기
_POSIX_SPAWN_HIGH_BITS_ASLR:
ASLR 슬라이드의 높은 비트 무작위화
게다가, posix_spawn
은 생성된 프로세스의 일부 측면을 제어하는 posix_spawnattr
배열을 지정할 수 있으며, 설명자의 상태를 수정하기 위해 **posix_spawn_file_actions
**를 사용할 수 있습니다.
프로세스가 종료되면 부모 프로세스에 반환 코드를 전송합니다(부모가 종료된 경우 새로운 부모는 PID 1)와 함께 신호 SIGCHLD
를 보냅니다. 부모는 wait4()
또는 waitid()
를 호출하여 이 값을 가져와야 하며, 그 일이 발생할 때까지 자식은 좀비 상태에 머물며 여전히 나열되지만 자원을 소모하지 않습니다.
PID는 프로세스 식별자로, 고유한 프로세스를 식별합니다. XNU에서 PID는 64비트이며 단조롭게 증가하고 절대 랩핑되지 않습니다(남용 방지를 위해).
프로세스는 그룹에 삽입되어 더 쉽게 처리할 수 있습니다. 예를 들어, 셸 스크립트의 명령은 동일한 프로세스 그룹에 있을 것이므로, 예를 들어 kill을 사용하여 함께 신호를 보낼 수 있습니다.
또한 세션에 프로세스를 그룹화하는 것도 가능합니다. 프로세스가 세션을 시작할 때(setsid(2)
), 자식 프로세스는 세션 내에 설정되며, 자신만의 세션을 시작하지 않는 한 그렇습니다.
Coalition은 Darwin에서 프로세스를 그룹화하는 또 다른 방법입니다. Coalition에 가입한 프로세스는 풀 리소스에 접근할 수 있으며, 원장 공유 또는 Jetsam에 직면할 수 있습니다. Coalition은 다양한 역할을 가지고 있습니다: 리더, XPC 서비스, 확장.
각 프로세스는 시스템 내에서 권한을 식별하는 자격 증명을 보유합니다. 각 프로세스는 하나의 기본 uid
와 하나의 기본 gid
를 가지며(여러 그룹에 속할 수 있음).
이진 파일이 setuid/setgid
비트를 가지고 있다면 사용자 및 그룹 ID를 변경하는 것도 가능합니다.
새로운 uids/gids를 설정하는 여러 함수가 있습니다.
시스템 호출 **persona
**는 대체 자격 증명 세트를 제공합니다. 페르소나를 채택하면 uid, gid 및 그룹 멤버십을 한 번에 가정합니다. 소스 코드에서 구조체를 찾을 수 있습니다:
POSIX 스레드 (pthreads): macOS는 C/C++의 표준 스레딩 API의 일부인 POSIX 스레드(pthreads
)를 지원합니다. macOS의 pthreads 구현은 /usr/lib/system/libsystem_pthread.dylib
에 있으며, 이는 공개적으로 사용 가능한 libpthread
프로젝트에서 가져온 것입니다. 이 라이브러리는 스레드를 생성하고 관리하는 데 필요한 기능을 제공합니다.
스레드 생성: pthread_create()
함수는 새로운 스레드를 생성하는 데 사용됩니다. 내부적으로 이 함수는 XNU 커널(즉, macOS가 기반으로 하는 커널)에 특정한 저수준 시스템 호출인 bsdthread_create()
를 호출합니다. 이 시스템 호출은 스레드 동작을 지정하는 pthread_attr
(속성)에서 파생된 다양한 플래그를 사용합니다. 여기에는 스케줄링 정책과 스택 크기가 포함됩니다.
기본 스택 크기: 새로운 스레드의 기본 스택 크기는 512 KB로, 일반적인 작업에는 충분하지만 더 많거나 적은 공간이 필요할 경우 스레드 속성을 통해 조정할 수 있습니다.
스레드 초기화: __pthread_init()
함수는 스레드 설정 중에 중요하며, env[]
인수를 사용하여 스택의 위치와 크기에 대한 세부 정보를 포함할 수 있는 환경 변수를 구문 분석합니다.
스레드 종료: 스레드는 일반적으로 pthread_exit()
를 호출하여 종료됩니다. 이 함수는 스레드가 깔끔하게 종료되도록 하며, 필요한 정리를 수행하고 스레드가 모든 조인자에게 반환 값을 보낼 수 있도록 합니다.
스레드 정리: pthread_exit()
를 호출하면 pthread_terminate()
함수가 호출되어 모든 관련 스레드 구조를 제거합니다. 이 함수는 Mach 스레드 포트를 해제하고(Mach는 XNU 커널의 통신 하위 시스템) 스레드와 관련된 커널 수준 구조를 제거하는 시스템 호출인 bsdthread_terminate
를 호출합니다.
공유 자원에 대한 접근을 관리하고 경쟁 조건을 피하기 위해 macOS는 여러 동기화 원시 타입을 제공합니다. 이는 데이터 무결성과 시스템 안정성을 보장하기 위해 다중 스레딩 환경에서 중요합니다:
뮤텍스:
일반 뮤텍스 (서명: 0x4D555458): 메모리 사용량이 60바이트(뮤텍스 56바이트 + 서명 4바이트)인 표준 뮤텍스입니다.
빠른 뮤텍스 (서명: 0x4d55545A): 일반 뮤텍스와 유사하지만 더 빠른 작업을 위해 최적화된 것으로, 크기는 60바이트입니다.
조건 변수:
특정 조건이 발생할 때까지 대기하는 데 사용되며, 크기는 44바이트(40바이트 + 4바이트 서명)입니다.
조건 변수 속성 (서명: 0x434e4441): 조건 변수의 구성 속성으로, 크기는 12바이트입니다.
한 번 변수 (서명: 0x4f4e4345):
초기화 코드가 한 번만 실행되도록 보장합니다. 크기는 12바이트입니다.
읽기-쓰기 잠금:
동시에 여러 독자가 있거나 한 작성자가 있을 수 있도록 하여 공유 데이터에 대한 효율적인 접근을 촉진합니다.
읽기 쓰기 잠금 (서명: 0x52574c4b): 크기는 196바이트입니다.
읽기 쓰기 잠금 속성 (서명: 0x52574c41): 읽기-쓰기 잠금의 속성으로, 크기는 20바이트입니다.
이 객체의 마지막 4바이트는 오버플로우를 감지하는 데 사용됩니다.
**스레드 로컬 변수 (TLV)**는 Mach-O 파일(즉, macOS의 실행 파일 형식) 맥락에서 다중 스레드 애플리케이션에서 각 스레드에 특정한 변수를 선언하는 데 사용됩니다. 이는 각 스레드가 변수의 별도 인스턴스를 가지도록 하여 충돌을 피하고 데이터 무결성을 유지할 수 있는 방법을 제공합니다.
C 및 관련 언어에서는 __thread
키워드를 사용하여 스레드 로컬 변수를 선언할 수 있습니다. 다음은 예제에서 작동하는 방식입니다:
이 스니펫은 tlv_var
를 스레드 로컬 변수로 정의합니다. 이 코드를 실행하는 각 스레드는 자신의 tlv_var
를 가지며, 한 스레드가 tlv_var
에 가한 변경은 다른 스레드의 tlv_var
에 영향을 미치지 않습니다.
Mach-O 바이너리에서 스레드 로컬 변수와 관련된 데이터는 특정 섹션으로 구성됩니다:
__DATA.__thread_vars
: 이 섹션은 스레드 로컬 변수에 대한 메타데이터, 즉 변수의 유형과 초기화 상태를 포함합니다.
__DATA.__thread_bss
: 이 섹션은 명시적으로 초기화되지 않은 스레드 로컬 변수에 사용됩니다. 이는 제로 초기화된 데이터에 할당된 메모리의 일부입니다.
Mach-O는 스레드가 종료될 때 스레드 로컬 변수를 관리하기 위해 **tlv_atexit
**라는 특정 API를 제공합니다. 이 API를 사용하면 스레드가 종료될 때 스레드 로컬 데이터를 정리하는 소멸자를 등록할 수 있습니다.
스레드 우선순위를 이해하려면 운영 체제가 어떤 스레드를 언제 실행할지를 결정하는 방식을 살펴봐야 합니다. 이 결정은 각 스레드에 할당된 우선순위 수준에 의해 영향을 받습니다. macOS 및 유닉스 계열 시스템에서는 nice
, renice
, QoS(서비스 품질) 클래스와 같은 개념을 사용하여 이를 처리합니다.
Nice:
프로세스의 nice
값은 우선순위에 영향을 미치는 숫자입니다. 모든 프로세스는 -20(가장 높은 우선순위)에서 19(가장 낮은 우선순위)까지의 nice 값을 가집니다. 프로세스가 생성될 때 기본 nice 값은 일반적으로 0입니다.
낮은 nice 값( -20에 가까운)은 프로세스를 더 "이기적"으로 만들어, 더 높은 nice 값을 가진 다른 프로세스에 비해 더 많은 CPU 시간을 부여합니다.
Renice:
renice
는 이미 실행 중인 프로세스의 nice 값을 변경하는 데 사용되는 명령입니다. 이는 프로세스의 우선순위를 동적으로 조정하는 데 사용될 수 있으며, 새로운 nice 값에 따라 CPU 시간 할당을 증가시키거나 감소시킬 수 있습니다.
예를 들어, 프로세스가 일시적으로 더 많은 CPU 리소스가 필요하다면 renice
를 사용하여 nice 값을 낮출 수 있습니다.
QoS 클래스는 특히 **Grand Central Dispatch (GCD)**를 지원하는 macOS와 같은 시스템에서 스레드 우선순위를 처리하는 보다 현대적인 접근 방식입니다. QoS 클래스는 개발자가 작업의 중요성이나 긴급성에 따라 다양한 수준으로 작업을 분류할 수 있게 합니다. macOS는 이러한 QoS 클래스를 기반으로 스레드 우선순위를 자동으로 관리합니다:
사용자 상호작용:
이 클래스는 현재 사용자와 상호작용 중이거나 좋은 사용자 경험을 제공하기 위해 즉각적인 결과가 필요한 작업을 위한 것입니다. 이러한 작업은 인터페이스를 반응적으로 유지하기 위해 가장 높은 우선순위를 부여받습니다(예: 애니메이션 또는 이벤트 처리).
사용자 시작:
사용자가 시작하고 즉각적인 결과를 기대하는 작업으로, 문서를 열거나 계산이 필요한 버튼을 클릭하는 것과 같은 작업입니다. 이들은 높은 우선순위를 가지지만 사용자 상호작용보다는 낮습니다.
유틸리티:
이러한 작업은 장기 실행되며 일반적으로 진행 표시기를 표시합니다(예: 파일 다운로드, 데이터 가져오기). 이들은 사용자 시작 작업보다 우선순위가 낮으며 즉시 완료될 필요는 없습니다.
백그라운드:
이 클래스는 백그라운드에서 작동하며 사용자에게는 보이지 않는 작업을 위한 것입니다. 이러한 작업은 인덱싱, 동기화 또는 백업과 같은 작업일 수 있습니다. 이들은 가장 낮은 우선순위를 가지며 시스템 성능에 미치는 영향이 최소화됩니다.
QoS 클래스를 사용하면 개발자는 정확한 우선순위 숫자를 관리할 필요가 없으며, 작업의 성격에 집중하고 시스템이 CPU 리소스를 최적화하도록 할 수 있습니다.
또한, 스레드 스케줄링 정책이 있으며, 이는 스케줄러가 고려할 스케줄링 매개변수 집합을 지정하는 흐름입니다. 이는 thread_policy_[set/get]
를 사용하여 수행할 수 있습니다. 이는 경쟁 조건 공격에 유용할 수 있습니다.
MacOS는 다른 운영 체제와 마찬가지로 프로세스가 상호작용하고, 통신하며, 데이터를 공유하는 다양한 방법과 메커니즘을 제공합니다. 이러한 기술은 효율적인 시스템 기능에 필수적이지만, 위협 행위자에 의해 악의적인 활동을 수행하는 데 남용될 수 있습니다.
라이브러리 주입은 공격자가 프로세스가 악성 라이브러리를 로드하도록 강제하는 기술입니다. 주입된 후, 라이브러리는 대상 프로세스의 컨텍스트에서 실행되어 공격자에게 프로세스와 동일한 권한과 접근을 제공합니다.
macOS Library Injection함수 후킹은 소프트웨어 코드 내에서 함수 호출 또는 메시지를 가로채는 것을 포함합니다. 함수를 후킹함으로써 공격자는 프로세스의 동작을 수정하거나 민감한 데이터를 관찰하거나 실행 흐름을 제어할 수 있습니다.
macOS Function Hooking프로세스 간 통신(IPC)은 별도의 프로세스가 데이터를 공유하고 교환하는 다양한 방법을 나타냅니다. IPC는 많은 합법적인 애플리케이션에 필수적이지만, 프로세스 격리를 무너뜨리거나 민감한 정보를 유출하거나 무단 작업을 수행하는 데 남용될 수 있습니다.
macOS IPC - Inter Process Communication특정 환경 변수를 사용하여 실행된 Electron 애플리케이션은 프로세스 주입에 취약할 수 있습니다:
macOS Electron Applications Injection--load-extension
및 --use-fake-ui-for-media-stream
플래그를 사용하여 브라우저 내 공격을 수행하여 키 입력, 트래픽, 쿠키를 훔치고 페이지에 스크립트를 주입할 수 있습니다:
NIB 파일은 사용자 인터페이스(UI) 요소와 애플리케이션 내에서의 상호작용을 정의합니다. 그러나 이들은 임의의 명령을 실행할 수 있으며 Gatekeeper는 이미 실행된 애플리케이션이 NIB 파일이 수정된 경우 실행되는 것을 막지 않습니다. 따라서 이들은 임의의 프로그램이 임의의 명령을 실행하도록 만드는 데 사용될 수 있습니다:
macOS Dirty NIB특정 Java 기능(예: _JAVA_OPTS
환경 변수)을 남용하여 Java 애플리케이션이 임의의 코드/명령을 실행하도록 만들 수 있습니다.
.Net 디버깅 기능을 남용하여 .Net 애플리케이션에 코드를 주입할 수 있습니다(이는 macOS 보호(런타임 강화)로 보호되지 않음).
macOS .Net Applications InjectionPerl 스크립트가 임의의 코드를 실행하도록 만드는 다양한 옵션을 확인하십시오:
macOS Perl Applications InjectionRuby 환경 변수를 남용하여 임의의 스크립트가 임의의 코드를 실행하도록 만들 수 있습니다:
macOS Ruby Applications Injection환경 변수 **PYTHONINSPECT
**가 설정되면 Python 프로세스는 완료되면 Python CLI로 드롭됩니다. 또한 **PYTHONSTARTUP
**을 사용하여 대화형 세션 시작 시 실행할 Python 스크립트를 지정할 수 있습니다.
그러나 **PYTHONINSPECT
**가 대화형 세션을 생성할 때 PYTHONSTARTUP
스크립트는 실행되지 않습니다.
PYTHONPATH
및 **PYTHONHOME
**과 같은 다른 환경 변수도 Python 명령이 임의의 코드를 실행하도록 만드는 데 유용할 수 있습니다.
**pyinstaller
**로 컴파일된 실행 파일은 내장 Python을 사용하더라도 이러한 환경 변수를 사용하지 않는다는 점에 유의하십시오.
전반적으로 환경 변수를 남용하여 Python이 임의의 코드를 실행하도록 만드는 방법을 찾을 수 없었습니다. 그러나 대부분의 사람들은 Hombrew를 사용하여 Python을 설치하며, 이는 기본 관리자 사용자에게 쓰기 가능한 위치에 Python을 설치합니다. 다음과 같은 방법으로 이를 탈취할 수 있습니다:
Even root will run this code when running python.
Shield (Github)는 프로세스 주입 작업을 탐지하고 차단할 수 있는 오픈 소스 애플리케이션입니다:
환경 변수 사용: 다음 환경 변수 중 하나의 존재를 모니터링합니다: DYLD_INSERT_LIBRARIES
, CFNETWORK_LIBRARY_PATH
, RAWCAMERA_BUNDLE_PATH
및 ELECTRON_RUN_AS_NODE
task_for_pid
호출 사용: 한 프로세스가 다른 프로세스의 작업 포트를 얻으려 할 때를 찾습니다. 이는 프로세스에 코드를 주입할 수 있게 해줍니다.
Electron 앱 매개변수: 누군가 --inspect
, --inspect-brk
및 --remote-debugging-port
명령줄 인수를 사용하여 디버깅 모드에서 Electron 앱을 시작하고, 따라서 코드 주입을 할 수 있습니다.
심볼릭 링크 또는 하드 링크 사용: 일반적으로 가장 흔한 남용은 우리 사용자 권한으로 링크를 생성하고, 더 높은 권한 위치를 가리키게 하는 것입니다. 하드 링크와 심볼릭 링크 모두에 대한 탐지는 매우 간단합니다. 링크를 생성하는 프로세스의 권한 수준이 대상 파일과 다르면 경고를 생성합니다. 불행히도 심볼릭 링크의 경우, 생성 전에 링크의 목적지에 대한 정보가 없기 때문에 차단이 불가능합니다. 이는 Apple의 EndpointSecuriy 프레임워크의 제한 사항입니다.
이 블로그 포스트에서 task_name_for_pid
함수를 사용하여 다른 프로세스가 프로세스에 코드를 주입하는 정보를 얻고, 그 다른 프로세스에 대한 정보를 얻는 방법을 찾을 수 있습니다.
이 함수를 호출하려면 프로세스를 실행하는 것과 같은 uid여야 하거나 root여야 합니다 (그리고 이 함수는 프로세스에 대한 정보를 반환하며, 코드를 주입하는 방법은 반환하지 않습니다).
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)