From f3e03ddb4233ea4f4011d29fa7025dffefde6dfd Mon Sep 17 00:00:00 2001 From: Chris John Riley Date: Fri, 2 Nov 2012 16:32:34 +0100 Subject: [PATCH] Concrete5 CMS member list scanner --- .../scanner/concrete5_member_list.rb | 137 ++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 modules/auxiliary/scanner/concrete5_member_list.rb diff --git a/modules/auxiliary/scanner/concrete5_member_list.rb b/modules/auxiliary/scanner/concrete5_member_list.rb new file mode 100644 index 0000000000..70953d1773 --- /dev/null +++ b/modules/auxiliary/scanner/concrete5_member_list.rb @@ -0,0 +1,137 @@ +## +# $Id$ +## + +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + +require 'msf/core' + +class Metasploit4 < Msf::Auxiliary + + include Msf::Exploit::Remote::HttpClient + include Msf::Auxiliary::Scanner + include Msf::Auxiliary::Report + + def initialize + super( + 'Name' => 'Concrete5 Member List', + 'Version' => '$Revision$', + 'Description' => %q{ + This module extracts username information from the Concrete5 member page + }, + 'References' => + [ + # General + [ 'URL', 'http://blog.c22.cc' ] + ], + 'Author' => [ 'Chris John Riley' ], + 'License' => MSF_LICENSE + ) + + register_options( + [ + Opt::RPORT(80), + OptString.new('URI', [false, 'URL of the Concrete5 root', '/']), + ], self.class) + deregister_options('RHOST') + end + + def run_host(rhost) + # check the only one forward slash appears in the url + if datastore['URI'][0,1] == "/" + url = datastore['URI'] + else + url = "/" + datastore['URI'] + end + + begin + res = send_request_cgi({ + 'uri' => "#{url}/members", + 'method' => 'GET', + 'headers' => + { + 'User-Agent' => datastore['UserAgent'] + } + }, 25) + + rescue ::Rex::ConnectionError + print_error("#{rhost}:#{rport} Unable to connect to #{url}") + return + end + + if not res + print_error("#{rhost}:#{rport} Unable to connect to #{url}") + return + end + + # extract member info from response if present + if res and res.body =~ /ccm-profile-member-username/i + extract_members(res, url) + elsif res + print_status("#{rhost}:#{rport} No members listed or profiles disabled") + else + print_error("#{rhost}:#{rport} No response received") + end + + end + + def extract_members(res, url) + + members = res.body.scan(/
(.*)<\/div>/i) + + if members + print_good("#{rhost}:#{rport} Extracted #{members.length} entries") + + # separate user data into userID, username and Profile URL + memberlist = [] + users = [] + + members.each do | mem | + userid = mem[0].scan(/\/view\/(\d+)/i) + username = mem[0].scan(/">(.+)<\/a>/i) + profile = mem[0].scan(/href="(.+)">/i) + # add all data to memberlist for table output + memberlist.push([userid[0], username[0], profile[0]]) + # add usernames to users array for reporting + users.push(username[0]) + end + + membertbl = Msf::Ui::Console::Table.new( + Msf::Ui::Console::Table::Style::Default, + 'Header' => "Concrete5 members", + 'Prefix' => "\n", + 'Postfix' => "\n", + 'Indent' => 1, + 'Columns' => + [ + "UserID", + "Username", + "Profile" + ]) + + memberlist.each do | mem | + membertbl << ["#{mem[0].join}", "#{mem[1].join}", "#{mem[2].join}"] + end + + # print table + print(membertbl.to_s) + + #store username to loot + report_note( + :host => rhost, + :port => rport, + :proto => 'tcp', + :type => "concrete5 CMS members", + :data => {:proto => "http", :users => users.join(",")}, + ) + + else + print_status("#{rhost}:#{rport} Unable to extract members") + end + end +end