Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GSOC] Post-exploitation API improvements and pseudo_shell (metashell) module added #10119

Merged
merged 24 commits into from Jan 24, 2019
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
c9a4cc4
Initial upload of Vulnerateca Post-Exploitation Framework (VPEF)
invalid-email-address May 31, 2018
6df8e28
Some syntax fixes and name changes
invalid-email-address Jun 1, 2018
96cd65a
Added new whoami module and some fixes
invalid-email-address Jun 1, 2018
be1ea15
Post-exploitation API improvements and pseudo_shell module added
invalid-email-address Jun 19, 2018
53e6fae
Module description fixed
AlbertoCoding Jun 19, 2018
667f6cb
Some minor fixes in pseudo_shell module and priv.rb
AlbertoCoding Jun 19, 2018
247437c
Change global variables to instance variables in pseudo_shell module …
AlbertoCoding Jun 21, 2018
33e9d1a
clear_screen function added
AlbertoCoding Jun 21, 2018
5b36515
Merge remote-tracking branch 'origin/master' into vpef
AlbertoCoding Jul 12, 2018
5b60a91
Style and code optimization changes
AlbertoCoding Jul 12, 2018
60becc2
Native DNS Spoofing module added
AlbertoCoding Jul 12, 2018
9341348
IPTABLES rules removal module added
AlbertoCoding Jul 12, 2018
259b92a
iptables_removal.rb module added
AlbertoCoding Aug 14, 2018
75ef8e8
enum_commands.rb module added
AlbertoCoding Aug 14, 2018
9bf7bec
Multiple functions to simulate native commands added
AlbertoCoding Aug 14, 2018
e43798b
minor fix
AlbertoCoding Aug 14, 2018
8e109b4
Some minor fixes
AlbertoCoding Aug 14, 2018
bb24c31
Minor code style fixes made
AlbertoCoding Aug 15, 2018
3bf4726
Fix pid_uid
wvu Jan 15, 2019
06de16a
Merge remote-tracking branch 'upstream/master' into pr/10119
wvu Jan 16, 2019
f8af9a9
Merge remote-tracking branch 'upstream/master' into pr/10119
wvu Jan 18, 2019
8b68072
Fix whoami
wvu Jan 24, 2019
006faa3
Fix prompt
wvu Jan 24, 2019
8cdcba8
Fix SessionTypes
wvu Jan 24, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
46 changes: 41 additions & 5 deletions lib/msf/core/post/common.rb
Expand Up @@ -2,6 +2,10 @@

module Msf::Post::Common

def clear_screen
Gem.win_platform? ? (system "cls") : (system "clear")
end

def rhost
return nil unless session

Expand Down Expand Up @@ -80,10 +84,31 @@ def has_pid?(pid)
#
# Returns a (possibly multi-line) String.
#
def cmd_exec(cmd, args="", time_out=15)
def cmd_exec(cmd, args=nil, time_out=15)
case session.type
when /meterpreter/
#
# The meterpreter API requires arguments to come separately from the
# executable path. This has no effect on Windows where the two are just
# blithely concatenated and passed to CreateProcess or its brethren. On
# POSIX, this allows the server to execve just the executable when a
# shell is not needed. Determining when a shell is not needed is not
# always easy, so it assumes anything with arguments needs to go through
# /bin/sh.
#
# This problem was originally solved by using Shellwords.shellwords but
# unfortunately, it is unsuitable. When a backslash occurs inside double
# quotes (as is often the case with Windows commands) it inexplicably
# removes them. So. Shellwords is out.
#
# By setting +args+ to an empty string, we can get POSIX to send it
# through /bin/sh, solving all the pesky parsing troubles, without
# affecting Windows.
#
start = Time.now.to_i
if args.nil? and cmd =~ /[^a-zA-Z0-9\/._-]/
args = ""
end

session.response_timeout = time_out
process = session.sys.process.execute(cmd, args, {'Hidden' => true, 'Channelized' => true})
Expand All @@ -99,6 +124,7 @@ def cmd_exec(cmd, args="", time_out=15)
end
end
end
o.chomp! if o

begin
process.channel.close
Expand All @@ -108,12 +134,22 @@ def cmd_exec(cmd, args="", time_out=15)

process.close
when /powershell/
o = session.shell_command("#{cmd} #{args}", time_out)
if args.nil? || args.empty?
o = session.shell_command("#{cmd}", time_out)
else
o = session.shell_command("#{cmd} #{args}", time_out)
end
o.chomp! if o
when /shell/
o = session.shell_command_token("#{cmd} #{args}", time_out)
if args.nil? || args.empty?
o = session.shell_command_token("#{cmd}", time_out)
else
o = session.shell_command_token("#{cmd} #{args}", time_out)
end
o.chomp! if o
end

o ? o.chomp : ""
return "" if o.nil?
return o
end

def cmd_exec_get_pid(cmd, args=nil, time_out=15)
Expand Down
69 changes: 45 additions & 24 deletions lib/msf/core/post/file.rb
Expand Up @@ -32,7 +32,12 @@ def pwd
# and 2k
return session.shell_command_token("echo %CD%")
else
return session.shell_command_token("pwd")
if command_exists?("pwd")
return session.shell_command_token("pwd")
else
# Result on systems without pwd command
return session.shell_command_token("echo $PWD")
end
end
end
end
Expand All @@ -43,13 +48,29 @@ def pwd
def dir(directory)
if session.type == 'meterpreter'
return session.fs.dir.entries(directory)
else
if session.platform == 'windows'
return session.shell_command_token("dir #{directory}").split(/[\r\n]+/)
else
return session.shell_command_token("ls #{directory}").split(/[\r\n]+/)
bcoles marked this conversation as resolved.
Show resolved Hide resolved
end
end

if session.platform == 'windows'
return session.shell_command_token("dir #{directory}").split(/[\r\n]+/)
end

if command_exists?('ls')
return session.shell_command_token("ls #{directory}").split(/[\r\n]+/)
end

# Result on systems without ls command
if directory[-1] != '/'
directory = directory + "/"
end
result = []
data = session.shell_command_token("for fn in #{directory}*; do echo $fn; done")
parts = data.split("\n")
parts.each do |line|
line = line.split("/")[-1]
result.insert(-1, line)
end

result
end

alias ls dir
Expand All @@ -69,7 +90,6 @@ def directory?(path)
else
f = session.shell_command_token("test -d \"#{path}\" && echo true")
end

return false if f.nil? || f.empty?
return false unless f =~ /true/
true
Expand Down Expand Up @@ -106,7 +126,6 @@ def file?(path)
else
f = session.shell_command_token("test -f \"#{path}\" && echo true")
end

return false if f.nil? || f.empty?
return false unless f =~ /true/
true
Expand All @@ -128,7 +147,6 @@ def setuid?(path)
if session.platform != 'windows'
f = session.shell_command_token("test -u \"#{path}\" && echo true")
end

return false if f.nil? || f.empty?
return false unless f =~ /true/
true
Expand All @@ -149,7 +167,6 @@ def exist?(path)
else
f = cmd_exec("test -e \"#{path}\" && echo true")
end

return false if f.nil? || f.empty?
return false unless f =~ /true/
true
Expand All @@ -168,7 +185,6 @@ def file_local_write(local_file_name, data)
unless ::File.exist?(local_file_name)
::FileUtils.touch(local_file_name)
end

output = ::File.open(local_file_name, "a")
data.each_line do |d|
output.puts(d)
Expand Down Expand Up @@ -275,19 +291,26 @@ def file_remote_digestsha2(file_name)
#
# @param file_name [String] Remote file name to read
# @return [String] Contents of the file
#
# @return [Array] of strings(lines)
#
def read_file(file_name)
bcoles marked this conversation as resolved.
Show resolved Hide resolved
data = nil
if session.type == "meterpreter"
data = _read_file_meterpreter(file_name)
elsif session.type == "shell"
if session.platform == 'windows'
data = session.shell_command_token("type \"#{file_name}\"")
else
data = session.shell_command_token("cat \"#{file_name}\"")
end
if session.type == 'meterpreter'
return _read_file_meterpreter(file_name)
end

return nil unless session.type == 'shell'

if session.platform == 'windows'
return session.shell_command_token("type \"#{file_name}\"")
end
data

if command_exists?('cat')
return session.shell_command_token("cat \"#{file_name}\"")
end

# Result on systems without cat command
session.shell_command_token("while read line; do echo $line; done <#{file_name}")
end

# Platform-agnostic file write. Writes given object content to a remote file.
Expand All @@ -308,7 +331,6 @@ def write_file(file_name, data)
else
_write_file_unix_shell(file_name, data)
end

end
true
end
Expand Down Expand Up @@ -387,7 +409,6 @@ def rm_rf(*remote_dirs)
end
end
end

alias :file_rm :rm_f
alias :dir_rm :rm_rf

Expand Down
136 changes: 125 additions & 11 deletions lib/msf/core/post/linux/priv.rb
Expand Up @@ -9,23 +9,137 @@ module Priv

#
# Returns true if running as root, false if not.
# @return [Boolean]
#
def is_root?
bcoles marked this conversation as resolved.
Show resolved Hide resolved
root_priv = false
user_id = cmd_exec("id -u")
clean_user_id = user_id.to_s.gsub(/[^\d]/,"")
unless clean_user_id.empty?
if clean_user_id =~ /^0$/
root_priv = true
elsif clean_user_id =~ /^\d*$/
root_priv = false
if command_exists?('id')
user_id = cmd_exec('id -u')
clean_user_id = user_id.to_s.gsub(/[^\d]/, '')
if clean_user_id.empty?
raise "Could not determine UID: #{user_id.inspect}"
end
else
raise "Could not determine UID: #{user_id.inspect}"
return clean_user_id.match(/^0$/) ? true : false
end
return root_priv
user = whoami
data = cmd_exec('while read line; do echo $line; done </etc/passwd')
data.each_line do |line|
line = line.split(':')
return true if line[0] == user && line[3].to_i == 0
end
false
end

#
# Multiple functions to simulate native commands added
#

def download_cmd(remote_path, local_path)
file_origin = read_file(remote_path)
`echo "#{file_origin}" > #{local_path}`
end

def touch_cmd(new_path_file)
cmd_exec("> #{new_path_file}")
end

def cp_cmd(origin_file, final_file)
file_origin = read_file(origin_file)
cmd_exec("echo '#{file_origin}' > #{final_file}")
end

def pids()
dir_proc = "/proc/"
pids = []

directories_proc = dir(dir_proc)
directories_proc.each do |elem|
elem.gsub( / *\n+/, "")
if elem[-1] == '1' || elem[-1] == '2' || elem[-1] == '3' || elem[-1] == '4' || elem[-1] == '5' || elem[-1] == '6' || elem[-1] == '7' || elem[-1] == '8' || elem[-1] == '9' || elem[-1] == '0'
pids.insert(-1, elem)
end
end

return pids.sort_by(&:to_i)
end

def binary_of_pid(pid)
binary = read_file("/proc/#{pid}/cmdline")
if binary == "" #binary.empty?
binary = read_file("/proc/#{pid}/comm")
end
if binary[-1] == "\n"
binary = binary.split("\n")[0]
end
return binary
end

def seq(first, increment, last)
result = []
(first..last).step(increment) do |i|
result.insert(-1, i)
end
return result
end

def wc_cmd(file)
[nlines_file(file), nwords_file(file), nchars_file(file), file]
end

def nchars_file(file)
nchars = 0
lines = read_file(file).split("\n")
nchars = lines.length()
lines.each do |line|
line.gsub(/[ ]/, ' ' => '')
nchars_line = line.length()
nchars = nchars + nchars_line
end
return nchars
end

def nwords_file(file)
nwords = 0
lines = read_file(file).split("\n")
lines.each do |line|
words = line.split(" ")
nwords_line = words.length()
nwords = nwords + nwords_line
end
return nwords
end

def nlines_file(file)
lines = read_file(file).split("\n")
nlines = lines.length()
return nlines
end

def head_cmd(file, nlines)
lines = read_file(file).split("\n")
result = lines[0..nlines-1]
return result
end

def tail_cmd(file, nlines)
lines = read_file(file).split("\n")
result = lines[-1*(nlines)..-1]
return result
end

def grep_cmd(file, string)
result = []
lines = read_file(file).split("\n")

lines.each do |line|
if line.include?(string)
result.insert(-1, line)
end
end
return result
end



end # Priv
end # Linux
end # Post
Expand Down