Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for macOS Mojave #52

Open
notzheng opened this issue Oct 1, 2018 · 13 comments
Open

Add support for macOS Mojave #52

notzheng opened this issue Oct 1, 2018 · 13 comments

Comments

@notzheng
Copy link

notzheng commented Oct 1, 2018

I follow the README OS X usage, and everything seems right, but it still does't work...
Is it not support macOS Mojave?
2018-10-01 3 08 07
2018-10-01 3 08 49
2018-10-01 3 09 39

@XMB5
Copy link

XMB5 commented Oct 1, 2018

Might be the same problem as ios 11.3.1

@nabla-c0d3
Copy link
Owner

I tried the iOS 12 version of SSL Kill Switch on Mojave, but it looks like fishhook is unable to hook any functions. I am pretty sure the patch/tweak itself will work (as iOS 12 and Mojave should have a very similar network stack), but we need a new hooking implementation to replace fishhook.

@nabla-c0d3 nabla-c0d3 changed the title It doesn't work on macOS Mojave App Store Add support for macOS Mojave May 2, 2019
@MarkVillacampa
Copy link

MarkVillacampa commented Jun 2, 2019

I was able to hook functions in 10.14 using https://github.com/steven-michaud/HookCase/

Here's the diff of the hook example I used:

https://github.com/steven-michaud/HookCase/blob/da204378b66720e3a8417b03e0103d445191d72f/HookLibraryTemplate/hook.mm

diff --git a/HookLibraryTemplate/Makefile b/HookLibraryTemplate/Makefile
index b22c760..615a1f2 100644
--- a/HookLibraryTemplate/Makefile
+++ b/HookLibraryTemplate/Makefile
@@ -23,13 +23,13 @@
 CC=/usr/bin/clang++
 
 hook.dylib : hook.o
-	$(CC) -arch i386 -arch x86_64 -o hook.dylib hook.o \
-		-lobjc -framework Cocoa -framework Carbon \
+	$(CC) -arch x86_64 -o hook.dylib hook.o \
+		-lobjc -framework Cocoa\
 		-Wl,-F/System/Library/PrivateFrameworks -framework CoreSymbolication \
 		-dynamiclib
 
 hook.o : hook.mm
-	$(CC) -arch i386 -arch x86_64 -o hook.o \
+	$(CC) -arch x86_64 -o hook.o \
 		-Wno-deprecated-declarations -c hook.mm
 
 clean :
diff --git a/HookLibraryTemplate/hook.mm b/HookLibraryTemplate/hook.mm
index f455fc9..61beee3 100644
--- a/HookLibraryTemplate/hook.mm
+++ b/HookLibraryTemplate/hook.mm
@@ -50,7 +50,6 @@
 #include <stdarg.h>
 #include <time.h>
 #import <Cocoa/Cocoa.h>
-#import <Carbon/Carbon.h>
 #import <objc/Object.h>
 extern "C" {
 #include <mach-o/getsect.h>
@@ -888,11 +887,42 @@ - (id)Example_doSomethingWith:(id)whatever
     "_" #function,                                     \
     "" }
 
+enum ssl_verify_result_t {
+    ssl_verify_ok = 0,
+    ssl_verify_invalid,
+    ssl_verify_retry,
+};
+
+/* extern "C" void (*SSL_CTX_set_custom_verify)(void *ctx, int mode, int (*callback)(void *ssl, uint8_t *out_alert)); */
+
+static int custom_verify_callback_that_does_not_validate(void *ssl, uint8_t *out_alert)
+{
+    // Yes this certificate is 100% valid...
+    return ssl_verify_ok;
+}
+
+static void (*SSL_CTX_set_custom_verify_caller)(void *ctx, int mode, int (*callback)(void *ssl, uint8_t *out_alert));
+static void Hooked_SSL_CTX_set_custom_verify(void *ctx, int mode, int (*callback)(void *ssl, uint8_t *out_alert))
+{
+    printf("Entering replaced_SSL_CTX_set_custom_verify()\n");
+    SSL_CTX_set_custom_verify_caller(ctx, 0, custom_verify_callback_that_does_not_validate);
+    return;
+}
+
+static char (*SSL_get_psk_identity_caller)(void *ssl);
+char *Hooked_SSL_get_psk_identity(void *ssl)
+{
+    printf("SSL_get_psk_identity\n");
+    return "notarealPSKidentity";
+}
+
 __attribute__((used)) static const hook_desc user_hooks[]
   __attribute__((section("__DATA, __hook"))) =
 {
   INTERPOSE_FUNCTION(NSPushAutoreleasePool),
   PATCH_FUNCTION(__CFInitialize, /System/Library/Frameworks/CoreFoundation.framework/CoreFoundation),
+  PATCH_FUNCTION(SSL_CTX_set_custom_verify, /usr/lib/libboringssl.dylib),
+  PATCH_FUNCTION(SSL_get_psk_identity, /usr/lib/libboringssl.dylib),
 };
 
 // What follows are declarations of the CoreSymbolication APIs that we use to

After loading the HookCase kext, I can insert my dylib hook into any executable:

HC_INSERT_LIBRARY=/Users/mark/src/HookCase/HookLibraryTemplate/hook.dylib /Applications/Tweetbot.app/Contents/MacOS/Tweetbot

However, I keep getting this error:

Entering replaced_SSL_CTX_set_custom_verify()
2019-06-02 15:06:20.738 Tweetbot[5245:314032] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9810)
Entering replaced_SSL_CTX_set_custom_verify()
2019-06-02 15:06:21.097 Tweetbot[5245:314032] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9810)

Any idea what could be happening?

@nabla-c0d3
Copy link
Owner

That's really cool - I hadn't heard of HookCase.

-9810 is for an "internal error" (https://gist.github.com/ubergoob/04a981caa92d766a7f37f59848b6bc07) so I am not sure. It's possible that the patch as it is actually doesn't work on macOS.

@MarkVillacampa
Copy link

MarkVillacampa commented Jun 3, 2019 via email

@nabla-c0d3
Copy link
Owner

If I succeed, would it be ok if I submit a PR with the hook dylib implementation plus instructions to install HookCase?

Yes for sure! Thanks

@lupojpoodle
Copy link

I was able to get the kill switch somewhat working in 10.14 using HookCase. The functions that need to be patched are all in /usr/lib/libboringssl.dylib. So far, I've patched SSL_CTX_set_custom_verify, SSL_get_psk_identity (as above) and also boringssl_context_issue_tls_handshake_callback. My boringssl_context_issue_tls_handshake_callback just returns zero.

This seems to work with applications that just use the NSURLSession Delegate methods to test the certificate. The delegate methods never get called. However, the patches may be too simplistic - the code we're replacing updates the SSLContext that's being passed around. Processes that perform more sophisticated validation eventually fail or crash. For example, akd (AuthKitDaemon) will eventually fail with the "peer trust" errors.

Has anyone tried patching at a higher level (like CFNetwork)? Only Apple's networking uses their forked BoringSSL library, so applications the use different network libraries (e.g. curl) will require an alternate bypass method anyway.

@liuxuan30
Copy link

H i there, I just came across this thread. Any updates with the HookCase PR?

@liuxuan30
Copy link

@MarkVillacampa I tried your diff on Catalina, seems not working. I would like to dig into it. Any updates?

@liuxuan30
Copy link

actually, I found a super important thing: HC_INSERT_LIBRARY must be using full path, even if you are in the current folder... this saved my day.

@savandriy
Copy link

Hey guys!

Are there any updates on the situation? I really want to see how the api calls look for the App Store.

I've tried the diff by @MarkVillacampa on Catalina, and App Store doesn't work.

@lupojpoodle can you please share the full patched boringssl_context_issue_tls_handshake_callback function? As far as I understand you need to know the function type and args to patch it. I would really like to test if patching that function helps!

@savandriy
Copy link

Hello again, everyone!

I have some great news!

I stumbled upon a Frida script that allowed me to bypass the ssl certificate pinning in App Store on macOS Catalina!

Huge thank you to @kendfinger for the impressive work!

You can access the script here -> https://gist.github.com/kendfinger/37f941de24c5dfe46f3b8e93d94ce909

I had Catalina running on Virtualbox, with SIP disabled, and mitmproxy installed & configured.

All I had to do in order to disable the certificate pinning was:

  1. Install Frida with pip install frida-tools.
  2. Launch the App Store with proxy disabled.
  3. Run frida-ps to see all running processes, and find the pid for the App Store.
  4. Run frida <pid> -l disable-ssl-pin.js.
  5. Enable the proxy.

That's it! And I was able to see all of the requests coming from the App Store!

@JJTech0130
Copy link

The original gist is down, so I'll paste it here so it doesn't get lost forever:

var SecTrustEvaluate_handle =
    Module.findExportByName('Security', 'SecTrustEvaluate');
var SecTrustEvaluateWithError_handle =
    Module.findExportByName('Security', 'SecTrustEvaluateWithError');
var SSL_CTX_set_custom_verify_handle =
    Module.findExportByName('libboringssl.dylib', 'SSL_CTX_set_custom_verify');
var SSL_get_psk_identity_handle =
    Module.findExportByName('libboringssl.dylib', 'SSL_get_psk_identity');
var boringssl_context_set_verify_mode_handle = Module.findExportByName(
    'libboringssl.dylib', 'boringssl_context_set_verify_mode');

if (SecTrustEvaluateWithError_handle) {
  var SecTrustEvaluateWithError = new NativeFunction(
      SecTrustEvaluateWithError_handle, 'int', ['pointer', 'pointer']);

  Interceptor.replace(
      SecTrustEvaluateWithError_handle,
      new NativeCallback(function(trust, error) {
        console.log('[*] Called SecTrustEvaluateWithError()');
        SecTrustEvaluateWithError(trust, NULL);
        Memory.writeU8(error, 0);
        return 1;
      }, 'int', ['pointer', 'pointer']));
  console.log('[+] SecTrustEvaluateWithError() hook installed.');
}

if (SecTrustEvaluate_handle) {
  var SecTrustEvaluate = new NativeFunction(
      SecTrustEvaluate_handle, 'int', ['pointer', 'pointer']);

  Interceptor.replace(
      SecTrustEvaluate_handle, new NativeCallback(function(trust, result) {
        console.log('[*] Called SecTrustEvaluate()');
        SecTrustEvaluate(trust, result);
        Memory.writeU8(result, 1);
        return 0;
      }, 'int', ['pointer', 'pointer']));
  console.log('[+] SecTrustEvaluate() hook installed.');
}

if (SSL_CTX_set_custom_verify_handle) {
  var SSL_CTX_set_custom_verify = new NativeFunction(
      SSL_CTX_set_custom_verify_handle, 'void', ['pointer', 'int', 'pointer']);

  var replaced_callback = new NativeCallback(function(ssl, out) {
    console.log('[*] Called custom SSL verifier')
    return 0;
  }, 'int', ['pointer', 'pointer']);

  Interceptor.replace(
      SSL_CTX_set_custom_verify_handle,
      new NativeCallback(function(ctx, mode, callback) {
        console.log('[*] Called SSL_CTX_set_custom_verify()');
        SSL_CTX_set_custom_verify(ctx, 0, replaced_callback);
      }, 'int', ['pointer', 'int', 'pointer']));
  console.log('[+] SSL_CTX_set_custom_verify() hook installed.')
}

if (SSL_get_psk_identity_handle) {
  Interceptor.replace(
      SSL_get_psk_identity_handle, new NativeCallback(function(ssl) {
        console.log('[*] Called SSL_get_psk_identity_handle()');
        return 'notarealPSKidentity';
      }, 'pointer', ['pointer']));
  console.log('[+] SSL_get_psk_identity() hook installed.')
}

if (boringssl_context_set_verify_mode_handle) {
  var boringssl_context_set_verify_mode = new NativeFunction(
      boringssl_context_set_verify_mode_handle, 'int', ['pointer', 'pointer']);

  Interceptor.replace(
      boringssl_context_set_verify_mode_handle,
      new NativeCallback(function(a, b) {
        console.log('[*] Called boringssl_context_set_verify_mode()');
        return 0;
      }, 'int', ['pointer', 'pointer']));
  console.log('[+] boringssl_context_set_verify_mode() hook installed.')
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants