Skip to content

Objective-C: Missing parameters from completion handler #8135

@CDuPlooy

Description

@CDuPlooy

Version and Platform (required):

  • Binary Ninja Version: [e.g. 4.0.4000-dev] (if version is stable, please also test the latest development build via the "Update Channel" option)
  • Edition: Personal
  • Tested on Linux and MacOS
  • OS Version: Arch Linux, 26.4.1
  • CPU Architecture: x64 & M1

Bug Description:
When looking at the pseudo objective-c view of a compiled binary the completion handler arguments are dropped.

Original code:

- (void)URLSession:(NSURLSession *)session
    didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
      completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler {

    if (![challenge.protectionSpace.authenticationMethod
          isEqualToString:NSURLAuthenticationMethodServerTrust]) {
        completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
        return;
    }

    SecTrustRef trust = challenge.protectionSpace.serverTrust;
    [self appendLog:[NSString stringWithFormat:@"TLS challenge from: %@",
                     challenge.protectionSpace.host]];
    [self logCertificateChain:trust];
    [self appendLog:@""];
    [self appendLog:@"[No Chain Validation]"];

    completionHandler(NSURLSessionAuthChallengeUseCredential,
                      [NSURLCredential credentialForTrust:trust]);

}

Steps To Reproduce:

Create a dummy application using the linked source
Compile and open in binary ninja
Select objective-c view
Navigate to "didReceiveChallenge"
Inspect result

For me it's:

100001944    void 
100001944      -[Ex3_NoChainValidationViewController URLSession:didReceiveChallenge:completionHandler:]
100001944      (struct Ex3_NoChainValidationViewController* self, SEL sel, id URLSession, 
100001944      id didReceiveChallenge, id completionHandler)

100001944    {
100001944        SEL sel_1 = sel;
10000196c        id location_2 = nullptr;
100001970        _objc_storeStrong(&location_2, URLSession);
10000197c        id location_1 = nullptr;
100001980        _objc_storeStrong(&location_1, didReceiveChallenge);
10000198c        id location = nullptr;
100001990        _objc_storeStrong(&location, completionHandler);
1000019a4        id obj = [[location_1 protectionSpace] retain];
1000019b8        id obj_1 = [[obj authenticationMethod] retain];
1000019d0        int32_t x0_6 =
1000019d0            [obj_1 isEqualToString:*(uint64_t*)_NSURLAuthenticationMethodServerTrust];
1000019e8        [obj_1 release];
1000019f8        [obj release];
1000019f8        
100001a00        if (x0_6 & 1)
100001a00        {
100001a30            id obj_2 = [[location_1 protectionSpace] retain];
100001a44            int64_t x0_12 = [obj_2 serverTrust];
100001a5c            [obj_2 release];
100001a7c            struct objc_class* const var_b0_1 = NSString;
100001a8c            id obj_3 = [[location_1 protectionSpace] retain];
100001aa0            id obj_4 = [[obj_3 host] retain];
100001ab8            id obj_7 = obj_4;
100001acc            int64_t obj_5 =
100001acc                [[NSString stringWithFormat:@"TLS challenge from: %@"] retain];
100001ae0            [self appendLog:obj_5];
100001af0            [obj_5 release];
100001b00            [obj_4 release];
100001b10            [obj_3 release];
100001b20            [self logCertificateChain:x0_12];
100001b34            [self appendLog:&cfstr_];
100001b48            [self appendLog:@"[No Chain Validation]"];
100001b5c            [self appendLog:@"  WARNING: skipping ALL certificate validation."];
100001b70            [self appendLog:
100001b70                &cfstr___Any_cert_?_self-signed,_expired,_wrong_CA_?_is_accepted.];
100001b84            [self appendLog:@"
100001b84                Fully vulnerable to MITM attacks. Never use in production."];
100001b98            [self appendLog:@"  => ACCEPTED (no checks performed)"];
100001ba0            id location_4 = location;
100001bbc            id obj_6 = [[NSURLCredential credentialForTrust:x0_12] retain];

/*
The next line corresponds to:

    completionHandler(NSURLSessionAuthChallengeUseCredential,
                      [NSURLCredential credentialForTrust:trust]);

But the credential object is never passed, only 0 is visible, which maps to NSURLSessionAuthChallengeUseCredential.
*/

100001bd4            (*(int64_t*)((char*)location_4 + 0x10))(location_4, 0);
100001be4            [obj_6 release];
100001be8            int32_t var_3c_1 = 0;
100001a00        }
100001a00        else
100001a00        {

/*
This one is more correct as NULL is passed as the final parameter
*/

100001a08            id location_3 = location;
100001a18            (*(int64_t*)((char*)location_3 + 0x10))(location_3, 1, 0);
100001a20            int32_t var_3c = 1;
100001a00        }
100001a00        
100001bfc        _objc_storeStrong(&location, nullptr);
100001c08        _objc_storeStrong(&location_1, nullptr);
100001c14        _objc_storeStrong(&location_2, nullptr);
100001944    }

Expected Behavior:

The parameter shouldn't just be dropped from the view, it appears as if it's unused but that cannot be the case, otherwise the test application would have errored out. Since it doesn't, the credential object must be passed.

Binary:
If applicable, please provide us with the binary to help us work with the issue faster. Here are a few options:

#import "Ex3_NoChainValidationViewController.h"

@interface Ex3_NoChainValidationViewController () <NSURLSessionDelegate>
@property (nonatomic, strong) NSURLSession *session;
@end

@implementation Ex3_NoChainValidationViewController

- (NSString *)exampleTitle {
    return @"3. No Chain Validation";
}

- (NSString *)exampleDescription {
    return @"DANGER";
}

- (NSString *)exampleURL {
    return @"https://self-signed.badssl.com";
}

- (void)performRequest {
    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
    self.session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];

    NSURL *url = [NSURL URLWithString:[self exampleURL]];
    [[self.session dataTaskWithURL:url
                 completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        [self handleHTTPResponse:response data:data error:error];
        [self finishRequest];
        [self.session invalidateAndCancel];
    }] resume];
}

#pragma mark - NSURLSessionDelegate

- (void)URLSession:(NSURLSession *)session
    didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
      completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler {

    if (![challenge.protectionSpace.authenticationMethod
          isEqualToString:NSURLAuthenticationMethodServerTrust]) {
        completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
        return;
    }

    SecTrustRef trust = challenge.protectionSpace.serverTrust;
    [self appendLog:[NSString stringWithFormat:@"TLS challenge from: %@",
                     challenge.protectionSpace.host]];
    [self logCertificateChain:trust];
    [self appendLog:@""];
    [self appendLog:@"[No Chain Validation]"];

    completionHandler(NSURLSessionAuthChallengeUseCredential,
                      [NSURLCredential credentialForTrust:trust]);

}

@end

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions