diff --git a/lib/msf/core/exploit/powershell.rb b/lib/msf/core/exploit/powershell.rb index 394ef36a07..4a53cd4596 100644 --- a/lib/msf/core/exploit/powershell.rb +++ b/lib/msf/core/exploit/powershell.rb @@ -357,6 +357,7 @@ EOS compressed_payload = compress_script(psh_payload) encoded_payload = encode_script(psh_payload) + # This branch is probably never taken... if encoded_payload.length <= compressed_payload.length smallest_payload = encoded_payload encoded = true diff --git a/spec/lib/msf/core/exploit/powershell.rb b/spec/lib/msf/core/exploit/powershell.rb index 7c671dd849..c02f3c72a4 100644 --- a/spec/lib/msf/core/exploit/powershell.rb +++ b/spec/lib/msf/core/exploit/powershell.rb @@ -13,6 +13,7 @@ describe Msf::Exploit::Powershell do mod = Msf::Exploit.allocate mod.extend described_class mod.send(:initialize, {}) + mod.datastore['Verbose'] = true mod end @@ -20,6 +21,14 @@ describe Msf::Exploit::Powershell do File.join(Msf::Config.data_directory, "exploits", "powershell", "powerdump.ps1") end + let(:payload) do + Rex::Text.rand_text_alpha(120) + end + + let(:arch) do + 'x86' + end + describe "::read_script" do it 'should read a sample script file' do script = subject.read_script(example_script) @@ -147,67 +156,247 @@ describe Msf::Exploit::Powershell do end end - describe "::cmd_psh_payload" do - it 'should generate a command line with an x86 payload' do + describe "::run_hidden_psh" do + + let(:encoded) do + false end - it 'should generate a command line with an x64 payload' do + context 'when x86 payload' do + it 'should generate code' do + code = subject.run_hidden_psh(payload, arch, encoded) + code.include?('syswow64').should be_true + end + end + context 'when x64 payload' do + it 'should generate code' do + code = subject.run_hidden_psh(payload, 'x86_64', encoded) + code.include?('sysnative').should be_true + end + end + + context 'when encoded' do + it 'should generate a code including an encoded command' do + code = subject.run_hidden_psh(payload, arch, true) + code.include?('-nop -w hidden -e ').should be_true + end + end + + context 'when command' do + it 'should generate code including a -c command' do + code = subject.run_hidden_psh(payload, arch, encoded) + code.include?('-nop -w hidden -c ').should be_true + end + end + + context 'when old' do + before do + subject.datastore['Powershell::method'] = 'old' + subject.options.validate(subject.datastore) + end + it 'should generate a code including unshorted args' do + code = subject.run_hidden_psh(payload, arch, encoded) + code.include?('-NoProfile -WindowStyle hidden -NoExit -Command ').should be_true + end + end + end + + describe "::cmd_psh_payload" do + context 'when payload is huge' do + it 'should raise an exception' do + except = false + begin + code = subject.cmd_psh_payload(Rex::Text.rand_text_alpha(12000), arch) + rescue RuntimeError => e + except = true + end + + except.should be_true + end end context 'when persist is true' do - it 'should add a persistance loop' + before do + subject.datastore['Powershell::persist'] = true + subject.options.validate(subject.datastore) + end + it 'should add a persistance loop' do + code = subject.cmd_psh_payload(payload, arch) + decompress(code).include?('while(1){Start-Sleep -s ').should be_true end end context 'when persist is false' do + before do + subject.datastore['Powershell::persist'] = false + subject.options.validate(subject.datastore) + end it 'shouldnt add a persistance loop' do + code = subject.cmd_psh_payload(payload, arch) + decompress(code).include?('while(1){Start-Sleep -s ').should be_false end end context 'when prepend_sleep is set' do - it 'should add a sleep' do - + before do + subject.datastore['Powershell::prepend_sleep'] = 5 + subject.options.validate(subject.datastore) + end + it 'should prepend sleep' do + code = subject.cmd_psh_payload(payload, arch) + decompress(code).include?('Start-Sleep -s ').should be_true end end context 'when prepend_sleep isnt set' do - it 'shouldnt add a sleep' do + before do + subject.datastore['Powershell::prepend_sleep'] = nil + subject.options.validate(subject.datastore) + end + it 'shouldnt prepend sleep' do + code = subject.cmd_psh_payload(payload, arch) + decompress(code).include?('Start-Sleep -s ').should be_false + end + end + context 'when prepend_sleep is 0' do + before do + subject.datastore['Powershell::prepend_sleep'] = 0 + subject.options.validate(subject.datastore) + end + it 'shouldnt prepend sleep' do + code = subject.cmd_psh_payload(payload, arch) + decompress(code).include?('Start-Sleep -s ').should be_false end end context 'when method is old' do - + before do + subject.datastore['Powershell::method'] = 'old' + subject.options.validate(subject.datastore) + end + it 'should generate a command line' do + code = subject.cmd_psh_payload(payload, arch) + decompress(code).include?('-namespace Win32Functions').should be_true + end + it 'shouldnt shorten args' do + code = subject.cmd_psh_payload(payload, arch) + code.include?('-NoProfile -WindowStyle hidden -Command').should be_true + end + it 'should include -NoExit' do + code = subject.cmd_psh_payload(payload, arch) + code.include?('-NoProfile -WindowStyle hidden -NoExit -Command').should be_true + end end context 'when method is net' do - + before do + subject.datastore['Powershell::method'] = 'net' + subject.options.validate(subject.datastore) + end + it 'should generate a command line' do + code = subject.cmd_psh_payload(payload, arch) + decompress(code).include?('System.Runtime.InteropServices;').should be_true + end end context 'when method is reflection' do - + before do + subject.datastore['Powershell::method'] = 'reflection' + subject.options.validate(subject.datastore) + end + it 'should generate a command line' do + code = subject.cmd_psh_payload(payload, arch) + decompress(code).include?('GlobalAssemblyCache').should be_true + end end context 'when method is msil' do + before do + subject.datastore['Powershell::method'] = 'msil' + subject.options.validate(subject.datastore) + end + it 'should raise an exception' do + except = false + begin + subject.cmd_psh_payload(payload, arch) + rescue RuntimeError + except = true + end + except.should be_true + end + end + context 'when method is unknown' do + before do + subject.datastore['Powershell::method'] = 'blah' + end + it 'should raise an exception' do + except = false + begin + subject.cmd_psh_payload(payload, arch) + rescue RuntimeError + except = true + end + except.should be_true + end + after do + subject.datastore['Powershell::method'] = 'reflection' + subject.options.validate(subject.datastore) + end end context 'when encode_inner_payload' do + it 'should contain an inner payload with -e' do + code = subject.cmd_psh_payload(payload, arch, {:encode_inner_payload => true}) + code.include?(' -e ').should be_true + end + context 'when no_equals is true' do + it 'should raise an exception' do + except = false + begin + code = subject.cmd_psh_payload(payload, arch, {:encode_inner_payload => true, :no_equals => true}) + rescue RuntimeError + except = true + end + except.should be_true + end + end end context 'when encode_final_payload' do - + context 'when no_equals is false' do + it 'should contain a final payload with -e' do + code = subject.cmd_psh_payload(payload, arch, {:encode_final_payload => true, :no_equals => false}) + code.include?(' -e ').should be_true + code.include?(' -c ').should be_false + end + end + context 'when no_equals is true' do + it 'should contain a final payload with -e' do + code = subject.cmd_psh_payload(payload, arch, {:encode_final_payload => true, :no_equals => true}) + code.include?(' -e ').should be_true + code.include?(' -c ').should be_false + code.include?('=').should be_false + end + end end context 'when remove_comspec' do - + it 'shouldnt contain %COMSPEC%' do + code = subject.cmd_psh_payload(payload, arch, {:remove_comspec => true}) + code.include?('%COMSPEC%').should be_false + end end context 'when use single quotes' do - + it 'should wrap in single quotes' do + code = subject.cmd_psh_payload(payload, arch, {:use_single_quotes => true}) + code.include?(' -c \'').should be_true + end end end