What what what, Post-Exploitation attack!
git-svn-id: file:///home/svn/incoming/trunk@2334 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
87e3fda1fc
commit
c5a1fe6716
|
@ -0,0 +1,3 @@
|
|||
#!/usr/bin/ruby
|
||||
|
||||
require 'Rex/Post/DispatchNinja'
|
|
@ -0,0 +1,3 @@
|
|||
#!/usr/bin/ruby
|
||||
|
||||
require 'Rex/Post/DispatchNinja/Client.rb'
|
|
@ -0,0 +1,77 @@
|
|||
#!/usr/bin/ruby
|
||||
|
||||
require 'Rex/Post/DispatchNinja/File'
|
||||
require 'Rex/Post/DispatchNinja/FileStat'
|
||||
require 'Rex/Post/DispatchNinja/Process'
|
||||
|
||||
module Rex
|
||||
module Post
|
||||
module DispatchNinja
|
||||
|
||||
class Client
|
||||
|
||||
private
|
||||
attr_accessor :sock
|
||||
public
|
||||
|
||||
def initialize(sock)
|
||||
self.sock = sock
|
||||
|
||||
checksig()
|
||||
end
|
||||
|
||||
def file
|
||||
klass = Rex::Post::DispatchNinja::File.dup
|
||||
klass.client = self
|
||||
return klass
|
||||
end
|
||||
|
||||
def filestat
|
||||
klass = Rex::Post::DispatchNinja::FileStat.dup
|
||||
klass.client = self
|
||||
return klass
|
||||
end
|
||||
|
||||
def process
|
||||
klass = Rex::Post::DispatchNinja::Process.dup
|
||||
klass.client = self
|
||||
return klass
|
||||
end
|
||||
|
||||
def sendmodule(name)
|
||||
name = 'lib/Rex/Post/DispatchNinja/modules/' + name
|
||||
data = IO.readlines(name, '')[0]
|
||||
sockwrite([data.length].pack('V'))
|
||||
sockwrite(data)
|
||||
end
|
||||
|
||||
def checksig
|
||||
if !select( [ sock ], nil, nil, 2)
|
||||
puts "Possible sync problem?"
|
||||
else
|
||||
sig = sockread(4)
|
||||
if sig != "AAAA"
|
||||
puts "Sig #{sig} didn't match"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def sendfilename(dir)
|
||||
dir += "\x00" # null terminate filename for easy syscall
|
||||
sockwrite( [ dir.length ].pack('V') )
|
||||
sockwrite(dir)
|
||||
end
|
||||
|
||||
# do true full read/write, blocking. So if I say read 4 bytes, I'll
|
||||
# block until I get all 4 bytes
|
||||
def sockwrite(data)
|
||||
sock.write(data)
|
||||
end
|
||||
|
||||
def sockread(len)
|
||||
return sock.read(len)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end; end; end # DispatchNinja/Post/Rex
|
|
@ -0,0 +1,117 @@
|
|||
#!/usr/bin/ruby
|
||||
|
||||
require 'Rex/DispatchNinja/Stat'
|
||||
|
||||
module Rex
|
||||
module Post
|
||||
module DispatchNinja
|
||||
|
||||
class File < Rex::Post::File
|
||||
|
||||
#
|
||||
# Class Methods
|
||||
#
|
||||
|
||||
@@structstat = [
|
||||
'st_dev', 2,
|
||||
'pad1', 2,
|
||||
'st_ino', 4,
|
||||
'st_mode', 2,
|
||||
'st_nlink', 2,
|
||||
'st_uid', 2,
|
||||
'st_gid', 2,
|
||||
'st_rdev', 2,
|
||||
'pad2', 2,
|
||||
'st_size', 4,
|
||||
'st_blksize', 4,
|
||||
'st_blocks', 4,
|
||||
'st_atime', 4,
|
||||
'unused1', 4,
|
||||
'st_mtime', 4,
|
||||
'unused2', 4,
|
||||
'st_ctime', 4,
|
||||
'unused3', 4,
|
||||
'unused4', 4,
|
||||
'unused5', 4
|
||||
]
|
||||
|
||||
# setup a class variable for our client pointer
|
||||
class <<self
|
||||
attr_accessor :client
|
||||
end
|
||||
|
||||
def File.stat(file)
|
||||
return client.filestat.new(file)
|
||||
end
|
||||
def ls(dir)
|
||||
|
||||
sendmodule('ls')
|
||||
|
||||
sendfilename(dir)
|
||||
|
||||
res = sockread(4).unpack('l')[0] # ug, not portable, later...
|
||||
|
||||
files = [ ]
|
||||
|
||||
while true
|
||||
len = sockread(2).unpack('S')[0]
|
||||
break if len == 0
|
||||
files << sockread(len)
|
||||
end
|
||||
|
||||
checksig()
|
||||
|
||||
return [ res, files ]
|
||||
end
|
||||
|
||||
def File.stat_hash(file)
|
||||
|
||||
client.sendmodule('stat')
|
||||
client.sendfilename(file)
|
||||
|
||||
data = client.sockread(68)
|
||||
res = data[0, 4].unpack('l')[0]
|
||||
|
||||
# throw exception! blah!
|
||||
|
||||
client.checksig()
|
||||
|
||||
data = data[4 .. -1]
|
||||
|
||||
elements = @@structstat
|
||||
hash = { }
|
||||
i = 0
|
||||
o = 0
|
||||
while i < elements.length
|
||||
name = elements[i]
|
||||
size = elements[i + 1]
|
||||
i += 2
|
||||
|
||||
e = data[o, size].unpack(size == 2 ? 'S' : 'L')[0]
|
||||
o += size
|
||||
|
||||
hash[name] = e
|
||||
end
|
||||
|
||||
return(hash)
|
||||
end
|
||||
|
||||
#
|
||||
# Instance Methods
|
||||
#
|
||||
|
||||
# setup an instance variable, just for ease and copy it over..
|
||||
# and so you can change it instance wise
|
||||
private
|
||||
attr_accessor :client
|
||||
public
|
||||
|
||||
def initialize()
|
||||
self.client = self.class.client
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
end; end; end # DispatchNinja/Post/Rex
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
#!/usr/bin/ruby
|
||||
|
||||
require 'Rex/Post/File'
|
||||
|
||||
module Rex
|
||||
module Post
|
||||
module DispatchNinja
|
||||
|
||||
class File < Rex::Post::File
|
||||
|
||||
# setup a class variable for our client pointer
|
||||
class <<self
|
||||
attr_accessor :client
|
||||
end
|
||||
|
||||
def File.stat(name)
|
||||
client.filestat.new(name)
|
||||
end
|
||||
|
||||
def File.stat_data(file)
|
||||
|
||||
client.sendmodule('stat')
|
||||
client.sendfilename(file)
|
||||
|
||||
data = client.sockread(68)
|
||||
res = data[0, 4].unpack('l')[0]
|
||||
|
||||
# throw exception! blah!
|
||||
|
||||
client.checksig()
|
||||
|
||||
return data[4 .. -1]
|
||||
end
|
||||
end
|
||||
|
||||
end; end; end # DispatchNinja/Post/Rex
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
#!/usr/bin/ruby
|
||||
|
||||
require 'Rex/Post/FileStat'
|
||||
|
||||
module Rex
|
||||
module Post
|
||||
module DispatchNinja
|
||||
|
||||
class FileStat < Rex::Post::FileStat
|
||||
|
||||
@@structstat = [
|
||||
'st_dev', 2,
|
||||
'pad1', 2,
|
||||
'st_ino', 4,
|
||||
'st_mode', 2,
|
||||
'st_nlink', 2,
|
||||
'st_uid', 2,
|
||||
'st_gid', 2,
|
||||
'st_rdev', 2,
|
||||
'pad2', 2,
|
||||
'st_size', 4,
|
||||
'st_blksize', 4,
|
||||
'st_blocks', 4,
|
||||
'st_atime', 4,
|
||||
'unused1', 4,
|
||||
'st_mtime', 4,
|
||||
'unused2', 4,
|
||||
'st_ctime', 4,
|
||||
'unused3', 4,
|
||||
'unused4', 4,
|
||||
'unused5', 4
|
||||
]
|
||||
class <<self
|
||||
attr_accessor :client
|
||||
end
|
||||
|
||||
def initialize(file)
|
||||
self.stathash = parse_struct_stat(self.class.client.file.stat_data(file))
|
||||
end
|
||||
def parse_struct_stat(data)
|
||||
elements = @@structstat
|
||||
hash = { }
|
||||
i = 0
|
||||
o = 0
|
||||
while i < elements.length
|
||||
name = elements[i]
|
||||
size = elements[i + 1]
|
||||
i += 2
|
||||
|
||||
e = data[o, size].unpack(size == 2 ? 'S' : 'L')[0]
|
||||
o += size
|
||||
|
||||
hash[name] = e
|
||||
end
|
||||
|
||||
return(hash)
|
||||
end
|
||||
end
|
||||
end; end; end # DispatchNinja/Post/Rex
|
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/ruby
|
||||
|
||||
require 'Rex/Post/Process'
|
||||
|
||||
module Rex
|
||||
module Post
|
||||
module DispatchNinja
|
||||
|
||||
class Process < Rex::Post::Process
|
||||
class <<self
|
||||
attr_accessor :client
|
||||
end
|
||||
|
||||
def Process.getresuid()
|
||||
|
||||
# gotta fix this, getresuid could fail
|
||||
# I don't transfer the return value on the wire...
|
||||
|
||||
client.sendmodule('getresuid')
|
||||
data = client.sockread(12)
|
||||
|
||||
client.checksig()
|
||||
return data.unpack('l3')
|
||||
end
|
||||
end
|
||||
|
||||
end; end; end # DispatchNinja/Post/Rex
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
#!/usr/bin/ruby
|
||||
|
||||
module Rex
|
||||
module Post
|
||||
|
||||
class File
|
||||
|
||||
#
|
||||
# Class Methods
|
||||
#
|
||||
|
||||
# setup a class variable for our client pointer
|
||||
# class <<self
|
||||
# attr_accessor :client
|
||||
# end
|
||||
|
||||
# def File.stat(file)
|
||||
# return client.filestat.new(file)
|
||||
# end
|
||||
|
||||
# def File.stat_hash(file)
|
||||
# raise NotImplementedError
|
||||
# end
|
||||
|
||||
#
|
||||
# autogen'd stat passthroughs
|
||||
#
|
||||
def File.atime(name)
|
||||
stat(name).atime
|
||||
end
|
||||
def File.blockdev?(name)
|
||||
stat(name).blockdev?
|
||||
end
|
||||
def File.chardev?(name)
|
||||
stat(name).chardev?
|
||||
end
|
||||
def File.ctime(name)
|
||||
stat(name).ctime
|
||||
end
|
||||
def File.directory?(name)
|
||||
stat(name).directory?
|
||||
end
|
||||
def File.executable?(name)
|
||||
stat(name).executable?
|
||||
end
|
||||
def File.executable_real?(name)
|
||||
stat(name).executable_real?
|
||||
end
|
||||
def File.file?(name)
|
||||
stat(name).file?
|
||||
end
|
||||
def File.ftype(name)
|
||||
stat(name).ftype
|
||||
end
|
||||
def File.grpowned?(name)
|
||||
stat(name).grpowned?
|
||||
end
|
||||
def File.mtime(name)
|
||||
stat(name).mtime
|
||||
end
|
||||
def File.owned?(name)
|
||||
stat(name).owned?
|
||||
end
|
||||
def File.pipe?(name)
|
||||
stat(name).pipe?
|
||||
end
|
||||
def File.readable?(name)
|
||||
stat(name).readable?
|
||||
end
|
||||
def File.readable_real?(name)
|
||||
stat(name).readable_real?
|
||||
end
|
||||
def File.setuid?(name)
|
||||
stat(name).setuid?
|
||||
end
|
||||
def File.setgid?(name)
|
||||
stat(name).setgid?
|
||||
end
|
||||
def File.size(name)
|
||||
stat(name).size
|
||||
end
|
||||
def File.socket?(name)
|
||||
stat(name).socket?
|
||||
end
|
||||
def File.sticky?(name)
|
||||
stat(name).sticky?
|
||||
end
|
||||
def File.symlink?(name)
|
||||
stat(name).symlink?
|
||||
end
|
||||
def File.writeable?(name)
|
||||
stat(name).writeable?
|
||||
end
|
||||
def File.writeable_real?(name)
|
||||
stat(name).writeable_real?
|
||||
end
|
||||
def File.zero?(name)
|
||||
stat(name).zero?
|
||||
end
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Instance Methods
|
||||
#
|
||||
|
||||
# setup an instance variable, just for ease and copy it over..
|
||||
# and so you can change it instance wise
|
||||
# private
|
||||
# attr_accessor :client
|
||||
# public
|
||||
|
||||
# def initialize()
|
||||
# self.client = self.class.client
|
||||
# end
|
||||
|
||||
|
||||
end
|
||||
|
||||
end; end # Post/Rex
|
|
@ -0,0 +1,198 @@
|
|||
#!/usr/bin/ruby
|
||||
|
||||
#
|
||||
# This is just a container class basically, that acts like File::Struct
|
||||
#
|
||||
# You must supply an initialize method that somehow populates the stathash..
|
||||
#
|
||||
|
||||
module Rex
|
||||
module Post
|
||||
|
||||
class FileStat
|
||||
@@ftypes = [
|
||||
'fifo', 'characterSpecial', 'directory',
|
||||
'blockSpecial', 'file', 'link', 'socket'
|
||||
]
|
||||
|
||||
# class <<self
|
||||
# attr_accessor :client
|
||||
# end
|
||||
|
||||
private
|
||||
attr_accessor :stathash
|
||||
public
|
||||
|
||||
# def initialize(file)
|
||||
# self.stathash = self.class.client.file.stat_hash(file)
|
||||
# end
|
||||
|
||||
def dev
|
||||
stathash['st_dev']
|
||||
end
|
||||
def ino
|
||||
stathash['st_ino']
|
||||
end
|
||||
def mode
|
||||
stathash['st_mode']
|
||||
end
|
||||
def nlink
|
||||
stathash['st_nlink']
|
||||
end
|
||||
def uid
|
||||
stathash['st_uid']
|
||||
end
|
||||
def gid
|
||||
stathash['st_gid']
|
||||
end
|
||||
def rdev
|
||||
stathash['st_rdev']
|
||||
end
|
||||
def size
|
||||
stathash['st_size']
|
||||
end
|
||||
def blksize
|
||||
stathash['st_blksize']
|
||||
end
|
||||
def blocks
|
||||
stathash['st_blocks']
|
||||
end
|
||||
def atime
|
||||
Time.at(stathash['st_atime'])
|
||||
end
|
||||
def mtime
|
||||
Time.at(stathash['st_mtime'])
|
||||
end
|
||||
def ctime
|
||||
Time.at(stathash['st_ctime'])
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# S_IFMT 0170000 bitmask for the file type bitfields
|
||||
# S_IFSOCK 0140000 socket
|
||||
# S_IFLNK 0120000 symbolic link
|
||||
# S_IFREG 0100000 regular file
|
||||
# S_IFBLK 0060000 block device
|
||||
# S_IFDIR 0040000 directory
|
||||
# S_IFCHR 0020000 character device
|
||||
# S_IFIFO 0010000 fifo
|
||||
#
|
||||
|
||||
# this is my own, just a helper...
|
||||
def filetype?(mask)
|
||||
return true if mode & 0170000 == mask
|
||||
return false
|
||||
end
|
||||
|
||||
def blockdev?
|
||||
filetype?(060000)
|
||||
end
|
||||
def chardev?
|
||||
filetype?(020000)
|
||||
end
|
||||
def directory?
|
||||
filetype?(040000)
|
||||
end
|
||||
def file?
|
||||
filetype?(0100000)
|
||||
end
|
||||
def pipe?
|
||||
filetype?(010000) # ??? fifo?
|
||||
end
|
||||
def socket?
|
||||
filetype(0140000)
|
||||
end
|
||||
def symlink?
|
||||
filetype(0120000)
|
||||
end
|
||||
|
||||
def ftype
|
||||
return @@ftypes[(mode & 0170000) >> 13].dup
|
||||
end
|
||||
|
||||
#
|
||||
# S_ISUID 0004000 set UID bit
|
||||
# S_ISGID 0002000 set GID bit (see below)
|
||||
# S_ISVTX 0001000 sticky bit (see below)
|
||||
# S_IRWXU 00700 mask for file owner permissions
|
||||
# S_IRUSR 00400 owner has read permission
|
||||
# S_IWUSR 00200 owner has write permission
|
||||
# S_IXUSR 00100 owner has execute permission
|
||||
# S_IRWXG 00070 mask for group permissions
|
||||
# S_IRGRP 00040 group has read permission
|
||||
# S_IWGRP 00020 group has write permission
|
||||
# S_IXGRP 00010 group has execute permission
|
||||
# S_IRWXO 00007 mask for permissions for others (not in group)
|
||||
# S_IROTH 00004 others have read permission
|
||||
# S_IWOTH 00002 others have write permisson
|
||||
# S_IXOTH 00001 others have execute permission
|
||||
#
|
||||
|
||||
def perm?(mask)
|
||||
return true if mode & mask == mask
|
||||
return false
|
||||
end
|
||||
|
||||
def setgid?
|
||||
perm?(02000)
|
||||
end
|
||||
def setuid?
|
||||
perm?(04000)
|
||||
end
|
||||
def sticky?
|
||||
perm?(01000)
|
||||
end
|
||||
|
||||
def executable?
|
||||
raise NotImplementedError
|
||||
end
|
||||
def executable_real?
|
||||
raise NotImplementedError
|
||||
end
|
||||
def grpowned?
|
||||
raise NotImplementedError
|
||||
end
|
||||
def owned?
|
||||
raise NotImplementedError
|
||||
end
|
||||
def readable?
|
||||
raise NotImplementedError
|
||||
end
|
||||
def readable_real?
|
||||
raise NotImplementedError
|
||||
end
|
||||
def writeable?
|
||||
raise NotImplementedError
|
||||
end
|
||||
def writeable_real?
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
def prettymode
|
||||
m = mode
|
||||
om = '%04o' % m
|
||||
perms = ''
|
||||
|
||||
3.times {
|
||||
perms = ((m & 01) == 01 ? 'x' : '-') + perms
|
||||
perms = ((m & 02) == 02 ? 'w' : '-') + perms
|
||||
perms = ((m & 04) == 04 ? 'r' : '-') + perms
|
||||
m >>= 3
|
||||
}
|
||||
|
||||
return "#{om}/#{perms}"
|
||||
end
|
||||
|
||||
def pretty
|
||||
" Size: #{size} Blocks: #{blocks} IO Block: #{blksize} Type: #{rdev}\n"\
|
||||
"Device: #{dev} Inode: #{ino} Links: #{nlink}\n"\
|
||||
" Mode: #{prettymode}\n"\
|
||||
" Uid: #{uid} Gid: #{gid}\n"\
|
||||
"Access: #{atime}\n"\
|
||||
"Modify: #{mtime}\n"\
|
||||
"Change: #{ctime}\n"
|
||||
end
|
||||
|
||||
end
|
||||
end; end # Post/Rex
|
|
@ -0,0 +1,13 @@
|
|||
#!/usr/bin/perl
|
||||
use strict;
|
||||
|
||||
|
||||
foreach my $f ('atime', 'blockdev?', 'chardev?', 'ctime', 'directory?',
|
||||
'executable?', 'executable_real?', 'file?', 'ftype', 'grpowned?',
|
||||
'mtime', 'owned?', 'pipe?', 'readable?', 'readable_real?', 'setuid?',
|
||||
'setgid?', 'size', 'socket?', 'sticky?', 'symlink?', 'writeable?',
|
||||
'writeable_real?', 'zero?') {
|
||||
|
||||
my $t = "\t";
|
||||
print "${t}def File.$f(name)\n\t${t}stat(name).$f\n${t}end\n";
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
#!/usr/bin/ruby
|
||||
|
||||
module Rex
|
||||
module Post
|
||||
|
||||
class Process
|
||||
|
||||
private_class_method :new
|
||||
|
||||
def Process.getresuid
|
||||
raise NotImplementedError
|
||||
end
|
||||
def Process.setresuid(a, b, c)
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
def Process.euid
|
||||
getresuid()[1]
|
||||
end
|
||||
def Process.euid=(id)
|
||||
setresuid(-1, id, -1)
|
||||
end
|
||||
def Process.uid
|
||||
getresuid()[0]
|
||||
end
|
||||
def Process.uid=(id)
|
||||
setresuid(id, -1, -1)
|
||||
end
|
||||
|
||||
def Process.egid
|
||||
getresgid()[1]
|
||||
end
|
||||
def Process.egid=(id)
|
||||
setresgid(-1, id, -1)
|
||||
end
|
||||
def Process.gid
|
||||
getresgid()[0]
|
||||
end
|
||||
def Process.gid=(id)
|
||||
setresgid(id, -1, -1)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end; end # Post/Rex
|
Loading…
Reference in New Issue