Landing #1874 - Post API cleanup
commit
90117c322c
|
@ -1,7 +1,6 @@
|
|||
# -*- coding: binary -*-
|
||||
require 'msf/core'
|
||||
require 'msf/core/module'
|
||||
require 'msf/core/post'
|
||||
|
||||
module Msf
|
||||
|
||||
|
@ -30,6 +29,8 @@ end
|
|||
###
|
||||
class Exploit < Msf::Module
|
||||
|
||||
require 'msf/core/post'
|
||||
require 'msf/core/exploit/local'
|
||||
|
||||
##
|
||||
# Exceptions
|
||||
|
@ -219,25 +220,6 @@ class Exploit < Msf::Module
|
|||
Passive = "passive"
|
||||
end
|
||||
|
||||
###
|
||||
#
|
||||
# The local exploit class is a specialization of the exploit module class that
|
||||
# is geared toward exploits that are performed locally. Locally, in this
|
||||
# case, is defined as an exploit that is realized by means other than network
|
||||
# communication.
|
||||
#
|
||||
###
|
||||
class Local < Exploit
|
||||
include PostMixin
|
||||
|
||||
#
|
||||
# Returns the fact that this exploit is a local exploit.
|
||||
#
|
||||
def exploit_type
|
||||
Exploit::Type::Local
|
||||
end
|
||||
end
|
||||
|
||||
###
|
||||
#
|
||||
# The remote exploit class is a specialization of the exploit module class
|
||||
|
@ -315,6 +297,7 @@ class Exploit < Msf::Module
|
|||
# algorithm. It's just important that it returns an array of all of the
|
||||
# mixin modules.
|
||||
#
|
||||
# @return [Array]
|
||||
def self.mixins
|
||||
mixins = []
|
||||
wl = [ Msf::Exploit ]
|
||||
|
|
|
@ -1,9 +1,28 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core/exploit/local/unix'
|
||||
require 'msf/core/exploit/local/linux_kernel'
|
||||
require 'msf/core/post_mixin'
|
||||
|
||||
module Msf
|
||||
module Exploit::Local
|
||||
class Exploit
|
||||
|
||||
###
|
||||
#
|
||||
# A specialization of the {Exploit exploit module class} that is geared
|
||||
# toward exploits that are performed locally. Locally, in this case,
|
||||
# is defined as an exploit that is realized by means other than
|
||||
# network communication.
|
||||
#
|
||||
###
|
||||
class Local < Exploit
|
||||
include PostMixin
|
||||
|
||||
#
|
||||
# Returns the fact that this exploit is a local exploit.
|
||||
#
|
||||
def exploit_type
|
||||
Exploit::Type::Local
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,209 +1,9 @@
|
|||
# -*- coding: binary -*-
|
||||
require 'msf/core'
|
||||
require 'msf/core/module'
|
||||
|
||||
require 'msf/core/post_mixin'
|
||||
|
||||
module Msf
|
||||
|
||||
#
|
||||
# A mixin used for providing Modules with post-exploitation options and helper methods
|
||||
#
|
||||
module PostMixin
|
||||
|
||||
include Msf::Auxiliary::Report
|
||||
|
||||
include Msf::Module::HasActions
|
||||
|
||||
def initialize(info={})
|
||||
super
|
||||
|
||||
register_options( [
|
||||
OptInt.new('SESSION', [ true, "The session to run this module on." ])
|
||||
] , Msf::Post)
|
||||
|
||||
# Default stance is active
|
||||
self.passive = (info['Passive'] and info['Passive'] == true) || false
|
||||
end
|
||||
|
||||
#
|
||||
# Grabs a session object from the framework or raises OptionValidateError
|
||||
# if one doesn't exist. Initializes user input and output on the session.
|
||||
#
|
||||
def setup
|
||||
if not session
|
||||
raise Msf::OptionValidateError.new(["SESSION"])
|
||||
end
|
||||
|
||||
super
|
||||
|
||||
check_for_session_readiness() if session.type == "meterpreter"
|
||||
|
||||
@session.init_ui(self.user_input, self.user_output)
|
||||
@sysinfo = nil
|
||||
end
|
||||
|
||||
# Meterpreter sometimes needs a little bit of extra time to
|
||||
# actually be responsive for post modules. Default tries
|
||||
# and retries for 5 seconds.
|
||||
def check_for_session_readiness(tries=6)
|
||||
session_ready_count = 0
|
||||
session_ready = false
|
||||
until session.sys or session_ready_count > tries
|
||||
session_ready_count += 1
|
||||
back_off_period = (session_ready_count**2)/10.0
|
||||
select(nil,nil,nil,back_off_period)
|
||||
end
|
||||
session_ready = !!session.sys
|
||||
raise "Could not get a hold of the session." unless session_ready
|
||||
return session_ready
|
||||
end
|
||||
|
||||
#
|
||||
# Default cleanup handler does nothing
|
||||
#
|
||||
def cleanup
|
||||
end
|
||||
|
||||
#
|
||||
# Return the associated session or nil if there isn't one
|
||||
#
|
||||
def session
|
||||
# Try the cached one
|
||||
return @session if @session and not session_changed?
|
||||
|
||||
if datastore["SESSION"]
|
||||
@session = framework.sessions[datastore["SESSION"].to_i]
|
||||
else
|
||||
@session = nil
|
||||
end
|
||||
|
||||
@session
|
||||
end
|
||||
|
||||
alias :client :session
|
||||
|
||||
#
|
||||
# Cached sysinfo, returns nil for non-meterpreter sessions
|
||||
#
|
||||
def sysinfo
|
||||
begin
|
||||
@sysinfo ||= session.sys.config.sysinfo
|
||||
rescue NoMethodError
|
||||
@sysinfo = nil
|
||||
end
|
||||
@sysinfo
|
||||
end
|
||||
|
||||
#
|
||||
# Can be overridden by individual modules to add new commands
|
||||
#
|
||||
def post_commands
|
||||
{}
|
||||
end
|
||||
|
||||
def passive?
|
||||
self.passive
|
||||
end
|
||||
|
||||
#
|
||||
# Return a (possibly empty) list of all compatible sessions
|
||||
#
|
||||
def compatible_sessions
|
||||
sessions = []
|
||||
framework.sessions.each do |sid, s|
|
||||
sessions << sid if session_compatible?(s)
|
||||
end
|
||||
sessions
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Return false if the given session is not compatible with this module
|
||||
#
|
||||
# Checks the session's type against this module's
|
||||
# +module_info["SessionTypes"]+ as well as examining platform
|
||||
# compatibility. +sess_or_sid+ can be a Session object, Fixnum, or String.
|
||||
# In the latter cases it sould be a key in in +framework.sessions+.
|
||||
#
|
||||
# NOTE: because it errs on the side of compatibility, a true return value
|
||||
# from this method does not guarantee the module will work with the
|
||||
# session.
|
||||
#
|
||||
def session_compatible?(sess_or_sid)
|
||||
# Normalize the argument to an actual Session
|
||||
case sess_or_sid
|
||||
when ::Fixnum, ::String
|
||||
s = framework.sessions[sess_or_sid.to_i]
|
||||
when ::Msf::Session
|
||||
s = sess_or_sid
|
||||
end
|
||||
|
||||
# Can't do anything without a session
|
||||
return false if s.nil?
|
||||
|
||||
# Can't be compatible if it's the wrong type
|
||||
if self.module_info["SessionTypes"]
|
||||
return false unless self.module_info["SessionTypes"].include?(s.type)
|
||||
end
|
||||
|
||||
# XXX: Special-case java and php for now. This sucks and Session
|
||||
# should have a method to auto-detect the underlying platform of
|
||||
# platform-independent sessions such as these.
|
||||
plat = s.platform
|
||||
if plat =~ /php|java/ and sysinfo and sysinfo["OS"]
|
||||
plat = sysinfo["OS"]
|
||||
end
|
||||
|
||||
# Types are okay, now check the platform. This is kind of a ghetto
|
||||
# workaround for session platforms being ad-hoc and Platform being
|
||||
# inflexible.
|
||||
if self.platform and self.platform.kind_of?(Msf::Module::PlatformList)
|
||||
[
|
||||
# Add as necessary
|
||||
"win", "linux", "osx"
|
||||
].each do |name|
|
||||
if plat =~ /#{name}/
|
||||
p = Msf::Module::PlatformList.transform(name)
|
||||
return false unless self.platform.supports? p
|
||||
end
|
||||
end
|
||||
elsif self.platform and self.platform.kind_of?(Msf::Module::Platform)
|
||||
p_klass = Msf::Module::Platform
|
||||
case plat.downcase
|
||||
when /win/
|
||||
return false unless self.platform.kind_of?(p_klass::Windows)
|
||||
when /osx/
|
||||
return false unless self.platform.kind_of?(p_klass::OSX)
|
||||
when /linux/
|
||||
return false unless self.platform.kind_of?(p_klass::Linux)
|
||||
end
|
||||
end
|
||||
|
||||
# If we got here, we haven't found anything that definitely
|
||||
# disqualifies this session. Assume that means we can use it.
|
||||
return true
|
||||
end
|
||||
|
||||
#
|
||||
# True when this module is passive, false when active
|
||||
#
|
||||
attr_reader :passive
|
||||
|
||||
protected
|
||||
|
||||
attr_writer :passive
|
||||
|
||||
def session_changed?
|
||||
@ds_session ||= datastore["SESSION"]
|
||||
|
||||
if (@ds_session != datastore["SESSION"])
|
||||
@ds_session = nil
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# A Post-exploitation module
|
||||
#
|
||||
|
|
|
@ -0,0 +1,221 @@
|
|||
# -*- coding: binary -*-
|
||||
require 'msf/core'
|
||||
require 'msf/core/module'
|
||||
|
||||
module Msf
|
||||
|
||||
#
|
||||
# A mixin used for providing Modules with post-exploitation options and helper methods
|
||||
#
|
||||
module PostMixin
|
||||
|
||||
include Msf::Auxiliary::Report
|
||||
|
||||
include Msf::Module::HasActions
|
||||
|
||||
def initialize(info={})
|
||||
super
|
||||
|
||||
register_options( [
|
||||
OptInt.new('SESSION', [ true, "The session to run this module on." ])
|
||||
] , Msf::Post)
|
||||
|
||||
# Default stance is active
|
||||
self.passive = (info['Passive'] and info['Passive'] == true) || false
|
||||
end
|
||||
|
||||
#
|
||||
# Grabs a session object from the framework or raises {OptionValidateError}
|
||||
# if one doesn't exist. Initializes user input and output on the session.
|
||||
#
|
||||
# @raise [OptionValidateError] if {#session} returns nil
|
||||
def setup
|
||||
if not session
|
||||
raise Msf::OptionValidateError.new(["SESSION"])
|
||||
end
|
||||
|
||||
super
|
||||
|
||||
check_for_session_readiness() if session.type == "meterpreter"
|
||||
|
||||
@session.init_ui(self.user_input, self.user_output)
|
||||
@sysinfo = nil
|
||||
end
|
||||
|
||||
# Meterpreter sometimes needs a little bit of extra time to
|
||||
# actually be responsive for post modules. Default tries
|
||||
# and retries for 5 seconds.
|
||||
def check_for_session_readiness(tries=6)
|
||||
session_ready_count = 0
|
||||
session_ready = false
|
||||
until session.sys or session_ready_count > tries
|
||||
session_ready_count += 1
|
||||
back_off_period = (session_ready_count**2)/10.0
|
||||
select(nil,nil,nil,back_off_period)
|
||||
end
|
||||
session_ready = !!session.sys
|
||||
raise "Could not get a hold of the session." unless session_ready
|
||||
return session_ready
|
||||
end
|
||||
|
||||
#
|
||||
# Default cleanup handler does nothing
|
||||
#
|
||||
def cleanup
|
||||
end
|
||||
|
||||
#
|
||||
# Return the associated session or nil if there isn't one
|
||||
#
|
||||
# @return [Msf::Session]
|
||||
# @return [nil] if the id provided in the datastore does not
|
||||
# correspond to a session
|
||||
def session
|
||||
# Try the cached one
|
||||
return @session if @session and not session_changed?
|
||||
|
||||
if datastore["SESSION"]
|
||||
@session = framework.sessions[datastore["SESSION"].to_i]
|
||||
else
|
||||
@session = nil
|
||||
end
|
||||
|
||||
@session
|
||||
end
|
||||
|
||||
alias :client :session
|
||||
|
||||
#
|
||||
# Cached sysinfo, returns nil for non-meterpreter sessions
|
||||
#
|
||||
# @return [Hash,nil]
|
||||
def sysinfo
|
||||
begin
|
||||
@sysinfo ||= session.sys.config.sysinfo
|
||||
rescue NoMethodError
|
||||
@sysinfo = nil
|
||||
end
|
||||
@sysinfo
|
||||
end
|
||||
|
||||
#
|
||||
# Can be overridden by individual modules to add new commands
|
||||
#
|
||||
def post_commands
|
||||
{}
|
||||
end
|
||||
|
||||
# Whether this module's {Msf::Exploit::Stance} is {Msf::Exploit::Stance::Passive passive}
|
||||
def passive?
|
||||
self.passive
|
||||
end
|
||||
|
||||
#
|
||||
# Return a (possibly empty) list of all compatible sessions
|
||||
#
|
||||
# @return [Array]
|
||||
def compatible_sessions
|
||||
sessions = []
|
||||
framework.sessions.each do |sid, s|
|
||||
sessions << sid if session_compatible?(s)
|
||||
end
|
||||
sessions
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Return false if the given session is not compatible with this module
|
||||
#
|
||||
# Checks the session's type against this module's
|
||||
# <tt>module_info["SessionTypes"]</tt> as well as examining platform
|
||||
# compatibility. +sess_or_sid+ can be a Session object, Fixnum, or
|
||||
# String. In the latter cases it sould be a key in
|
||||
# +framework.sessions+.
|
||||
#
|
||||
# @note Because it errs on the side of compatibility, a true return
|
||||
# value from this method does not guarantee the module will work
|
||||
# with the session.
|
||||
#
|
||||
# @param sess_or_sid [Msf::Session,Fixnum,String]
|
||||
# A session or session ID to compare against this module for
|
||||
# compatibility.
|
||||
#
|
||||
def session_compatible?(sess_or_sid)
|
||||
# Normalize the argument to an actual Session
|
||||
case sess_or_sid
|
||||
when ::Fixnum, ::String
|
||||
s = framework.sessions[sess_or_sid.to_i]
|
||||
when ::Msf::Session
|
||||
s = sess_or_sid
|
||||
end
|
||||
|
||||
# Can't do anything without a session
|
||||
return false if s.nil?
|
||||
|
||||
# Can't be compatible if it's the wrong type
|
||||
if self.module_info["SessionTypes"]
|
||||
return false unless self.module_info["SessionTypes"].include?(s.type)
|
||||
end
|
||||
|
||||
# XXX: Special-case java and php for now. This sucks and Session
|
||||
# should have a method to auto-detect the underlying platform of
|
||||
# platform-independent sessions such as these.
|
||||
plat = s.platform
|
||||
if plat =~ /php|java/ and sysinfo and sysinfo["OS"]
|
||||
plat = sysinfo["OS"]
|
||||
end
|
||||
|
||||
# Types are okay, now check the platform. This is kind of a ghetto
|
||||
# workaround for session platforms being ad-hoc and Platform being
|
||||
# inflexible.
|
||||
if self.platform and self.platform.kind_of?(Msf::Module::PlatformList)
|
||||
[
|
||||
# Add as necessary
|
||||
"win", "linux", "osx"
|
||||
].each do |name|
|
||||
if plat =~ /#{name}/
|
||||
p = Msf::Module::PlatformList.transform(name)
|
||||
return false unless self.platform.supports? p
|
||||
end
|
||||
end
|
||||
elsif self.platform and self.platform.kind_of?(Msf::Module::Platform)
|
||||
p_klass = Msf::Module::Platform
|
||||
case plat.downcase
|
||||
when /win/
|
||||
return false unless self.platform.kind_of?(p_klass::Windows)
|
||||
when /osx/
|
||||
return false unless self.platform.kind_of?(p_klass::OSX)
|
||||
when /linux/
|
||||
return false unless self.platform.kind_of?(p_klass::Linux)
|
||||
end
|
||||
end
|
||||
|
||||
# If we got here, we haven't found anything that definitely
|
||||
# disqualifies this session. Assume that means we can use it.
|
||||
return true
|
||||
end
|
||||
|
||||
#
|
||||
# True when this module is passive, false when active
|
||||
#
|
||||
# @return [Boolean]
|
||||
# @see passive?
|
||||
attr_reader :passive
|
||||
|
||||
protected
|
||||
|
||||
attr_writer :passive
|
||||
|
||||
def session_changed?
|
||||
@ds_session ||= datastore["SESSION"]
|
||||
|
||||
if (@ds_session != datastore["SESSION"])
|
||||
@ds_session = nil
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -27,7 +27,6 @@ class Metasploit4 < Msf::Exploit::Local
|
|||
include Msf::Post::File
|
||||
include Msf::Post::Common
|
||||
|
||||
include Msf::Exploit::Local::LinuxKernel
|
||||
include Msf::Exploit::Local::Linux
|
||||
include Msf::Exploit::Local::Unix
|
||||
|
||||
|
@ -47,7 +46,7 @@ class Metasploit4 < Msf::Exploit::Local
|
|||
'egypt' # metasploit module
|
||||
],
|
||||
'Platform' => [ 'linux' ],
|
||||
'Arch' => [ ARCH_X86 ],
|
||||
'Arch' => [ ARCH_X86, ARCH_X86_64 ],
|
||||
'SessionTypes' => [ 'shell', 'meterpreter' ],
|
||||
'References' =>
|
||||
[
|
||||
|
@ -103,53 +102,74 @@ class Metasploit4 < Msf::Exploit::Local
|
|||
call exit
|
||||
|
|
||||
|
||||
# Set up the same include order as the bionic build system.
|
||||
# See external/source/meterpreter/source/bionic/libc/Jamfile
|
||||
cparser.lexer.include_search_path = [
|
||||
"external/source/meterpreter/source/bionic/libc/include/",
|
||||
"external/source/meterpreter/source/bionic/libc/private/",
|
||||
"external/source/meterpreter/source/bionic/libc/bionic/",
|
||||
"external/source/meterpreter/source/bionic/libc/kernel/arch-x86/",
|
||||
"external/source/meterpreter/source/bionic/libc/kernel/common/",
|
||||
"external/source/meterpreter/source/bionic/libc/arch-x86/include/",
|
||||
]
|
||||
|
||||
cparser.parse(%Q|
|
||||
#define DEBUGGING
|
||||
// Fixes a parse error in bionic's libc/kernel/arch-x86/asm/types.h
|
||||
#ifndef __extension__
|
||||
#define __extension__
|
||||
#endif
|
||||
// Fixes a parse error in bionic's libc/include/sys/cdefs_elf.h
|
||||
// Doing #if on an undefined macro is fine in GCC, but a parse error in
|
||||
// metasm.
|
||||
#ifndef __STDC__
|
||||
#define __STDC__ 0
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|)
|
||||
|
||||
[
|
||||
"external/source/meterpreter/source/bionic/libc/bionic/__errno.c",
|
||||
"external/source/meterpreter/source/bionic/libc/bionic/__set_errno.c",
|
||||
"external/source/meterpreter/source/bionic/libc/stdio/stdio.c",
|
||||
].each do |fname|
|
||||
cparser.parse(File.read(fname), fname)
|
||||
end
|
||||
|
||||
payload_path = "#{datastore["WritableDir"]}/#{Rex::Text.rand_text_alpha(10)}"
|
||||
evil_path = "#{datastore["WritableDir"]}/#{Rex::Text.rand_text_alpha(10)}"
|
||||
|
||||
unix_socket_h(sc)
|
||||
linux_x86_syscall_wrappers(sc)
|
||||
|
||||
main = %Q^
|
||||
/*
|
||||
** All of these includes are now factorized.
|
||||
**/
|
||||
/*
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <linux/netlink.h>
|
||||
*/
|
||||
|
||||
#define NETLINK_KOBJECT_UEVENT 15
|
||||
#define PF_NETLINK 16
|
||||
#define SOCK_DGRAM 2
|
||||
#define AF_NETLINK PF_NETLINK
|
||||
|
||||
typedef unsigned short __kernel_sa_family_t;
|
||||
typedef unsigned int __socklen_t;
|
||||
typedef int __ssize_t;
|
||||
typedef unsigned int __u32;
|
||||
extern int close(int __fd);
|
||||
typedef unsigned short sa_family_t;
|
||||
typedef unsigned long size_t;
|
||||
extern int socket(int __domain, int __type, int __protocol);
|
||||
extern int sprintf(char *__s, const char *__format, ...);
|
||||
|
||||
const struct iovec {
|
||||
void *iov_base;
|
||||
size_t iov_len;
|
||||
};
|
||||
extern void *memset(void *__s, int __c, size_t __n);
|
||||
|
||||
const struct sockaddr {
|
||||
sa_family_t sa_family;
|
||||
char sa_data[14];
|
||||
};
|
||||
|
||||
struct sockaddr_nl {
|
||||
__kernel_sa_family_t nl_family;
|
||||
unsigned short nl_pad;
|
||||
__u32 nl_pid;
|
||||
__u32 nl_groups;
|
||||
};
|
||||
typedef __socklen_t socklen_t;
|
||||
typedef __ssize_t ssize_t;
|
||||
|
||||
extern int bind(int __fd, const struct sockaddr *__addr, socklen_t __len);
|
||||
|
||||
const struct msghdr {
|
||||
void *msg_name;
|
||||
socklen_t msg_namelen;
|
||||
const struct iovec *msg_iov;
|
||||
size_t msg_iovlen;
|
||||
void *msg_control;
|
||||
size_t msg_controllen;
|
||||
int msg_flags;
|
||||
};
|
||||
|
||||
extern ssize_t sendmsg(int __fd, const struct msghdr *__message, int __flags);
|
||||
/* end factorize */
|
||||
|
||||
#define NULL 0
|
||||
|
||||
int main() {
|
||||
|
@ -196,6 +216,10 @@ int main() {
|
|||
}
|
||||
^
|
||||
cparser.parse(main, "main.c")
|
||||
# This will give you all the structs and #defines (from all included
|
||||
# headers) that are actually used by our C code so we can avoid
|
||||
# needing them at runtime.
|
||||
#puts cparser.factorize
|
||||
|
||||
asm = cpu.new_ccompiler(cparser, sc).compile
|
||||
|
||||
|
|
Loading…
Reference in New Issue