jxa 入门
A poor man’s Powershell for macOS
适用于macOS的穷人的Powershell
介绍 (Introduction)
Over the last year or so, I have been diving into macOS tradecraft. Through my research, an area of particular interest is the use of JavaScript for Automation (JXA) on macOS. My goal was to fulfill an operational need to decrease dependency on Python and further my understanding of macOS tradecraft that I can hopefully build on. This post serves as an overview of the benefits of JXA for macOS tradecraft development, highlights a well-known persistence method, and a few lesser-known JXA execution methods.
在过去的大约一年中,我一直在研究macOS tradecraft。 通过我的研究,特别感兴趣的领域是在macOS上使用JavaScript for Automation(JXA)。 我的目标是满足操作需求,以减少对Python的依赖,并进一步理解我希望可以建立的macOS tradecraft。 这篇文章概述了JXA对macOS Tradecraft开发的好处,重点介绍了一种众所周知的持久性方法和一些鲜为人知的JXA执行方法。
JXA的简史 (A Brief History of JXA)
MacOS Yosemite (10.10) introduced JXA. Its implementation allows users to control applications and the operating system using the JavaScript language. It can be invoked via osascript
, a compiled script (.scpt
), or a compiled Application (.app
). Additionally, it can be leveraged in OSAKit from within other macho binaries without spawning the osascript
binary.
MacOS Yosemite(10.10)引入了JXA。 它的实现允许用户使用JavaScript语言控制应用程序和操作系统。 可以通过osascript
,已编译脚本( .scpt
)或已编译应用程序( .app
)调用它。 另外,可以在OSAKit中从其他猛男二进制文件中利用它,而不会产生osascript
二进制文件。
为什么选择JXA? (Why JXA?)
The preferred method for post-exploitation macOS tradecraft is scripting languages over binaries. They allow attackers to avoid leveraging unsigned code and avoid going through the code signing cert process with Apple. Compiled binaries are subject to more scrutiny due to the built-in protections on macOS (Gatekeeper, Notarization, and XProtect).
漏洞利用后的macOS Tradecraft的首选方法是在二进制文件上编写脚本语言。 它们使攻击者可以避免利用未签名的代码,并避免与Apple一起进行代码签名证书过程。 由于macOS上的内置保护(Gatekeeper,Notarization和XProtect),编译后的二进制文件将受到更多审查。
As mentioned previously, Python was the favorite for macOS post-exploitation tradecraft. Python was great for macOS tradecraft as it was easy to develop with and installed by default of macOS. However, the following note from the macOS Catalina (10.15) release indicates Apple is slowly migrating away from having Python and other scripting languages included by default.
如前所述,Python是macOS开发后交易工具的最爱。 Python非常适合macOS tradecraft,因为它很容易使用macOS开发并默认安装。 但是,以下来自macOS Catalina(10.15)发行版的注释表明Apple逐渐从默认包含Python和其他脚本语言迁移。
Upon looking for future areas of tradecraft development, another option that arose was AppleScript. AppleScript has the same benefits of JXA but is quirky and, in my opinion, harder to develop with than JXA. It’s quirky because it attempts to use “natural language.” The best description I heard was it is trying to script through a series of conversations with Siri.
在寻找未来的Craft.io品开发领域时,出现了另一个选择是AppleScript 。 AppleScript具有与JXA相同的优点,但是它很古怪,而且在我看来,与JXA一起开发更难。 这很奇怪,因为它尝试使用“自然语言”。 我听到的最好的描述是它试图通过与Siri的一系列对话来编写脚本。
Based on those considerations, I turned towards JXA. JXA has similarities with early Powershell versions. It is not as robust as Powershell but allows for a convenient method to interact with macOS. JXA has a built-in Objective-C bridge that enables you to access the file system and Cocoa frameworks, such as Foundation and AppKit, which allows us to call Apple APIs without building binaries. Similar to Powershell commands, you can even obfuscate your commands using a simple JavaScript obfuscator to slow down defenders.
基于这些考虑,我转向了JXA。 JXA与早期Powershell版本具有相似之处。 它不如Powershell强大,但允许使用便捷的方法与macOS进行交互。 JXA具有内置的Objective-C桥,使您能够访问文件系统和Cocoa框架,例如Foundation和AppKit,这使我们能够在不构建二进制文件的情况下调用Apple API。 与Powershell命令类似,您甚至可以使用简单JavaScript 模糊处理程序来模糊化命令,从而降低防御程序的速度。
There are a few projects that leverage JXA for macOS tradecraft. HealthInspector and Orchard from its-a-feature leverage JXA for host situational awareness and Active Directory enumeration, respectively. Additionally, the Apfell JXA agent which facilitates Command and Control (C2).
有一些项目将JXA用于macOS tradecraft。 HealthInspector和Orchard利用其功能来分别利用JXA进行主机态势感知和Active Directory枚举。 此外, Apfell JXA代理可简化命令和控制(C2)。
持久JXA (Persistent JXA)
To further develop my understanding of established macOS tradecraft, I developed the PersistentJXA project.
为了进一步了解已建立的macOS Tradecraft,我开发了PersistentJXA项目。
This section goes through a couple of usage examples as well as the related detections.
本节介绍了几个用法示例以及相关的检测。
持久性的Bash配置文件 (Bash Profiles for Persistence)
背景 (Background)
An older persistence method on macOS is the use of bash profiles. As a brief background, the ~/.bash_profile is a shell script that contains shell commands and is executed in the user’s context when a new shell opens. Attackers can abuse this by adding malicious commands to the profile to maintain persistence.
在macOS上,较旧的持久性方法是使用bash配置文件。 作为简要背景 ,〜/ .bash_profile是一个包含脚本命令的shell脚本,并在打开新的shell时在用户上下文中执行。 攻击者可以通过向配置文件添加恶意命令来保持持久性,从而滥用此功能。
The benefit of this persistence mechanism is that if an organization allows end-users to modify bash profiles, mitigation, and even detection becomes difficult due to the number of false positives. In my testing, I have found it easier to detect the actions the profile performs than the modification of the bash profile itself.
这种持久性机制的好处在于,如果组织允许最终用户修改bash配置文件,则由于误报的数量,缓解,甚至检测变得困难。 在测试中,我发现检测配置文件执行的操作比修改bash配置文件本身更容易。
The implementation within PersistentJXA checks to determine if osascript
is running; if not, it executes our persistence action (assumed osascript
) upon opening a new terminal window. Since macOS Catalina, zshell
is the default shell. If the script detects the host as macOS Catalina, then ~/.zshenv
is used instead.
PersistentJXA中的实现检查以确定osascript
是否正在运行; 如果没有,它将在打开新的终端窗口时执行我们的持久性动作(假定为osascript
)。 从macOS Catalina开始, zshell
是默认的shell。 如果脚本将主机检测为macOS Catalina,则使用~/.zshenv
。
用法 (Usage)
The Apfell JXA agent can leverage all of the scripts within the PersistentJXA project. To gain access to the function, use the jsimport
command.
Apfell JXA代理可以利用PersistentJXA项目中的所有脚本。 要访问该功能,请使用jsimport
命令。
![Image for post](https://miro.medium.com/max/9999/1*u_romVSl5OOV7hAZ4XLcpw.png)
After importing, we can use the jsimport_call
command to run the imported function.
导入后,我们可以使用jsimport_call
命令运行导入的函数。
![Image for post](https://miro.medium.com/max/9999/1*MREMKY0CFRHZpf_M_p9jaA.png)
The PersistentJXA implementation of bash profile persistence creates two shell scripts in a created hidden directory. The apple.sh
script provides the osascript
monitoring action and the update.sh
contains the user-specified persistence action.
bash概要文件持久性的PersistentJXA实现在创建的隐藏目录中创建两个Shell脚本。 apple.sh
脚本提供osascript
监视操作,而update.sh
包含用户指定的持久性操作。
侦测 (Detection)
Again the modification of the ~/.bash_profile
can be tracked but is not scalable. However, other elements of the persistence method can be detected.
同样,可以跟踪~/.bash_profile
的修改,但不能扩展。 但是,可以检测到持久性方法的其他元素。
osquery does not capture process events by default. For my testing, I made modifications to the Palantir osquery configuration found here and here. I then forwarded the osquery logs to Splunk.
osquery默认不捕获进程事件。 为了进行测试,我对此处和此处找到的Palantir osquery配置进行了修改。 然后,我将osquery日志转发到Splunk。
osquery captures the chmod
actions on the apple.sh
and update.sh
scripts within the created hidden directory ./security
.
osquery在已创建的隐藏目录./security
捕获apple.sh
和update.sh
脚本上的chmod
操作。
![Image for post](https://miro.medium.com/max/9999/1*KRimT6Bs2Pp62yAn-kNzDQ.png)
Additionally, osquery captures those scripts’ execution events upon opening a new terminal window in which osascript
is not already running.
另外,osquery在打开尚未运行osascript
的新终端窗口时捕获这些脚本的执行事件。
![Image for post](https://miro.medium.com/max/9999/1*HwMhCoSNSlGwzjXbGlNrxA.png)
![Image for post](https://miro.medium.com/max/9999/1*UKY5VxwJR-N2nmgFmeASEA.png)
Lastly, osquery captures the launching of the persistence action (Apfell JXA payload). Flagging on the osascript
invocation would be the most straightforward detection approach and would still occur if the persistence action was placed directly in the bash profile.
最后,osquery捕获持久性动作(Apfell JXA有效负载)的启动。 对osascript
调用进行标记将是最直接的检测方法,并且如果将持久性操作直接放置在bash概要文件中,则仍然会发生。
![Image for post](https://miro.medium.com/max/9999/1*Ep7Er3HLGVlSWXuFCcTOnQ.png)
![Image for post](https://miro.medium.com/max/9999/1*ZuF6yF-5rf2de3YmncET4A.png)
崇高的持久性插件 (Sublime Plugin for Persistence)
背景 (Background)
Another persistence method is abusing sublime plugins. This method discovered by Chris Ross (xorrior) exploits the ability of end-users creating plugins for Sublime.
另一种持久性方法是滥用Sublime插件。 克里斯·罗斯( xorrior )发现的这种方法利用了最终用户为Sublime创建插件的能力。
The Sublime Text Editor provides the ability to create plugins that Sublime loads upon application execution. Adversaries can take advantage of this mechanism to plant malicious plugins to gain persistence. The abuse of Sublime Text Editor plugins requires a plugin at ~/Library/Application\ Support\ Text\ <2 or 3>\Packages
. These plugins are typically python scripts. If a malicious plugin is placed in the Packages
directory and is formatted to load our malicious dynamic library (dylib), then Sublime will execute our code upon initialization by the user under the context of Sublime plugin_host
.
Sublime文本编辑器提供了创建在应用程序执行时Sublime加载的插件的功能。 攻击者可以利用这种机制来植入恶意插件以获得持久性。 要滥用Sublime Text Editor插件,需要使用~/Library/Application\ Support\ Text\ <2 or 3>\Packages
的插件。 这些插件通常是python脚本。 如果将恶意插件放置在Packages
目录中并经过格式化以加载我们的恶意动态库(dylib),则Sublime将在用户在Sublime plugin_host
上下文下初始化时执行我们的代码。
用法 (Usage)
![Image for post](https://miro.medium.com/max/9999/1*tN86MKv5A1ZY8wsH4Uy_Nw.png)
This persistence method requires uploading/creating a dylib on the target. After importing, we can use the jsimport_call
command to run the imported function, specifying the targeted dylib location.
此持久性方法需要在目标上上传/创建dylib。 导入后,我们可以使用jsimport_call
命令运行导入的函数,并指定目标dylib位置。
![Image for post](https://miro.medium.com/max/9999/1*j1Pi0Y4w1fZ5UGLuZLVyng.png)
The PersistentJXA implementation creates a fake plugin called PrettyText
to load the dylib.
PersistentJXA实现创建了一个名为PrettyText
的假插件来加载dylib。
![Image for post](https://miro.medium.com/max/9999/1*ngWZcw2osxeJ3qFdN7I8Lg.png)
侦测 (Detection)
From Truetree, we can follow the process execution from Finder to Sublime Text and ultimately to the Sublime Text plugin_host
, which is PID 661
.
在Truetree中 ,我们可以跟踪从Finder到Sublime Text并最终到达Sublime Text plugin_host
的过程执行,即PID 661
。
![Image for post](https://miro.medium.com/max/9999/1*QRGmb-Qsd2B5UI67EY_1xg.png)
Additionally, we can monitor the creation of Sublime plugins within the packages folder, but your mileage will vary depending on use in the environment. Also, network connections under the plugin host process is a nontypical occurrence.
此外,我们可以在packages文件夹中监视Sublime插件的创建,但是您的工作量会因环境中的使用而异。 同样,插件宿主进程下的网络连接是非典型的。
![Image for post](https://miro.medium.com/max/9999/1*B_FKWuBVwzJnxhkRQ9aqdg.png)
![Image for post](https://miro.medium.com/max/9999/1*_HFeUNG8QPEPUt4Fxakwpw.png)
plugin_host
PID 661
plugin_host
PID 661中运行
Sublime Application Script for Persistence (Sublime Application Script for Persistence)
背景 (Background)
Another fun method is using the Sublime application script for persistence. This method, discovered by theevilbit, allows us to simply execute our JXA payload on Sublime startup without requiring a dylib on the target. Through the modification of the application script located at /Applications/Sublime\ Text.app/Contents/MacOS/sublime.py
, we can have our payload executed when the target user starts Sublime.
另一个有趣的方法是使用Sublime应用程序脚本进行持久化。 该方法由theevilbit发现, 它使我们可以在Sublime启动时简单地执行JXA有效负载,而无需在目标服务器上使用dylib。 通过修改位于/Applications/Sublime\ Text.app/Contents/MacOS/sublime.py
的应用程序脚本,可以在目标用户启动Sublime时执行有效负载。
用法 (Usage)
![Image for post](https://miro.medium.com/max/9999/1*VM7CjeU1MQtmeaYxn_IhWw.png)
Next, call the function and specify our persistence action.
接下来,调用该函数并指定我们的持久性动作。
![Image for post](https://miro.medium.com/max/9999/1*hBLjCLnG-vWLldoYJkzUUQ.png)
![Image for post](https://miro.medium.com/max/9999/1*gzepSUjTKV9sPit5SNt8Og.png)
侦测 (Detection)
This method follows a similar process tree as the plugin method except osascript
is a child of Sublime Text. We can see the process execution from Finder to Sublime Text to osascript
, PID 2212
.
该方法遵循与插件方法相似的过程树,只是osascript
是Sublime Text的子级。 我们可以看到从Finder到Sublime Text到osascript
( PID 2212
的过程执行。
![Image for post](https://miro.medium.com/max/9999/1*6qBzZ2OH0QKe9togeBW6ZQ.png)
Furthermore, osquery captures the launching of our payload.
此外,osquery捕获有效负载的启动。
![Image for post](https://miro.medium.com/max/9999/1*w_lOuzpPx_kmjGsE849aDg.png)
![Image for post](https://miro.medium.com/max/9999/1*NSM9bsEKnneLZKWg1g0HYw.png)
If enabled, another artifact would be the file modification of the sublime.py script, which is not typically modified unless the entire Sublime package is under a change.
如果启用,另一个工件将是sublime.py脚本的文件修改,除非整个Sublime软件包都处于更改状态,否则通常不会进行修改。
自动化的持久性工作流程 (Automator Workflows for Persistence)
Through my research, I found that Automator can execute JXA as well. Automator allows for the completion of tasks through workflow files. The actions can interact with a variety of apps and parts of macOS. Perhaps unknown to some, there is a command-line tool for Automator. It is vastly reduced compared to its GUI counterpart but allows for the execution of workflow files.
通过研究,我发现Automator也可以执行JXA。 Automator允许通过工作流文件完成任务。 这些动作可以与各种应用程序和部分macOS进行交互。 也许某些人不知道,有一个Automator命令行工具。 与GUI相比,它大大减少了,但允许执行工作流文件。
We can create a workflow in the Automator GUI that will run our JXA payload and leverage the Automator command-line tool to execute. This method is merely replacing osascript
command-line usage with Automator for a command-line detection perspective. Although simple, it is a useful option to bypass any of the alerts only looking at osascript
.
我们可以在Automator GUI中创建一个工作流,该工作流将运行我们的JXA有效负载并利用Automator命令行工具执行。 此方法仅用Automator替换osascript
命令行用法,以用于命令行检测。 尽管很简单,但是绕过仅查看osascript
任何警报是一个有用的选项。
Within the PersistentJXA project is a workflow template, which is a modified version of the one created through the Automator GUI.
PersistentJXA项目中有一个工作流程模板,它是通过Automator GUI创建的工作模板的修改版本。
To create through the workflow through Automator, first, we select the workflow template.
要通过Automator创建工作流,首先,我们选择工作流模板。
![Image for post](https://miro.medium.com/max/9999/1*P10QnohEY-U33JAcBTy1Vw.png)
Next, we select the Run JavaScript action and paste our JXA payload.
接下来,我们选择“运行JavaScript”操作并粘贴我们的JXA有效负载。
![Image for post](https://miro.medium.com/max/9999/1*qE4UdGMq2Ym3TU1b7bwTaw.png)
After creation, we can take out the created document.wflow
file under <FileName>.workflow/Contents/
, upload to the target, and invoke using the command line Automator binary.
创建后,我们可以在<FileName>.workflow/Contents/
下取出创建的document.wflow
文件,上传到目标,然后使用命令行Automator二进制文件进行调用。
![Image for post](https://miro.medium.com/max/9999/1*kb4qSXoP05qi_Vz7PRJDow.png)
侦测 (Detection)
Command-line detection for Automator binary is a simple alert as its usage is probably uncommon in environments.
Automator二进制文件的命令行检测是一个简单的警报,因为在环境中它的用法可能并不常见。
![Image for post](https://miro.medium.com/max/9999/1*AYd3q71GqwuV4X9Ojic8OQ.png)
Another indicator with this method is due to the long-running processes resulting in the “cog” indicator. As noted in the post regarding folder actions, longer running processes result in an icon in the top menu bar indicating that something is processing, and if you click on it, you can see the workflow name.
此方法的另一个指标是由于长时间运行的过程导致出现“ cog”指标。 如有关文件夹操作的文章所述,长时间运行的进程会在顶部菜单栏中显示一个图标,指示正在处理某些内容,如果单击该图标,则可以看到工作流程名称。
![Image for post](https://miro.medium.com/max/9999/1*__lrPoCqWTTZ17hs6fPGow.png)
As far as the process tree, the execution of Automator shows a child of the terminal app, but the com.automator.runner.xpc PID 2569
in which our payload is executing under is not a child of Automator PID 2658
yet appears to be a separate child of the terminal app. However, killing the Automator process kills the runner, which is what our payload is running in.
就进程树而言,Automator的执行显示了终端应用程序的子级,但是有效负载在其下执行的com.automator.runner.xpc PID 2569
不是Automator PID 2658
的子级,终端应用程序的单独子项。 但是,杀死Automator进程会杀死运行程序,这是我们的有效负载所运行的。
![Image for post](https://miro.medium.com/max/9999/1*FSCgtJQuF1WpuumZoOvzCg.png)
结论 (Conclusion)
The purpose of this post was to display the benefits of JXA while highlighting some lesser-known persistence methods on macOS. By no means are the implementations within the PersistentJXA project perfect. I’m still new to macOS tradecraft and JXA development. If you have any thoughts on improvements/ additions, I am open to pull requests 😃. Regardless, I hope this post serves as a starting point for those interested in reviewing some macOS persistence methods and provides a starting point on some indicators to aid detections of malicious behavior.
这篇文章的目的是展示JXA的好处,同时重点介绍macOS上一些鲜为人知的持久性方法。 PersistentJXA项目中的实现绝不是完美的。 我仍然是macOS tradecraft和JXA开发的新手。 如果您对改进/增加有任何想法,我愿意提出要求requests。 无论如何,我希望这篇博文可以作为那些对审查某些macOS持久性方法感兴趣的人的起点,并为一些有助于检测恶意行为的指标提供起点。
参考资料/资源: (References / Resources:)
https://www.sentinelone.com/blog/how-offensive-actors-use-applescript-for-attacking-macos/
https://www.sentinelone.com/blog/how-offensive-actors-use-applescript-for-attacking-macos/
https://developer.apple.com/documentation/macos-release-notes/macos-catalina-10_15-release-notes
https://developer.apple.com/documentation/macos-release-notes/macos-catalina-10_15-release-notes
https://hackmag.com/coding/getting-to-grips-with-javascript-automation-for-os-x/
https://hackmag.com/coding/getting-to-grips-with-javascript-automation-for-os-x/
https://osquery.readthedocs.io/en/stable/deployment/process-auditing/
https://osquery.readthedocs.io/zh_CN/stable/deployment/process-auditing/
https://medium.com/@zercurity/process-monitoring-with-osquery-22c6f38fc239
https://medium.com/@zercurity/process-monitoring-with-osquery-22c6f38fc239
翻译自: https://posts.specterops.io/persistent-jxa-66e1c3cd1cf5
jxa 入门