Skip to content

Commit

Permalink
v1.2
Browse files Browse the repository at this point in the history
  • Loading branch information
theevilbit committed May 19, 2021
1 parent bf6256c commit 2265a61
Show file tree
Hide file tree
Showing 21 changed files with 645 additions and 329 deletions.
7 changes: 5 additions & 2 deletions Common/Constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,20 @@
#define ATTACK_FILELINKS @1

//notification strings
//common
#define NOTIFICATION_ATTACK_TYPE @"attack_type"
#define NOTIFICATION_TYPE @"type"
#define NOTIFICATION_ID @"id"

//notification strings for process injection
#define NOTIFICATION_TYPE @"type"
#define NOTIFICATION_VICTIM_PATH @"victim_path"
#define NOTIFICATION_ATTACKER_PATH @"attacker_path"
#define NOTIFICATION_DYLIB_PATH @"dylib_path"
#define NOTIFICATION_ENV @"env"
#define NOTIFICATION_ARGUMENTS @"arguments"

//notification strings for symlink/hardlink detection
#define NOTIFICATION_LINK_TYPE @"type"
#define NOTIFICATION_LINK_TYPE @"link_type"
#define NOTIFICATION_LINK_PROCESS_PATH @"process_path"
#define NOTIFICATION_LINK_SOURCE_PATH @"source_path"
#define NOTIFICATION_LINK_DESTINATION_PATH @"destination_path"
Expand Down
2 changes: 1 addition & 1 deletion Common/XPCExtensionProtocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
-(void)update_preferences:(NSDictionary *)prefs reply:(void (^)(BOOL))reply;

//allowlist operation
-(void)add_item_to_allowlist:(NSDictionary *)al reply:(void (^)(BOOL))reply;
-(void)add_item_to_allowlist:(NSDictionary *)al generic:(BOOL)generic reply:(void (^)(BOOL))reply;
-(void)remove_item_from_allowlist:(NSDictionary *)al reply:(void (^)(BOOL))reply;
-(void)clear_allowlist:(void (^)(BOOL))reply;
-(void)get_allowlist:(void (^)(NSArray *))reply;
Expand Down
4 changes: 2 additions & 2 deletions Extension/AllowList.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@
-(BOOL)is_item_in_allowlist:(NSDictionary*)item;

//manage allowlist
-(BOOL)add_item_to_allowlist:(NSDictionary*)item;
-(BOOL)add_item_to_allowlist:(NSMutableDictionary*)item generic:(BOOL)generic;

-(BOOL)remove_item_from_allowlist:(NSDictionary*)item;
-(BOOL)remove_item_from_allowlist:(NSMutableDictionary*)item;

-(NSDictionary*) get_allowlist;

Expand Down
107 changes: 90 additions & 17 deletions Extension/AllowList.m
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ -(BOOL)init_file {
}
}
self.allowlist_full = [NSMutableDictionary new];
self.allowlist_full[@"version"] = @"1.0";
self.allowlist_full[@"version"] = @"2.0";

BOOL saved = [self save];
if(saved == NO) {
Expand Down Expand Up @@ -106,6 +106,20 @@ -(BOOL)load
//replace NSDictionary in dictionary to the previosuly created NSMutableDictionaries
[self.allowlist_full setObject:self.allowlist_items forKey:@"items"];

//upgrade allow list from 1.0 to 2.0
if([self.allowlist_full[@"version"] isEqualToString:@"1.0"]) {
//upgrade version number
self.allowlist_full[@"version"] = @"2.0";
//1.0 is old, we need to add attack type ATTACK_INJECTION
int i;
for (i = 0; i < [self.allowlist_items count]; i++) {
NSMutableDictionary* element = [[self.allowlist_items objectAtIndex:i] mutableCopy];
element[NOTIFICATION_ATTACK_TYPE] = ATTACK_INJECTION;
[self.allowlist_items replaceObjectAtIndex:i withObject:element];
}
[self save];
}

//dbg msg
os_log_error(log_handle, "'%s' loaded allowlist: %@", __PRETTY_FUNCTION__, self.allowlist_full);

Expand All @@ -128,28 +142,88 @@ -(BOOL)save
-(BOOL)is_item_in_allowlist:(NSDictionary*)item {

os_log_debug(log_handle, "Checking allowlist %s", __PRETTY_FUNCTION__);

os_log_debug(log_handle, "Checking item in allowlist %@", item);

BOOL found = NO;
//iterate over the array
for (NSDictionary* element in self.allowlist_items) {
//compare, normal isequaltodictionary doesn't work
if([item[NOTIFICATION_TYPE] isEqualToString:element[NOTIFICATION_TYPE]] &&
[item[NOTIFICATION_ATTACKER_PATH] isEqualToString:element[NOTIFICATION_ATTACKER_PATH]] &&
[item[NOTIFICATION_VICTIM_PATH] isEqualToString:element[NOTIFICATION_VICTIM_PATH]] &&
[item[NOTIFICATION_ENV] isEqualToString:element[NOTIFICATION_ENV]] &&
[item[NOTIFICATION_ARGUMENTS] isEqualToString:element[NOTIFICATION_ARGUMENTS]] &&
[item[NOTIFICATION_DYLIB_PATH] isEqualToString:element[NOTIFICATION_DYLIB_PATH]]) {
found = YES;
break;
os_log_debug(log_handle, "Checking element in allowlist %@", element);
//check for ATTACK_INJECTION entries
if ([item[NOTIFICATION_ATTACK_TYPE] isEqualToNumber:ATTACK_INJECTION] && [element[NOTIFICATION_ATTACK_TYPE] isEqualToNumber:ATTACK_INJECTION]) {
os_log_debug(log_handle, "Comparing to attack type ATTACK_INJECTION");
//compare, normal isequaltodictionary doesn't work
//we compare each entry, these should be always exists
if([item[NOTIFICATION_TYPE] isEqualToString:element[NOTIFICATION_TYPE]] &&
[item[NOTIFICATION_ATTACKER_PATH] isEqualToString:element[NOTIFICATION_ATTACKER_PATH]] &&
[item[NOTIFICATION_VICTIM_PATH] isEqualToString:element[NOTIFICATION_VICTIM_PATH]] &&
[item[NOTIFICATION_ENV] isEqualToString:element[NOTIFICATION_ENV]] &&
[item[NOTIFICATION_ARGUMENTS] isEqualToString:element[NOTIFICATION_ARGUMENTS]] &&
[item[NOTIFICATION_DYLIB_PATH] isEqualToString:element[NOTIFICATION_DYLIB_PATH]]) {
os_log_debug(log_handle, "Found entry in allowlist for %@", item);
found = YES;
break;
}
//find wildcard match
//for wildcard we always save "*"
if([element[NOTIFICATION_TYPE] isEqualToString:item[NOTIFICATION_TYPE]] &&
[element[NOTIFICATION_ATTACKER_PATH] isEqualToString:@"*"] &&
[element[NOTIFICATION_VICTIM_PATH] isEqualToString:item[NOTIFICATION_VICTIM_PATH]] &&
[element[NOTIFICATION_ENV] isEqualToString:@"*"] &&
[element[NOTIFICATION_ARGUMENTS] isEqualToString:@"*"] &&
[element[NOTIFICATION_DYLIB_PATH] isEqualToString:@"*"]) {
found = YES;
os_log_debug(log_handle, "Found generic entry in allowlist for %@", item);
break;
}
}
//check for ATTACK_FILELINKS entries
else if ([item[NOTIFICATION_ATTACK_TYPE] isEqualToNumber:ATTACK_FILELINKS] && [element[NOTIFICATION_ATTACK_TYPE] isEqualToNumber:ATTACK_FILELINKS]) {
os_log_debug(log_handle, "Comparing to attack type ATTACK_FILELINKS");
if([item[NOTIFICATION_LINK_TYPE] isEqualToString:element[NOTIFICATION_LINK_TYPE]] &&
[item[NOTIFICATION_LINK_FILE_UID] isEqualToString:element[NOTIFICATION_LINK_FILE_UID]] &&
[item[NOTIFICATION_LINK_PROCESS_UID] isEqualToString:element[NOTIFICATION_LINK_PROCESS_UID]] &&
[item[NOTIFICATION_LINK_SOURCE_PATH] isEqualToString:element[NOTIFICATION_LINK_SOURCE_PATH]] &&
[item[NOTIFICATION_LINK_DESTINATION_PATH] isEqualToString:element[NOTIFICATION_LINK_DESTINATION_PATH]] &&
[item[NOTIFICATION_LINK_PROCESS_PATH] isEqualToString:element[NOTIFICATION_LINK_PROCESS_PATH]]) {
os_log_debug(log_handle, "Found entry in allowlist for %@", item);
found = YES;
break;
}
//find wildcard match
if([element[NOTIFICATION_LINK_TYPE] isEqualToString:item[NOTIFICATION_LINK_TYPE]] &&
[element[NOTIFICATION_LINK_FILE_UID] isEqualToString:@"*"] &&
[element[NOTIFICATION_LINK_PROCESS_UID] isEqualToString:@"*"] &&
[element[NOTIFICATION_LINK_SOURCE_PATH] isEqualToString:@"*"] &&
[element[NOTIFICATION_LINK_DESTINATION_PATH] isEqualToString:@"*"] &&
[element[NOTIFICATION_LINK_PROCESS_PATH] isEqualToString:item[NOTIFICATION_LINK_PROCESS_PATH]]) {
found = YES;
os_log_debug(log_handle, "Found generic entry in allowlist for %@", item);
break;
}
}
}

return found;
}

//add entry
-(BOOL)add_item_to_allowlist:(NSDictionary*)item {
-(BOOL)add_item_to_allowlist:(NSMutableDictionary*)item generic:(BOOL)generic {

//replace strings with "*" wildcards
if(generic) {
if ([item[NOTIFICATION_ATTACK_TYPE] isEqualToNumber:ATTACK_INJECTION]) {
item[NOTIFICATION_ATTACKER_PATH] = @"*";
item[NOTIFICATION_ENV] = @"*";
item[NOTIFICATION_ARGUMENTS] = @"*";
item[NOTIFICATION_DYLIB_PATH] = @"*";
}
else if ([item[NOTIFICATION_ATTACK_TYPE] isEqualToNumber:ATTACK_FILELINKS]) {
item[NOTIFICATION_LINK_SOURCE_PATH] = @"*";
item[NOTIFICATION_LINK_DESTINATION_PATH] = @"*";
item[NOTIFICATION_LINK_PROCESS_UID] = @"*";
item[NOTIFICATION_LINK_FILE_UID] = @"*";
}
}
os_log_debug(log_handle, "Adding entry to allowlist %@ %s", item, __PRETTY_FUNCTION__);
item = [self get_id_free_item:item];

Expand All @@ -159,7 +233,7 @@ -(BOOL)add_item_to_allowlist:(NSDictionary*)item {
}

//check for entries
-(BOOL)remove_item_from_allowlist:(NSDictionary*)item {
-(BOOL)remove_item_from_allowlist:(NSMutableDictionary*)item {

//iterate over the array
item = [self get_id_free_item:item];
Expand All @@ -184,10 +258,9 @@ -(BOOL)clear_allowlist {
return [self load];
}

-(NSDictionary* )get_id_free_item:(NSDictionary *)item {
NSMutableDictionary* element = [item mutableCopy];
[element removeObjectForKey:@"id"];
return [element copy];
-(NSMutableDictionary* )get_id_free_item:(NSMutableDictionary *)item {
[item removeObjectForKey:@"id"];
return [item copy];
}

@end
30 changes: 12 additions & 18 deletions Extension/ShieldMonitor.m
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ - (BOOL) monitor
//learning mode check, only effective if non-blocking
if(([preferences.preferences[PREF_ISLEARNING] boolValue] == YES) && ([preferences.preferences[PREF_ISBLOCKING] boolValue] == NO)) {
//add to allowlist
[allowlist add_item_to_allowlist:notification];
[allowlist add_item_to_allowlist:notification generic:NO];
}
//notify otherwise
else {
Expand All @@ -368,21 +368,6 @@ - (BOOL) monitor
ESFileCallbackBlock file_block = ^(File* file, es_client_t *client, es_message_t *message)
{

/*temporary fix for time machine madness*/
NSString* tm = @"/System/Library/CoreServices/backupd.bundle/Contents/Resources/backupd";
if([file.process.path isEqualToString:tm])
{
//we need to allow everything we ignore, otherwise everything will hang
if(ES_ACTION_TYPE_AUTH == message->action_type) {
es_respond_auth_result(client,
message,
ES_AUTH_RESULT_ALLOW,
false
);
}
//ignore
return;
}
es_auth_result_t authResult = ES_AUTH_RESULT_ALLOW;
es_respond_result_t res;
NSMutableDictionary* notification = [NSMutableDictionary new];
Expand Down Expand Up @@ -415,6 +400,10 @@ - (BOOL) monitor
notification[NOTIFICATION_LINK_PROCESS_PATH] = file.process.path;
notification[NOTIFICATION_LINK_FILE_UID] = [NSString stringWithFormat:@"%@",file_uid];
notification[NOTIFICATION_LINK_PROCESS_UID] = [NSString stringWithFormat:@"%d",file.process.uid];
if([allowlist is_item_in_allowlist:notification]) {
res = es_respond_auth_result(client, message, authResult, false);
break;
}
notify = YES;
if([[preferences.preferences objectForKey:PREF_ISBLOCKING] boolValue] == NO) {
os_log_error(log_handle, "Hardlink Attack detected source:%@ , process:%@", file.sourcePath, file.process.path);
Expand Down Expand Up @@ -460,13 +449,18 @@ - (BOOL) monitor
NSNumber* file_uid = get_file_uid(valid_path);
if (file_uid != nil) {
//file UID and process UID expected to be the same normally
if ([file_uid intValue] != file.process.uid ) {
//exclude events where a higgher priv process (0) point to lower priv (>0)
if (([file_uid intValue] != file.process.uid) && !([file_uid intValue] > 0 && file.process.uid == 0)) {
notification[NOTIFICATION_LINK_TYPE] = @"Symbolic link";
notification[NOTIFICATION_LINK_SOURCE_PATH] = [NSString stringWithFormat:@"%s",destination_path];
notification[NOTIFICATION_LINK_DESTINATION_PATH] = file.destinationPath;
notification[NOTIFICATION_LINK_PROCESS_PATH] = file.process.path;
notification[NOTIFICATION_LINK_FILE_UID] = [NSString stringWithFormat:@"%@",file_uid];
notification[NOTIFICATION_LINK_PROCESS_UID] = [NSString stringWithFormat:@"%d",file.process.uid];
if([allowlist is_item_in_allowlist:notification]) {
res = es_respond_auth_result(client, message, authResult, false);
break;
}
notify = YES;
if([[preferences.preferences objectForKey:PREF_ISBLOCKING] boolValue] == NO) {
os_log_error(log_handle, "Symlink Attack detected source:%@ , process:%@", file.destinationPath, file.process.path);
Expand Down Expand Up @@ -500,7 +494,7 @@ - (BOOL) monitor
//learning mode check, only effective if non-blocking
if(([preferences.preferences[PREF_ISLEARNING] boolValue] == YES) && ([preferences.preferences[PREF_ISBLOCKING] boolValue] == NO)) {
//add to allowlist
//[allowlist add_item_to_allowlist:notification];
[allowlist add_item_to_allowlist:notification generic:NO];
}
//notify otherwise
else {
Expand Down
4 changes: 2 additions & 2 deletions Extension/XPCExtension.m
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,10 @@ - (void) get_allowlist:(void (^)(NSArray *))reply {
reply([allowlist.allowlist_items copy]);
}

-(void)add_item_to_allowlist:(NSDictionary *)al reply:(void (^)(BOOL))reply
-(void)add_item_to_allowlist:(NSDictionary *)al generic:(BOOL)generic reply:(void (^)(BOOL))reply
{
os_log_debug(log_handle, "Updating allowlist");
reply([allowlist add_item_to_allowlist:[al mutableCopy]]);
reply([allowlist add_item_to_allowlist:[al mutableCopy] generic:generic]);
}

-(void)remove_item_from_allowlist:(NSDictionary *)al reply:(void (^)(BOOL))reply
Expand Down
Loading

0 comments on commit 2265a61

Please sign in to comment.