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/lib/rex/parser/unattend.rb
Views: 11780
# -*- coding: binary -*-12module Rex3module Parser45# This is a parser for the Windows Unattended Answer File6# format. It's used by modules/post/windows/gather/enum_unattend.rb7# and uses REXML (as opposed to Nokogiri) for its XML parsing.8# See: http://technet.microsoft.com/en-us/library/ff7158019# http://technet.microsoft.com/en-us/library/cc749415(v=ws.10).aspx10# Samples: http://technet.microsoft.com/en-us/library/cc732280%28v=ws.10%29.aspx11class Unattend1213require 'rex/text'1415def self.parse(xml)16return [] if xml.nil?17results = []18unattend = xml.elements['unattend']19return [] if unattend.nil?20unattend.each_element do |settings|21next if settings.class != REXML::Element22settings.get_elements('component').each do |c|23next if c.class != REXML::Element24results << extract_useraccounts(c.elements['UserAccounts'])25results << extract_autologon(c.elements['AutoLogon'])26results << extract_deployment(c.elements['WindowsDeploymentServices'])27results << extract_domain_join(c.elements['Identification/Credentials'])28end29end30return results.flatten31end3233#34# Extract sensitive data from Deployment Services.35# We can only seem to add one <Login> with Windows System Image Manager, so36# we'll only enum one.37#38def self.extract_deployment(deployment)39return [] if deployment.nil?40domain = deployment.elements['Login/Credentials/Domain'].get_text.value rescue ''41username = deployment.elements['Login/Credentials/Username'].get_text.value rescue ''42password = deployment.elements['Login/Credentials/Password'].get_text.value rescue ''43plaintext = deployment.elements['Login/Credentials/Password/PlainText'].get_text.value rescue 'true'4445if plaintext == 'false'46password = Rex::Text.decode_base64(password)47password = password.gsub(/#{Rex::Text.to_unicode('Password')}$/, '')48end4950return {'type' => 'wds', 'domain' => domain, 'username' => username, 'password' => password }51end5253#54# Extract sensitive data from 'Secure' Domain Join55#56def self.extract_domain_join(credentials)57return [] if credentials.nil?58domain = credentials.elements['Domain'].get_text.value rescue ''59username = credentials.elements['Username'].get_text.value rescue ''60password = credentials.elements['Password'].get_text.value rescue ''6162return {'type' => 'domain_join', 'domain' => domain, 'username' => username, 'password' => password }63end6465#66# Extract sensitive data from AutoLogon67#68def self.extract_autologon(auto_logon)69return [] if auto_logon.nil?7071domain = auto_logon.elements['Domain'].get_text.value rescue ''72username = auto_logon.elements['Username'].get_text.value rescue ''73password = auto_logon.elements['Password/Value'].get_text.value rescue ''74plaintext = auto_logon.elements['Password/PlainText'].get_text.value rescue 'true'7576if plaintext == 'false'77password = Rex::Text.decode_base64(password)78password = password.gsub(/#{Rex::Text.to_unicode('Password')}$/, '')79end8081return {'type' => 'auto', 'domain' => domain, 'username' => username, 'password' => password }82end8384#85# Extract sensitive data from UserAccounts86#87def self.extract_useraccounts(user_accounts)88return[] if user_accounts.nil?8990results = []91account_types = ['AdministratorPassword', 'DomainAccounts', 'LocalAccounts']92account_types.each do |t|93element = user_accounts.elements[t]94next if element.nil?9596case t97#98# Extract the password from AdministratorPasswords99#100when account_types[0]101password = element.elements['Value'].get_text.value rescue ''102plaintext = element.elements['PlainText'].get_text.value rescue 'true'103104if plaintext == 'false'105password = Rex::Text.decode_base64(password)106password = password.gsub(/#{Rex::Text.to_unicode('AdministratorPassword')}$/, '')107end108109unless password.empty?110results << {'type' => 'admin', 'username' => 'Administrator', 'password' => password}111end112113#114# Extract the sensitive data from DomainAccounts.115# According to MSDN, unattend.xml doesn't seem to store passwords for domain accounts116#117when account_types[1] #DomainAccounts118element.elements.each do |account_list|119name = account_list.elements['DomainAccount/Name'].get_text.value rescue ''120group = account_list.elements['DomainAccount/Group'].get_text.value rescue 'true'121122results << {'type' => 'domain', 'username' => name, 'group' => group}123end124#125# Extract the username/password from LocalAccounts126#127when account_types[2] #LocalAccounts128element.elements.each do |local|129password = local.elements['Password/Value'].get_text.value rescue ''130plaintext = local.elements['Password/PlainText'].get_text.value rescue 'true'131132if plaintext == 'false'133password = Rex::Text.decode_base64(password)134password = password.gsub(/#{Rex::Text.to_unicode('Password')}$/, '')135end136137username = local.elements['Name'].get_text.value rescue ''138results << {'type' => 'local', 'username' => username, 'password' => password}139end140end141end142143return results144end145146def self.create_table(results)147return nil if results.nil? or results.empty?148table = Rex::Text::Table.new({149'Header' => 'Unattend Credentials',150'Indent' => 1,151'Columns' => ['Type', 'Domain', 'Username', 'Password', 'Groups']152})153154results.each do |result|155case result['type']156when 'wds', 'auto', 'domain_join'157table << [result['type'], result['domain'], result['username'], result['password'], ""]158when 'admin', 'local'159table << [result['type'], "", result['username'], result['password'], ""]160when 'domain'161table << [result['type'], "", result['username'], "", result['group']]162end163end164165return table166end167end168end169end170171172173