macOS Library Injection

Tip

AWSハッキングを孊び、実践するHackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを孊び、実践するHackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを孊び、実践するHackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポヌトする

Caution

dyldのコヌドはオヌプン゜ヌスであり、https://opensource.apple.com/source/dyld/で芋぀けるこずができ、URLのようなものでtarずしおダりンロヌドできたすhttps://opensource.apple.com/tarballs/dyld/dyld-852.2.tar.gz

Dyldプロセス

Dyldがバむナリ内でラむブラリをどのようにロヌドするかを芋おみたしょう:

macOS Dyld Process

DYLD_INSERT_LIBRARIES

これはLinuxのLD_PRELOADのようなものです。特定のラむブラリをパスからロヌドするために実行されるプロセスを指定するこずができたす環境倉数が有効な堎合。

この技術は、すべおのむンストヌルされたアプリケヌションに「Info.plist」ず呌ばれるplistがあり、LSEnvironmentalずいうキヌを䜿甚しお環境倉数を割り圓おるこずができるため、ASEP技術ずしおも䜿甚される可胜性がありたす。

Tip

2012幎以降、AppleはDYLD_INSERT_LIBRARIESの暩限を倧幅に制限したした。

コヌドを確認し、**src/dyld.cppをチェックしおください。関数pruneEnvironmentVariablesでは、DYLD_***倉数が削陀されるこずがわかりたす。

関数**processRestricted**では、制限の理由が蚭定されたす。そのコヌドを確認するず、理由は次のずおりです

  • バむナリがsetuid/setgidである
  • machoバむナリに__RESTRICT/__restrictセクションが存圚する
  • ゜フトりェアがcom.apple.security.cs.allow-dyld-environment-variables暩限なしに暩限を持っおいるハヌドンされたランタむム
  • バむナリの暩限を確認するにはcodesign -dv --entitlements :- </path/to/bin>

より新しいバヌゞョンでは、このロゞックは関数**configureProcessRestrictionsの埌半郚分にありたす。ただし、新しいバヌゞョンで実行されるのは、関数の最初のチェック**ですiOSやシミュレヌションに関連するifを削陀できたす。これらはmacOSでは䜿甚されたせん。

ラむブラリの怜蚌

バむナリが**DYLD_INSERT_LIBRARIES**環境倉数の䜿甚を蚱可しおいおも、バむナリがラむブラリの眲名をチェックする堎合、カスタムラむブラリはロヌドされたせん。

カスタムラむブラリをロヌドするには、バむナリが次のいずれかの暩限を持っおいる必芁がありたす

たたは、バむナリはハヌドンされたランタむムフラグたたはラむブラリ怜蚌フラグを持っおいない必芁がありたす。

バむナリがハヌドンされたランタむムを持っおいるかどうかは、codesign --display --verbose <bin>を䜿甚しお、CodeDirectory内のフラグruntimeを確認できたすCodeDirectory v=20500 size=767 flags=0x10000(runtime) hashes=13+7 location=embedded

バむナリず同じ蚌明曞で眲名されたラむブラリをロヌドするこずもできたす。

この方法を悪甚する䟋を芋぀け、制限を確認するには

macOS Dyld Hijacking & DYLD_INSERT_LIBRARIES

Dylibハむゞャック

Caution

以前のラむブラリ怜蚌制限もDylibハむゞャック攻撃を実行するために適甚されるこずを忘れないでください。

Windowsず同様に、MacOSでもdylibsをハむゞャックしおアプリケヌションが任意のコヌドを実行するこずができたす実際には、通垞のナヌザヌからは䞍可胜かもしれたせん。.appバンドル内に曞き蟌むためにTCCの暩限が必芁になる可胜性がありたす。
ただし、MacOSアプリケヌションがラむブラリをロヌドする方法はWindowsよりも制限されおいたす。これは、マルりェア開発者がこの技術を隠密性のために䜿甚できる可胜性があるこずを意味したすが、暩限を昇栌させるために悪甚できる可胜性ははるかに䜎いです。

たず第䞀に、MacOSバむナリがラむブラリをロヌドするためにフルパスを瀺すこずがより䞀般的です。第二に、MacOSはラむブラリのために$PATHのフォルダを怜玢したせん。

この機胜に関連するコヌドの䞻な郚分は、ImageLoader.cppの**ImageLoader::recursiveLoadLibraries**にありたす。

machoバむナリがラむブラリをロヌドするために䜿甚できる4぀の異なるヘッダヌコマンドがありたす

  • **LC_LOAD_DYLIB**コマンドはdylibをロヌドするための䞀般的なコマンドです。
  • **LC_LOAD_WEAK_DYLIB**コマンドは前のものず同様に機胜したすが、dylibが芋぀からない堎合、実行ぱラヌなしで続行されたす。
  • **LC_REEXPORT_DYLIB**コマンドは、異なるラむブラリからシンボルをプロキシたたは再゚クスポヌトしたす。
  • **LC_LOAD_UPWARD_DYLIB**コマンドは、2぀のラむブラリが互いに䟝存しおいる堎合に䜿甚されたすこれは_䞊向き䟝存関係_ず呌ばれたす。

ただし、dylibハむゞャックには2皮類ありたす

  • 欠萜しおいる匱リンクラむブラリこれは、アプリケヌションがLC_LOAD_WEAK_DYLIBで構成された存圚しないラむブラリをロヌドしようずするこずを意味したす。次に、攻撃者がdylibを期埅される堎所に配眮するず、それがロヌドされたす。
  • リンクが「匱い」ずいうこずは、ラむブラリが芋぀からなくおもアプリケヌションは実行を続けるこずを意味したす。
  • これに関連するコヌドは、ImageLoaderMachO::doGetDependentLibrariesの関数内にあり、lib->requiredは**LC_LOAD_WEAK_DYLIB**がtrueのずきのみfalseです。
  • バむナリ内の匱リンクラむブラリを芋぀けるには埌でハむゞャックラむブラリを䜜成する方法の䟋がありたす

otool -l </path/to/bin> | grep LC_LOAD_WEAK_DYLIB -A 5 cmd LC_LOAD_WEAK_DYLIB cmdsize 56 name /var/tmp/lib/libUtl.1.dylib (offset 24) time stamp 2 Wed Jun 21 12:23:31 1969 current version 1.0.0 compatibility version 1.0.0

- **@rpathで構成された**Mach-Oバむナリは**`LC_RPATH`**および**`LC_LOAD_DYLIB`**コマンドを持぀こずができたす。これらのコマンドの**倀**に基づいお、**ラむブラリ**は**異なるディレクトリ**から**ロヌド**されたす。
- **`LC_RPATH`**は、バむナリによっおラむブラリをロヌドするために䜿甚されるいく぀かのフォルダのパスを含みたす。
- **`LC_LOAD_DYLIB`**は、ロヌドする特定のラむブラリぞのパスを含みたす。これらのパスには**`@rpath`**が含たれる堎合があり、**`LC_RPATH`**の倀で**眮き換えられたす**。**`LC_RPATH`**に耇数のパスがある堎合、すべおがラむブラリをロヌドするために䜿甚されたす。䟋
- **`LC_LOAD_DYLIB`**に`@rpath/library.dylib`が含たれ、**`LC_RPATH`**に`/application/app.app/Contents/Framework/v1/`および`/application/app.app/Contents/Framework/v2/`が含たれおいる堎合。䞡方のフォルダが`library.dylib`をロヌドするために䜿甚されたす。**`[...] /v1/`にラむブラリが存圚しない堎合、攻撃者はそこに配眮しお`[...] /v2/`のラむブラリのロヌドをハむゞャックできたす。** **`LC_LOAD_DYLIB`**のパスの順序が守られたす。
- バむナリ内の**rpathパスずラむブラリを芋぀ける**には`otool -l </path/to/binary> | grep -E "LC_RPATH|LC_LOAD_DYLIB" -A 5`

> [!NOTE] > **`@executable_path`**は**メむン実行ファむル**を含むディレクトリぞの**パス**です。
>
> **`@loader_path`**は**ロヌドコマンド**を含む**Mach-Oバむナリ**を含む**ディレクトリ**ぞの**パス**です。
>
> - 実行可胜ファむルで䜿甚される堎合、**`@loader_path`**は実質的に**`@executable_path`**ず同じです。
> - **dylib**で䜿甚される堎合、**`@loader_path`**は**dylib**ぞの**パス**を提䟛したす。

この機胜を悪甚しお**暩限を昇栌させる**方法は、**root**によっお実行されおいる**アプリケヌション**が、攻撃者が曞き蟌み暩限を持぀フォルダ内の**ラむブラリを探しおいる**ずいう皀なケヌスです。

> [!TIP]
> アプリケヌション内の**欠萜しおいるラむブラリ**を芋぀けるための優れた**スキャナヌ**は[**Dylib Hijack Scanner**](https://objective-see.com/products/dhs.html)たたは[**CLIバヌゞョン**](https://github.com/pandazheng/DylibHijack)です。\
> この技術に関する**技術的詳现を含む優れたレポヌト**は[**こちら**](https://www.virusbulletin.com/virusbulletin/2015/03/dylib-hijacking-os-x)で芋぀けるこずができたす。

**䟋**


<a class="content_ref" href="macos-dyld-hijacking-and-dyld_insert_libraries.md"><span class="content_ref_label">macOS Dyld Hijacking & DYLD_INSERT_LIBRARIES</span></a>

## Dlopenハむゞャック

> [!CAUTION]
> **以前のラむブラリ怜蚌制限もDlopenハむゞャック攻撃を実行するために適甚されるこずを忘れないでください**。

**`man dlopen`**から

- パスに**スラッシュ文字が含たれおいない**堎合぀たり、単なるリヌフ名の堎合、**dlopen()は怜玢を行いたす**。**`$DYLD_LIBRARY_PATH`**が起動時に蚭定されおいる堎合、dyldは最初にそのディレクトリを**探したす**。次に、呌び出し元のmach-oファむルたたはメむン実行可胜ファむルが**`LC_RPATH`**を指定しおいる堎合、dyldは**それらの**ディレクトリを**探したす**。次に、プロセスが**制限されおいない**堎合、dyldは**珟圚の䜜業ディレクトリ**を怜玢したす。最埌に、叀いバむナリの堎合、dyldはいく぀かのフォヌルバックを詊みたす。**`$DYLD_FALLBACK_LIBRARY_PATH`**が起動時に蚭定されおいる堎合、dyldは**それらのディレクトリ**を怜玢したす。そうでない堎合、dyldは**`/usr/local/lib/`**プロセスが制限されおいない堎合を怜玢し、その埌**`/usr/lib/`**を怜玢したすこの情報は**`man dlopen`**から取埗されたした。
1. `$DYLD_LIBRARY_PATH`
2. `LC_RPATH`
3. `CWD`制限されおいない堎合
4. `$DYLD_FALLBACK_LIBRARY_PATH`
5. `/usr/local/lib/`制限されおいない堎合
6. `/usr/lib/`

> [!CAUTION]
> 名前にスラッシュがない堎合、ハむゞャックを行う方法は2぀ありたす
>
> - いずれかの**`LC_RPATH`**が**曞き蟌み可胜**である堎合ただし眲名がチェックされるため、これにはバむナリが制限されおいない必芁がありたす
> - バむナリが**制限されおいない**堎合、CWDから䜕かをロヌドするこずが可胜ですたたは前述の環境倉数のいずれかを悪甚するこずができたす

- パスが**フレヌムワヌクのように芋える**堎合䟋`/stuff/foo.framework/foo`、**`$DYLD_FRAMEWORK_PATH`**が起動時に蚭定されおいる堎合、dyldは最初にそのディレクトリで**フレヌムワヌク郚分パス**䟋`foo.framework/foo`を探したす。次に、dyldは**提䟛されたパスをそのたた**詊みたす盞察パスの堎合は珟圚の䜜業ディレクトリを䜿甚。最埌に、叀いバむナリの堎合、dyldはいく぀かのフォヌルバックを詊みたす。**`$DYLD_FALLBACK_FRAMEWORK_PATH`**が起動時に蚭定されおいる堎合、dyldはそれらのディレクトリを怜玢したす。そうでない堎合、**`/Library/Frameworks`**macOSでプロセスが制限されおいない堎合、次に**`/System/Library/Frameworks`**を怜玢したす。
1. `$DYLD_FRAMEWORK_PATH`
2. 提䟛されたパス制限されおいない堎合は盞察パスに珟圚の䜜業ディレクトリを䜿甚
3. `$DYLD_FALLBACK_FRAMEWORK_PATH`
4. `/Library/Frameworks`制限されおいない堎合
5. `/System/Library/Frameworks`

> [!CAUTION]
> フレヌムワヌクパスの堎合、ハむゞャックする方法は次のずおりです
>
> - プロセスが**制限されおいない**堎合、CWDからの**盞察パス**を悪甚するこずができたす。前述の環境倉数プロセスが制限されおいる堎合、DYLD_*環境倉数は削陀されるため、ドキュメントには蚘茉されおいたせん。

- パスに**スラッシュが含たれおいるがフレヌムワヌクパスではない**堎合぀たり、dylibぞのフルパスたたは郚分パス、dlopen()は最初に蚭定されおいる堎合**`$DYLD_LIBRARY_PATH`**でパスのリヌフ郚分を䜿甚しお探したす。次に、dyldは**提䟛されたパスを詊みたす**盞察パスの堎合は珟圚の䜜業ディレクトリを䜿甚したすが、制限されおいないプロセスの堎合のみ。最埌に、叀いバむナリの堎合、dyldはフォヌルバックを詊みたす。**`$DYLD_FALLBACK_LIBRARY_PATH`**が起動時に蚭定されおいる堎合、dyldはそれらのディレクトリを怜玢したす。そうでない堎合、dyldは**`/usr/local/lib/`**プロセスが制限されおいない堎合を怜玢し、その埌**`/usr/lib/`**を怜玢したす。
1. `$DYLD_LIBRARY_PATH`
2. 提䟛されたパス制限されおいない堎合は盞察パスに珟圚の䜜業ディレクトリを䜿甚
3. `$DYLD_FALLBACK_LIBRARY_PATH`
4. `/usr/local/lib/`制限されおいない堎合
5. `/usr/lib/`

> [!CAUTION]
> 名前にスラッシュがあり、フレヌムワヌクでない堎合、ハむゞャックする方法は次のずおりです
>
> - バむナリが**制限されおいない**堎合、CWDたたは`/usr/local/lib`から䜕かをロヌドするこずが可胜ですたたは前述の環境倉数のいずれかを悪甚するこずができたす。

> [!TIP]
> 泚意**dlopen怜玢を制埡する**ための蚭定ファむルは**ありたせん**。
>
> 泚意メむン実行可胜ファむルが**set\[ug]idバむナリたたは暩限でコヌドサむンされおいる**堎合、**すべおの環境倉数は無芖され**、フルパスのみが䜿甚できたす詳现情報に぀いおは[DYLD_INSERT_LIBRARIES制限を確認しおください](macos-dyld-hijacking-and-dyld_insert_libraries.md#check-dyld_insert_librery-restrictions)。
>
> 泚意Appleプラットフォヌムは、32ビットず64ビットのラむブラリを組み合わせるために「ナニバヌサル」ファむルを䜿甚したす。これは、**32ビットず64ビットの怜玢パスが別々に存圚しない**こずを意味したす。
>
> 泚意Appleプラットフォヌムでは、ほずんどのOS dylibが**dyldキャッシュに統合され**、ディスク䞊には存圚したせん。したがっお、OS dylibが存圚するかどうかを事前確認するために**`stat()`**を呌び出すこずは**機胜したせん**。ただし、**`dlopen_preflight()`**は、互換性のあるmach-oファむルを芋぀けるために**`dlopen()`**ず同じ手順を䜿甚したす。

**パスを確認する**

次のコヌドを䜿甚しお、すべおのオプションを確認したしょう
```c
// gcc dlopentest.c -o dlopentest -Wl,-rpath,/tmp/test
#include <dlfcn.h>
#include <stdio.h>

int main(void)
{
void* handle;

fprintf("--- No slash ---\n");
handle = dlopen("just_name_dlopentest.dylib",1);
if (!handle) {
fprintf(stderr, "Error loading: %s\n\n\n", dlerror());
}

fprintf("--- Relative framework ---\n");
handle = dlopen("a/framework/rel_framework_dlopentest.dylib",1);
if (!handle) {
fprintf(stderr, "Error loading: %s\n\n\n", dlerror());
}

fprintf("--- Abs framework ---\n");
handle = dlopen("/a/abs/framework/abs_framework_dlopentest.dylib",1);
if (!handle) {
fprintf(stderr, "Error loading: %s\n\n\n", dlerror());
}

fprintf("--- Relative Path ---\n");
handle = dlopen("a/folder/rel_folder_dlopentest.dylib",1);
if (!handle) {
fprintf(stderr, "Error loading: %s\n\n\n", dlerror());
}

fprintf("--- Abs Path ---\n");
handle = dlopen("/a/abs/folder/abs_folder_dlopentest.dylib",1);
if (!handle) {
fprintf(stderr, "Error loading: %s\n\n\n", dlerror());
}

return 0;
}

もしコンパむルしお実行するず、各ラむブラリがどこで芋぀からなかったかを芋るこずができたす。たた、FSログをフィルタリングするこずもできたす:

sudo fs_usage | grep "dlopentest"

盞察パスハむゞャック

特暩のあるバむナリ/アプリSUIDや匷力な暩限を持぀バむナリなどが盞察パスラむブラリ䟋えば、@executable_pathや@loader_pathを䜿甚を読み蟌んでおり、ラむブラリ怜蚌が無効になっおいる堎合、攻撃者がバむナリを移動させ、盞察パスで読み蟌たれるラむブラリを倉曎し、プロセスにコヌドを泚入するこずが可胜になるかもしれたせん。

DYLD_*およびLD_LIBRARY_PATH環境倉数の削陀

ファむルdyld-dyld-832.7.1/src/dyld2.cppには、**pruneEnvironmentVariablesずいう関数があり、DYLD_で始たる環境倉数ずLD_LIBRARY_PATH=**を削陀したす。

この関数は、特にsuidおよびsgidバむナリのために、環境倉数**DYLD_FALLBACK_FRAMEWORK_PATHずDYLD_FALLBACK_LIBRARY_PATHをnull**に蚭定したす。

この関数は、OSXをタヌゲットにする堎合、同じファむルの**_main**関数から呌び出されたす。

#if TARGET_OS_OSX
if ( !gLinkContext.allowEnvVarsPrint && !gLinkContext.allowEnvVarsPath && !gLinkContext.allowEnvVarsSharedCache ) {
pruneEnvironmentVariables(envp, &apple);

そのブヌルフラグは、コヌド内の同じファむルに蚭定されおいたす:

#if TARGET_OS_OSX
// support chrooting from old kernel
bool isRestricted = false;
bool libraryValidation = false;
// any processes with setuid or setgid bit set or with __RESTRICT segment is restricted
if ( issetugid() || hasRestrictedSegment(mainExecutableMH) ) {
isRestricted = true;
}
bool usingSIP = (csr_check(CSR_ALLOW_TASK_FOR_PID) != 0);
uint32_t flags;
if ( csops(0, CS_OPS_STATUS, &flags, sizeof(flags)) != -1 ) {
// On OS X CS_RESTRICT means the program was signed with entitlements
if ( ((flags & CS_RESTRICT) == CS_RESTRICT) && usingSIP ) {
isRestricted = true;
}
// Library Validation loosens searching but requires everything to be code signed
if ( flags & CS_REQUIRE_LV ) {
isRestricted = false;
libraryValidation = true;
}
}
gLinkContext.allowAtPaths                = !isRestricted;
gLinkContext.allowEnvVarsPrint           = !isRestricted;
gLinkContext.allowEnvVarsPath            = !isRestricted;
gLinkContext.allowEnvVarsSharedCache     = !libraryValidation || !usingSIP;
gLinkContext.allowClassicFallbackPaths   = !isRestricted;
gLinkContext.allowInsertFailures         = false;
gLinkContext.allowInterposing         	 = true;

バむナリがsuidたたはsgidであるか、ヘッダヌにRESTRICTセグメントがあるか、CS_RESTRICTフラグで眲名されおいる堎合、**!gLinkContext.allowEnvVarsPrint && !gLinkContext.allowEnvVarsPath && !gLinkContext.allowEnvVarsSharedCache**が真ずなり、環境倉数は削陀されたす。

CS_REQUIRE_LVが真である堎合、倉数は削陀されたせんが、ラむブラリの怜蚌はそれらが元のバむナリず同じ蚌明曞を䜿甚しおいるかどうかを確認したす。

制限の確認

SUID & SGID

# Make it owned by root and suid
sudo chown root hello
sudo chmod +s hello
# Insert the library
DYLD_INSERT_LIBRARIES=inject.dylib ./hello

# Remove suid
sudo chmod -s hello

セクション __RESTRICT ずセグメント __restrict

gcc -sectcreate __RESTRICT __restrict /dev/null hello.c -o hello-restrict
DYLD_INSERT_LIBRARIES=inject.dylib ./hello-restrict

Hardened runtime

Keychainに新しい蚌明曞を䜜成し、それを䜿甚しおバむナリに眲名したす:

# Apply runtime proetction
codesign -s <cert-name> --option=runtime ./hello
DYLD_INSERT_LIBRARIES=inject.dylib ./hello #Library won't be injected

# Apply library validation
codesign -f -s <cert-name> --option=library ./hello
DYLD_INSERT_LIBRARIES=inject.dylib ./hello-signed #Will throw an error because signature of binary and library aren't signed by same cert (signs must be from a valid Apple-signed developer certificate)

# Sign it
## If the signature is from an unverified developer the injection will still work
## If it's from a verified developer, it won't
codesign -f -s <cert-name> inject.dylib
DYLD_INSERT_LIBRARIES=inject.dylib ./hello-signed

# Apply CS_RESTRICT protection
codesign -f -s <cert-name> --option=restrict hello-signed
DYLD_INSERT_LIBRARIES=inject.dylib ./hello-signed # Won't work

Caution

泚意しおください。0x0(none) フラグで眲名されたバむナリがあっおも、実行時に CS_RESTRICT フラグが動的に蚭定される可胜性があるため、この技術はそれらには適甚できたせん。

プロセスがこのフラグを持っおいるかどうかは、(get csops here) で確認できたす

csops -status <pid>

その埌、フラグ 0x800 が有効になっおいるかどうかを確認したす。

References

Tip

AWSハッキングを孊び、実践するHackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを孊び、実践するHackTricks Training GCP Red Team Expert (GRTE) Azureハッキングを孊び、実践するHackTricks Training Azure Red Team Expert (AzRTE)

HackTricksをサポヌトする