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/msf/base/sessions/powershell.rb
Views: 11784
# -*- coding: binary -*-12class Msf::Sessions::PowerShell < Msf::Sessions::CommandShell3module Mixin4#5# Takes over the shell_command of the parent6#7def shell_command(cmd, timeout = 1800)8# insert random marker9strm = Rex::Text.rand_text_alpha(15)10endm = Rex::Text.rand_text_alpha(15)1112# Send the shell channel's stdin.13shell_write(";'#{strm}'\n" + cmd + "\n'#{endm}';\n")1415etime = ::Time.now.to_f + timeout1617buff = ''18# Keep reading data until the marker has been received or the 30 minute timeout has occurred19while (::Time.now.to_f < etime)20res = shell_read(-1, timeout)21break unless res2223timeout = etime - ::Time.now.to_f2425buff << res26next unless buff.include?(endm)2728# if you see the end marker, read the buffer from the start marker to the end and then display back to screen29buff = buff.split(/#{strm}\r\n/)[-1]30buff = buff.split(endm)[0]31buff.gsub!(/(?<=\r\n)PS [^>]*>/, '')32return buff33end34buff35end36end3738include Mixin3940# Convert the executable and argument array to a command that can be run in this command shell41# @param cmd_and_args [Array<String>] The process path and the arguments to the process42def to_cmd(cmd_and_args)43self.class.to_cmd(cmd_and_args)44end4546# Convert the executable and argument array to a command that can be run in this command shell47# @param cmd_and_args [Array<String>] The process path and the arguments to the process48def self.to_cmd(cmd_and_args)49# The principle here is that we want to launch a process such that it receives *exactly* what is in `args`.50# This means we need to:51# - Escape all special characters52# - Not escape environment variables53# - Side-step any PowerShell magic54# If someone specifically wants to use the PowerShell magic, they can use other APIs5556needs_wrapping_chars = ['$', '`', '(', ')', '@', '>', '<', '{','}', '&', ',', ' ', ';']5758result = ""59cmd_and_args.each_with_index do |arg, index|60needs_single_quoting = false61if arg.include?("'")62arg = arg.gsub("'", "''")63needs_single_quoting = true64end6566if arg.include?('"')67# PowerShell acts weird around quotes and backslashes68# First we need to escape backslashes immediately prior to a double-quote, because69# they're treated differently than backslashes anywhere else70arg = arg.gsub(/(\\+)"/, '\\1\\1"')7172# Then we can safely prepend a backslash to escape our double-quote73arg = arg.gsub('"', '\\"')74needs_single_quoting = true75end7677needs_wrapping_chars.each do |char|78if arg.include?(char)79needs_single_quoting = true80end81end8283# PowerShell magic - https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_special_characters?view=powershell-7.4#stop-parsing-token---84if arg == '--%'85needs_single_quoting = true86end8788will_be_double_quoted_by_powershell = [' ', '\t', '\v'].any? do |bad_char|89arg.include?(bad_char)90end9192if will_be_double_quoted_by_powershell93# This is horrible, and I'm so so sorry.94# If an argument ends with a series of backslashes, and it will be quoted by PowerShell when *it* launches the process (e.g. because the arg contains a space),95# PowerShell will not correctly handle backslashes immediately preceeding the quote that it *itself* adds. So we need to be responsible for this.96arg = arg.gsub(/(\\*)$/, '\\1\\1')97end9899if needs_single_quoting100arg = "'#{arg}'"101end102103if arg == ''104# Pass in empty strings105arg = '\'""\''106end107108if index == 0109if needs_single_quoting110# If the executable name (i.e. index 0) has beeen wrapped, then we'll have converted it to a string.111# We then need to use the call operator ('&') to call it.112# https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_operators?view=powershell-7.3#call-operator-113result = "& #{arg}"114else115result = arg116end117else118result = "#{result} #{arg}"119end120end121122result123end124125#126# Execute any specified auto-run scripts for this session127#128def process_autoruns(datastore)129# Read the username and hostname from the initial banner130initial_output = shell_read(-1, 2)131if initial_output =~ /running as user ([^\s]+) on ([^\s]+)/132username = Regexp.last_match(1)133hostname = Regexp.last_match(2)134self.info = "#{username} @ #{hostname}"135elsif initial_output136self.info = initial_output.gsub(/[\r\n]/, ' ')137end138139# Call our parent class's autoruns processing method140super141end142143#144# Returns the type of session.145#146def self.type147'powershell'148end149150def self.can_cleanup_files151true152end153154#155# Returns the session platform.156#157def platform158'windows'159end160161#162# Returns the session description.163#164def desc165'Powershell session'166end167168end169170171