Add some spec mockery
parent
81fa509b50
commit
975ddc9092
|
@ -42,7 +42,7 @@ module Msf::Post::Windows::Runas
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Create a STARTUP_INFO struct for use with CreateProcessa
|
# Create a STARTUP_INFO struct for use with CreateProcessA
|
||||||
#
|
#
|
||||||
# This struct will cause the process to be hidden
|
# This struct will cause the process to be hidden
|
||||||
#
|
#
|
||||||
|
@ -192,6 +192,9 @@ module Msf::Post::Windows::Runas
|
||||||
# @return [Hash] The values from the process_information struct
|
# @return [Hash] The values from the process_information struct
|
||||||
#
|
#
|
||||||
def parse_process_information(process_information)
|
def parse_process_information(process_information)
|
||||||
|
fail ArgumentError, 'process_information is nil' if process_information.nil?
|
||||||
|
fail ArgumentError, 'process_information is empty string' if process_information.empty?
|
||||||
|
|
||||||
pi = process_information.unpack('LLLL')
|
pi = process_information.unpack('LLLL')
|
||||||
{ :process_handle => pi[0], :thread_handle => pi[1], :process_id => pi[2], :thread_id => pi[3] }
|
{ :process_handle => pi[0], :thread_handle => pi[1], :process_id => pi[2], :thread_id => pi[3] }
|
||||||
end
|
end
|
||||||
|
@ -208,6 +211,8 @@ module Msf::Post::Windows::Runas
|
||||||
# @return [True] True if username is in the correct format
|
# @return [True] True if username is in the correct format
|
||||||
#
|
#
|
||||||
def check_user_format(username, domain)
|
def check_user_format(username, domain)
|
||||||
|
fail ArgumentError, 'username is nil' if username.nil?
|
||||||
|
|
||||||
if domain && username.include?('@')
|
if domain && username.include?('@')
|
||||||
raise ArgumentError, 'Username is in UPN format (user@domain) so the domain parameter must be nil'
|
raise ArgumentError, 'Username is in UPN format (user@domain) so the domain parameter must be nil'
|
||||||
end
|
end
|
||||||
|
@ -230,12 +235,17 @@ module Msf::Post::Windows::Runas
|
||||||
# @return [True] True if the command_line is within the correct bounds
|
# @return [True] True if the command_line is within the correct bounds
|
||||||
#
|
#
|
||||||
def check_command_length(application_name, command_line, max_length)
|
def check_command_length(application_name, command_line, max_length)
|
||||||
|
fail ArgumentError, 'max_length is nil' if max_length.nil?
|
||||||
|
|
||||||
if application_name.nil? && command_line.nil?
|
if application_name.nil? && command_line.nil?
|
||||||
raise ArgumentError, 'Both application_name and command_line are nil'
|
raise ArgumentError, 'Both application_name and command_line are nil'
|
||||||
elsif application_name.nil? && command_line && command_line.length > MAX_PATH
|
elsif command_line && command_line.length > max_length
|
||||||
raise ArgumentError, "When application_name is nil the command line must be less than MAX_PATH #{MAX_PATH} characters (Currently #{command_line.length})"
|
raise ArgumentError, "Command line must be less than #{max_length} characters (Currently #{command_line.length})"
|
||||||
elsif application_name && command_line && command_line.length > max_length
|
elsif application_name.nil? && command_line
|
||||||
raise ArgumentError, "When application_name is set, command line must be less than #{max_length} characters (Currently #{command_line.length})"
|
cl = command_line.split(' ')
|
||||||
|
if cl[0] && cl[0].length > MAX_PATH
|
||||||
|
raise ArgumentError, "When application_name is nil the command line module must be less than MAX_PATH #{MAX_PATH} characters (Currently #{cl[0].length})"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
true
|
true
|
||||||
|
|
|
@ -0,0 +1,207 @@
|
||||||
|
# -*- coding: binary -*-
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
require 'msf/core/post/windows/runas'
|
||||||
|
|
||||||
|
describe Msf::Post::Windows::Runas do
|
||||||
|
let(:process_info) do
|
||||||
|
"\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00"
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:phToken) do
|
||||||
|
"testPhToken"
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:advapi32) do
|
||||||
|
advapi32 = double('advapi32')
|
||||||
|
advapi32.stub(:CreateProcessWithLogonW).and_return(
|
||||||
|
'return' => true,
|
||||||
|
'lpProcessInformation' => process_info
|
||||||
|
)
|
||||||
|
advapi32.stub(:CreateProcessAsUserA).and_return ({
|
||||||
|
'return' => true,
|
||||||
|
'lpProcessInformation' => process_info
|
||||||
|
})
|
||||||
|
advapi32.stub(:LogonUserA).and_return ({
|
||||||
|
'return' => true,
|
||||||
|
'phToken' => phToken
|
||||||
|
})
|
||||||
|
advapi32
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:kernel32) do
|
||||||
|
double('kernel32', CloseHandle: nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
subject do
|
||||||
|
mod = Module.new
|
||||||
|
mod.extend described_class
|
||||||
|
stubs = [ :vprint_status, :print_status, :vprint_good, :print_good, :print_error ]
|
||||||
|
stubs.each { |meth| mod.stub(meth) }
|
||||||
|
mod.stub_chain("session.railgun.kernel32").and_return(kernel32)
|
||||||
|
mod.stub_chain("session.railgun.advapi32").and_return(advapi32)
|
||||||
|
mod
|
||||||
|
end
|
||||||
|
|
||||||
|
context "#create_process_with_logon" do
|
||||||
|
it "should return a process_info hash" do
|
||||||
|
expect(advapi32).to receive(:CreateProcessWithLogonW)
|
||||||
|
expect(kernel32).not_to receive(:CloseHandle)
|
||||||
|
pi = subject.create_process_with_logon(nil, 'bob', 'pass', nil, 'cmd.exe')
|
||||||
|
pi.should be_kind_of(Hash)
|
||||||
|
pi.should eq(process_handle: 1, thread_handle: 2, process_id: 3, thread_id: 4)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should return a nil on failure" do
|
||||||
|
expect(advapi32).to receive(:CreateProcessWithLogonW)
|
||||||
|
expect(kernel32).not_to receive(:CloseHandle)
|
||||||
|
advapi32.stub(:CreateProcessWithLogonW).and_return('return' => false, 'GetLastError' => 1783, 'ErrorMessage' => 'parp')
|
||||||
|
subject.create_process_with_logon(nil, 'bob', 'pass', nil, 'cmd.exe').should be nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "#create_process_as_user" do
|
||||||
|
it "should return a process_info hash" do
|
||||||
|
expect(advapi32).to receive(:LogonUserA)
|
||||||
|
expect(advapi32).to receive(:CreateProcessAsUserA)
|
||||||
|
expect(kernel32).to receive(:CloseHandle).with(phToken)
|
||||||
|
expect(kernel32).to receive(:CloseHandle).with(1)
|
||||||
|
expect(kernel32).to receive(:CloseHandle).with(2)
|
||||||
|
pi = subject.create_process_as_user(nil, 'bob', 'pass', nil, 'cmd.exe')
|
||||||
|
pi.should be_kind_of(Hash)
|
||||||
|
pi.should eq(process_handle: 1, thread_handle: 2, process_id: 3, thread_id: 4)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should return a nil on failure of create process" do
|
||||||
|
expect(advapi32).to receive(:LogonUserA)
|
||||||
|
expect(advapi32).to receive(:CreateProcessAsUserA)
|
||||||
|
expect(kernel32).to receive(:CloseHandle).with(phToken)
|
||||||
|
expect(kernel32).not_to receive(:CloseHandle).with(1)
|
||||||
|
expect(kernel32).not_to receive(:CloseHandle).with(2)
|
||||||
|
advapi32.stub(:CreateProcessAsUserA).and_return('return' => false, 'GetLastError' => 1783, 'ErrorMessage' => 'parp')
|
||||||
|
subject.create_process_as_user(nil, 'bob', 'pass', nil, 'cmd.exe').should be nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should return a nil on failure of logon user" do
|
||||||
|
expect(advapi32).to receive(:LogonUserA)
|
||||||
|
expect(advapi32).not_to receive(:CreateProcessAsUserA)
|
||||||
|
expect(kernel32).not_to receive(:CloseHandle).with(phToken)
|
||||||
|
expect(kernel32).not_to receive(:CloseHandle).with(1)
|
||||||
|
expect(kernel32).not_to receive(:CloseHandle).with(2)
|
||||||
|
advapi32.stub(:LogonUserA).and_return('return' => false, 'GetLastError' => 1783, 'ErrorMessage' => 'parp')
|
||||||
|
subject.create_process_as_user(nil, 'bob', 'pass', nil, 'cmd.exe').should be nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "#startup_info" do
|
||||||
|
it "should be 68 bytes" do
|
||||||
|
subject.startup_info.size.should eq(68)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should return SW_HIDE=0 and STARTF_USESHOWWINDOW=1" do
|
||||||
|
si = subject.startup_info.unpack('VVVVVVVVVVVVvvVVVV')
|
||||||
|
si[11].should eq(1)
|
||||||
|
si[12].should eq(0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "#parse_process_information" do
|
||||||
|
it "should return a hash when given valid data" do
|
||||||
|
pi = subject.parse_process_information(process_info)
|
||||||
|
pi.should be_kind_of(Hash)
|
||||||
|
pi.should eq(process_handle: 1, thread_handle: 2, process_id: 3, thread_id: 4)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should return an exception when given an empty string" do
|
||||||
|
expect { subject.parse_process_information("") }.to raise_error
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should return an exception when given an nil value" do
|
||||||
|
expect { subject.parse_process_information(nil) }.to raise_error
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "#check_user_format" do
|
||||||
|
let(:upn_username) do
|
||||||
|
"bob@flob.com"
|
||||||
|
end
|
||||||
|
let(:domain_username) do
|
||||||
|
"flob\\bob"
|
||||||
|
end
|
||||||
|
let(:domain) do
|
||||||
|
"flob"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should return an exception when username is nil" do
|
||||||
|
expect { subject.check_user_format(nil, domain) }.to raise_error
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should return an exception when UPN format and domain supplied" do
|
||||||
|
expect { subject.check_user_format(upn_username, domain) }.to raise_error
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should return true when UPN format and domain is nil" do
|
||||||
|
subject.check_user_format(upn_username, nil).should be true
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should return true when domain format and domain is nil" do
|
||||||
|
subject.check_user_format(domain_username, nil).should be true
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should return true when domain format and domain supplied" do
|
||||||
|
subject.check_user_format(domain_username, domain).should be true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "#check_command_length" do
|
||||||
|
let(:max_length) do
|
||||||
|
1024
|
||||||
|
end
|
||||||
|
let(:max_path) do
|
||||||
|
256
|
||||||
|
end
|
||||||
|
let(:large_command_module) do
|
||||||
|
("A" * max_path + 1) + " arg1 arg2"
|
||||||
|
end
|
||||||
|
let(:normal_command_module) do
|
||||||
|
("A" * max_path) + " arg1 arg2"
|
||||||
|
end
|
||||||
|
let(:large_command_line) do
|
||||||
|
"A" * max_length + 1
|
||||||
|
end
|
||||||
|
let(:normal_command_line) do
|
||||||
|
"A" * max_length
|
||||||
|
end
|
||||||
|
let(:application_name) do
|
||||||
|
"c:\\windows\\system32\\calc.exe"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should raise an exception when max_length is nil" do
|
||||||
|
expect { subject.check_command_length(nil, nil, nil) }.to raise_error
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should raise an exception when application_name and command_line are nil" do
|
||||||
|
expect { subject.check_command_length(nil, nil, max_length) }.to raise_error
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should return true when application_name is set and command_line is nil" do
|
||||||
|
subject.check_command_length(application_name, nil, max_length).should be true
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should return true when application_name is set and command_line is max_length" do
|
||||||
|
subject.check_command_length(application_name, normal_command_line, max_length).should be true
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should raise an exception when command_line is larger than max_length" do
|
||||||
|
expect { subject.check_command_length(nil, large_command_line, max_length) }.to raise_error
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should raise an exception when application_name is nil command_line module is larger than MAX_PATH" do
|
||||||
|
expect { subject.check_command_length(nil, large_command_module, max_length) }.to raise_error
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should return true when application_name is nil and command_module is less than MAX_PATH" do
|
||||||
|
subject.check_command_length(nil, normal_command_module, max_length).should be true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue